/* * Argument handling and main. * Copyright (c) 1995-2003 Markku Rossi. * * Author: Markku Rossi */ /* * This file is part of GNU Enscript. * * Enscript 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 3 of the License, or * (at your option) any later version. * * Enscript 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 for more details. * * You should have received a copy of the GNU General Public License * along with Enscript. If not, see . */ #include "gsint.h" #include "getopt.h" /* * Prototypes for static functions. */ /* * Open output file according to user options. Void if output file * has already been opened. */ static void open_output_file (); /* Close output file. */ static void close_output_file (); /* Handle options from environment variable */ static void handle_env_options ___P ((char *var)); /* Handle options from array. */ static void handle_options ___P ((int argc, char *argv[])); /* Print usage info. */ static void usage (); /* Print version info. */ static void version (); /* * Global variables. */ char *program; /* Program's name, used for messages. */ FILE *ofp = NULL; /* Output file. */ void *printer_context; /* Context for the printer. */ char *date_string = NULL; /* Preformatted time string. */ struct tm run_tm; /* Time when program is run. */ struct tm mod_tm; /* Last modification time for current file. */ struct passwd *passwd; /* Passwd entry for the user running this program. */ /* Path to our library. */ char *enscript_library = LIBRARY; /* Library lookup path. */ char *libpath = NULL; /* AFM library lookup path. */ char *afm_path = NULL; MediaEntry *media_names = NULL; /* List of known media. */ MediaEntry *media = NULL; /* Entry for used media. */ int bs = 8; /* The backspace character. */ /* Statistics. */ int total_pages = 0; /* Total number of pages printed. */ int num_truncated_lines = 0; /* Number of lines truncated. */ int num_missing_chars = 0; /* Number of unknown characters. */ int missing_chars[256] = {0}; /* Table of unknown characters. */ int num_non_printable_chars = 0; /* Number of non-printable characters. */ int non_printable_chars[256] = {0}; /* Table of non-printable characters. */ /* Output media dimensions that are used during PostScript emission. */ int d_page_w = 0; /* page's width */ int d_page_h = 0; /* page's height */ int d_header_w = 0; /* fancy header's width */ int d_header_h = 0; /* fancy header's height */ int d_footer_h = 0; /* fancy footer's height */ int d_output_w = 0; /* output area's width */ int d_output_h = 0; /* output area's height */ int d_output_x_margin = 5; /* output area's x marginal */ int d_output_y_margin = 2; /* output area's y marginal */ /* Document needed resources. */ StringHashPtr res_fonts; /* fonts */ /* Fonts to download. */ StringHashPtr download_fonts; /* Additional key-value pairs, passed to the generated PostScript code. */ StringHashPtr pagedevice; /* for setpagedevice */ StringHashPtr statusdict; /* for statusdict */ /* User defined strings. */ StringHashPtr user_strings; /* Cache for AFM files. */ StringHashPtr afm_cache = NULL; StringHashPtr afm_info_cache = NULL; /* AFM library handle. */ AFMHandle afm = NULL; /* Options. */ /* * Free single-letter options are: Q, x, y, Y */ /* * -# * * An alias for -n, --copies. */ /* * -1, -2, -3, -4, -5, -6, -7, -8, -9, --columns=NUM * * Number of columns per page. The default is 1 column. */ int num_columns = 1; /* * -a PAGES, --pages=PAGES * * Specify which pages are printed. */ PageRange *page_ranges = NULL; /* * -A ALIGN, --file-align=ALIGN * * Align input files to start from ALIGN page count. This is handy * for two-side printings. */ unsigned int file_align = 1; /* * -b STRING, --header=STRING * * Set the string that is used as the page header. As a default, page * header is constructed from filename, date and page number. */ char *page_header = NULL; /* * -B, --no-header * * Do not print page headers. */ /* * -c, --truncate-lines * * Truncate lines that are longer than the page width. Default is character * wrap. */ LineEndType line_end = LE_CHAR_WRAP; /* * -C [START], --line-numbers[=START] * * Precede each line with its line number. As a default, do not mark * line numbers. If the optional argument START is given, it * specifies the number from which the line numbers are assumed to * start in the file. This is useful if the file contains a region * of a bigger file. */ int line_numbers = 0; unsigned int start_line_number = 1; /* * -d, -P, --printer * * Name of the printer to which output is send. Defaults to system's * default printer. */ char *printer = NULL; /* * -e [CHAR], --escapes[=CHAR] * * Enable special escape ('\000') interpretation. If option CHAR is given * it is assumed to specify the escape character. */ int special_escapes = 0; int escape_char = '\0'; int default_escape_char; /* * -E [LANG], --highlight=[LANG] (deprecated --pretty-print[=LANG]) * * Highlight program source code. Highlighting is handled by creating * an input filter with the states-program. States makes an educated * guess about the start state but sometimes it fails, so the start * state can also be specified to be LANG. This option overwrites * input filter and enables special escapes. */ int highlight = 0; char *hl_start_state = NULL; /* * -f, --font * * Select body font. */ char *Fname = "Courier"; FontPoint Fpt = {10.0, 10.0}; FontPoint default_Fpt; /* Point size of the original font. */ char *default_Fname; /* Name of the original font. */ InputEncoding default_Fencoding; /* The encoding of the original font. */ int user_body_font_defined = 0; /* Has user defined new body font? */ double font_widths[256]; /* Width array for body font. */ char font_ctype[256]; /* Font character types. */ int font_is_fixed; /* Is body font a fixed pitch font? */ double font_bbox_lly; /* Font's bounding box's lly-coordinate. */ /* * -F, --header-font * * Select font to be used to print the standard simple header. */ char *HFname = "Courier-Bold"; FontPoint HFpt = {10.0, 10.0}; /* * -g, --print-anyway * * Print document even it contains binary data. This does nothing * since enscript prints files anyway. */ /* * -G, --fancy-header * * Add a fancy header to top of every page. There are several header styles * but the default is 'no fancy header'. */ HeaderType header = HDR_SIMPLE; char *fancy_header_name = NULL; char *fancy_header_default = NULL; /* * -h, --no-job-header * * Supress the job header page. */ static int no_job_header = 0; /* * -H num, --highlight-bars=num * * Print highlight bars under text. Bars will be lines high. * As a default, do not print bars. */ unsigned int highlight_bars = 0; /* * -i, --indent * * Indent every line this many characters. */ double line_indent = 0.0; char *line_indent_spec = "0"; /* * -I CMD, --filter=CMD * * Read input files through input filter CMD. */ char *input_filter = NULL; /* * -j, --borders * * Print borders around columns. */ int borders = 0; /* * -J * * An alias for -t, --title. */ /* * -k, --page-prefeed * -K, --no-page-prefeed * * Control page prefeed. */ int page_prefeed = 0; /* * -l, --lineprinter * * Emulate lineprinter - make pages 66 lines long and omit headers. */ /* * -L, --lines-per-page * * Specify how many lines should be printed on a single page. Normally * enscript counts it from font point sizes. */ unsigned int lines_per_page = (unsigned int) -1; /* * -m, --mail * * Send mail notification to user after print job has been completed. */ int mail = 0; /* * -M, --media * * Name of the output media. Default is A4. */ char *media_name = NULL; /* * -n, --copies * * Number of copies to print. */ int num_copies = 1; /* * -N, --newline * * Set the newline character: '\n' or '\r'. As a default, the newline * character is specified by the input encoding. */ int nl = -1; /* * -o, -p, --output * * Leave output to the specified file. As a default result is spooled to * printer. */ char *output_file = OUTPUT_FILE_NONE; /* * -O, --missing-characters * * List all missing characters. Default is no listing. */ int list_missing_characters = 0; /* * -q, --quiet * * Do not tell what we are doing. Default is to tell something but * not --verbose. */ int quiet = 0; /* * -r, --landscape * -R, --portrait * * Print with page rotated 90 degrees (landscape mode). Default is * portrait. */ int landscape = 0; /* * -s, --baselineskip * * Specify baselineskip value that is used when enscript moves to * a new line. Current point movement is font_point_size + baselineskip. */ double baselineskip = 1.0; /* * -t, --title * * Title which is printed to the banner page. If this option is given * from the command line, this sets also the name of the stdin which * is by the default "". */ char *title = "Enscript Output"; int title_given = 0; /* * -T, --tabsize * * Specify tabulator size. */ int tabsize = 8; /* * -u, --underlay * * Place text under every page. Default is no underlay. */ double ul_gray = .8; FontPoint ul_ptsize = {200.0, 200.0}; char *ul_font = "Times-Roman"; char *underlay = NULL; char *ul_position = NULL; /* Position info as a string. */ double ul_x; /* Position x-coordinate. */ double ul_y; /* Position y-coordinate. */ double ul_angle; unsigned int ul_style = UL_STYLE_OUTLINE; char *ul_style_str = NULL; int ul_position_p = 0; /* Is ul-position given? */ int ul_angle_p = 0; /* Is ul-angle given? */ /* * -U NUM, --nup=NUM * * Print NUM PostScript pages on each output page (n-up printing). */ unsigned int nup = 1; unsigned int nup_exp = 0; unsigned int nup_rows = 1; unsigned int nup_columns = 1; int nup_landscape = 0; unsigned int nup_width; unsigned int nup_height; double nup_scale; /* * -v, --verbose * * Tell what we are doing. Default is no verbose outputs. */ int verbose = 0; /* * -V, --version * * Print version information. */ /* * -w LANGUAGE, --language=LANGUAGE * * Generate output for language LANGUAGE. The default is PostScript. */ char *output_language = "PostScript"; int output_language_pass_through = 0; /* * -W APP,option, --options=APP,OPTION * * Pass additional option to enscript's helper applications. The * first part of the option's argument (APP) specifies the * helper application to which the options are added. Currently the * following helper application are defined: * * s states */ Buffer *helper_options[256] = {0}; /* * -X, --encoding * * Specifies input encoding. Default is ISO-8859.1. */ InputEncoding encoding = ENC_ISO_8859_1; char *encoding_name = NULL; /* * -z, --no-formfeed * * Do not interpret form feed characters. As a default, form feed * characters are interpreted. */ int interpret_formfeed = 1; /* * -Z, --pass-through * * Pass through all PostScript and PCL files without any modifications. * As a default, don't. */ int pass_through = 0; /* * --color[=bool] * * Create color output with states? */ /* * --continuous-page-numbers * * Count page numbers across input files. Don't restart numbering * at beginning of each file. */ int continuous_page_numbers = 0; /* * --download-font=FONT * * Download font FONT to printer. */ /* * --extended-return-values * * Enable extended return values. */ int extended_return_values = 0; /* * --filter-stdin=STR * * How stdin is shown to the filter command. The default is "" but * some utilities might want it as "-". */ char *input_filter_stdin = ""; /* * --footer=STRING * * Set the string that is used as the page footer. As a default, the * page has no footer. Setting this option does not necessary show * any footer strings in the output. It depends on the selected * header (`.hdr' file) whether it supports footer strings or not. */ char *page_footer = NULL; /* * --h-column-height=HEIGHT * * Set the horizontal column (channel) height to be HEIGHT. This option * also sets the FormFeedType to `hcolumn'. The default value is set to be * big enough to cause a jump to the next vertical column (100m). */ double horizontal_column_height = 283465.0; /* * --help-highlight (deprecated --help-pretty-print) * * Descript all supported -E, --highlight languages and file formats. */ int help_highlight = 0; /* * --highlight-bar-gray=val * * Specify the gray level for highlight bars. */ double highlight_bar_gray = .97; /* * --list-media * * List all known media. As a default do not list media names. */ int list_media = 0; /* * --margins=LEFT:RIGHT:TOP:BOTTOM * * Adjust page marginals. */ char *margins_spec = NULL; /* * --mark-wrapped-lines[=STYLE] * * Mark wrapped lines so that they can be easily detected from the printout. * Optional parameter STYLE specifies the marking style, the system default * is black box. */ char *mark_wrapped_lines_style_name = NULL; MarkWrappedLinesStyle mark_wrapped_lines_style = MWLS_NONE; /* * --non-printable-format=FORMAT * * Format in which non-printable characters are printed. */ char *npf_name = NULL; NonPrintableFormat non_printable_format = NPF_OCTAL; /* * --nup-columnwise * * Layout N-up pages colunwise instead of row-wise. */ int nup_columnwise = 0; /* * --nup-xpad=NUM * * The x-padding between N-up subpages. */ unsigned int nup_xpad = 10; /* * --nup-ypad=NUM * * The y-padding between N-up subpages. */ unsigned int nup_ypad = 10; /* * --page-label-format=FORMAT * * Format in which page labels are printed; the default is "short". */ char *page_label_format = NULL; PageLabelFormat page_label; /* * --ps-level=LEVEL * * The PostScript language level that enscript should use; the default is 2. */ unsigned int pslevel = 2; /* * --printer-options=OPTIONS * * Pass extra options OPTIONS to the printer spooler. */ char *printer_options = NULL; /* * --rotate-even-pages * * Rotate each even-numbered page 180 degrees. This might be handy in * two-side printing when the resulting pages are bind from some side. * Greetings to Jussi-Pekka Sairanen. */ int rotate_even_pages = 0; /* * --slice=NUM * * Horizontal input slicing. Print only NUMth wrapped input pages. */ int slicing = 0; unsigned int slice = 1; /* * --swap-even-page-margins * * Swap left and right side margins for each even numbered page. This * might be handy in two-side printing. */ int swap_even_page_margins = 0; /* * --toc * * Print Table of Contents page. */ int toc = 0; FILE *toc_fp; char *toc_fmt_string; /* * --word-wrap * * Wrap long lines from word boundaries. The default is character wrap. */ /* * AcceptCompositeCharacters: bool * * Specify whatever we accept composite characters or should them be * considered as non-existent. As a default, do not accept them. */ int accept_composites = 0; /* * AppendCtrlD: bool * * Append ^D character to the end of the output. Some printers require this * but the default is false. */ int append_ctrl_D = 0; /* * Clean7Bit: bool * * Specify how characters greater than 127 are printed. */ int clean_7bit = 1; /* * FormFeedType: type * * Specify what to do when a formfeed character is encountered from the * input stream. The default action is to jump to the beginning of the * next column. */ FormFeedType formfeed_type = FORMFEED_COLUMN; /* * GeneratePageSize: bool * * Specify whether the `PageSize' pagedevice definitions should be * generated to the output. */ int generate_PageSize = 1; /* * NoJobHeaderSwitch: switch * * Spooler switch to suppress the job header (-h). */ char *no_job_header_switch = NULL; /* * OutputFirstLine: line * * Set the PostScript output's first line to something your system can handle. * The default is "%!PS-Adobe-3.0" */ char *output_first_line = NULL; /* * QueueParam: param * * The spooler command switch to select the printer queue (-P). */ char *queue_param = NULL; /* * Spooler: command * * The spooler command name (lpr). */ char *spooler_command = NULL; /* * StatesBinary: path * * An absolute path to the `states' binary. */ char *states_binary = NULL; /* * StatesColor: bool * * Should the States program generate color outputs. */ int states_color = 0; /* * StatesConfigFile: file * * The name of the states' configuration file. */ char *states_config_file = NULL; /* * StatesHighlightStyle: style * * The highlight style. */ char *states_highlight_style = NULL; /* * StatesPath: path * * Define the path for the states program. The states program will * lookup its state definition files from this path. */ char *states_path = NULL; /* ^@shade{GRAY}, set the line highlight gray. */ double line_highlight_gray = 1.0; /* ^@bggray{GRAY}, set the text background gray. */ double bggray = 1.0; EncodingRegistry encodings[] = { {{"88591", "latin1", NULL}, ENC_ISO_8859_1, '\n', 8}, {{"88592", "latin2", NULL}, ENC_ISO_8859_2, '\n', 8}, {{"88593", "latin3", NULL}, ENC_ISO_8859_3, '\n', 8}, {{"88594", "latin4", NULL}, ENC_ISO_8859_4, '\n', 8}, {{"88595", "cyrillic", NULL}, ENC_ISO_8859_5, '\n', 8}, {{"88597", "greek", NULL}, ENC_ISO_8859_7, '\n', 8}, {{"88599", "latin5", NULL}, ENC_ISO_8859_9, '\n', 8}, {{"885910", "latin6", NULL}, ENC_ISO_8859_10, '\n', 8}, {{"ascii", NULL, NULL}, ENC_ASCII, '\n', 8}, {{"asciifise", "asciifi", "asciise"}, ENC_ASCII_FISE, '\n', 8}, {{"asciidkno", "asciidk", "asciino"}, ENC_ASCII_DKNO, '\n', 8}, {{"ibmpc", "pc", "dos"}, ENC_IBMPC, '\n', 8}, {{"mac", NULL, NULL}, ENC_MAC, '\r', 8}, {{"vms", NULL, NULL}, ENC_VMS, '\n', 8}, {{"hp8", NULL, NULL}, ENC_HP8, '\n', 8}, {{"koi8", NULL, NULL}, ENC_KOI8, '\n', 8}, {{"ps", "PS", NULL}, ENC_PS, '\n', 8}, {{"pslatin1", "ISOLatin1Encoding", NULL}, ENC_ISO_8859_1, '\n', 8}, {{NULL, NULL, NULL}, 0, 0, 0}, }; /* * Static variables. */ static struct option long_options[] = { {"columns", required_argument, 0, 0}, {"pages", required_argument, 0, 'a'}, {"file-align", required_argument, 0, 'A'}, {"header", required_argument, 0, 'b'}, {"no-header", no_argument, 0, 'B'}, {"truncate-lines", no_argument, 0, 'c'}, {"line-numbers", optional_argument, 0, 'C'}, {"printer", required_argument, 0, 'd'}, {"setpagedevice", required_argument, 0, 'D'}, {"escapes", optional_argument, 0, 'e'}, {"highlight", optional_argument, 0, 'E'}, {"font", required_argument, 0, 'f'}, {"header-font", required_argument, 0, 'F'}, {"print-anyway", no_argument, 0, 'g'}, {"fancy-header", optional_argument, 0, 'G'}, {"no-job-header", no_argument, 0, 'h'}, {"highlight-bars", optional_argument, 0, 'H'}, {"indent", required_argument, 0, 'i'}, {"filter", required_argument, 0, 'I'}, {"borders", no_argument, 0, 'j'}, {"page-prefeed", no_argument, 0, 'k'}, {"no-page-prefeed", no_argument, 0, 'K'}, {"lineprinter", no_argument, 0, 'l'}, {"lines-per-page", required_argument, 0, 'L'}, {"mail", no_argument, 0, 'm'}, {"media", required_argument, 0, 'M'}, {"copies", required_argument, 0, 'n'}, {"newline", required_argument, 0, 'N'}, {"output", required_argument, 0, 'p'}, {"missing-characters", no_argument, 0, 'O'}, {"quiet", no_argument, 0, 'q'}, {"silent", no_argument, 0, 'q'}, {"landscape", no_argument, 0, 'r'}, {"portrait", no_argument, 0, 'R'}, {"baselineskip", required_argument, 0, 's'}, {"statusdict", required_argument, 0, 'S'}, {"title", required_argument, 0, 't'}, {"tabsize", required_argument, 0, 'T'}, {"underlay", optional_argument, 0, 'u'}, {"nup", required_argument, 0, 'U'}, {"verbose", optional_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"language", required_argument, 0, 'w'}, {"option", required_argument, 0, 'W'}, {"encoding", required_argument, 0, 'X'}, {"no-formfeed", no_argument, 0, 'z'}, {"pass-through", no_argument, 0, 'Z'}, /* Long options without short counterparts. Next free is 157. */ {"color", optional_argument, 0, 142}, {"continuous-page-numbers", no_argument, 0, 156}, {"download-font", required_argument, 0, 131}, {"extended-return-values", no_argument, 0, 154}, {"filter-stdin", required_argument, 0, 138}, {"footer", required_argument, 0, 155}, {"h-column-height", required_argument, 0, 148}, {"help", no_argument, 0, 135}, {"help-highlight", no_argument, 0, 141}, {"highlight-bar-gray", required_argument, 0, 136}, {"list-media", no_argument, &list_media, 1}, {"margins", required_argument, 0, 144}, {"mark-wrapped-lines", optional_argument, 0, 143}, {"non-printable-format", required_argument, 0, 134}, {"nup-columnwise", no_argument, 0, 152}, {"nup-xpad", required_argument, 0, 145}, {"nup-ypad", required_argument, 0, 146}, {"page-label-format", required_argument, 0, 130}, {"ps-level", required_argument, 0, 149}, {"printer-options", required_argument, 0, 139}, {"rotate-even-pages", no_argument, 0, 150}, {"slice", required_argument, 0, 140}, {"style", required_argument, 0, 151}, {"swap-even-page-margins", no_argument, 0, 153}, {"toc", no_argument, &toc, 1}, {"word-wrap", no_argument, 0, 147}, {"ul-angle", required_argument, 0, 132}, {"ul-font", required_argument, 0, 128}, {"ul-gray", required_argument, 0, 129}, {"ul-position", required_argument, 0, 133}, {"ul-style", required_argument, 0, 137}, /* Backwards compatiblity options. */ {"pretty-print", optional_argument, 0, 'E'}, {"help-pretty-print", no_argument, 0, 141}, {NULL, 0, 0, 0}, }; /* * Global functions. */ int main (int argc, char *argv[]) { InputStream is; time_t tim; struct tm *tm; int i, j, found; unsigned int ui; MediaEntry *mentry; AFMError afm_error; char *cp, *cp2; int retval = 0; Buffer buffer; /* Init our dynamic memory buffer. */ buffer_init (&buffer); /* Get program's name. */ program = strrchr (argv[0], '/'); if (program == NULL) program = argv[0]; else program++; /* Make getopt_long() to use our modified programname. */ argv[0] = program; /* Create the default TOC format string. Wow, this is cool! */ /* xgettext:no-c-format */ toc_fmt_string = _("$3v $-40N $3% pages $4L lines $E $C"); /* Internationalization. */ #if HAVE_SETLOCALE /* * We want to change only messages (gs do not like decimals in 0,1 * format ;) */ #if HAVE_LC_MESSAGES setlocale (LC_MESSAGES, ""); #endif #endif #if ENABLE_NLS bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); #endif /* Create date string. */ tim = time (NULL); tm = localtime (&tim); memcpy (&run_tm, tm, sizeof (*tm)); date_string = xstrdup (asctime (&run_tm)); i = strlen (date_string); date_string[i - 1] = '\0'; /* Get user's passwd entry. */ passwd = getpwuid (getuid ()); if (passwd == NULL) FATAL ((stderr, _("couldn't get passwd entry for uid=%d: %s"), getuid (), strerror (errno))); /* Defaults for some options. */ media_name = xstrdup ("A4"); encoding_name = xstrdup ("88591"); npf_name = xstrdup ("octal"); page_label_format = xstrdup ("short"); ul_style_str = xstrdup ("outline"); ul_position = xstrdup ("+0-0"); spooler_command = xstrdup ("lpr"); queue_param = xstrdup ("-P"); no_job_header_switch = xstrdup ("-h"); fancy_header_default = xstrdup ("enscript"); output_first_line = xstrdup ("%!PS-Adobe-3.0"); /* Check ENSCRIPT_LIBRARY for custom library location. */ cp = getenv ("ENSCRIPT_LIBRARY"); if (cp) enscript_library = cp; /* Fill up build-in libpath. */ cp = getenv ("HOME"); if (cp == NULL) cp = passwd->pw_dir; buffer_clear (&buffer); buffer_append (&buffer, enscript_library); buffer_append (&buffer, PATH_SEPARATOR_STR); buffer_append (&buffer, cp); buffer_append (&buffer, "/.enscript"); libpath = buffer_copy (&buffer); /* Defaults for the states filter. */ states_binary = xstrdup ("states"); /* Take it from the user path. */ buffer_clear (&buffer); buffer_append (&buffer, enscript_library); buffer_append (&buffer, "/hl/enscript.st"); states_config_file = buffer_copy (&buffer); states_highlight_style = xstrdup ("emacs"); /* The holds the user's home directory. */ buffer_clear (&buffer); buffer_append (&buffer, cp); buffer_append (&buffer, "/.enscript"); buffer_append (&buffer, PATH_SEPARATOR_STR); buffer_append (&buffer, enscript_library); buffer_append (&buffer, "/hl"); states_path = buffer_copy (&buffer); /* Initialize resource sets. */ res_fonts = strhash_init (); download_fonts = strhash_init (); pagedevice = strhash_init (); statusdict = strhash_init (); user_strings = strhash_init (); /* * Read configuration files. */ /* Global config. */ #define CFG_FILE_NAME "enscript.cfg" if (!read_config (SYSCONFDIR, CFG_FILE_NAME)) { int saved_errno = errno; /* Try to read it from our library directory. This is mostly the case for the micro ports. */ if (!read_config (enscript_library, CFG_FILE_NAME)) { /* Try `enscript_library/../../etc/'. This is the case for installations which set the prefix after the compilation and our SYSCONFDIR points to wrong directory. */ buffer_clear (&buffer); buffer_append (&buffer, enscript_library); buffer_append (&buffer, "/../../etc"); if (!read_config (buffer_ptr (&buffer), CFG_FILE_NAME)) { /* Maybe we are not installed yet, let's try `../lib' and `../../lib'. */ if (!read_config ("../lib", CFG_FILE_NAME) && !read_config ("../../lib", CFG_FILE_NAME)) { /* No luck, report error from the original config file. */ ERROR ((stderr, _("couldn't read config file \"%s/%s\": %s"), enscript_library, CFG_FILE_NAME, strerror (saved_errno))); ERROR ((stderr, _("I did also try the following directories:"))); ERROR ((stderr, _("\t%s"), SYSCONFDIR)); ERROR ((stderr, _("\t%s"), enscript_library)); ERROR ((stderr, _("\t%s"), buffer_ptr (&buffer))); ERROR ((stderr, _("\t../lib"))); ERROR ((stderr, _("\t../../lib"))); ERROR ((stderr, _("This is probably an installation error. Please, try to rebuild:"))); ERROR ((stderr, _("\tmake distclean"))); ERROR ((stderr, _("\t./configure --prefix=PREFIX"))); ERROR ((stderr, _("\tmake"))); ERROR ((stderr, _("\tmake check"))); ERROR ((stderr, _("\tmake install"))); ERROR ((stderr, _("or set the environment variable `ENSCRIPT_LIBRARY'" " to point to your library directory."))); exit (1); } /* Ok, we are not installed yet. Here is a small kludge to conform the GNU coding standards: we must be able to run without being installed, so we must append the `../lib' and `../../lib' directories to the libpath. The later allows us to be run form the `src/tests' directory. */ buffer_clear (&buffer); buffer_append (&buffer, libpath); buffer_append (&buffer, PATH_SEPARATOR_STR); buffer_append (&buffer, "../lib"); buffer_append (&buffer, PATH_SEPARATOR_STR); buffer_append (&buffer, "../../lib"); xfree (libpath); libpath = buffer_copy (&buffer); } } } /* Site config. */ read_config (SYSCONFDIR, "enscriptsite.cfg"); /* Personal config. */ read_config (cp, ".enscriptrc"); /* * Options. */ /* Environment variables. */ handle_env_options ("ENSCRIPT"); handle_env_options ("GENSCRIPT"); /* Command line arguments. */ handle_options (argc, argv); /* * Check options which have some validity conditions. */ /* * Save the user-specified escape char so ^@escape{default} knows * what to set. */ default_escape_char = escape_char; /* Input encoding. */ found = 0; for (i = 0; !found && encodings[i].names[0]; i++) for (j = 0; j < 3; j++) if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j], encoding_name)) { /* Found a match for this encoding. Use the first "official" name. */ encoding = encodings[i].encoding; xfree (encoding_name); encoding_name = xstrdup (encodings[i].names[0]); if (nl < 0) nl = encodings[i].nl; bs = encodings[i].bs; found = 1; break; } if (!found) FATAL ((stderr, _("unknown encoding: %s"), encoding_name)); /* Fonts. */ /* Default font for landscape, 2 column printing is Courier 7. */ if (!user_body_font_defined && landscape && num_columns > 1) Fpt.w = Fpt.h = 7.0; /* Cache for font AFM information. */ afm_cache = strhash_init (); afm_info_cache = strhash_init (); /* Open AFM library. */ afm_error = afm_create (afm_path, verbose, &afm); if (afm_error != AFM_SUCCESS) { char buf[256]; afm_error_to_string (afm_error, buf); FATAL ((stderr, _("couldn't open AFM library: %s"), buf)); } /* * Save default Fpt and Fname since special escape 'font' can change * it and later we might want to switch back to the "default" font. */ default_Fpt.w = Fpt.w; default_Fpt.h = Fpt.h; default_Fname = Fname; default_Fencoding = encoding; /* Register that document uses at least these fonts. */ strhash_put (res_fonts, Fname, strlen (Fname) + 1, NULL, NULL); strhash_put (res_fonts, HFname, strlen (HFname) + 1, NULL, NULL); /* As a default, download both named fonts. */ strhash_put (download_fonts, Fname, strlen (Fname) + 1, NULL, NULL); strhash_put (download_fonts, HFname, strlen (HFname) + 1, NULL, NULL); /* Read font's character widths and character types. */ read_font_info (); /* Count the line indentation. */ line_indent = parse_float (line_indent_spec, 1, 1); /* List media names. */ if (list_media) { printf (_("known media:\n\ name width\theight\tllx\tlly\turx\tury\n\ ------------------------------------------------------------\n")); for (mentry = media_names; mentry; mentry = mentry->next) printf ("%-16s %d\t%d\t%d\t%d\t%d\t%d\n", mentry->name, mentry->w, mentry->h, mentry->llx, mentry->lly, mentry->urx, mentry->ury); /* Exit after listing. */ exit (0); } /* Output media. */ for (mentry = media_names; mentry; mentry = mentry->next) if (strcmp (media_name, mentry->name) == 0) { media = mentry; break; } if (media == NULL) FATAL ((stderr, _("do not know anything about media \"%s\""), media_name)); if (margins_spec) { /* Adjust marginals. */ for (i = 0; i < 4; i++) { if (*margins_spec == '\0') /* All done. */ break; if (*margins_spec == ':') { margins_spec++; continue; } j = atoi (margins_spec); for (; *margins_spec != ':' && *margins_spec != '\0'; margins_spec++) ; if (*margins_spec == ':') margins_spec++; switch (i) { case 0: /* left */ media->llx = j; break; case 1: /* right */ media->urx = media->w - j; break; case 2: /* top */ media->ury = media->h - j; break; case 3: /* bottom */ media->lly = j; break; } } MESSAGE (1, (stderr, _("set new marginals for media `%s' (%dx%d): llx=%d, lly=%d, urx=%d, ury=%d\n"), media->name, media->w, media->h, media->llx, media->lly, media->urx, media->ury)); } /* Page label format. */ if (MATCH (page_label_format, "short")) page_label = LABEL_SHORT; else if (MATCH (page_label_format, "long")) page_label = LABEL_LONG; else FATAL ((stderr, _("illegal page label format \"%s\""), page_label_format)); /* Non-printable format. */ if (MATCH (npf_name, "space")) non_printable_format = NPF_SPACE; else if (MATCH (npf_name, "questionmark")) non_printable_format = NPF_QUESTIONMARK; else if (MATCH (npf_name, "caret")) non_printable_format = NPF_CARET; else if (MATCH (npf_name, "octal")) non_printable_format = NPF_OCTAL; else FATAL ((stderr, _("illegal non-printable format \"%s\""), npf_name)); /* Mark wrapped lines style. */ if (mark_wrapped_lines_style_name) { if (MATCH (mark_wrapped_lines_style_name, "none")) mark_wrapped_lines_style = MWLS_NONE; else if (MATCH (mark_wrapped_lines_style_name, "plus")) mark_wrapped_lines_style = MWLS_PLUS; else if (MATCH (mark_wrapped_lines_style_name, "box")) mark_wrapped_lines_style = MWLS_BOX; else if (MATCH (mark_wrapped_lines_style_name, "arrow")) mark_wrapped_lines_style = MWLS_ARROW; else FATAL ((stderr, _("illegal style for wrapped line marker: \"%s\""), mark_wrapped_lines_style_name)); } /* Count N-up stuffs. */ for (i = 0; ; i++) { ui = nup >> i; if (ui == 0) FATAL ((stderr, _("illegal N-up argument: %d"), nup)); if (ui & 0x1) { if (ui != 1) FATAL ((stderr, _("N-up argument must be power of 2: %d"), nup)); nup_exp = i; break; } } nup_rows = nup_exp / 2 * 2; if (nup_rows == 0) nup_rows = 1; nup_columns = (nup_exp + 1) / 2 * 2; if (nup_columns == 0) nup_columns = 1; nup_landscape = nup_exp & 0x1; /* * Count output media dimensions. */ if (landscape) { d_page_w = media->ury - media->lly; d_page_h = media->urx - media->llx; } else { d_page_w = media->urx - media->llx; d_page_h = media->ury - media->lly; } /* * Count N-up page width, height and scale. */ if (nup_landscape) { nup_width = media->ury - media->lly; nup_height = media->urx - media->llx; } else { nup_width = media->urx - media->llx; nup_height = media->ury - media->lly; } { double w, h; w = ((double) nup_width - (nup_columns - 1) * nup_xpad) / nup_columns; h = ((double) nup_height - (nup_rows - 1) * nup_ypad) / nup_rows; nup_width = w; nup_height = h; w = w / (media->urx - media->llx); h = h / (media->ury - media->lly); nup_scale = w < h ? w : h; } /* * Underlay (this must come after output media dimensions, because * `underlay position' needs them). */ if (underlay != NULL) { strhash_put (res_fonts, ul_font, strlen (ul_font) + 1, NULL, NULL); underlay = escape_string (underlay); } /* Underlay X-coordinate. */ ul_x = strtod (ul_position, &cp); if (cp == ul_position) { malformed_position: FATAL ((stderr, _("malformed underlay position: %s"), ul_position)); } if (ul_position[0] == '-') ul_x += d_page_w; /* Underlay Y-coordinate. */ ul_y = strtod (cp, &cp2); if (cp2 == cp) goto malformed_position; if (cp[0] == '-') ul_y += d_page_h; /* Underlay Angle. */ if (!ul_angle_p) /* No angle given, count the default. */ ul_angle = (atan2 (-d_page_h, d_page_w) / 3.14159265 * 180); /* Underlay style. */ if (strcmp (ul_style_str, "outline") == 0) ul_style = UL_STYLE_OUTLINE; else if (strcmp (ul_style_str, "filled") == 0) ul_style = UL_STYLE_FILLED; else FATAL ((stderr, _("illegal underlay style: %s"), ul_style_str)); /* * Header. Note! The header attributes can be changed from * the `.hdr' files, these are only the defaults. */ d_header_w = d_page_w; switch (header) { case HDR_NONE: d_header_h = 0; break; case HDR_SIMPLE: d_header_h = HFpt.h * 1.5; break; case HDR_FANCY: d_header_h = 36; break; } /* Help highlight. */ if (help_highlight) { /* Create description with states. */ printf (_("Highlighting is supported for the following languages and file formats:\n\n")); fflush (stdout); buffer_clear (&buffer); buffer_append (&buffer, states_binary); buffer_append (&buffer, " -f \""); buffer_append (&buffer, states_config_file); buffer_append (&buffer, "\" -p \""); buffer_append (&buffer, states_path); buffer_append (&buffer, "\" -s describe_languages "); buffer_append (&buffer, enscript_library); buffer_append (&buffer, "/hl/*.st"); system (buffer_ptr (&buffer)); exit (0); } /* * And now to the main business. The actual input file processing * is divided to two parts: PostScript generation and everything else. * The PostScript generation is handled in the conventional way, we * process the input and generate PostScript. However all other input * languages will be handled with States, we only pass enscript's * options to the states pre-filter and dump output. */ if (output_language_pass_through) { char *start_state; Buffer cmd; char intbuf[256]; /* The States output generation. */ /* Resolve the start state. */ if (hl_start_state) start_state = hl_start_state; else if (highlight) start_state = NULL; else start_state = "passthrough"; /* Create the states command. */ buffer_init (&cmd); buffer_append (&cmd, states_binary); buffer_append (&cmd, " -f \""); buffer_append (&cmd, states_config_file); buffer_append (&cmd, "\" -p \""); buffer_append (&cmd, states_path); buffer_append (&cmd, "\" "); if (verbose > 0) buffer_append (&cmd, "-v "); if (start_state) { buffer_append (&cmd, "-s"); buffer_append (&cmd, start_state); buffer_append (&cmd, " "); } buffer_append (&cmd, "-Dcolor="); buffer_append (&cmd, states_color ? "1" : "0"); buffer_append (&cmd, " "); buffer_append (&cmd, "-Dstyle="); buffer_append (&cmd, states_highlight_style); buffer_append (&cmd, " "); buffer_append (&cmd, "-Dlanguage="); buffer_append (&cmd, output_language); buffer_append (&cmd, " "); buffer_append (&cmd, "-Dnum_input_files="); sprintf (intbuf, "%d", optind == argc ? 1 : argc - optind); buffer_append (&cmd, intbuf); buffer_append (&cmd, " "); buffer_append (&cmd, "-Ddocument_title=\'"); if ((cp = shell_escape (title)) != NULL) { buffer_append (&cmd, cp); free (cp); } buffer_append (&cmd, "\' "); buffer_append (&cmd, "-Dtoc="); buffer_append (&cmd, toc ? "1" : "0"); /* Additional options for states? */ if (helper_options['s']) { Buffer *opts = helper_options['s']; buffer_append (&cmd, " "); buffer_append_len (&cmd, buffer_ptr (opts), buffer_len (opts)); } /* Append input files. */ for (i = optind; i < argc; i++) { char *cp; if ((cp = shell_escape (argv[i])) != NULL) { buffer_append (&cmd, " \'"); buffer_append (&cmd, cp); buffer_append (&cmd, "\'"); free (cp); } } /* And do the job. */ if (is_open (&is, stdin, NULL, buffer_ptr (&cmd))) { open_output_file (); process_file ("unused", &is, 0); is_close (&is); } buffer_uninit (&cmd); } else { /* The conventional way. */ /* Highlighting. */ if (highlight) { char fbuf[256]; /* Create a highlight input filter. */ buffer_clear (&buffer); buffer_append (&buffer, states_binary); buffer_append (&buffer, " -f \""); buffer_append (&buffer, states_config_file); buffer_append (&buffer, "\" -p \""); buffer_append (&buffer, states_path); buffer_append (&buffer, "\""); if (verbose > 0) buffer_append (&buffer, " -v"); if (hl_start_state) { buffer_append (&buffer, " -s "); buffer_append (&buffer, hl_start_state); } buffer_append (&buffer, " -Dcolor="); buffer_append (&buffer, states_color ? "1" : "0"); buffer_append (&buffer, " -Dstyle="); buffer_append (&buffer, states_highlight_style); buffer_append (&buffer, " -Dfont_spec="); buffer_append (&buffer, Fname); sprintf (fbuf, "@%g/%g", Fpt.w, Fpt.h); buffer_append (&buffer, fbuf); /* Additional options for states? */ if (helper_options['s']) { Buffer *opts = helper_options['s']; buffer_append (&buffer, " "); buffer_append_len (&buffer, buffer_ptr (opts), buffer_len (opts)); } buffer_append (&buffer, " \'%s\'"); input_filter = buffer_copy (&buffer); input_filter_stdin = "-"; } /* Table of Contents. */ if (toc) { toc_fp = tmpfile (); if (toc_fp == NULL) FATAL ((stderr, _("couldn't create temporary toc file: %s"), strerror (errno))); } /* * Process files. */ if (optind == argc) { /* stdin's modification time is the current time. */ memcpy (&mod_tm, &run_tm, sizeof (run_tm)); if (is_open (&is, stdin, NULL, input_filter)) { /* Open output file. */ open_output_file (); process_file (title_given ? title : "", &is, 0); is_close (&is); } } else { for (; optind < argc; optind++) { if (is_open (&is, NULL, argv[optind], input_filter)) { struct stat stat_st; /* Get modification time. */ if (stat (argv[optind], &stat_st) == 0) { tim = stat_st.st_mtime; tm = localtime (&tim); memcpy (&mod_tm, tm, sizeof (*tm)); /* * Open output file. Output file opening is delayed to * this point so we can optimize the case when a * non-existing input file is printed => we do nothing. */ open_output_file (); process_file (argv[optind], &is, 0); } else ERROR ((stderr, _("couldn't stat input file \"%s\": %s"), argv[optind], strerror (errno))); is_close (&is); } } } /* Table of Contents. */ if (toc) { /* This is really cool... */ /* Set the printing options for toc. */ toc = 0; special_escapes = 1; line_numbers = 0; if (fseek (toc_fp, 0, SEEK_SET) != 0) FATAL ((stderr, _("couldn't rewind toc file: %s"), strerror (errno))); memcpy (&mod_tm, &run_tm, sizeof (run_tm)); if (is_open (&is, toc_fp, NULL, NULL)) { process_file (_("Table of Contents"), &is, 1); is_close (&is); } } /* Give trailer a chance to dump itself. */ dump_ps_trailer (); /* * Append ^D to the end of the output? Note! It must be ^D followed * by a newline. */ if (ofp != NULL && append_ctrl_D) fprintf (ofp, "\004\n"); } /* Close output file. */ close_output_file (); /* Tell how things went. */ if (ofp == NULL) { /* * The value of is not reset in close_output_file(), * this is ugly but it saves one flag. */ MESSAGE (0, (stderr, _("no output generated\n"))); } else if (output_language_pass_through) { if (output_file == OUTPUT_FILE_NONE) MESSAGE (0, (stderr, _("output sent to %s\n"), printer ? printer : _("printer"))); else MESSAGE (0, (stderr, _("output left in %s\n"), output_file == OUTPUT_FILE_STDOUT ? "-" : output_file)); } else { unsigned int real_total_pages; if (nup > 1) { if (total_pages > 0) real_total_pages = (total_pages - 1) / nup + 1; else real_total_pages = 0; } else real_total_pages = total_pages; /* We did something, tell what. */ char message[80]; snprintf(message, sizeof message, "%s%s%s%s%s", "[ ", ngettext("%d page", "%d pages", real_total_pages), " * ", ngettext("%d copy", "%d copies", num_copies), " ]"); MESSAGE (0, (stderr, message, real_total_pages, num_copies)); if (output_file == OUTPUT_FILE_NONE) MESSAGE (0, (stderr, _(" sent to %s\n"), printer ? printer : _("printer"))); else MESSAGE (0, (stderr, _(" left in %s\n"), output_file == OUTPUT_FILE_STDOUT ? "-" : output_file)); if (num_truncated_lines) { retval |= 2; MESSAGE (0, (stderr, ngettext("%d line was %s\n", "%d lines were %s\n", num_truncated_lines), num_truncated_lines, line_end == LE_TRUNCATE ? _("truncated") : _("wrapped"))); } if (num_missing_chars) { retval |= 4; MESSAGE (0, (stderr, ngettext("%d character was missing\n", "%d characters were missing\n", num_missing_chars), num_missing_chars)); if (list_missing_characters) { MESSAGE (0, (stderr, _("missing character codes (decimal):\n"))); do_list_missing_characters (missing_chars); } } if (num_non_printable_chars) { retval |= 8; MESSAGE (0, (stderr, ngettext("%d non-printable character\n", "%d non-printable characters\n", num_non_printable_chars), num_non_printable_chars)); if (list_missing_characters) { MESSAGE (0, (stderr, _("non-printable character codes (decimal):\n"))); do_list_missing_characters (non_printable_chars); } } } /* Uninit our dynamic memory buffer. */ buffer_uninit (&buffer); /* Return the extended return values only if requested. */ if (!extended_return_values) retval = 0; /* This is the end. */ return retval; } /* * Static functions. */ static void open_output_file () { if (ofp) /* Output file has already been opened, do nothing. */ return; if (output_file == OUTPUT_FILE_NONE) { char spooler_options[512]; /* Format spooler options. */ spooler_options[0] = '\0'; if (mail) strcat (spooler_options, "-m "); if (no_job_header) { strcat (spooler_options, no_job_header_switch); strcat (spooler_options, " "); } if (printer_options) strcat (spooler_options, printer_options); /* Open printer. */ ofp = printer_open (spooler_command, spooler_options, queue_param, printer, &printer_context); if (ofp == NULL) FATAL ((stderr, _("couldn't open printer `%s': %s"), printer, strerror (errno))); } else if (output_file == OUTPUT_FILE_STDOUT) ofp = stdout; else { ofp = fopen (output_file, "w"); if (ofp == NULL) FATAL ((stderr, _("couldn't create output file \"%s\": %s"), output_file, strerror (errno))); } } static void close_output_file () { if (ofp == NULL) /* Output file hasn't been opened, we are done. */ return; if (output_file == OUTPUT_FILE_NONE) printer_close (printer_context); else if (output_file != OUTPUT_FILE_STDOUT) if (fclose (ofp)) FATAL ((stderr, _("couldn't close output file \"%s\": %s"), output_file, strerror (errno))); /* We do not reset since its value is needed in diagnostigs. */ } static void handle_env_options (char *var) { int argc; char **argv; char *string; char *str; int i; string = getenv (var); if (string == NULL) return; MESSAGE (2, (stderr, "handle_env_options(): %s=\"%s\"\n", var, string)); /* Copy string so we can modify it in place. */ str = xstrdup (string); /* * We can count this, each option takes at least 1 character and one * space. We also need one for program's name and one for the * trailing NULL. */ argc = (strlen (str) + 1) / 2 + 2; argv = xcalloc (argc, sizeof (char *)); /* Set program name. */ argc = 0; argv[argc++] = program; /* Split string and set arguments to argv array. */ i = 0; while (str[i]) { /* Skip leading whitespace. */ for (; str[i] && isspace (str[i]); i++) ; if (!str[i]) break; /* Check for quoted arguments. */ if (str[i] == '"' || str[i] == '\'') { int endch = str[i++]; argv[argc++] = str + i; /* Skip until we found the end of the quotation. */ for (; str[i] && str[i] != endch; i++) ; if (!str[i]) FATAL ((stderr, _("syntax error in option string %s=\"%s\":\n\ missing end of quotation: %c"), var, string, endch)); str[i++] = '\0'; } else { argv[argc++] = str + i; /* Skip until whitespace if found. */ for (; str[i] && !isspace (str[i]); i++) ; if (str[i]) str[i++] = '\0'; } } /* argv[argc] must be NULL. */ argv[argc] = NULL; MESSAGE (2, (stderr, "found following options (argc=%d):\n", argc)); for (i = 0; i < argc; i++) MESSAGE (2, (stderr, "%3d = \"%s\"\n", i, argv[i])); /* Process options. */ handle_options (argc, argv); /* Check that all got processed. */ if (optind != argc) { MESSAGE (0, (stderr, _("warning: didn't process following options from \ environment variable %s:\n"), var)); for (; optind < argc; optind++) MESSAGE (0, (stderr, _(" option %d = \"%s\"\n"), optind, argv[optind])); } /* Cleanup. */ xfree (argv); /* * must not be freed, since some global variables can point to * its elements */ } static void handle_options (int argc, char *argv[]) { int c; PageRange *prange; /* Reset optind. */ optind = 0; while (1) { int option_index = 0; const char *cp; int i; c = getopt_long (argc, argv, "#:123456789a:A:b:BcC::d:D:e::E::f:F:gGhH::i:I:jJ:kKlL:mM:n:N:o:Op:P:qrRs:S:t:T:u::U:vVw:W:X:zZ", long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* Long option found. */ cp = long_options[option_index].name; if (strcmp (cp, "columns") == 0) { num_columns = atoi (optarg); if (num_columns < 1) FATAL ((stderr, _("number of columns must be larger than zero"))); } break; /* Short options. */ case '1': /* 1 column */ case '2': /* 2 columns */ case '3': /* 3 columns */ case '4': /* 4 columns */ case '5': /* 5 columns */ case '6': /* 6 columns */ case '7': /* 7 columns */ case '8': /* 8 columns */ case '9': /* 9 columns */ num_columns = c - '0'; break; case 'a': /* pages */ prange = (PageRange *) xcalloc (1, sizeof (PageRange)); if (strcmp (optarg, "odd") == 0) prange->odd = 1; else if (strcmp (optarg, "even") == 0) prange->even = 1; else { cp = strchr (optarg, '-'); if (cp) { if (optarg[0] == '-') /* -end */ prange->end = atoi (optarg + 1); else if (cp[1] == '\0') { /* begin- */ prange->start = atoi (optarg); prange->end = (unsigned int) -1; } else { /* begin-end */ prange->start = atoi (optarg); prange->end = atoi (cp + 1); } } else /* pagenumber */ prange->start = prange->end = atoi (optarg); } prange->next = page_ranges; page_ranges = prange; break; case 'A': /* file alignment */ file_align = atoi (optarg); if (file_align == 0) FATAL ((stderr, _("file alignment must be larger than zero"))); break; case 'b': /* page header */ page_header = optarg; break; case 'B': /* no page headers */ header = HDR_NONE; break; case 'c': /* truncate (cut) long lines */ line_end = LE_TRUNCATE; break; case 'C': /* line numbers */ line_numbers = 1; if (optarg) start_line_number = atoi (optarg); break; case 'd': /* specify printer */ case 'P': xfree (printer); printer = xstrdup (optarg); output_file = OUTPUT_FILE_NONE; break; case 'D': /* setpagedevice */ parse_key_value_pair (pagedevice, optarg); break; case 'e': /* special escapes */ special_escapes = 1; if (optarg) { /* Specify the escape character. */ if (isdigit (optarg[0])) /* As decimal, octal, or hexadicimal number. */ escape_char = (int) strtoul (optarg, NULL, 0); else /* As character directly. */ escape_char = ((unsigned char *) optarg)[0]; } break; case 'E': /* highlight */ highlight = 1; special_escapes = 1; escape_char = '\0'; hl_start_state = optarg; break; case 'f': /* font */ if (!parse_font_spec (optarg, &Fname, &Fpt, NULL)) FATAL ((stderr, _("malformed font spec: %s"), optarg)); user_body_font_defined = 1; break; case 'F': /* header font */ if (!parse_font_spec (optarg, &HFname, &HFpt, NULL)) FATAL ((stderr, _("malformed font spec: %s"), optarg)); break; case 'g': /* print anyway */ /* nothing. */ break; case 'G': /* fancy header */ header = HDR_FANCY; if (optarg) fancy_header_name = optarg; else fancy_header_name = fancy_header_default; if (!file_existsp (fancy_header_name, ".hdr")) FATAL ((stderr, _("couldn't find header definition file \"%s.hdr\""), fancy_header_name)); break; case 'h': /* no job header */ no_job_header = 1; break; case 'H': /* highlight bars */ if (optarg) highlight_bars = atoi (optarg); else highlight_bars = 2; break; case 'i': /* line indent */ line_indent_spec = optarg; break; case 'I': /* input filter */ input_filter = optarg; break; case 'j': /* borders */ borders = 1; break; case 'k': /* enable page prefeed */ page_prefeed = 1; break; case 'K': /* disable page prefeed */ page_prefeed = 0; break; case 'l': /* emulate lineprinter */ lines_per_page = 66; header = HDR_NONE; break; case 'L': /* lines per page */ lines_per_page = atoi (optarg); if (lines_per_page <= 0) FATAL ((stderr, _("must print at least one line per each page: %s"), argv[optind])); break; case 'm': /* send mail upon completion */ mail = 1; break; case 'M': /* select output media */ media_name = xstrdup (optarg); break; case 'n': /* num copies */ case '#': num_copies = atoi (optarg); break; case 'N': /* newline character */ if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0') { fprintf (stderr, _("%s: illegal newline character specifier: \ '%s': expected 'n' or 'r'\n"), program, optarg); goto option_error; } if (optarg[0] == 'n') nl = '\n'; else nl = '\r'; break; case 'o': case 'p': /* output file */ /* Check output file "-". */ if (strcmp (optarg, "-") == 0) output_file = OUTPUT_FILE_STDOUT; else output_file = optarg; break; case 'O': /* list missing characters */ list_missing_characters = 1; break; case 'q': /* quiet */ quiet = 1; verbose = 0; break; case 'r': /* landscape */ landscape = 1; break; case 'R': /* portrait */ landscape = 0; break; case 's': /* baselineskip */ baselineskip = atof (optarg); break; case 'S': /* statusdict */ parse_key_value_pair (statusdict, optarg); break; case 't': /* title */ case 'J': title = optarg; title_given = 1; break; case 'T': /* tabulator size */ tabsize = atoi (optarg); if (tabsize <= 0) tabsize = 1; break; case 'u': /* underlay */ underlay = optarg; break; case 'U': /* nup */ nup = atoi (optarg); break; case 'v': /* verbose */ if (optarg) verbose = atoi (optarg); else verbose++; quiet = 0; break; case 'V': /* version */ version (); exit (0); break; case 'w': /* output language */ output_language = optarg; if (strcmp (output_language, "PostScript") != 0) /* Other output languages are handled with states. */ output_language_pass_through = 1; break; case 'W': /* a helper application option */ cp = strchr (optarg, ','); if (cp == NULL) FATAL ((stderr, _("malformed argument `%s' for option -W, --option: \ no comma found"), optarg)); if (cp - optarg != 1) FATAL ((stderr, _("helper application specification must be \ single character: %s"), optarg)); /* Take the index of the helper application and update `cp' to point to the beginning of the option. */ i = *optarg; cp++; if (helper_options[i] == NULL) helper_options[i] = buffer_alloc (); else { /* We already had some options for this helper application. Let's separate these arguments. */ buffer_append (helper_options[i], " "); } /* Add this new option. */ buffer_append (helper_options[i], cp); break; case 'X': /* input encoding */ xfree (encoding_name); encoding_name = xstrdup (optarg); break; case 'z': /* no form feeds */ interpret_formfeed = 0; break; case 'Z': /* pass through */ pass_through = 1; break; case 128: /* underlay font */ if (!parse_font_spec (optarg, &ul_font, &ul_ptsize, NULL)) FATAL ((stderr, _("malformed font spec: %s"), optarg)); break; case 129: /* underlay gray */ ul_gray = atof (optarg); break; case 130: /* page label format */ xfree (page_label_format); page_label_format = xstrdup (optarg); break; case 131: /* download font */ strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL, NULL); break; case 132: /* underlay angle */ ul_angle = atof (optarg); ul_angle_p = 1; break; case 133: /* underlay position */ xfree (ul_position); ul_position = xstrdup (optarg); ul_position_p = 1; break; case 134: /* non-printable format */ xfree (npf_name); npf_name = xstrdup (optarg); break; case 135: /* help */ usage (); exit (0); break; case 136: /* highlight bar gray */ highlight_bar_gray = atof (optarg); break; case 137: /* underlay style */ xfree (ul_style_str); ul_style_str = xstrdup (optarg); break; case 138: /* filter stdin */ input_filter_stdin = optarg; break; case 139: /* extra options for the printer spooler */ printer_options = optarg; break; case 140: /* slicing */ slicing = 1; slice = atoi (optarg); if (slice <= 0) FATAL ((stderr, _("slice must be greater than zero"))); break; case 141: /* help-highlight */ help_highlight = 1; break; case 142: /* States color? */ if (optarg == NULL) states_color = 1; else states_color = atoi (optarg); break; case 143: /* mark-wrapped-lines */ if (optarg) { xfree (mark_wrapped_lines_style_name); mark_wrapped_lines_style_name = xstrdup (optarg); } else /* Set the system default. */ mark_wrapped_lines_style = MWLS_BOX; break; case 144: /* adjust margins */ margins_spec = optarg; break; case 145: /* N-up x-pad */ nup_xpad = atoi (optarg); break; case 146: /* N-up y-pad */ nup_ypad = atoi (optarg); break; case 147: /* word wrap */ line_end = LE_WORD_WRAP; break; case 148: /* horizontal column height */ horizontal_column_height = atof (optarg); formfeed_type = FORMFEED_HCOLUMN; break; case 149: /* PostScript language level */ pslevel = atoi (optarg); break; case 150: /* rotate even-numbered pages */ rotate_even_pages = 1; break; case 151: /* highlight style */ xfree (states_highlight_style); states_highlight_style = xstrdup (optarg); break; case 152: /* N-up colunwise */ nup_columnwise = 1; break; case 153: /* swap even page margins */ swap_even_page_margins = 1; break; case 154: /* extended return values */ extended_return_values = 1; break; case 155: /* footer */ page_footer = optarg; break; case 156: /* continuous page numbers */ continuous_page_numbers = 1; break; case '?': /* Errors found during getopt_long(). */ option_error: fprintf (stderr, _("Try `%s --help' for more information.\n"), program); exit (1); break; default: printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c); if (optarg) printf (" with arg %s", optarg); printf ("\n"); FATAL ((stderr, "This is a bug!")); break; } } } static void usage () { printf (_("\ Usage: %s [OPTION]... [FILE]...\n\ Mandatory arguments to long options are mandatory for short options too.\n\ -# an alias for option -n, --copies\n\ -1 same as --columns=1\n\ -2 same as --columns=2\n\ --columns=NUM specify the number of columns per page\n\ -a, --pages=PAGES specify which pages are printed\n\ -A, --file-align=ALIGN align separate input files to ALIGN\n\ -b, --header=HEADER set page header\n\ -B, --no-header no page headers\n\ -c, --truncate-lines cut long lines (default is to wrap)\n\ -C[START], --line-numbers[=START]\n\ precede each line with its line number\n\ -d an alias for option --printer\n\ -D, --setpagedevice=KEY[:VALUE]\n\ pass a page device definition to output\n\ -e[CHAR], --escapes[=CHAR] enable special escape interpretation\n"), program); printf (_("\ -E[LANG], --highlight[=LANG] highlight source code\n")); printf (_("\ -f, --font=NAME use font NAME for body text\n\ -F, --header-font=NAME use font NAME for header texts\n\ -g, --print-anyway nothing (compatibility option)\n\ -G same as --fancy-header\n\ --fancy-header[=NAME] select fancy page header\n\ -h, --no-job-header suppress the job header page\n\ -H[NUM], --highlight-bars[=NUM] specify how high highlight bars are\n\ -i, --indent=NUM set line indent to NUM characters\n\ -I, --filter=CMD read input files through input filter CMD\n\ -j, --borders print borders around columns\n\ -J, an alias for option --title\n\ -k, --page-prefeed enable page prefeed\n\ -K, --no-page-prefeed disable page prefeed\n\ -l, --lineprinter simulate lineprinter, this is an alias for:\n\ --lines-per-page=66, --no-header, --portrait,\n\ --columns=1\n")); printf (_("\ -L, --lines-per-page=NUM specify how many lines are printed on each page\n\ -m, --mail send mail upon completion\n\ -M, --media=NAME use output media NAME\n\ -n, --copies=NUM print NUM copies of each page\n\ -N, --newline=NL select the newline character. Possible\n\ values for NL are: n (`\\n') and r (`\\r').\n\ -o an alias for option --output\n\ -O, --missing-characters list missing characters\n\ -p, --output=FILE leave output to file FILE. If FILE is `-',\n\ leave output to stdout.\n\ -P, --printer=NAME print output to printer NAME\n\ -q, --quiet, --silent be really quiet\n\ -r, --landscape print in landscape mode\n\ -R, --portrait print in portrait mode\n")); printf (_("\ -s, --baselineskip=NUM set baselineskip to NUM\n\ -S, --statusdict=KEY[:VALUE]\n\ pass a statusdict definition to the output\n\ -t, --title=TITLE set banner page's job title to TITLE. Option\n\ sets also the name of the input file stdin.\n\ -T, --tabsize=NUM set tabulator size to NUM\n\ -u[TEXT], --underlay[=TEXT] print TEXT under every page\n\ -U, --nup=NUM print NUM logical pages on each output page\n\ -v, --verbose tell what we are doing\n\ -V, --version print version number\n\ -w, --language=LANG set output language to LANG\n\ -W, --options=APP,OPTION pass option OPTION to helper application APP\n\ -X, --encoding=NAME use input encoding NAME\n\ -z, --no-formfeed do not interpret form feed characters\n\ -Z, --pass-through pass through PostScript and PCL files\n\ without any modifications\n")); printf (_("Long-only options:\n\ --color[=bool] create color outputs with states\n\ --continuous-page-numbers count page numbers across input files. Don't\n\ restart numbering at beginning of each file.\n\ --download-font=NAME download font NAME\n\ --extended-return-values enable extended return values\n\ --filter-stdin=NAME specify how stdin is shown to the input filter\n\ --footer=FOOTER set page footer\n\ --h-column-height=HEIGHT set the horizontal column height to HEIGHT\n\ --help print this help and exit\n")); printf (_("\ --help-highlight describe all supported --highlight languages\n\ and file formats\n\ --highlight-bar-gray=NUM print highlight bars with gray NUM (0 - 1)\n\ --list-media list names of all known media\n\ --margins=LEFT:RIGHT:TOP:BOTTOM\n\ adjust page marginals\n\ --mark-wrapped-lines[STYLE]\n\ mark wrapped lines in the output with STYLE\n\ --non-printable-format=FMT specify how non-printable chars are printed\n")); printf (_("\ --nup-columnwise layout pages in the N-up printing columnwise\n\ --nup-xpad=NUM set the page x-padding of N-up printing to NUM\n\ --nup-ypad=NUM set the page y-padding of N-up printing to NUM\n\ --page-label-format=FMT set page label format to FMT\n\ --ps-level=LEVEL set the PostScript language level that enscript\n\ should use\n\ --printer-options=OPTIONS pass extra options to the printer command\n\ --rotate-even-pages rotate even-numbered pages 180 degrees\n")); printf (_("\ --slice=NUM print vertical slice NUM\n\ --style=STYLE use highlight style STYLE\n\ --swap-even-page-margins swap left and right side margins for each even\n\ numbered page\n\ --toc print table of contents\n\ --ul-angle=ANGLE set underlay text's angle to ANGLE\n\ --ul-font=NAME print underlays with font NAME\n\ --ul-gray=NUM print underlays with gray value NUM\n\ --ul-position=POS set underlay's starting position to POS\n\ --ul-style=STYLE print underlays with style STYLE\n\ --word-wrap wrap long lines from word boundaries\n\ ")); printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); } static void version () { printf ("%s\n\ Copyright (C) 1995-2003, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.\n\ %s comes with NO WARRANTY, to the extent permitted by law.\n\ You may redistribute copies of %s under the terms of the GNU\n\ General Public License, version 3 or, at your option, any later version.\n\ For more information about these matters, see the files named COPYING.\n", PACKAGE_STRING, PACKAGE_NAME, PACKAGE_NAME); }