2 * Argument handling and main.
3 * Copyright (c) 1995-2003 Markku Rossi.
5 * Author: Markku Rossi <mtr@iki.fi>
9 * This file is part of GNU enscript.
11 * This program 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 2, or (at your option)
16 * This program 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.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
31 * Prototypes for static functions.
35 * Open output file according to user options. Void if output file
36 * has already been opened.
38 static void open_output_file ();
40 /* Close output file. */
41 static void close_output_file ();
43 /* Handle options from environment variable <var> */
44 static void handle_env_options ___P ((char *var));
46 /* Handle options from <argv> array. */
47 static void handle_options ___P ((int argc, char *argv[]));
49 /* Print usage info. */
52 /* Print version info. */
53 static void version ();
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 *version_string = NULL; /* Enscript's version string. */
64 char *ps_version_string = NULL; /* Version string for PS procsets. */
65 char *date_string = NULL; /* Preformatted time string. */
66 struct tm run_tm; /* Time when program is run. */
67 struct tm mod_tm; /* Last modification time for current file. */
68 struct passwd *passwd; /* Passwd entry for the user running this
71 /* Path to our library. */
72 char *enscript_library = LIBRARY;
74 /* Library lookup path. */
77 /* AFM library lookup path. */
78 char *afm_path = NULL;
80 MediaEntry *media_names = NULL; /* List of known media. */
81 MediaEntry *media = NULL; /* Entry for used media. */
82 int bs = 8; /* The backspace character. */
85 int total_pages = 0; /* Total number of pages printed. */
86 int num_truncated_lines = 0; /* Number of lines truncated. */
87 int num_missing_chars = 0; /* Number of unknown characters. */
88 int missing_chars[256] = {0}; /* Table of unknown characters. */
89 int num_non_printable_chars = 0; /* Number of non-printable characters. */
90 int non_printable_chars[256] = {0}; /* Table of non-printable characters. */
92 /* Output media dimensions that are used during PostScript emission. */
93 int d_page_w = 0; /* page's width */
94 int d_page_h = 0; /* page's height */
95 int d_header_w = 0; /* fancy header's width */
96 int d_header_h = 0; /* fancy header's height */
97 int d_footer_h = 0; /* fancy footer's height */
98 int d_output_w = 0; /* output area's width */
99 int d_output_h = 0; /* output area's height */
100 int d_output_x_margin = 5; /* output area's x marginal */
101 int d_output_y_margin = 2; /* output area's y marginal */
103 /* Document needed resources. */
104 StringHashPtr res_fonts; /* fonts */
106 /* Fonts to download. */
107 StringHashPtr download_fonts;
109 /* Additional key-value pairs, passed to the generated PostScript code. */
110 StringHashPtr pagedevice; /* for setpagedevice */
111 StringHashPtr statusdict; /* for statusdict */
113 /* User defined strings. */
114 StringHashPtr user_strings;
116 /* Cache for AFM files. */
117 StringHashPtr afm_cache = NULL;
118 StringHashPtr afm_info_cache = NULL;
120 /* AFM library handle. */
121 AFMHandle afm = NULL;
127 * Free single-letter options are: Q, x, y, Y
133 * An alias for -n, --copies.
137 * -1, -2, -3, -4, -5, -6, -7, -8, -9, --columns=NUM
139 * Number of columns per page. The default is 1 column.
144 * -a PAGES, --pages=PAGES
146 * Specify which pages are printed.
148 PageRange *page_ranges = NULL;
151 * -A ALIGN, --file-align=ALIGN
153 * Align input files to start from ALIGN page count. This is handy
154 * for two-side printings.
156 unsigned int file_align = 1;
159 * -b STRING, --header=STRING
161 * Set the string that is used as the page header. As a default, page
162 * header is constructed from filename, date and page number.
164 char *page_header = NULL;
169 * Do not print page headers.
173 * -c, --truncate-lines
175 * Truncate lines that are longer than the page width. Default is character
178 LineEndType line_end = LE_CHAR_WRAP;
181 * -C [START], --line-numbers[=START]
183 * Precede each line with its line number. As a default, do not mark
184 * line numbers. If the optional argument START is given, it
185 * specifies the number from which the line numbers are assumed to
186 * start in the file. This is useful if the file contains a region
189 int line_numbers = 0;
190 unsigned int start_line_number = 1;
195 * Name of the printer to which output is send. Defaults to system's
198 char *printer = NULL;
201 * -e [CHAR], --escapes[=CHAR]
203 * Enable special escape ('\000') interpretation. If option CHAR is given
204 * it is assumed to specify the escape character.
206 int special_escapes = 0;
207 int escape_char = '\0';
208 int default_escape_char;
211 * -E [LANG], --highlight=[LANG] (deprecated --pretty-print[=LANG])
213 * Highlight program source code. Highlighting is handled by creating
214 * an input filter with the states-program. States makes an educated
215 * guess about the start state but sometimes it fails, so the start
216 * state can also be specified to be LANG. This option overwrites
217 * input filter and enables special escapes.
221 char *hl_start_state = NULL;
228 char *Fname = "Courier";
229 FontPoint Fpt = {10.0, 10.0};
230 FontPoint default_Fpt; /* Point size of the original font. */
231 char *default_Fname; /* Name of the original font. */
232 InputEncoding default_Fencoding; /* The encoding of the original font. */
233 int user_body_font_defined = 0; /* Has user defined new body font? */
235 double font_widths[256]; /* Width array for body font. */
236 char font_ctype[256]; /* Font character types. */
237 int font_is_fixed; /* Is body font a fixed pitch font? */
238 double font_bbox_lly; /* Font's bounding box's lly-coordinate. */
243 * Select font to be used to print the standard simple header.
245 char *HFname = "Courier-Bold";
246 FontPoint HFpt = {10.0, 10.0};
251 * Print document even it contains binary data. This does nothing
252 * since enscript prints files anyway.
258 * Add a fancy header to top of every page. There are several header styles
259 * but the default is 'no fancy header'.
261 HeaderType header = HDR_SIMPLE;
262 char *fancy_header_name = NULL;
263 char *fancy_header_default = NULL;
266 * -h, --no-job-header
268 * Supress the job header page.
270 static int no_job_header = 0;
273 * -H num, --highlight-bars=num
275 * Print highlight bars under text. Bars will be <num> lines high.
276 * As a default, do not print bars.
278 unsigned int highlight_bars = 0;
283 * Indent every line this many characters.
285 double line_indent = 0.0;
286 char *line_indent_spec = "0";
289 * -I CMD, --filter=CMD
291 * Read input files through input filter CMD.
293 char *input_filter = NULL;
298 * Print borders around columns.
305 * An alias for -t, --title.
310 * -K, --no-page-prefeed
312 * Control page prefeed.
314 int page_prefeed = 0;
319 * Emulate lineprinter - make pages 66 lines long and omit headers.
323 * -L, --lines-per-page
325 * Specify how many lines should be printed on a single page. Normally
326 * enscript counts it from font point sizes.
328 unsigned int lines_per_page = (unsigned int) -1;
333 * Send mail notification to user after print job has been completed.
340 * Name of the output media. Default is A4.
342 char *media_name = NULL;
347 * Number of copies to print.
354 * Set the newline character: '\n' or '\r'. As a default, the newline
355 * character is specified by the input encoding.
362 * Leave output to the specified file. As a default result is spooled to
365 char *output_file = OUTPUT_FILE_NONE;
368 * -O, --missing-characters
370 * List all missing characters. Default is no listing.
372 int list_missing_characters = 0;
377 * Do not tell what we are doing. Default is to tell something but
386 * Print with page rotated 90 degrees (landscape mode). Default is
394 * Specify baselineskip value that is used when enscript moves to
395 * a new line. Current point movement is font_point_size + baselineskip.
397 double baselineskip = 1.0;
402 * Title which is printed to the banner page. If this option is given
403 * from the command line, this sets also the name of the stdin which
404 * is by the default "".
406 char *title = "Enscript Output";
412 * Specify tabulator size.
419 * Place text under every page. Default is no underlay.
422 FontPoint ul_ptsize = {200.0, 200.0};
423 char *ul_font = "Times-Roman";
424 char *underlay = NULL;
425 char *ul_position = NULL; /* Position info as a string. */
426 double ul_x; /* Position x-coordinate. */
427 double ul_y; /* Position y-coordinate. */
429 unsigned int ul_style = UL_STYLE_OUTLINE;
430 char *ul_style_str = NULL;
431 int ul_position_p = 0; /* Is ul-position given? */
432 int ul_angle_p = 0; /* Is ul-angle given? */
437 * Print NUM PostScript pages on each output page (n-up printing).
439 unsigned int nup = 1;
440 unsigned int nup_exp = 0;
441 unsigned int nup_rows = 1;
442 unsigned int nup_columns = 1;
443 int nup_landscape = 0;
444 unsigned int nup_width;
445 unsigned int nup_height;
451 * Tell what we are doing. Default is no verbose outputs.
458 * Print version information.
462 * -w LANGUAGE, --language=LANGUAGE
464 * Generate output for language LANGUAGE. The default is PostScript.
466 char *output_language = "PostScript";
467 int output_language_pass_through = 0;
470 * -W APP,option, --options=APP,OPTION
472 * Pass additional option to enscript's helper applications. The
473 * first part of the option's argument (APP) specifies the
474 * helper application to which the options are added. Currently the
475 * following helper application are defined:
479 Buffer *helper_options[256] = {0};
484 * Specifies input encoding. Default is ISO-8859.1.
486 InputEncoding encoding = ENC_ISO_8859_1;
487 char *encoding_name = NULL;
492 * Do not interpret form feed characters. As a default, form feed
493 * characters are interpreted.
495 int interpret_formfeed = 1;
500 * Pass through all PostScript and PCL files without any modifications.
501 * As a default, don't.
503 int pass_through = 0;
508 * Create color output with states?
512 * --continuous-page-numbers
514 * Count page numbers across input files. Don't restart numbering
515 * at beginning of each file.
517 int continuous_page_numbers = 0;
520 * --download-font=FONT
522 * Download font FONT to printer.
526 * --extended-return-values
528 * Enable extended return values.
530 int extended_return_values = 0;
535 * How stdin is shown to the filter command. The default is "" but
536 * some utilities might want it as "-".
538 char *input_filter_stdin = "";
543 * Set the string that is used as the page footer. As a default, the
544 * page has no footer. Setting this option does not necessary show
545 * any footer strings in the output. It depends on the selected
546 * header (`.hdr' file) whether it supports footer strings or not.
548 char *page_footer = NULL;
551 * --h-column-height=HEIGHT
553 * Set the horizontal column (channel) height to be HEIGHT. This option
554 * also sets the FormFeedType to `hcolumn'. The default value is set to be
555 * big enough to cause a jump to the next vertical column (100m).
557 double horizontal_column_height = 283465.0;
560 * --help-highlight (deprecated --help-pretty-print)
562 * Descript all supported -E, --highlight languages and file formats.
564 int help_highlight = 0;
567 * --highlight-bar-gray=val
569 * Specify the gray level for highlight bars.
571 double highlight_bar_gray = .97;
576 * List all known media. As a default do not list media names.
581 * --margins=LEFT:RIGHT:TOP:BOTTOM
583 * Adjust page marginals.
585 char *margins_spec = NULL;
588 * --mark-wrapped-lines[=STYLE]
590 * Mark wrapped lines so that they can be easily detected from the printout.
591 * Optional parameter STYLE specifies the marking style, the system default
594 char *mark_wrapped_lines_style_name = NULL;
595 MarkWrappedLinesStyle mark_wrapped_lines_style = MWLS_NONE;
598 * --non-printable-format=FORMAT
600 * Format in which non-printable characters are printed.
602 char *npf_name = NULL;
603 NonPrintableFormat non_printable_format = NPF_OCTAL;
608 * Layout N-up pages colunwise instead of row-wise.
610 int nup_columnwise = 0;
615 * The x-padding between N-up subpages.
617 unsigned int nup_xpad = 10;
622 * The y-padding between N-up subpages.
624 unsigned int nup_ypad = 10;
627 * --page-label-format=FORMAT
629 * Format in which page labels are printed; the default is "short".
631 char *page_label_format = NULL;
632 PageLabelFormat page_label;
637 * The PostScript language level that enscript should use; the default is 2.
639 unsigned int pslevel = 2;
642 * --printer-options=OPTIONS
644 * Pass extra options OPTIONS to the printer spooler.
646 char *printer_options = NULL;
649 * --rotate-even-pages
651 * Rotate each even-numbered page 180 degrees. This might be handy in
652 * two-side printing when the resulting pages are bind from some side.
653 * Greetings to Jussi-Pekka Sairanen.
655 int rotate_even_pages = 0;
660 * Horizontal input slicing. Print only NUMth wrapped input pages.
663 unsigned int slice = 1;
666 * --swap-even-page-margins
668 * Swap left and right side margins for each even numbered page. This
669 * might be handy in two-side printing.
671 int swap_even_page_margins = 0;
676 * Print Table of Contents page.
680 char *toc_fmt_string;
685 * Wrap long lines from word boundaries. The default is character wrap.
689 * AcceptCompositeCharacters: bool
691 * Specify whatever we accept composite characters or should them be
692 * considered as non-existent. As a default, do not accept them.
694 int accept_composites = 0;
699 * Append ^D character to the end of the output. Some printers require this
700 * but the default is false.
702 int append_ctrl_D = 0;
707 * Specify how characters greater than 127 are printed.
714 * Specify what to do when a formfeed character is encountered from the
715 * input stream. The default action is to jump to the beginning of the
718 FormFeedType formfeed_type = FORMFEED_COLUMN;
721 * GeneratePageSize: bool
723 * Specify whether the `PageSize' pagedevice definitions should be
724 * generated to the output.
726 int generate_PageSize = 1;
729 * NoJobHeaderSwitch: switch
731 * Spooler switch to suppress the job header (-h).
733 char *no_job_header_switch = NULL;
736 * OutputFirstLine: line
738 * Set the PostScript output's first line to something your system can handle.
739 * The default is "%!PS-Adobe-3.0"
741 char *output_first_line = NULL;
746 * The spooler command switch to select the printer queue (-P).
748 char *queue_param = NULL;
753 * The spooler command name (lpr).
755 char *spooler_command = NULL;
760 * An absolute path to the `states' binary.
763 char *states_binary = NULL;
768 * Should the States program generate color outputs.
770 int states_color = 0;
773 * StatesConfigFile: file
775 * The name of the states' configuration file.
777 char *states_config_file = NULL;
780 * StatesHighlightStyle: style
782 * The highlight style.
784 char *states_highlight_style = NULL;
789 * Define the path for the states program. The states program will
790 * lookup its state definition files from this path.
792 char *states_path = NULL;
794 /* ^@shade{GRAY}, set the line highlight gray. */
795 double line_highlight_gray = 1.0;
797 /* ^@bggray{GRAY}, set the text background gray. */
800 EncodingRegistry encodings[] =
802 {{"88591", "latin1", NULL}, ENC_ISO_8859_1, '\n', 8},
803 {{"88592", "latin2", NULL}, ENC_ISO_8859_2, '\n', 8},
804 {{"88593", "latin3", NULL}, ENC_ISO_8859_3, '\n', 8},
805 {{"88594", "latin4", NULL}, ENC_ISO_8859_4, '\n', 8},
806 {{"88595", "cyrillic", NULL}, ENC_ISO_8859_5, '\n', 8},
807 {{"88597", "greek", NULL}, ENC_ISO_8859_7, '\n', 8},
808 {{"88599", "latin5", NULL}, ENC_ISO_8859_9, '\n', 8},
809 {{"885910", "latin6", NULL}, ENC_ISO_8859_10, '\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},
821 {{NULL, NULL, NULL}, 0, 0, 0},
829 static struct option long_options[] =
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", no_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'},
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},
912 /* Backwards compatiblity options. */
913 {"pretty-print", optional_argument, 0, 'E'},
914 {"help-pretty-print", no_argument, 0, 141},
925 main (int argc, char *argv[])
938 /* Init our dynamic memory buffer. */
939 buffer_init (&buffer);
941 /* Get program's name. */
942 program = strrchr (argv[0], '/');
948 /* Make getopt_long() to use our modified programname. */
951 /* Create version strings. */
953 buffer_clear (&buffer);
954 buffer_append (&buffer, "GNU ");
955 buffer_append (&buffer, PACKAGE);
956 buffer_append (&buffer, " ");
957 buffer_append (&buffer, VERSION);
958 version_string = buffer_copy (&buffer);
960 ps_version_string = xstrdup (VERSION);
961 cp = strrchr (ps_version_string, '.');
964 /* Create the default TOC format string. Wow, this is cool! */
965 /* xgettext:no-c-format */
966 toc_fmt_string = _("$3v $-40N $3% pages $4L lines $E $C");
968 /* Internationalization. */
971 * We want to change only messages (gs do not like decimals in 0,1
975 setlocale (LC_MESSAGES, "");
979 bindtextdomain (PACKAGE, LOCALEDIR);
980 textdomain (PACKAGE);
983 /* Create date string. */
986 tm = localtime (&tim);
987 memcpy (&run_tm, tm, sizeof (*tm));
989 date_string = xstrdup (asctime (&run_tm));
990 i = strlen (date_string);
991 date_string[i - 1] = '\0';
993 /* Get user's passwd entry. */
994 passwd = getpwuid (getuid ());
996 FATAL ((stderr, _("couldn't get passwd entry for uid=%d: %s"), getuid (),
999 /* Defaults for some options. */
1000 media_name = xstrdup ("A4");
1001 encoding_name = xstrdup ("88591");
1002 npf_name = xstrdup ("octal");
1003 page_label_format = xstrdup ("short");
1004 ul_style_str = xstrdup ("outline");
1005 ul_position = xstrdup ("+0-0");
1006 spooler_command = xstrdup ("lpr");
1007 queue_param = xstrdup ("-P");
1008 no_job_header_switch = xstrdup ("-h");
1009 fancy_header_default = xstrdup ("enscript");
1010 output_first_line = xstrdup ("%!PS-Adobe-3.0");
1012 /* Check ENSCRIPT_LIBRARY for custom library location. */
1013 cp = getenv ("ENSCRIPT_LIBRARY");
1015 enscript_library = cp;
1017 /* Fill up build-in libpath. */
1019 cp = getenv ("HOME");
1021 cp = passwd->pw_dir;
1023 buffer_clear (&buffer);
1024 buffer_append (&buffer, enscript_library);
1025 buffer_append (&buffer, PATH_SEPARATOR_STR);
1026 buffer_append (&buffer, cp);
1027 buffer_append (&buffer, "/.enscript");
1028 libpath = buffer_copy (&buffer);
1030 /* Defaults for the states filter. */
1032 states_binary = xstrdup ("states"); /* Take it from the user path. */
1034 buffer_clear (&buffer);
1035 buffer_append (&buffer, enscript_library);
1036 buffer_append (&buffer, "/hl/enscript.st");
1037 states_config_file = buffer_copy (&buffer);
1039 states_highlight_style = xstrdup ("emacs");
1041 /* The <cp> holds the user's home directory. */
1042 buffer_clear (&buffer);
1043 buffer_append (&buffer, cp);
1044 buffer_append (&buffer, "/.enscript");
1045 buffer_append (&buffer, PATH_SEPARATOR_STR);
1046 buffer_append (&buffer, enscript_library);
1047 buffer_append (&buffer, "/hl");
1048 states_path = buffer_copy (&buffer);
1050 /* Initialize resource sets. */
1051 res_fonts = strhash_init ();
1052 download_fonts = strhash_init ();
1053 pagedevice = strhash_init ();
1054 statusdict = strhash_init ();
1055 user_strings = strhash_init ();
1059 * Read configuration files.
1062 /* Global config. */
1063 #define CFG_FILE_NAME "enscript.cfg"
1064 if (!read_config (SYSCONFDIR, CFG_FILE_NAME))
1066 int saved_errno = errno;
1068 /* Try to read it from our library directory. This is mostly
1069 the case for the micro ports. */
1070 if (!read_config (enscript_library, CFG_FILE_NAME))
1072 /* Try `enscript_library/../../etc/'. This is the case for
1073 installations which set the prefix after the compilation
1074 and our SYSCONFDIR points to wrong directory. */
1076 buffer_clear (&buffer);
1077 buffer_append (&buffer, enscript_library);
1078 buffer_append (&buffer, "/../../etc");
1080 if (!read_config (buffer_ptr (&buffer), CFG_FILE_NAME))
1082 /* Maybe we are not installed yet, let's try `../lib'
1084 if (!read_config ("../lib", CFG_FILE_NAME)
1085 && !read_config ("../../lib", CFG_FILE_NAME))
1087 /* No luck, report error from the original config file. */
1088 ERROR ((stderr, _("couldn't read config file \"%s/%s\": %s"),
1089 enscript_library, CFG_FILE_NAME,
1090 strerror (saved_errno)));
1092 _("I did also try the following directories:")));
1093 ERROR ((stderr, _("\t%s"), SYSCONFDIR));
1094 ERROR ((stderr, _("\t%s"), enscript_library));
1095 ERROR ((stderr, _("\t%s"), buffer_ptr (&buffer)));
1096 ERROR ((stderr, _("\t../lib")));
1097 ERROR ((stderr, _("\t../../lib")));
1099 _("This is probably an installation error. Please, try to rebuild:")));
1100 ERROR ((stderr, _("\tmake distclean")));
1101 ERROR ((stderr, _("\t./configure --prefix=PREFIX")));
1102 ERROR ((stderr, _("\tmake")));
1103 ERROR ((stderr, _("\tmake check")));
1104 ERROR ((stderr, _("\tmake install")));
1106 _("or set the environment variable `ENSCRIPT_LIBRARY' to point to your")));
1108 _("library directory.")));
1112 /* Ok, we are not installed yet. Here is a small kludge
1113 to conform the GNU coding standards: we must be able
1114 to run without being installed, so we must append the
1115 `../lib' and `../../lib' directories to the libpath.
1116 The later allows us to be run form the `src/tests'
1118 buffer_clear (&buffer);
1119 buffer_append (&buffer, libpath);
1120 buffer_append (&buffer, PATH_SEPARATOR_STR);
1121 buffer_append (&buffer, "../lib");
1122 buffer_append (&buffer, PATH_SEPARATOR_STR);
1123 buffer_append (&buffer, "../../lib");
1126 libpath = buffer_copy (&buffer);
1132 (void) read_config (SYSCONFDIR, "enscriptsite.cfg");
1134 /* Personal config. */
1135 (void) read_config (passwd->pw_dir, ".enscriptrc");
1141 /* Environment variables. */
1142 handle_env_options ("ENSCRIPT");
1143 handle_env_options ("GENSCRIPT");
1145 /* Command line arguments. */
1146 handle_options (argc, argv);
1149 * Check options which have some validity conditions.
1153 * Save the user-specified escape char so ^@escape{default} knows
1156 default_escape_char = escape_char;
1158 /* Input encoding. */
1161 for (i = 0; !found && encodings[i].names[0]; i++)
1162 for (j = 0; j < 3; j++)
1163 if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j],
1166 /* Found a match for this encoding. Use the first
1169 encoding = encodings[i].encoding;
1170 xfree (encoding_name);
1171 encoding_name = xstrdup (encodings[i].names[0]);
1174 nl = encodings[i].nl;
1175 bs = encodings[i].bs;
1180 FATAL ((stderr, _("unknown encoding: %s"), encoding_name));
1184 /* Default font for landscape, 2 column printing is Courier 7. */
1185 if (!user_body_font_defined && landscape && num_columns > 1)
1186 Fpt.w = Fpt.h = 7.0;
1188 /* Cache for font AFM information. */
1189 afm_cache = strhash_init ();
1190 afm_info_cache = strhash_init ();
1192 /* Open AFM library. */
1193 afm_error = afm_create (afm_path, verbose, &afm);
1194 if (afm_error != AFM_SUCCESS)
1198 afm_error_to_string (afm_error, buf);
1199 FATAL ((stderr, _("couldn't open AFM library: %s"), buf));
1203 * Save default Fpt and Fname since special escape 'font' can change
1204 * it and later we might want to switch back to the "default" font.
1206 default_Fpt.w = Fpt.w;
1207 default_Fpt.h = Fpt.h;
1208 default_Fname = Fname;
1209 default_Fencoding = encoding;
1211 /* Register that document uses at least these fonts. */
1212 strhash_put (res_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
1213 strhash_put (res_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
1215 /* As a default, download both named fonts. */
1216 strhash_put (download_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
1217 strhash_put (download_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
1219 /* Read font's character widths and character types. */
1222 /* Count the line indentation. */
1223 line_indent = parse_float (line_indent_spec, 1, 1);
1225 /* List media names. */
1228 printf (_("known media:\n\
1229 name width\theight\tllx\tlly\turx\tury\n\
1230 ------------------------------------------------------------\n"));
1231 for (mentry = media_names; mentry; mentry = mentry->next)
1232 printf ("%-16s %d\t%d\t%d\t%d\t%d\t%d\n",
1233 mentry->name, mentry->w, mentry->h,
1234 mentry->llx, mentry->lly, mentry->urx, mentry->ury);
1235 /* Exit after listing. */
1240 for (mentry = media_names; mentry; mentry = mentry->next)
1241 if (strcmp (media_name, mentry->name) == 0)
1247 FATAL ((stderr, _("do not know anything about media \"%s\""), media_name));
1251 /* Adjust marginals. */
1252 for (i = 0; i < 4; i++)
1254 if (*margins_spec == '\0')
1258 if (*margins_spec == ':')
1264 j = atoi (margins_spec);
1265 for (; *margins_spec != ':' && *margins_spec != '\0'; margins_spec++)
1267 if (*margins_spec == ':')
1277 media->urx = media->w - j;
1281 media->ury = media->h - j;
1284 case 3: /* bottom */
1291 _("set new marginals for media `%s' (%dx%d): llx=%d, lly=%d, urx=%d, ury=%d\n"),
1292 media->name, media->w, media->h, media->llx, media->lly,
1293 media->urx, media->ury));
1296 /* Page label format. */
1297 if (MATCH (page_label_format, "short"))
1298 page_label = LABEL_SHORT;
1299 else if (MATCH (page_label_format, "long"))
1300 page_label = LABEL_LONG;
1302 FATAL ((stderr, _("illegal page label format \"%s\""), page_label_format));
1304 /* Non-printable format. */
1305 if (MATCH (npf_name, "space"))
1306 non_printable_format = NPF_SPACE;
1307 else if (MATCH (npf_name, "questionmark"))
1308 non_printable_format = NPF_QUESTIONMARK;
1309 else if (MATCH (npf_name, "caret"))
1310 non_printable_format = NPF_CARET;
1311 else if (MATCH (npf_name, "octal"))
1312 non_printable_format = NPF_OCTAL;
1314 FATAL ((stderr, _("illegal non-printable format \"%s\""), npf_name));
1316 /* Mark wrapped lines style. */
1317 if (mark_wrapped_lines_style_name)
1319 if (MATCH (mark_wrapped_lines_style_name, "none"))
1320 mark_wrapped_lines_style = MWLS_NONE;
1321 else if (MATCH (mark_wrapped_lines_style_name, "plus"))
1322 mark_wrapped_lines_style = MWLS_PLUS;
1323 else if (MATCH (mark_wrapped_lines_style_name, "box"))
1324 mark_wrapped_lines_style = MWLS_BOX;
1325 else if (MATCH (mark_wrapped_lines_style_name, "arrow"))
1326 mark_wrapped_lines_style = MWLS_ARROW;
1328 FATAL ((stderr, _("illegal style for wrapped line marker: \"%s\""),
1329 mark_wrapped_lines_style_name));
1332 /* Count N-up stuffs. */
1338 FATAL ((stderr, _("illegal N-up argument: %d"), nup));
1343 FATAL ((stderr, _("N-up argument must be power of 2: %d"), nup));
1350 nup_rows = nup_exp / 2 * 2;
1353 nup_columns = (nup_exp + 1) / 2 * 2;
1354 if (nup_columns == 0)
1357 nup_landscape = nup_exp & 0x1;
1361 * Count output media dimensions.
1366 d_page_w = media->ury - media->lly;
1367 d_page_h = media->urx - media->llx;
1371 d_page_w = media->urx - media->llx;
1372 d_page_h = media->ury - media->lly;
1376 * Count N-up page width, height and scale.
1381 nup_width = media->ury - media->lly;
1382 nup_height = media->urx - media->llx;
1386 nup_width = media->urx - media->llx;
1387 nup_height = media->ury - media->lly;
1393 w = ((double) nup_width - (nup_columns - 1) * nup_xpad) / nup_columns;
1394 h = ((double) nup_height - (nup_rows - 1) * nup_ypad) / nup_rows;
1399 w = w / (media->urx - media->llx);
1400 h = h / (media->ury - media->lly);
1402 nup_scale = w < h ? w : h;
1406 * Underlay (this must come after output media dimensions, because
1407 * `underlay position' needs them).
1409 if (underlay != NULL)
1411 strhash_put (res_fonts, ul_font, strlen (ul_font) + 1, NULL, NULL);
1412 underlay = escape_string (underlay);
1415 /* Underlay X-coordinate. */
1416 ul_x = strtod (ul_position, &cp);
1417 if (cp == ul_position)
1420 FATAL ((stderr, _("malformed underlay position: %s"), ul_position));
1422 if (ul_position[0] == '-')
1425 /* Underlay Y-coordinate. */
1426 ul_y = strtod (cp, &cp2);
1428 goto malformed_position;
1432 /* Underlay Angle. */
1434 /* No angle given, count the default. */
1435 ul_angle = (atan2 (-d_page_h, d_page_w) / 3.14159265 * 180);
1437 /* Underlay style. */
1438 if (strcmp (ul_style_str, "outline") == 0)
1439 ul_style = UL_STYLE_OUTLINE;
1440 else if (strcmp (ul_style_str, "filled") == 0)
1441 ul_style = UL_STYLE_FILLED;
1443 FATAL ((stderr, _("illegal underlay style: %s"), ul_style_str));
1446 * Header. Note! The header attributes can be changed from
1447 * the `.hdr' files, these are only the defaults.
1450 d_header_w = d_page_w;
1458 d_header_h = HFpt.h * 1.5;
1466 /* Help highlight. */
1469 /* Create description with states. */
1470 printf (_("Highlighting is supported for the following languages and file formats:\n\n"));
1473 buffer_clear (&buffer);
1474 buffer_append (&buffer, states_binary);
1475 buffer_append (&buffer, " -f \"");
1476 buffer_append (&buffer, states_config_file);
1477 buffer_append (&buffer, "\" -p \"");
1478 buffer_append (&buffer, states_path);
1479 buffer_append (&buffer, "\" -s describe_languages ");
1480 buffer_append (&buffer, enscript_library);
1481 buffer_append (&buffer, "/hl/*.st");
1483 system (buffer_ptr (&buffer));
1488 * And now to the main business. The actual input file processing
1489 * is divided to two parts: PostScript generation and everything else.
1490 * The PostScript generation is handled in the conventional way, we
1491 * process the input and generate PostScript. However all other input
1492 * languages will be handled with States, we only pass enscript's
1493 * options to the states pre-filter and dump output.
1495 if (output_language_pass_through)
1501 /* The States output generation. */
1503 /* Resolve the start state. */
1505 start_state = hl_start_state;
1509 start_state = "passthrough";
1511 /* Create the states command. */
1515 buffer_append (&cmd, states_binary);
1516 buffer_append (&cmd, " -f \"");
1517 buffer_append (&cmd, states_config_file);
1518 buffer_append (&cmd, "\" -p \"");
1519 buffer_append (&cmd, states_path);
1520 buffer_append (&cmd, "\" ");
1523 buffer_append (&cmd, "-v ");
1527 buffer_append (&cmd, "-s");
1528 buffer_append (&cmd, start_state);
1529 buffer_append (&cmd, " ");
1532 buffer_append (&cmd, "-Dcolor=");
1533 buffer_append (&cmd, states_color ? "1" : "0");
1534 buffer_append (&cmd, " ");
1536 buffer_append (&cmd, "-Dstyle=");
1537 buffer_append (&cmd, states_highlight_style);
1538 buffer_append (&cmd, " ");
1540 buffer_append (&cmd, "-Dlanguage=");
1541 buffer_append (&cmd, output_language);
1542 buffer_append (&cmd, " ");
1544 buffer_append (&cmd, "-Dnum_input_files=");
1545 sprintf (intbuf, "%d", optind == argc ? 1 : argc - optind);
1546 buffer_append (&cmd, intbuf);
1547 buffer_append (&cmd, " ");
1549 buffer_append (&cmd, "-Ddocument_title=\"");
1550 buffer_append (&cmd, title);
1551 buffer_append (&cmd, "\" ");
1553 buffer_append (&cmd, "-Dtoc=");
1554 buffer_append (&cmd, toc ? "1" : "0");
1556 /* Additional options for states? */
1557 if (helper_options['s'])
1559 Buffer *opts = helper_options['s'];
1561 buffer_append (&cmd, " ");
1562 buffer_append_len (&cmd, buffer_ptr (opts), buffer_len (opts));
1565 /* Append input files. */
1566 for (i = optind; i < argc; i++)
1568 buffer_append (&cmd, " ");
1569 buffer_append (&cmd, argv[i]);
1572 /* And do the job. */
1573 if (is_open (&is, stdin, NULL, buffer_ptr (&cmd)))
1575 open_output_file ();
1576 process_file ("unused", &is, 0);
1580 buffer_uninit (&cmd);
1584 /* The conventional way. */
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, "\"");
1601 buffer_append (&buffer, " -v");
1605 buffer_append (&buffer, " -s ");
1606 buffer_append (&buffer, hl_start_state);
1609 buffer_append (&buffer, " -Dcolor=");
1610 buffer_append (&buffer, states_color ? "1" : "0");
1612 buffer_append (&buffer, " -Dstyle=");
1613 buffer_append (&buffer, states_highlight_style);
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);
1620 /* Additional options for states? */
1621 if (helper_options['s'])
1623 Buffer *opts = helper_options['s'];
1625 buffer_append (&buffer, " ");
1626 buffer_append_len (&buffer,
1627 buffer_ptr (opts), buffer_len (opts));
1630 buffer_append (&buffer, " \"%s\"");
1632 input_filter = buffer_copy (&buffer);
1633 input_filter_stdin = "-";
1636 /* Table of Contents. */
1639 toc_fp = tmpfile ();
1641 FATAL ((stderr, _("couldn't create temporary toc file: %s"),
1652 /* stdin's modification time is the current time. */
1653 memcpy (&mod_tm, &run_tm, sizeof (run_tm));
1655 if (is_open (&is, stdin, NULL, input_filter))
1657 /* Open output file. */
1658 open_output_file ();
1659 process_file (title_given ? title : "", &is, 0);
1665 for (; optind < argc; optind++)
1667 if (is_open (&is, NULL, argv[optind], input_filter))
1669 struct stat stat_st;
1671 /* Get modification time. */
1672 if (stat (argv[optind], &stat_st) == 0)
1674 tim = stat_st.st_mtime;
1675 tm = localtime (&tim);
1676 memcpy (&mod_tm, tm, sizeof (*tm));
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.
1683 open_output_file ();
1685 process_file (argv[optind], &is, 0);
1688 ERROR ((stderr, _("couldn't stat input file \"%s\": %s"),
1697 /* Table of Contents. */
1700 /* This is really cool... */
1702 /* Set the printing options for toc. */
1704 special_escapes = 1;
1707 if (fseek (toc_fp, 0, SEEK_SET) != 0)
1708 FATAL ((stderr, _("couldn't rewind toc file: %s"),
1711 memcpy (&mod_tm, &run_tm, sizeof (run_tm));
1712 if (is_open (&is, toc_fp, NULL, NULL))
1714 process_file (_("Table of Contents"), &is, 1);
1719 /* Give trailer a chance to dump itself. */
1723 * Append ^D to the end of the output? Note! It must be ^D followed
1726 if (ofp != NULL && append_ctrl_D)
1727 fprintf (ofp, "\004\n");
1730 /* Close output file. */
1731 close_output_file ();
1733 /* Tell how things went. */
1737 * The value of <ofp> is not reset in close_output_file(),
1738 * this is ugly but it saves one flag.
1740 MESSAGE (0, (stderr, _("no output generated\n")));
1742 else if (output_language_pass_through)
1744 if (output_file == OUTPUT_FILE_NONE)
1745 MESSAGE (0, (stderr, _("output sent to %s\n"),
1746 printer ? printer : _("printer")));
1748 MESSAGE (0, (stderr, _("output left in %s\n"),
1749 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1753 unsigned int real_total_pages;
1757 if (total_pages > 0)
1758 real_total_pages = (total_pages - 1) / nup + 1;
1760 real_total_pages = 0;
1763 real_total_pages = total_pages;
1765 /* We did something, tell what. */
1766 MESSAGE (0, (stderr, _("[ %d pages * %d copy ]"), real_total_pages,
1768 if (output_file == OUTPUT_FILE_NONE)
1769 MESSAGE (0, (stderr, _(" sent to %s\n"),
1770 printer ? printer : _("printer")));
1772 MESSAGE (0, (stderr, _(" left in %s\n"),
1773 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1774 if (num_truncated_lines)
1777 MESSAGE (0, (stderr, _("%d lines were %s\n"), num_truncated_lines,
1778 line_end == LE_TRUNCATE
1779 ? _("truncated") : _("wrapped")));
1782 if (num_missing_chars)
1785 MESSAGE (0, (stderr, _("%d characters were missing\n"),
1786 num_missing_chars));
1787 if (list_missing_characters)
1789 MESSAGE (0, (stderr, _("missing character codes (decimal):\n")));
1790 do_list_missing_characters (missing_chars);
1794 if (num_non_printable_chars)
1797 MESSAGE (0, (stderr, _("%d non-printable characters\n"),
1798 num_non_printable_chars));
1799 if (list_missing_characters)
1801 MESSAGE (0, (stderr,
1802 _("non-printable character codes (decimal):\n")));
1803 do_list_missing_characters (non_printable_chars);
1808 /* Uninit our dynamic memory buffer. */
1809 buffer_uninit (&buffer);
1811 /* Return the extended return values only if requested. */
1812 if (!extended_return_values)
1815 /* This is the end. */
1828 /* Output file has already been opened, do nothing. */
1831 if (output_file == OUTPUT_FILE_NONE)
1833 char spooler_options[512];
1835 /* Format spooler options. */
1836 spooler_options[0] = '\0';
1838 strcat (spooler_options, "-m ");
1841 strcat (spooler_options, no_job_header_switch);
1842 strcat (spooler_options, " ");
1844 if (printer_options)
1845 strcat (spooler_options, printer_options);
1848 ofp = printer_open (spooler_command, spooler_options, queue_param,
1849 printer, &printer_context);
1851 FATAL ((stderr, _("couldn't open printer `%s': %s"), printer,
1854 else if (output_file == OUTPUT_FILE_STDOUT)
1858 ofp = fopen (output_file, "w");
1860 FATAL ((stderr, _("couldn't create output file \"%s\": %s"),
1861 output_file, strerror (errno)));
1867 close_output_file ()
1870 /* Output file hasn't been opened, we are done. */
1873 if (output_file == OUTPUT_FILE_NONE)
1874 printer_close (printer_context);
1875 else if (output_file != OUTPUT_FILE_STDOUT)
1877 FATAL ((stderr, _("couldn't close output file \"%s\": %s"),
1878 output_file, strerror (errno)));
1880 /* We do not reset <ofp> since its value is needed in diagnostigs. */
1885 handle_env_options (char *var)
1893 string = getenv (var);
1897 MESSAGE (2, (stderr, "handle_env_options(): %s=\"%s\"\n", var, string));
1899 /* Copy string so we can modify it in place. */
1900 str = xstrdup (string);
1903 * We can count this, each option takes at least 1 character and one
1904 * space. We also need one for program's name and one for the
1907 argc = (strlen (str) + 1) / 2 + 2;
1908 argv = xcalloc (argc, sizeof (char *));
1910 /* Set program name. */
1912 argv[argc++] = program;
1914 /* Split string and set arguments to argv array. */
1918 /* Skip leading whitespace. */
1919 for (; str[i] && isspace (str[i]); i++)
1924 /* Check for quoted arguments. */
1925 if (str[i] == '"' || str[i] == '\'')
1927 int endch = str[i++];
1929 argv[argc++] = str + i;
1931 /* Skip until we found the end of the quotation. */
1932 for (; str[i] && str[i] != endch; i++)
1935 FATAL ((stderr, _("syntax error in option string %s=\"%s\":\n\
1936 missing end of quotation: %c"), var, string, endch));
1942 argv[argc++] = str + i;
1944 /* Skip until whitespace if found. */
1945 for (; str[i] && !isspace (str[i]); i++)
1952 /* argv[argc] must be NULL. */
1955 MESSAGE (2, (stderr, "found following options (argc=%d):\n", argc));
1956 for (i = 0; i < argc; i++)
1957 MESSAGE (2, (stderr, "%3d = \"%s\"\n", i, argv[i]));
1959 /* Process options. */
1960 handle_options (argc, argv);
1962 /* Check that all got processed. */
1967 _("warning: didn't process following options from \
1968 environment variable %s:\n"),
1970 for (; optind < argc; optind++)
1971 MESSAGE (0, (stderr, _(" option %d = \"%s\"\n"), optind,
1979 * <str> must not be freed, since some global variables can point to
1986 handle_options (int argc, char *argv[])
1996 int option_index = 0;
2000 c = getopt_long (argc, argv,
2001 "#:123456789a:A:b:BcC::d:D:e::E::f:F:gGhH::i:I:jJ:kKlL:mM:n:N:o:Op:P:qrRs:S:t:T:u::U:vVW:X:zZ",
2002 long_options, &option_index);
2009 case 0: /* Long option found. */
2010 cp = long_options[option_index].name;
2012 if (strcmp (cp, "columns") == 0)
2014 num_columns = atoi (optarg);
2015 if (num_columns < 1)
2017 _("number of columns must be larger than zero")));
2021 /* Short options. */
2023 case '1': /* 1 column */
2024 case '2': /* 2 columns */
2025 case '3': /* 3 columns */
2026 case '4': /* 4 columns */
2027 case '5': /* 5 columns */
2028 case '6': /* 6 columns */
2029 case '7': /* 7 columns */
2030 case '8': /* 8 columns */
2031 case '9': /* 9 columns */
2032 num_columns = c - '0';
2035 case 'a': /* pages */
2036 prange = (PageRange *) xcalloc (1, sizeof (PageRange));
2038 if (strcmp (optarg, "odd") == 0)
2040 else if (strcmp (optarg, "even") == 0)
2044 cp = strchr (optarg, '-');
2047 if (optarg[0] == '-')
2049 prange->end = atoi (optarg + 1);
2050 else if (cp[1] == '\0')
2053 prange->start = atoi (optarg);
2054 prange->end = (unsigned int) -1;
2059 prange->start = atoi (optarg);
2060 prange->end = atoi (cp + 1);
2065 prange->start = prange->end = atoi (optarg);
2068 prange->next = page_ranges;
2069 page_ranges = prange;
2072 case 'A': /* file alignment */
2073 file_align = atoi (optarg);
2074 if (file_align == 0)
2075 FATAL ((stderr, _("file alignment must be larger than zero")));
2078 case 'b': /* page header */
2079 page_header = optarg;
2082 case 'B': /* no page headers */
2086 case 'c': /* truncate (cut) long lines */
2087 line_end = LE_TRUNCATE;
2090 case 'C': /* line numbers */
2093 start_line_number = atoi (optarg);
2096 case 'd': /* specify printer */
2099 printer = xstrdup (optarg);
2100 output_file = OUTPUT_FILE_NONE;
2103 case 'D': /* setpagedevice */
2104 parse_key_value_pair (pagedevice, optarg);
2107 case 'e': /* special escapes */
2108 special_escapes = 1;
2111 /* Specify the escape character. */
2112 if (isdigit (optarg[0]))
2113 /* As decimal, octal, or hexadicimal number. */
2114 escape_char = (int) strtoul (optarg, NULL, 0);
2116 /* As character directly. */
2117 escape_char = ((unsigned char *) optarg)[0];
2121 case 'E': /* highlight */
2123 special_escapes = 1;
2125 hl_start_state = optarg;
2128 case 'f': /* font */
2129 if (!parse_font_spec (optarg, &Fname, &Fpt, NULL))
2130 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2131 user_body_font_defined = 1;
2134 case 'F': /* header font */
2135 if (!parse_font_spec (optarg, &HFname, &HFpt, NULL))
2136 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2139 case 'g': /* print anyway */
2143 case 'G': /* fancy header */
2146 fancy_header_name = optarg;
2148 fancy_header_name = fancy_header_default;
2150 if (!file_existsp (fancy_header_name, ".hdr"))
2152 _("couldn't find header definition file \"%s.hdr\""),
2153 fancy_header_name));
2156 case 'h': /* no job header */
2160 case 'H': /* highlight bars */
2162 highlight_bars = atoi (optarg);
2167 case 'i': /* line indent */
2168 line_indent_spec = optarg;
2171 case 'I': /* input filter */
2172 input_filter = optarg;
2175 case 'j': /* borders */
2179 case 'k': /* enable page prefeed */
2183 case 'K': /* disable page prefeed */
2187 case 'l': /* emulate lineprinter */
2188 lines_per_page = 66;
2192 case 'L': /* lines per page */
2193 lines_per_page = atoi (optarg);
2194 if (lines_per_page <= 0)
2196 _("must print at least one line per each page: %s"),
2200 case 'm': /* send mail upon completion */
2204 case 'M': /* select output media */
2205 media_name = xstrdup (optarg);
2208 case 'n': /* num copies */
2210 num_copies = atoi (optarg);
2213 case 'N': /* newline character */
2214 if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0')
2216 fprintf (stderr, _("%s: illegal newline character specifier: \
2217 '%s': expected 'n' or 'r'\n"),
2221 if (optarg[0] == 'n')
2228 case 'p': /* output file */
2229 /* Check output file "-". */
2230 if (strcmp (optarg, "-") == 0)
2231 output_file = OUTPUT_FILE_STDOUT;
2233 output_file = optarg;
2236 case 'O': /* list missing characters */
2237 list_missing_characters = 1;
2240 case 'q': /* quiet */
2245 case 'r': /* landscape */
2249 case 'R': /* portrait */
2253 case 's': /* baselineskip */
2254 baselineskip = atof (optarg);
2257 case 'S': /* statusdict */
2258 parse_key_value_pair (statusdict, optarg);
2261 case 't': /* title */
2267 case 'T': /* tabulator size */
2268 tabsize = atoi (optarg);
2273 case 'u': /* underlay */
2278 nup = atoi (optarg);
2281 case 'v': /* verbose */
2283 verbose = atoi (optarg);
2289 case 'V': /* version */
2294 case 'w': /* output language */
2295 output_language = optarg;
2296 if (strcmp (output_language, "PostScript") != 0)
2297 /* Other output languages are handled with states. */
2298 output_language_pass_through = 1;
2301 case 'W': /* a helper application option */
2302 cp = strchr (optarg, ',');
2305 _("malformed argument `%s' for option -W, --option: \
2309 if (cp - optarg != 1)
2310 FATAL ((stderr, _("helper application specification must be \
2311 single character: %s"),
2314 /* Take the index of the helper application and update `cp'
2315 to point to the beginning of the option. */
2319 if (helper_options[i] == NULL)
2320 helper_options[i] = buffer_alloc ();
2323 /* We already had some options for this helper
2324 application. Let's separate these arguments. */
2325 buffer_append (helper_options[i], " ");
2328 /* Add this new option. */
2329 buffer_append (helper_options[i], cp);
2332 case 'X': /* input encoding */
2333 xfree (encoding_name);
2334 encoding_name = xstrdup (optarg);
2337 case 'z': /* no form feeds */
2338 interpret_formfeed = 0;
2341 case 'Z': /* pass through */
2345 case 128: /* underlay font */
2346 if (!parse_font_spec (optarg, &ul_font, &ul_ptsize, NULL))
2347 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2350 case 129: /* underlay gray */
2351 ul_gray = atof (optarg);
2354 case 130: /* page label format */
2355 xfree (page_label_format);
2356 page_label_format = xstrdup (optarg);
2359 case 131: /* download font */
2360 strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL,
2364 case 132: /* underlay angle */
2365 ul_angle = atof (optarg);
2369 case 133: /* underlay position */
2370 xfree (ul_position);
2371 ul_position = xstrdup (optarg);
2375 case 134: /* non-printable format */
2377 npf_name = xstrdup (optarg);
2380 case 135: /* help */
2385 case 136: /* highlight bar gray */
2386 highlight_bar_gray = atof (optarg);
2389 case 137: /* underlay style */
2390 xfree (ul_style_str);
2391 ul_style_str = xstrdup (optarg);
2394 case 138: /* filter stdin */
2395 input_filter_stdin = optarg;
2398 case 139: /* extra options for the printer spooler */
2399 printer_options = optarg;
2402 case 140: /* slicing */
2404 slice = atoi (optarg);
2406 FATAL ((stderr, _("slice must be greater than zero")));
2409 case 141: /* help-highlight */
2413 case 142: /* States color? */
2417 states_color = atoi (optarg);
2420 case 143: /* mark-wrapped-lines */
2423 xfree (mark_wrapped_lines_style_name);
2424 mark_wrapped_lines_style_name = xstrdup (optarg);
2427 /* Set the system default. */
2428 mark_wrapped_lines_style = MWLS_BOX;
2431 case 144: /* adjust margins */
2432 margins_spec = optarg;
2435 case 145: /* N-up x-pad */
2436 nup_xpad = atoi (optarg);
2439 case 146: /* N-up y-pad */
2440 nup_ypad = atoi (optarg);
2443 case 147: /* word wrap */
2444 line_end = LE_WORD_WRAP;
2447 case 148: /* horizontal column height */
2448 horizontal_column_height = atof (optarg);
2449 formfeed_type = FORMFEED_HCOLUMN;
2452 case 149: /* PostScript language level */
2453 pslevel = atoi (optarg);
2456 case 150: /* rotate even-numbered pages */
2457 rotate_even_pages = 1;
2460 case 151: /* highlight style */
2461 xfree (states_highlight_style);
2462 states_highlight_style = xstrdup (optarg);
2465 case 152: /* N-up colunwise */
2469 case 153: /* swap even page margins */
2470 swap_even_page_margins = 1;
2473 case 154: /* extended return values */
2474 extended_return_values = 1;
2477 case 155: /* footer */
2478 page_footer = optarg;
2481 case 156: /* continuous page numbers */
2482 continuous_page_numbers = 1;
2485 case '?': /* Errors found during getopt_long(). */
2487 fprintf (stderr, _("Try `%s --help' for more information.\n"),
2493 printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c);
2495 printf (" with arg %s", optarg);
2497 FATAL ((stderr, "This is a bug!"));
2508 Usage: %s [OPTION]... [FILE]...\n\
2509 Mandatory arguments to long options are mandatory for short options too.\n\
2510 -# an alias for option -n, --copies\n\
2511 -1 same as --columns=1\n\
2512 -2 same as --columns=2\n\
2513 --columns=NUM specify the number of columns per page\n\
2514 -a, --pages=PAGES specify which pages are printed\n\
2515 -A, --file-align=ALIGN align separate input files to ALIGN\n\
2516 -b, --header=HEADER set page header\n\
2517 -B, --no-header no page headers\n\
2518 -c, --truncate-lines cut long lines (default is to wrap)\n\
2519 -C, --line-numbers[=START]\n\
2520 precede each line with its line number\n\
2521 -d an alias for option --printer\n\
2522 -D, --setpagedevice=KEY[:VALUE]\n\
2523 pass a page device definition to output\n\
2524 -e, --escapes[=CHAR] enable special escape interpretation\n"),
2528 -E, --highlight[=LANG] highlight source code\n"));
2531 -f, --font=NAME use font NAME for body text\n\
2532 -F, --header-font=NAME use font NAME for header texts\n\
2533 -g, --print-anyway nothing (compatibility option)\n\
2534 -G same as --fancy-header\n\
2535 --fancy-header[=NAME] select fancy page header\n\
2536 -h, --no-job-header suppress the job header page\n\
2537 -H, --highlight-bars=NUM specify how high highlight bars are\n\
2538 -i, --indent=NUM set line indent to NUM characters\n\
2539 -I, --filter=CMD read input files through input filter CMD\n\
2540 -j, --borders print borders around columns\n\
2541 -J, an alias for option --title\n\
2542 -k, --page-prefeed enable page prefeed\n\
2543 -K, --no-page-prefeed disable page prefeed\n\
2544 -l, --lineprinter simulate lineprinter, this is an alias for:\n\
2545 --lines-per-page=66, --no-header, --portrait,\n\
2549 -L, --lines-per-page=NUM specify how many lines are printed on each page\n\
2550 -m, --mail send mail upon completion\n\
2551 -M, --media=NAME use output media NAME\n\
2552 -n, --copies=NUM print NUM copies of each page\n\
2553 -N, --newline=NL select the newline character. Possible\n\
2554 values for NL are: n (`\\n') and r (`\\r').\n\
2555 -o an alias for option --output\n\
2556 -O, --missing-characters list missing characters\n\
2557 -p, --output=FILE leave output to file FILE. If FILE is `-',\n\
2558 leave output to stdout.\n\
2559 -P, --printer=NAME print output to printer NAME\n\
2560 -q, --quiet, --silent be really quiet\n\
2561 -r, --landscape print in landscape mode\n\
2562 -R, --portrait print in portrait mode\n"));
2565 -s, --baselineskip=NUM set baselineskip to NUM\n\
2566 -S, --statusdict=KEY[:VALUE]\n\
2567 pass a statusdict definition to the output\n\
2568 -t, --title=TITLE set banner page's job title to TITLE. Option\n\
2569 sets also the name of the input file stdin.\n\
2570 -T, --tabsize=NUM set tabulator size to NUM\n\
2571 -u, --underlay[=TEXT] print TEXT under every page\n\
2572 -U, --nup=NUM print NUM logical pages on each output page\n\
2573 -v, --verbose tell what we are doing\n\
2574 -V, --version print version number\n\
2575 -w, --language=LANG set output language to LANG\n\
2576 -W, --options=APP,OPTION pass option OPTION to helper application APP\n\
2577 -X, --encoding=NAME use input encoding NAME\n\
2578 -z, --no-formfeed do not interpret form feed characters\n\
2579 -Z, --pass-through pass through PostScript and PCL files\n\
2580 without any modifications\n"));
2582 printf (_("Long-only options:\n\
2583 --color[=bool] create color outputs with states\n\
2584 --continuous-page-numbers count page numbers across input files. Don't\n\
2585 restart numbering at beginning of each file.\n\
2586 --download-font=NAME download font NAME\n\
2587 --extended-return-values enable extended return values\n\
2588 --filter-stdin=NAME specify how stdin is shown to the input filter\n\
2589 --footer=FOOTER set page footer\n\
2590 --h-column-height=HEIGHT set the horizontal column height to HEIGHT\n\
2591 --help print this help and exit\n"));
2594 --help-highlight describe all supported --highlight languages\n\
2596 --highlight-bar-gray=NUM print highlight bars with gray NUM (0 - 1)\n\
2597 --list-media list names of all known media\n\
2598 --margins=LEFT:RIGHT:TOP:BOTTOM\n\
2599 adjust page marginals\n\
2600 --mark-wrapped-lines[STYLE]\n\
2601 mark wrapped lines in the output with STYLE\n\
2602 --non-printable-format=FMT specify how non-printable chars are printed\n"));
2605 --nup-columnwise layout pages in the N-up printing columnwise\n\
2606 --nup-xpad=NUM set the page x-padding of N-up printing to NUM\n\
2607 --nup-ypad=NUM set the page y-padding of N-up printing to NUM\n\
2608 --page-label-format=FMT set page label format to FMT\n\
2609 --ps-level=LEVEL set the PostScript language level that enscript\n\
2611 --printer-options=OPTIONS pass extra options to the printer command\n\
2612 --rotate-even-pages rotate even-numbered pages 180 degrees\n"));
2615 --slice=NUM print vertical slice NUM\n\
2616 --style=STYLE use highlight style STYLE\n\
2617 --swap-even-page-margins swap left and right side margins for each even\n\
2619 --toc print table of contents\n\
2620 --ul-angle=ANGLE set underlay text's angle to ANGLE\n\
2621 --ul-font=NAME print underlays with font NAME\n\
2622 --ul-gray=NUM print underlays with gray value NUM\n\
2623 --ul-position=POS set underlay's starting position to POS\n\
2624 --ul-style=STYLE print underlays with style STYLE\n\
2625 --word-wrap wrap long lines from word boundaries\n\
2628 printf (_("\nReport bugs to mtr@iki.fi.\n"));
2636 Copyright (C) 2003 Markku Rossi.\n\
2637 GNU enscript comes with NO WARRANTY, to the extent permitted by law.\n\
2638 You may redistribute copies of GNU enscript under the terms of the GNU\n\
2639 General Public License. For more information about these matters, see\n\
2640 the files named COPYING.\n",