2 /* Copyright (C) 1989-1992, 2000, 2001, 2002, 2003, 2006, 2009
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 3 of the License, or
11 (at your option) any later version.
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
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 extern "C" const char *Version_string;
27 char *graphname; // the picture box name in TeX mode
30 int zero_length_line_flag = 0;
31 // Non-zero means we're using a groff driver.
32 int driver_extension_flag = 1;
33 int compatible_flag = 0;
35 int command_char = '.'; // the character that introduces lines
36 // that should be passed through transparently
37 static int lf_flag = 1; // non-zero if we should attempt to understand
38 // lines beginning with `.lf'
40 // Non-zero means a parse error was encountered.
41 static int had_parse_error = 0;
43 void do_file(const char *filename);
45 class top_input : public input {
55 int get_location(const char **, int *);
58 top_input::top_input(FILE *p) : fp(p), bol(1), eof(0)
60 push_back[0] = push_back[1] = push_back[2] = EOF;
61 start_lineno = current_lineno;
68 if (push_back[2] != EOF) {
73 else if (push_back[1] != EOF) {
78 else if (push_back[0] != EOF) {
84 while (invalid_input_char(c)) {
85 error("invalid input character code %1", int(c));
89 if (bol && c == '.') {
93 if (c == 'F' || c == 'E') {
97 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
99 flyback_flag = c == 'F';
110 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
138 error("end of file before .PE or .PF");
139 error_with_file_and_line(current_filename, start_lineno - 1,
145 int top_input::peek()
149 if (push_back[2] != EOF)
151 if (push_back[1] != EOF)
153 if (push_back[0] != EOF)
156 while (invalid_input_char(c)) {
157 error("invalid input character code %1", int(c));
161 if (bol && c == '.') {
165 if (c == 'F' || c == 'E') {
169 if (d == EOF || d == ' ' || d == '\n' || compatible_flag) {
171 flyback_flag = c == 'F';
183 if (c == EOF || c == ' ' || c == '\n' || compatible_flag) {
213 int top_input::get_location(const char **filenamep, int *linenop)
215 *filenamep = current_filename;
216 *linenop = current_lineno;
220 void do_picture(FILE *fp)
225 graphname = strsave("graph"); // default picture name in TeX mode
226 while ((c = getc(fp)) == ' ')
230 while ((c = getc(fp)) == ' ')
232 while (c != EOF && c != ' ' && c != '\n') {
239 } while (c != EOF && c != '\n');
243 if (filename.length() == 0)
244 error("missing filename after `<'");
247 const char *old_filename = current_filename;
248 int old_lineno = current_lineno;
249 // filenames must be permanent
250 do_file(strsave(filename.contents()));
251 current_filename = old_filename;
252 current_lineno = old_lineno;
254 out->set_location(current_filename, current_lineno);
257 out->set_location(current_filename, current_lineno);
271 switch (sscanf(&start_line[0], "%lf %lf", &wid, &ht)) {
281 out->set_desired_width_height(wid, ht);
282 out->set_args(start_line.contents());
283 lex_init(new top_input(fp));
286 lex_error("giving up on this picture");
291 // skip the rest of the .PF/.PE line
292 while ((c = getc(fp)) != EOF && c != '\n')
296 out->set_location(current_filename, current_lineno);
300 void do_file(const char *filename)
303 if (strcmp(filename, "-") == 0)
307 fp = fopen(filename, "r");
310 fatal("can't open `%1': %2", filename, strerror(errno));
313 out->set_location(filename, 1);
314 current_filename = filename;
316 enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
345 else if (lf_flag && c == 'l')
374 if (c == ' ' || c == '\n' || compatible_flag) {
380 fputs(".PS", stdout);
401 if (c == ' ' || c == '\n' || compatible_flag) {
412 interpret_lf_args(line.contents());
413 printf(".lf%s", line.contents());
417 fputs(".lf", stdout);
433 fputs(".\n", stdout);
436 fputs(".P\n", stdout);
439 fputs(".PS\n", stdout);
442 fputs(".l\n", stdout);
445 fputs(".lf\n", stdout);
453 void do_whole_file(const char *filename)
455 // Do not set current_filename.
457 if (strcmp(filename, "-") == 0)
461 fp = fopen(filename, "r");
463 fatal("can't open `%1': %2", filename, strerror(errno));
465 lex_init(new file_input(fp, filename));
473 void usage(FILE *stream)
475 fprintf(stream, "usage: %s [ -nvCSU ] [ filename ... ]\n", program_name);
477 fprintf(stream, " %s -t [ -cvzCSU ] [ filename ... ]\n", program_name);
480 fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name);
484 #if defined(__MSDOS__) || defined(__EMX__)
485 static char *fix_program_name(char *arg, char *dflt)
489 char *prog = strchr(arg, '\0');
494 if (strchr("\\/:", *prog)) {
499 char *ext = strchr(prog, '.');
502 for (char *p = prog; *p; p++)
503 if ('A' <= *p && *p <= 'Z')
504 *p = 'a' + (*p - 'A');
507 #endif /* __MSDOS__ || __EMX__ */
509 int main(int argc, char **argv)
511 setlocale(LC_NUMERIC, "C");
512 #if defined(__MSDOS__) || defined(__EMX__)
513 argv[0] = fix_program_name(argv[0], "pic");
514 #endif /* __MSDOS__ || __EMX__ */
515 program_name = argv[0];
516 static char stderr_buf[BUFSIZ];
517 setbuf(stderr, stderr_buf);
524 int whole_file_flag = 0;
527 static const struct option long_options[] = {
528 { "help", no_argument, 0, CHAR_MAX + 1 },
529 { "version", no_argument, 0, 'v' },
532 while ((opt = getopt_long(argc, argv, "T:CDSUtcvnxzpf", long_options, NULL))
552 fatal("fig support not included");
556 driver_extension_flag = 0;
560 warning("-%1 option is obsolete", char(opt));
566 fatal("TeX support not included");
573 fatal("TeX support not included");
578 printf("GNU pic (groff) version %s\n", Version_string);
583 // zero length lines will be printed as dots
584 zero_length_line_flag++;
586 case CHAR_MAX + 1: // --help
600 out = make_tpic_output();
604 out = make_tex_output();
612 out = make_fig_output();
615 out = make_troff_output();
617 if (whole_file_flag) {
620 else if (argc - optind > 1) {
624 do_whole_file(argv[optind]);
631 for (int i = optind; i < argc; i++)
637 if (ferror(stdout) || fflush(stdout) < 0)
638 fatal("output error");
639 return had_parse_error;