2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2005, 2007,
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "stringclass.h"
25 #include "searchpath.h"
26 #include "macropath.h"
31 #define STARTUP_FILE "eqnrc"
34 extern "C" const char *Version_string;
36 static char *delim_search (char *, int);
37 static int inline_equation (FILE *, string &, string &);
39 char start_delim = '\0';
40 char end_delim = '\0';
44 int one_size_reduction_flag = 0;
45 int compatible_flag = 0;
46 int no_newline_in_delim_flag = 0;
49 eqnmode_t output_format;
51 int read_line(FILE *fp, string *p)
55 while ((c = getc(fp)) != EOF) {
56 if (!invalid_input_char(c))
59 error("invalid input character code `%1'", c);
64 return p->length() > 0;
67 void do_file(FILE *fp, const char *filename)
71 if (output_format == troff)
72 printf(".lf 1 %s\n", filename);
73 current_filename = filename;
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);
81 if (interpret_lf_args(linebuf.contents() + 3))
84 else if (linebuf.length() >= 4
88 && (linebuf[3] == ' ' || linebuf[3] == '\n'
89 || compatible_flag)) {
90 put_string(linebuf, stdout);
91 int start_lineno = current_lineno + 1;
94 if (!read_line(fp, &linebuf))
95 fatal("end of file before .EN");
96 if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
98 && (linebuf.length() == 3 || linebuf[3] == ' '
99 || linebuf[3] == '\n' || compatible_flag))
101 else if (linebuf[2] == 'Q' && linebuf.length() > 3
102 && (linebuf[3] == ' ' || linebuf[3] == '\n'
110 init_lex(str.contents(), current_filename, start_lineno);
114 restore_compatibility();
116 if (output_format == mathml)
119 printf(".lf %d\n", current_lineno - 1);
122 if (output_format == troff)
123 printf(".lf %d\n", current_lineno);
124 put_string(linebuf, stdout);
126 else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
127 && inline_equation(fp, linebuf, str))
130 put_string(linebuf, stdout);
132 current_filename = 0;
136 // Handle an inline equation. Return 1 if it was an inline equation,
138 static int inline_equation(FILE *fp, string &linebuf, string &str)
141 char *ptr = &linebuf[0];
142 char *start = delim_search(ptr, start_delim);
144 // It wasn't a delimiter after all.
145 linebuf.set_length(linebuf.length() - 1); // strip the '\0'
151 if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
152 error("missing `%1'", end_delim);
153 char *nl = strchr(start + 1, '\n');
159 int start_lineno = current_lineno;
165 char *end = strchr(ptr, end_delim);
173 if (!read_line(fp, &linebuf))
174 fatal("unterminated `%1' at line %2, looking for `%3'",
175 start_delim, start_lineno, end_delim);
180 if (output_format == troff && html) {
181 printf(".as1 %s ", LINE_STRING);
182 html_begin_suppress();
185 init_lex(str.contents(), current_filename, start_lineno);
187 if (output_format == troff && html) {
188 printf(".as1 %s ", LINE_STRING);
192 if (output_format == mathml)
195 /* skip leading spaces */
196 while ((*ptr != '\0') && (*ptr == ' '))
199 start = delim_search(ptr, start_delim);
201 char *nl = strchr(ptr, '\n');
208 restore_compatibility();
209 if (output_format == troff)
210 printf(".lf %d\n", current_lineno);
212 if (output_format == troff)
213 printf(".lf %d\n", current_lineno + 1);
217 /* Search for delim. Skip over number register and string names etc. */
219 static char *delim_search(char *ptr, int delim)
224 if (*ptr++ == '\\') {
236 if (*++ptr != '\\' && *ptr != '\0'
237 && *++ptr != '\\' && *ptr != '\0')
241 while (*++ptr != '\0')
264 void usage(FILE *stream)
267 "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
271 int main(int argc, char **argv)
273 program_name = argv[0];
274 static char stderr_buf[BUFSIZ];
275 setbuf(stderr, stderr_buf);
277 int load_startup_file = 1;
278 static const struct option long_options[] = {
279 { "help", no_argument, 0, CHAR_MAX + 1 },
280 { "version", no_argument, 0, 'v' },
283 while ((opt = getopt_long(argc, argv, "DCRvd:f:p:s:m:T:M:rN", long_options,
290 case 'R': // don't load eqnrc
291 load_startup_file = 0;
294 config_macro_path.command_line_dir(optarg);
297 printf("GNU eqn (groff) version %s\n", Version_string);
301 if (optarg[0] == '\0' || optarg[1] == '\0')
302 error("-d requires two character argument");
303 else if (invalid_input_char(optarg[0]))
304 error("bad delimiter `%1'", optarg[0]);
305 else if (invalid_input_char(optarg[1]))
306 error("bad delimiter `%1'", optarg[1]);
308 start_delim = optarg[0];
309 end_delim = optarg[1];
317 if (strcmp(device, "ps:html") == 0) {
321 else if (strcmp(device, "MathML") == 0) {
322 output_format = mathml;
323 load_startup_file = 0;
325 else if (strcmp(device, "mathml:xhtml") == 0) {
327 output_format = mathml;
328 load_startup_file = 0;
333 if (!set_gsize(optarg))
334 error("invalid size `%1'", optarg);
339 if (sscanf(optarg, "%d", &n) == 1)
340 set_script_reduction(n);
342 error("bad size `%1'", optarg);
348 if (sscanf(optarg, "%d", &n) == 1)
351 error("bad size `%1'", optarg);
355 one_size_reduction_flag = 1;
358 warning("-D option is obsolete: use `set draw_lines 1' instead");
362 no_newline_in_delim_flag = 1;
364 case CHAR_MAX + 1: // --help
377 if (output_format == troff) {
378 printf(".if !'\\*(.T'%s' "
379 ".if !'\\*(.T'html' " // the html device uses `-Tps' to render
380 // equations as images
381 ".tm warning: %s should have been given a `-T\\*(.T' option\n",
382 device, program_name);
383 printf(".if '\\*(.T'html' "
385 ".tm warning: %s should have been given a `-Tps' option\n",
386 device, program_name);
387 printf(".if '\\*(.T'html' "
389 ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n",
392 if (load_startup_file) {
394 FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
404 for (int i = optind; i < argc; i++)
405 if (strcmp(argv[i], "-") == 0)
409 FILE *fp = fopen(argv[i], "r");
411 fatal("can't open `%1': %2", argv[i], strerror(errno));
413 do_file(fp, argv[i]);
417 if (ferror(stdout) || fflush(stdout) < 0)
418 fatal("output error");