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