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);