2 /* Copyright (C) 1989-1992, 2000, 2001, 2002 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 2, or (at your option) any later
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 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. */
24 extern "C" const char *Version_string;
29 int zero_length_line_flag = 0;
30 // Non-zero means we're using a groff driver.
31 int driver_extension_flag = 1;
32 int compatible_flag = 0;
34 int command_char = '.'; // the character that introduces lines
35 // that should be passed through tranparently
36 static int lf_flag = 1; // non-zero if we should attempt to understand
37 // lines beginning with `.lf'
39 // Non-zero means a parse error was encountered.
40 static int had_parse_error = 0;
42 void do_file(const char *filename);
44 class top_input : public input {
54 int get_location(const char **, int *);
57 top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
59 push_back[0] = push_back[1] = push_back[2] = EOF;
60 start_lineno = current_lineno;
67 if (push_back[2] != EOF) {
72 else if (push_back[1] != EOF) {
77 else if (push_back[0] != EOF) {
83 while (invalid_input_char(c)) {
84 error("invalid input character code %1", int(c));
88 if (bol && c == '.') {
92 if (c == 'F' || c == 'E') {
96 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
98 flyback_flag = c == 'F';
109 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
137 error("end of file before .PE or .PF");
138 error_with_file_and_line(current_filename, start_lineno - 1,
144 int top_input::peek()
148 if (push_back[2] != EOF)
150 if (push_back[1] != EOF)
152 if (push_back[0] != EOF)
155 while (invalid_input_char(c)) {
156 error("invalid input character code %1", int(c));
160 if (bol && c == '.') {
164 if (c == 'F' || c == 'E') {
168 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
170 flyback_flag = c == 'F';
182 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
212 int top_input::get_location(const char **filenamep, int *linenop)
214 *filenamep = current_filename;
215 *linenop = current_lineno;
219 void do_picture(FILE *fp)
223 while ((c = getc(fp)) == ' ')
227 while ((c = getc(fp)) == ' ')
229 while (c != EOF && c != ' ' && c != '\n') {
236 } while (c != EOF && c != '\n');
240 if (filename.length() == 0)
241 error("missing filename after `<'");
244 const char *old_filename = current_filename;
245 int old_lineno = current_lineno;
246 // filenames must be permanent
247 do_file(strsave(filename.contents()));
248 current_filename = old_filename;
249 current_lineno = old_lineno;
251 out->set_location(current_filename, current_lineno);
254 out->set_location(current_filename, current_lineno);
268 switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
278 out->set_desired_width_height(wid, ht);
279 out->set_args(start_line.contents());
280 lex_init(new top_input(fp));
283 lex_error("giving up on this picture");
288 // skip the rest of the .PF/.PE line
289 while ((c = getc(fp)) != EOF && c != '\n')
293 out->set_location(current_filename, current_lineno);
297 void do_file(const char *filename)
300 if (strcmp(filename, "-") == 0)
304 fp = fopen(filename, "r");
306 fatal("can't open `%1': %2", filename, strerror(errno));
308 out->set_location(filename, 1);
309 current_filename = filename;
311 enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
340 else if (lf_flag && c == 'l')
369 if (c == ' ' || c == '\n' || compatible_flag) {
375 fputs(".PS", stdout);
396 if (c == ' ' || c == '\n' || compatible_flag) {
407 interpret_lf_args(line.contents());
408 printf(".lf%s", line.contents());
412 fputs(".lf", stdout);
428 fputs(".\n", stdout);
431 fputs(".P\n", stdout);
434 fputs(".PS\n", stdout);
437 fputs(".l\n", stdout);
440 fputs(".lf\n", stdout);
448 void do_whole_file(const char *filename)
450 // Do not set current_filename.
452 if (strcmp(filename, "-") == 0)
456 fp = fopen(filename, "r");
458 fatal("can't open `%1': %2", filename, strerror(errno));
460 lex_init(new file_input(fp, filename));
468 void usage(FILE *stream)
470 fprintf(stream, "usage: %s [ -nvC ] [ filename ... ]\n", program_name);
472 fprintf(stream, " %s -t [ -cvzC ] [ filename ... ]\n", program_name);
475 fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name);
479 #if defined(__MSDOS__) || defined(__EMX__)
480 static char *fix_program_name(char *arg, char *dflt)
484 char *prog = strchr(arg, '\0');
489 if (strchr("\\/:", *prog)) {
494 char *ext = strchr(prog, '.');
497 for (char *p = prog; *p; p++)
498 if ('A' <= *p && *p <= 'Z')
499 *p = 'a' + (*p - 'A');
502 #endif /* __MSDOS__ || __EMX__ */
504 int main(int argc, char **argv)
506 #if defined(__MSDOS__) || defined(__EMX__)
507 argv[0] = fix_program_name(argv[0], "pic");
508 #endif /* __MSDOS__ || __EMX__ */
509 program_name = argv[0];
510 static char stderr_buf[BUFSIZ];
511 setbuf(stderr, stderr_buf);
518 int whole_file_flag = 0;
521 static const struct option long_options[] = {
522 { "help", no_argument, 0, CHAR_MAX + 1 },
523 { "version", no_argument, 0, 'v' },
526 while ((opt = getopt_long(argc, argv, "T:CDSUtcvnxzpf", long_options, NULL))
546 fatal("fig support not included");
550 driver_extension_flag = 0;
554 warning("-%1 option is obsolete", char(opt));
560 fatal("TeX support not included");
567 fatal("TeX support not included");
572 printf("GNU pic (groff) version %s\n", Version_string);
577 // zero length lines will be printed as dots
578 zero_length_line_flag++;
580 case CHAR_MAX + 1: // --help
594 out = make_tpic_output();
598 out = make_tex_output();
606 out = make_fig_output();
609 out = make_troff_output();
611 if (whole_file_flag) {
614 else if (argc - optind > 1) {
618 do_whole_file(argv[optind]);
625 for (int i = optind; i < argc; i++)
631 if (ferror(stdout) || fflush(stdout) < 0)
632 fatal("output error");
633 return had_parse_error;