Updating the ChangeLog file
[enscript.git] / src / main.c
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 }