No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / groff / src / preproc / eqn / main.cpp
blobb323989f34166cd4980aa1089179a7d6f4ced06f
1 /* $NetBSD$ */
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include "eqn.h"
25 #include "stringclass.h"
26 #include "device.h"
27 #include "searchpath.h"
28 #include "macropath.h"
29 #include "htmlhint.h"
30 #include "pbox.h"
31 #include "ctype.h"
33 #define STARTUP_FILE "eqnrc"
35 extern int yyparse();
36 extern "C" const char *Version_string;
38 static char *delim_search (char *, int);
39 static int inline_equation (FILE *, string &, string &);
41 char start_delim = '\0';
42 char end_delim = '\0';
43 int non_empty_flag;
44 int inline_flag;
45 int draw_flag = 0;
46 int one_size_reduction_flag = 0;
47 int compatible_flag = 0;
48 int no_newline_in_delim_flag = 0;
49 int html = 0;
52 int read_line(FILE *fp, string *p)
54 p->clear();
55 int c = -1;
56 while ((c = getc(fp)) != EOF) {
57 if (!invalid_input_char(c))
58 *p += char(c);
59 else
60 error("invalid input character code `%1'", c);
61 if (c == '\n')
62 break;
64 current_lineno++;
65 return p->length() > 0;
68 void do_file(FILE *fp, const char *filename)
70 string linebuf;
71 string str;
72 printf(".lf 1 %s\n", filename);
73 current_filename = filename;
74 current_lineno = 0;
75 while (read_line(fp, &linebuf)) {
76 if (linebuf.length() >= 4
77 && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
78 && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
79 put_string(linebuf, stdout);
80 linebuf += '\0';
81 if (interpret_lf_args(linebuf.contents() + 3))
82 current_lineno--;
84 else if (linebuf.length() >= 4
85 && linebuf[0] == '.'
86 && linebuf[1] == 'E'
87 && linebuf[2] == 'Q'
88 && (linebuf[3] == ' ' || linebuf[3] == '\n'
89 || compatible_flag)) {
90 put_string(linebuf, stdout);
91 int start_lineno = current_lineno + 1;
92 str.clear();
93 for (;;) {
94 if (!read_line(fp, &linebuf))
95 fatal("end of file before .EN");
96 if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
97 if (linebuf[2] == 'N'
98 && (linebuf.length() == 3 || linebuf[3] == ' '
99 || linebuf[3] == '\n' || compatible_flag))
100 break;
101 else if (linebuf[2] == 'Q' && linebuf.length() > 3
102 && (linebuf[3] == ' ' || linebuf[3] == '\n'
103 || compatible_flag))
104 fatal("nested .EQ");
106 str += linebuf;
108 str += '\0';
109 start_string();
110 init_lex(str.contents(), current_filename, start_lineno);
111 non_empty_flag = 0;
112 inline_flag = 0;
113 yyparse();
114 restore_compatibility();
115 if (non_empty_flag) {
116 printf(".lf %d\n", current_lineno - 1);
117 output_string();
119 printf(".lf %d\n", current_lineno);
120 put_string(linebuf, stdout);
122 else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
123 && inline_equation(fp, linebuf, str))
125 else
126 put_string(linebuf, stdout);
128 current_filename = 0;
129 current_lineno = 0;
132 // Handle an inline equation. Return 1 if it was an inline equation,
133 // otherwise.
134 static int inline_equation(FILE *fp, string &linebuf, string &str)
136 linebuf += '\0';
137 char *ptr = &linebuf[0];
138 char *start = delim_search(ptr, start_delim);
139 if (!start) {
140 // It wasn't a delimiter after all.
141 linebuf.set_length(linebuf.length() - 1); // strip the '\0'
142 return 0;
144 start_string();
145 inline_flag = 1;
146 for (;;) {
147 if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
148 error("missing `%1'", end_delim);
149 char *nl = strchr(start + 1, '\n');
150 if (nl != 0)
151 *nl = '\0';
152 do_text(ptr);
153 break;
155 int start_lineno = current_lineno;
156 *start = '\0';
157 do_text(ptr);
158 ptr = start + 1;
159 str.clear();
160 for (;;) {
161 char *end = strchr(ptr, end_delim);
162 if (end != 0) {
163 *end = '\0';
164 str += ptr;
165 ptr = end + 1;
166 break;
168 str += ptr;
169 if (!read_line(fp, &linebuf))
170 fatal("unterminated `%1' at line %2, looking for `%3'",
171 start_delim, start_lineno, end_delim);
172 linebuf += '\0';
173 ptr = &linebuf[0];
175 str += '\0';
176 if (html) {
177 printf(".as1 %s ", LINE_STRING);
178 html_begin_suppress();
179 printf("\n");
181 init_lex(str.contents(), current_filename, start_lineno);
182 yyparse();
183 if (html) {
184 printf(".as1 %s ", LINE_STRING);
185 html_end_suppress();
186 printf("\n");
188 start = delim_search(ptr, start_delim);
189 if (start == 0) {
190 char *nl = strchr(ptr, '\n');
191 if (nl != 0)
192 *nl = '\0';
193 do_text(ptr);
194 break;
197 restore_compatibility();
198 printf(".lf %d\n", current_lineno);
199 output_string();
200 printf(".lf %d\n", current_lineno + 1);
201 return 1;
204 /* Search for delim. Skip over number register and string names etc. */
206 static char *delim_search(char *ptr, int delim)
208 while (*ptr) {
209 if (*ptr == delim)
210 return ptr;
211 if (*ptr++ == '\\') {
212 switch (*ptr) {
213 case 'n':
214 case '*':
215 case 'f':
216 case 'g':
217 case 'k':
218 switch (*++ptr) {
219 case '\0':
220 case '\\':
221 break;
222 case '(':
223 if (*++ptr != '\\' && *ptr != '\0'
224 && *++ptr != '\\' && *ptr != '\0')
225 ptr++;
226 break;
227 case '[':
228 while (*++ptr != '\0')
229 if (*ptr == ']') {
230 ptr++;
231 break;
233 break;
234 default:
235 ptr++;
236 break;
238 break;
239 case '\\':
240 case '\0':
241 break;
242 default:
243 ptr++;
244 break;
248 return 0;
251 void usage(FILE *stream)
253 fprintf(stream,
254 "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
255 program_name);
258 int main(int argc, char **argv)
260 program_name = argv[0];
261 static char stderr_buf[BUFSIZ];
262 setbuf(stderr, stderr_buf);
263 int opt;
264 int load_startup_file = 1;
265 static const struct option long_options[] = {
266 { "help", no_argument, 0, CHAR_MAX + 1 },
267 { "version", no_argument, 0, 'v' },
268 { NULL, 0, 0, 0 }
270 while ((opt = getopt_long(argc, argv, "DCRvd:f:p:s:m:T:M:rN", long_options,
271 NULL))
272 != EOF)
273 switch (opt) {
274 case 'C':
275 compatible_flag = 1;
276 break;
277 case 'R': // don't load eqnrc
278 load_startup_file = 0;
279 break;
280 case 'M':
281 config_macro_path.command_line_dir(optarg);
282 break;
283 case 'v':
285 printf("GNU eqn (groff) version %s\n", Version_string);
286 exit(0);
287 break;
289 case 'd':
290 if (optarg[0] == '\0' || optarg[1] == '\0')
291 error("-d requires two character argument");
292 else if (invalid_input_char(optarg[0]))
293 error("bad delimiter `%1'", optarg[0]);
294 else if (invalid_input_char(optarg[1]))
295 error("bad delimiter `%1'", optarg[1]);
296 else {
297 start_delim = optarg[0];
298 end_delim = optarg[1];
300 break;
301 case 'f':
302 set_gfont(optarg);
303 break;
304 case 'T':
305 device = optarg;
306 if (strcmp(device, "ps:html") == 0) {
307 device = "ps";
308 html = 1;
310 break;
311 case 's':
312 if (!set_gsize(optarg))
313 error("invalid size `%1'", optarg);
314 break;
315 case 'p':
317 int n;
318 if (sscanf(optarg, "%d", &n) == 1)
319 set_script_reduction(n);
320 else
321 error("bad size `%1'", optarg);
323 break;
324 case 'm':
326 int n;
327 if (sscanf(optarg, "%d", &n) == 1)
328 set_minimum_size(n);
329 else
330 error("bad size `%1'", optarg);
332 break;
333 case 'r':
334 one_size_reduction_flag = 1;
335 break;
336 case 'D':
337 warning("-D option is obsolete: use `set draw_lines 1' instead");
338 draw_flag = 1;
339 break;
340 case 'N':
341 no_newline_in_delim_flag = 1;
342 break;
343 case CHAR_MAX + 1: // --help
344 usage(stdout);
345 exit(0);
346 break;
347 case '?':
348 usage(stderr);
349 exit(1);
350 break;
351 default:
352 assert(0);
354 init_table(device);
355 init_char_table();
356 printf(".if !'\\*(.T'%s' "
357 ".if !'\\*(.T'html' " // the html device uses `-Tps' to render
358 // equations as images
359 ".tm warning: %s should have been given a `-T\\*(.T' option\n",
360 device, program_name);
361 printf(".if '\\*(.T'html' "
362 ".if !'%s'ps' "
363 ".tm warning: %s should have been given a `-Tps' option\n",
364 device, program_name);
365 printf(".if '\\*(.T'html' "
366 ".if !'%s'ps' "
367 ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n",
368 device);
369 if (load_startup_file) {
370 char *path;
371 FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
372 if (fp) {
373 do_file(fp, path);
374 fclose(fp);
375 a_delete path;
378 if (optind >= argc)
379 do_file(stdin, "-");
380 else
381 for (int i = optind; i < argc; i++)
382 if (strcmp(argv[i], "-") == 0)
383 do_file(stdin, "-");
384 else {
385 errno = 0;
386 FILE *fp = fopen(argv[i], "r");
387 if (!fp)
388 fatal("can't open `%1': %2", argv[i], strerror(errno));
389 else {
390 do_file(fp, argv[i]);
391 fclose(fp);
394 if (ferror(stdout) || fflush(stdout) < 0)
395 fatal("output error");
396 return 0;