169484Sbostic // -*- C++ -*-
269484Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
369484Sbostic      Written by James Clark (jjc@jclark.com)
469484Sbostic 
569484Sbostic This file is part of groff.
669484Sbostic 
769484Sbostic groff is free software; you can redistribute it and/or modify it under
869484Sbostic the terms of the GNU General Public License as published by the Free
969484Sbostic Software Foundation; either version 2, or (at your option) any later
1069484Sbostic version.
1169484Sbostic 
1269484Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
1369484Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
1469484Sbostic FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1569484Sbostic for more details.
1669484Sbostic 
1769484Sbostic You should have received a copy of the GNU General Public License along
1869484Sbostic with groff; see the file COPYING.  If not, write to the Free Software
1969484Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
2069484Sbostic 
2169484Sbostic // A front end for groff.
2269484Sbostic 
2369484Sbostic #include <stdio.h>
2469484Sbostic #include <string.h>
25*69501Sbostic #include <unistd.h>
2669484Sbostic #include <stdlib.h>
2769484Sbostic #include <signal.h>
2869484Sbostic #include <errno.h>
2969484Sbostic 
3069484Sbostic #include "lib.h"
3169484Sbostic #include "assert.h"
3269484Sbostic #include "errarg.h"
3369484Sbostic #include "error.h"
3469484Sbostic #include "stringclass.h"
3569484Sbostic #include "cset.h"
3669484Sbostic #include "font.h"
3769484Sbostic #include "device.h"
3869484Sbostic #include "pipeline.h"
3969484Sbostic #include "defs.h"
4069484Sbostic 
4169484Sbostic #define BSHELL "/bin/sh"
4269484Sbostic #define GXDITVIEW "gxditview"
4369484Sbostic 
4469484Sbostic // troff will be passed an argument of -rXREG=1 if the -X option is
4569484Sbostic // specified
4669484Sbostic #define XREG ".X"
4769484Sbostic 
4869484Sbostic #ifndef STDLIB_H_DECLARES_PUTENV
4969484Sbostic extern "C" {
5069484Sbostic   int putenv(const char *);
5169484Sbostic }
5269484Sbostic #endif /* not STDLIB_H_DECLARES_PUTENV */
5369484Sbostic 
5469484Sbostic const char *strsignal(int);
5569484Sbostic 
5669484Sbostic const int SOELIM_INDEX = 0;
5769484Sbostic const int REFER_INDEX = SOELIM_INDEX + 1;
5869484Sbostic const int PIC_INDEX = REFER_INDEX + 1;
5969484Sbostic const int TBL_INDEX = PIC_INDEX + 1;
6069484Sbostic const int EQN_INDEX = TBL_INDEX + 1;
6169484Sbostic const int TROFF_INDEX = EQN_INDEX + 1;
6269484Sbostic const int POST_INDEX = TROFF_INDEX + 1;
6369484Sbostic const int SPOOL_INDEX = POST_INDEX + 1;
6469484Sbostic 
6569484Sbostic const int NCOMMANDS = SPOOL_INDEX + 1;
6669484Sbostic 
6769484Sbostic class possible_command {
6869484Sbostic   char *name;
6969484Sbostic   string args;
7069484Sbostic   char **argv;
7169484Sbostic 
7269484Sbostic   void build_argv();
7369484Sbostic public:
7469484Sbostic   possible_command();
7569484Sbostic   ~possible_command();
7669484Sbostic   void set_name(const char *);
7769484Sbostic   void set_name(const char *, const char *);
7869484Sbostic   const char *get_name();
7969484Sbostic   void append_arg(const char *, const char * = 0);
8069484Sbostic   void clear_args();
8169484Sbostic   char **get_argv();
8269484Sbostic   void print(int is_last, FILE *fp);
8369484Sbostic };
8469484Sbostic 
8569484Sbostic int lflag = 0;
8669484Sbostic char *spooler = 0;
8769484Sbostic char *driver = 0;
8869484Sbostic 
8969484Sbostic possible_command commands[NCOMMANDS];
9069484Sbostic 
9169484Sbostic int run_commands();
9269484Sbostic void print_commands();
9369484Sbostic void append_arg_to_string(const char *arg, string &str);
9469484Sbostic void handle_unknown_desc_command(const char *command, const char *arg,
9569484Sbostic 				 const char *filename, int lineno);
9669484Sbostic const char *basename(const char *);
9769484Sbostic 
9869484Sbostic void usage();
9969484Sbostic void help();
10069484Sbostic 
main(int argc,char ** argv)10169484Sbostic int main(int argc, char **argv)
10269484Sbostic {
10369484Sbostic   program_name = argv[0];
10469484Sbostic   static char stderr_buf[BUFSIZ];
10569484Sbostic   setbuf(stderr, stderr_buf);
10669484Sbostic   assert(NCOMMANDS <= MAX_COMMANDS);
10769484Sbostic   string Pargs, Largs, Fargs;
10869484Sbostic   int Vflag = 0;
10969484Sbostic   int zflag = 0;
11069484Sbostic   int iflag = 0;
11169484Sbostic   int Xflag = 0;
11269484Sbostic   int opt;
11369484Sbostic   const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
11469484Sbostic   if (!command_prefix)
11569484Sbostic     command_prefix = PROG_PREFIX;
11669484Sbostic   commands[TROFF_INDEX].set_name(command_prefix, "troff");
11769484Sbostic   while ((opt = getopt(argc, argv,
11869484Sbostic 		       "itpeRszavVhblCENXZF:m:T:f:w:W:M:d:r:n:o:P:L:"))
11969484Sbostic 	 != EOF) {
12069484Sbostic     char buf[3];
12169484Sbostic     buf[0] = '-';
12269484Sbostic     buf[1] = opt;
12369484Sbostic     buf[2] = '\0';
12469484Sbostic     switch (opt) {
12569484Sbostic     case 'i':
12669484Sbostic       iflag = 1;
12769484Sbostic       break;
12869484Sbostic     case 't':
12969484Sbostic       commands[TBL_INDEX].set_name(command_prefix, "tbl");
13069484Sbostic       break;
13169484Sbostic     case 'p':
13269484Sbostic       commands[PIC_INDEX].set_name(command_prefix, "pic");
13369484Sbostic       break;
13469484Sbostic     case 'e':
13569484Sbostic       commands[EQN_INDEX].set_name(command_prefix, "eqn");
13669484Sbostic       break;
13769484Sbostic     case 's':
13869484Sbostic       commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
13969484Sbostic       break;
14069484Sbostic     case 'R':
14169484Sbostic       commands[REFER_INDEX].set_name(command_prefix, "refer");
14269484Sbostic       break;
14369484Sbostic     case 'z':
14469484Sbostic     case 'a':
14569484Sbostic       commands[TROFF_INDEX].append_arg(buf);
14669484Sbostic       // fall through
14769484Sbostic     case 'Z':
14869484Sbostic       zflag++;
14969484Sbostic       break;
15069484Sbostic     case 'l':
15169484Sbostic       lflag++;
15269484Sbostic       break;
15369484Sbostic     case 'V':
15469484Sbostic       Vflag++;
15569484Sbostic       break;
15669484Sbostic     case 'v':
15769484Sbostic     case 'C':
15869484Sbostic       commands[SOELIM_INDEX].append_arg(buf);
15969484Sbostic       commands[PIC_INDEX].append_arg(buf);
16069484Sbostic       commands[TBL_INDEX].append_arg(buf);
16169484Sbostic       commands[EQN_INDEX].append_arg(buf);
16269484Sbostic       commands[TROFF_INDEX].append_arg(buf);
16369484Sbostic       break;
16469484Sbostic     case 'N':
16569484Sbostic       commands[EQN_INDEX].append_arg(buf);
16669484Sbostic       break;
16769484Sbostic     case 'h':
16869484Sbostic       help();
16969484Sbostic       break;
17069484Sbostic     case 'E':
17169484Sbostic     case 'b':
17269484Sbostic       commands[TROFF_INDEX].append_arg(buf);
17369484Sbostic       break;
17469484Sbostic     case 'T':
17569484Sbostic       if (strcmp(optarg, "Xps") == 0) {
17669484Sbostic 	warning("-TXps option is obsolete: use -X -Tps instead");
17769484Sbostic 	device = "ps";
17869484Sbostic 	Xflag++;
17969484Sbostic       }
18069484Sbostic       else
18169484Sbostic 	device = optarg;
18269484Sbostic       break;
18369484Sbostic     case 'F':
18469484Sbostic       font::command_line_font_dir(optarg);
18569484Sbostic       if (Fargs.length() > 0) {
18669484Sbostic 	Fargs += ':';
18769484Sbostic 	Fargs += optarg;
18869484Sbostic       }
18969484Sbostic       else
19069484Sbostic 	Fargs = optarg;
19169484Sbostic       break;
19269484Sbostic     case 'f':
19369484Sbostic     case 'o':
19469484Sbostic     case 'm':
19569484Sbostic     case 'r':
19669484Sbostic     case 'd':
19769484Sbostic     case 'n':
19869484Sbostic     case 'w':
19969484Sbostic     case 'W':
20069484Sbostic       commands[TROFF_INDEX].append_arg(buf, optarg);
20169484Sbostic       break;
20269484Sbostic     case 'M':
20369484Sbostic       commands[EQN_INDEX].append_arg(buf, optarg);
20469484Sbostic       commands[TROFF_INDEX].append_arg(buf, optarg);
20569484Sbostic       break;
20669484Sbostic     case 'P':
20769484Sbostic       Pargs += optarg;
20869484Sbostic       Pargs += '\0';
20969484Sbostic       break;
21069484Sbostic     case 'L':
21169484Sbostic       append_arg_to_string(optarg, Largs);
21269484Sbostic       break;
21369484Sbostic     case 'X':
21469484Sbostic       Xflag++;
21569484Sbostic       break;
21669484Sbostic     case '?':
21769484Sbostic       usage();
21869484Sbostic       break;
21969484Sbostic     default:
22069484Sbostic       assert(0);
22169484Sbostic       break;
22269484Sbostic     }
22369484Sbostic   }
22469484Sbostic   font::set_unknown_desc_command_handler(handle_unknown_desc_command);
22569484Sbostic   if (!font::load_desc())
22669484Sbostic     fatal("invalid device `%1'", device);
22769484Sbostic   if (!driver)
22869484Sbostic     fatal("no `postpro' command in DESC file for device `%1'", device);
22969484Sbostic   const char *real_driver = 0;
23069484Sbostic   if (Xflag) {
23169484Sbostic     real_driver = driver;
23269484Sbostic     driver = GXDITVIEW;
23369484Sbostic     commands[TROFF_INDEX].append_arg("-r" XREG "=", "1");
23469484Sbostic   }
23569484Sbostic   if (driver)
23669484Sbostic     commands[POST_INDEX].set_name(driver);
23769484Sbostic   int gxditview_flag = driver && strcmp(basename(driver), GXDITVIEW) == 0;
23869484Sbostic   if (gxditview_flag && argc - optind == 1) {
23969484Sbostic     commands[POST_INDEX].append_arg("-title");
24069484Sbostic     commands[POST_INDEX].append_arg(argv[optind]);
24169484Sbostic     commands[POST_INDEX].append_arg("-xrm");
24269484Sbostic     commands[POST_INDEX].append_arg("*iconName:", argv[optind]);
24369484Sbostic     string filename_string("|");
24469484Sbostic     append_arg_to_string(argv[0], filename_string);
24569484Sbostic     append_arg_to_string("-Z", filename_string);
24669484Sbostic     for (int i = 1; i < argc; i++)
24769484Sbostic       append_arg_to_string(argv[i], filename_string);
24869484Sbostic     filename_string += '\0';
24969484Sbostic     commands[POST_INDEX].append_arg("-filename");
25069484Sbostic     commands[POST_INDEX].append_arg(filename_string.contents());
25169484Sbostic   }
25269484Sbostic   if (gxditview_flag && Xflag) {
25369484Sbostic     string print_string(real_driver);
25469484Sbostic     if (spooler) {
25569484Sbostic       print_string += " | ";
25669484Sbostic       print_string += spooler;
25769484Sbostic       print_string += Largs;
25869484Sbostic     }
25969484Sbostic     print_string += '\0';
26069484Sbostic     commands[POST_INDEX].append_arg("-printCommand");
26169484Sbostic     commands[POST_INDEX].append_arg(print_string.contents());
26269484Sbostic   }
26369484Sbostic   const char *p = Pargs.contents();
26469484Sbostic   const char *end = p + Pargs.length();
26569484Sbostic   while (p < end) {
26669484Sbostic     commands[POST_INDEX].append_arg(p);
26769484Sbostic     p = strchr(p, '\0') + 1;
26869484Sbostic   }
26969484Sbostic   if (gxditview_flag)
27069484Sbostic     commands[POST_INDEX].append_arg("-");
27169484Sbostic   if (lflag && !Xflag && spooler) {
27269484Sbostic     commands[SPOOL_INDEX].set_name(BSHELL);
27369484Sbostic     commands[SPOOL_INDEX].append_arg("-c");
27469484Sbostic     Largs += '\0';
27569484Sbostic     Largs = spooler + Largs;
27669484Sbostic     commands[SPOOL_INDEX].append_arg(Largs.contents());
27769484Sbostic   }
27869484Sbostic   if (zflag) {
27969484Sbostic     commands[POST_INDEX].set_name(0);
28069484Sbostic     commands[SPOOL_INDEX].set_name(0);
28169484Sbostic   }
28269484Sbostic   commands[TROFF_INDEX].append_arg("-T", device);
28369484Sbostic   commands[EQN_INDEX].append_arg("-T", device);
28469484Sbostic 
28569484Sbostic   for (int first_index = 0; first_index < TROFF_INDEX; first_index++)
28669484Sbostic     if (commands[first_index].get_name() != 0)
28769484Sbostic       break;
28869484Sbostic   if (optind < argc) {
28969484Sbostic     if (argv[optind][0] == '-' && argv[optind][1] != '\0')
29069484Sbostic       commands[first_index].append_arg("--");
29169484Sbostic     for (int i = optind; i < argc; i++)
29269484Sbostic       commands[first_index].append_arg(argv[i]);
29369484Sbostic     if (iflag)
29469484Sbostic       commands[first_index].append_arg("-");
29569484Sbostic   }
29669484Sbostic   if (Fargs.length() > 0) {
29769484Sbostic     string e = "GROFF_FONT_PATH";
29869484Sbostic     e += '=';
29969484Sbostic     e += Fargs;
30069484Sbostic     char *fontpath = getenv("GROFF_FONT_PATH");
30169484Sbostic     if (fontpath && *fontpath) {
30269484Sbostic       e += ':';
30369484Sbostic       e += fontpath;
30469484Sbostic     }
30569484Sbostic     e += '\0';
30669484Sbostic     if (putenv(strsave(e.contents())))
30769484Sbostic       fatal("putenv failed");
30869484Sbostic   }
30969484Sbostic   if (Vflag) {
31069484Sbostic     print_commands();
31169484Sbostic     exit(0);
31269484Sbostic   }
31369484Sbostic   exit(run_commands());
31469484Sbostic }
31569484Sbostic 
basename(const char * s)31669484Sbostic const char *basename(const char *s)
31769484Sbostic {
31869484Sbostic   if (!s)
31969484Sbostic     return 0;
32069484Sbostic   const char *p = strrchr(s, '/');
32169484Sbostic   return p ? p + 1 : s;
32269484Sbostic }
32369484Sbostic 
handle_unknown_desc_command(const char * command,const char * arg,const char * filename,int lineno)32469484Sbostic void handle_unknown_desc_command(const char *command, const char *arg,
32569484Sbostic 				 const char *filename, int lineno)
32669484Sbostic {
32769484Sbostic   if (strcmp(command, "print") == 0) {
32869484Sbostic     if (arg == 0)
32969484Sbostic       error_with_file_and_line(filename, lineno,
33069484Sbostic 			       "`print' command requires an argument");
33169484Sbostic     else
33269484Sbostic       spooler = strsave(arg);
33369484Sbostic   }
33469484Sbostic   if (strcmp(command, "postpro") == 0) {
33569484Sbostic     if (arg == 0)
33669484Sbostic       error_with_file_and_line(filename, lineno,
33769484Sbostic 			       "`postpro' command requires an argument");
33869484Sbostic     else {
33969484Sbostic       for (const char *p = arg; *p; p++)
34069484Sbostic 	if (csspace(*p)) {
34169484Sbostic 	  error_with_file_and_line(filename, lineno,
34269484Sbostic 				   "invalid `postpro' argument `%1'"
34369484Sbostic 				   ": program name required", arg);
34469484Sbostic 	  return;
34569484Sbostic 	}
34669484Sbostic       driver = strsave(arg);
34769484Sbostic     }
34869484Sbostic   }
34969484Sbostic }
35069484Sbostic 
print_commands()35169484Sbostic void print_commands()
35269484Sbostic {
35369484Sbostic   for (int last = SPOOL_INDEX; last >= 0; last--)
35469484Sbostic     if (commands[last].get_name() != 0)
35569484Sbostic       break;
35669484Sbostic   for (int i = 0; i <= last; i++)
35769484Sbostic     if (commands[i].get_name() != 0)
35869484Sbostic       commands[i].print(i == last, stdout);
35969484Sbostic }
36069484Sbostic 
36169484Sbostic // Run the commands. Return the code with which to exit.
36269484Sbostic 
run_commands()36369484Sbostic int run_commands()
36469484Sbostic {
36569484Sbostic   char **v[NCOMMANDS];
36669484Sbostic   int j = 0;
36769484Sbostic   for (int i = 0; i < NCOMMANDS; i++)
36869484Sbostic     if (commands[i].get_name() != 0)
36969484Sbostic       v[j++] = commands[i].get_argv();
37069484Sbostic   return run_pipeline(j, v);
37169484Sbostic }
37269484Sbostic 
possible_command()37369484Sbostic possible_command::possible_command()
37469484Sbostic : name(0), argv(0)
37569484Sbostic {
37669484Sbostic }
37769484Sbostic 
~possible_command()37869484Sbostic possible_command::~possible_command()
37969484Sbostic {
38069484Sbostic   a_delete name;
38169484Sbostic   a_delete argv;
38269484Sbostic }
38369484Sbostic 
set_name(const char * s)38469484Sbostic void possible_command::set_name(const char *s)
38569484Sbostic {
38669484Sbostic   a_delete name;
38769484Sbostic   name = strsave(s);
38869484Sbostic }
38969484Sbostic 
set_name(const char * s1,const char * s2)39069484Sbostic void possible_command::set_name(const char *s1, const char *s2)
39169484Sbostic {
39269484Sbostic   a_delete name;
39369484Sbostic   name = new char[strlen(s1) + strlen(s2) + 1];
39469484Sbostic   strcpy(name, s1);
39569484Sbostic   strcat(name, s2);
39669484Sbostic }
39769484Sbostic 
get_name()39869484Sbostic const char *possible_command::get_name()
39969484Sbostic {
40069484Sbostic   return name;
40169484Sbostic }
40269484Sbostic 
clear_args()40369484Sbostic void possible_command::clear_args()
40469484Sbostic {
40569484Sbostic   args.clear();
40669484Sbostic }
40769484Sbostic 
append_arg(const char * s,const char * t)40869484Sbostic void possible_command::append_arg(const char *s, const char *t)
40969484Sbostic {
41069484Sbostic   args += s;
41169484Sbostic   if (t)
41269484Sbostic     args += t;
41369484Sbostic   args += '\0';
41469484Sbostic }
41569484Sbostic 
build_argv()41669484Sbostic void possible_command::build_argv()
41769484Sbostic {
41869484Sbostic   if (argv)
41969484Sbostic     return;
42069484Sbostic   // Count the number of arguments.
42169484Sbostic   int len = args.length();
42269484Sbostic   int argc = 1;
42369484Sbostic   char *p = 0;
42469484Sbostic   if (len > 0) {
42569484Sbostic     p = &args[0];
42669484Sbostic     for (int i = 0; i < len; i++)
42769484Sbostic       if (p[i] == '\0')
42869484Sbostic 	argc++;
42969484Sbostic   }
43069484Sbostic   // Build an argument vector.
43169484Sbostic   argv = new char *[argc + 1];
43269484Sbostic   argv[0] = name;
43369484Sbostic   for (int i = 1; i < argc; i++) {
43469484Sbostic     argv[i] = p;
43569484Sbostic     p = strchr(p, '\0') + 1;
43669484Sbostic   }
43769484Sbostic   argv[argc] = 0;
43869484Sbostic }
43969484Sbostic 
print(int is_last,FILE * fp)44069484Sbostic void possible_command::print(int is_last, FILE *fp)
44169484Sbostic {
44269484Sbostic   build_argv();
44369484Sbostic   if (argv[0] != 0 && strcmp(argv[0], BSHELL) == 0
44469484Sbostic       && argv[1] != 0 && strcmp(argv[1], "-c") == 0
44569484Sbostic       && argv[2] != 0 && argv[3] == 0)
44669484Sbostic     fputs(argv[2], fp);
44769484Sbostic   else {
44869484Sbostic     fputs(argv[0], fp);
44969484Sbostic     string str;
45069484Sbostic     for (int i = 1; argv[i] != 0; i++) {
45169484Sbostic       str.clear();
45269484Sbostic       append_arg_to_string(argv[i], str);
45369484Sbostic       put_string(str, fp);
45469484Sbostic     }
45569484Sbostic   }
45669484Sbostic   if (is_last)
45769484Sbostic     putc('\n', fp);
45869484Sbostic   else
45969484Sbostic     fputs(" | ", fp);
46069484Sbostic }
46169484Sbostic 
append_arg_to_string(const char * arg,string & str)46269484Sbostic void append_arg_to_string(const char *arg, string &str)
46369484Sbostic {
46469484Sbostic   str += ' ';
46569484Sbostic   int needs_quoting = 0;
46669484Sbostic   int contains_single_quote = 0;
46769484Sbostic   for (const char *p = arg; *p != '\0'; p++)
46869484Sbostic     switch (*p) {
46969484Sbostic     case ';':
47069484Sbostic     case '&':
47169484Sbostic     case '(':
47269484Sbostic     case ')':
47369484Sbostic     case '|':
47469484Sbostic     case '^':
47569484Sbostic     case '<':
47669484Sbostic     case '>':
47769484Sbostic     case '\n':
47869484Sbostic     case ' ':
47969484Sbostic     case '\t':
48069484Sbostic     case '\\':
48169484Sbostic     case '"':
48269484Sbostic     case '$':
48369484Sbostic     case '?':
48469484Sbostic     case '*':
48569484Sbostic       needs_quoting = 1;
48669484Sbostic       break;
48769484Sbostic     case '\'':
48869484Sbostic       contains_single_quote = 1;
48969484Sbostic       break;
49069484Sbostic     }
49169484Sbostic   if (contains_single_quote || arg[0] == '\0') {
49269484Sbostic     str += '"';
49369484Sbostic     for (p = arg; *p != '\0'; p++)
49469484Sbostic       switch (*p) {
49569484Sbostic       case '"':
49669484Sbostic       case '\\':
49769484Sbostic       case '$':
49869484Sbostic 	str += '\\';
49969484Sbostic 	// fall through
50069484Sbostic       default:
50169484Sbostic 	str += *p;
50269484Sbostic 	break;
50369484Sbostic       }
50469484Sbostic     str += '"';
50569484Sbostic   }
50669484Sbostic   else if (needs_quoting) {
50769484Sbostic     str += '\'';
50869484Sbostic     str += arg;
50969484Sbostic     str += '\'';
51069484Sbostic   }
51169484Sbostic   else
51269484Sbostic     str += arg;
51369484Sbostic }
51469484Sbostic 
get_argv()51569484Sbostic char **possible_command::get_argv()
51669484Sbostic {
51769484Sbostic   build_argv();
51869484Sbostic   return argv;
51969484Sbostic }
52069484Sbostic 
synopsis()52169484Sbostic void synopsis()
52269484Sbostic {
52369484Sbostic   fprintf(stderr,
52469484Sbostic "usage: %s [-abehilpstvzCENRVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n"
52569484Sbostic "       [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n"
52669484Sbostic "       [files...]\n",
52769484Sbostic 	  program_name);
52869484Sbostic }
52969484Sbostic 
help()53069484Sbostic void help()
53169484Sbostic {
53269484Sbostic   synopsis();
53369484Sbostic   fputs("\n"
53469484Sbostic "-h\tprint this message\n"
53569484Sbostic "-t\tpreprocess with tbl\n"
53669484Sbostic "-p\tpreprocess with pic\n"
53769484Sbostic "-e\tpreprocess with eqn\n"
53869484Sbostic "-s\tpreprocess with soelim\n"
53969484Sbostic "-R\tpreprocess with refer\n"
54069484Sbostic "-Tdev\tuse device dev\n"
54169484Sbostic "-X\tuse X11 previewer rather than usual postprocessor\n"
54269484Sbostic "-mname\tread macros tmac.name\n"
54369484Sbostic "-dcs\tdefine a string c as s\n"
54469484Sbostic "-rcn\tdefine a number register c as n\n"
54569484Sbostic "-nnum\tnumber first page n\n"
54669484Sbostic "-olist\toutput only pages in list\n"
54769484Sbostic "-ffam\tuse fam as the default font family\n"
54869484Sbostic "-Fdir\tsearch directory dir for device directories\n"
54969484Sbostic "-Mdir\tsearch dir for macro files\n"
55069484Sbostic "-v\tprint version number\n"
55169484Sbostic "-z\tsuppress formatted output\n"
55269484Sbostic "-Z\tdon't postprocess\n"
55369484Sbostic "-a\tproduce ASCII description of output\n"
55469484Sbostic "-i\tread standard input after named input files\n"
55569484Sbostic "-wname\tenable warning name\n"
55669484Sbostic "-Wname\tinhibit warning name\n"
55769484Sbostic "-E\tinhibit all errors\n"
55869484Sbostic "-b\tprint backtraces with errors or warnings\n"
55969484Sbostic "-l\tspool the output\n"
56069484Sbostic "-C\tenable compatibility mode\n"
56169484Sbostic "-V\tprint commands on stdout instead of running them\n"
56269484Sbostic "-Parg\tpass arg to the postprocessor\n"
56369484Sbostic "-Larg\tpass arg to the spooler\n"
56469484Sbostic "-N\tdon't allow newlines within eqn delimiters\n"
56569484Sbostic "\n",
56669484Sbostic 	stderr);
56769484Sbostic   exit(0);
56869484Sbostic }
56969484Sbostic 
usage()57069484Sbostic void usage()
57169484Sbostic {
57269484Sbostic   synopsis();
57369484Sbostic   fprintf(stderr, "%s -h gives more help\n", program_name);
57469484Sbostic   exit(1);
57569484Sbostic }
57669484Sbostic 
57769484Sbostic extern "C" {
57869484Sbostic 
c_error(const char * format,const char * arg1,const char * arg2,const char * arg3)57969484Sbostic void c_error(const char *format, const char *arg1, const char *arg2,
58069484Sbostic 	     const char *arg3)
58169484Sbostic {
58269484Sbostic   error(format, arg1, arg2, arg3);
58369484Sbostic }
58469484Sbostic 
c_fatal(const char * format,const char * arg1,const char * arg2,const char * arg3)58569484Sbostic void c_fatal(const char *format, const char *arg1, const char *arg2,
58669484Sbostic 	     const char *arg3)
58769484Sbostic {
58869484Sbostic   fatal(format, arg1, arg2, arg3);
58969484Sbostic }
59069484Sbostic 
59169484Sbostic }
592