]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/groff/eqn/main.cc
unfinished sblive driver, playback/mixer only for now - not enabled in
[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       put_string(".if '\\*(.T'html' \\X(graphic-start(\\c\n", stdout);
82       int start_lineno = current_lineno + 1;
83       str.clear();
84       for (;;) {
85         if (!read_line(fp, &linebuf))
86           fatal("end of file before .EN");
87         if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
88           if (linebuf[2] == 'N'
89               && (linebuf.length() == 3 || linebuf[3] == ' '
90                   || linebuf[3] == '\n' || compatible_flag))
91             break;
92           else if (linebuf[2] == 'Q' && linebuf.length() > 3
93                    && (linebuf[3] == ' ' || linebuf[3] == '\n'
94                        || compatible_flag))
95             fatal("nested .EQ");
96         }
97         str += linebuf;
98       }
99       str += '\0';
100       start_string();
101       init_lex(str.contents(), current_filename, start_lineno);
102       non_empty_flag = 0;
103       inline_flag = 0;
104       yyparse();
105       if (non_empty_flag) {
106         printf(".lf %d\n", current_lineno - 1);
107         output_string();
108       }
109       restore_compatibility();
110       printf(".lf %d\n", current_lineno);
111       put_string(".if '\\*(.T'html' \\X(graphic-end(\\c\n", stdout);
112       put_string(linebuf, stdout);
113     }
114     else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
115              && inline_equation(fp, linebuf, str))
116       ;
117     else
118       put_string(linebuf, stdout);
119   }
120   current_filename = 0;
121   current_lineno = 0;
122 }
123
124 /* Handle an inline equation.  Return 1 if it was an inline equation,
125 0 otherwise. */
126
127 static int inline_equation(FILE *fp, string &linebuf, string &str)
128 {
129   linebuf += '\0';
130   char *ptr = &linebuf[0];
131   char *start = delim_search(ptr, start_delim);
132   if (!start) {
133     // It wasn't a delimiter after all.
134     linebuf.set_length(linebuf.length() - 1); // strip the '\0'
135     return 0;
136   }
137   start_string();
138   inline_flag = 1;
139   for (;;) {
140     if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
141       error("missing `%1'", end_delim);
142       char *nl = strchr(start + 1, '\n');
143       if (nl != 0)
144         *nl = '\0';
145       do_text(ptr);
146       break;
147     }
148     int start_lineno = current_lineno;
149     *start = '\0';
150     do_text(ptr);
151     ptr = start + 1;
152     str.clear();
153     for (;;) {
154       char *end = strchr(ptr, end_delim);
155       if (end != 0) {
156         *end = '\0';
157         str += ptr;
158         ptr = end + 1;
159         break;
160       }
161       str += ptr;
162       if (!read_line(fp, &linebuf))
163         fatal("end of file before `%1'", end_delim);
164       linebuf += '\0';
165       ptr = &linebuf[0];
166     }
167     str += '\0';
168     put_string(".if '\\*(.T'html' \\X(graphic-start(\\c\n", stdout);
169     init_lex(str.contents(), current_filename, start_lineno);
170     yyparse();
171     start = delim_search(ptr, start_delim);
172     if (start == 0) {
173       char *nl = strchr(ptr, '\n');
174       if (nl != 0)
175         *nl = '\0';
176       do_text(ptr);
177       break;
178     }
179   }
180   printf(".lf %d\n", current_lineno);
181   output_string();
182   restore_compatibility();
183   put_string(".if '\\*(.T'html' \\X(graphic-end(\\c\n", stdout);
184   printf(".lf %d\n", current_lineno + 1);
185   return 1;
186 }
187
188 /* Search for delim.  Skip over number register and string names etc. */
189
190 static char *delim_search(char *ptr, int delim)
191 {
192   while (*ptr) {
193     if (*ptr == delim)
194       return ptr;
195     if (*ptr++ == '\\') {
196       switch (*ptr) {
197       case 'n':
198       case '*':
199       case 'f':
200       case 'g':
201       case 'k':
202         switch (*++ptr) {
203         case '\0':
204         case '\\':
205           break;
206         case '(':
207           if (*++ptr != '\\' && *ptr != '\0' && *++ptr != '\\' && *ptr != '\0')
208               ptr++;
209           break;
210         case '[':
211           while (*++ptr != '\0')
212             if (*ptr == ']') {
213               ptr++;
214               break;
215             }
216           break;
217         default:
218           ptr++;
219           break;
220         }
221         break;
222       case '\\':
223       case '\0':
224         break;
225       default:
226         ptr++;
227         break;
228       }
229     }
230   }
231   return 0;
232 }
233
234 void usage()
235 {
236   fprintf(stderr,
237         "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
238         program_name);
239   exit(1);
240 }
241
242 int main(int argc, char **argv)
243 {
244   program_name = argv[0];
245   static char stderr_buf[BUFSIZ];
246   setbuf(stderr, stderr_buf);
247   int opt;
248   int load_startup_file = 1;
249   while ((opt = getopt(argc, argv, "DCRvd:f:p:s:m:T:M:rN")) != EOF)
250     switch (opt) {
251     case 'C':
252       compatible_flag = 1;
253       break;
254     case 'R':                   // don't load eqnchar
255       load_startup_file = 0;
256       break;
257     case 'M':
258       macro_path.command_line_dir(optarg);
259       break;
260     case 'v':
261       {
262         extern const char *version_string;
263         fprintf(stderr, "GNU eqn version %s\n", version_string);
264         fflush(stderr);
265         break;
266       }
267     case 'd':
268       if (optarg[0] == '\0' || optarg[1] == '\0')
269         error("-d requires two character argument");
270       else if (illegal_input_char(optarg[0]))
271         error("bad delimiter `%1'", optarg[0]);
272       else if (illegal_input_char(optarg[1]))
273         error("bad delimiter `%1'", optarg[1]);
274       else {
275         start_delim = optarg[0];
276         end_delim = optarg[1];
277       }
278       break;
279     case 'f':
280       set_gfont(optarg);
281       break;
282     case 'T':
283       device = optarg;
284       break;
285     case 's':
286       if (!set_gsize(optarg))
287         error("invalid size `%1'", optarg);
288       break;
289     case 'p':
290       {
291         int n;
292         if (sscanf(optarg, "%d", &n) == 1)
293           set_script_reduction(n);
294         else
295           error("bad size `%1'", optarg);
296       }
297       break;
298     case 'm':
299       {
300         int n;
301         if (sscanf(optarg, "%d", &n) == 1)
302           set_minimum_size(n);
303         else
304           error("bad size `%1'", optarg);
305       }
306       break;
307     case 'r':
308       one_size_reduction_flag = 1;
309       break;
310     case 'D':
311       warning("-D option is obsolete: use `set draw_lines 1' instead");
312       draw_flag = 1;
313       break;
314     case 'N':
315       no_newline_in_delim_flag = 1;
316       break;
317     case '?':
318       usage();
319       break;
320     default:
321       assert(0);
322     }
323   init_table(device);
324   init_char_table();
325   printf(".if !'\\*(.T'%s' "
326          ".tm warning: %s should have been given a `-T\\*(.T' option\n",
327          device, program_name);
328   if (load_startup_file) {
329     char *path;
330     FILE *fp = macro_path.open_file(STARTUP_FILE, &path);
331     if (fp) {
332       do_file(fp, path);
333       fclose(fp);
334       a_delete path;
335     }
336   }
337   if (optind >= argc)
338     do_file(stdin, "-");
339   else
340     for (int i = optind; i < argc; i++)
341       if (strcmp(argv[i], "-") == 0)
342         do_file(stdin, "-");
343       else {
344         errno = 0;
345         FILE *fp = fopen(argv[i], "r");
346         if (!fp)
347           fatal("can't open `%1': %2", argv[i], strerror(errno));
348         else {
349           do_file(fp, argv[i]);
350           fclose(fp);
351         }
352       }
353   if (ferror(stdout) || fflush(stdout) < 0)
354     fatal("output error");
355   return 0;
356 }