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 * 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.
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.
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/>.
29 * Prototypes for static functions.
33 * Open output file according to user options. Void if output file
34 * has already been opened.
36 static void open_output_file ();
38 /* Close output file. */
39 static void close_output_file ();
41 /* Handle options from environment variable <var> */
42 static void handle_env_options ___P ((char *var));
44 /* Handle options from <argv> array. */
45 static void handle_options ___P ((int argc, char *argv[]));
47 /* Print usage info. */
50 /* Print version info. */
51 static void version ();
58 char *program; /* Program's name, used for messages. */
59 FILE *ofp = NULL; /* Output file. */
60 void *printer_context; /* Context for the printer. */
61 char *version_string = NULL; /* Enscript's version string. */
62 char *ps_version_string = NULL; /* Version string for PS procsets. */
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
69 /* Path to our library. */
70 char *enscript_library = LIBRARY;
72 /* Library lookup path. */
75 /* AFM library lookup path. */
76 char *afm_path = NULL;
78 MediaEntry *media_names = NULL; /* List of known media. */
79 MediaEntry *media = NULL; /* Entry for used media. */
80 int bs = 8; /* The backspace character. */
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. */
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 */
101 /* Document needed resources. */
102 StringHashPtr res_fonts; /* fonts */
104 /* Fonts to download. */
105 StringHashPtr download_fonts;
107 /* Additional key-value pairs, passed to the generated PostScript code. */
108 StringHashPtr pagedevice; /* for setpagedevice */
109 StringHashPtr statusdict; /* for statusdict */
111 /* User defined strings. */
112 StringHashPtr user_strings;
114 /* Cache for AFM files. */
115 StringHashPtr afm_cache = NULL;
116 StringHashPtr afm_info_cache = NULL;
118 /* AFM library handle. */
119 AFMHandle afm = NULL;
125 * Free single-letter options are: Q, x, y, Y
131 * An alias for -n, --copies.
135 * -1, -2, -3, -4, -5, -6, -7, -8, -9, --columns=NUM
137 * Number of columns per page. The default is 1 column.
142 * -a PAGES, --pages=PAGES
144 * Specify which pages are printed.
146 PageRange *page_ranges = NULL;
149 * -A ALIGN, --file-align=ALIGN
151 * Align input files to start from ALIGN page count. This is handy
152 * for two-side printings.
154 unsigned int file_align = 1;
157 * -b STRING, --header=STRING
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.
162 char *page_header = NULL;
167 * Do not print page headers.
171 * -c, --truncate-lines
173 * Truncate lines that are longer than the page width. Default is character
176 LineEndType line_end = LE_CHAR_WRAP;
179 * -C [START], --line-numbers[=START]
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
187 int line_numbers = 0;
188 unsigned int start_line_number = 1;
193 * Name of the printer to which output is send. Defaults to system's
196 char *printer = NULL;
199 * -e [CHAR], --escapes[=CHAR]
201 * Enable special escape ('\000') interpretation. If option CHAR is given
202 * it is assumed to specify the escape character.
204 int special_escapes = 0;
205 int escape_char = '\0';
206 int default_escape_char;
209 * -E [LANG], --highlight=[LANG] (deprecated --pretty-print[=LANG])
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.
219 char *hl_start_state = NULL;
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? */
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. */
241 * Select font to be used to print the standard simple header.
243 char *HFname = "Courier-Bold";
244 FontPoint HFpt = {10.0, 10.0};
249 * Print document even it contains binary data. This does nothing
250 * since enscript prints files anyway.
256 * Add a fancy header to top of every page. There are several header styles
257 * but the default is 'no fancy header'.
259 HeaderType header = HDR_SIMPLE;
260 char *fancy_header_name = NULL;
261 char *fancy_header_default = NULL;
264 * -h, --no-job-header
266 * Supress the job header page.
268 static int no_job_header = 0;
271 * -H num, --highlight-bars=num
273 * Print highlight bars under text. Bars will be <num> lines high.
274 * As a default, do not print bars.
276 unsigned int highlight_bars = 0;
281 * Indent every line this many characters.
283 double line_indent = 0.0;
284 char *line_indent_spec = "0";
287 * -I CMD, --filter=CMD
289 * Read input files through input filter CMD.
291 char *input_filter = NULL;
296 * Print borders around columns.
303 * An alias for -t, --title.
308 * -K, --no-page-prefeed
310 * Control page prefeed.
312 int page_prefeed = 0;
317 * Emulate lineprinter - make pages 66 lines long and omit headers.
321 * -L, --lines-per-page
323 * Specify how many lines should be printed on a single page. Normally
324 * enscript counts it from font point sizes.
326 unsigned int lines_per_page = (unsigned int) -1;
331 * Send mail notification to user after print job has been completed.
338 * Name of the output media. Default is A4.
340 char *media_name = NULL;
345 * Number of copies to print.
352 * Set the newline character: '\n' or '\r'. As a default, the newline
353 * character is specified by the input encoding.
360 * Leave output to the specified file. As a default result is spooled to
363 char *output_file = OUTPUT_FILE_NONE;
366 * -O, --missing-characters
368 * List all missing characters. Default is no listing.
370 int list_missing_characters = 0;
375 * Do not tell what we are doing. Default is to tell something but
384 * Print with page rotated 90 degrees (landscape mode). Default is
392 * Specify baselineskip value that is used when enscript moves to
393 * a new line. Current point movement is font_point_size + baselineskip.
395 double baselineskip = 1.0;
400 * Title which is printed to the banner page. If this option is given
401 * from the command line, this sets also the name of the stdin which
402 * is by the default "".
404 char *title = "Enscript Output";
410 * Specify tabulator size.
417 * Place text under every page. Default is no underlay.
420 FontPoint ul_ptsize = {200.0, 200.0};
421 char *ul_font = "Times-Roman";
422 char *underlay = NULL;
423 char *ul_position = NULL; /* Position info as a string. */
424 double ul_x; /* Position x-coordinate. */
425 double ul_y; /* Position y-coordinate. */
427 unsigned int ul_style = UL_STYLE_OUTLINE;
428 char *ul_style_str = NULL;
429 int ul_position_p = 0; /* Is ul-position given? */
430 int ul_angle_p = 0; /* Is ul-angle given? */
435 * Print NUM PostScript pages on each output page (n-up printing).
437 unsigned int nup = 1;
438 unsigned int nup_exp = 0;
439 unsigned int nup_rows = 1;
440 unsigned int nup_columns = 1;
441 int nup_landscape = 0;
442 unsigned int nup_width;
443 unsigned int nup_height;
449 * Tell what we are doing. Default is no verbose outputs.
456 * Print version information.
460 * -w LANGUAGE, --language=LANGUAGE
462 * Generate output for language LANGUAGE. The default is PostScript.
464 char *output_language = "PostScript";
465 int output_language_pass_through = 0;
468 * -W APP,option, --options=APP,OPTION
470 * Pass additional option to enscript's helper applications. The
471 * first part of the option's argument (APP) specifies the
472 * helper application to which the options are added. Currently the
473 * following helper application are defined:
477 Buffer *helper_options[256] = {0};
482 * Specifies input encoding. Default is ISO-8859.1.
484 InputEncoding encoding = ENC_ISO_8859_1;
485 char *encoding_name = NULL;
490 * Do not interpret form feed characters. As a default, form feed
491 * characters are interpreted.
493 int interpret_formfeed = 1;
498 * Pass through all PostScript and PCL files without any modifications.
499 * As a default, don't.
501 int pass_through = 0;
506 * Create color output with states?
510 * --continuous-page-numbers
512 * Count page numbers across input files. Don't restart numbering
513 * at beginning of each file.
515 int continuous_page_numbers = 0;
518 * --download-font=FONT
520 * Download font FONT to printer.
524 * --extended-return-values
526 * Enable extended return values.
528 int extended_return_values = 0;
533 * How stdin is shown to the filter command. The default is "" but
534 * some utilities might want it as "-".
536 char *input_filter_stdin = "";
541 * Set the string that is used as the page footer. As a default, the
542 * page has no footer. Setting this option does not necessary show
543 * any footer strings in the output. It depends on the selected
544 * header (`.hdr' file) whether it supports footer strings or not.
546 char *page_footer = NULL;
549 * --h-column-height=HEIGHT
551 * Set the horizontal column (channel) height to be HEIGHT. This option
552 * also sets the FormFeedType to `hcolumn'. The default value is set to be
553 * big enough to cause a jump to the next vertical column (100m).
555 double horizontal_column_height = 283465.0;
558 * --help-highlight (deprecated --help-pretty-print)
560 * Descript all supported -E, --highlight languages and file formats.
562 int help_highlight = 0;
565 * --highlight-bar-gray=val
567 * Specify the gray level for highlight bars.
569 double highlight_bar_gray = .97;
574 * List all known media. As a default do not list media names.
579 * --margins=LEFT:RIGHT:TOP:BOTTOM
581 * Adjust page marginals.
583 char *margins_spec = NULL;
586 * --mark-wrapped-lines[=STYLE]
588 * Mark wrapped lines so that they can be easily detected from the printout.
589 * Optional parameter STYLE specifies the marking style, the system default
592 char *mark_wrapped_lines_style_name = NULL;
593 MarkWrappedLinesStyle mark_wrapped_lines_style = MWLS_NONE;
596 * --non-printable-format=FORMAT
598 * Format in which non-printable characters are printed.
600 char *npf_name = NULL;
601 NonPrintableFormat non_printable_format = NPF_OCTAL;
606 * Layout N-up pages colunwise instead of row-wise.
608 int nup_columnwise = 0;
613 * The x-padding between N-up subpages.
615 unsigned int nup_xpad = 10;
620 * The y-padding between N-up subpages.
622 unsigned int nup_ypad = 10;
625 * --page-label-format=FORMAT
627 * Format in which page labels are printed; the default is "short".
629 char *page_label_format = NULL;
630 PageLabelFormat page_label;
635 * The PostScript language level that enscript should use; the default is 2.
637 unsigned int pslevel = 2;
640 * --printer-options=OPTIONS
642 * Pass extra options OPTIONS to the printer spooler.
644 char *printer_options = NULL;
647 * --rotate-even-pages
649 * Rotate each even-numbered page 180 degrees. This might be handy in
650 * two-side printing when the resulting pages are bind from some side.
651 * Greetings to Jussi-Pekka Sairanen.
653 int rotate_even_pages = 0;
658 * Horizontal input slicing. Print only NUMth wrapped input pages.
661 unsigned int slice = 1;
664 * --swap-even-page-margins
666 * Swap left and right side margins for each even numbered page. This
667 * might be handy in two-side printing.
669 int swap_even_page_margins = 0;
674 * Print Table of Contents page.
678 char *toc_fmt_string;
683 * Wrap long lines from word boundaries. The default is character wrap.
687 * AcceptCompositeCharacters: bool
689 * Specify whatever we accept composite characters or should them be
690 * considered as non-existent. As a default, do not accept them.
692 int accept_composites = 0;
697 * Append ^D character to the end of the output. Some printers require this
698 * but the default is false.
700 int append_ctrl_D = 0;
705 * Specify how characters greater than 127 are printed.
712 * Specify what to do when a formfeed character is encountered from the
713 * input stream. The default action is to jump to the beginning of the
716 FormFeedType formfeed_type = FORMFEED_COLUMN;
719 * GeneratePageSize: bool
721 * Specify whether the `PageSize' pagedevice definitions should be
722 * generated to the output.
724 int generate_PageSize = 1;
727 * NoJobHeaderSwitch: switch
729 * Spooler switch to suppress the job header (-h).
731 char *no_job_header_switch = NULL;
734 * OutputFirstLine: line
736 * Set the PostScript output's first line to something your system can handle.
737 * The default is "%!PS-Adobe-3.0"
739 char *output_first_line = NULL;
744 * The spooler command switch to select the printer queue (-P).
746 char *queue_param = NULL;
751 * The spooler command name (lpr).
753 char *spooler_command = NULL;
758 * An absolute path to the `states' binary.
761 char *states_binary = NULL;
766 * Should the States program generate color outputs.
768 int states_color = 0;
771 * StatesConfigFile: file
773 * The name of the states' configuration file.
775 char *states_config_file = NULL;
778 * StatesHighlightStyle: style
780 * The highlight style.
782 char *states_highlight_style = NULL;
787 * Define the path for the states program. The states program will
788 * lookup its state definition files from this path.
790 char *states_path = NULL;
792 /* ^@shade{GRAY}, set the line highlight gray. */
793 double line_highlight_gray = 1.0;
795 /* ^@bggray{GRAY}, set the text background gray. */
798 EncodingRegistry encodings[] =
800 {{"88591", "latin1", NULL}, ENC_ISO_8859_1, '\n', 8},
801 {{"88592", "latin2", NULL}, ENC_ISO_8859_2, '\n', 8},
802 {{"88593", "latin3", NULL}, ENC_ISO_8859_3, '\n', 8},
803 {{"88594", "latin4", NULL}, ENC_ISO_8859_4, '\n', 8},
804 {{"88595", "cyrillic", NULL}, ENC_ISO_8859_5, '\n', 8},
805 {{"88597", "greek", NULL}, ENC_ISO_8859_7, '\n', 8},
806 {{"88599", "latin5", NULL}, ENC_ISO_8859_9, '\n', 8},
807 {{"885910", "latin6", NULL}, ENC_ISO_8859_10, '\n', 8},
808 {{"ascii", NULL, NULL}, ENC_ASCII, '\n', 8},
809 {{"asciifise", "asciifi", "asciise"}, ENC_ASCII_FISE, '\n', 8},
810 {{"asciidkno", "asciidk", "asciino"}, ENC_ASCII_DKNO, '\n', 8},
811 {{"ibmpc", "pc", "dos"}, ENC_IBMPC, '\n', 8},
812 {{"mac", NULL, NULL}, ENC_MAC, '\r', 8},
813 {{"vms", NULL, NULL}, ENC_VMS, '\n', 8},
814 {{"hp8", NULL, NULL}, ENC_HP8, '\n', 8},
815 {{"koi8", NULL, NULL}, ENC_KOI8, '\n', 8},
816 {{"ps", "PS", NULL}, ENC_PS, '\n', 8},
817 {{"pslatin1", "ISOLatin1Encoding", NULL}, ENC_ISO_8859_1, '\n', 8},
819 {{NULL, NULL, NULL}, 0, 0, 0},
827 static struct option long_options[] =
829 {"columns", required_argument, 0, 0},
830 {"pages", required_argument, 0, 'a'},
831 {"file-align", required_argument, 0, 'A'},
832 {"header", required_argument, 0, 'b'},
833 {"no-header", no_argument, 0, 'B'},
834 {"truncate-lines", no_argument, 0, 'c'},
835 {"line-numbers", optional_argument, 0, 'C'},
836 {"printer", required_argument, 0, 'd'},
837 {"setpagedevice", required_argument, 0, 'D'},
838 {"escapes", optional_argument, 0, 'e'},
839 {"highlight", optional_argument, 0, 'E'},
840 {"font", required_argument, 0, 'f'},
841 {"header-font", required_argument, 0, 'F'},
842 {"print-anyway", no_argument, 0, 'g'},
843 {"fancy-header", optional_argument, 0, 'G'},
844 {"no-job-header", no_argument, 0, 'h'},
845 {"highlight-bars", optional_argument, 0, 'H'},
846 {"indent", required_argument, 0, 'i'},
847 {"filter", required_argument, 0, 'I'},
848 {"borders", no_argument, 0, 'j'},
849 {"page-prefeed", no_argument, 0, 'k'},
850 {"no-page-prefeed", no_argument, 0, 'K'},
851 {"lineprinter", no_argument, 0, 'l'},
852 {"lines-per-page", required_argument, 0, 'L'},
853 {"mail", no_argument, 0, 'm'},
854 {"media", required_argument, 0, 'M'},
855 {"copies", required_argument, 0, 'n'},
856 {"newline", required_argument, 0, 'N'},
857 {"output", required_argument, 0, 'p'},
858 {"missing-characters", no_argument, 0, 'O'},
859 {"quiet", no_argument, 0, 'q'},
860 {"silent", no_argument, 0, 'q'},
861 {"landscape", no_argument, 0, 'r'},
862 {"portrait", no_argument, 0, 'R'},
863 {"baselineskip", required_argument, 0, 's'},
864 {"statusdict", required_argument, 0, 'S'},
865 {"title", required_argument, 0, 't'},
866 {"tabsize", required_argument, 0, 'T'},
867 {"underlay", optional_argument, 0, 'u'},
868 {"nup", required_argument, 0, 'U'},
869 {"verbose", optional_argument, 0, 'v'},
870 {"version", no_argument, 0, 'V'},
871 {"language", required_argument, 0, 'w'},
872 {"option", required_argument, 0, 'W'},
873 {"encoding", required_argument, 0, 'X'},
874 {"no-formfeed", no_argument, 0, 'z'},
875 {"pass-through", no_argument, 0, 'Z'},
877 /* Long options without short counterparts. Next free is 157. */
878 {"color", optional_argument, 0, 142},
879 {"continuous-page-numbers", no_argument, 0, 156},
880 {"download-font", required_argument, 0, 131},
881 {"extended-return-values", no_argument, 0, 154},
882 {"filter-stdin", required_argument, 0, 138},
883 {"footer", required_argument, 0, 155},
884 {"h-column-height", required_argument, 0, 148},
885 {"help", no_argument, 0, 135},
886 {"help-highlight", no_argument, 0, 141},
887 {"highlight-bar-gray", required_argument, 0, 136},
888 {"list-media", no_argument, &list_media, 1},
889 {"margins", required_argument, 0, 144},
890 {"mark-wrapped-lines", optional_argument, 0, 143},
891 {"non-printable-format", required_argument, 0, 134},
892 {"nup-columnwise", no_argument, 0, 152},
893 {"nup-xpad", required_argument, 0, 145},
894 {"nup-ypad", required_argument, 0, 146},
895 {"page-label-format", required_argument, 0, 130},
896 {"ps-level", required_argument, 0, 149},
897 {"printer-options", required_argument, 0, 139},
898 {"rotate-even-pages", no_argument, 0, 150},
899 {"slice", required_argument, 0, 140},
900 {"style", required_argument, 0, 151},
901 {"swap-even-page-margins", no_argument, 0, 153},
902 {"toc", no_argument, &toc, 1},
903 {"word-wrap", no_argument, 0, 147},
904 {"ul-angle", required_argument, 0, 132},
905 {"ul-font", required_argument, 0, 128},
906 {"ul-gray", required_argument, 0, 129},
907 {"ul-position", required_argument, 0, 133},
908 {"ul-style", required_argument, 0, 137},
910 /* Backwards compatiblity options. */
911 {"pretty-print", optional_argument, 0, 'E'},
912 {"help-pretty-print", no_argument, 0, 141},
923 main (int argc, char *argv[])
936 /* Init our dynamic memory buffer. */
937 buffer_init (&buffer);
939 /* Get program's name. */
940 program = strrchr (argv[0], '/');
946 /* Make getopt_long() to use our modified programname. */
949 /* Create version strings. */
951 buffer_clear (&buffer);
952 buffer_append (&buffer, "GNU ");
953 buffer_append (&buffer, PACKAGE);
954 buffer_append (&buffer, " ");
955 buffer_append (&buffer, VERSION);
956 version_string = buffer_copy (&buffer);
958 ps_version_string = xstrdup (VERSION);
959 cp = strrchr (ps_version_string, '.');
962 /* Create the default TOC format string. Wow, this is cool! */
963 /* xgettext:no-c-format */
964 toc_fmt_string = _("$3v $-40N $3% pages $4L lines $E $C");
966 /* Internationalization. */
969 * We want to change only messages (gs do not like decimals in 0,1
973 setlocale (LC_MESSAGES, "");
977 bindtextdomain (PACKAGE, LOCALEDIR);
978 textdomain (PACKAGE);
981 /* Create date string. */
984 tm = localtime (&tim);
985 memcpy (&run_tm, tm, sizeof (*tm));
987 date_string = xstrdup (asctime (&run_tm));
988 i = strlen (date_string);
989 date_string[i - 1] = '\0';
991 /* Get user's passwd entry. */
992 passwd = getpwuid (getuid ());
994 FATAL ((stderr, _("couldn't get passwd entry for uid=%d: %s"), getuid (),
997 /* Defaults for some options. */
998 media_name = xstrdup ("A4");
999 encoding_name = xstrdup ("88591");
1000 npf_name = xstrdup ("octal");
1001 page_label_format = xstrdup ("short");
1002 ul_style_str = xstrdup ("outline");
1003 ul_position = xstrdup ("+0-0");
1004 spooler_command = xstrdup ("lpr");
1005 queue_param = xstrdup ("-P");
1006 no_job_header_switch = xstrdup ("-h");
1007 fancy_header_default = xstrdup ("enscript");
1008 output_first_line = xstrdup ("%!PS-Adobe-3.0");
1010 /* Check ENSCRIPT_LIBRARY for custom library location. */
1011 cp = getenv ("ENSCRIPT_LIBRARY");
1013 enscript_library = cp;
1015 /* Fill up build-in libpath. */
1017 cp = getenv ("HOME");
1019 cp = passwd->pw_dir;
1021 buffer_clear (&buffer);
1022 buffer_append (&buffer, enscript_library);
1023 buffer_append (&buffer, PATH_SEPARATOR_STR);
1024 buffer_append (&buffer, cp);
1025 buffer_append (&buffer, "/.enscript");
1026 libpath = buffer_copy (&buffer);
1028 /* Defaults for the states filter. */
1030 states_binary = xstrdup ("states"); /* Take it from the user path. */
1032 buffer_clear (&buffer);
1033 buffer_append (&buffer, enscript_library);
1034 buffer_append (&buffer, "/hl/enscript.st");
1035 states_config_file = buffer_copy (&buffer);
1037 states_highlight_style = xstrdup ("emacs");
1039 /* The <cp> holds the user's home directory. */
1040 buffer_clear (&buffer);
1041 buffer_append (&buffer, cp);
1042 buffer_append (&buffer, "/.enscript");
1043 buffer_append (&buffer, PATH_SEPARATOR_STR);
1044 buffer_append (&buffer, enscript_library);
1045 buffer_append (&buffer, "/hl");
1046 states_path = buffer_copy (&buffer);
1048 /* Initialize resource sets. */
1049 res_fonts = strhash_init ();
1050 download_fonts = strhash_init ();
1051 pagedevice = strhash_init ();
1052 statusdict = strhash_init ();
1053 user_strings = strhash_init ();
1057 * Read configuration files.
1060 /* Global config. */
1061 #define CFG_FILE_NAME "enscript.cfg"
1062 if (!read_config (SYSCONFDIR, CFG_FILE_NAME))
1064 int saved_errno = errno;
1066 /* Try to read it from our library directory. This is mostly
1067 the case for the micro ports. */
1068 if (!read_config (enscript_library, CFG_FILE_NAME))
1070 /* Try `enscript_library/../../etc/'. This is the case for
1071 installations which set the prefix after the compilation
1072 and our SYSCONFDIR points to wrong directory. */
1074 buffer_clear (&buffer);
1075 buffer_append (&buffer, enscript_library);
1076 buffer_append (&buffer, "/../../etc");
1078 if (!read_config (buffer_ptr (&buffer), CFG_FILE_NAME))
1080 /* Maybe we are not installed yet, let's try `../lib'
1082 if (!read_config ("../lib", CFG_FILE_NAME)
1083 && !read_config ("../../lib", CFG_FILE_NAME))
1085 /* No luck, report error from the original config file. */
1086 ERROR ((stderr, _("couldn't read config file \"%s/%s\": %s"),
1087 enscript_library, CFG_FILE_NAME,
1088 strerror (saved_errno)));
1090 _("I did also try the following directories:")));
1091 ERROR ((stderr, _("\t%s"), SYSCONFDIR));
1092 ERROR ((stderr, _("\t%s"), enscript_library));
1093 ERROR ((stderr, _("\t%s"), buffer_ptr (&buffer)));
1094 ERROR ((stderr, _("\t../lib")));
1095 ERROR ((stderr, _("\t../../lib")));
1097 _("This is probably an installation error. Please, try to rebuild:")));
1098 ERROR ((stderr, _("\tmake distclean")));
1099 ERROR ((stderr, _("\t./configure --prefix=PREFIX")));
1100 ERROR ((stderr, _("\tmake")));
1101 ERROR ((stderr, _("\tmake check")));
1102 ERROR ((stderr, _("\tmake install")));
1104 _("or set the environment variable `ENSCRIPT_LIBRARY' to point to your")));
1106 _("library directory.")));
1110 /* Ok, we are not installed yet. Here is a small kludge
1111 to conform the GNU coding standards: we must be able
1112 to run without being installed, so we must append the
1113 `../lib' and `../../lib' directories to the libpath.
1114 The later allows us to be run form the `src/tests'
1116 buffer_clear (&buffer);
1117 buffer_append (&buffer, libpath);
1118 buffer_append (&buffer, PATH_SEPARATOR_STR);
1119 buffer_append (&buffer, "../lib");
1120 buffer_append (&buffer, PATH_SEPARATOR_STR);
1121 buffer_append (&buffer, "../../lib");
1124 libpath = buffer_copy (&buffer);
1130 (void) read_config (SYSCONFDIR, "enscriptsite.cfg");
1132 /* Personal config. */
1133 (void) read_config (passwd->pw_dir, ".enscriptrc");
1139 /* Environment variables. */
1140 handle_env_options ("ENSCRIPT");
1141 handle_env_options ("GENSCRIPT");
1143 /* Command line arguments. */
1144 handle_options (argc, argv);
1147 * Check options which have some validity conditions.
1151 * Save the user-specified escape char so ^@escape{default} knows
1154 default_escape_char = escape_char;
1156 /* Input encoding. */
1159 for (i = 0; !found && encodings[i].names[0]; i++)
1160 for (j = 0; j < 3; j++)
1161 if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j],
1164 /* Found a match for this encoding. Use the first
1167 encoding = encodings[i].encoding;
1168 xfree (encoding_name);
1169 encoding_name = xstrdup (encodings[i].names[0]);
1172 nl = encodings[i].nl;
1173 bs = encodings[i].bs;
1178 FATAL ((stderr, _("unknown encoding: %s"), encoding_name));
1182 /* Default font for landscape, 2 column printing is Courier 7. */
1183 if (!user_body_font_defined && landscape && num_columns > 1)
1184 Fpt.w = Fpt.h = 7.0;
1186 /* Cache for font AFM information. */
1187 afm_cache = strhash_init ();
1188 afm_info_cache = strhash_init ();
1190 /* Open AFM library. */
1191 afm_error = afm_create (afm_path, verbose, &afm);
1192 if (afm_error != AFM_SUCCESS)
1196 afm_error_to_string (afm_error, buf);
1197 FATAL ((stderr, _("couldn't open AFM library: %s"), buf));
1201 * Save default Fpt and Fname since special escape 'font' can change
1202 * it and later we might want to switch back to the "default" font.
1204 default_Fpt.w = Fpt.w;
1205 default_Fpt.h = Fpt.h;
1206 default_Fname = Fname;
1207 default_Fencoding = encoding;
1209 /* Register that document uses at least these fonts. */
1210 strhash_put (res_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
1211 strhash_put (res_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
1213 /* As a default, download both named fonts. */
1214 strhash_put (download_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
1215 strhash_put (download_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
1217 /* Read font's character widths and character types. */
1220 /* Count the line indentation. */
1221 line_indent = parse_float (line_indent_spec, 1, 1);
1223 /* List media names. */
1226 printf (_("known media:\n\
1227 name width\theight\tllx\tlly\turx\tury\n\
1228 ------------------------------------------------------------\n"));
1229 for (mentry = media_names; mentry; mentry = mentry->next)
1230 printf ("%-16s %d\t%d\t%d\t%d\t%d\t%d\n",
1231 mentry->name, mentry->w, mentry->h,
1232 mentry->llx, mentry->lly, mentry->urx, mentry->ury);
1233 /* Exit after listing. */
1238 for (mentry = media_names; mentry; mentry = mentry->next)
1239 if (strcmp (media_name, mentry->name) == 0)
1245 FATAL ((stderr, _("do not know anything about media \"%s\""), media_name));
1249 /* Adjust marginals. */
1250 for (i = 0; i < 4; i++)
1252 if (*margins_spec == '\0')
1256 if (*margins_spec == ':')
1262 j = atoi (margins_spec);
1263 for (; *margins_spec != ':' && *margins_spec != '\0'; margins_spec++)
1265 if (*margins_spec == ':')
1275 media->urx = media->w - j;
1279 media->ury = media->h - j;
1282 case 3: /* bottom */
1289 _("set new marginals for media `%s' (%dx%d): llx=%d, lly=%d, urx=%d, ury=%d\n"),
1290 media->name, media->w, media->h, media->llx, media->lly,
1291 media->urx, media->ury));
1294 /* Page label format. */
1295 if (MATCH (page_label_format, "short"))
1296 page_label = LABEL_SHORT;
1297 else if (MATCH (page_label_format, "long"))
1298 page_label = LABEL_LONG;
1300 FATAL ((stderr, _("illegal page label format \"%s\""), page_label_format));
1302 /* Non-printable format. */
1303 if (MATCH (npf_name, "space"))
1304 non_printable_format = NPF_SPACE;
1305 else if (MATCH (npf_name, "questionmark"))
1306 non_printable_format = NPF_QUESTIONMARK;
1307 else if (MATCH (npf_name, "caret"))
1308 non_printable_format = NPF_CARET;
1309 else if (MATCH (npf_name, "octal"))
1310 non_printable_format = NPF_OCTAL;
1312 FATAL ((stderr, _("illegal non-printable format \"%s\""), npf_name));
1314 /* Mark wrapped lines style. */
1315 if (mark_wrapped_lines_style_name)
1317 if (MATCH (mark_wrapped_lines_style_name, "none"))
1318 mark_wrapped_lines_style = MWLS_NONE;
1319 else if (MATCH (mark_wrapped_lines_style_name, "plus"))
1320 mark_wrapped_lines_style = MWLS_PLUS;
1321 else if (MATCH (mark_wrapped_lines_style_name, "box"))
1322 mark_wrapped_lines_style = MWLS_BOX;
1323 else if (MATCH (mark_wrapped_lines_style_name, "arrow"))
1324 mark_wrapped_lines_style = MWLS_ARROW;
1326 FATAL ((stderr, _("illegal style for wrapped line marker: \"%s\""),
1327 mark_wrapped_lines_style_name));
1330 /* Count N-up stuffs. */
1336 FATAL ((stderr, _("illegal N-up argument: %d"), nup));
1341 FATAL ((stderr, _("N-up argument must be power of 2: %d"), nup));
1348 nup_rows = nup_exp / 2 * 2;
1351 nup_columns = (nup_exp + 1) / 2 * 2;
1352 if (nup_columns == 0)
1355 nup_landscape = nup_exp & 0x1;
1359 * Count output media dimensions.
1364 d_page_w = media->ury - media->lly;
1365 d_page_h = media->urx - media->llx;
1369 d_page_w = media->urx - media->llx;
1370 d_page_h = media->ury - media->lly;
1374 * Count N-up page width, height and scale.
1379 nup_width = media->ury - media->lly;
1380 nup_height = media->urx - media->llx;
1384 nup_width = media->urx - media->llx;
1385 nup_height = media->ury - media->lly;
1391 w = ((double) nup_width - (nup_columns - 1) * nup_xpad) / nup_columns;
1392 h = ((double) nup_height - (nup_rows - 1) * nup_ypad) / nup_rows;
1397 w = w / (media->urx - media->llx);
1398 h = h / (media->ury - media->lly);
1400 nup_scale = w < h ? w : h;
1404 * Underlay (this must come after output media dimensions, because
1405 * `underlay position' needs them).
1407 if (underlay != NULL)
1409 strhash_put (res_fonts, ul_font, strlen (ul_font) + 1, NULL, NULL);
1410 underlay = escape_string (underlay);
1413 /* Underlay X-coordinate. */
1414 ul_x = strtod (ul_position, &cp);
1415 if (cp == ul_position)
1418 FATAL ((stderr, _("malformed underlay position: %s"), ul_position));
1420 if (ul_position[0] == '-')
1423 /* Underlay Y-coordinate. */
1424 ul_y = strtod (cp, &cp2);
1426 goto malformed_position;
1430 /* Underlay Angle. */
1432 /* No angle given, count the default. */
1433 ul_angle = (atan2 (-d_page_h, d_page_w) / 3.14159265 * 180);
1435 /* Underlay style. */
1436 if (strcmp (ul_style_str, "outline") == 0)
1437 ul_style = UL_STYLE_OUTLINE;
1438 else if (strcmp (ul_style_str, "filled") == 0)
1439 ul_style = UL_STYLE_FILLED;
1441 FATAL ((stderr, _("illegal underlay style: %s"), ul_style_str));
1444 * Header. Note! The header attributes can be changed from
1445 * the `.hdr' files, these are only the defaults.
1448 d_header_w = d_page_w;
1456 d_header_h = HFpt.h * 1.5;
1464 /* Help highlight. */
1467 /* Create description with states. */
1468 printf (_("Highlighting is supported for the following languages and file formats:\n\n"));
1471 buffer_clear (&buffer);
1472 buffer_append (&buffer, states_binary);
1473 buffer_append (&buffer, " -f \"");
1474 buffer_append (&buffer, states_config_file);
1475 buffer_append (&buffer, "\" -p \"");
1476 buffer_append (&buffer, states_path);
1477 buffer_append (&buffer, "\" -s describe_languages ");
1478 buffer_append (&buffer, enscript_library);
1479 buffer_append (&buffer, "/hl/*.st");
1481 system (buffer_ptr (&buffer));
1486 * And now to the main business. The actual input file processing
1487 * is divided to two parts: PostScript generation and everything else.
1488 * The PostScript generation is handled in the conventional way, we
1489 * process the input and generate PostScript. However all other input
1490 * languages will be handled with States, we only pass enscript's
1491 * options to the states pre-filter and dump output.
1493 if (output_language_pass_through)
1499 /* The States output generation. */
1501 /* Resolve the start state. */
1503 start_state = hl_start_state;
1507 start_state = "passthrough";
1509 /* Create the states command. */
1513 buffer_append (&cmd, states_binary);
1514 buffer_append (&cmd, " -f \"");
1515 buffer_append (&cmd, states_config_file);
1516 buffer_append (&cmd, "\" -p \"");
1517 buffer_append (&cmd, states_path);
1518 buffer_append (&cmd, "\" ");
1521 buffer_append (&cmd, "-v ");
1525 buffer_append (&cmd, "-s");
1526 buffer_append (&cmd, start_state);
1527 buffer_append (&cmd, " ");
1530 buffer_append (&cmd, "-Dcolor=");
1531 buffer_append (&cmd, states_color ? "1" : "0");
1532 buffer_append (&cmd, " ");
1534 buffer_append (&cmd, "-Dstyle=");
1535 buffer_append (&cmd, states_highlight_style);
1536 buffer_append (&cmd, " ");
1538 buffer_append (&cmd, "-Dlanguage=");
1539 buffer_append (&cmd, output_language);
1540 buffer_append (&cmd, " ");
1542 buffer_append (&cmd, "-Dnum_input_files=");
1543 sprintf (intbuf, "%d", optind == argc ? 1 : argc - optind);
1544 buffer_append (&cmd, intbuf);
1545 buffer_append (&cmd, " ");
1547 buffer_append (&cmd, "-Ddocument_title=\"");
1548 buffer_append (&cmd, title);
1549 buffer_append (&cmd, "\" ");
1551 buffer_append (&cmd, "-Dtoc=");
1552 buffer_append (&cmd, toc ? "1" : "0");
1554 /* Additional options for states? */
1555 if (helper_options['s'])
1557 Buffer *opts = helper_options['s'];
1559 buffer_append (&cmd, " ");
1560 buffer_append_len (&cmd, buffer_ptr (opts), buffer_len (opts));
1563 /* Append input files. */
1564 for (i = optind; i < argc; i++)
1566 buffer_append (&cmd, " ");
1567 buffer_append (&cmd, argv[i]);
1570 /* And do the job. */
1571 if (is_open (&is, stdin, NULL, buffer_ptr (&cmd)))
1573 open_output_file ();
1574 process_file ("unused", &is, 0);
1578 buffer_uninit (&cmd);
1582 /* The conventional way. */
1589 /* Create a highlight input filter. */
1590 buffer_clear (&buffer);
1591 buffer_append (&buffer, states_binary);
1592 buffer_append (&buffer, " -f \"");
1593 buffer_append (&buffer, states_config_file);
1594 buffer_append (&buffer, "\" -p \"");
1595 buffer_append (&buffer, states_path);
1596 buffer_append (&buffer, "\"");
1599 buffer_append (&buffer, " -v");
1603 buffer_append (&buffer, " -s ");
1604 buffer_append (&buffer, hl_start_state);
1607 buffer_append (&buffer, " -Dcolor=");
1608 buffer_append (&buffer, states_color ? "1" : "0");
1610 buffer_append (&buffer, " -Dstyle=");
1611 buffer_append (&buffer, states_highlight_style);
1613 buffer_append (&buffer, " -Dfont_spec=");
1614 buffer_append (&buffer, Fname);
1615 sprintf (fbuf, "@%g/%g", Fpt.w, Fpt.h);
1616 buffer_append (&buffer, fbuf);
1618 /* Additional options for states? */
1619 if (helper_options['s'])
1621 Buffer *opts = helper_options['s'];
1623 buffer_append (&buffer, " ");
1624 buffer_append_len (&buffer,
1625 buffer_ptr (opts), buffer_len (opts));
1628 buffer_append (&buffer, " \"%s\"");
1630 input_filter = buffer_copy (&buffer);
1631 input_filter_stdin = "-";
1634 /* Table of Contents. */
1637 toc_fp = tmpfile ();
1639 FATAL ((stderr, _("couldn't create temporary toc file: %s"),
1650 /* stdin's modification time is the current time. */
1651 memcpy (&mod_tm, &run_tm, sizeof (run_tm));
1653 if (is_open (&is, stdin, NULL, input_filter))
1655 /* Open output file. */
1656 open_output_file ();
1657 process_file (title_given ? title : "", &is, 0);
1663 for (; optind < argc; optind++)
1665 if (is_open (&is, NULL, argv[optind], input_filter))
1667 struct stat stat_st;
1669 /* Get modification time. */
1670 if (stat (argv[optind], &stat_st) == 0)
1672 tim = stat_st.st_mtime;
1673 tm = localtime (&tim);
1674 memcpy (&mod_tm, tm, sizeof (*tm));
1677 * Open output file. Output file opening is delayed to
1678 * this point so we can optimize the case when a
1679 * non-existing input file is printed => we do nothing.
1681 open_output_file ();
1683 process_file (argv[optind], &is, 0);
1686 ERROR ((stderr, _("couldn't stat input file \"%s\": %s"),
1695 /* Table of Contents. */
1698 /* This is really cool... */
1700 /* Set the printing options for toc. */
1702 special_escapes = 1;
1705 if (fseek (toc_fp, 0, SEEK_SET) != 0)
1706 FATAL ((stderr, _("couldn't rewind toc file: %s"),
1709 memcpy (&mod_tm, &run_tm, sizeof (run_tm));
1710 if (is_open (&is, toc_fp, NULL, NULL))
1712 process_file (_("Table of Contents"), &is, 1);
1717 /* Give trailer a chance to dump itself. */
1721 * Append ^D to the end of the output? Note! It must be ^D followed
1724 if (ofp != NULL && append_ctrl_D)
1725 fprintf (ofp, "\004\n");
1728 /* Close output file. */
1729 close_output_file ();
1731 /* Tell how things went. */
1735 * The value of <ofp> is not reset in close_output_file(),
1736 * this is ugly but it saves one flag.
1738 MESSAGE (0, (stderr, _("no output generated\n")));
1740 else if (output_language_pass_through)
1742 if (output_file == OUTPUT_FILE_NONE)
1743 MESSAGE (0, (stderr, _("output sent to %s\n"),
1744 printer ? printer : _("printer")));
1746 MESSAGE (0, (stderr, _("output left in %s\n"),
1747 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1751 unsigned int real_total_pages;
1755 if (total_pages > 0)
1756 real_total_pages = (total_pages - 1) / nup + 1;
1758 real_total_pages = 0;
1761 real_total_pages = total_pages;
1763 /* We did something, tell what. */
1764 MESSAGE (0, (stderr, _("[ %d pages * %d copy ]"), real_total_pages,
1766 if (output_file == OUTPUT_FILE_NONE)
1767 MESSAGE (0, (stderr, _(" sent to %s\n"),
1768 printer ? printer : _("printer")));
1770 MESSAGE (0, (stderr, _(" left in %s\n"),
1771 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1772 if (num_truncated_lines)
1775 MESSAGE (0, (stderr, _("%d lines were %s\n"), num_truncated_lines,
1776 line_end == LE_TRUNCATE
1777 ? _("truncated") : _("wrapped")));
1780 if (num_missing_chars)
1783 MESSAGE (0, (stderr, _("%d characters were missing\n"),
1784 num_missing_chars));
1785 if (list_missing_characters)
1787 MESSAGE (0, (stderr, _("missing character codes (decimal):\n")));
1788 do_list_missing_characters (missing_chars);
1792 if (num_non_printable_chars)
1795 MESSAGE (0, (stderr, _("%d non-printable characters\n"),
1796 num_non_printable_chars));
1797 if (list_missing_characters)
1799 MESSAGE (0, (stderr,
1800 _("non-printable character codes (decimal):\n")));
1801 do_list_missing_characters (non_printable_chars);
1806 /* Uninit our dynamic memory buffer. */
1807 buffer_uninit (&buffer);
1809 /* Return the extended return values only if requested. */
1810 if (!extended_return_values)
1813 /* This is the end. */
1826 /* Output file has already been opened, do nothing. */
1829 if (output_file == OUTPUT_FILE_NONE)
1831 char spooler_options[512];
1833 /* Format spooler options. */
1834 spooler_options[0] = '\0';
1836 strcat (spooler_options, "-m ");
1839 strcat (spooler_options, no_job_header_switch);
1840 strcat (spooler_options, " ");
1842 if (printer_options)
1843 strcat (spooler_options, printer_options);
1846 ofp = printer_open (spooler_command, spooler_options, queue_param,
1847 printer, &printer_context);
1849 FATAL ((stderr, _("couldn't open printer `%s': %s"), printer,
1852 else if (output_file == OUTPUT_FILE_STDOUT)
1856 ofp = fopen (output_file, "w");
1858 FATAL ((stderr, _("couldn't create output file \"%s\": %s"),
1859 output_file, strerror (errno)));
1865 close_output_file ()
1868 /* Output file hasn't been opened, we are done. */
1871 if (output_file == OUTPUT_FILE_NONE)
1872 printer_close (printer_context);
1873 else if (output_file != OUTPUT_FILE_STDOUT)
1875 FATAL ((stderr, _("couldn't close output file \"%s\": %s"),
1876 output_file, strerror (errno)));
1878 /* We do not reset <ofp> since its value is needed in diagnostigs. */
1883 handle_env_options (char *var)
1891 string = getenv (var);
1895 MESSAGE (2, (stderr, "handle_env_options(): %s=\"%s\"\n", var, string));
1897 /* Copy string so we can modify it in place. */
1898 str = xstrdup (string);
1901 * We can count this, each option takes at least 1 character and one
1902 * space. We also need one for program's name and one for the
1905 argc = (strlen (str) + 1) / 2 + 2;
1906 argv = xcalloc (argc, sizeof (char *));
1908 /* Set program name. */
1910 argv[argc++] = program;
1912 /* Split string and set arguments to argv array. */
1916 /* Skip leading whitespace. */
1917 for (; str[i] && isspace (str[i]); i++)
1922 /* Check for quoted arguments. */
1923 if (str[i] == '"' || str[i] == '\'')
1925 int endch = str[i++];
1927 argv[argc++] = str + i;
1929 /* Skip until we found the end of the quotation. */
1930 for (; str[i] && str[i] != endch; i++)
1933 FATAL ((stderr, _("syntax error in option string %s=\"%s\":\n\
1934 missing end of quotation: %c"), var, string, endch));
1940 argv[argc++] = str + i;
1942 /* Skip until whitespace if found. */
1943 for (; str[i] && !isspace (str[i]); i++)
1950 /* argv[argc] must be NULL. */
1953 MESSAGE (2, (stderr, "found following options (argc=%d):\n", argc));
1954 for (i = 0; i < argc; i++)
1955 MESSAGE (2, (stderr, "%3d = \"%s\"\n", i, argv[i]));
1957 /* Process options. */
1958 handle_options (argc, argv);
1960 /* Check that all got processed. */
1965 _("warning: didn't process following options from \
1966 environment variable %s:\n"),
1968 for (; optind < argc; optind++)
1969 MESSAGE (0, (stderr, _(" option %d = \"%s\"\n"), optind,
1977 * <str> must not be freed, since some global variables can point to
1984 handle_options (int argc, char *argv[])
1994 int option_index = 0;
1998 c = getopt_long (argc, argv,
1999 "#: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",
2000 long_options, &option_index);
2007 case 0: /* Long option found. */
2008 cp = long_options[option_index].name;
2010 if (strcmp (cp, "columns") == 0)
2012 num_columns = atoi (optarg);
2013 if (num_columns < 1)
2015 _("number of columns must be larger than zero")));
2019 /* Short options. */
2021 case '1': /* 1 column */
2022 case '2': /* 2 columns */
2023 case '3': /* 3 columns */
2024 case '4': /* 4 columns */
2025 case '5': /* 5 columns */
2026 case '6': /* 6 columns */
2027 case '7': /* 7 columns */
2028 case '8': /* 8 columns */
2029 case '9': /* 9 columns */
2030 num_columns = c - '0';
2033 case 'a': /* pages */
2034 prange = (PageRange *) xcalloc (1, sizeof (PageRange));
2036 if (strcmp (optarg, "odd") == 0)
2038 else if (strcmp (optarg, "even") == 0)
2042 cp = strchr (optarg, '-');
2045 if (optarg[0] == '-')
2047 prange->end = atoi (optarg + 1);
2048 else if (cp[1] == '\0')
2051 prange->start = atoi (optarg);
2052 prange->end = (unsigned int) -1;
2057 prange->start = atoi (optarg);
2058 prange->end = atoi (cp + 1);
2063 prange->start = prange->end = atoi (optarg);
2066 prange->next = page_ranges;
2067 page_ranges = prange;
2070 case 'A': /* file alignment */
2071 file_align = atoi (optarg);
2072 if (file_align == 0)
2073 FATAL ((stderr, _("file alignment must be larger than zero")));
2076 case 'b': /* page header */
2077 page_header = optarg;
2080 case 'B': /* no page headers */
2084 case 'c': /* truncate (cut) long lines */
2085 line_end = LE_TRUNCATE;
2088 case 'C': /* line numbers */
2091 start_line_number = atoi (optarg);
2094 case 'd': /* specify printer */
2097 printer = xstrdup (optarg);
2098 output_file = OUTPUT_FILE_NONE;
2101 case 'D': /* setpagedevice */
2102 parse_key_value_pair (pagedevice, optarg);
2105 case 'e': /* special escapes */
2106 special_escapes = 1;
2109 /* Specify the escape character. */
2110 if (isdigit (optarg[0]))
2111 /* As decimal, octal, or hexadicimal number. */
2112 escape_char = (int) strtoul (optarg, NULL, 0);
2114 /* As character directly. */
2115 escape_char = ((unsigned char *) optarg)[0];
2119 case 'E': /* highlight */
2121 special_escapes = 1;
2123 hl_start_state = optarg;
2126 case 'f': /* font */
2127 if (!parse_font_spec (optarg, &Fname, &Fpt, NULL))
2128 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2129 user_body_font_defined = 1;
2132 case 'F': /* header font */
2133 if (!parse_font_spec (optarg, &HFname, &HFpt, NULL))
2134 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2137 case 'g': /* print anyway */
2141 case 'G': /* fancy header */
2144 fancy_header_name = optarg;
2146 fancy_header_name = fancy_header_default;
2148 if (!file_existsp (fancy_header_name, ".hdr"))
2150 _("couldn't find header definition file \"%s.hdr\""),
2151 fancy_header_name));
2154 case 'h': /* no job header */
2158 case 'H': /* highlight bars */
2160 highlight_bars = atoi (optarg);
2165 case 'i': /* line indent */
2166 line_indent_spec = optarg;
2169 case 'I': /* input filter */
2170 input_filter = optarg;
2173 case 'j': /* borders */
2177 case 'k': /* enable page prefeed */
2181 case 'K': /* disable page prefeed */
2185 case 'l': /* emulate lineprinter */
2186 lines_per_page = 66;
2190 case 'L': /* lines per page */
2191 lines_per_page = atoi (optarg);
2192 if (lines_per_page <= 0)
2194 _("must print at least one line per each page: %s"),
2198 case 'm': /* send mail upon completion */
2202 case 'M': /* select output media */
2203 media_name = xstrdup (optarg);
2206 case 'n': /* num copies */
2208 num_copies = atoi (optarg);
2211 case 'N': /* newline character */
2212 if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0')
2214 fprintf (stderr, _("%s: illegal newline character specifier: \
2215 '%s': expected 'n' or 'r'\n"),
2219 if (optarg[0] == 'n')
2226 case 'p': /* output file */
2227 /* Check output file "-". */
2228 if (strcmp (optarg, "-") == 0)
2229 output_file = OUTPUT_FILE_STDOUT;
2231 output_file = optarg;
2234 case 'O': /* list missing characters */
2235 list_missing_characters = 1;
2238 case 'q': /* quiet */
2243 case 'r': /* landscape */
2247 case 'R': /* portrait */
2251 case 's': /* baselineskip */
2252 baselineskip = atof (optarg);
2255 case 'S': /* statusdict */
2256 parse_key_value_pair (statusdict, optarg);
2259 case 't': /* title */
2265 case 'T': /* tabulator size */
2266 tabsize = atoi (optarg);
2271 case 'u': /* underlay */
2276 nup = atoi (optarg);
2279 case 'v': /* verbose */
2281 verbose = atoi (optarg);
2287 case 'V': /* version */
2292 case 'w': /* output language */
2293 output_language = optarg;
2294 if (strcmp (output_language, "PostScript") != 0)
2295 /* Other output languages are handled with states. */
2296 output_language_pass_through = 1;
2299 case 'W': /* a helper application option */
2300 cp = strchr (optarg, ',');
2303 _("malformed argument `%s' for option -W, --option: \
2307 if (cp - optarg != 1)
2308 FATAL ((stderr, _("helper application specification must be \
2309 single character: %s"),
2312 /* Take the index of the helper application and update `cp'
2313 to point to the beginning of the option. */
2317 if (helper_options[i] == NULL)
2318 helper_options[i] = buffer_alloc ();
2321 /* We already had some options for this helper
2322 application. Let's separate these arguments. */
2323 buffer_append (helper_options[i], " ");
2326 /* Add this new option. */
2327 buffer_append (helper_options[i], cp);
2330 case 'X': /* input encoding */
2331 xfree (encoding_name);
2332 encoding_name = xstrdup (optarg);
2335 case 'z': /* no form feeds */
2336 interpret_formfeed = 0;
2339 case 'Z': /* pass through */
2343 case 128: /* underlay font */
2344 if (!parse_font_spec (optarg, &ul_font, &ul_ptsize, NULL))
2345 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2348 case 129: /* underlay gray */
2349 ul_gray = atof (optarg);
2352 case 130: /* page label format */
2353 xfree (page_label_format);
2354 page_label_format = xstrdup (optarg);
2357 case 131: /* download font */
2358 strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL,
2362 case 132: /* underlay angle */
2363 ul_angle = atof (optarg);
2367 case 133: /* underlay position */
2368 xfree (ul_position);
2369 ul_position = xstrdup (optarg);
2373 case 134: /* non-printable format */
2375 npf_name = xstrdup (optarg);
2378 case 135: /* help */
2383 case 136: /* highlight bar gray */
2384 highlight_bar_gray = atof (optarg);
2387 case 137: /* underlay style */
2388 xfree (ul_style_str);
2389 ul_style_str = xstrdup (optarg);
2392 case 138: /* filter stdin */
2393 input_filter_stdin = optarg;
2396 case 139: /* extra options for the printer spooler */
2397 printer_options = optarg;
2400 case 140: /* slicing */
2402 slice = atoi (optarg);
2404 FATAL ((stderr, _("slice must be greater than zero")));
2407 case 141: /* help-highlight */
2411 case 142: /* States color? */
2415 states_color = atoi (optarg);
2418 case 143: /* mark-wrapped-lines */
2421 xfree (mark_wrapped_lines_style_name);
2422 mark_wrapped_lines_style_name = xstrdup (optarg);
2425 /* Set the system default. */
2426 mark_wrapped_lines_style = MWLS_BOX;
2429 case 144: /* adjust margins */
2430 margins_spec = optarg;
2433 case 145: /* N-up x-pad */
2434 nup_xpad = atoi (optarg);
2437 case 146: /* N-up y-pad */
2438 nup_ypad = atoi (optarg);
2441 case 147: /* word wrap */
2442 line_end = LE_WORD_WRAP;
2445 case 148: /* horizontal column height */
2446 horizontal_column_height = atof (optarg);
2447 formfeed_type = FORMFEED_HCOLUMN;
2450 case 149: /* PostScript language level */
2451 pslevel = atoi (optarg);
2454 case 150: /* rotate even-numbered pages */
2455 rotate_even_pages = 1;
2458 case 151: /* highlight style */
2459 xfree (states_highlight_style);
2460 states_highlight_style = xstrdup (optarg);
2463 case 152: /* N-up colunwise */
2467 case 153: /* swap even page margins */
2468 swap_even_page_margins = 1;
2471 case 154: /* extended return values */
2472 extended_return_values = 1;
2475 case 155: /* footer */
2476 page_footer = optarg;
2479 case 156: /* continuous page numbers */
2480 continuous_page_numbers = 1;
2483 case '?': /* Errors found during getopt_long(). */
2485 fprintf (stderr, _("Try `%s --help' for more information.\n"),
2491 printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c);
2493 printf (" with arg %s", optarg);
2495 FATAL ((stderr, "This is a bug!"));
2506 Usage: %s [OPTION]... [FILE]...\n\
2507 Mandatory arguments to long options are mandatory for short options too.\n\
2508 -# an alias for option -n, --copies\n\
2509 -1 same as --columns=1\n\
2510 -2 same as --columns=2\n\
2511 --columns=NUM specify the number of columns per page\n\
2512 -a, --pages=PAGES specify which pages are printed\n\
2513 -A, --file-align=ALIGN align separate input files to ALIGN\n\
2514 -b, --header=HEADER set page header\n\
2515 -B, --no-header no page headers\n\
2516 -c, --truncate-lines cut long lines (default is to wrap)\n\
2517 -C, --line-numbers[=START]\n\
2518 precede each line with its line number\n\
2519 -d an alias for option --printer\n\
2520 -D, --setpagedevice=KEY[:VALUE]\n\
2521 pass a page device definition to output\n\
2522 -e, --escapes[=CHAR] enable special escape interpretation\n"),
2526 -E, --highlight[=LANG] highlight source code\n"));
2529 -f, --font=NAME use font NAME for body text\n\
2530 -F, --header-font=NAME use font NAME for header texts\n\
2531 -g, --print-anyway nothing (compatibility option)\n\
2532 -G same as --fancy-header\n\
2533 --fancy-header[=NAME] select fancy page header\n\
2534 -h, --no-job-header suppress the job header page\n\
2535 -H, --highlight-bars=NUM specify how high highlight bars are\n\
2536 -i, --indent=NUM set line indent to NUM characters\n\
2537 -I, --filter=CMD read input files through input filter CMD\n\
2538 -j, --borders print borders around columns\n\
2539 -J, an alias for option --title\n\
2540 -k, --page-prefeed enable page prefeed\n\
2541 -K, --no-page-prefeed disable page prefeed\n\
2542 -l, --lineprinter simulate lineprinter, this is an alias for:\n\
2543 --lines-per-page=66, --no-header, --portrait,\n\
2547 -L, --lines-per-page=NUM specify how many lines are printed on each page\n\
2548 -m, --mail send mail upon completion\n\
2549 -M, --media=NAME use output media NAME\n\
2550 -n, --copies=NUM print NUM copies of each page\n\
2551 -N, --newline=NL select the newline character. Possible\n\
2552 values for NL are: n (`\\n') and r (`\\r').\n\
2553 -o an alias for option --output\n\
2554 -O, --missing-characters list missing characters\n\
2555 -p, --output=FILE leave output to file FILE. If FILE is `-',\n\
2556 leave output to stdout.\n\
2557 -P, --printer=NAME print output to printer NAME\n\
2558 -q, --quiet, --silent be really quiet\n\
2559 -r, --landscape print in landscape mode\n\
2560 -R, --portrait print in portrait mode\n"));
2563 -s, --baselineskip=NUM set baselineskip to NUM\n\
2564 -S, --statusdict=KEY[:VALUE]\n\
2565 pass a statusdict definition to the output\n\
2566 -t, --title=TITLE set banner page's job title to TITLE. Option\n\
2567 sets also the name of the input file stdin.\n\
2568 -T, --tabsize=NUM set tabulator size to NUM\n\
2569 -u, --underlay[=TEXT] print TEXT under every page\n\
2570 -U, --nup=NUM print NUM logical pages on each output page\n\
2571 -v, --verbose tell what we are doing\n\
2572 -V, --version print version number\n\
2573 -w, --language=LANG set output language to LANG\n\
2574 -W, --options=APP,OPTION pass option OPTION to helper application APP\n\
2575 -X, --encoding=NAME use input encoding NAME\n\
2576 -z, --no-formfeed do not interpret form feed characters\n\
2577 -Z, --pass-through pass through PostScript and PCL files\n\
2578 without any modifications\n"));
2580 printf (_("Long-only options:\n\
2581 --color[=bool] create color outputs with states\n\
2582 --continuous-page-numbers count page numbers across input files. Don't\n\
2583 restart numbering at beginning of each file.\n\
2584 --download-font=NAME download font NAME\n\
2585 --extended-return-values enable extended return values\n\
2586 --filter-stdin=NAME specify how stdin is shown to the input filter\n\
2587 --footer=FOOTER set page footer\n\
2588 --h-column-height=HEIGHT set the horizontal column height to HEIGHT\n\
2589 --help print this help and exit\n"));
2592 --help-highlight describe all supported --highlight languages\n\
2594 --highlight-bar-gray=NUM print highlight bars with gray NUM (0 - 1)\n\
2595 --list-media list names of all known media\n\
2596 --margins=LEFT:RIGHT:TOP:BOTTOM\n\
2597 adjust page marginals\n\
2598 --mark-wrapped-lines[STYLE]\n\
2599 mark wrapped lines in the output with STYLE\n\
2600 --non-printable-format=FMT specify how non-printable chars are printed\n"));
2603 --nup-columnwise layout pages in the N-up printing columnwise\n\
2604 --nup-xpad=NUM set the page x-padding of N-up printing to NUM\n\
2605 --nup-ypad=NUM set the page y-padding of N-up printing to NUM\n\
2606 --page-label-format=FMT set page label format to FMT\n\
2607 --ps-level=LEVEL set the PostScript language level that enscript\n\
2609 --printer-options=OPTIONS pass extra options to the printer command\n\
2610 --rotate-even-pages rotate even-numbered pages 180 degrees\n"));
2613 --slice=NUM print vertical slice NUM\n\
2614 --style=STYLE use highlight style STYLE\n\
2615 --swap-even-page-margins swap left and right side margins for each even\n\
2617 --toc print table of contents\n\
2618 --ul-angle=ANGLE set underlay text's angle to ANGLE\n\
2619 --ul-font=NAME print underlays with font NAME\n\
2620 --ul-gray=NUM print underlays with gray value NUM\n\
2621 --ul-position=POS set underlay's starting position to POS\n\
2622 --ul-style=STYLE print underlays with style STYLE\n\
2623 --word-wrap wrap long lines from word boundaries\n\
2626 printf (_("\nReport bugs to %s.\n"), PACKAGE_BUGREPORT);
2634 Copyright (C) 2003 Markku Rossi.\n\
2635 GNU enscript comes with NO WARRANTY, to the extent permitted by law.\n\
2636 You may redistribute copies of GNU enscript under the terms of the GNU\n\
2637 General Public License. For more information about these matters, see\n\
2638 the files named COPYING.\n",