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);
1718 /* Clean up toc file. */
1722 /* Give trailer a chance to dump itself. */
1726 * Append ^D to the end of the output? Note! It must be ^D followed
1729 if (ofp != NULL && append_ctrl_D)
1730 fprintf (ofp, "\004\n");
1733 /* Close output file. */
1734 close_output_file ();
1736 /* Tell how things went. */
1740 * The value of <ofp> is not reset in close_output_file(),
1741 * this is ugly but it saves one flag.
1743 MESSAGE (0, (stderr, _("no output generated\n")));
1745 else if (output_language_pass_through)
1747 if (output_file == OUTPUT_FILE_NONE)
1748 MESSAGE (0, (stderr, _("output sent to %s\n"),
1749 printer ? printer : _("printer")));
1751 MESSAGE (0, (stderr, _("output left in %s\n"),
1752 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1756 unsigned int real_total_pages;
1760 if (total_pages > 0)
1761 real_total_pages = (total_pages - 1) / nup + 1;
1763 real_total_pages = 0;
1766 real_total_pages = total_pages;
1768 /* We did something, tell what. */
1769 MESSAGE (0, (stderr, _("[ %d pages * %d copy ]"), real_total_pages,
1771 if (output_file == OUTPUT_FILE_NONE)
1772 MESSAGE (0, (stderr, _(" sent to %s\n"),
1773 printer ? printer : _("printer")));
1775 MESSAGE (0, (stderr, _(" left in %s\n"),
1776 output_file == OUTPUT_FILE_STDOUT ? "-" : output_file));
1777 if (num_truncated_lines)
1780 MESSAGE (0, (stderr, _("%d lines were %s\n"), num_truncated_lines,
1781 line_end == LE_TRUNCATE
1782 ? _("truncated") : _("wrapped")));
1785 if (num_missing_chars)
1788 MESSAGE (0, (stderr, _("%d characters were missing\n"),
1789 num_missing_chars));
1790 if (list_missing_characters)
1792 MESSAGE (0, (stderr, _("missing character codes (decimal):\n")));
1793 do_list_missing_characters (missing_chars);
1797 if (num_non_printable_chars)
1800 MESSAGE (0, (stderr, _("%d non-printable characters\n"),
1801 num_non_printable_chars));
1802 if (list_missing_characters)
1804 MESSAGE (0, (stderr,
1805 _("non-printable character codes (decimal):\n")));
1806 do_list_missing_characters (non_printable_chars);
1811 /* Uninit our dynamic memory buffer. */
1812 buffer_uninit (&buffer);
1814 /* Return the extended return values only if requested. */
1815 if (!extended_return_values)
1818 /* This is the end. */
1831 /* Output file has already been opened, do nothing. */
1834 if (output_file == OUTPUT_FILE_NONE)
1836 char spooler_options[512];
1838 /* Format spooler options. */
1839 spooler_options[0] = '\0';
1841 strcat (spooler_options, "-m ");
1844 strcat (spooler_options, no_job_header_switch);
1845 strcat (spooler_options, " ");
1847 if (printer_options)
1848 strcat (spooler_options, printer_options);
1851 ofp = printer_open (spooler_command, spooler_options, queue_param,
1852 printer, &printer_context);
1854 FATAL ((stderr, _("couldn't open printer `%s': %s"), printer,
1857 else if (output_file == OUTPUT_FILE_STDOUT)
1861 ofp = fopen (output_file, "w");
1863 FATAL ((stderr, _("couldn't create output file \"%s\": %s"),
1864 output_file, strerror (errno)));
1870 close_output_file ()
1873 /* Output file hasn't been opened, we are done. */
1876 if (output_file == OUTPUT_FILE_NONE)
1877 printer_close (printer_context);
1878 else if (output_file != OUTPUT_FILE_STDOUT)
1880 FATAL ((stderr, _("couldn't close output file \"%s\": %s"),
1881 output_file, strerror (errno)));
1883 /* We do not reset <ofp> since its value is needed in diagnostigs. */
1888 handle_env_options (char *var)
1896 string = getenv (var);
1900 MESSAGE (2, (stderr, "handle_env_options(): %s=\"%s\"\n", var, string));
1902 /* Copy string so we can modify it in place. */
1903 str = xstrdup (string);
1906 * We can count this, each option takes at least 1 character and one
1907 * space. We also need one for program's name and one for the
1910 argc = (strlen (str) + 1) / 2 + 2;
1911 argv = xcalloc (argc, sizeof (char *));
1913 /* Set program name. */
1915 argv[argc++] = program;
1917 /* Split string and set arguments to argv array. */
1921 /* Skip leading whitespace. */
1922 for (; str[i] && isspace (str[i]); i++)
1927 /* Check for quoted arguments. */
1928 if (str[i] == '"' || str[i] == '\'')
1930 int endch = str[i++];
1932 argv[argc++] = str + i;
1934 /* Skip until we found the end of the quotation. */
1935 for (; str[i] && str[i] != endch; i++)
1938 FATAL ((stderr, _("syntax error in option string %s=\"%s\":\n\
1939 missing end of quotation: %c"), var, string, endch));
1945 argv[argc++] = str + i;
1947 /* Skip until whitespace if found. */
1948 for (; str[i] && !isspace (str[i]); i++)
1955 /* argv[argc] must be NULL. */
1958 MESSAGE (2, (stderr, "found following options (argc=%d):\n", argc));
1959 for (i = 0; i < argc; i++)
1960 MESSAGE (2, (stderr, "%3d = \"%s\"\n", i, argv[i]));
1962 /* Process options. */
1963 handle_options (argc, argv);
1965 /* Check that all got processed. */
1970 _("warning: didn't process following options from \
1971 environment variable %s:\n"),
1973 for (; optind < argc; optind++)
1974 MESSAGE (0, (stderr, _(" option %d = \"%s\"\n"), optind,
1982 * <str> must not be freed, since some global variables can point to
1989 handle_options (int argc, char *argv[])
1999 int option_index = 0;
2003 c = getopt_long (argc, argv,
2004 "#: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",
2005 long_options, &option_index);
2012 case 0: /* Long option found. */
2013 cp = long_options[option_index].name;
2015 if (strcmp (cp, "columns") == 0)
2017 num_columns = atoi (optarg);
2018 if (num_columns < 1)
2020 _("number of columns must be larger than zero")));
2024 /* Short options. */
2026 case '1': /* 1 column */
2027 case '2': /* 2 columns */
2028 case '3': /* 3 columns */
2029 case '4': /* 4 columns */
2030 case '5': /* 5 columns */
2031 case '6': /* 6 columns */
2032 case '7': /* 7 columns */
2033 case '8': /* 8 columns */
2034 case '9': /* 9 columns */
2035 num_columns = c - '0';
2038 case 'a': /* pages */
2039 prange = (PageRange *) xcalloc (1, sizeof (PageRange));
2041 if (strcmp (optarg, "odd") == 0)
2043 else if (strcmp (optarg, "even") == 0)
2047 cp = strchr (optarg, '-');
2050 if (optarg[0] == '-')
2052 prange->end = atoi (optarg + 1);
2053 else if (cp[1] == '\0')
2056 prange->start = atoi (optarg);
2057 prange->end = (unsigned int) -1;
2062 prange->start = atoi (optarg);
2063 prange->end = atoi (cp + 1);
2068 prange->start = prange->end = atoi (optarg);
2071 prange->next = page_ranges;
2072 page_ranges = prange;
2075 case 'A': /* file alignment */
2076 file_align = atoi (optarg);
2077 if (file_align == 0)
2078 FATAL ((stderr, _("file alignment must be larger than zero")));
2081 case 'b': /* page header */
2082 page_header = optarg;
2085 case 'B': /* no page headers */
2089 case 'c': /* truncate (cut) long lines */
2090 line_end = LE_TRUNCATE;
2093 case 'C': /* line numbers */
2096 start_line_number = atoi (optarg);
2099 case 'd': /* specify printer */
2102 printer = xstrdup (optarg);
2103 output_file = OUTPUT_FILE_NONE;
2106 case 'D': /* setpagedevice */
2107 parse_key_value_pair (pagedevice, optarg);
2110 case 'e': /* special escapes */
2111 special_escapes = 1;
2114 /* Specify the escape character. */
2115 if (isdigit (optarg[0]))
2116 /* As decimal, octal, or hexadicimal number. */
2117 escape_char = (int) strtoul (optarg, NULL, 0);
2119 /* As character directly. */
2120 escape_char = ((unsigned char *) optarg)[0];
2124 case 'E': /* highlight */
2126 special_escapes = 1;
2128 hl_start_state = optarg;
2131 case 'f': /* font */
2132 if (!parse_font_spec (optarg, &Fname, &Fpt, NULL))
2133 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2134 user_body_font_defined = 1;
2137 case 'F': /* header font */
2138 if (!parse_font_spec (optarg, &HFname, &HFpt, NULL))
2139 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2142 case 'g': /* print anyway */
2146 case 'G': /* fancy header */
2149 fancy_header_name = optarg;
2151 fancy_header_name = fancy_header_default;
2153 if (!file_existsp (fancy_header_name, ".hdr"))
2155 _("couldn't find header definition file \"%s.hdr\""),
2156 fancy_header_name));
2159 case 'h': /* no job header */
2163 case 'H': /* highlight bars */
2165 highlight_bars = atoi (optarg);
2170 case 'i': /* line indent */
2171 line_indent_spec = optarg;
2174 case 'I': /* input filter */
2175 input_filter = optarg;
2178 case 'j': /* borders */
2182 case 'k': /* enable page prefeed */
2186 case 'K': /* disable page prefeed */
2190 case 'l': /* emulate lineprinter */
2191 lines_per_page = 66;
2195 case 'L': /* lines per page */
2196 lines_per_page = atoi (optarg);
2197 if (lines_per_page <= 0)
2199 _("must print at least one line per each page: %s"),
2203 case 'm': /* send mail upon completion */
2207 case 'M': /* select output media */
2208 media_name = xstrdup (optarg);
2211 case 'n': /* num copies */
2213 num_copies = atoi (optarg);
2216 case 'N': /* newline character */
2217 if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0')
2219 fprintf (stderr, _("%s: illegal newline character specifier: \
2220 '%s': expected 'n' or 'r'\n"),
2224 if (optarg[0] == 'n')
2231 case 'p': /* output file */
2232 /* Check output file "-". */
2233 if (strcmp (optarg, "-") == 0)
2234 output_file = OUTPUT_FILE_STDOUT;
2236 output_file = optarg;
2239 case 'O': /* list missing characters */
2240 list_missing_characters = 1;
2243 case 'q': /* quiet */
2248 case 'r': /* landscape */
2252 case 'R': /* portrait */
2256 case 's': /* baselineskip */
2257 baselineskip = atof (optarg);
2260 case 'S': /* statusdict */
2261 parse_key_value_pair (statusdict, optarg);
2264 case 't': /* title */
2270 case 'T': /* tabulator size */
2271 tabsize = atoi (optarg);
2276 case 'u': /* underlay */
2281 nup = atoi (optarg);
2284 case 'v': /* verbose */
2286 verbose = atoi (optarg);
2292 case 'V': /* version */
2297 case 'w': /* output language */
2298 output_language = optarg;
2299 if (strcmp (output_language, "PostScript") != 0)
2300 /* Other output languages are handled with states. */
2301 output_language_pass_through = 1;
2304 case 'W': /* a helper application option */
2305 cp = strchr (optarg, ',');
2308 _("malformed argument `%s' for option -W, --option: \
2312 if (cp - optarg != 1)
2313 FATAL ((stderr, _("helper application specification must be \
2314 single character: %s"),
2317 /* Take the index of the helper application and update `cp'
2318 to point to the beginning of the option. */
2322 if (helper_options[i] == NULL)
2323 helper_options[i] = buffer_alloc ();
2326 /* We already had some options for this helper
2327 application. Let's separate these arguments. */
2328 buffer_append (helper_options[i], " ");
2331 /* Add this new option. */
2332 buffer_append (helper_options[i], cp);
2335 case 'X': /* input encoding */
2336 xfree (encoding_name);
2337 encoding_name = xstrdup (optarg);
2340 case 'z': /* no form feeds */
2341 interpret_formfeed = 0;
2344 case 'Z': /* pass through */
2348 case 128: /* underlay font */
2349 if (!parse_font_spec (optarg, &ul_font, &ul_ptsize, NULL))
2350 FATAL ((stderr, _("malformed font spec: %s"), optarg));
2353 case 129: /* underlay gray */
2354 ul_gray = atof (optarg);
2357 case 130: /* page label format */
2358 xfree (page_label_format);
2359 page_label_format = xstrdup (optarg);
2362 case 131: /* download font */
2363 strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL,
2367 case 132: /* underlay angle */
2368 ul_angle = atof (optarg);
2372 case 133: /* underlay position */
2373 xfree (ul_position);
2374 ul_position = xstrdup (optarg);
2378 case 134: /* non-printable format */
2380 npf_name = xstrdup (optarg);
2383 case 135: /* help */
2388 case 136: /* highlight bar gray */
2389 highlight_bar_gray = atof (optarg);
2392 case 137: /* underlay style */
2393 xfree (ul_style_str);
2394 ul_style_str = xstrdup (optarg);
2397 case 138: /* filter stdin */
2398 input_filter_stdin = optarg;
2401 case 139: /* extra options for the printer spooler */
2402 printer_options = optarg;
2405 case 140: /* slicing */
2407 slice = atoi (optarg);
2409 FATAL ((stderr, _("slice must be greater than zero")));
2412 case 141: /* help-highlight */
2416 case 142: /* States color? */
2420 states_color = atoi (optarg);
2423 case 143: /* mark-wrapped-lines */
2426 xfree (mark_wrapped_lines_style_name);
2427 mark_wrapped_lines_style_name = xstrdup (optarg);
2430 /* Set the system default. */
2431 mark_wrapped_lines_style = MWLS_BOX;
2434 case 144: /* adjust margins */
2435 margins_spec = optarg;
2438 case 145: /* N-up x-pad */
2439 nup_xpad = atoi (optarg);
2442 case 146: /* N-up y-pad */
2443 nup_ypad = atoi (optarg);
2446 case 147: /* word wrap */
2447 line_end = LE_WORD_WRAP;
2450 case 148: /* horizontal column height */
2451 horizontal_column_height = atof (optarg);
2452 formfeed_type = FORMFEED_HCOLUMN;
2455 case 149: /* PostScript language level */
2456 pslevel = atoi (optarg);
2459 case 150: /* rotate even-numbered pages */
2460 rotate_even_pages = 1;
2463 case 151: /* highlight style */
2464 xfree (states_highlight_style);
2465 states_highlight_style = xstrdup (optarg);
2468 case 152: /* N-up colunwise */
2472 case 153: /* swap even page margins */
2473 swap_even_page_margins = 1;
2476 case 154: /* extended return values */
2477 extended_return_values = 1;
2480 case 155: /* footer */
2481 page_footer = optarg;
2484 case 156: /* continuous page numbers */
2485 continuous_page_numbers = 1;
2488 case '?': /* Errors found during getopt_long(). */
2490 fprintf (stderr, _("Try `%s --help' for more information.\n"),
2496 printf ("Hey! main() didn't handle option \"%c\" (%d)", c, c);
2498 printf (" with arg %s", optarg);
2500 FATAL ((stderr, "This is a bug!"));
2511 Usage: %s [OPTION]... [FILE]...\n\
2512 Mandatory arguments to long options are mandatory for short options too.\n\
2513 -# an alias for option -n, --copies\n\
2514 -1 same as --columns=1\n\
2515 -2 same as --columns=2\n\
2516 --columns=NUM specify the number of columns per page\n\
2517 -a, --pages=PAGES specify which pages are printed\n\
2518 -A, --file-align=ALIGN align separate input files to ALIGN\n\
2519 -b, --header=HEADER set page header\n\
2520 -B, --no-header no page headers\n\
2521 -c, --truncate-lines cut long lines (default is to wrap)\n\
2522 -C, --line-numbers[=START]\n\
2523 precede each line with its line number\n\
2524 -d an alias for option --printer\n\
2525 -D, --setpagedevice=KEY[:VALUE]\n\
2526 pass a page device definition to output\n\
2527 -e, --escapes[=CHAR] enable special escape interpretation\n"),
2531 -E, --highlight[=LANG] highlight source code\n"));
2534 -f, --font=NAME use font NAME for body text\n\
2535 -F, --header-font=NAME use font NAME for header texts\n\
2536 -g, --print-anyway nothing (compatibility option)\n\
2537 -G same as --fancy-header\n\
2538 --fancy-header[=NAME] select fancy page header\n\
2539 -h, --no-job-header suppress the job header page\n\
2540 -H, --highlight-bars=NUM specify how high highlight bars are\n\
2541 -i, --indent=NUM set line indent to NUM characters\n\
2542 -I, --filter=CMD read input files through input filter CMD\n\
2543 -j, --borders print borders around columns\n\
2544 -J, an alias for option --title\n\
2545 -k, --page-prefeed enable page prefeed\n\
2546 -K, --no-page-prefeed disable page prefeed\n\
2547 -l, --lineprinter simulate lineprinter, this is an alias for:\n\
2548 --lines-per-page=66, --no-header, --portrait,\n\
2552 -L, --lines-per-page=NUM specify how many lines are printed on each page\n\
2553 -m, --mail send mail upon completion\n\
2554 -M, --media=NAME use output media NAME\n\
2555 -n, --copies=NUM print NUM copies of each page\n\
2556 -N, --newline=NL select the newline character. Possible\n\
2557 values for NL are: n (`\\n') and r (`\\r').\n\
2558 -o an alias for option --output\n\
2559 -O, --missing-characters list missing characters\n\
2560 -p, --output=FILE leave output to file FILE. If FILE is `-',\n\
2561 leave output to stdout.\n\
2562 -P, --printer=NAME print output to printer NAME\n\
2563 -q, --quiet, --silent be really quiet\n\
2564 -r, --landscape print in landscape mode\n\
2565 -R, --portrait print in portrait mode\n"));
2568 -s, --baselineskip=NUM set baselineskip to NUM\n\
2569 -S, --statusdict=KEY[:VALUE]\n\
2570 pass a statusdict definition to the output\n\
2571 -t, --title=TITLE set banner page's job title to TITLE. Option\n\
2572 sets also the name of the input file stdin.\n\
2573 -T, --tabsize=NUM set tabulator size to NUM\n\
2574 -u, --underlay[=TEXT] print TEXT under every page\n\
2575 -U, --nup=NUM print NUM logical pages on each output page\n\
2576 -v, --verbose tell what we are doing\n\
2577 -V, --version print version number\n\
2578 -w, --language=LANG set output language to LANG\n\
2579 -W, --options=APP,OPTION pass option OPTION to helper application APP\n\
2580 -X, --encoding=NAME use input encoding NAME\n\
2581 -z, --no-formfeed do not interpret form feed characters\n\
2582 -Z, --pass-through pass through PostScript and PCL files\n\
2583 without any modifications\n"));
2585 printf (_("Long-only options:\n\
2586 --color[=bool] create color outputs with states\n\
2587 --continuous-page-numbers count page numbers across input files. Don't\n\
2588 restart numbering at beginning of each file.\n\
2589 --download-font=NAME download font NAME\n\
2590 --extended-return-values enable extended return values\n\
2591 --filter-stdin=NAME specify how stdin is shown to the input filter\n\
2592 --footer=FOOTER set page footer\n\
2593 --h-column-height=HEIGHT set the horizontal column height to HEIGHT\n\
2594 --help print this help and exit\n"));
2597 --help-highlight describe all supported --highlight languages\n\
2599 --highlight-bar-gray=NUM print highlight bars with gray NUM (0 - 1)\n\
2600 --list-media list names of all known media\n\
2601 --margins=LEFT:RIGHT:TOP:BOTTOM\n\
2602 adjust page marginals\n\
2603 --mark-wrapped-lines[STYLE]\n\
2604 mark wrapped lines in the output with STYLE\n\
2605 --non-printable-format=FMT specify how non-printable chars are printed\n"));
2608 --nup-columnwise layout pages in the N-up printing columnwise\n\
2609 --nup-xpad=NUM set the page x-padding of N-up printing to NUM\n\
2610 --nup-ypad=NUM set the page y-padding of N-up printing to NUM\n\
2611 --page-label-format=FMT set page label format to FMT\n\
2612 --ps-level=LEVEL set the PostScript language level that enscript\n\
2614 --printer-options=OPTIONS pass extra options to the printer command\n\
2615 --rotate-even-pages rotate even-numbered pages 180 degrees\n"));
2618 --slice=NUM print vertical slice NUM\n\
2619 --style=STYLE use highlight style STYLE\n\
2620 --swap-even-page-margins swap left and right side margins for each even\n\
2622 --toc print table of contents\n\
2623 --ul-angle=ANGLE set underlay text's angle to ANGLE\n\
2624 --ul-font=NAME print underlays with font NAME\n\
2625 --ul-gray=NUM print underlays with gray value NUM\n\
2626 --ul-position=POS set underlay's starting position to POS\n\
2627 --ul-style=STYLE print underlays with style STYLE\n\
2628 --word-wrap wrap long lines from word boundaries\n\
2631 printf (_("\nReport bugs to mtr@iki.fi.\n"));
2639 Copyright (C) 2003 Markku Rossi.\n\
2640 GNU enscript comes with NO WARRANTY, to the extent permitted by law.\n\
2641 You may redistribute copies of GNU enscript under the terms of the GNU\n\
2642 General Public License. For more information about these matters, see\n\
2643 the files named COPYING.\n",