]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/groff/eqn/main.cc
This commit was generated by cvs2svn to compensate for changes in r48730,
[FreeBSD/FreeBSD.git] / contrib / groff / eqn / main.cc
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include "eqn.h"
22 #include "stringclass.h"
23 #include "device.h"
24 #include "searchpath.h"
25 #include "macropath.h"
26
27 #define STARTUP_FILE "eqnrc"
28
29 extern int yyparse();
30
31 static char *delim_search(char *, int);
32 static int inline_equation(FILE *, string &, string &);
33
34 char start_delim = '\0';
35 char end_delim = '\0';
36 int non_empty_flag;
37 int inline_flag;
38 int draw_flag = 0;
39 int one_size_reduction_flag = 0;
40 int compatible_flag = 0;
41 int no_newline_in_delim_flag = 0;
42
43 int read_line(FILE *fp, string *p)
44 {
45   p->clear();
46   int c = -1;
47   while ((c = getc(fp)) != EOF) {
48     if (!illegal_input_char(c))
49       *p += char(c);
50     else
51       error("illegal input character code `%1'", c);
52     if (c == '\n')
53       break;
54   }
55   current_lineno++;
56   return p->length() > 0;
57 }
58
59 void do_file(FILE *fp, const char *filename)
60 {
61   string linebuf;
62   string str;
63   printf(".lf 1 %s\n", filename);
64   current_filename = filename;
65   current_lineno = 0;
66   while (read_line(fp, &linebuf)) {
67     if (linebuf.length() >= 4
68         && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
69         && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
70       put_string(linebuf, stdout);
71       linebuf += '\0';
72       if (interpret_lf_args(linebuf.contents() + 3))
73         current_lineno--;
74     }
75     else if (linebuf.length() >= 4
76              && linebuf[0] == '.'
77              && linebuf[1] == 'E'
78              && linebuf[2] == 'Q'
79              && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
80       put_string(linebuf, stdout);
81       int start_lineno = current_lineno + 1;
82       str.clear();
83       for (;;) {
84         if (!read_line(fp, &linebuf))
85           fatal("end of file before .EN");
86         if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
87           if (linebuf[2] == 'N'
88               && (linebuf.length() == 3 || linebuf[3] == ' '
89                   || linebuf[3] == '\n' || compatible_flag))
90             break;
91           else if (linebuf[2] == 'Q' && linebuf.length() > 3
92                    && (linebuf[3] == ' ' || linebuf[3] == '\n'
93                        || compatible_flag))
94             fatal("nested .EQ");
95         }
96         str += linebuf;
97       }
98       str += '\0';
99       start_string();
100       init_lex(str.contents(), current_filename, start_lineno);
101       non_empty_flag = 0;
102       inline_flag = 0;
103       yyparse();
104       if (non_empty_flag) {
105         printf(".lf %d\n", current_lineno - 1);
106         output_string();
107       }
108       restore_compatibility();
109       printf(".lf %d\n", current_lineno);
110       put_string(linebuf, stdout);
111     }
112     else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
113              && inline_equation(fp, linebuf, str))
114       ;
115     else
116       put_string(linebuf, stdout);
117   }
118   current_filename = 0;
119   current_lineno = 0;
120 }
121
122 /* Handle an inline equation.  Return 1 if it was an inline equation,
123 0 otherwise. */
124
125 static int inline_equation(FILE *fp, string &linebuf, string &str)
126 {
127   linebuf += '\0';
128   char *ptr = &linebuf[0];
129   char *start = delim_search(ptr, start_delim);
130   if (!start) {
131     // It wasn't a delimiter after all.
132     linebuf.set_length(linebuf.length() - 1); // strip the '\0'
133     return 0;
134   }
135   start_string();
136   inline_flag = 1;
137   for (;;) {
138     if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
139       error("missing `%1'", end_delim);
140       char *nl = strchr(start + 1, '\n');
141       if (nl != 0)
142         *nl = '\0';
143       do_text(ptr);
144       break;
145     }
146     int start_lineno = current_lineno;
147     *start = '\0';
148     do_text(ptr);
149     ptr = start + 1;
150     str.clear();
151     for (;;) {
152       char *end = strchr(ptr, end_delim);
153       if (end != 0) {
154         *end = '\0';
155         str += ptr;
156         ptr = end + 1;
157         break;
158       }
159       str += ptr;
160       if (!read_line(fp, &linebuf))
161         fatal("end of file before `%1'", end_delim);
162       linebuf += '\0';
163       ptr = &linebuf[0];
164     }
165     str += '\0';
166     init_lex(str.contents(), current_filename, start_lineno);
167     yyparse();
168     start = delim_search(ptr, start_delim);
169     if (start == 0) {
170       char *nl = strchr(ptr, '\n');
171       if (nl != 0)
172         *nl = '\0';
173       do_text(ptr);
174       break;
175     }
176   }
177   printf(".lf %d\n", current_lineno);
178   output_string();
179   restore_compatibility();
180   printf(".lf %d\n", current_lineno + 1);
181   return 1;
182 }
183
184 /* Search for delim.  Skip over number register and string names etc. */
185
186 static char *delim_search(char *ptr, int delim)
187 {
188   while (*ptr) {
189     if (*ptr == delim)
190       return ptr;
191     if (*ptr++ == '\\') {
192       switch (*ptr) {
193       case 'n':
194       case '*':
195       case 'f':
196       case 'g':
197       case 'k':
198         switch (*++ptr) {
199         case '\0':
200         case '\\':
201           break;
202         case '(':
203           if (*++ptr != '\\' && *ptr != '\0' && *++ptr != '\\' && *ptr != '\0')
204               ptr++;
205           break;
206         case '[':
207           while (*++ptr != '\0')
208             if (*ptr == ']') {
209               ptr++;
210               break;
211             }
212           break;
213         default:
214           ptr++;
215           break;
216         }
217         break;
218       case '\\':
219       case '\0':
220         break;
221       default:
222         ptr++;
223         break;
224       }
225     }
226   }
227   return 0;
228 }
229
230 void usage()
231 {
232   fprintf(stderr,
233         "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
234         program_name);
235   exit(1);
236 }
237
238 int main(int argc, char **argv)
239 {
240   program_name = argv[0];
241   static char stderr_buf[BUFSIZ];
242   setbuf(stderr, stderr_buf);
243   int opt;
244   int load_startup_file = 1;
245   while ((opt = getopt(argc, argv, "DCRvd:f:p:s:m:T:M:rN")) != EOF)
246     switch (opt) {
247     case 'C':
248       compatible_flag = 1;
249       break;
250     case 'R':                   // don't load eqnchar
251       load_startup_file = 0;
252       break;
253     case 'M':
254       macro_path.command_line_dir(optarg);
255       break;
256     case 'v':
257       {
258         extern const char *version_string;
259         fprintf(stderr, "GNU eqn version %s\n", version_string);
260         fflush(stderr);
261         break;
262       }
263     case 'd':
264       if (optarg[0] == '\0' || optarg[1] == '\0')
265         error("-d requires two character argument");
266       else if (illegal_input_char(optarg[0]))
267         error("bad delimiter `%1'", optarg[0]);
268       else if (illegal_input_char(optarg[1]))
269         error("bad delimiter `%1'", optarg[1]);
270       else {
271         start_delim = optarg[0];
272         end_delim = optarg[1];
273       }
274       break;
275     case 'f':
276       set_gfont(optarg);
277       break;
278     case 'T':
279       device = optarg;
280       break;
281     case 's':
282       if (!set_gsize(optarg))
283         error("invalid size `%1'", optarg);
284       break;
285     case 'p':
286       {
287         int n;
288         if (sscanf(optarg, "%d", &n) == 1)
289           set_script_reduction(n);
290         else
291           error("bad size `%1'", optarg);
292       }
293       break;
294     case 'm':
295       {
296         int n;
297         if (sscanf(optarg, "%d", &n) == 1)
298           set_minimum_size(n);
299         else
300           error("bad size `%1'", optarg);
301       }
302       break;
303     case 'r':
304       one_size_reduction_flag = 1;
305       break;
306     case 'D':
307       warning("-D option is obsolete: use `set draw_lines 1' instead");
308       draw_flag = 1;
309       break;
310     case 'N':
311       no_newline_in_delim_flag = 1;
312       break;
313     case '?':
314       usage();
315       break;
316     default:
317       assert(0);
318     }
319   init_table(device);
320   init_char_table();
321   printf(".if !'\\*(.T'%s' "
322          ".tm warning: %s should have been given a `-T\\*(.T' option\n",
323          device, program_name);
324   if (load_startup_file) {
325     char *path;
326     FILE *fp = macro_path.open_file(STARTUP_FILE, &path);
327     if (fp) {
328       do_file(fp, path);
329       fclose(fp);
330       a_delete path;
331     }
332   }
333   if (optind >= argc)
334     do_file(stdin, "-");
335   else
336     for (int i = optind; i < argc; i++)
337       if (strcmp(argv[i], "-") == 0)
338         do_file(stdin, "-");
339       else {
340         errno = 0;
341         FILE *fp = fopen(argv[i], "r");
342         if (!fp)
343           fatal("can't open `%1': %2", argv[i], strerror(errno));
344         else {
345           do_file(fp, argv[i]);
346           fclose(fp);
347         }
348       }
349   if (ferror(stdout) || fflush(stdout) < 0)
350     fatal("output error");
351   return 0;
352 }