main.c - enscript - GNU Enscript
 (HTM) git clone git://thinkerwim.org/enscript.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       main.c (67750B)
       ---
            1 /*
            2  * Argument handling and main.
            3  * Copyright (c) 1995-2003 Markku Rossi.
            4  *
            5  * Author: Markku Rossi <mtr@iki.fi>
            6  */
            7 
            8 /*
            9  * This file is part of GNU Enscript.
           10  *
           11  * Enscript is free software: you can redistribute it and/or modify
           12  * it under the terms of the GNU General Public License as published by
           13  * the Free Software Foundation, either version 3 of the License, or
           14  * (at your option) any later version.
           15  *
           16  * Enscript is distributed in the hope that it will be useful,
           17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
           18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
           19  * GNU General Public License for more details.
           20  *
           21  * You should have received a copy of the GNU General Public License
           22  * along with Enscript.  If not, see <http://www.gnu.org/licenses/>.
           23  */
           24 
           25 #include "gsint.h"
           26 #include "getopt.h"
           27 #include <locale.h>
           28 #include <limits.h>
           29 
           30 /*
           31  * Prototypes for static functions.
           32  */
           33 
           34 /*
           35  * Open output file according to user options.  Void if output file
           36  * has already been opened.
           37  */
           38 static void open_output_file ();
           39 
           40 /* Close output file. */
           41 static void close_output_file ();
           42 
           43 /* Handle options from environment variable <var> */
           44 static void handle_env_options ___P ((char *var));
           45 
           46 /* Handle options from <argv> array. */
           47 static void handle_options ___P ((int argc, char *argv[]));
           48 
           49 /* Print usage info. */
           50 static void usage ();
           51 
           52 /* Print version info. */
           53 static void version ();
           54 
           55 
           56 /*
           57  * Global variables.
           58  */
           59 
           60 char *program;                        /* Program's name, used for messages. */
           61 FILE *ofp = NULL;                /* Output file. */
           62 void *printer_context;                /* Context for the printer. */
           63 char *date_string = NULL;        /* Preformatted time string. */
           64 struct tm run_tm;                /* Time when program is run. */
           65 struct tm mod_tm;                /* Last modification time for current file. */
           66 struct passwd *passwd;                /* Passwd entry for the user running this
           67                                    program. */
           68 
           69 /* Path to our library. */
           70 char *enscript_library = LIBRARY;
           71 
           72 /* Library lookup path. */
           73 char *libpath = NULL;
           74 
           75 /* AFM library lookup path. */
           76 char *afm_path = NULL;
           77 
           78 MediaEntry *media_names = NULL;        /* List of known media. */
           79 MediaEntry *media = NULL;        /* Entry for used media. */
           80 int bs = 8;                        /* The backspace character. */
           81 
           82 /* Statistics. */
           83 int total_pages = 0;                /* Total number of pages printed. */
           84 int num_truncated_lines = 0;        /* Number of lines truncated. */
           85 int num_missing_chars = 0;        /* Number of unknown characters. */
           86 int missing_chars[256] = {0};        /* Table of unknown characters. */
           87 int num_non_printable_chars = 0; /* Number of non-printable characters. */
           88 int non_printable_chars[256] = {0}; /* Table of non-printable characters. */
           89 
           90 /* Output media dimensions that are used during PostScript emission. */
           91 int d_page_w = 0;                /* page's width */
           92 int d_page_h = 0;                /* page's height */
           93 int d_header_w = 0;                /* fancy header's width */
           94 int d_header_h = 0;                /* fancy header's height */
           95 int d_footer_h = 0;                /* fancy footer's height */
           96 int d_output_w = 0;                /* output area's width */
           97 int d_output_h = 0;                /* output area's height  */
           98 int d_output_x_margin = 5;        /* output area's x marginal */
           99 int d_output_y_margin = 2;        /* output area's y marginal */
          100 
          101 /* Document needed resources. */
          102 StringHashPtr res_fonts;        /* fonts */
          103 
          104 /* Fonts to download. */
          105 StringHashPtr download_fonts;
          106 
          107 /* Additional key-value pairs, passed to the generated PostScript code. */
          108 StringHashPtr pagedevice;        /* for setpagedevice */
          109 StringHashPtr statusdict;        /* for statusdict */
          110 
          111 /* User defined strings. */
          112 StringHashPtr user_strings;
          113 
          114 /* Cache for AFM files. */
          115 StringHashPtr afm_cache = NULL;
          116 StringHashPtr afm_info_cache = NULL;
          117 
          118 /* AFM library handle. */
          119 AFMHandle afm = NULL;
          120 
          121 
          122 /* Options. */
          123 
          124 /*
          125  * Free single-letter options are: Q, x, y, Y
          126  */
          127 
          128 /*
          129  * -#
          130  *
          131  * An alias for -n, --copies.
          132  */
          133 
          134 /*
          135  * -1, -2, -3, -4, -5, -6, -7, -8, -9, --columns=NUM
          136  *
          137  * Number of columns per page.  The default is 1 column.
          138  */
          139 int num_columns = 1;
          140 
          141 /*
          142  * -a PAGES, --pages=PAGES
          143  *
          144  * Specify which pages are printed.
          145  */
          146 PageRange *page_ranges = NULL;
          147 
          148 /*
          149  * -A ALIGN, --file-align=ALIGN
          150  *
          151  * Align input files to start from ALIGN page count.  This is handy
          152  * for two-side printings.
          153  */
          154 unsigned int file_align = 1;
          155 
          156 /*
          157  * -b STRING, --header=STRING
          158  *
          159  * Set the string that is used as the page header.  As a default, page
          160  * header is constructed from filename, date and page number.
          161  */
          162 char *page_header = NULL;
          163 
          164 /*
          165  * -B, --no-header
          166  *
          167  * Do not print page headers.
          168  */
          169 
          170 /*
          171  * -c, --truncate-lines
          172  *
          173  * Truncate lines that are longer than the page width.  Default is character
          174  * wrap.
          175  */
          176 LineEndType line_end = LE_CHAR_WRAP;
          177 
          178 /*
          179  * -C [START], --line-numbers[=START]
          180  *
          181  * Precede each line with its line number.  As a default, do not mark
          182  * line numbers.  If the optional argument START is given, it
          183  * specifies the number from which the line numbers are assumed to
          184  * start in the file.  This is useful if the file contains a region
          185  * of a bigger file.
          186  */
          187 int line_numbers = 0;
          188 unsigned int start_line_number = 1;
          189 
          190 /*
          191  * -d, -P, --printer
          192  *
          193  * Name of the printer to which output is send.  Defaults to system's
          194  * default printer.
          195  */
          196 char *printer = NULL;
          197 
          198 /*
          199  * -e [CHAR], --escapes[=CHAR]
          200  *
          201  * Enable special escape ('\000') interpretation.  If option CHAR is given
          202  * it is assumed to specify the escape character.
          203  */
          204 int special_escapes = 0;
          205 int escape_char = '\0';
          206 int default_escape_char;
          207 
          208 /*
          209  * -E [LANG], --highlight=[LANG] (deprecated --pretty-print[=LANG])
          210  *
          211  * Highlight program source code.  Highlighting is handled by creating
          212  * an input filter with the states-program.  States makes an educated
          213  * guess about the start state but sometimes it fails, so the start
          214  * state can also be specified to be LANG.  This option overwrites
          215  * input filter and enables special escapes.
          216  */
          217 
          218 int highlight = 0;
          219 char *hl_start_state = NULL;
          220 
          221 /*
          222  * -f, --font
          223  *
          224  * Select body font.
          225  */
          226 char *Fname = "Courier";
          227 FontPoint Fpt = {10.0, 10.0};
          228 FontPoint default_Fpt;                /* Point size of the original font. */
          229 char *default_Fname;                /* Name of the original font. */
          230 InputEncoding default_Fencoding; /* The encoding of the original font. */
          231 int user_body_font_defined = 0;        /* Has user defined new body font? */
          232 
          233 double font_widths[256];        /* Width array for body font. */
          234 char font_ctype[256];                /* Font character types. */
          235 int font_is_fixed;                /* Is body font a fixed pitch font? */
          236 double font_bbox_lly;                /* Font's bounding box's lly-coordinate. */
          237 
          238 /*
          239  * -F, --header-font
          240  *
          241  * Select font to be used to print the standard simple header.
          242  */
          243 char *HFname = "Courier-Bold";
          244 FontPoint HFpt = {10.0, 10.0};
          245 
          246 /*
          247  * -g, --print-anyway
          248  *
          249  * Print document even it contains binary data.  This does nothing
          250  * since enscript prints files anyway.
          251  */
          252 
          253 /*
          254  * -G, --fancy-header
          255  *
          256  * Add a fancy header to top of every page.  There are several header styles
          257  * but the default is 'no fancy header'.
          258  */
          259 HeaderType header = HDR_SIMPLE;
          260 char *fancy_header_name = NULL;
          261 char *fancy_header_default = NULL;
          262 
          263 /*
          264  * -h, --no-job-header
          265  *
          266  * Supress the job header page.
          267  */
          268 static int no_job_header = 0;
          269 
          270 /*
          271  * -H num, --highlight-bars=num
          272  *
          273  * Print highlight bars under text.  Bars will be <num> lines high.
          274  * As a default, do not print bars.
          275  */
          276 unsigned int highlight_bars = 0;
          277 
          278 /*
          279  * -i, --indent
          280  *
          281  * Indent every line this many characters.
          282  */
          283 double line_indent = 0.0;
          284 char *line_indent_spec = "0";
          285 
          286 /*
          287  * -I CMD, --filter=CMD
          288  *
          289  * Read input files through input filter CMD.
          290  */
          291 char *input_filter = NULL;
          292 
          293 /*
          294  * -j, --borders
          295  *
          296  * Print borders around columns.
          297  */
          298 int borders = 0;
          299 
          300 /*
          301  * -J
          302  *
          303  * An alias for -t, --title.
          304  */
          305 
          306 /*
          307  * -k, --page-prefeed
          308  * -K, --no-page-prefeed
          309  *
          310  * Control page prefeed.
          311  */
          312 int page_prefeed = 0;
          313 
          314 /*
          315  * -l, --lineprinter
          316  *
          317  * Emulate lineprinter -  make pages 66 lines long and omit headers.
          318  */
          319 
          320 /*
          321  * -L, --lines-per-page
          322  *
          323  * Specify how many lines should be printed on a single page.  Normally
          324  * enscript counts it from font point sizes.
          325  */
          326 unsigned int lines_per_page = (unsigned int) -1;
          327 
          328 /*
          329  * -m, --mail
          330  *
          331  * Send mail notification to user after print job has been completed.
          332  */
          333 int mail = 0;
          334 char *mailto;
          335 
          336 /*
          337  * -M, --media
          338  *
          339  * Name of the output media.  Default is A4.
          340  */
          341 char *media_name = NULL;
          342 
          343 /*
          344  * -n, --copies
          345  *
          346  * Number of copies to print.
          347  */
          348 int num_copies = 1;
          349 
          350 /*
          351  * -N, --newline
          352  *
          353  * Set the newline character: '\n' or '\r'.  As a default, the newline
          354  * character is specified by the input encoding.
          355  */
          356 int nl = -1;
          357 
          358 /*
          359  * -o, -p, --output
          360  *
          361  * Leave output to the specified file.  As a default result is spooled to
          362  * printer.
          363  */
          364 char *output_file = OUTPUT_FILE_NONE;
          365 
          366 /*
          367  * -O, --missing-characters
          368  *
          369  * List all missing characters.  Default is no listing.
          370  */
          371 int list_missing_characters = 0;
          372 
          373 /*
          374  * -q, --quiet
          375  *
          376  * Do not tell what we are doing.  Default is to tell something but
          377  * not --verbose.
          378  */
          379 int quiet = 0;
          380 
          381 /*
          382  * -r, --landscape
          383  * -R, --portrait
          384  *
          385  * Print with page rotated 90 degrees (landscape mode).  Default is
          386  * portrait.
          387  */
          388 int landscape = 0;
          389 
          390 /*
          391  * -s, --baselineskip
          392  *
          393  * Specify baselineskip value that is used when enscript moves to
          394  * a new line.  Current point movement is font_point_size + baselineskip.
          395  */
          396 double baselineskip = 1.0;
          397 
          398 /*
          399  * -t, --title
          400  *
          401  * Title which is printed to the banner page.  If this option is given
          402  * from the command line, this sets also the name of the stdin which
          403  * is by the default "".
          404  */
          405 char *title = "Enscript Output";
          406 int title_given = 0;
          407 
          408 /*
          409  * -T, --tabsize
          410  *
          411  * Specify tabulator size.
          412  */
          413 int tabsize = 8;
          414 
          415 /*
          416  * -u, --underlay
          417  *
          418  * Place text under every page.  Default is no underlay.
          419  */
          420 double ul_gray = .8;
          421 FontPoint ul_ptsize = {200.0, 200.0};
          422 char *ul_font = "Times-Roman";
          423 char *underlay = NULL;
          424 char *ul_position = NULL;        /* Position info as a string. */
          425 double ul_x;                        /* Position x-coordinate. */
          426 double ul_y;                        /* Position y-coordinate. */
          427 double ul_angle;
          428 unsigned int ul_style = UL_STYLE_OUTLINE;
          429 char *ul_style_str = NULL;
          430 int ul_position_p = 0;                /* Is ul-position given? */
          431 int ul_angle_p = 0;                /* Is ul-angle given? */
          432 
          433 /*
          434  * -U NUM, --nup=NUM
          435  *
          436  * Print NUM PostScript pages on each output page (n-up printing).
          437  */
          438 unsigned int nup = 1;
          439 unsigned int nup_exp = 0;
          440 unsigned int nup_rows = 1;
          441 unsigned int nup_columns = 1;
          442 int nup_landscape = 0;
          443 unsigned int nup_width;
          444 unsigned int nup_height;
          445 double nup_scale;
          446 
          447 /*
          448  * -v, --verbose
          449  *
          450  * Tell what we are doing.  Default is no verbose outputs.
          451  */
          452 int verbose = 0;
          453 
          454 /*
          455  * -V, --version
          456  *
          457  * Print version information.
          458  */
          459 
          460 /*
          461  * -w LANGUAGE, --language=LANGUAGE
          462  *
          463  * Generate output for language LANGUAGE.  The default is PostScript.
          464  */
          465 char *output_language = "PostScript";
          466 int output_language_pass_through = 0;
          467 
          468 /*
          469  * -W APP,option, --options=APP,OPTION
          470  *
          471  * Pass additional option to enscript's helper applications.  The
          472  * first part of the option's argument (APP) specifies the
          473  * helper application to which the options are added.  Currently the
          474  * following helper application are defined:
          475  *
          476  *   s        states
          477  */
          478 Buffer *helper_options[256] = {0};
          479 
          480 /*
          481  * -X, --encoding
          482  *
          483  * Specifies input encoding.  Default is ISO-8859.1.
          484  */
          485 InputEncoding encoding = ENC_ISO_8859_1;
          486 char *encoding_name = NULL;
          487 
          488 /*
          489  * -z, --no-formfeed
          490  *
          491  * Do not interpret form feed characters.  As a default, form feed
          492  * characters are interpreted.
          493  */
          494 int interpret_formfeed = 1;
          495 
          496 /*
          497  * -Z, --pass-through
          498  *
          499  * Pass through all PostScript and PCL files without any modifications.
          500  * As a default, don't.
          501  */
          502 int pass_through = 0;
          503 
          504 /*
          505  * --color[=bool]
          506  *
          507  * Create color output with states?
          508  */
          509 
          510 /*
          511  * --continuous-page-numbers
          512  *
          513  * Count page numbers across input files.  Don't restart numbering
          514  * at beginning of each file.
          515  */
          516 int continuous_page_numbers = 0;
          517 
          518 /*
          519  * --download-font=FONT
          520  *
          521  * Download font FONT to printer.
          522  */
          523 
          524 /*
          525  * --extended-return-values
          526  *
          527  * Enable extended return values.
          528  */
          529 int extended_return_values = 0;
          530 
          531 /*
          532  * --filter-stdin=STR
          533  *
          534  * How stdin is shown to the filter command.  The default is "" but
          535  * some utilities might want it as "-".
          536  */
          537 char *input_filter_stdin = "";
          538 
          539 /*
          540  * --footer=STRING
          541  *
          542  * Set the string that is used as the page footer.  As a default, the
          543  * page has no footer.  Setting this option does not necessary show
          544  * any footer strings in the output.  It depends on the selected
          545  * header (`.hdr' file) whether it supports footer strings or not.
          546  */
          547 char *page_footer = NULL;
          548 
          549 /*
          550  * --h-column-height=HEIGHT
          551  *
          552  * Set the horizontal column (channel) height to be HEIGHT.  This option
          553  * also sets the FormFeedType to `hcolumn'.  The default value is set to be
          554  * big enough to cause a jump to the next vertical column (100m).
          555  */
          556 double horizontal_column_height = 283465.0;
          557 
          558 /*
          559  * --help-highlight (deprecated --help-pretty-print)
          560  *
          561  * Descript all supported -E, --highlight languages and file formats.
          562  */
          563 int help_highlight = 0;
          564 
          565 /*
          566  * --highlight-bar-gray=val
          567  *
          568  * Specify the gray level for highlight bars.
          569  */
          570 double highlight_bar_gray = .97;
          571 
          572 /*
          573  * --list-media
          574  *
          575  * List all known media.  As a default do not list media names.
          576  */
          577 int list_media = 0;
          578 
          579 /*
          580  * --margins=LEFT:RIGHT:TOP:BOTTOM
          581  *
          582  * Adjust page marginals.
          583  */
          584 char *margins_spec = NULL;
          585 
          586 /*
          587  * --mark-wrapped-lines[=STYLE]
          588  *
          589  * Mark wrapped lines so that they can be easily detected from the printout.
          590  * Optional parameter STYLE specifies the marking style, the system default
          591  * is black box.
          592  */
          593 char *mark_wrapped_lines_style_name = NULL;
          594 MarkWrappedLinesStyle mark_wrapped_lines_style = MWLS_NONE;
          595 
          596 /*
          597  * --non-printable-format=FORMAT
          598  *
          599  * Format in which non-printable characters are printed.
          600  */
          601 char *npf_name = NULL;
          602 NonPrintableFormat non_printable_format = NPF_OCTAL;
          603 
          604 /*
          605  * --nup-columnwise
          606  *
          607  * Layout N-up pages colunwise instead of row-wise.
          608  */
          609 int nup_columnwise = 0;
          610 
          611 /*
          612  * --nup-xpad=NUM
          613  *
          614  * The x-padding between N-up subpages.
          615  */
          616 unsigned int nup_xpad = 10;
          617 
          618 /*
          619  * --nup-ypad=NUM
          620  *
          621  * The y-padding between N-up subpages.
          622  */
          623 unsigned int nup_ypad = 10;
          624 
          625 /*
          626  * --page-label-format=FORMAT
          627  *
          628  * Format in which page labels are printed; the default is "short".
          629  */
          630 char *page_label_format = NULL;
          631 PageLabelFormat page_label;
          632 
          633 /*
          634  * --ps-level=LEVEL
          635  *
          636  * The PostScript language level that enscript should use; the default is 2.
          637  */
          638 unsigned int pslevel = 2;
          639 
          640 /*
          641  * --printer-options=OPTIONS
          642  *
          643  * Pass extra options OPTIONS to the printer spooler.
          644  */
          645 char *printer_options = NULL;
          646 
          647 /*
          648  * --rotate-even-pages
          649  *
          650  * Rotate each even-numbered page 180 degrees.  This might be handy in
          651  * two-side printing when the resulting pages are bind from some side.
          652  * Greetings to Jussi-Pekka Sairanen.
          653  */
          654 int rotate_even_pages = 0;
          655 
          656 /*
          657  * --slice=NUM
          658  *
          659  * Horizontal input slicing.  Print only NUMth wrapped input pages.
          660  */
          661 int slicing = 0;
          662 unsigned int slice = 1;
          663 
          664 /*
          665  * --swap-even-page-margins
          666  *
          667  * Swap left and right side margins for each even numbered page.  This
          668  * might be handy in two-side printing.
          669  */
          670 int swap_even_page_margins = 0;
          671 
          672 /*
          673  * --toc
          674  *
          675  * Print Table of Contents page.
          676  */
          677 int toc = 0;
          678 FILE *toc_fp;
          679 char *toc_fmt_string;
          680 
          681 /*
          682  * --word-wrap
          683  *
          684  * Wrap long lines from word boundaries.  The default is character wrap.
          685  */
          686 
          687 /*
          688  * AcceptCompositeCharacters: bool
          689  *
          690  * Specify whatever we accept composite characters or should them be
          691  * considered as non-existent.  As a default, do not accept them.
          692  */
          693 int accept_composites = 0;
          694 
          695 /*
          696  * AppendCtrlD: bool
          697  *
          698  * Append ^D character to the end of the output.  Some printers require this
          699  * but the default is false.
          700  */
          701 int append_ctrl_D = 0;
          702 
          703 /*
          704  * Clean7Bit: bool
          705  *
          706  * Specify how characters greater than 127 are printed.
          707  */
          708 int clean_7bit = 1;
          709 
          710 /*
          711  * FormFeedType: type
          712  *
          713  * Specify what to do when a formfeed character is encountered from the
          714  * input stream.  The default action is to jump to the beginning of the
          715  * next column.
          716  */
          717 FormFeedType formfeed_type = FORMFEED_COLUMN;
          718 
          719 /*
          720  * GeneratePageSize: bool
          721  *
          722  * Specify whether the `PageSize' pagedevice definitions should be
          723  * generated to the output.
          724  */
          725 int generate_PageSize = 1;
          726 
          727 /*
          728  * NoJobHeaderSwitch: switch
          729  *
          730  * Spooler switch to suppress the job header (-h).
          731  */
          732 char *no_job_header_switch = NULL;
          733 
          734 /*
          735  * OutputFirstLine: line
          736  *
          737  * Set the PostScript output's first line to something your system can handle.
          738  * The default is "%!PS-Adobe-3.0"
          739  */
          740 char *output_first_line = NULL;
          741 
          742 /*
          743  * QueueParam: param
          744  *
          745  * The spooler command switch to select the printer queue (-P).
          746  */
          747 char *queue_param = NULL;
          748 
          749 /*
          750  * Spooler: command
          751  *
          752  * The spooler command name (lpr).
          753  */
          754 char *spooler_command = NULL;
          755 
          756 /*
          757  * StatesBinary: path
          758  *
          759  * An absolute path to the `states' binary.
          760  */
          761 
          762 char *states_binary = NULL;
          763 
          764 /*
          765  * StatesColor: bool
          766  *
          767  * Should the States program generate color outputs.
          768  */
          769 int states_color = 0;
          770 
          771 /*
          772  * StatesConfigFile: file
          773  *
          774  * The name of the states' configuration file.
          775  */
          776 char *states_config_file = NULL;
          777 
          778 /*
          779  * StatesHighlightStyle: style
          780  *
          781  * The highlight style.
          782  */
          783 char *states_highlight_style = NULL;
          784 
          785 /*
          786  * StatesPath: path
          787  *
          788  * Define the path for the states program.  The states program will
          789  * lookup its state definition files from this path.
          790  */
          791 char *states_path = NULL;
          792 
          793 /* ^@shade{GRAY}, set the line highlight gray. */
          794 double line_highlight_gray = 1.0;
          795 
          796 /* ^@bggray{GRAY}, set the text background gray. */
          797 double bggray = 1.0;
          798 
          799 EncodingRegistry encodings[] =
          800 {
          801   {{"88591", "latin1", NULL},                ENC_ISO_8859_1,                '\n', 8},
          802   {{"88592", "latin2", NULL},                ENC_ISO_8859_2,                '\n', 8},
          803   {{"88593", "latin3", NULL},                ENC_ISO_8859_3,                '\n', 8},
          804   {{"88594", "latin4", NULL},                ENC_ISO_8859_4,                '\n', 8},
          805   {{"88595", "cyrillic", NULL},                ENC_ISO_8859_5,                '\n', 8},
          806   {{"88597", "greek", NULL},                ENC_ISO_8859_7,                '\n', 8},
          807   {{"88599", "latin5", NULL},                ENC_ISO_8859_9,                '\n', 8},
          808   {{"885910", "latin6", NULL},                ENC_ISO_8859_10,        '\n', 8},
          809   {{"885915", "latin9", NULL},                ENC_ISO_8859_15,        '\n', 8},
          810   {{"ascii", NULL, NULL},                ENC_ASCII,                 '\n', 8},
          811   {{"asciifise", "asciifi", "asciise"},        ENC_ASCII_FISE,                '\n', 8},
          812   {{"asciidkno", "asciidk", "asciino"},        ENC_ASCII_DKNO,                '\n', 8},
          813   {{"ibmpc", "pc", "dos"},                ENC_IBMPC,                 '\n', 8},
          814   {{"mac", NULL, NULL},                        ENC_MAC,                 '\r', 8},
          815   {{"vms", NULL, NULL},                        ENC_VMS,                 '\n', 8},
          816   {{"hp8", NULL, NULL},                        ENC_HP8,                '\n', 8},
          817   {{"koi8", NULL, NULL},                ENC_KOI8,                '\n', 8},
          818   {{"ps", "PS", NULL},                        ENC_PS,                 '\n', 8},
          819   {{"pslatin1", "ISOLatin1Encoding", NULL},        ENC_ISO_8859_1,        '\n', 8},
          820 
          821   {{NULL, NULL, NULL}, 0, 0, 0},
          822 };
          823 
          824 
          825 /*
          826  * Static variables.
          827  */
          828 
          829 static struct option long_options[] =
          830 {
          831   {"columns",                        required_argument,        0, 0},
          832   {"pages",                        required_argument,        0, 'a'},
          833   {"file-align",                required_argument,        0, 'A'},
          834   {"header",                        required_argument,        0, 'b'},
          835   {"no-header",                        no_argument,                0, 'B'},
          836   {"truncate-lines",                no_argument,                0, 'c'},
          837   {"line-numbers",                optional_argument,        0, 'C'},
          838   {"printer",                        required_argument,        0, 'd'},
          839   {"setpagedevice",                required_argument,        0, 'D'},
          840   {"escapes",                        optional_argument,        0, 'e'},
          841   {"highlight",                        optional_argument,        0, 'E'},
          842   {"font",                        required_argument,        0, 'f'},
          843   {"header-font",                required_argument,        0, 'F'},
          844   {"print-anyway",                no_argument,                0, 'g'},
          845   {"fancy-header",                optional_argument,        0, 'G'},
          846   {"no-job-header",                no_argument,                 0, 'h'},
          847   {"highlight-bars",                optional_argument,        0, 'H'},
          848   {"indent",                        required_argument,        0, 'i'},
          849   {"filter",                        required_argument,        0, 'I'},
          850   {"borders",                        no_argument,                0, 'j'},
          851   {"page-prefeed",                no_argument,                0, 'k'},
          852   {"no-page-prefeed",                no_argument,                0, 'K'},
          853   {"lineprinter",                no_argument,                0, 'l'},
          854   {"lines-per-page",                required_argument,        0, 'L'},
          855   {"mail",                        optional_argument,        0, 'm'},
          856   {"media",                        required_argument,        0, 'M'},
          857   {"copies",                        required_argument,        0, 'n'},
          858   {"newline",                        required_argument,        0, 'N'},
          859   {"output",                        required_argument,        0, 'p'},
          860   {"missing-characters",        no_argument,                0, 'O'},
          861   {"quiet",                        no_argument,                0, 'q'},
          862   {"silent",                        no_argument,                0, 'q'},
          863   {"landscape",                        no_argument,                0, 'r'},
          864   {"portrait",                        no_argument,                0, 'R'},
          865   {"baselineskip",                required_argument,        0, 's'},
          866   {"statusdict",                required_argument,        0, 'S'},
          867   {"title",                        required_argument,        0, 't'},
          868   {"tabsize",                        required_argument,        0, 'T'},
          869   {"underlay",                        optional_argument,        0, 'u'},
          870   {"nup",                        required_argument,        0, 'U'},
          871   {"verbose",                        optional_argument,        0, 'v'},
          872   {"version",                        no_argument,                0, 'V'},
          873   {"language",                        required_argument,        0, 'w'},
          874   {"option",                        required_argument,        0, 'W'},
          875   {"encoding",                        required_argument,        0, 'X'},
          876   {"no-formfeed",                no_argument,                0, 'z'},
          877   {"pass-through",                no_argument,                0, 'Z'},
          878 
          879   /* Long options without short counterparts.  Next free is 157. */
          880   {"color",                        optional_argument,        0, 142},
          881   {"continuous-page-numbers",        no_argument,                0, 156},
          882   {"download-font",                required_argument,        0, 131},
          883   {"extended-return-values",        no_argument,                0, 154},
          884   {"filter-stdin",                required_argument,        0, 138},
          885   {"footer",                        required_argument,        0, 155},
          886   {"h-column-height",                 required_argument,        0, 148},
          887   {"help",                         no_argument,                 0, 135},
          888   {"help-highlight",                 no_argument,                 0, 141},
          889   {"highlight-bar-gray",        required_argument,         0, 136},
          890   {"list-media",                no_argument,                &list_media, 1},
          891   {"margins",                        required_argument,        0, 144},
          892   {"mark-wrapped-lines",        optional_argument,        0, 143},
          893   {"non-printable-format",        required_argument,        0, 134},
          894   {"nup-columnwise",                no_argument,                0, 152},
          895   {"nup-xpad",                        required_argument,        0, 145},
          896   {"nup-ypad",                        required_argument,        0, 146},
          897   {"page-label-format",                required_argument,        0, 130},
          898   {"ps-level",                        required_argument,        0, 149},
          899   {"printer-options",                required_argument,        0, 139},
          900   {"rotate-even-pages",                no_argument,                0, 150},
          901   {"slice",                        required_argument,        0, 140},
          902   {"style",                        required_argument,        0, 151},
          903   {"swap-even-page-margins",        no_argument,                0, 153},
          904   {"toc",                        no_argument,                &toc, 1},
          905   {"word-wrap",                        no_argument,                0, 147},
          906   {"ul-angle",                        required_argument,        0, 132},
          907   {"ul-font",                        required_argument,        0, 128},
          908   {"ul-gray",                        required_argument,        0, 129},
          909   {"ul-position",                required_argument,        0, 133},
          910   {"ul-style",                        required_argument,        0, 137},
          911 
          912   /* Backwards compatiblity options. */
          913   {"pretty-print",                optional_argument,        0, 'E'},
          914   {"help-pretty-print",         no_argument,                 0, 141},
          915 
          916   {NULL, 0, 0, 0},
          917 };
          918 
          919 
          920 /*
          921  * Global functions.
          922  */
          923 
          924 int
          925 main (int argc, char *argv[])
          926 {
          927   InputStream is;
          928   time_t tim;
          929   struct tm *tm;
          930   int i, j, found;
          931   unsigned int ui;
          932   MediaEntry *mentry;
          933   AFMError afm_error;
          934   char *cp, *cp2;
          935   int retval = 0;
          936   Buffer buffer;
          937 
          938   /* Init our dynamic memory buffer. */
          939   buffer_init (&buffer);
          940 
          941   /* Get program's name. */
          942   program = strrchr (argv[0], '/');
          943   if (program == NULL)
          944     program = argv[0];
          945   else
          946     program++;
          947 
          948   /* Make getopt_long() to use our modified programname. */
          949   argv[0] = program;
          950 
          951   /* Create the default TOC format string.  Wow, this is cool! */
          952   /* xgettext:no-c-format */
          953   toc_fmt_string = _("$3v $-40N $3% pages $4L lines  $E $C");
          954 
          955   /* Internationalization. */
          956 #if HAVE_SETLOCALE
          957   /*
          958    * We want to change only messages (gs do not like decimals in 0,1
          959    * format ;)
          960    */
          961 #if HAVE_LC_MESSAGES
          962   setlocale (LC_MESSAGES, "");
          963 #endif
          964   setlocale (LC_CTYPE, "");
          965 #ifdef LC_PAPER
          966   setlocale (LC_PAPER, "");
          967 #endif
          968 #endif
          969 #if ENABLE_NLS
          970   bindtextdomain (PACKAGE, LOCALEDIR);
          971   textdomain (PACKAGE);
          972 #endif
          973 
          974   /* Create date string. */
          975 
          976   tim = time (NULL);
          977   tm = localtime (&tim);
          978   memcpy (&run_tm, tm, sizeof (*tm));
          979 
          980   date_string = xstrdup (asctime (&run_tm));
          981   i = strlen (date_string);
          982   date_string[i - 1] = '\0';
          983 
          984   /* Get user's passwd entry. */
          985   passwd = getpwuid (getuid ());
          986   if (passwd == NULL)
          987     FATAL ((stderr, _("couldn't get passwd entry for uid=%d: %s"), getuid (),
          988             strerror (errno)));
          989 
          990   /* Defaults for some options. */
          991   media_name                 = xstrdup ("A4");
          992   encoding_name                = xstrdup ("88591");
          993   npf_name                = xstrdup ("octal");
          994   page_label_format        = xstrdup ("short");
          995   ul_style_str                = xstrdup ("outline");
          996   ul_position                = xstrdup ("+0-0");
          997   spooler_command         = xstrdup ("lpr");
          998   queue_param                 = xstrdup ("-P");
          999   no_job_header_switch         = xstrdup ("-h");
         1000   fancy_header_default         = xstrdup ("enscript");
         1001   output_first_line         = xstrdup ("%!PS-Adobe-3.0");
         1002 
         1003   /* Check ENSCRIPT_LIBRARY for custom library location. */
         1004   cp = getenv ("ENSCRIPT_LIBRARY");
         1005   if (cp)
         1006     enscript_library = cp;
         1007 
         1008   /* Fill up build-in libpath. */
         1009 
         1010   cp = getenv ("HOME");
         1011   if (cp == NULL)
         1012     cp = passwd->pw_dir;
         1013 
         1014   buffer_clear (&buffer);
         1015   buffer_append (&buffer, enscript_library);
         1016   buffer_append (&buffer, PATH_SEPARATOR_STR);
         1017   buffer_append (&buffer, cp);
         1018   buffer_append (&buffer, "/.enscript");
         1019   libpath = buffer_copy (&buffer);
         1020 
         1021   /* Defaults for the states filter. */
         1022 
         1023   states_binary = xstrdup ("states"); /* Take it from the user path. */
         1024 
         1025   buffer_clear (&buffer);
         1026   buffer_append (&buffer, enscript_library);
         1027   buffer_append (&buffer, "/hl/enscript.st");
         1028   states_config_file = buffer_copy (&buffer);
         1029 
         1030   states_highlight_style = xstrdup ("emacs");
         1031 
         1032   /* The <cp> holds the user's home directory. */
         1033   buffer_clear (&buffer);
         1034   buffer_append (&buffer, cp);
         1035   buffer_append (&buffer, "/.enscript");
         1036   buffer_append (&buffer, PATH_SEPARATOR_STR);
         1037   buffer_append (&buffer, enscript_library);
         1038   buffer_append (&buffer, "/hl");
         1039   states_path = buffer_copy (&buffer);
         1040 
         1041   /* Initialize resource sets. */
         1042   res_fonts = strhash_init ();
         1043   download_fonts = strhash_init ();
         1044   pagedevice = strhash_init ();
         1045   statusdict = strhash_init ();
         1046   user_strings = strhash_init ();
         1047 
         1048 
         1049   /*
         1050    * Read configuration files.
         1051    */
         1052 
         1053   /* Global config. */
         1054 #define CFG_FILE_NAME "enscript.cfg"
         1055   if (!read_config (SYSCONFDIR, CFG_FILE_NAME))
         1056     {
         1057       int saved_errno = errno;
         1058 
         1059       /* Try to read it from our library directory.  This is mostly
         1060          the case for the micro ports.  */
         1061       if (!read_config (enscript_library, CFG_FILE_NAME))
         1062         {
         1063           /* Try `enscript_library/../../etc/'.  This is the case for
         1064              installations which set the prefix after the compilation
         1065              and our SYSCONFDIR points to wrong directory. */
         1066 
         1067           buffer_clear (&buffer);
         1068           buffer_append (&buffer, enscript_library);
         1069           buffer_append (&buffer, "/../../etc");
         1070 
         1071           if (!read_config (buffer_ptr (&buffer), CFG_FILE_NAME))
         1072             {
         1073               /* Maybe we are not installed yet, let's try `../lib'
         1074                  and `../../lib'. */
         1075               if (!read_config ("../lib", CFG_FILE_NAME)
         1076                   && !read_config ("../../lib", CFG_FILE_NAME))
         1077                 {
         1078                   /* No luck, report error from the original config file. */
         1079                   ERROR ((stderr, _("couldn't read config file \"%s/%s\": %s"),
         1080                           enscript_library, CFG_FILE_NAME,
         1081                           strerror (saved_errno)));
         1082                   ERROR ((stderr,
         1083                           _("I did also try the following directories:")));
         1084                   ERROR ((stderr, _("\t%s"), SYSCONFDIR));
         1085                   ERROR ((stderr, _("\t%s"), enscript_library));
         1086                   ERROR ((stderr, _("\t%s"), buffer_ptr (&buffer)));
         1087                   ERROR ((stderr, _("\t../lib")));
         1088                   ERROR ((stderr, _("\t../../lib")));
         1089                   ERROR ((stderr,
         1090 _("This is probably an installation error.  Please, try to rebuild:")));
         1091                   ERROR ((stderr, _("\tmake distclean")));
         1092                   ERROR ((stderr, _("\t./configure --prefix=PREFIX")));
         1093                   ERROR ((stderr, _("\tmake")));
         1094                   ERROR ((stderr, _("\tmake check")));
         1095                   ERROR ((stderr, _("\tmake install")));
         1096                   ERROR ((stderr, _("or set the environment variable `ENSCRIPT_LIBRARY'"
         1097                         " to point to your library directory.")));
         1098                   exit (1);
         1099                 }
         1100 
         1101               /* Ok, we are not installed yet.  Here is a small kludge
         1102                  to conform the GNU coding standards: we must be able
         1103                  to run without being installed, so we must append the
         1104                  `../lib' and `../../lib' directories to the libpath.
         1105                  The later allows us to be run form the `src/tests'
         1106                  directory.  */
         1107               buffer_clear (&buffer);
         1108               buffer_append (&buffer, libpath);
         1109               buffer_append (&buffer, PATH_SEPARATOR_STR);
         1110               buffer_append (&buffer, "../lib");
         1111               buffer_append (&buffer, PATH_SEPARATOR_STR);
         1112               buffer_append (&buffer, "../../lib");
         1113 
         1114               xfree (libpath);
         1115               libpath = buffer_copy (&buffer);
         1116             }
         1117         }
         1118     }
         1119 
         1120   /* Site config. */
         1121   read_config (SYSCONFDIR, "enscriptsite.cfg");
         1122 
         1123   /* Personal config. */
         1124   read_config (cp, ".enscriptrc");
         1125 
         1126   /*
         1127    * Options.
         1128    */
         1129 
         1130   /* Environment variables. */
         1131   handle_env_options ("ENSCRIPT");
         1132   handle_env_options ("GENSCRIPT");
         1133 
         1134   /* Command line arguments. */
         1135   handle_options (argc, argv);
         1136 
         1137   /*
         1138    * Check options which have some validity conditions.
         1139    */
         1140 
         1141   /*
         1142    * Save the user-specified escape char so ^@escape{default} knows
         1143    * what to set.
         1144    */
         1145   default_escape_char = escape_char;
         1146 
         1147   /* Input encoding. */
         1148 
         1149   found = 0;
         1150   for (i = 0; !found && encodings[i].names[0]; i++)
         1151     for (j = 0; j < 3; j++)
         1152       if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j],
         1153                                                   encoding_name))
         1154         {
         1155           /* Found a match for this encoding.  Use the first
         1156              "official" name. */
         1157 
         1158           encoding = encodings[i].encoding;
         1159           xfree (encoding_name);
         1160           encoding_name = xstrdup (encodings[i].names[0]);
         1161 
         1162           if (nl < 0)
         1163             nl = encodings[i].nl;
         1164           bs = encodings[i].bs;
         1165           found = 1;
         1166           break;
         1167         }
         1168   if (!found)
         1169     FATAL ((stderr, _("unknown encoding: %s"), encoding_name));
         1170 
         1171   /* Fonts. */
         1172 
         1173   /* Default font for landscape, 2 column printing is Courier 7. */
         1174   if (!user_body_font_defined && landscape && num_columns > 1)
         1175     Fpt.w = Fpt.h = 7.0;
         1176 
         1177   /* Cache for font AFM information. */
         1178   afm_cache = strhash_init ();
         1179   afm_info_cache = strhash_init ();
         1180 
         1181   /* Open AFM library. */
         1182   afm_error = afm_create (afm_path, verbose, &afm);
         1183   if (afm_error != AFM_SUCCESS)
         1184     {
         1185       char buf[256];
         1186 
         1187       afm_error_to_string (afm_error, buf);
         1188       FATAL ((stderr, _("couldn't open AFM library: %s"), buf));
         1189     }
         1190 
         1191   /*
         1192    * Save default Fpt and Fname since special escape 'font' can change
         1193    * it and later we might want to switch back to the "default" font.
         1194    */
         1195   default_Fpt.w = Fpt.w;
         1196   default_Fpt.h = Fpt.h;
         1197   default_Fname = Fname;
         1198   default_Fencoding = encoding;
         1199 
         1200   /* Register that document uses at least these fonts. */
         1201   strhash_put (res_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
         1202   strhash_put (res_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
         1203 
         1204   /* As a default, download both named fonts. */
         1205   strhash_put (download_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
         1206   strhash_put (download_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
         1207 
         1208   /* Read font's character widths and character types. */
         1209   read_font_info ();
         1210 
         1211   /* Count the line indentation. */
         1212   line_indent = parse_float (line_indent_spec, 1, 1);
         1213 
         1214   /* List media names. */
         1215   if (list_media)
         1216     {
         1217       printf (_("known media:\n\
         1218 name             width\theight\tllx\tlly\turx\tury\n\
         1219 ------------------------------------------------------------\n"));
         1220       for (mentry = media_names; mentry; mentry = mentry->next)
         1221         printf ("%-16s %d\t%d\t%d\t%d\t%d\t%d\n",
         1222                 mentry->name, mentry->w, mentry->h,
         1223                 mentry->llx, mentry->lly, mentry->urx, mentry->ury);
         1224       /* Exit after listing. */
         1225       exit (0);
         1226     }
         1227 
         1228   /* Output media. */
         1229   for (mentry = media_names; mentry; mentry = mentry->next)
         1230     if (strcmp (media_name, mentry->name) == 0)
         1231       {
         1232         media = mentry;
         1233         break;
         1234       }
         1235   if (media == NULL)
         1236     FATAL ((stderr, _("do not know anything about media \"%s\""), media_name));
         1237 
         1238   if (margins_spec)
         1239     {
         1240       /* Adjust marginals. */
         1241       for (i = 0; i < 4; i++)
         1242         {
         1243           if (*margins_spec == '\0')
         1244             /* All done. */
         1245             break;
         1246 
         1247           if (*margins_spec == ':')
         1248             {
         1249               margins_spec++;
         1250               continue;
         1251             }
         1252 
         1253           j = atoi (margins_spec);
         1254           for (; *margins_spec != ':' && *margins_spec != '\0'; margins_spec++)
         1255             ;
         1256           if (*margins_spec == ':')
         1257             margins_spec++;
         1258 
         1259           switch (i)
         1260             {
         1261             case 0:                /* left */
         1262               media->llx = j;
         1263               break;
         1264 
         1265             case 1:                /* right */
         1266               media->urx = media->w - j;
         1267               break;
         1268 
         1269             case 2:                /* top */
         1270               media->ury = media->h - j;
         1271               break;
         1272 
         1273             case 3:                /* bottom */
         1274               media->lly = j;
         1275               break;
         1276             }
         1277         }
         1278       MESSAGE (1,
         1279                (stderr,
         1280                 _("set new marginals for media `%s' (%dx%d): llx=%d, lly=%d, urx=%d, ury=%d\n"),
         1281                 media->name, media->w, media->h, media->llx, media->lly,
         1282                 media->urx, media->ury));
         1283     }
         1284 
         1285   /* Page label format. */
         1286   if (MATCH (page_label_format, "short"))
         1287     page_label = LABEL_SHORT;
         1288   else if (MATCH (page_label_format, "long"))
         1289     page_label = LABEL_LONG;
         1290   else
         1291     FATAL ((stderr, _("illegal page label format \"%s\""), page_label_format));
         1292 
         1293   /* Non-printable format. */
         1294   if (MATCH (npf_name, "space"))
         1295     non_printable_format = NPF_SPACE;
         1296   else if (MATCH (npf_name, "questionmark"))
         1297     non_printable_format = NPF_QUESTIONMARK;
         1298   else if (MATCH (npf_name, "caret"))
         1299     non_printable_format = NPF_CARET;
         1300   else if (MATCH (npf_name, "octal"))
         1301     non_printable_format = NPF_OCTAL;
         1302   else
         1303     FATAL ((stderr, _("illegal non-printable format \"%s\""), npf_name));
         1304 
         1305   /* Mark wrapped lines style. */
         1306   if (mark_wrapped_lines_style_name)
         1307     {
         1308       if (MATCH (mark_wrapped_lines_style_name, "none"))
         1309         mark_wrapped_lines_style = MWLS_NONE;
         1310       else if (MATCH (mark_wrapped_lines_style_name, "plus"))
         1311         mark_wrapped_lines_style = MWLS_PLUS;
         1312       else if (MATCH (mark_wrapped_lines_style_name, "box"))
         1313         mark_wrapped_lines_style = MWLS_BOX;
         1314       else if (MATCH (mark_wrapped_lines_style_name, "arrow"))
         1315         mark_wrapped_lines_style = MWLS_ARROW;
         1316       else
         1317         FATAL ((stderr, _("illegal style for wrapped line marker: \"%s\""),
         1318                 mark_wrapped_lines_style_name));
         1319     }
         1320 
         1321   /* Count N-up stuffs. */
         1322   for (i = 0; ; i++)
         1323     {
         1324       ui = nup >> i;
         1325 
         1326       if (ui == 0)
         1327         FATAL ((stderr, _("illegal N-up argument: %d"), nup));
         1328 
         1329       if (ui & 0x1)
         1330         {
         1331           if (ui != 1)
         1332             FATAL ((stderr, _("N-up argument must be power of 2: %d"), nup));
         1333 
         1334           nup_exp = i;
         1335           break;
         1336         }
         1337     }
         1338 
         1339   nup_rows = nup_exp / 2 * 2;
         1340   if (nup_rows == 0)
         1341     nup_rows = 1;
         1342   nup_columns = (nup_exp + 1) / 2 * 2;
         1343   if (nup_columns == 0)
         1344     nup_columns = 1;
         1345 
         1346   nup_landscape = nup_exp & 0x1;
         1347 
         1348 
         1349   /*
         1350    * Count output media dimensions.
         1351    */
         1352 
         1353   if (landscape)
         1354     {
         1355       d_page_w = media->ury - media->lly;
         1356       d_page_h = media->urx - media->llx;
         1357     }
         1358   else
         1359     {
         1360       d_page_w = media->urx - media->llx;
         1361       d_page_h = media->ury - media->lly;
         1362     }
         1363 
         1364   /*
         1365    * Count N-up page width, height and scale.
         1366    */
         1367 
         1368   if (nup_landscape)
         1369     {
         1370       nup_width = media->ury - media->lly;
         1371       nup_height = media->urx - media->llx;
         1372     }
         1373   else
         1374     {
         1375       nup_width = media->urx - media->llx;
         1376       nup_height = media->ury - media->lly;
         1377     }
         1378 
         1379   {
         1380     double w, h;
         1381 
         1382     w = ((double) nup_width - (nup_columns - 1) * nup_xpad) / nup_columns;
         1383     h = ((double) nup_height - (nup_rows - 1) * nup_ypad) / nup_rows;
         1384 
         1385     nup_width = w;
         1386     nup_height = h;
         1387 
         1388     w = w / (media->urx - media->llx);
         1389     h = h / (media->ury - media->lly);
         1390 
         1391     nup_scale = w < h ? w : h;
         1392   }
         1393 
         1394   /*
         1395    * Underlay (this must come after output media dimensions, because
         1396    * `underlay position' needs them).
         1397    */
         1398   if (underlay != NULL)
         1399     {
         1400       strhash_put (res_fonts, ul_font, strlen (ul_font) + 1, NULL, NULL);
         1401       underlay = escape_string (underlay);
         1402     }
         1403 
         1404   /* Underlay X-coordinate. */
         1405   ul_x = strtod (ul_position, &cp);
         1406   if (cp == ul_position)
         1407     {
         1408     malformed_position:
         1409       FATAL ((stderr, _("malformed underlay position: %s"), ul_position));
         1410     }
         1411   if (ul_position[0] == '-')
         1412     ul_x += d_page_w;
         1413 
         1414   /* Underlay Y-coordinate. */
         1415   ul_y = strtod (cp, &cp2);
         1416   if (cp2 == cp)
         1417     goto malformed_position;
         1418   if (cp[0] == '-')
         1419     ul_y += d_page_h;
         1420 
         1421   /* Underlay Angle. */
         1422   if (!ul_angle_p)
         1423     /* No angle given, count the default. */
         1424     ul_angle = (atan2 (-d_page_h, d_page_w) / 3.14159265 * 180);
         1425 
         1426   /* Underlay style. */
         1427   if (strcmp (ul_style_str, "outline") == 0)
         1428     ul_style = UL_STYLE_OUTLINE;
         1429   else if (strcmp (ul_style_str, "filled") == 0)
         1430     ul_style = UL_STYLE_FILLED;
         1431   else
         1432     FATAL ((stderr, _("illegal underlay style: %s"), ul_style_str));
         1433 
         1434   /*
         1435    * Header.  Note! The header attributes can be changed from
         1436    * the `.hdr' files, these are only the defaults.
         1437    */
         1438 
         1439   d_header_w = d_page_w;
         1440   switch (header)
         1441     {
         1442     case HDR_NONE:
         1443       d_header_h = 0;
         1444       break;
         1445 
         1446     case HDR_SIMPLE:
         1447       d_header_h = HFpt.h * 1.5;
         1448       break;
         1449 
         1450     case HDR_FANCY:
         1451       d_header_h = 36;
         1452       break;
         1453     }
         1454 
         1455   /* Help highlight. */
         1456   if (help_highlight)
         1457     {
         1458       /* Create description with states. */
         1459       printf (_("Highlighting is supported for the following languages and file formats:\n\n"));
         1460       fflush (stdout);
         1461 
         1462       buffer_clear (&buffer);
         1463       buffer_append (&buffer, states_binary);
         1464       buffer_append (&buffer, " -f \"");
         1465       buffer_append (&buffer, states_config_file);
         1466       buffer_append (&buffer, "\" -p \"");
         1467       buffer_append (&buffer, states_path);
         1468       buffer_append (&buffer, "\" -s describe_languages ");
         1469       buffer_append (&buffer, enscript_library);
         1470       buffer_append (&buffer, "/hl/*.st");
         1471 
         1472       if (system (buffer_ptr (&buffer)) < 0)
         1473         perror("system");
         1474       exit (0);
         1475     }
         1476 
         1477   /*
         1478    * And now to the main business.  The actual input file processing
         1479    * is divided to two parts: PostScript generation and everything else.
         1480    * The PostScript generation is handled in the conventional way, we
         1481    * process the input and generate PostScript.  However all other input
         1482    * languages will be handled with States, we only pass enscript's
         1483    * options to the states pre-filter and dump output.
         1484    */
         1485   if (output_language_pass_through)
         1486     {
         1487       char *start_state;
         1488       Buffer cmd;
         1489       char intbuf[256];
         1490 
         1491       /* The States output generation. */
         1492 
         1493       /* Resolve the start state. */
         1494       if (hl_start_state)
         1495         start_state = hl_start_state;
         1496       else if (highlight)
         1497         start_state = NULL;
         1498       else
         1499         start_state = "passthrough";
         1500 
         1501       /* Create the states command. */
         1502 
         1503       buffer_init (&cmd);
         1504 
         1505       buffer_append (&cmd, states_binary);
         1506       buffer_append (&cmd, " -f \"");
         1507       buffer_append (&cmd, states_config_file);
         1508       buffer_append (&cmd, "\" -p \"");
         1509       buffer_append (&cmd, states_path);
         1510       buffer_append (&cmd, "\" ");
         1511 
         1512       if (verbose > 0)
         1513         buffer_append (&cmd, "-v ");
         1514 
         1515       if (start_state)
         1516         {
         1517           buffer_append (&cmd, "-s");
         1518           buffer_append (&cmd, start_state);
         1519           buffer_append (&cmd, " ");
         1520         }
         1521 
         1522       buffer_append (&cmd, "-Dcolor=");
         1523       buffer_append (&cmd, states_color ? "1" : "0");
         1524       buffer_append (&cmd, " ");
         1525 
         1526       buffer_append (&cmd, "-Dstyle=");
         1527       buffer_append (&cmd, states_highlight_style);
         1528       buffer_append (&cmd, " ");
         1529 
         1530       buffer_append (&cmd, "-Dlanguage=");
         1531       buffer_append (&cmd, output_language);
         1532       buffer_append (&cmd, " ");
         1533 
         1534       buffer_append (&cmd, "-Dnum_input_files=");
         1535       sprintf (intbuf, "%d", optind == argc ? 1 : argc - optind);
         1536       buffer_append (&cmd, intbuf);
         1537       buffer_append (&cmd, " ");
         1538 
         1539       buffer_append (&cmd, "-Ddocument_title=\'");
         1540       if ((cp = shell_escape (title)) != NULL)
         1541         {
         1542           buffer_append (&cmd, cp);
         1543           free (cp);
         1544         }
         1545       buffer_append (&cmd, "\' ");
         1546 
         1547       buffer_append (&cmd, "-Dtoc=");
         1548       buffer_append (&cmd, toc ? "1" : "0");
         1549 
         1550       /* Additional options for states? */
         1551       if (helper_options['s'])
         1552         {
         1553           Buffer *opts = helper_options['s'];
         1554 
         1555           buffer_append (&cmd, " ");
         1556           buffer_append_len (&cmd, buffer_ptr (opts), buffer_len (opts));
         1557         }
         1558 
         1559       /* Append input files. */
         1560       for (i = optind; i < argc; i++)
         1561         {
         1562           char *cp;
         1563           if ((cp = shell_escape (argv[i])) != NULL)
         1564             {
         1565               buffer_append (&cmd, " \'");
         1566               buffer_append (&cmd, cp);
         1567               buffer_append (&cmd, "\'");
         1568               free (cp);
         1569             }
         1570         }
         1571 
         1572       /* And do the job. */
         1573       if (is_open (&is, stdin, NULL, buffer_ptr (&cmd)))
         1574         {
         1575           open_output_file ();
         1576           process_file ("unused", &is, 0);
         1577           is_close (&is);
         1578         }
         1579 
         1580       buffer_uninit (&cmd);
         1581     }
         1582   else
         1583     {
         1584       /* The conventional way. */
         1585 
         1586       /* Highlighting. */
         1587       if (highlight)
         1588         {
         1589           char fbuf[256];
         1590 
         1591           /* Create a highlight input filter. */
         1592           buffer_clear (&buffer);
         1593           buffer_append (&buffer, states_binary);
         1594           buffer_append (&buffer, " -f \"");
         1595           buffer_append (&buffer, states_config_file);
         1596           buffer_append (&buffer, "\" -p \"");
         1597           buffer_append (&buffer, states_path);
         1598           buffer_append (&buffer, "\"");
         1599 
         1600           if (verbose > 0)
         1601             buffer_append (&buffer, " -v");
         1602 
         1603           if (hl_start_state)
         1604             {
         1605               buffer_append (&buffer, " -s ");
         1606               buffer_append (&buffer, hl_start_state);
         1607             }
         1608 
         1609           buffer_append (&buffer, " -Dcolor=");
         1610           buffer_append (&buffer, states_color ? "1" : "0");
         1611 
         1612           buffer_append (&buffer, " -Dstyle=");
         1613           buffer_append (&buffer, states_highlight_style);
         1614 
         1615           buffer_append (&buffer, " -Dfont_spec=");
         1616           buffer_append (&buffer, Fname);
         1617           sprintf (fbuf, "@%g/%g", Fpt.w, Fpt.h);
         1618           buffer_append (&buffer, fbuf);
         1619 
         1620           /* Additional options for states? */
         1621           if (helper_options['s'])
         1622             {
         1623               Buffer *opts = helper_options['s'];
         1624 
         1625               buffer_append (&buffer, " ");
         1626               buffer_append_len (&buffer,
         1627                                  buffer_ptr (opts), buffer_len (opts));
         1628             }
         1629 
         1630           buffer_append (&buffer, " \'%s\'");
         1631 
         1632           input_filter = buffer_copy (&buffer);
         1633           input_filter_stdin = "-";
         1634         }
         1635 
         1636       /* Table of Contents. */
         1637       if (toc)
         1638         {
         1639           toc_fp = tmpfile ();
         1640           if (toc_fp == NULL)
         1641             FATAL ((stderr, _("couldn't create temporary toc file: %s"),
         1642                     strerror (errno)));
         1643         }
         1644 
         1645 
         1646       /*
         1647        * Process files.
         1648        */
         1649 
         1650       if (optind == argc)
         1651         {
         1652           /* stdin's modification time is the current time. */
         1653           memcpy (&mod_tm, &run_tm, sizeof (run_tm));
         1654 
         1655           if (is_open (&is, stdin, NULL, input_filter))
         1656             {
         1657               /* Open output file. */
         1658               open_output_file ();
         1659               process_file (title_given ? title : "", &is, 0);
         1660               is_close (&is);
         1661             }
         1662         }
         1663       else
         1664         {
         1665           for (; optind < argc; optind++)
         1666             {
         1667               if (is_open (&is, NULL, argv[optind], input_filter))
         1668                 {
         1669                   struct stat stat_st;
         1670 
         1671                   /* Get modification time. */
         1672                   if (stat (argv[optind], &stat_st) == 0)
         1673                     {
         1674                       tim = stat_st.st_mtime;
         1675                       tm = localtime (&tim);
         1676                       memcpy (&mod_tm, tm, sizeof (*tm));
         1677 
         1678                       /*
         1679                        * Open output file.  Output file opening is delayed to
         1680                        * this point so we can optimize the case when a
         1681                        * non-existing input file is printed => we do nothing.
         1682                        */
         1683                       open_output_file ();
         1684 
         1685                       process_file (argv[optind], &is, 0);
         1686                     }
         1687                   else
         1688                     ERROR ((stderr, _("couldn't stat input file \"%s\": %s"),
         1689                             argv[optind],
         1690                             strerror (errno)));
         1691 
         1692                   is_close (&is);
         1693                 }
         1694             }
         1695         }
         1696 
         1697       /* Table of Contents. */
         1698       if (toc)
         1699         {
         1700           /* This is really cool... */
         1701 
         1702           /* Set the printing options for toc. */
         1703           toc = 0;
         1704           special_escapes = 1;
         1705           line_numbers = 0;
         1706 
         1707           if (fseek (toc_fp, 0, SEEK_SET) != 0)
         1708             FATAL ((stderr, _("couldn't rewind toc file: %s"),
         1709                     strerror (errno)));
         1710 
         1711           memcpy (&mod_tm, &run_tm, sizeof (run_tm));
         1712           if (is_open (&is, toc_fp, NULL, NULL))
         1713             {
         1714               process_file (_("Table of Contents"), &is, 1);
         1715               is_close (&is);
         1716             }
         1717         }
         1718 
         1719       /* Give trailer a chance to dump itself. */
         1720       dump_ps_trailer ();
         1721 
         1722       /*
         1723        * Append ^D to the end of the output?  Note! It must be ^D followed
         1724        * by a newline.
         1725        */
         1726       if (ofp != NULL && append_ctrl_D)
         1727         fprintf (ofp, "\004\n");
         1728     }
         1729 
         1730   /* Close output file. */
         1731   close_output_file ();
         1732 
         1733   /* Tell how things went. */
         1734   if (ofp == NULL)
         1735     {
         1736       /*
         1737        * The value of <ofp> is not reset in close_output_file(),
         1738        * this is ugly but it saves one flag.
         1739        */
         1740       MESSAGE (0, (stderr, _("no output generated\n")));
         1741     }
         1742   else if (output_language_pass_through)
         1743     {
         1744       if (output_file == OUTPUT_FILE_NONE)
         1745         MESSAGE (0, (stderr, _("output sent to %s\n"),
         1746                      printer ? printer : _("printer")));
         1747       else
         1748         MESSAGE (0, (stderr, _("output left in %s\n"),
         1749                      output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
         1750     }
         1751   else
         1752     {
         1753       unsigned int real_total_pages;
         1754 
         1755       if (nup > 1)
         1756         {
         1757           if (total_pages > 0)
         1758             real_total_pages = (total_pages - 1) / nup + 1;
         1759           else
         1760             real_total_pages = 0;
         1761         }
         1762       else
         1763         real_total_pages = total_pages;
         1764 
         1765       /* We did something, tell what.  */
         1766       char message[80];
         1767       snprintf(message, sizeof message, "%s%s%s%s%s",
         1768                "[ ",
         1769                ngettext("%d page", "%d pages", real_total_pages),
         1770                " * ",
         1771                ngettext("%d copy", "%d copies", num_copies),
         1772                " ]");
         1773       MESSAGE (0, (stderr, message, real_total_pages, num_copies));
         1774 
         1775       if (output_file == OUTPUT_FILE_NONE)
         1776         MESSAGE (0, (stderr, _(" sent to %s\n"),
         1777                      printer ? printer : _("printer")));
         1778       else
         1779         MESSAGE (0, (stderr, _(" left in %s\n"),
         1780                      output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
         1781       if (num_truncated_lines)
         1782         {
         1783           retval |= 2;
         1784           MESSAGE (0, (stderr,
         1785                        ngettext("%d line was %s\n",
         1786                                 "%d lines were %s\n",
         1787                                 num_truncated_lines),
         1788                        num_truncated_lines,
         1789                        line_end == LE_TRUNCATE
         1790                        ? _("truncated") : _("wrapped")));
         1791         }
         1792 
         1793       if (num_missing_chars)
         1794         {
         1795           retval |= 4;
         1796           MESSAGE (0, (stderr,
         1797                        ngettext("%d character was missing\n",
         1798                                 "%d characters were missing\n",
         1799                                 num_missing_chars),
         1800                        num_missing_chars));
         1801           if (list_missing_characters)
         1802             {
         1803               MESSAGE (0, (stderr, _("missing character codes (decimal):\n")));
         1804               do_list_missing_characters (missing_chars);
         1805             }
         1806         }
         1807 
         1808       if (num_non_printable_chars)
         1809         {
         1810           retval |= 8;
         1811           MESSAGE (0, (stderr,
         1812                        ngettext("%d non-printable character\n",
         1813                                 "%d non-printable characters\n",
         1814                                 num_non_printable_chars),
         1815                        num_non_printable_chars));
         1816           if (list_missing_characters)
         1817             {
         1818               MESSAGE (0, (stderr,
         1819                            _("non-printable character codes (decimal):\n")));
         1820               do_list_missing_characters (non_printable_chars);
         1821             }
         1822         }
         1823     }
         1824 
         1825   /* Uninit our dynamic memory buffer. */
         1826   buffer_uninit (&buffer);
         1827 
         1828   /* Return the extended return values only if requested. */
         1829   if (!extended_return_values)
         1830     retval = 0;
         1831 
         1832   /* This is the end. */
         1833   return retval;
         1834 }
         1835 
         1836 
         1837 /*
         1838  * Static functions.
         1839  */
         1840 
         1841 static void
         1842 open_output_file ()
         1843 {
         1844   if (ofp)
         1845     /* Output file has already been opened, do nothing. */
         1846     return;
         1847 
         1848   if (output_file == OUTPUT_FILE_NONE)
         1849     {
         1850       char spooler_options[512];
         1851 
         1852       /* Format spooler options. */
         1853       spooler_options[0] = '\0';
         1854       if (mail)
         1855         {
         1856           strcat (spooler_options, "-m ");
         1857           strcat (spooler_options, mailto);
         1858           strcat (spooler_options, " ");
         1859         }
         1860       if (no_job_header)
         1861         {
         1862           strcat (spooler_options, no_job_header_switch);
         1863           strcat (spooler_options, " ");
         1864         }
         1865       if (printer_options)
         1866         strcat (spooler_options, printer_options);
         1867 
         1868       /* Open printer. */
         1869       ofp = printer_open (spooler_command, spooler_options, queue_param,
         1870                           printer, &printer_context);
         1871       if (ofp == NULL)
         1872         FATAL ((stderr, _("couldn't open printer `%s': %s"), printer,
         1873                 strerror (errno)));
         1874     }
         1875   else if (output_file == OUTPUT_FILE_STDOUT)
         1876     ofp = stdout;
         1877   else
         1878     {
         1879       ofp = fopen (output_file, "w");
         1880       if (ofp == NULL)
         1881         FATAL ((stderr, _("couldn't create output file \"%s\": %s"),
         1882                 output_file, strerror (errno)));
         1883     }
         1884 }
         1885 
         1886 
         1887 static void
         1888 close_output_file ()
         1889 {
         1890   if (ofp == NULL)
         1891     /* Output file hasn't been opened, we are done. */
         1892     return;
         1893 
         1894   if (output_file == OUTPUT_FILE_NONE)
         1895     printer_close (printer_context);
         1896   else if (output_file != OUTPUT_FILE_STDOUT)
         1897     if (fclose (ofp))
         1898       FATAL ((stderr, _("couldn't close output file \"%s\": %s"),
         1899               output_file, strerror (errno)));
         1900 
         1901   /* We do not reset <ofp> since its value is needed in diagnostigs. */
         1902 }
         1903 
         1904 
         1905 static void
         1906 handle_env_options (char *var)
         1907 {
         1908   int argc;
         1909   char **argv;
         1910   char *string;
         1911   char *str;
         1912   int i;
         1913 
         1914   string = getenv (var);
         1915   if (string == NULL)
         1916     return;
         1917 
         1918   MESSAGE (2, (stderr, "handle_env_options(): %s=\"%s\"\n", var, string));
         1919 
         1920   /* Copy string so we can modify it in place. */
         1921   str = xstrdup (string);
         1922 
         1923   /*
         1924    * We can count this, each option takes at least 1 character and one
         1925    * space.  We also need one for program's name and one for the
         1926    * trailing NULL.
         1927    */
         1928   argc = (strlen (str) + 1) / 2 + 2;
         1929   argv = xcalloc (argc, sizeof (char *));
         1930 
         1931   /* Set program name. */
         1932   argc = 0;
         1933   argv[argc++] = program;
         1934 
         1935   /* Split string and set arguments to argv array. */
         1936   i = 0;
         1937   while (str[i])
         1938     {
         1939       /* Skip leading whitespace. */
         1940       for (; str[i] && isspace (str[i]); i++)
         1941         ;
         1942       if (!str[i])
         1943         break;
         1944 
         1945       /* Check for quoted arguments. */
         1946       if (str[i] == '"' || str[i] == '\'')
         1947         {
         1948           int endch = str[i++];
         1949 
         1950           argv[argc++] = str + i;
         1951 
         1952           /* Skip until we found the end of the quotation. */
         1953           for (; str[i] && str[i] != endch; i++)
         1954             ;
         1955           if (!str[i])
         1956             FATAL ((stderr, _("syntax error in option string %s=\"%s\":\n\
         1957 missing end of quotation: %c"), var, string, endch));
         1958 
         1959           str[i++] = '\0';
         1960         }
         1961       else
         1962         {
         1963           argv[argc++] = str + i;
         1964 
         1965           /* Skip until whitespace if found. */
         1966           for (; str[i] && !isspace (str[i]); i++)
         1967             ;
         1968           if (str[i])
         1969             str[i++] = '\0';
         1970         }
         1971     }
         1972 
         1973   /* argv[argc] must be NULL. */
         1974   argv[argc] = NULL;
         1975 
         1976   MESSAGE (2, (stderr, "found following options (argc=%d):\n", argc));
         1977   for (i = 0; i < argc; i++)
         1978     MESSAGE (2, (stderr, "%3d = \"%s\"\n", i, argv[i]));
         1979 
         1980   /* Process options. */
         1981   handle_options (argc, argv);
         1982 
         1983   /* Check that all got processed. */
         1984   if (optind != argc)
         1985     {
         1986       MESSAGE (0,
         1987                (stderr,
         1988                 _("warning: didn't process following options from \
         1989 environment variable %s:\n"),
         1990                 var));
         1991       for (; optind < argc; optind++)
         1992         MESSAGE (0, (stderr, _("  option %d = \"%s\"\n"), optind,
         1993                      argv[optind]));
         1994     }
         1995 
         1996   /* Cleanup. */
         1997   xfree (argv);
         1998 
         1999   /*
         2000    * <str> must not be freed, since some global variables can point to
         2001    * its elements
         2002    */
         2003 }
         2004 
         2005 
         2006 static void
         2007 handle_options (int argc, char *argv[])
         2008 {
         2009   int c;
         2010   PageRange *prange;
         2011 
         2012   /* Reset optind. */
         2013   optind = 0;
         2014 
         2015   while (1)
         2016     {
         2017       int option_index = 0;
         2018       const char *cp;
         2019       int i;
         2020 
         2021       c = getopt_long (argc, argv,
         2022                        "#:123456789a:A:b:BcC::d:D:e::E::f:F:gGhH::i:I:jJ:kKlL:m::M:n:N:o:Op:P:qrRs:S:t:T:u::U:vVw:W:X:zZ",
         2023                        long_options, &option_index);
         2024 
         2025       if (c == -1)
         2026         break;
         2027 
         2028       switch (c)
         2029         {
         2030         case 0:                        /* Long option found. */
         2031           cp = long_options[option_index].name;
         2032 
         2033           if (strcmp (cp, "columns") == 0)
         2034             {
         2035               num_columns = atoi (optarg);
         2036               if (num_columns < 1)
         2037                 FATAL ((stderr,
         2038                         _("number of columns must be larger than zero")));
         2039             }
         2040           break;
         2041 
         2042           /* Short options. */
         2043 
         2044         case '1':                /* 1 column */
         2045         case '2':                /* 2 columns */
         2046         case '3':                /* 3 columns */
         2047         case '4':                /* 4 columns */
         2048         case '5':                /* 5 columns */
         2049         case '6':                /* 6 columns */
         2050         case '7':                /* 7 columns */
         2051         case '8':                /* 8 columns */
         2052         case '9':                /* 9 columns */
         2053           num_columns = c - '0';
         2054           break;
         2055 
         2056         case 'a':                /* pages */
         2057           prange = (PageRange *) xcalloc (1, sizeof (PageRange));
         2058 
         2059           if (strcmp (optarg, "odd") == 0)
         2060             prange->odd = 1;
         2061           else if (strcmp (optarg, "even") == 0)
         2062             prange->even = 1;
         2063           else
         2064             {
         2065               cp = strchr (optarg, '-');
         2066               if (cp)
         2067                 {
         2068                   if (optarg[0] == '-')
         2069                     /* -end */
         2070                     prange->end = atoi (optarg + 1);
         2071                   else if (cp[1] == '\0')
         2072                     {
         2073                       /* begin- */
         2074                       prange->start = atoi (optarg);
         2075                       prange->end = (unsigned int) -1;
         2076                     }
         2077                   else
         2078                     {
         2079                       /* begin-end */
         2080                       prange->start = atoi (optarg);
         2081                       prange->end = atoi (cp + 1);
         2082                     }
         2083                 }
         2084               else
         2085                 /* pagenumber */
         2086                 prange->start = prange->end = atoi (optarg);
         2087             }
         2088 
         2089           prange->next = page_ranges;
         2090           page_ranges = prange;
         2091           break;
         2092 
         2093         case 'A':                /* file alignment */
         2094           file_align = atoi (optarg);
         2095           if (file_align == 0)
         2096             FATAL ((stderr, _("file alignment must be larger than zero")));
         2097           break;
         2098 
         2099         case 'b':                /* page header */
         2100           page_header = optarg;
         2101           break;
         2102 
         2103         case 'B':                /* no page headers */
         2104           header = HDR_NONE;
         2105           break;
         2106 
         2107         case 'c':                /* truncate (cut) long lines */
         2108           line_end = LE_TRUNCATE;
         2109           break;
         2110 
         2111         case 'C':                /* line numbers */
         2112           line_numbers = 1;
         2113           if (optarg)
         2114             start_line_number = atoi (optarg);
         2115           break;
         2116 
         2117         case 'd':                /* specify printer */
         2118         case 'P':
         2119           xfree (printer);
         2120           printer = xstrdup (optarg);
         2121           output_file = OUTPUT_FILE_NONE;
         2122           break;
         2123 
         2124         case 'D':                /* setpagedevice */
         2125           parse_key_value_pair (pagedevice, optarg);
         2126           break;
         2127 
         2128         case 'e':                /* special escapes */
         2129           special_escapes = 1;
         2130           if (optarg)
         2131             {
         2132               /* Specify the escape character. */
         2133               if (isdigit (optarg[0]))
         2134                 /* As decimal, octal, or hexadicimal number. */
         2135                 escape_char = (int) strtoul (optarg, NULL, 0);
         2136               else
         2137                 /* As character directly. */
         2138                 escape_char = ((unsigned char *) optarg)[0];
         2139             }
         2140           break;
         2141 
         2142         case 'E':                /* highlight */
         2143           highlight = 1;
         2144           special_escapes = 1;
         2145           escape_char = '\0';
         2146           hl_start_state = optarg;
         2147           break;
         2148 
         2149         case 'f':                /* font */
         2150           if (!parse_font_spec (optarg, &Fname, &Fpt, NULL))
         2151             FATAL ((stderr, _("malformed font spec: %s"), optarg));
         2152           user_body_font_defined = 1;
         2153           break;
         2154 
         2155         case 'F':                /* header font */
         2156           if (!parse_font_spec (optarg, &HFname, &HFpt, NULL))
         2157             FATAL ((stderr, _("malformed font spec: %s"), optarg));
         2158           break;
         2159 
         2160         case 'g':                /* print anyway */
         2161           /* nothing. */
         2162           break;
         2163 
         2164         case 'G':                /* fancy header */
         2165           header = HDR_FANCY;
         2166           if (optarg)
         2167             fancy_header_name = optarg;
         2168           else
         2169             fancy_header_name = fancy_header_default;
         2170 
         2171           if (!file_existsp (fancy_header_name, ".hdr"))
         2172             FATAL ((stderr,
         2173                     _("couldn't find header definition file \"%s.hdr\""),
         2174                     fancy_header_name));
         2175           break;
         2176 
         2177         case 'h':                /* no job header */
         2178           no_job_header = 1;
         2179           break;
         2180 
         2181         case 'H':                /* highlight bars */
         2182           if (optarg)
         2183             highlight_bars = atoi (optarg);
         2184           else
         2185             highlight_bars = 2;
         2186           break;
         2187 
         2188         case 'i':                /* line indent */
         2189           line_indent_spec = optarg;
         2190           break;
         2191 
         2192         case 'I':                /* input filter */
         2193           input_filter = optarg;
         2194           break;
         2195 
         2196         case 'j':                /* borders */
         2197           borders = 1;
         2198           break;
         2199 
         2200         case 'k':                /* enable page prefeed */
         2201           page_prefeed = 1;
         2202           break;
         2203 
         2204         case 'K':                /* disable page prefeed */
         2205           page_prefeed = 0;
         2206           break;
         2207 
         2208         case 'l':                /* emulate lineprinter */
         2209           lines_per_page = 66;
         2210           header = HDR_NONE;
         2211           break;
         2212 
         2213         case 'L':                /* lines per page */
         2214           lines_per_page = atoi (optarg);
         2215           if (lines_per_page <= 0)
         2216             FATAL ((stderr,
         2217                     _("must print at least one line per each page: %s"),
         2218                     argv[optind]));
         2219           break;
         2220 
         2221         case 'm':                /* send mail upon completion */
         2222           mail = 1;
         2223           if(optarg)
         2224             mailto = (optarg);
         2225           else
         2226             mailto = (*passwd).pw_name;
         2227           break;
         2228 
         2229         case 'M':                /* select output media */
         2230           media_name = xstrdup (optarg);
         2231           break;
         2232 
         2233         case 'n':                /* num copies */
         2234         case '#':
         2235           num_copies = atoi (optarg);
         2236           break;
         2237 
         2238         case 'N':                /* newline character */
         2239           if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0')
         2240             {
         2241               fprintf (stderr, _("%s: illegal newline character specifier: \
         2242 '%s': expected 'n' or 'r'\n"),
         2243                        program, optarg);
         2244               goto option_error;
         2245             }
         2246           if (optarg[0] == 'n')
         2247             nl = '\n';
         2248           else
         2249             nl = '\r';
         2250           break;
         2251 
         2252         case 'o':
         2253         case 'p':                /* output file */
         2254           /* Check output file "-". */
         2255           if (strcmp (optarg, "-") == 0)
         2256             output_file = OUTPUT_FILE_STDOUT;
         2257           else
         2258             output_file = optarg;
         2259           break;
         2260 
         2261         case 'O':                /* list missing characters */
         2262           list_missing_characters = 1;
         2263           break;
         2264 
         2265         case 'q':                /* quiet */
         2266           quiet = 1;
         2267           verbose = 0;
         2268           break;
         2269 
         2270         case 'r':                /* landscape */
         2271           landscape = 1;
         2272           break;
         2273 
         2274         case 'R':                /* portrait */
         2275           landscape = 0;
         2276           break;
         2277 
         2278         case 's':                /* baselineskip */
         2279           baselineskip = atof (optarg);
         2280           break;
         2281 
         2282         case 'S':                /* statusdict */
         2283           parse_key_value_pair (statusdict, optarg);
         2284           break;
         2285 
         2286         case 't':                /* title */
         2287         case 'J':
         2288           title = optarg;
         2289           title_given = 1;
         2290           break;
         2291 
         2292         case 'T':                /* tabulator size */
         2293           tabsize = atoi (optarg);
         2294           if (tabsize <= 0)
         2295             tabsize = 1;
         2296           break;
         2297 
         2298         case 'u':                /* underlay */
         2299           underlay = optarg;
         2300           break;
         2301 
         2302         case 'U':                /* nup */
         2303           nup = atoi (optarg);
         2304           break;
         2305 
         2306         case 'v':                /* verbose */
         2307           if (optarg)
         2308             verbose = atoi (optarg);
         2309           else
         2310             verbose++;
         2311           quiet = 0;
         2312           break;
         2313 
         2314         case 'V':                /* version */
         2315           version ();
         2316           exit (0);
         2317           break;
         2318 
         2319         case 'w':                /* output language */
         2320           output_language = optarg;
         2321           if (strcmp (output_language, "PostScript") != 0)
         2322             /* Other output languages are handled with states. */
         2323             output_language_pass_through = 1;
         2324           break;
         2325 
         2326         case 'W':                /* a helper application option */
         2327           cp = strchr (optarg, ',');
         2328           if (cp == NULL)
         2329             FATAL ((stderr,
         2330                     _("malformed argument `%s' for option -W, --option: \
         2331 no comma found"),
         2332                       optarg));
         2333 
         2334           if (cp - optarg != 1)
         2335             FATAL ((stderr, _("helper application specification must be \
         2336 single character: %s"),
         2337                               optarg));
         2338 
         2339           /* Take the index of the helper application and update `cp'
         2340              to point to the beginning of the option. */
         2341           i = *optarg;
         2342           cp++;
         2343 
         2344           if (helper_options[i] == NULL)
         2345             helper_options[i] = buffer_alloc ();
         2346           else
         2347             {
         2348               /* We already had some options for this helper
         2349                  application.  Let's separate these arguments. */
         2350               buffer_append (helper_options[i], " ");
         2351             }
         2352 
         2353           /* Add this new option. */
         2354           buffer_append (helper_options[i], cp);
         2355           break;
         2356 
         2357         case 'X':                /* input encoding */
         2358           xfree (encoding_name);
         2359           encoding_name = xstrdup (optarg);
         2360           break;
         2361 
         2362         case 'z':                /* no form feeds */
         2363           interpret_formfeed = 0;
         2364           break;
         2365 
         2366         case 'Z':                /* pass through */
         2367           pass_through = 1;
         2368           break;
         2369 
         2370         case 128:                /* underlay font */
         2371           if (!parse_font_spec (optarg, &ul_font, &ul_ptsize, NULL))
         2372             FATAL ((stderr, _("malformed font spec: %s"), optarg));
         2373           break;
         2374 
         2375         case 129:                /* underlay gray */
         2376           ul_gray = atof (optarg);
         2377           break;
         2378 
         2379         case 130:                /* page label format */
         2380           xfree (page_label_format);
         2381           page_label_format = xstrdup (optarg);
         2382           break;
         2383 
         2384         case 131:                /* download font */
         2385           strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL,
         2386                        NULL);
         2387           break;
         2388 
         2389         case 132:                /* underlay angle */
         2390           ul_angle = atof (optarg);
         2391           ul_angle_p = 1;
         2392           break;
         2393 
         2394         case 133:                /* underlay position */
         2395           xfree (ul_position);
         2396           ul_position = xstrdup (optarg);
         2397           ul_position_p = 1;
         2398           break;
         2399 
         2400         case 134:                /* non-printable format */
         2401           xfree (npf_name);
         2402           npf_name = xstrdup (optarg);
         2403           break;
         2404 
         2405         case 135:                /* help */
         2406           usage ();
         2407           exit (0);
         2408           break;
         2409 
         2410         case 136:                /* highlight bar gray */
         2411           highlight_bar_gray = atof (optarg);
         2412           break;
         2413 
         2414         case 137:                /* underlay style */
         2415           xfree (ul_style_str);
         2416           ul_style_str = xstrdup (optarg);
         2417           break;
         2418 
         2419         case 138:                /* filter stdin */
         2420           input_filter_stdin = optarg;
         2421           break;
         2422 
         2423         case 139:                /* extra options for the printer spooler */
         2424           printer_options = optarg;
         2425           break;
         2426 
         2427         case 140:                /* slicing */
         2428           slicing = 1;
         2429           slice = atoi (optarg);
         2430           if (slice <= 0)
         2431             FATAL ((stderr, _("slice must be greater than zero")));
         2432           break;
         2433 
         2434         case 141:                /* help-highlight */
         2435           help_highlight = 1;
         2436           break;
         2437 
         2438         case 142:                /* States color? */
         2439           if (optarg == NULL)
         2440             states_color = 1;
         2441           else
         2442             states_color = atoi (optarg);
         2443           break;
         2444 
         2445         case 143:                /* mark-wrapped-lines */
         2446           if (optarg)
         2447             {
         2448               xfree (mark_wrapped_lines_style_name);
         2449               mark_wrapped_lines_style_name = xstrdup (optarg);
         2450             }
         2451           else
         2452             /* Set the system default. */
         2453             mark_wrapped_lines_style = MWLS_BOX;
         2454           break;
         2455 
         2456         case 144:                /* adjust margins */
         2457           margins_spec = optarg;
         2458           break;
         2459 
         2460         case 145:                /* N-up x-pad */
         2461           nup_xpad = atoi (optarg);
         2462           break;
         2463 
         2464         case 146:                /* N-up y-pad */
         2465           nup_ypad = atoi (optarg);
         2466           break;
         2467 
         2468         case 147:                /* word wrap */
         2469           line_end = LE_WORD_WRAP;
         2470           break;
         2471 
         2472         case 148:                /* horizontal column height */
         2473           horizontal_column_height = atof (optarg);
         2474           formfeed_type = FORMFEED_HCOLUMN;
         2475           break;
         2476 
         2477         case 149:                /* PostScript language level */
         2478           pslevel = atoi (optarg);
         2479           break;
         2480 
         2481         case 150:                /* rotate even-numbered pages */
         2482           rotate_even_pages = 1;
         2483           break;
         2484 
         2485         case 151:                /* highlight style */
         2486           xfree (states_highlight_style);
         2487           states_highlight_style = xstrdup (optarg);
         2488           break;
         2489 
         2490         case 152:                /* N-up colunwise */
         2491           nup_columnwise = 1;
         2492           break;
         2493 
         2494         case 153:                /* swap even page margins */
         2495           swap_even_page_margins = 1;
         2496           break;
         2497 
         2498         case 154:                /* extended return values */
         2499           extended_return_values = 1;
         2500           break;
         2501 
         2502         case 155:                /* footer */
         2503           page_footer = optarg;
         2504           break;
         2505 
         2506         case 156:                /* continuous page numbers */
         2507           continuous_page_numbers = 1;
         2508           break;
         2509 
         2510         case '?':                /* Errors found during getopt_long(). */
         2511         option_error:
         2512           fprintf (stderr, _("Try `%s --help' for more information.\n"),
         2513                    program);
         2514           exit (1);
         2515           break;
         2516 
         2517         default:
         2518           printf ("Hey!  main() didn't handle option \"%c\" (%d)", c, c);
         2519           if (optarg)
         2520             printf (" with arg %s", optarg);
         2521           printf ("\n");
         2522           FATAL ((stderr, "This is a bug!"));
         2523           break;
         2524         }
         2525     }
         2526 }
         2527 
         2528 
         2529 static void
         2530 usage ()
         2531 {
         2532   printf (_("\
         2533 Usage: %s [OPTION]... [FILE]...\n\
         2534 Mandatory arguments to long options are mandatory for short options too.\n\
         2535   -#                         an alias for option -n, --copies\n\
         2536   -1                         same as --columns=1\n\
         2537   -2                         same as --columns=2\n\
         2538       --columns=NUM          specify the number of columns per page\n\
         2539   -a, --pages=PAGES          specify which pages are printed\n\
         2540   -A, --file-align=ALIGN     align separate input files to ALIGN\n\
         2541   -b, --header=HEADER        set page header\n\
         2542   -B, --no-header            no page headers\n\
         2543   -c, --truncate-lines       cut long lines (default is to wrap)\n\
         2544   -C[START], --line-numbers[=START]\n\
         2545                              precede each line with its line number\n\
         2546   -d                         an alias for option --printer\n\
         2547   -D, --setpagedevice=KEY[:VALUE]\n\
         2548                              pass a page device definition to output\n\
         2549   -e[CHAR], --escapes[=CHAR]       enable special escape interpretation\n"),
         2550           program);
         2551 
         2552   printf (_("\
         2553   -E[LANG], --highlight[=LANG]     highlight source code\n"));
         2554 
         2555   printf (_("\
         2556   -f, --font=NAME            use font NAME for body text\n\
         2557   -F, --header-font=NAME     use font NAME for header texts\n\
         2558   -g, --print-anyway         nothing (compatibility option)\n\
         2559   -G                         same as --fancy-header\n\
         2560       --fancy-header[=NAME]  select fancy page header\n\
         2561   -h, --no-job-header        suppress the job header page\n\
         2562   -H[NUM], --highlight-bars[=NUM]  specify how high highlight bars are\n\
         2563   -i, --indent=NUM           set line indent to NUM characters\n\
         2564   -I, --filter=CMD           read input files through input filter CMD\n\
         2565   -j, --borders              print borders around columns\n\
         2566   -J,                        an alias for option --title\n\
         2567   -k, --page-prefeed         enable page prefeed\n\
         2568   -K, --no-page-prefeed      disable page prefeed\n\
         2569   -l, --lineprinter          simulate lineprinter, this is an alias for:\n\
         2570                                --lines-per-page=66, --no-header, --portrait,\n\
         2571                                --columns=1\n"));
         2572 
         2573   printf (_("\
         2574   -L, --lines-per-page=NUM   specify how many lines are printed on each page\n\
         2575   -m, --mail                 send mail upon completion\n\
         2576   -M, --media=NAME           use output media NAME\n\
         2577   -n, --copies=NUM           print NUM copies of each page\n\
         2578   -N, --newline=NL           select the newline character.  Possible\n\
         2579                              values for NL are: n (`\\n') and r (`\\r').\n\
         2580   -o                         an alias for option --output\n\
         2581   -O, --missing-characters   list missing characters\n\
         2582   -p, --output=FILE          leave output to file FILE.  If FILE is `-',\n\
         2583                              leave output to stdout.\n\
         2584   -P, --printer=NAME         print output to printer NAME\n\
         2585   -q, --quiet, --silent      be really quiet\n\
         2586   -r, --landscape            print in landscape mode\n\
         2587   -R, --portrait             print in portrait mode\n"));
         2588 
         2589   printf (_("\
         2590   -s, --baselineskip=NUM     set baselineskip to NUM\n\
         2591   -S, --statusdict=KEY[:VALUE]\n\
         2592                              pass a statusdict definition to the output\n\
         2593   -t, --title=TITLE          set banner page's job title to TITLE.  Option\n\
         2594                              sets also the name of the input file stdin.\n\
         2595   -T, --tabsize=NUM          set tabulator size to NUM\n\
         2596   -u[TEXT], --underlay[=TEXT]      print TEXT under every page\n\
         2597   -U, --nup=NUM              print NUM logical pages on each output page\n\
         2598   -v, --verbose              tell what we are doing\n\
         2599   -V, --version              print version number\n\
         2600   -w, --language=LANG        set output language to LANG\n\
         2601   -W, --options=APP,OPTION   pass option OPTION to helper application APP\n\
         2602   -X, --encoding=NAME        use input encoding NAME\n\
         2603   -z, --no-formfeed          do not interpret form feed characters\n\
         2604   -Z, --pass-through         pass through PostScript and PCL files\n\
         2605                              without any modifications\n"));
         2606 
         2607   printf (_("Long-only options:\n\
         2608   --color[=bool]             create color outputs with states\n\
         2609   --continuous-page-numbers  count page numbers across input files.  Don't\n\
         2610                              restart numbering at beginning of each file.\n\
         2611   --download-font=NAME       download font NAME\n\
         2612   --extended-return-values   enable extended return values\n\
         2613   --filter-stdin=NAME        specify how stdin is shown to the input filter\n\
         2614   --footer=FOOTER            set page footer\n\
         2615   --h-column-height=HEIGHT   set the horizontal column height to HEIGHT\n\
         2616   --help                     print this help and exit\n"));
         2617 
         2618   printf (_("\
         2619   --help-highlight           describe all supported --highlight languages\n\
         2620                              and file formats\n\
         2621   --highlight-bar-gray=NUM   print highlight bars with gray NUM (0 - 1)\n\
         2622   --list-media               list names of all known media\n\
         2623   --margins=LEFT:RIGHT:TOP:BOTTOM\n\
         2624                              adjust page marginals\n\
         2625   --mark-wrapped-lines[STYLE]\n\
         2626                              mark wrapped lines in the output with STYLE\n\
         2627   --non-printable-format=FMT specify how non-printable chars are printed\n"));
         2628 
         2629   printf (_("\
         2630   --nup-columnwise           layout pages in the N-up printing columnwise\n\
         2631   --nup-xpad=NUM             set the page x-padding of N-up printing to NUM\n\
         2632   --nup-ypad=NUM             set the page y-padding of N-up printing to NUM\n\
         2633   --page-label-format=FMT    set page label format to FMT\n\
         2634   --ps-level=LEVEL           set the PostScript language level that enscript\n\
         2635                              should use\n\
         2636   --printer-options=OPTIONS  pass extra options to the printer command\n\
         2637   --rotate-even-pages        rotate even-numbered pages 180 degrees\n"));
         2638 
         2639   printf (_("\
         2640   --slice=NUM                print vertical slice NUM\n\
         2641   --style=STYLE              use highlight style STYLE\n\
         2642   --swap-even-page-margins   swap left and right side margins for each even\n\
         2643                              numbered page\n\
         2644   --toc                      print table of contents\n\
         2645   --ul-angle=ANGLE           set underlay text's angle to ANGLE\n\
         2646   --ul-font=NAME             print underlays with font NAME\n\
         2647   --ul-gray=NUM              print underlays with gray value NUM\n\
         2648   --ul-position=POS          set underlay's starting position to POS\n\
         2649   --ul-style=STYLE           print underlays with style STYLE\n\
         2650   --word-wrap                wrap long lines from word boundaries\n\
         2651 "));
         2652 
         2653   printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
         2654 }
         2655 
         2656 
         2657 static void
         2658 version ()
         2659 {
         2660   printf ("%s\n\
         2661 Copyright (C) 1995-2003, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.\n\
         2662 %s comes with NO WARRANTY, to the extent permitted by law.\n\
         2663 You may redistribute copies of %s under the terms of the GNU\n\
         2664 General Public License, version 3 or, at your option, any later version.\n\
         2665 For more information about these matters, see the files named COPYING.\n",
         2666           PACKAGE_STRING,
         2667           PACKAGE_NAME,
         2668           PACKAGE_NAME);
         2669 }