* This code is derived from software copyrighted by the Free Software
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
static char sccsid
[] = "@(#)groff.cc 6.5 (Berkeley) 5/8/91";
/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
// A C++ implementation of groff.sh.
#endif /* HAVE_SYS_SIGLIST */
const char *strsignal(int);
// HAVE_UNION_WAIT exists only because Sun's osfcn.h includes sys/wait.h.
#else /* !HAVE_UNION_WAIT */
#endif /* !HAVE_UNION_WAIT */
#define DVIPRINT "lpr", "-d",
const char *ps_print
[] = { PSPRINT
0 };
const char *dvi_print
[] = { DVIPRINT
0 };
const char *grops
[] = { "grops", 0 };
const char *grotty
[] = { "grotty", 0 };
const char *grodvi
[] = { "grodvi", 0 };
const char *gxditview
[] = { "gxditview", "-", 0 };
const char *name
; // Name of the device.
const char *description
; // Description of device (used in help message).
const char **driver
; // Driver argument vector.
unsigned flags
; // Bitwise OR of
#define EQN_D_OPTION 01 /* Add -D option to eqn. */
#define PIC_X_OPTION 02 /* Add -x option to pic. */
#define PIC_P_OPTION 04 /* Add -p option to pic. */
#define GROFF_OPTIONS 010 /* Driver understands -F and -v options. */
#define XT_OPTION 020 /* Driver understands -title and -xrm options. */
const char *macro_file
; // -m option to pass to troff
const char **spooler
; // Spooler argument vector.
EQN_D_OPTION
|PIC_X_OPTION
|PIC_P_OPTION
|GROFF_OPTIONS
,
GROFF_OPTIONS
|PIC_X_OPTION
,
"X11 previewer at 100dpi",
EQN_D_OPTION
|PIC_X_OPTION
|XT_OPTION
,
"X11 previewer at 75dpi",
EQN_D_OPTION
|PIC_X_OPTION
|XT_OPTION
,
"X11 previewer at 100dpi (optimized for 12 point text)",
EQN_D_OPTION
|PIC_X_OPTION
|XT_OPTION
,
"X11 previewer at 75dpi (optimized for 12 point text)",
EQN_D_OPTION
|PIC_X_OPTION
|XT_OPTION
,
const int SOELIM_INDEX
= 0;
const int PIC_INDEX
= SOELIM_INDEX
+ 1;
const int TBL_INDEX
= PIC_INDEX
+ 1;
const int EQN_INDEX
= TBL_INDEX
+ 1;
const int TROFF_INDEX
= EQN_INDEX
+ 1;
const int POST_INDEX
= TROFF_INDEX
+ 1;
const int SPOOL_INDEX
= POST_INDEX
+ 1;
const int NCOMMANDS
= SPOOL_INDEX
+ 1;
// Children exit with this status if the execvp failed.
const int EXEC_FAILED_EXIT_STATUS
= 0xff;
void set_name(const char *);
void append_arg(const char *, const char * = 0);
void print(int is_last
, FILE *fp
);
possible_command commands
[NCOMMANDS
];
void sys_fatal(const char *);
int main(int argc
, char **argv
)
static char stderr_buf
[BUFSIZ
];
setbuf(stderr
, stderr_buf
);
const char *device
= getenv("GROFF_TYPESETTER");
commands
[TROFF_INDEX
].set_name("troff");
while ((opt
= getopt(argc
, argv
,
"itpeszavVhblCENZH:F:m:T:f:w:W:M:d:r:n:o:P:L:"))
commands
[TBL_INDEX
].set_name("tbl");
commands
[PIC_INDEX
].set_name("pic");
commands
[EQN_INDEX
].set_name("eqn");
commands
[SOELIM_INDEX
].set_name("soelim");
commands
[TROFF_INDEX
].append_arg(buf
);
commands
[POST_INDEX
].append_arg(buf
);
commands
[SOELIM_INDEX
].append_arg(buf
);
commands
[PIC_INDEX
].append_arg(buf
);
commands
[TBL_INDEX
].append_arg(buf
);
commands
[EQN_INDEX
].append_arg(buf
);
commands
[TROFF_INDEX
].append_arg(buf
);
commands
[EQN_INDEX
].append_arg(buf
);
commands
[TROFF_INDEX
].append_arg(buf
);
font::command_line_font_dir(optarg
);
commands
[POST_INDEX
].append_arg(buf
, optarg
);
commands
[TROFF_INDEX
].append_arg(buf
, optarg
);
for (int device_index
= 0;
device_index
< sizeof(device_table
)/sizeof(device_table
[0]);
if (strcmp(device
, device_table
[device_index
].name
) == 0) {
error("unknown device `%1'", device
);
if (device_table
[device_index
].macro_file
!= 0)
commands
[TROFF_INDEX
].append_arg("-m",
device_table
[device_index
].macro_file
);
commands
[POST_INDEX
].set_name(device_table
[device_index
].driver
[0]);
if (!(device_table
[device_index
].flags
& GROFF_OPTIONS
))
commands
[POST_INDEX
].clear_args();
if ((device_table
[device_index
].flags
& XT_OPTION
)
commands
[POST_INDEX
].append_arg("-title");
commands
[POST_INDEX
].append_arg(argv
[optind
]);
commands
[POST_INDEX
].append_arg("-xrm");
commands
[POST_INDEX
].append_arg("*iconName:", argv
[optind
]);
const char *p
= Pargs
.contents();
const char *end
= p
+ Pargs
.length();
commands
[POST_INDEX
].append_arg(p
);
for (i
= 1; device_table
[device_index
].driver
[i
]; i
++)
commands
[POST_INDEX
].append_arg(device_table
[device_index
].driver
[i
]);
if (device_table
[device_index
].flags
& PIC_X_OPTION
)
commands
[PIC_INDEX
].append_arg("-x");
if (device_table
[device_index
].flags
& PIC_P_OPTION
)
commands
[PIC_INDEX
].append_arg("-p");
if (device_table
[device_index
].flags
& EQN_D_OPTION
)
commands
[EQN_INDEX
].append_arg("-D");
if (lflag
&& device_table
[device_index
].spooler
) {
commands
[SPOOL_INDEX
].set_name(device_table
[device_index
].spooler
[0]);
end
= p
+ Largs
.length();
commands
[SPOOL_INDEX
].append_arg(p
);
for (i
= 1; device_table
[device_index
].spooler
[i
]; i
++)
commands
[SPOOL_INDEX
].append_arg(device_table
[device_index
].spooler
[i
]);
commands
[POST_INDEX
].set_name(0);
commands
[SPOOL_INDEX
].set_name(0);
commands
[TROFF_INDEX
].append_arg("-T", device
);
if (commands
[EQN_INDEX
].get_name() != 0) {
commands
[EQN_INDEX
].append_arg("-T", device
);
font::set_device_name(device
);
FILE *fp
= font::open_file("eqnchar", &path
);
if (path
[0] == '-' && path
[1] != '\0')
commands
[EQN_INDEX
].append_arg("--");
commands
[EQN_INDEX
].append_arg(path
);
for (int first_index
= 0; first_index
< TROFF_INDEX
; first_index
++)
if (commands
[first_index
].get_name() != 0)
if (argv
[optind
][0] == '-' && argv
[optind
][1] != '\0'
&& (!have_eqnchar
|| first_index
!= EQN_INDEX
))
commands
[first_index
].append_arg("--");
for (i
= optind
; i
< argc
; i
++)
commands
[first_index
].append_arg(argv
[i
]);
commands
[first_index
].append_arg("-");
if (have_eqnchar
&& (first_index
!= EQN_INDEX
|| optind
>= argc
))
commands
[EQN_INDEX
].append_arg("-");
for (int last
= SPOOL_INDEX
; last
>= 0; last
--)
if (commands
[last
].get_name() != 0)
for (int i
= 0; i
<= last
; i
++)
if (commands
[i
].get_name() != 0)
commands
[i
].print(i
== last
, stdout
);
// Run the commands. Return the code with which to exit.
for (int last
= SPOOL_INDEX
; last
>= 0; last
--)
if (commands
[last
].get_name() != 0)
for (int i
= 0; i
<= last
; i
++)
if (commands
[i
].get_name() != 0) {
if (close(last_input
) < 0)
if (close(last_input
) < 0)
// union wait is just syntactic sugar: it's really just an int.
int pid
= wait((union wait
*)&status
);
#else /* !HAVE_UNION_WAIT */
#endif /* !HAVE_UNION_WAIT */
for (i
= 0; i
< NCOMMANDS
; i
++)
if (commands
[i
].pid
== pid
) {
if ((status
& 0xffff) != 0) {
if ((status
& 0xff) != 0) {
strsignal(status
& 0x7f),
(status
& 0x80) ? " (core dumped)" : "");
int exit_status
= (status
>> 8) & 0xff;
if (exit_status
== EXEC_FAILED_EXIT_STATUS
)
else if (exit_status
!= 0)
possible_command::possible_command()
: pid(-1), name(0), argv(0)
possible_command::~possible_command()
void possible_command::set_name(const char *s
)
const char *possible_command::get_name()
void possible_command::clear_args()
void possible_command::append_arg(const char *s
, const char *t
)
void possible_command::build_argv()
// Count the number of arguments.
for (int i
= 0; i
< len
; i
++)
// Build an argument vector.
argv
= new char *[argc
+ 1];
for (int i
= 1; i
< argc
; i
++) {
void possible_command::print(int is_last
, FILE *fp
)
for (int i
= 1; argv
[i
] != 0; i
++) {
int contains_single_quote
= 0;
for (const char *p
= argv
[i
]; *p
!= '\0'; p
++)
contains_single_quote
= 1;
if (contains_single_quote
|| argv
[i
][0] == '\0') {
for (p
= argv
[i
]; *p
!= '\0'; p
++)
fprintf(fp
, " '%s'", argv
[i
]);
fprintf(fp
, " %s", argv
[i
]);
void possible_command::execp()
error("couldn't exec %1: %2", name
, strerror(errno
));
// vfork(2) says not to call exit when execve fails after vforking.
_exit(EXEC_FAILED_EXIT_STATUS
);
exit(EXEC_FAILED_EXIT_STATUS
);
"usage: %s [-abehilpstvzCENVZ] [-Hfile] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
" [-wname] [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n"
fputs("Available devices are:\n", stderr
);
for (int i
= 0; i
< sizeof(device_table
)/sizeof(device_table
[0]); i
++)
fprintf(stderr
, "%s\t%s\n",
device_table
[i
].description
);
"-h\tprint this message\n"
"-t\tpreprocess with tbl\n"
"-p\tpreprocess with pic\n"
"-e\tpreprocess with eqn\n"
"-s\tpreprocess with soelim\n"
"-Tdev\tuse device dev\n"
"-mname\tread macros tmac.name\n"
"-dcs\tdefine a string c as s\n"
"-rcn\tdefine a number register c as n\n"
"-nnum\tnumber first page n\n"
"-olist\toutput only pages in list\n"
"-ffam\tuse fam as the default font family\n"
"-Fdir\tsearch directory dir for device directories\n"
"-Mdir\tsearch dir for macro files\n"
"-Hfile\tread hyphenation patterns from file\n"
"-v\tprint version number\n"
"-z\tsuppress formatted output\n"
"-Z\tdon't postprocess\n"
"-a\tproduce ASCII description of output\n"
"-i\tread standard input after named input files\n"
"-wname\tenable warning name\n"
"-Wname\tinhibit warning name\n"
"-E\tinhibit all errors\n"
"-b\tprint backtraces with errors or warnings\n"
"-C\tenable compatibility mode\n"
"-V\tprint commands on stdout instead of running them\n"
"-Parg\tpass arg to the postprocessor\n"
"-Larg\tpass arg to the spooler\n"
"-N\tdon't allow newlines within eqn delimiters\n"
fprintf(stderr
, "%s -h gives more help\n", program_name
);
void sys_fatal(const char *s
)
fatal("%1: %2", s
, strerror(errno
));
extern char *sys_siglist
[];
#endif /* HAVE_SYS_SIGLIST */
const char *strsignal(int n
)
static char buf
[sizeof("Signal ") + 1 + INT_DIGITS
];
if (n
>= 0 && n
< NSIG
&& sys_siglist
[n
] != 0)
#endif /* HAVE_SYS_SIGLIST */
sprintf(buf
, "Signal %d", n
);