2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2000 - 2003, 2006
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
24 #include "pic-config.h"
26 #include "file_case.h"
33 char *graphname
; // the picture box name in TeX mode
36 int zero_length_line_flag
= 0;
37 // Non-zero means we're using a groff driver.
38 int driver_extension_flag
= 1;
39 int compatible_flag
= 0;
41 int command_char
= '.'; // the character that introduces lines
42 // that should be passed through transparently
43 static int lf_flag
= 1; // non-zero if we should attempt to understand
44 // lines beginning with `.lf'
46 // Non-zero means a parse error was encountered.
47 static int had_parse_error
= 0;
49 static void do_file(char const *filename
);
61 top_input(file_case
*);
64 int get_location(const char **, int *);
67 top_input::top_input(file_case
*fcp
) : _fcp(fcp
), bol(1), eof(0)
69 push_back
[0] = push_back
[1] = push_back
[2] = EOF
;
70 start_lineno
= current_lineno
;
77 if (push_back
[2] != EOF
) {
82 else if (push_back
[1] != EOF
) {
87 else if (push_back
[0] != EOF
) {
92 int c
= _fcp
->get_c();
93 while (invalid_input_char(c
)) {
94 error("invalid input character code %1", int(c
));
98 if (bol
&& c
== '.') {
102 if (c
== 'F' || c
== 'E') {
103 int d
= _fcp
->get_c();
106 if (d
== EOF
|| d
== ' ' || d
== '\n' || compatible_flag
) {
108 flyback_flag
= c
== 'F';
119 if (c
== EOF
|| c
== ' ' || c
== '\n' || compatible_flag
) {
147 error("end of file before .PE or .PF");
148 error_with_file_and_line(current_filename
, start_lineno
- 1,
154 int top_input::peek()
158 if (push_back
[2] != EOF
)
160 if (push_back
[1] != EOF
)
162 if (push_back
[0] != EOF
)
164 int c
= _fcp
->get_c();
165 while (invalid_input_char(c
)) {
166 error("invalid input character code %1", int(c
));
170 if (bol
&& c
== '.') {
174 if (c
== 'F' || c
== 'E') {
175 int d
= _fcp
->get_c();
178 if (d
== EOF
|| d
== ' ' || d
== '\n' || compatible_flag
) {
180 flyback_flag
= c
== 'F';
192 if (c
== EOF
|| c
== ' ' || c
== '\n' || compatible_flag
) {
222 int top_input::get_location(const char **filenamep
, int *linenop
)
224 *filenamep
= current_filename
;
225 *linenop
= current_lineno
;
229 void do_picture(file_case
*fcp
)
234 graphname
= strsave("graph"); // default picture name in TeX mode
235 while ((c
= fcp
->get_c()) == ' ')
239 while ((c
= fcp
->get_c()) == ' ')
241 while (c
!= EOF
&& c
!= ' ' && c
!= '\n') {
248 } while (c
!= EOF
&& c
!= '\n');
252 if (filename
.length() == 0)
253 error("missing filename after `<'");
256 const char *old_filename
= current_filename
;
257 int old_lineno
= current_lineno
;
258 // filenames must be permanent
259 do_file(strsave(filename
.contents()));
260 current_filename
= old_filename
;
261 current_lineno
= old_lineno
;
263 out
->set_location(current_filename
, current_lineno
);
266 out
->set_location(current_filename
, current_lineno
);
280 switch (sscanf(&start_line
[0], "%lf %lf", &wid
, &ht
)) {
290 out
->set_desired_width_height(wid
, ht
);
291 out
->set_args(start_line
.contents());
292 lex_init(new top_input(fcp
));
295 lex_error("giving up on this picture");
300 // skip the rest of the .PF/.PE line
301 while ((c
= fcp
->get_c()) != EOF
&& c
!= '\n')
305 out
->set_location(current_filename
, current_lineno
);
310 do_file(char const *filename
)
313 if ((fcp
= file_case::muxer(filename
)) == NULL
) {
314 assert(strcmp(filename
, "-"));
316 fatal("can't open `%1': %2", filename
, strerror(errno
));
319 out
->set_location(filename
, 1);
320 current_filename
= filename
;
322 enum { START
, MIDDLE
, HAD_DOT
, HAD_P
, HAD_PS
, HAD_l
, HAD_lf
} state
= START
;
324 int c
= fcp
->get_c();
325 while (invalid_input_char(c
)) {
326 error("invalid input character code %1", int(c
));
355 else if (lf_flag
&& c
== 'l')
384 if (c
== ' ' || c
== '\n' || compatible_flag
) {
390 fputs(".PS", stdout
);
411 if (c
== ' ' || c
== '\n' || compatible_flag
) {
422 interpret_lf_args(line
.contents());
423 printf(".lf%s", line
.contents());
427 fputs(".lf", stdout
);
443 fputs(".\n", stdout
);
446 fputs(".P\n", stdout
);
449 fputs(".PS\n", stdout
);
452 fputs(".l\n", stdout
);
455 fputs(".lf\n", stdout
);
463 void do_whole_file(const char *filename
)
465 // Do not set current_filename.
467 if ((fcp
= file_case::muxer(filename
)) == NULL
) {
468 assert(strcmp(filename
, "-"));
469 fatal("can't open `%1': %2", filename
, strerror(errno
));
472 lex_init(new file_input(fcp
, filename
));
482 void usage(FILE *stream
)
484 fprintf(stream
, "Synopsis: %s [ -nvCSU ] [ filename ... ]\n", program_name
);
486 fprintf(stream
, " %s -t [ -cvzCSU ] [ filename ... ]\n", program_name
);
489 fprintf(stream
, " %s -f [ -v ] [ filename ]\n", program_name
);
493 #if defined(__MSDOS__) || defined(__EMX__) /* FIXME */
494 static char *fix_program_name(char *arg
, char *dflt
) /* FIXME: if, then lib! */
498 char *prog
= strchr(arg
, '\0');
503 if (strchr("\\/:", *prog
)) {
508 char *ext
= strchr(prog
, '.');
511 for (char *p
= prog
; *p
; p
++)
512 if ('A' <= *p
&& *p
<= 'Z')
513 *p
= 'a' + (*p
- 'A');
516 #endif /* __MSDOS__ || __EMX__ */
518 int main(int argc
, char **argv
)
520 setlocale(LC_NUMERIC
, "C");
521 #if defined(__MSDOS__) || defined(__EMX__)
522 argv
[0] = fix_program_name(argv
[0], "pic");
523 #endif /* __MSDOS__ || __EMX__ */
524 program_name
= argv
[0];
525 static char stderr_buf
[BUFSIZ
];
526 setbuf(stderr
, stderr_buf
);
533 int whole_file_flag
= 0;
536 static const struct option long_options
[] = {
537 { "help", no_argument
, 0, CHAR_MAX
+ 1 },
538 { "version", no_argument
, 0, 'v' },
541 while ((opt
= getopt_long(argc
, argv
, "T:CDSUtcvnxzpf", long_options
, NULL
))
561 fatal("fig support not included");
565 driver_extension_flag
= 0;
569 warning("-%1 option is obsolete", char(opt
));
575 fatal("TeX support not included");
582 fatal("TeX support not included");
587 puts(L_P_PIC
" (" T_ROFF
") v" VERSION
);
592 // zero length lines will be printed as dots
593 zero_length_line_flag
++;
595 case CHAR_MAX
+ 1: // --help
609 out
= make_tpic_output();
613 out
= make_tex_output();
621 out
= make_fig_output();
624 out
= make_troff_output();
626 if (whole_file_flag
) {
629 else if (argc
- optind
> 1) {
633 do_whole_file(argv
[optind
]);
640 for (int i
= optind
; i
< argc
; i
++)
646 if (ferror(stdout
) || fflush(stdout
) < 0)
647 fatal("output error");
648 return had_parse_error
;