2 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
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 3 of the License, or
10 (at your option) any later version.
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
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "stringclass.h"
23 #include "searchpath.h"
24 #include "macropath.h"
30 #define STARTUP_FILE "eqnrc"
33 extern "C" const char *Version_string;
35 static char *delim_search (char *, int);
36 static int inline_equation (FILE *, string &, string &);
38 char start_delim = '\0';
39 char end_delim = '\0';
43 int one_size_reduction_flag = 0;
44 int compatible_flag = 0;
45 int no_newline_in_delim_flag = 0;
48 eqnmode_t output_format;
50 int read_line(FILE *fp, string *p)
54 while ((c = getc(fp)) != EOF) {
55 if (!invalid_input_char(c))
58 error("invalid input character code '%1'", c);
63 return p->length() > 0;
66 void do_file(FILE *fp, const char *filename)
73 current_filename = fn.contents();
74 if (output_format == troff)
75 printf(".lf 1 %s\n", current_filename);
77 while (read_line(fp, &linebuf)) {
78 if (linebuf.length() >= 4
79 && linebuf[0] == '.' && linebuf[1] == 'l' && linebuf[2] == 'f'
80 && (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
81 put_string(linebuf, stdout);
83 if (interpret_lf_args(linebuf.contents() + 3))
86 else if (linebuf.length() >= 4
90 && (linebuf[3] == ' ' || linebuf[3] == '\n'
91 || compatible_flag)) {
92 put_string(linebuf, stdout);
93 int start_lineno = current_lineno + 1;
96 if (!read_line(fp, &linebuf))
97 fatal("end of file before .EN");
98 if (linebuf.length() >= 3 && linebuf[0] == '.' && linebuf[1] == 'E') {
100 && (linebuf.length() == 3 || linebuf[3] == ' '
101 || linebuf[3] == '\n' || compatible_flag))
103 else if (linebuf[2] == 'Q' && linebuf.length() > 3
104 && (linebuf[3] == ' ' || linebuf[3] == '\n'
112 init_lex(str.contents(), current_filename, start_lineno);
116 restore_compatibility();
117 if (non_empty_flag) {
118 if (output_format == mathml)
121 printf(".lf %d\n", current_lineno - 1);
125 if (output_format == troff)
126 printf(".lf %d\n", current_lineno);
127 put_string(linebuf, stdout);
129 else if (start_delim != '\0' && linebuf.search(start_delim) >= 0
130 && inline_equation(fp, linebuf, str))
133 put_string(linebuf, stdout);
135 current_filename = 0;
139 // Handle an inline equation. Return 1 if it was an inline equation,
141 static int inline_equation(FILE *fp, string &linebuf, string &str)
144 char *ptr = &linebuf[0];
145 char *start = delim_search(ptr, start_delim);
147 // It wasn't a delimiter after all.
148 linebuf.set_length(linebuf.length() - 1); // strip the '\0'
154 if (no_newline_in_delim_flag && strchr(start + 1, end_delim) == 0) {
155 error("missing '%1'", end_delim);
156 char *nl = strchr(start + 1, '\n');
162 int start_lineno = current_lineno;
168 char *end = strchr(ptr, end_delim);
176 if (!read_line(fp, &linebuf))
177 fatal("unterminated '%1' at line %2, looking for '%3'",
178 start_delim, start_lineno, end_delim);
183 if (output_format == troff && html) {
184 printf(".as1 %s ", LINE_STRING);
185 html_begin_suppress();
188 init_lex(str.contents(), current_filename, start_lineno);
190 if (output_format == troff && html) {
191 printf(".as1 %s ", LINE_STRING);
195 if (output_format == mathml)
198 /* skip leading spaces */
199 while ((*ptr != '\0') && (*ptr == ' '))
202 start = delim_search(ptr, start_delim);
204 char *nl = strchr(ptr, '\n');
211 restore_compatibility();
212 if (output_format == troff)
213 printf(".lf %d\n", current_lineno);
215 if (output_format == troff)
216 printf(".lf %d\n", current_lineno + 1);
220 /* Search for delim. Skip over number register and string names etc. */
222 static char *delim_search(char *ptr, int delim)
227 if (*ptr++ == '\\') {
239 if (*++ptr != '\\' && *ptr != '\0'
240 && *++ptr != '\\' && *ptr != '\0')
244 while (*++ptr != '\0')
267 void usage(FILE *stream)
270 "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
274 int main(int argc, char **argv)
276 program_name = argv[0];
277 static char stderr_buf[BUFSIZ];
278 setbuf(stderr, stderr_buf);
280 int load_startup_file = 1;
281 static const struct option long_options[] = {
282 { "help", no_argument, 0, CHAR_MAX + 1 },
283 { "version", no_argument, 0, 'v' },
286 while ((opt = getopt_long(argc, argv, "DCRvd:f:p:s:m:T:M:rN", long_options,
293 case 'R': // don't load eqnrc
294 load_startup_file = 0;
297 config_macro_path.command_line_dir(optarg);
300 printf("GNU eqn (groff) version %s\n", Version_string);
304 if (optarg[0] == '\0' || optarg[1] == '\0')
305 error("-d requires two character argument");
306 else if (invalid_input_char(optarg[0]))
307 error("bad delimiter '%1'", optarg[0]);
308 else if (invalid_input_char(optarg[1]))
309 error("bad delimiter '%1'", optarg[1]);
311 start_delim = optarg[0];
312 end_delim = optarg[1];
320 if (strcmp(device, "ps:html") == 0) {
324 else if (strcmp(device, "MathML") == 0) {
325 output_format = mathml;
326 load_startup_file = 0;
328 else if (strcmp(device, "mathml:xhtml") == 0) {
330 output_format = mathml;
331 load_startup_file = 0;
336 if (!set_gsize(optarg))
337 error("invalid size '%1'", optarg);
342 if (sscanf(optarg, "%d", &n) == 1)
343 set_script_reduction(n);
345 error("bad size '%1'", optarg);
351 if (sscanf(optarg, "%d", &n) == 1)
354 error("bad size '%1'", optarg);
358 one_size_reduction_flag = 1;
361 warning("-D option is obsolete: use 'set draw_lines 1' instead");
365 no_newline_in_delim_flag = 1;
367 case CHAR_MAX + 1: // --help
380 printf(".if !dEQ .ds EQ\n"
381 ".if !dEN .ds EN\n");
382 if (output_format == troff) {
383 printf(".if !'\\*(.T'%s' "
384 ".if !'\\*(.T'html' " // the html device uses '-Tps' to render
385 // equations as images
386 ".tm warning: %s should have been given a '-T\\*(.T' option\n",
387 device, program_name);
388 printf(".if '\\*(.T'html' "
390 ".tm warning: %s should have been given a '-Tps' option\n",
391 device, program_name);
392 printf(".if '\\*(.T'html' "
394 ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n",
397 if (load_startup_file) {
399 FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
409 for (int i = optind; i < argc; i++)
410 if (strcmp(argv[i], "-") == 0)
414 FILE *fp = fopen(argv[i], "r");
416 fatal("can't open '%1': %2", argv[i], strerror(errno));
418 do_file(fp, argv[i]);
422 if (ferror(stdout) || fflush(stdout) < 0)
423 fatal("output error");