2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2005, 2007
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include "stringclass.h"
25 #include "file_case.h"
26 #include "searchpath.h"
27 #include "macropath.h"
32 #define STARTUP_FILE "eqnrc"
35 extern "C" const char *Version_string
;
37 static char *delim_search (char *, int);
38 static int inline_equation (file_case
*, string
&, string
&);
40 char start_delim
= '\0';
41 char end_delim
= '\0';
45 int one_size_reduction_flag
= 0;
46 int compatible_flag
= 0;
47 int no_newline_in_delim_flag
= 0;
50 eqnmode_t output_format
;
52 int read_line(file_case
*fcp
, string
*p
)
56 while ((c
= fcp
->get_c()) != EOF
) {
57 if (!invalid_input_char(c
))
60 error("invalid input character code `%1'", c
);
65 return p
->length() > 0;
68 void do_file(file_case
*fcp
, const char *filename
)
72 if (output_format
== troff
)
73 printf(".lf 1 %s\n", filename
);
74 current_filename
= filename
;
76 while (read_line(fcp
, &linebuf
)) {
77 if (linebuf
.length() >= 4
78 && linebuf
[0] == '.' && linebuf
[1] == 'l' && linebuf
[2] == 'f'
79 && (linebuf
[3] == ' ' || linebuf
[3] == '\n' || compatible_flag
)) {
80 put_string(linebuf
, stdout
);
82 if (interpret_lf_args(linebuf
.contents() + 3))
85 else if (linebuf
.length() >= 4
89 && (linebuf
[3] == ' ' || linebuf
[3] == '\n'
90 || compatible_flag
)) {
91 put_string(linebuf
, stdout
);
92 int start_lineno
= current_lineno
+ 1;
95 if (!read_line(fcp
, &linebuf
))
96 fatal("end of file before .EN");
97 if (linebuf
.length() >= 3 && linebuf
[0] == '.' && linebuf
[1] == 'E') {
99 && (linebuf
.length() == 3 || linebuf
[3] == ' '
100 || linebuf
[3] == '\n' || compatible_flag
))
102 else if (linebuf
[2] == 'Q' && linebuf
.length() > 3
103 && (linebuf
[3] == ' ' || linebuf
[3] == '\n'
111 init_lex(str
.contents(), current_filename
, start_lineno
);
115 restore_compatibility();
117 if (output_format
== mathml
)
120 printf(".lf %d\n", current_lineno
- 1);
123 if (output_format
== troff
)
124 printf(".lf %d\n", current_lineno
);
125 put_string(linebuf
, stdout
);
127 else if (start_delim
!= '\0' && linebuf
.search(start_delim
) >= 0
128 && inline_equation(fcp
, linebuf
, str
))
131 put_string(linebuf
, stdout
);
133 current_filename
= 0;
137 // Handle an inline equation. Return 1 if it was an inline equation,
139 static int inline_equation(file_case
*fcp
, string
&linebuf
, string
&str
)
142 char *ptr
= &linebuf
[0];
143 char *start
= delim_search(ptr
, start_delim
);
145 // It wasn't a delimiter after all.
146 linebuf
.set_length(linebuf
.length() - 1); // strip the '\0'
152 if (no_newline_in_delim_flag
&& strchr(start
+ 1, end_delim
) == 0) {
153 error("missing `%1'", end_delim
);
154 char *nl
= strchr(start
+ 1, '\n');
160 int start_lineno
= current_lineno
;
166 char *end
= strchr(ptr
, end_delim
);
174 if (!read_line(fcp
, &linebuf
))
175 fatal("unterminated `%1' at line %2, looking for `%3'",
176 start_delim
, start_lineno
, end_delim
);
181 if (output_format
== troff
&& html
) {
182 printf(".as1 %s ", LINE_STRING
);
183 html_begin_suppress();
186 init_lex(str
.contents(), current_filename
, start_lineno
);
188 if (output_format
== troff
&& html
) {
189 printf(".as1 %s ", LINE_STRING
);
193 if (output_format
== mathml
)
196 /* skip leading spaces */
197 while ((*ptr
!= '\0') && (*ptr
== ' '))
200 start
= delim_search(ptr
, start_delim
);
202 char *nl
= strchr(ptr
, '\n');
209 restore_compatibility();
210 if (output_format
== troff
)
211 printf(".lf %d\n", current_lineno
);
213 if (output_format
== troff
)
214 printf(".lf %d\n", current_lineno
+ 1);
218 /* Search for delim. Skip over number register and string names etc. */
220 static char *delim_search(char *ptr
, int delim
)
225 if (*ptr
++ == '\\') {
237 if (*++ptr
!= '\\' && *ptr
!= '\0'
238 && *++ptr
!= '\\' && *ptr
!= '\0')
242 while (*++ptr
!= '\0')
265 void usage(FILE *stream
)
268 "usage: %s [ -rvDCNR ] -dxx -fn -sn -pn -mn -Mdir -Ts [ files ... ]\n",
272 int main(int argc
, char **argv
)
274 program_name
= argv
[0];
275 static char stderr_buf
[BUFSIZ
];
276 setbuf(stderr
, stderr_buf
);
278 int load_startup_file
= 1;
279 static const struct option long_options
[] = {
280 { "help", no_argument
, 0, CHAR_MAX
+ 1 },
281 { "version", no_argument
, 0, 'v' },
284 while ((opt
= getopt_long(argc
, argv
, "DCRvd:f:p:s:m:T:M:rN", long_options
,
291 case 'R': // don't load eqnrc
292 load_startup_file
= 0;
295 config_macro_path
.command_line_dir(optarg
);
298 printf("GNU eqn (groff) version %s\n", Version_string
);
302 if (optarg
[0] == '\0' || optarg
[1] == '\0')
303 error("-d requires two character argument");
304 else if (invalid_input_char(optarg
[0]))
305 error("bad delimiter `%1'", optarg
[0]);
306 else if (invalid_input_char(optarg
[1]))
307 error("bad delimiter `%1'", optarg
[1]);
309 start_delim
= optarg
[0];
310 end_delim
= optarg
[1];
318 if (strcmp(device
, "ps:html") == 0) {
322 else if (strcmp(device
, "MathML") == 0) {
323 output_format
= mathml
;
324 load_startup_file
= 0;
326 else if (strcmp(device
, "mathml:xhtml") == 0) {
328 output_format
= mathml
;
329 load_startup_file
= 0;
334 if (!set_gsize(optarg
))
335 error("invalid size `%1'", optarg
);
340 if (sscanf(optarg
, "%d", &n
) == 1)
341 set_script_reduction(n
);
343 error("bad size `%1'", optarg
);
349 if (sscanf(optarg
, "%d", &n
) == 1)
352 error("bad size `%1'", optarg
);
356 one_size_reduction_flag
= 1;
359 warning("-D option is obsolete: use `set draw_lines 1' instead");
363 no_newline_in_delim_flag
= 1;
365 case CHAR_MAX
+ 1: // --help
378 if (output_format
== troff
) {
379 printf(".if !'\\*(.T'%s' "
380 ".if !'\\*(.T'html' " // the html device uses `-Tps' to render
381 // equations as images
382 ".tm warning: %s should have been given a `-T\\*(.T' option\n",
383 device
, program_name
);
384 printf(".if '\\*(.T'html' "
386 ".tm warning: %s should have been given a `-Tps' option\n",
387 device
, program_name
);
388 printf(".if '\\*(.T'html' "
390 ".tm warning: (it is advisable to invoke groff via: groff -Thtml -e)\n",
395 if (load_startup_file
) {
396 if ((fcp
= config_macro_path
.open_file(STARTUP_FILE
, fcp
->fc_const_path
)
398 do_file(fcp
, fcp
->path());
405 for (; i
< argc
; ++i
) {
406 if (!strcmp(argv
[i
], "-")) {
408 fcp
= new file_case(stdin
, "stdin",
409 fcp
->fc_dont_close
| fcp
->fc_const_path
/*| fcp->fc_have_stdio*/);
412 fcp
= file_case::muxer(argv
[i
]);
414 fatal("can't open `%1': %2", argv
[i
], strerror(errno
));
415 do_file(fcp
, argv
[i
]);
419 if (ferror(stdout
) || fflush(stdout
) < 0)
420 fatal("output error");