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/>. */
23 extern "C" const char *Version_string;
26 char *graphname; // the picture box name in TeX mode
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 transparently
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)
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));
315 normalize_for_lf(fn);
316 current_filename = fn.contents();
317 out->set_location(current_filename, 1);
319 enum { START, MIDDLE, HAD_DOT, HAD_P, HAD_PS, HAD_l, HAD_lf } state = START;
322 while (invalid_input_char(c)) {
323 error("invalid input character code %1", int(c));
352 else if (lf_flag && c == 'l')
381 if (c == ' ' || c == '\n' || compatible_flag) {
387 fputs(".PS", stdout);
408 if (c == ' ' || c == '\n' || compatible_flag) {
419 interpret_lf_args(line.contents());
420 printf(".lf%s", line.contents());
424 fputs(".lf", stdout);
440 fputs(".\n", stdout);
443 fputs(".P\n", stdout);
446 fputs(".PS\n", stdout);
449 fputs(".l\n", stdout);
452 fputs(".lf\n", stdout);
460 void do_whole_file(const char *filename)
462 // Do not set current_filename.
464 if (strcmp(filename, "-") == 0)
468 fp = fopen(filename, "r");
470 fatal("can't open '%1': %2", filename, strerror(errno));
472 lex_init(new file_input(fp, filename));
480 void usage(FILE *stream)
482 fprintf(stream, "usage: %s [ -nvCSU ] [ filename ... ]\n", program_name);
484 fprintf(stream, " %s -t [ -cvzCSU ] [ filename ... ]\n", program_name);
487 fprintf(stream, " %s -f [ -v ] [ filename ]\n", program_name);
491 #if defined(__MSDOS__) || defined(__EMX__)
492 static char *fix_program_name(char *arg, char *dflt)
496 char *prog = strchr(arg, '\0');
501 if (strchr("\\/:", *prog)) {
506 char *ext = strchr(prog, '.');
509 for (char *p = prog; *p; p++)
510 if ('A' <= *p && *p <= 'Z')
511 *p = 'a' + (*p - 'A');
514 #endif /* __MSDOS__ || __EMX__ */
516 int main(int argc, char **argv)
518 setlocale(LC_NUMERIC, "C");
519 #if defined(__MSDOS__) || defined(__EMX__)
520 argv[0] = fix_program_name(argv[0], "pic");
521 #endif /* __MSDOS__ || __EMX__ */
522 program_name = argv[0];
523 static char stderr_buf[BUFSIZ];
524 setbuf(stderr, stderr_buf);
531 int whole_file_flag = 0;
534 static const struct option long_options[] = {
535 { "help", no_argument, 0, CHAR_MAX + 1 },
536 { "version", no_argument, 0, 'v' },
539 while ((opt = getopt_long(argc, argv, "T:CDSUtcvnxzpf", long_options, NULL))
559 fatal("fig support not included");
563 driver_extension_flag = 0;
567 warning("-%1 option is obsolete", char(opt));
573 fatal("TeX support not included");
580 fatal("TeX support not included");
585 printf("GNU pic (groff) version %s\n", Version_string);
590 // zero length lines will be printed as dots
591 zero_length_line_flag++;
593 case CHAR_MAX + 1: // --help
607 out = make_tpic_output();
611 out = make_tex_output();
619 out = make_fig_output();
623 out = make_troff_output();
624 printf(".if !dPS .ds PS\n"
625 ".if !dPE .ds PE\n");
628 if (whole_file_flag) {
631 else if (argc - optind > 1) {
635 do_whole_file(argv[optind]);
642 for (int i = optind; i < argc; i++)
648 if (ferror(stdout) || fflush(stdout) < 0)
649 fatal("output error");
650 return had_parse_error;