📄 groff.cc
字号:
// -*- C++ -*-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com)This file is part of groff.groff is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING. If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */// A front end for groff.#include <stdio.h>#include <string.h>#include <stdlib.h>#include <signal.h>#include <errno.h>#include "lib.h"#include "assert.h"#include "errarg.h"#include "error.h"#include "stringclass.h"#include "cset.h"#include "font.h"#include "device.h"#include "pipeline.h"#include "defs.h"#define BSHELL "/bin/sh"#define GXDITVIEW "gxditview"// troff will be passed an argument of -rXREG=1 if the -X option is// specified#define XREG ".X"#ifndef STDLIB_H_DECLARES_PUTENVextern "C" { int putenv(const char *);}#endif /* not STDLIB_H_DECLARES_PUTENV */const char *strsignal(int);const int SOELIM_INDEX = 0;const int REFER_INDEX = SOELIM_INDEX + 1;const int PIC_INDEX = REFER_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;class possible_command { char *name; string args; char **argv; void build_argv();public: possible_command(); ~possible_command(); void set_name(const char *); void set_name(const char *, const char *); const char *get_name(); void append_arg(const char *, const char * = 0); void clear_args(); char **get_argv(); void print(int is_last, FILE *fp);};int lflag = 0;char *spooler = 0;char *driver = 0;possible_command commands[NCOMMANDS];int run_commands();void print_commands();void append_arg_to_string(const char *arg, string &str);void handle_unknown_desc_command(const char *command, const char *arg, const char *filename, int lineno);const char *basename(const char *);void usage();void help();int main(int argc, char **argv){ program_name = argv[0]; static char stderr_buf[BUFSIZ]; setbuf(stderr, stderr_buf); assert(NCOMMANDS <= MAX_COMMANDS); string Pargs, Largs, Fargs; int Vflag = 0; int zflag = 0; int iflag = 0; int Xflag = 0; int opt; const char *command_prefix = getenv("GROFF_COMMAND_PREFIX"); if (!command_prefix) command_prefix = PROG_PREFIX; commands[TROFF_INDEX].set_name(command_prefix, "troff"); while ((opt = getopt(argc, argv, "itpeRszavVhblCENXZF:m:T:f:w:W:M:d:r:n:o:P:L:")) != EOF) { char buf[3]; buf[0] = '-'; buf[1] = opt; buf[2] = '\0'; switch (opt) { case 'i': iflag = 1; break; case 't': commands[TBL_INDEX].set_name(command_prefix, "tbl"); break; case 'p': commands[PIC_INDEX].set_name(command_prefix, "pic"); break; case 'e': commands[EQN_INDEX].set_name(command_prefix, "eqn"); break; case 's': commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); break; case 'R': commands[REFER_INDEX].set_name(command_prefix, "refer"); break; case 'z': case 'a': commands[TROFF_INDEX].append_arg(buf); // fall through case 'Z': zflag++; break; case 'l': lflag++; break; case 'V': Vflag++; break; case 'v': case 'C': 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); break; case 'N': commands[EQN_INDEX].append_arg(buf); break; case 'h': help(); break; case 'E': case 'b': commands[TROFF_INDEX].append_arg(buf); break; case 'T': if (strcmp(optarg, "Xps") == 0) { warning("-TXps option is obsolete: use -X -Tps instead"); device = "ps"; Xflag++; } else device = optarg; break; case 'F': font::command_line_font_dir(optarg); if (Fargs.length() > 0) { Fargs += ':'; Fargs += optarg; } else Fargs = optarg; break; case 'f': case 'o': case 'm': case 'r': case 'd': case 'n': case 'w': case 'W': commands[TROFF_INDEX].append_arg(buf, optarg); break; case 'M': commands[EQN_INDEX].append_arg(buf, optarg); commands[TROFF_INDEX].append_arg(buf, optarg); break; case 'P': Pargs += optarg; Pargs += '\0'; break; case 'L': append_arg_to_string(optarg, Largs); break; case 'X': Xflag++; break; case '?': usage(); break; default: assert(0); break; } } font::set_unknown_desc_command_handler(handle_unknown_desc_command); if (!font::load_desc()) fatal("invalid device `%1'", device); if (!driver) fatal("no `postpro' command in DESC file for device `%1'", device); const char *real_driver = 0; if (Xflag) { real_driver = driver; driver = GXDITVIEW; commands[TROFF_INDEX].append_arg("-r" XREG "=", "1"); } if (driver) commands[POST_INDEX].set_name(driver); int gxditview_flag = driver && strcmp(basename(driver), GXDITVIEW) == 0; if (gxditview_flag && argc - optind == 1) { 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]); string filename_string("|"); append_arg_to_string(argv[0], filename_string); append_arg_to_string("-Z", filename_string); for (int i = 1; i < argc; i++) append_arg_to_string(argv[i], filename_string); filename_string += '\0'; commands[POST_INDEX].append_arg("-filename"); commands[POST_INDEX].append_arg(filename_string.contents()); } if (gxditview_flag && Xflag) { string print_string(real_driver); if (spooler) { print_string += " | "; print_string += spooler; print_string += Largs; } print_string += '\0'; commands[POST_INDEX].append_arg("-printCommand"); commands[POST_INDEX].append_arg(print_string.contents()); } const char *p = Pargs.contents(); const char *end = p + Pargs.length(); while (p < end) { commands[POST_INDEX].append_arg(p); p = strchr(p, '\0') + 1; } if (gxditview_flag) commands[POST_INDEX].append_arg("-"); if (lflag && !Xflag && spooler) { commands[SPOOL_INDEX].set_name(BSHELL); commands[SPOOL_INDEX].append_arg("-c"); Largs += '\0'; Largs = spooler + Largs; commands[SPOOL_INDEX].append_arg(Largs.contents()); } if (zflag) { commands[POST_INDEX].set_name(0); commands[SPOOL_INDEX].set_name(0); } commands[TROFF_INDEX].append_arg("-T", device); commands[EQN_INDEX].append_arg("-T", device); for (int first_index = 0; first_index < TROFF_INDEX; first_index++) if (commands[first_index].get_name() != 0) break; if (optind < argc) { if (argv[optind][0] == '-' && argv[optind][1] != '\0') commands[first_index].append_arg("--"); for (int i = optind; i < argc; i++) commands[first_index].append_arg(argv[i]); if (iflag) commands[first_index].append_arg("-"); } if (Fargs.length() > 0) { string e = "GROFF_FONT_PATH"; e += '='; e += Fargs; char *fontpath = getenv("GROFF_FONT_PATH"); if (fontpath && *fontpath) { e += ':'; e += fontpath; } e += '\0'; if (putenv(strsave(e.contents()))) fatal("putenv failed"); } if (Vflag) { print_commands(); exit(0); } exit(run_commands());}const char *basename(const char *s){ if (!s) return 0; const char *p = strrchr(s, '/'); return p ? p + 1 : s;}void handle_unknown_desc_command(const char *command, const char *arg, const char *filename, int lineno){ if (strcmp(command, "print") == 0) { if (arg == 0) error_with_file_and_line(filename, lineno, "`print' command requires an argument"); else spooler = strsave(arg); } if (strcmp(command, "postpro") == 0) { if (arg == 0) error_with_file_and_line(filename, lineno, "`postpro' command requires an argument"); else { for (const char *p = arg; *p; p++) if (csspace(*p)) { error_with_file_and_line(filename, lineno, "invalid `postpro' argument `%1'" ": program name required", arg); return; } driver = strsave(arg); } }}void print_commands(){ for (int last = SPOOL_INDEX; last >= 0; last--) if (commands[last].get_name() != 0) break; 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.int run_commands(){ char **v[NCOMMANDS]; int j = 0; for (int i = 0; i < NCOMMANDS; i++) if (commands[i].get_name() != 0) v[j++] = commands[i].get_argv(); return run_pipeline(j, v);}possible_command::possible_command(): name(0), argv(0){}possible_command::~possible_command(){ a_delete name; a_delete argv;}void possible_command::set_name(const char *s){ a_delete name; name = strsave(s);}void possible_command::set_name(const char *s1, const char *s2){ a_delete name; name = new char[strlen(s1) + strlen(s2) + 1]; strcpy(name, s1); strcat(name, s2);}const char *possible_command::get_name(){ return name;}void possible_command::clear_args(){ args.clear();}void possible_command::append_arg(const char *s, const char *t){ args += s; if (t) args += t; args += '\0';}void possible_command::build_argv(){ if (argv) return; // Count the number of arguments. int len = args.length(); int argc = 1; char *p = 0; if (len > 0) { p = &args[0]; for (int i = 0; i < len; i++) if (p[i] == '\0') argc++; } // Build an argument vector. argv = new char *[argc + 1]; argv[0] = name; for (int i = 1; i < argc; i++) { argv[i] = p; p = strchr(p, '\0') + 1; } argv[argc] = 0;}void possible_command::print(int is_last, FILE *fp){ build_argv(); if (argv[0] != 0 && strcmp(argv[0], BSHELL) == 0 && argv[1] != 0 && strcmp(argv[1], "-c") == 0 && argv[2] != 0 && argv[3] == 0) fputs(argv[2], fp); else { fputs(argv[0], fp); string str; for (int i = 1; argv[i] != 0; i++) { str.clear(); append_arg_to_string(argv[i], str); put_string(str, fp); } } if (is_last) putc('\n', fp); else fputs(" | ", fp);}void append_arg_to_string(const char *arg, string &str){ str += ' '; int needs_quoting = 0; int contains_single_quote = 0; for (const char *p = arg; *p != '\0'; p++) switch (*p) { case ';': case '&': case '(': case ')': case '|': case '^': case '<': case '>': case '\n': case ' ': case '\t': case '\\': case '"': case '$': case '?': case '*': needs_quoting = 1; break; case '\'': contains_single_quote = 1; break; } if (contains_single_quote || arg[0] == '\0') { str += '"'; for (p = arg; *p != '\0'; p++) switch (*p) { case '"': case '\\': case '$': str += '\\'; // fall through default: str += *p; break; } str += '"'; } else if (needs_quoting) { str += '\''; str += arg; str += '\''; } else str += arg;}char **possible_command::get_argv(){ build_argv(); return argv;}void synopsis(){ fprintf(stderr,"usage: %s [-abehilpstvzCENRVXZ] [-Fdir] [-mname] [-Tdev] [-ffam] [-wname]\n"" [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg] [-Larg]\n"" [files...]\n", program_name);}void help(){ synopsis(); fputs("\n""-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""-R\tpreprocess with refer\n""-Tdev\tuse device dev\n""-X\tuse X11 previewer rather than usual postprocessor\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""-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""-l\tspool the output\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""\n", stderr); exit(0);}void usage(){ synopsis(); fprintf(stderr, "%s -h gives more help\n", program_name); exit(1);}extern "C" {void c_error(const char *format, const char *arg1, const char *arg2, const char *arg3){ error(format, arg1, arg2, arg3);}void c_fatal(const char *format, const char *arg1, const char *arg2, const char *arg3){ fatal(format, arg1, arg2, arg3);}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -