2 /* Copyright (C) 1989-1992, 2000, 2001, 2002, 2003
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. */
25 extern "C" const char *Version_string;
28 char *graphname; // the picture box name in TeX mode
31 int zero_length_line_flag = 0;
32 // Non-zero means we're using a groff driver.
33 int driver_extension_flag = 1;
34 int compatible_flag = 0;
36 int command_char = '.'; // the character that introduces lines
37 // that should be passed through tranparently
38 static int lf_flag = 1; // non-zero if we should attempt to understand
39 // lines beginning with `.lf'
41 // Non-zero means a parse error was encountered.
42 static int had_parse_error = 0;
44 void do_file(const char *filename);
46 class top_input : public input {
56 int get_location(const char **, int *);
59 top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
61 push_back[0] = push_back[1] = push_back[2] = EOF;
62 start_lineno = current_lineno;
69 if (push_back[2] != EOF) {
74 else if (push_back[1] != EOF) {
79 else if (push_back[0] != EOF) {
85 while (invalid_input_char(c)) {
86 error("invalid input character code %1", int(c));
90 if (bol && c == '.') {
94 if (c == 'F' || c == 'E') {
98 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
100 flyback_flag = c == 'F';
111 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
139 error("end of file before .PE or .PF");
140 error_with_file_and_line(current_filename, start_lineno - 1,
146 int top_input::peek()
150 if (push_back[2] != EOF)
152 if (push_back[1] != EOF)
154 if (push_back[0] != EOF)
157 while (invalid_input_char(c)) {
158 error("invalid input character code %1", int(c));
162 if (bol && c == '.') {
166 if (c == 'F' || c == 'E') {
170 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
172 flyback_flag = c == 'F';
184 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
214 int top_input::get_location(const char **filenamep, int *linenop)
216 *filenamep = current_filename;
217 *linenop = current_lineno;
221 void do_picture(FILE *fp)
226 graphname = strsave("graph"); // default picture name in TeX mode
227 while ((c = getc(fp)) == ' ')
231 while ((c = getc(fp)) == ' ')
233 while (c != EOF && c != ' ' && c != '\n') {
240 } while (c != EOF && c != '\n');
244 if (filename.length() == 0)
245 error("missing filename after `<'");
248 const char *old_filename = current_filename;
249 int old_lineno = current_lineno;
250 // filenames must be permanent
251 do_file(strsave(filename.contents()));
252 current_filename = old_filename;
253 current_lineno = old_lineno;
255 out->set_location(current_filename, current_lineno);
258 out->set_location(current_filename, current_lineno);
272 switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
282 out->set_desired_width_height(wid, ht);
283 out->set_args(start_line.contents());
284 lex_init(new top_input(fp));
287 lex_error("giving up on this picture");
292 // skip the rest of the .PF/.PE line
293 while ((c = getc(fp)) != EOF && c != '\n')
297 out->set_location(current_filename, current_lineno);
301 void do_file(const char *filename)
304 if (strcmp(filename, "-") == 0)
308 fp = fopen(filename, "r");
311 fatal("can't open `%1': %2", filename, strerror(errno));
314 out->set_location(filename, 1);
315 current_filename = filename;
317 enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
346 else if (lf_flag && c == 'l')
375 if (c == ' ' || c == '\n' || compatible_flag) {
381 fputs(".PS", stdout);
402 if (c == ' ' || c == '\n' || compatible_flag) {
413 interpret_lf_args(line.contents());
414 printf(".lf%s", line.contents());
418 fputs(".lf", stdout);
434 fputs(".\n", stdout);
437 fputs(".P\n", stdout);
440 fputs(".PS\n", stdout);
443 fputs(".l\n", stdout);
446 fputs(".lf\n", stdout);
454 void do_whole_file(const char *filename)
456 // Do not set current_filename.
458 if (strcmp(filename, "-") == 0)
462 fp = fopen(filename, "r");
464 fatal("can't open `%1': %2", filename, strerror(errno));
466 lex_init(new file_input(fp, filename));
474 void usage(FILE *stream)
476 fprintf(stream, "usage: %s [ -nvC ] [ filename ... ]\n", program_name);
478 fprintf(stream, " %s -t [ -cvzC ] [ filename ... ]\n", program_name);
481 fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name);
485 #if defined(__MSDOS__) || defined(__EMX__)
486 static char *fix_program_name(char *arg, char *dflt)
490 char *prog = strchr(arg, '\0');
495 if (strchr("\\/:", *prog)) {
500 char *ext = strchr(prog, '.');
503 for (char *p = prog; *p; p++)
504 if ('A' <= *p && *p <= 'Z')
505 *p = 'a' + (*p - 'A');
508 #endif /* __MSDOS__ || __EMX__ */
510 int main(int argc, char **argv)
512 setlocale(LC_NUMERIC, "C");
513 #if defined(__MSDOS__) || defined(__EMX__)
514 argv[0] = fix_program_name(argv[0], "pic");
515 #endif /* __MSDOS__ || __EMX__ */
516 program_name = argv[0];
517 static char stderr_buf[BUFSIZ];
518 setbuf(stderr, stderr_buf);
525 int whole_file_flag = 0;
528 static const struct option long_options[] = {
529 { "help", no_argument, 0, CHAR_MAX + 1 },
530 { "version", no_argument, 0, 'v' },
533 while ((opt = getopt_long(argc, argv, "T:CDSUtcvnxzpf", long_options, NULL))
553 fatal("fig support not included");
557 driver_extension_flag = 0;
561 warning("-%1 option is obsolete", char(opt));
567 fatal("TeX support not included");
574 fatal("TeX support not included");
579 printf("GNU pic (groff) version %s\n", Version_string);
584 // zero length lines will be printed as dots
585 zero_length_line_flag++;
587 case CHAR_MAX + 1: // --help
601 out = make_tpic_output();
605 out = make_tex_output();
613 out = make_fig_output();
616 out = make_troff_output();
618 if (whole_file_flag) {
621 else if (argc - optind > 1) {
625 do_whole_file(argv[optind]);
632 for (int i = optind; i < argc; i++)
638 if (ferror(stdout) || fflush(stdout) < 0)
639 fatal("output error");
640 return had_parse_error;