2 /* Copyright (C) 1989, 1990, 1991, 1992 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. */
21 // A front end for groff.
33 #include "stringclass.h"
40 #define BSHELL "/bin/sh"
41 #define GXDITVIEW "gxditview"
43 // troff will be passed an argument of -rXREG=1 if the -X option is
47 #ifndef STDLIB_H_DECLARES_PUTENV
49 int putenv(const char *);
51 #endif /* not STDLIB_H_DECLARES_PUTENV */
53 const int SOELIM_INDEX
= 0;
54 const int REFER_INDEX
= SOELIM_INDEX
+ 1;
55 const int PIC_INDEX
= REFER_INDEX
+ 1;
56 const int TBL_INDEX
= PIC_INDEX
+ 1;
57 const int EQN_INDEX
= TBL_INDEX
+ 1;
58 const int TROFF_INDEX
= EQN_INDEX
+ 1;
59 const int POST_INDEX
= TROFF_INDEX
+ 1;
60 const int SPOOL_INDEX
= POST_INDEX
+ 1;
62 const int NCOMMANDS
= SPOOL_INDEX
+ 1;
64 class possible_command
{
73 void set_name(const char *);
74 void set_name(const char *, const char *);
75 const char *get_name();
76 void append_arg(const char *, const char * = 0);
77 void insert_arg(const char *);
80 void print(int is_last
, FILE *fp
);
87 possible_command commands
[NCOMMANDS
];
90 void print_commands();
91 void append_arg_to_string(const char *arg
, string
&str
);
92 void handle_unknown_desc_command(const char *command
, const char *arg
,
93 const char *filename
, int lineno
);
94 const char *xbasename(const char *);
99 int main(int argc
, char **argv
)
101 program_name
= argv
[0];
102 static char stderr_buf
[BUFSIZ
];
103 setbuf(stderr
, stderr_buf
);
104 assert(NCOMMANDS
<= MAX_COMMANDS
);
105 string Pargs
, Largs
, Fargs
;
112 const char *command_prefix
= getenv("GROFF_COMMAND_PREFIX");
114 command_prefix
= PROG_PREFIX
;
115 commands
[TROFF_INDEX
].set_name(command_prefix
, "troff");
116 while ((opt
= getopt(argc
, argv
,
117 "abCd:eEf:F:hiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ"))
128 commands
[SOELIM_INDEX
].set_name(command_prefix
, "soelim");
129 commands
[SOELIM_INDEX
].append_arg(buf
, optarg
);
132 commands
[TBL_INDEX
].set_name(command_prefix
, "tbl");
135 commands
[PIC_INDEX
].set_name(command_prefix
, "pic");
138 commands
[EQN_INDEX
].set_name(command_prefix
, "eqn");
141 commands
[SOELIM_INDEX
].set_name(command_prefix
, "soelim");
144 commands
[REFER_INDEX
].set_name(command_prefix
, "refer");
148 commands
[TROFF_INDEX
].append_arg(buf
);
161 commands
[SOELIM_INDEX
].append_arg(buf
);
162 commands
[PIC_INDEX
].append_arg(buf
);
163 commands
[TBL_INDEX
].append_arg(buf
);
164 commands
[EQN_INDEX
].append_arg(buf
);
165 commands
[TROFF_INDEX
].append_arg(buf
);
168 commands
[EQN_INDEX
].append_arg(buf
);
175 commands
[TROFF_INDEX
].append_arg(buf
);
184 if (strcmp(optarg
, "Xps") == 0) {
185 warning("-TXps option is obsolete: use -X -Tps instead");
193 font::command_line_font_dir(optarg
);
194 if (Fargs
.length() > 0) {
209 commands
[TROFF_INDEX
].append_arg(buf
, optarg
);
212 commands
[EQN_INDEX
].append_arg(buf
, optarg
);
213 commands
[TROFF_INDEX
].append_arg(buf
, optarg
);
220 append_arg_to_string(optarg
, Largs
);
234 commands
[PIC_INDEX
].append_arg("-S");
235 commands
[TROFF_INDEX
].insert_arg("-msafer");
237 commands
[TROFF_INDEX
].insert_arg("-U");
239 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
240 if (!font::load_desc())
241 fatal("invalid device `%1'", device
);
243 fatal("no `postpro' command in DESC file for device `%1'", device
);
244 const char *real_driver
= 0;
246 real_driver
= driver
;
248 commands
[TROFF_INDEX
].append_arg("-r" XREG
"=", "1");
251 commands
[POST_INDEX
].set_name(driver
);
252 int gxditview_flag
= driver
&& strcmp(xbasename(driver
), GXDITVIEW
) == 0;
253 if (gxditview_flag
&& argc
- optind
== 1) {
254 commands
[POST_INDEX
].append_arg("-title");
255 commands
[POST_INDEX
].append_arg(argv
[optind
]);
256 commands
[POST_INDEX
].append_arg("-xrm");
257 commands
[POST_INDEX
].append_arg("*iconName:", argv
[optind
]);
258 string
filename_string("|");
259 append_arg_to_string(argv
[0], filename_string
);
260 append_arg_to_string("-Z", filename_string
);
261 for (int i
= 1; i
< argc
; i
++)
262 append_arg_to_string(argv
[i
], filename_string
);
263 filename_string
+= '\0';
264 commands
[POST_INDEX
].append_arg("-filename");
265 commands
[POST_INDEX
].append_arg(filename_string
.contents());
267 if (gxditview_flag
&& Xflag
) {
268 string
print_string(real_driver
);
270 print_string
+= " | ";
271 print_string
+= spooler
;
272 print_string
+= Largs
;
274 print_string
+= '\0';
275 commands
[POST_INDEX
].append_arg("-printCommand");
276 commands
[POST_INDEX
].append_arg(print_string
.contents());
278 const char *p
= Pargs
.contents();
279 const char *end
= p
+ Pargs
.length();
281 commands
[POST_INDEX
].append_arg(p
);
282 p
= strchr(p
, '\0') + 1;
285 commands
[POST_INDEX
].append_arg("-");
286 if (lflag
&& !Xflag
&& spooler
) {
287 commands
[SPOOL_INDEX
].set_name(BSHELL
);
288 commands
[SPOOL_INDEX
].append_arg("-c");
290 Largs
= spooler
+ Largs
;
291 commands
[SPOOL_INDEX
].append_arg(Largs
.contents());
294 commands
[POST_INDEX
].set_name(0);
295 commands
[SPOOL_INDEX
].set_name(0);
297 commands
[TROFF_INDEX
].append_arg("-T", device
);
298 commands
[EQN_INDEX
].append_arg("-T", device
);
301 for (first_index
= 0; first_index
< TROFF_INDEX
; first_index
++)
302 if (commands
[first_index
].get_name() != 0)
305 if (argv
[optind
][0] == '-' && argv
[optind
][1] != '\0')
306 commands
[first_index
].append_arg("--");
307 for (int i
= optind
; i
< argc
; i
++)
308 commands
[first_index
].append_arg(argv
[i
]);
310 commands
[first_index
].append_arg("-");
312 if (Fargs
.length() > 0) {
313 string e
= "GROFF_FONT_PATH";
316 char *fontpath
= getenv("GROFF_FONT_PATH");
317 if (fontpath
&& *fontpath
) {
322 if (putenv(strsave(e
.contents())))
323 fatal("putenv failed");
329 return run_commands();
332 const char *xbasename(const char *s
)
336 const char *p
= strrchr(s
, '/');
337 return p
? p
+ 1 : s
;
340 void handle_unknown_desc_command(const char *command
, const char *arg
,
341 const char *filename
, int lineno
)
343 if (strcmp(command
, "print") == 0) {
345 error_with_file_and_line(filename
, lineno
,
346 "`print' command requires an argument");
348 spooler
= strsave(arg
);
350 if (strcmp(command
, "postpro") == 0) {
352 error_with_file_and_line(filename
, lineno
,
353 "`postpro' command requires an argument");
355 for (const char *p
= arg
; *p
; p
++)
357 error_with_file_and_line(filename
, lineno
,
358 "invalid `postpro' argument `%1'"
359 ": program name required", arg
);
362 driver
= strsave(arg
);
367 void print_commands()
370 for (last
= SPOOL_INDEX
; last
>= 0; last
--)
371 if (commands
[last
].get_name() != 0)
373 for (int i
= 0; i
<= last
; i
++)
374 if (commands
[i
].get_name() != 0)
375 commands
[i
].print(i
== last
, stdout
);
378 // Run the commands. Return the code with which to exit.
384 for (int i
= 0; i
< NCOMMANDS
; i
++)
385 if (commands
[i
].get_name() != 0)
386 v
[j
++] = commands
[i
].get_argv();
387 return run_pipeline(j
, v
);
390 possible_command::possible_command()
395 possible_command::~possible_command()
401 void possible_command::set_name(const char *s
)
407 void possible_command::set_name(const char *s1
, const char *s2
)
410 name
= new char[strlen(s1
) + strlen(s2
) + 1];
415 const char *possible_command::get_name()
420 void possible_command::clear_args()
425 void possible_command::append_arg(const char *s
, const char *t
)
433 void possible_command::insert_arg(const char *s
)
441 void possible_command::build_argv()
445 // Count the number of arguments.
446 int len
= args
.length();
451 for (int i
= 0; i
< len
; i
++)
455 // Build an argument vector.
456 argv
= new char *[argc
+ 1];
458 for (int i
= 1; i
< argc
; i
++) {
460 p
= strchr(p
, '\0') + 1;
465 void possible_command::print(int is_last
, FILE *fp
)
468 if (argv
[0] != 0 && strcmp(argv
[0], BSHELL
) == 0
469 && argv
[1] != 0 && strcmp(argv
[1], "-c") == 0
470 && argv
[2] != 0 && argv
[3] == 0)
475 for (int i
= 1; argv
[i
] != 0; i
++) {
477 append_arg_to_string(argv
[i
], str
);
487 void append_arg_to_string(const char *arg
, string
&str
)
490 int needs_quoting
= 0;
491 int contains_single_quote
= 0;
493 for (p
= arg
; *p
!= '\0'; p
++)
514 contains_single_quote
= 1;
517 if (contains_single_quote
|| arg
[0] == '\0') {
519 for (p
= arg
; *p
!= '\0'; p
++)
532 else if (needs_quoting
) {
541 char **possible_command::get_argv()
550 "usage: %s [-abehilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n"
551 " [-Wname] [-Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n"
560 "-h\tprint this message\n"
561 "-t\tpreprocess with tbl\n"
562 "-p\tpreprocess with pic\n"
563 "-e\tpreprocess with eqn\n"
564 "-s\tpreprocess with soelim\n"
565 "-R\tpreprocess with refer\n"
566 "-Tdev\tuse device dev\n"
567 "-X\tuse X11 previewer rather than usual postprocessor\n"
568 "-mname\tread macros tmac.name\n"
569 "-dcs\tdefine a string c as s\n"
570 "-rcn\tdefine a number register c as n\n"
571 "-nnum\tnumber first page n\n"
572 "-olist\toutput only pages in list\n"
573 "-ffam\tuse fam as the default font family\n"
574 "-Fdir\tsearch directory dir for device directories\n"
575 "-Mdir\tsearch dir for macro files\n"
576 "-v\tprint version number\n"
577 "-z\tsuppress formatted output\n"
578 "-Z\tdon't postprocess\n"
579 "-a\tproduce ASCII description of output\n"
580 "-i\tread standard input after named input files\n"
581 "-wname\tenable warning name\n"
582 "-Wname\tinhibit warning name\n"
583 "-E\tinhibit all errors\n"
584 "-b\tprint backtraces with errors or warnings\n"
585 "-l\tspool the output\n"
586 "-C\tenable compatibility mode\n"
587 "-V\tprint commands on stdout instead of running them\n"
588 "-Parg\tpass arg to the postprocessor\n"
589 "-Larg\tpass arg to the spooler\n"
590 "-N\tdon't allow newlines within eqn delimiters\n"
591 "-S\tenable safer mode (the default)\n"
592 "-U\tenable unsafe mode\n"
601 fprintf(stderr
, "%s -h gives more help\n", program_name
);
607 void c_error(const char *format
, const char *arg1
, const char *arg2
,
610 error(format
, arg1
, arg2
, arg3
);
613 void c_fatal(const char *format
, const char *arg1
, const char *arg2
,
616 fatal(format
, arg1
, arg2
, arg3
);