2 /* Copyright (C) 1989-2000 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 GRN_INDEX
= TBL_INDEX
+ 1;
58 const int EQN_INDEX
= GRN_INDEX
+ 1;
59 const int TROFF_INDEX
= EQN_INDEX
+ 1;
60 const int POST_INDEX
= TROFF_INDEX
+ 1;
61 const int SPOOL_INDEX
= POST_INDEX
+ 1;
63 const int NCOMMANDS
= SPOOL_INDEX
+ 1;
65 class possible_command
{
74 void set_name(const char *);
75 void set_name(const char *, const char *);
76 const char *get_name();
77 void append_arg(const char *, const char * = 0);
78 void insert_arg(const char *);
81 void print(int is_last
, FILE *fp
);
88 possible_command commands
[NCOMMANDS
];
91 void print_commands();
92 void append_arg_to_string(const char *arg
, string
&str
);
93 void handle_unknown_desc_command(const char *command
, const char *arg
,
94 const char *filename
, int lineno
);
95 const char *xbasename(const char *);
100 int main(int argc
, char **argv
)
102 program_name
= argv
[0];
103 static char stderr_buf
[BUFSIZ
];
104 setbuf(stderr
, stderr_buf
);
105 assert(NCOMMANDS
<= MAX_COMMANDS
);
106 string Pargs
, Largs
, Fargs
;
113 const char *command_prefix
= getenv("GROFF_COMMAND_PREFIX");
115 command_prefix
= PROG_PREFIX
;
116 commands
[TROFF_INDEX
].set_name(command_prefix
, "troff");
117 while ((opt
= getopt(argc
, argv
,
118 "abCd:eEf:F:ghiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ"))
129 commands
[SOELIM_INDEX
].set_name(command_prefix
, "soelim");
130 commands
[SOELIM_INDEX
].append_arg(buf
, optarg
);
133 commands
[TBL_INDEX
].set_name(command_prefix
, "tbl");
136 commands
[PIC_INDEX
].set_name(command_prefix
, "pic");
139 commands
[GRN_INDEX
].set_name(command_prefix
, "grn");
142 commands
[EQN_INDEX
].set_name(command_prefix
, "eqn");
145 commands
[SOELIM_INDEX
].set_name(command_prefix
, "soelim");
148 commands
[REFER_INDEX
].set_name(command_prefix
, "refer");
152 commands
[TROFF_INDEX
].append_arg(buf
);
165 commands
[SOELIM_INDEX
].append_arg(buf
);
166 commands
[PIC_INDEX
].append_arg(buf
);
167 commands
[TBL_INDEX
].append_arg(buf
);
168 commands
[GRN_INDEX
].append_arg(buf
);
169 commands
[EQN_INDEX
].append_arg(buf
);
170 commands
[TROFF_INDEX
].append_arg(buf
);
173 commands
[EQN_INDEX
].append_arg(buf
);
180 commands
[TROFF_INDEX
].append_arg(buf
);
189 if (strcmp(optarg
, "Xps") == 0) {
190 warning("-TXps option is obsolete: use -X -Tps instead");
198 font::command_line_font_dir(optarg
);
199 if (Fargs
.length() > 0) {
214 commands
[TROFF_INDEX
].append_arg(buf
, optarg
);
217 commands
[EQN_INDEX
].append_arg(buf
, optarg
);
218 commands
[GRN_INDEX
].append_arg(buf
, optarg
);
219 commands
[TROFF_INDEX
].append_arg(buf
, optarg
);
226 append_arg_to_string(optarg
, Largs
);
240 commands
[PIC_INDEX
].append_arg("-S");
241 commands
[TROFF_INDEX
].insert_arg("-msafer");
243 commands
[TROFF_INDEX
].insert_arg("-U");
245 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
246 if (!font::load_desc())
247 fatal("invalid device `%1'", device
);
249 fatal("no `postpro' command in DESC file for device `%1'", device
);
250 const char *real_driver
= 0;
252 real_driver
= driver
;
254 commands
[TROFF_INDEX
].append_arg("-r" XREG
"=", "1");
257 commands
[POST_INDEX
].set_name(driver
);
258 int gxditview_flag
= driver
&& strcmp(xbasename(driver
), GXDITVIEW
) == 0;
259 if (gxditview_flag
&& argc
- optind
== 1) {
260 commands
[POST_INDEX
].append_arg("-title");
261 commands
[POST_INDEX
].append_arg(argv
[optind
]);
262 commands
[POST_INDEX
].append_arg("-xrm");
263 commands
[POST_INDEX
].append_arg("*iconName:", argv
[optind
]);
264 string
filename_string("|");
265 append_arg_to_string(argv
[0], filename_string
);
266 append_arg_to_string("-Z", filename_string
);
267 for (int i
= 1; i
< argc
; i
++)
268 append_arg_to_string(argv
[i
], filename_string
);
269 filename_string
+= '\0';
270 commands
[POST_INDEX
].append_arg("-filename");
271 commands
[POST_INDEX
].append_arg(filename_string
.contents());
273 if (gxditview_flag
&& Xflag
) {
274 string
print_string(real_driver
);
276 print_string
+= " | ";
277 print_string
+= spooler
;
278 print_string
+= Largs
;
280 print_string
+= '\0';
281 commands
[POST_INDEX
].append_arg("-printCommand");
282 commands
[POST_INDEX
].append_arg(print_string
.contents());
284 const char *p
= Pargs
.contents();
285 const char *end
= p
+ Pargs
.length();
287 commands
[POST_INDEX
].append_arg(p
);
288 p
= strchr(p
, '\0') + 1;
291 commands
[POST_INDEX
].append_arg("-");
292 if (lflag
&& !Xflag
&& spooler
) {
293 commands
[SPOOL_INDEX
].set_name(BSHELL
);
294 commands
[SPOOL_INDEX
].append_arg("-c");
296 Largs
= spooler
+ Largs
;
297 commands
[SPOOL_INDEX
].append_arg(Largs
.contents());
300 commands
[POST_INDEX
].set_name(0);
301 commands
[SPOOL_INDEX
].set_name(0);
303 commands
[TROFF_INDEX
].append_arg("-T", device
);
304 commands
[EQN_INDEX
].append_arg("-T", device
);
305 commands
[GRN_INDEX
].append_arg("-T", device
);
308 for (first_index
= 0; first_index
< TROFF_INDEX
; first_index
++)
309 if (commands
[first_index
].get_name() != 0)
312 if (argv
[optind
][0] == '-' && argv
[optind
][1] != '\0')
313 commands
[first_index
].append_arg("--");
314 for (int i
= optind
; i
< argc
; i
++)
315 commands
[first_index
].append_arg(argv
[i
]);
317 commands
[first_index
].append_arg("-");
319 if (Fargs
.length() > 0) {
320 string e
= "GROFF_FONT_PATH";
323 char *fontpath
= getenv("GROFF_FONT_PATH");
324 if (fontpath
&& *fontpath
) {
329 if (putenv(strsave(e
.contents())))
330 fatal("putenv failed");
336 return run_commands();
339 const char *xbasename(const char *s
)
343 const char *p
= strrchr(s
, '/');
344 return p
? p
+ 1 : s
;
347 void handle_unknown_desc_command(const char *command
, const char *arg
,
348 const char *filename
, int lineno
)
350 if (strcmp(command
, "print") == 0) {
352 error_with_file_and_line(filename
, lineno
,
353 "`print' command requires an argument");
355 spooler
= strsave(arg
);
357 if (strcmp(command
, "postpro") == 0) {
359 error_with_file_and_line(filename
, lineno
,
360 "`postpro' command requires an argument");
362 for (const char *p
= arg
; *p
; p
++)
364 error_with_file_and_line(filename
, lineno
,
365 "invalid `postpro' argument `%1'"
366 ": program name required", arg
);
369 driver
= strsave(arg
);
374 void print_commands()
377 for (last
= SPOOL_INDEX
; last
>= 0; last
--)
378 if (commands
[last
].get_name() != 0)
380 for (int i
= 0; i
<= last
; i
++)
381 if (commands
[i
].get_name() != 0)
382 commands
[i
].print(i
== last
, stdout
);
385 // Run the commands. Return the code with which to exit.
391 for (int i
= 0; i
< NCOMMANDS
; i
++)
392 if (commands
[i
].get_name() != 0)
393 v
[j
++] = commands
[i
].get_argv();
394 return run_pipeline(j
, v
);
397 possible_command::possible_command()
402 possible_command::~possible_command()
408 void possible_command::set_name(const char *s
)
414 void possible_command::set_name(const char *s1
, const char *s2
)
417 name
= new char[strlen(s1
) + strlen(s2
) + 1];
422 const char *possible_command::get_name()
427 void possible_command::clear_args()
432 void possible_command::append_arg(const char *s
, const char *t
)
440 void possible_command::insert_arg(const char *s
)
448 void possible_command::build_argv()
452 // Count the number of arguments.
453 int len
= args
.length();
458 for (int i
= 0; i
< len
; i
++)
462 // Build an argument vector.
463 argv
= new char *[argc
+ 1];
465 for (int i
= 1; i
< argc
; i
++) {
467 p
= strchr(p
, '\0') + 1;
472 void possible_command::print(int is_last
, FILE *fp
)
475 if (argv
[0] != 0 && strcmp(argv
[0], BSHELL
) == 0
476 && argv
[1] != 0 && strcmp(argv
[1], "-c") == 0
477 && argv
[2] != 0 && argv
[3] == 0)
482 for (int i
= 1; argv
[i
] != 0; i
++) {
484 append_arg_to_string(argv
[i
], str
);
494 void append_arg_to_string(const char *arg
, string
&str
)
497 int needs_quoting
= 0;
498 int contains_single_quote
= 0;
500 for (p
= arg
; *p
!= '\0'; p
++)
521 contains_single_quote
= 1;
524 if (contains_single_quote
|| arg
[0] == '\0') {
526 for (p
= arg
; *p
!= '\0'; p
++)
539 else if (needs_quoting
) {
548 char **possible_command::get_argv()
557 "usage: %s [-abeghilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
558 " [-wname] [-Wname] [-Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n"
559 " [-Larg] [-Idir] [files...]\n",
567 "-h\tprint this message\n"
568 "-t\tpreprocess with tbl\n"
569 "-p\tpreprocess with pic\n"
570 "-e\tpreprocess with eqn\n"
571 "-g\tpreprocess with grn\n"
572 "-s\tpreprocess with soelim\n"
573 "-R\tpreprocess with refer\n"
574 "-Tdev\tuse device dev\n"
575 "-X\tuse X11 previewer rather than usual postprocessor\n"
576 "-mname\tread macros tmac.name\n"
577 "-dcs\tdefine a string c as s\n"
578 "-rcn\tdefine a number register c as n\n"
579 "-nnum\tnumber first page n\n"
580 "-olist\toutput only pages in list\n"
581 "-ffam\tuse fam as the default font family\n"
582 "-Fdir\tsearch dir for device directories\n"
583 "-Mdir\tsearch dir for macro files\n"
584 "-v\tprint version number\n"
585 "-z\tsuppress formatted output\n"
586 "-Z\tdon't postprocess\n"
587 "-a\tproduce ASCII description of output\n"
588 "-i\tread standard input after named input files\n"
589 "-wname\tenable warning name\n"
590 "-Wname\tinhibit warning name\n"
591 "-E\tinhibit all errors\n"
592 "-b\tprint backtraces with errors or warnings\n"
593 "-l\tspool the output\n"
594 "-C\tenable compatibility mode\n"
595 "-V\tprint commands on stdout instead of running them\n"
596 "-Parg\tpass arg to the postprocessor\n"
597 "-Larg\tpass arg to the spooler\n"
598 "-N\tdon't allow newlines within eqn delimiters\n"
599 "-S\tenable safer mode (the default)\n"
600 "-U\tenable unsafe mode\n"
601 "-Idir\tsearch dir for soelim. Implies -s\n"
610 fprintf(stderr
, "%s -h gives more help\n", program_name
);
616 void c_error(const char *format
, const char *arg1
, const char *arg2
,
619 error(format
, arg1
, arg2
, arg3
);
622 void c_fatal(const char *format
, const char *arg1
, const char *arg2
,
625 fatal(format
, arg1
, arg2
, arg3
);