10791b176Sbostic // -*- C++ -*-
20791b176Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
30791b176Sbostic      Written by James Clark (jjc@jclark.com)
40791b176Sbostic 
50791b176Sbostic This file is part of groff.
60791b176Sbostic 
70791b176Sbostic groff is free software; you can redistribute it and/or modify it under
80791b176Sbostic the terms of the GNU General Public License as published by the Free
90791b176Sbostic Software Foundation; either version 2, or (at your option) any later
100791b176Sbostic version.
110791b176Sbostic 
120791b176Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
130791b176Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
140791b176Sbostic FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
150791b176Sbostic for more details.
160791b176Sbostic 
170791b176Sbostic You should have received a copy of the GNU General Public License along
180791b176Sbostic with groff; see the file COPYING.  If not, write to the Free Software
190791b176Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
200791b176Sbostic 
210791b176Sbostic // A front end for groff.
220791b176Sbostic 
230791b176Sbostic #include <stdio.h>
240791b176Sbostic #include <string.h>
25*99dbc356Sbostic #include <unistd.h>
260791b176Sbostic #include <stdlib.h>
270791b176Sbostic #include <signal.h>
280791b176Sbostic #include <errno.h>
290791b176Sbostic 
300791b176Sbostic #include "lib.h"
310791b176Sbostic #include "assert.h"
320791b176Sbostic #include "errarg.h"
330791b176Sbostic #include "error.h"
340791b176Sbostic #include "stringclass.h"
350791b176Sbostic #include "cset.h"
360791b176Sbostic #include "font.h"
370791b176Sbostic #include "device.h"
380791b176Sbostic #include "pipeline.h"
390791b176Sbostic #include "defs.h"
400791b176Sbostic 
410791b176Sbostic #define BSHELL "/bin/sh"
420791b176Sbostic #define GXDITVIEW "gxditview"
430791b176Sbostic 
440791b176Sbostic // troff will be passed an argument of -rXREG=1 if the -X option is
450791b176Sbostic // specified
460791b176Sbostic #define XREG ".X"
470791b176Sbostic 
480791b176Sbostic #ifndef STDLIB_H_DECLARES_PUTENV
490791b176Sbostic extern "C" {
500791b176Sbostic   int putenv(const char *);
510791b176Sbostic }
520791b176Sbostic #endif /* not STDLIB_H_DECLARES_PUTENV */
530791b176Sbostic 
540791b176Sbostic const char *strsignal(int);
550791b176Sbostic 
560791b176Sbostic const int SOELIM_INDEX = 0;
570791b176Sbostic const int REFER_INDEX = SOELIM_INDEX + 1;
580791b176Sbostic const int PIC_INDEX = REFER_INDEX + 1;
590791b176Sbostic const int TBL_INDEX = PIC_INDEX + 1;
600791b176Sbostic const int EQN_INDEX = TBL_INDEX + 1;
610791b176Sbostic const int TROFF_INDEX = EQN_INDEX + 1;
620791b176Sbostic const int POST_INDEX = TROFF_INDEX + 1;
630791b176Sbostic const int SPOOL_INDEX = POST_INDEX + 1;
640791b176Sbostic 
650791b176Sbostic const int NCOMMANDS = SPOOL_INDEX + 1;
660791b176Sbostic 
670791b176Sbostic class possible_command {
680791b176Sbostic   char *name;
690791b176Sbostic   string args;
700791b176Sbostic   char **argv;
710791b176Sbostic 
720791b176Sbostic   void build_argv();
730791b176Sbostic public:
740791b176Sbostic   possible_command();
750791b176Sbostic   ~possible_command();
760791b176Sbostic   void set_name(const char *);
770791b176Sbostic   void set_name(const char *, const char *);
780791b176Sbostic   const char *get_name();
790791b176Sbostic   void append_arg(const char *, const char * = 0);
800791b176Sbostic   void clear_args();
810791b176Sbostic   char **get_argv();
820791b176Sbostic   void print(int is_last, FILE *fp);
830791b176Sbostic };
840791b176Sbostic 
850791b176Sbostic int lflag = 0;
860791b176Sbostic char *spooler = 0;
870791b176Sbostic char *driver = 0;
880791b176Sbostic 
890791b176Sbostic possible_command commands[NCOMMANDS];
900791b176Sbostic 
910791b176Sbostic int run_commands();
920791b176Sbostic void print_commands();
930791b176Sbostic void append_arg_to_string(const char *arg, string &str);
940791b176Sbostic void handle_unknown_desc_command(const char *command, const char *arg,
950791b176Sbostic 				 const char *filename, int lineno);
960791b176Sbostic const char *basename(const char *);
970791b176Sbostic 
980791b176Sbostic void usage();
990791b176Sbostic void help();
1000791b176Sbostic 
main(int argc,char ** argv)1010791b176Sbostic int main(int argc, char **argv)
1020791b176Sbostic {
1030791b176Sbostic   program_name = argv[0];
1040791b176Sbostic   static char stderr_buf[BUFSIZ];
1050791b176Sbostic   setbuf(stderr, stderr_buf);
1060791b176Sbostic   assert(NCOMMANDS <= MAX_COMMANDS);
1070791b176Sbostic   string Pargs, Largs, Fargs;
1080791b176Sbostic   int Vflag = 0;
1090791b176Sbostic   int zflag = 0;
1100791b176Sbostic   int iflag = 0;
1110791b176Sbostic   int Xflag = 0;
1120791b176Sbostic   int opt;
1130791b176Sbostic   const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
1140791b176Sbostic   if (!command_prefix)
1150791b176Sbostic     command_prefix = PROG_PREFIX;
1160791b176Sbostic   commands[TROFF_INDEX].set_name(command_prefix, "troff");
1170791b176Sbostic   while ((opt = getopt(argc, argv,
1180791b176Sbostic 		       "itpeRszavVhblCENXZF:m:T:f:w:W:M:d:r:n:o:P:L:"))
1190791b176Sbostic 	 != EOF) {
1200791b176Sbostic     char buf[3];
1210791b176Sbostic     buf[0] = '-';
1220791b176Sbostic     buf[1] = opt;
1230791b176Sbostic     buf[2] = '\0';
1240791b176Sbostic     switch (opt) {
1250791b176Sbostic     case 'i':
1260791b176Sbostic       iflag = 1;
1270791b176Sbostic       break;
1280791b176Sbostic     case 't':
1290791b176Sbostic       commands[TBL_INDEX].set_name(command_prefix, "tbl");
1300791b176Sbostic       break;
1310791b176Sbostic     case 'p':
1320791b176Sbostic       commands[PIC_INDEX].set_name(command_prefix, "pic");
1330791b176Sbostic       break;
1340791b176Sbostic     case 'e':
1350791b176Sbostic       commands[EQN_INDEX].set_name(command_prefix, "eqn");
1360791b176Sbostic       break;
1370791b176Sbostic     case 's':
1380791b176Sbostic       commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
1390791b176Sbostic       break;
1400791b176Sbostic     case 'R':
1410791b176Sbostic       commands[REFER_INDEX].set_name(command_prefix, "refer");
1420791b176Sbostic       break;
1430791b176Sbostic     case 'z':
1440791b176Sbostic     case 'a':
1450791b176Sbostic       commands[TROFF_INDEX].append_arg(buf);
1460791b176Sbostic       // fall through
1470791b176Sbostic     case 'Z':
1480791b176Sbostic       zflag++;
1490791b176Sbostic       break;
1500791b176Sbostic     case 'l':
1510791b176Sbostic       lflag++;
1520791b176Sbostic       break;
1530791b176Sbostic     case 'V':
1540791b176Sbostic       Vflag++;
1550791b176Sbostic       break;
1560791b176Sbostic     case 'v':
1570791b176Sbostic     case 'C':
1580791b176Sbostic       commands[SOELIM_INDEX].append_arg(buf);
1590791b176Sbostic       commands[PIC_INDEX].append_arg(buf);
1600791b176Sbostic       commands[TBL_INDEX].append_arg(buf);
1610791b176Sbostic       commands[EQN_INDEX].append_arg(buf);
1620791b176Sbostic       commands[TROFF_INDEX].append_arg(buf);
1630791b176Sbostic       break;
1640791b176Sbostic     case 'N':
1650791b176Sbostic       commands[EQN_INDEX].append_arg(buf);
1660791b176Sbostic       break;
1670791b176Sbostic     case 'h':
1680791b176Sbostic       help();
1690791b176Sbostic       break;
1700791b176Sbostic     case 'E':
1710791b176Sbostic     case 'b':
1720791b176Sbostic       commands[TROFF_INDEX].append_arg(buf);
1730791b176Sbostic       break;
1740791b176Sbostic     case 'T':
1750791b176Sbostic       if (strcmp(optarg, "Xps") == 0) {
1760791b176Sbostic 	warning("-TXps option is obsolete: use -X -Tps instead");
1770791b176Sbostic 	device = "ps";
1780791b176Sbostic 	Xflag++;
1790791b176Sbostic       }
1800791b176Sbostic       else
1810791b176Sbostic 	device = optarg;
1820791b176Sbostic       break;
1830791b176Sbostic     case 'F':
1840791b176Sbostic       font::command_line_font_dir(optarg);
1850791b176Sbostic       if (Fargs.length() > 0) {
1860791b176Sbostic 	Fargs += ':';
1870791b176Sbostic 	Fargs += optarg;
1880791b176Sbostic       }
1890791b176Sbostic       else
1900791b176Sbostic 	Fargs = optarg;
1910791b176Sbostic       break;
1920791b176Sbostic     case 'f':
1930791b176Sbostic     case 'o':
1940791b176Sbostic     case 'm':
1950791b176Sbostic     case 'r':
1960791b176Sbostic     case 'd':
1970791b176Sbostic     case 'n':
1980791b176Sbostic     case 'w':
1990791b176Sbostic     case 'W':
2000791b176Sbostic       commands[TROFF_INDEX].append_arg(buf, optarg);
2010791b176Sbostic       break;
2020791b176Sbostic     case 'M':
2030791b176Sbostic       commands[EQN_INDEX].append_arg(buf, optarg);
2040791b176Sbostic       commands[TROFF_INDEX].append_arg(buf, optarg);
2050791b176Sbostic       break;
2060791b176Sbostic     case 'P':
2070791b176Sbostic       Pargs += optarg;
2080791b176Sbostic       Pargs += '\0';
2090791b176Sbostic       break;
2100791b176Sbostic     case 'L':
2110791b176Sbostic       append_arg_to_string(optarg, Largs);
2120791b176Sbostic       break;
2130791b176Sbostic     case 'X':
2140791b176Sbostic       Xflag++;
2150791b176Sbostic       break;
2160791b176Sbostic     case '?':
2170791b176Sbostic       usage();
2180791b176Sbostic       break;
2190791b176Sbostic     default:
2200791b176Sbostic       assert(0);
2210791b176Sbostic       break;
2220791b176Sbostic     }
2230791b176Sbostic   }
2240791b176Sbostic   font::set_unknown_desc_command_handler(handle_unknown_desc_command);
2250791b176Sbostic   if (!font::load_desc())
2260791b176Sbostic     fatal("invalid device `%1'", device);
2270791b176Sbostic   if (!driver)
2280791b176Sbostic     fatal("no `postpro' command in DESC file for device `%1'", device);
2290791b176Sbostic   const char *real_driver = 0;
2300791b176Sbostic   if (Xflag) {
2310791b176Sbostic     real_driver = driver;
2320791b176Sbostic     driver = GXDITVIEW;
2330791b176Sbostic     commands[TROFF_INDEX].append_arg("-r" XREG "=", "1");
2340791b176Sbostic   }
2350791b176Sbostic   if (driver)
2360791b176Sbostic     commands[POST_INDEX].set_name(driver);
2370791b176Sbostic   int gxditview_flag = driver && strcmp(basename(driver), GXDITVIEW) == 0;
2380791b176Sbostic   if (gxditview_flag && argc - optind == 1) {
2390791b176Sbostic     commands[POST_INDEX].append_arg("-title");
2400791b176Sbostic     commands[POST_INDEX].append_arg(argv[optind]);
2410791b176Sbostic     commands[POST_INDEX].append_arg("-xrm");
2420791b176Sbostic     commands[POST_INDEX].append_arg("*iconName:", argv[optind]);
2430791b176Sbostic     string filename_string("|");
2440791b176Sbostic     append_arg_to_string(argv[0], filename_string);
2450791b176Sbostic     append_arg_to_string("-Z", filename_string);
2460791b176Sbostic     for (int i = 1; i < argc; i++)
2470791b176Sbostic       append_arg_to_string(argv[i], filename_string);
2480791b176Sbostic     filename_string += '\0';
2490791b176Sbostic     commands[POST_INDEX].append_arg("-filename");
2500791b176Sbostic     commands[POST_INDEX].append_arg(filename_string.contents());
2510791b176Sbostic   }
2520791b176Sbostic   if (gxditview_flag && Xflag) {
2530791b176Sbostic     string print_string(real_driver);
2540791b176Sbostic     if (spooler) {
2550791b176Sbostic       print_string += " | ";
2560791b176Sbostic       print_string += spooler;
2570791b176Sbostic       print_string += Largs;
2580791b176Sbostic     }
2590791b176Sbostic     print_string += '\0';
2600791b176Sbostic     commands[POST_INDEX].append_arg("-printCommand");
2610791b176Sbostic     commands[POST_INDEX].append_arg(print_string.contents());
2620791b176Sbostic   }
2630791b176Sbostic   const char *p = Pargs.contents();
2640791b176Sbostic   const char *end = p + Pargs.length();
2650791b176Sbostic   while (p < end) {
2660791b176Sbostic     commands[POST_INDEX].append_arg(p);
2670791b176Sbostic     p = strchr(p, '\0') + 1;
2680791b176Sbostic   }
2690791b176Sbostic   if (gxditview_flag)
2700791b176Sbostic     commands[POST_INDEX].append_arg("-");
2710791b176Sbostic   if (lflag && !Xflag && spooler) {
2720791b176Sbostic     commands[SPOOL_INDEX].set_name(BSHELL);
2730791b176Sbostic     commands[SPOOL_INDEX].append_arg("-c");
2740791b176Sbostic     Largs += '\0';
2750791b176Sbostic     Largs = spooler + Largs;
2760791b176Sbostic     commands[SPOOL_INDEX].append_arg(Largs.contents());
2770791b176Sbostic   }
2780791b176Sbostic   if (zflag) {
2790791b176Sbostic     commands[POST_INDEX].set_name(0);
2800791b176Sbostic     commands[SPOOL_INDEX].set_name(0);
2810791b176Sbostic   }
2820791b176Sbostic   commands[TROFF_INDEX].append_arg("-T", device);
2830791b176Sbostic   commands[EQN_INDEX].append_arg("-T", device);
2840791b176Sbostic 
2850791b176Sbostic   for (int first_index = 0; first_index < TROFF_INDEX; first_index++)
2860791b176Sbostic     if (commands[first_index].get_name() != 0)
2870791b176Sbostic       break;
2880791b176Sbostic   if (optind < argc) {
2890791b176Sbostic     if (argv[optind][0] == '-' && argv[optind][1] != '\0')
2900791b176Sbostic       commands[first_index].append_arg("--");
2910791b176Sbostic     for (int i = optind; i < argc; i++)
2920791b176Sbostic       commands[first_index].append_arg(argv[i]);
2930791b176Sbostic     if (iflag)
2940791b176Sbostic       commands[first_index].append_arg("-");
2950791b176Sbostic   }
2960791b176Sbostic   if (Fargs.length() > 0) {
2970791b176Sbostic     string e = "GROFF_FONT_PATH";
2980791b176Sbostic     e += '=';
2990791b176Sbostic     e += Fargs;
3000791b176Sbostic     char *fontpath = getenv("GROFF_FONT_PATH");
3010791b176Sbostic     if (fontpath && *fontpath) {
3020791b176Sbostic       e += ':';
3030791b176Sbostic       e += fontpath;
3040791b176Sbostic     }
3050791b176Sbostic     e += '\0';
3060791b176Sbostic     if (putenv(strsave(e.contents())))
3070791b176Sbostic       fatal("putenv failed");
3080791b176Sbostic   }
3090791b176Sbostic   if (Vflag) {
3100791b176Sbostic     print_commands();
3110791b176Sbostic     exit(0);
3120791b176Sbostic   }
3130791b176Sbostic   exit(run_commands());
3140791b176Sbostic }
3150791b176Sbostic 
basename(const char * s)3160791b176Sbostic const char *basename(const char *s)
3170791b176Sbostic {
3180791b176Sbostic   if (!s)
3190791b176Sbostic     return 0;
3200791b176Sbostic   const char *p = strrchr(s, '/');
3210791b176Sbostic   return p ? p + 1 : s;
3220791b176Sbostic }
3230791b176Sbostic 
handle_unknown_desc_command(const char * command,const char * arg,const char * filename,int lineno)3240791b176Sbostic void handle_unknown_desc_command(const char *command, const char *arg,
3250791b176Sbostic 				 const char *filename, int lineno)
3260791b176Sbostic {
3270791b176Sbostic   if (strcmp(command, "print") == 0) {
3280791b176Sbostic     if (arg == 0)
3290791b176Sbostic       error_with_file_and_line(filename, lineno,
3300791b176Sbostic 			       "`print' command requires an argument");
3310791b176Sbostic     else
3320791b176Sbostic       spooler = strsave(arg);
3330791b176Sbostic   }
3340791b176Sbostic   if (strcmp(command, "postpro") == 0) {
3350791b176Sbostic     if (arg == 0)
3360791b176Sbostic       error_with_file_and_line(filename, lineno,
3370791b176Sbostic 			       "`postpro' command requires an argument");
3380791b176Sbostic     else {
3390791b176Sbostic       for (const char *p = arg; *p; p++)
3400791b176Sbostic 	if (csspace(*p)) {
3410791b176Sbostic 	  error_with_file_and_line(filename, lineno,
3420791b176Sbostic 				   "invalid `postpro' argument `%1'"
3430791b176Sbostic 				   ": program name required", arg);
3440791b176Sbostic 	  return;
3450791b176Sbostic 	}
3460791b176Sbostic       driver = strsave(arg);
3470791b176Sbostic     }
3480791b176Sbostic   }
3490791b176Sbostic }
3500791b176Sbostic 
print_commands()3510791b176Sbostic void print_commands()
3520791b176Sbostic {
3530791b176Sbostic   for (int last = SPOOL_INDEX; last >= 0; last--)
3540791b176Sbostic     if (commands[last].get_name() != 0)
3550791b176Sbostic       break;
3560791b176Sbostic   for (int i = 0; i <= last; i++)
3570791b176Sbostic     if (commands[i].get_name() != 0)
3580791b176Sbostic       commands[i].print(i == last, stdout);
3590791b176Sbostic }
3600791b176Sbostic 
3610791b176Sbostic // Run the commands. Return the code with which to exit.
3620791b176Sbostic 
run_commands()3630791b176Sbostic int run_commands()
3640791b176Sbostic {
3650791b176Sbostic   char **v[NCOMMANDS];
3660791b176Sbostic   int j = 0;
3670791b176Sbostic   for (int i = 0; i < NCOMMANDS; i++)
3680791b176Sbostic     if (commands[i].get_name() != 0)
3690791b176Sbostic       v[j++] = commands[i].get_argv();
3700791b176Sbostic   return run_pipeline(j, v);
3710791b176Sbostic }
3720791b176Sbostic 
possible_command()3730791b176Sbostic possible_command::possible_command()
3740791b176Sbostic : name(0), argv(0)
3750791b176Sbostic {
3760791b176Sbostic }
3770791b176Sbostic 
~possible_command()3780791b176Sbostic possible_command::~possible_command()
3790791b176Sbostic {
3800791b176Sbostic   a_delete name;
3810791b176Sbostic   a_delete argv;
3820791b176Sbostic }
3830791b176Sbostic 
set_name(const char * s)3840791b176Sbostic void possible_command::set_name(const char *s)
3850791b176Sbostic {
3860791b176Sbostic   a_delete name;
3870791b176Sbostic   name = strsave(s);
3880791b176Sbostic }
3890791b176Sbostic 
set_name(const char * s1,const char * s2)3900791b176Sbostic void possible_command::set_name(const char *s1, const char *s2)
3910791b176Sbostic {
3920791b176Sbostic   a_delete name;
3930791b176Sbostic   name = new char[strlen(s1) + strlen(s2) + 1];
3940791b176Sbostic   strcpy(name, s1);
3950791b176Sbostic   strcat(name, s2);
3960791b176Sbostic }
3970791b176Sbostic 
get_name()3980791b176Sbostic const char *possible_command::get_name()
3990791b176Sbostic {
4000791b176Sbostic   return name;
4010791b176Sbostic }
4020791b176Sbostic 
clear_args()4030791b176Sbostic void possible_command::clear_args()
4040791b176Sbostic {
4050791b176Sbostic   args.clear();
4060791b176Sbostic }
4070791b176Sbostic 
append_arg(const char * s,const char * t)4080791b176Sbostic void possible_command::append_arg(const char *s, const char *t)
4090791b176Sbostic {
4100791b176Sbostic   args += s;
4110791b176Sbostic   if (t)
4120791b176Sbostic     args += t;
4130791b176Sbostic   args += '\0';
4140791b176Sbostic }
4150791b176Sbostic 
build_argv()4160791b176Sbostic void possible_command::build_argv()
4170791b176Sbostic {
4180791b176Sbostic   if (argv)
4190791b176Sbostic     return;
4200791b176Sbostic   // Count the number of arguments.
4210791b176Sbostic   int len = args.length();
4220791b176Sbostic   int argc = 1;
4230791b176Sbostic   char *p = 0;
4240791b176Sbostic   if (len > 0) {
4250791b176Sbostic     p = &args[0];
4260791b176Sbostic     for (int i = 0; i < len; i++)
4270791b176Sbostic       if (p[i] == '\0')
4280791b176Sbostic 	argc++;
4290791b176Sbostic   }
4300791b176Sbostic   // Build an argument vector.
4310791b176Sbostic   argv = new char *[argc + 1];
4320791b176Sbostic   argv[0] = name;
4330791b176Sbostic   for (int i = 1; i < argc; i++) {
4340791b176Sbostic     argv[i] = p;
4350791b176Sbostic     p = strchr(p, '\0') + 1;
4360791b176Sbostic   }
4370791b176Sbostic   argv[argc] = 0;
4380791b176Sbostic }
4390791b176Sbostic 
print(int is_last,FILE * fp)4400791b176Sbostic void possible_command::print(int is_last, FILE *fp)
4410791b176Sbostic {
4420791b176Sbostic   build_argv();
4430791b176Sbostic   if (argv[0] != 0 && strcmp(argv[0], BSHELL) == 0
4440791b176Sbostic       && argv[1] != 0 && strcmp(argv[1], "-c") == 0
4450791b176Sbostic       && argv[2] != 0 && argv[3] == 0)
4460791b176Sbostic     fputs(argv[2], fp);
4470791b176Sbostic   else {
4480791b176Sbostic     fputs(argv[0], fp);
4490791b176Sbostic     string str;
4500791b176Sbostic     for (int i = 1; argv[i] != 0; i++) {
4510791b176Sbostic       str.clear();
4520791b176Sbostic       append_arg_to_string(argv[i], str);
4530791b176Sbostic       put_string(str, fp);
4540791b176Sbostic     }
4550791b176Sbostic   }
4560791b176Sbostic   if (is_last)
4570791b176Sbostic     putc('\n', fp);
4580791b176Sbostic   else
4590791b176Sbostic     fputs(" | ", fp);
4600791b176Sbostic }
4610791b176Sbostic 
append_arg_to_string(const char * arg,string & str)4620791b176Sbostic void append_arg_to_string(const char *arg, string &str)
4630791b176Sbostic {
4640791b176Sbostic   str += ' ';
4650791b176Sbostic   int needs_quoting = 0;
4660791b176Sbostic   int contains_single_quote = 0;
4670791b176Sbostic   for (const char *p = arg; *p != '\0'; p++)
4680791b176Sbostic     switch (*p) {
4690791b176Sbostic     case ';':
4700791b176Sbostic     case '&':
4710791b176Sbostic     case '(':
4720791b176Sbostic     case ')':
4730791b176Sbostic     case '|':
4740791b176Sbostic     case '^':
4750791b176Sbostic     case '<':
4760791b176Sbostic     case '>':
4770791b176Sbostic     case '\n':
4780791b176Sbostic     case ' ':
4790791b176Sbostic     case '\t':
4800791b176Sbostic     case '\\':
4810791b176Sbostic     case '"':
4820791b176Sbostic     case '$':
4830791b176Sbostic     case '?':
4840791b176Sbostic     case '*':
4850791b176Sbostic       needs_quoting = 1;
4860791b176Sbostic       break;
4870791b176Sbostic     case '\'':
4880791b176Sbostic       contains_single_quote = 1;
4890791b176Sbostic       break;
4900791b176Sbostic     }
4910791b176Sbostic   if (contains_single_quote || arg[0] == '\0') {
4920791b176Sbostic     str += '"';
4930791b176Sbostic     for (p = arg; *p != '\0'; p++)
4940791b176Sbostic       switch (*p) {
4950791b176Sbostic       case '"':
4960791b176Sbostic       case '\\':
4970791b176Sbostic       case '$':
4980791b176Sbostic 	str += '\\';
4990791b176Sbostic 	// fall through
5000791b176Sbostic       default:
5010791b176Sbostic 	str += *p;
5020791b176Sbostic 	break;
5030791b176Sbostic       }
5040791b176Sbostic     str += '"';
5050791b176Sbostic   }
5060791b176Sbostic   else if (needs_quoting) {
5070791b176Sbostic     str += '\'';
5080791b176Sbostic     str += arg;
5090791b176Sbostic     str += '\'';
5100791b176Sbostic   }
5110791b176Sbostic   else
5120791b176Sbostic     str += arg;
5130791b176Sbostic }
5140791b176Sbostic 
get_argv()5150791b176Sbostic char **possible_command::get_argv()
5160791b176Sbostic {
5170791b176Sbostic   build_argv();
5180791b176Sbostic   return argv;
5190791b176Sbostic }
5200791b176Sbostic 
synopsis()5210791b176Sbostic void synopsis()
5220791b176Sbostic {
5230791b176Sbostic   fprintf(stderr,
5240791b176Sbostic "usage: %s [-abehilpstvzCENRVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n"
5250791b176Sbostic "       [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n"
5260791b176Sbostic "       [files...]\n",
5270791b176Sbostic 	  program_name);
5280791b176Sbostic }
5290791b176Sbostic 
help()5300791b176Sbostic void help()
5310791b176Sbostic {
5320791b176Sbostic   synopsis();
5330791b176Sbostic   fputs("\n"
5340791b176Sbostic "-h\tprint this message\n"
5350791b176Sbostic "-t\tpreprocess with tbl\n"
5360791b176Sbostic "-p\tpreprocess with pic\n"
5370791b176Sbostic "-e\tpreprocess with eqn\n"
5380791b176Sbostic "-s\tpreprocess with soelim\n"
5390791b176Sbostic "-R\tpreprocess with refer\n"
5400791b176Sbostic "-Tdev\tuse device dev\n"
5410791b176Sbostic "-X\tuse X11 previewer rather than usual postprocessor\n"
5420791b176Sbostic "-mname\tread macros tmac.name\n"
5430791b176Sbostic "-dcs\tdefine a string c as s\n"
5440791b176Sbostic "-rcn\tdefine a number register c as n\n"
5450791b176Sbostic "-nnum\tnumber first page n\n"
5460791b176Sbostic "-olist\toutput only pages in list\n"
5470791b176Sbostic "-ffam\tuse fam as the default font family\n"
5480791b176Sbostic "-Fdir\tsearch directory dir for device directories\n"
5490791b176Sbostic "-Mdir\tsearch dir for macro files\n"
5500791b176Sbostic "-v\tprint version number\n"
5510791b176Sbostic "-z\tsuppress formatted output\n"
5520791b176Sbostic "-Z\tdon't postprocess\n"
5530791b176Sbostic "-a\tproduce ASCII description of output\n"
5540791b176Sbostic "-i\tread standard input after named input files\n"
5550791b176Sbostic "-wname\tenable warning name\n"
5560791b176Sbostic "-Wname\tinhibit warning name\n"
5570791b176Sbostic "-E\tinhibit all errors\n"
5580791b176Sbostic "-b\tprint backtraces with errors or warnings\n"
5590791b176Sbostic "-l\tspool the output\n"
5600791b176Sbostic "-C\tenable compatibility mode\n"
5610791b176Sbostic "-V\tprint commands on stdout instead of running them\n"
5620791b176Sbostic "-Parg\tpass arg to the postprocessor\n"
5630791b176Sbostic "-Larg\tpass arg to the spooler\n"
5640791b176Sbostic "-N\tdon't allow newlines within eqn delimiters\n"
5650791b176Sbostic "\n",
5660791b176Sbostic 	stderr);
5670791b176Sbostic   exit(0);
5680791b176Sbostic }
5690791b176Sbostic 
usage()5700791b176Sbostic void usage()
5710791b176Sbostic {
5720791b176Sbostic   synopsis();
5730791b176Sbostic   fprintf(stderr, "%s -h gives more help\n", program_name);
5740791b176Sbostic   exit(1);
5750791b176Sbostic }
5760791b176Sbostic 
5770791b176Sbostic extern "C" {
5780791b176Sbostic 
c_error(const char * format,const char * arg1,const char * arg2,const char * arg3)5790791b176Sbostic void c_error(const char *format, const char *arg1, const char *arg2,
5800791b176Sbostic 	     const char *arg3)
5810791b176Sbostic {
5820791b176Sbostic   error(format, arg1, arg2, arg3);
5830791b176Sbostic }
5840791b176Sbostic 
c_fatal(const char * format,const char * arg1,const char * arg2,const char * arg3)5850791b176Sbostic void c_fatal(const char *format, const char *arg1, const char *arg2,
5860791b176Sbostic 	     const char *arg3)
5870791b176Sbostic {
5880791b176Sbostic   fatal(format, arg1, arg2, arg3);
5890791b176Sbostic }
5900791b176Sbostic 
5910791b176Sbostic }
592