source: tags/arb-6.0/TOOLS/arb_a2ps.c

Last change on this file was 9899, checked in by epruesse, 11 years ago

pass down argc/argv to AW_root::AW_root (for GTK)
GTK will pick its parameters (e.g. —g-fatal-warnings) from argv and
remove them, hence argv must not be const and AW_root() should
be called before command line parsing (if possible).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.9 KB
Line 
1//**********************************************************************
2/*                                                                      */
3// Description: Ascii to PostScript printer program.
4// File: bounty:/archive/src/a2ps/Last/a2ps.c
5// Created: Fri Nov 5 8:20 1993 by miguel@bountyimag.fr (Miguel Santana)
6// Version: 4.3
7/*                                                                      */
8// Edit history:
9// 1) Derived of shell program written by evan@csli (Evan Kirshenbaum).
10//    Written in C for improve speed execution and portability. Many
11//    improvements have been added.
12// Fixes by Oscar Nierstrasz @ cui.uucp:
13// 2) Fixed incorrect handling of stdin (removed error if no file names)
14// 3) Added start_page variable to eliminate blank pages printed for
15//      files that are exactly multiples of 132 lines (e.g., man pages)
16// Modified by santana@imag.fr:
17// 4) Added new options at installation : sheet format (height/width in
18//    inches), page format (number of columns per line and of lines per
19//    page).
20// Modified by santana@imag.fr:
21// 5) Added new option to print n copies of a same document.
22// 6) Cut long filenames if don't fit in the page header.
23// Modified by Tim Clark (T.Clark@warwick.ac.uk):
24// 7) Two additional modes of printing (portrait and wide format modes)
25// 8) Fixed to cope with filenames which contain a character which must
26//    be escaped in a PostScript string.
27// Modified by santana@imag.fr to
28// 9) Added new option to suppress heading printing.
29// 10) Added new option to suppress page surrounding border printing.
30// 11) Added new option to change font size. Lines and columns are
31//     automatically adjusted, depending on font size and printing mode
32// 12) Minor changes (best layout, usage message, etc).
33// Modified by tullemans@apolloway.prl.philips.nl
34// 13) Backspaces (^H) are now handled correctly.
35// Modified by Johan Vromans (jv@mh.nl) to
36// 14) Added new option to give a header title that replaces use of
37//     filename.
38// Modified by craig.r.stevenson@att.com to
39// 15) Print last modification date/time in header
40// 16) Printing current date/time on left side of footer (optional)
41// Modified by erikt@cs.umu.se:
42// 17) Added lpr support for the BSD version
43// 18) Added som output of pages printed.
44// Modified by wstahw@lso.win.tue.nl:
45// 19) Added option to allowing the printing of 2 files in one sheet
46// Modified by mai@wolfen.cc.uow.oz
47// 20) Added an option to set the lines per page to a specified value.
48// 21) Added support for printing nroff manuals
49// Modified by santana@imag.fr
50// 22) Integration of changes.
51// 23) No more standard header file (printed directly by a2ps).
52// 24) New format for command options.
53// 25) Other minor changes.
54// Modified by Johan Garpendahl (garp@isy.liu.se) and santana@imag.fr:
55// 26) Added 8-bit characters printing as ISO-latin 1 chars
56// Modified by John Interrante (interran@uluru.stanford.edu) and
57// santana@imag.fr:
58// 27) Two pages per physical page in portrait mode
59// Modified by santana@imag.fr:
60// 28) New option for two-sided printing
61// 29) Several fixes
62// Modified by Chris Adamo (adamo@ll.mit.edu) and
63//     Larry Barbieri (lbarbieri@ll.mit.edu) 3/12/93
64// 30) Output format enhancements.
65// 31) Added login_id flag (for SYSV and BSD only) for printing user's
66//     login ID at top of page.  Added command line parameter (-nL) to
67//     suppress this feature.
68// 33) Added filename_footer flag for printing file name at bottom
69//     of page.  Added command line parameter (-nu) to suppress this
70//     feature.
71// 34) Added -B (-nB) options to enable (disable) bold font
72// Modified by santana@imag.fr:
73// 35) Adapted to respect Adobe conventions for page independence. A2ps
74//     output can be now used by other Postscript processors.
75// 36) Names of most postscript variables have been coded in order to
76//     reduce the size of the output.
77// 37) Ansi C compilers are now automatically taken into account.
78// 38) Enhanced routine for cutting long filenames
79// 39) Added -q option to print files in quiet mode (no summary)
80// 40) Fixed some little bugs (counters, modification time for stdin,
81//     character separator when printing line numbers and cutting a
82//     line).
83// 41) Some minor changes (new preprocessing variables, formatting)
84/*                                                                      */
85//**********************************************************************
86
87/*
88 * Copyright (c) 1993, 1994, Miguel Santana, M.Santana@frgu.bull.fr
89 *
90 * Permission is granted to use, copy, and distribute this software for
91 * non commercial use, provided that the above copyright notice appear in
92 * all copies and that both that copyright notice and this permission
93 * notice appear in supporting documentation.
94 *
95 * Permission to modify the software is granted, but not the right to
96 * distribute the modified code. Please report bugs and changes to
97 * M.Santana@frgu.bull.fr
98 *
99 * This software is provided "as is" without express or implied warranty.
100 */
101
102
103//**********************************************************************
104/*                                                                      */
105//                      I n c l u d e   f i l e s
106/*                                                                      */
107//**********************************************************************
108
109#include <stdio.h>
110#include <stdlib.h>
111#include <unistd.h>
112#include <ctype.h>
113#include <sys/types.h>
114#include <sys/stat.h>
115#include <errno.h>
116
117#ifdef __STDC__
118#include <stdlib.h>
119#include <time.h>
120#include <string.h>
121#else
122#include <strings.h>
123#ifdef SYSV
124#include <sys/timeb.h>
125#include <time.h>
126#include <sys/utsname.h>
127#else
128#ifndef BSD
129#define BSD     1
130#endif
131#include <sys/time.h>
132#endif
133#endif
134
135
136//**********************************************************************
137/*                                                                      */
138//           P r e p r o c e s s i n g   d e f i n i t i o n s
139/*                                                                      */
140//**********************************************************************
141
142/*
143 * Common definitions
144 */
145#define FALSE           0
146#define TRUE            1
147#ifndef NULL
148#define NULL            0
149#endif
150#ifndef NUL
151#define NUL             '\0'
152#endif
153#ifndef EXIT_SUCCESS
154#define EXIT_SUCCESS    0
155#endif
156#ifndef EXIT_FAILURE
157#define EXIT_FAILURE    1
158#endif
159
160
161/*
162 * Version
163 */
164#define VERSION "4.3"
165#define LPR_PRINT 1
166
167/*
168 * Default page dimensions
169 */
170#ifndef WIDTH
171#define WIDTH   8.27
172#endif
173
174#ifndef HEIGHT
175#define HEIGHT  11.0
176#endif
177
178#ifndef MARGIN
179#define MARGIN  .5
180#endif
181
182
183/*
184 * Pathname separator for file system
185 */
186#ifndef DIR_SEP
187#define DIR_SEP '/'
188#endif
189
190
191/*
192 * Printing parameters
193 */
194#if LPR_PRINT
195
196#ifndef LPR_COMMAND
197#define LPR_COMMAND     "lpr"
198#endif
199
200#ifndef LPR_OPT
201#define LPR_OPT "-l"
202#endif
203
204#if defined(ONESIDED) && defined(TWOSIDED)
205#define RECTO_VERSO_PRINTING
206#ifndef TWOSIDED_DFLT
207#define TWOSIDED_DFLT   TRUE
208#endif
209#endif
210
211#endif
212
213
214/*
215 * Configuration values
216 */
217#define PORTRAIT_HEADER         0.29
218#define LANDSCAPE_HEADER        0.22
219#define PIXELS_INCH             72
220#define MAXFILENAME             32
221#define MAX_LINES               320             // max. lines per page
222#define MAN_LINES               66              // no lines for a man
223#define IS_ROMAN                0               // normal font
224#define IS_BOLD                 1               // bold sequence flag
225#if defined(SYSV) || defined(BSD)
226#define MAX_HOSTNAME            40
227#endif
228
229
230//**********************************************************************
231/*                                                                      */
232//                 G l o b a l   d e f i n i t i o n s
233/*                                                                      */
234//**********************************************************************
235
236
237/*
238 * Global types
239 */
240typedef enum { BOLD, NORMAL } WEIGHT;           // font weights
241
242
243/*
244 * Function declarations.
245 */
246
247static void print_page_prologue(int side);
248static void print_standard_prologue(char *datestring);
249static void startpage();
250static void endpage();
251
252#if defined(SYSV) || defined(BSD)
253char *getlogin();
254#endif
255#if defined(BSD)
256int   gethostname(char *name, int namelen);
257#endif
258
259/*
260 * Flags related to options.
261 */
262static int numbering = FALSE;          // Line numbering option
263static int folding = TRUE;             // Line folding option
264static int restart = FALSE;            // Don't restart page number after each file
265static int only_printable = FALSE;     // Replace non printable char by space
266static int interpret = TRUE;           // Interpret TAB, FF and BS chars option
267static int print_binaries = FALSE;     // Force printing for binary files
268static int landscape = TRUE;           // Otherwise portrait format sheets
269static int new_landscape = TRUE;       // To scrute changes of landscape option
270static int twinpages = TRUE;           // 2 pages per sheet if true, 1 otherwise
271static int new_twinpages = TRUE;       // To scrute changes of twinpages option
272static int twinfiles = FALSE;          // Allow 2 files per sheet
273static int no_header = FALSE;          // TRUE if user doesn't want the header
274static int no_border = FALSE;          // Don't print the surrounding border ?
275static int printdate = FALSE;          // Print current date as footnote
276static int filename_footer = TRUE;     // Print file name at bottom of page
277static int no_summary = FALSE;         // Quiet mode?
278static WEIGHT fontweight = NORMAL;     // Control font weight: BOLD or NORMAL
279static WEIGHT new_fontweight = NORMAL; // To scrute changes of bold option
280#if defined(SYSV) || defined(BSD)
281int login_id = TRUE;            // Print login ID at top of page
282#endif
283#if LPR_PRINT
284static int lpr_print = TRUE;           // Fork a lpr process to do the printing
285#ifdef RECTO_VERSO_PRINTING
286int rectoverso = TWOSIDED_DFLT; // Two-side printing
287#endif
288#endif
289static int ISOlatin1 = FALSE;          // Print 8-bit characters?
290
291
292/*
293 * Counters of different kinds.
294 */
295static int column = 0;                 // Column number (in current line)
296static int line = 0;                   // Line number (in current page)
297static int line_number = 0;            // Source line number
298static int pages = 0;                  // Number of logical pages printed
299static int sheets = 0;                 // Number of physical pages printed
300static int old_pages, old_sheets;      // Value before printing current file
301static int sheetside = 0;              // Side of the sheet currently printing
302static int linesperpage;               // Lines per page
303static int lines_requested = 0;        // Lines per page requested by the user
304static int new_linesrequest = 0;       // To scrute new values for lines_requested
305static int columnsperline;             // Characters per output line
306static int nonprinting_chars, chars;   // Number of nonprinting and total chars
307static int copies_number = 1;          // Number of copies to print
308static int column_width = 8;           // Default column tab width (8)
309
310
311/*
312 * Other global variables.
313 */
314static int first_page;                 // First page for a file
315static int no_files = TRUE;            // No file until now
316static int prefix_width;               // Width in characters for line prefix
317static float fontsize = 0.0;           // Size of a char for body font
318static float new_fontsize = 0.0;       // To scrute new values for fontsize
319static char *command;                  // Name of a2ps program
320static char *lpr_opt = NULL;           // Options to lpr
321static char *header_text = NULL;       // Allow for different header text
322static float header_size;              // Size of the page header
323static char *prologue = NULL;          // postscript header file
324static char current_filename[MAXFILENAME+1];   // Name of the file being printed
325static char currentdate[18];           // Date for today
326static char filedate[18];              // Last modification time for current file
327#if defined(SYSV) || defined(BSD)
328char *login = NULL;             // user's login name and host machine
329#endif
330
331
332/*
333 * Sheet dimensions
334 */
335static double page_height = HEIGHT;    // Paper height
336static double page_width = WIDTH;      // Paper width
337
338
339//**********************************************************************
340/*                                                                      */
341/*                                                                      */
342//**********************************************************************
343
344/*
345 * Print a usage message.
346 */
347static void usage(int failure) {
348    // failure: Must we exit with a failure code?
349    fprintf(stderr, "A2ps v%s usage: %s [pos. or global options] [ f1 [ [pos. options] f2 ...] ]\n", VERSION, command);
350    fprintf(stderr, "pos.   =  -#num\t\tnumber of copies to print\n");
351    fprintf(stderr, "          -1\t\tone page per sheet\n");
352    fprintf(stderr, "          -2\t\tTWIN PAGES per sheet\n");
353    fprintf(stderr, "          -d\t-nd\tprint (DON'T PRINT) current date at the bottom\n");
354    fprintf(stderr, "          -Fnum\t\tfont size, num is a float number\n");
355    fprintf(stderr, "          -Hstr\t\tuse str like header title for subsequent files\n");
356#if defined(SYSV) || defined(BSD)
357    fprintf(stderr, "          \t-nL\tdon't print login ID on top of page\n");
358#endif
359    fprintf(stderr, "          -l\t\tprint in LANDSCAPE mode\n");
360    fprintf(stderr, "          -lnum\t\tuse num lines per page\n");
361    fprintf(stderr, "          -m\t\tprocess the file as a man\n");
362    fprintf(stderr, "          -n\t-nn\tNUMBER (don't number) line files\n");
363    fprintf(stderr, "          -p\t\tprint in portrait mode\n");
364    fprintf(stderr, "          -q\t\tprint in quiet mode (no summary)\n");
365    fprintf(stderr, "          -s\t-ns\tPRINT (don't print) surrounding borders\n");
366    fprintf(stderr, "\n");
367    fprintf(stderr, "global =  -?\t\tprint this information\n");
368    fprintf(stderr, "          -B\t-nB\tprint (DON'T PRINT) in bold font\n");
369    fprintf(stderr, "          -b\t-nb\tforce (DON'T FORCE) binary printing\n");
370    fprintf(stderr, "          -c\t-nc\tallow (DON'T ALLOW) two files on the same sheet\n");
371    fprintf(stderr, "          -f\t-nf\tFOLD (don't fold) lines\n");
372    fprintf(stderr, "          \t-nH\tdon't print any header\n");
373    fprintf(stderr, "          -h\t\tprint this information\n");
374    fprintf(stderr, "          -Ifile\tinclude this file as a2ps prologue\n");
375    fprintf(stderr, "          -i\t-ni\tINTERPRET (don't interpret) tab, bs and ff chars\n");
376#if LPR_PRINT
377    fprintf(stderr, "          -Pprinter -nP\tSEND (don't send) directly to the printer");
378#ifdef LPR_OPT
379    if (LPR_OPT != NULL && sizeof(LPR_OPT) > 0)
380        fprintf(stderr, "\n\t\t\t(with options '%s' and -Pprinter)", LPR_OPT);
381#endif
382    fprintf(stderr, "\n");
383#endif
384    fprintf(stderr, "          -r\t-nr\tRESTART (don't restart) page number after each file\n");
385#ifdef RECTO_VERSO_PRINTING
386#ifdef TWOSIDED_DFLT
387    fprintf(stderr, "          -s1\t-s2\tone-sided (TWO-SIDED) printing\n");
388#else
389    fprintf(stderr, "          -s1\t-s2\tONE-SIDED (two-sided) printing\n");
390#endif
391#endif
392    fprintf(stderr, "          -tnum\t\tset tab size to n\n");
393    fprintf(stderr, "          \t-nu\tdon't print a filename footer\n");
394    fprintf(stderr, "          -v\t-nv\tVISIBLE (blank) display of unprintable chars\n");
395    fprintf(stderr, "          -8\t-n8\tdisplay (DON'T DISPLAY) 8-bit chars\n");
396    exit(failure);
397}
398
399/*
400 * Set an option only if it's global.
401 */
402static void set_global_option(char *arg) {
403    switch (arg[1]) {
404        case '?':                               // help
405        case 'h':
406            usage(EXIT_SUCCESS);
407        case 'b':                               // print binary files
408            if (arg[2] != NUL)
409                usage(EXIT_FAILURE);
410            print_binaries = TRUE;
411            break;
412        case 'c':                               // allow two files per sheet
413            if (arg[2] != NUL)
414                usage(EXIT_FAILURE);
415            twinfiles = TRUE;
416            break;
417        case 'f':                               // fold lines too large
418            if (arg[2] != NUL)
419                usage(EXIT_FAILURE);
420            folding = TRUE;
421            break;
422        case 'I':                               // include this file as a2ps prologue
423            if (arg[2] == NUL)
424                usage(EXIT_FAILURE);
425            prologue = arg+2;
426            break;
427        case 'i':                               // interpret control chars
428            if (arg[2] != NUL)
429                usage(EXIT_FAILURE);
430            interpret = TRUE;
431            break;
432        case 'n':
433            if (arg[2] == NUL)
434                return;
435            if (arg[3] != NUL)
436                usage(EXIT_FAILURE);
437            switch (arg[2]) {
438                case 'b':                       // don't print binaries
439                    print_binaries = FALSE;
440                    break;
441                case 'c':                       // don't allow 2 files/sheet
442                    twinfiles = FALSE;
443                    break;
444                case 'f':                       // cut lines too long
445                    folding = FALSE;
446                    break;
447                case 'H':                       // don't print header
448                    no_header = TRUE;
449                    break;
450                case 'i':                       // don't interpret ctrl chars
451                    interpret = FALSE;
452                    break;
453#if LPR_PRINT
454                case 'P':                       // don't lpr
455                    lpr_print = FALSE;
456                    break;
457#endif
458                case 'r':                       // don't restart sheet number
459                    restart = FALSE;
460                    break;
461                case 'v':                       // only printable chars
462                    only_printable = TRUE;
463                    break;
464                case '8':                       // don't print 8-bit chars
465                    ISOlatin1 = FALSE;
466                    break;
467                case 'B':
468                case 'd':
469                case 'L':
470                case 'm':
471                case 'n':
472                case 's':
473                case 'u':
474                    if (arg[3] != NUL)
475                        usage(EXIT_FAILURE);
476                    return;
477                default:
478                    usage(EXIT_FAILURE);
479            }
480            break;
481#if LPR_PRINT
482        case 'P':                                       // fork a process to print
483            if (arg[2] != NUL) {
484                lpr_opt = (char *)malloc(strlen(arg)+1);
485                strcpy(lpr_opt, arg);
486            }
487            lpr_print = TRUE;
488            break;
489#endif
490        case 'q':                                       // don't print a summary
491            no_summary = TRUE;
492            break;
493        case 'r':                                       // restart sheet number
494            if (arg[2] != NUL)
495                usage(EXIT_FAILURE);
496            restart = TRUE;
497            break;
498        case 's':
499            if (arg[2] == NUL)
500                return;
501#ifdef RECTO_VERSO_PRINTING
502            if (arg[3] == NUL) {
503                if (arg[2] == '1') {            // one-sided printing
504                    rectoverso = FALSE;
505                    break;
506                }
507                if (arg[2] == '2') {            // two-sided printing
508                    rectoverso = TRUE;
509                    break;
510                }
511            }
512#endif
513            usage(EXIT_FAILURE);
514            break;
515        case 't':                               // set tab size
516            if (arg[2] == NUL || (column_width = atoi(arg+2)) <= 0)
517                usage(EXIT_FAILURE);
518            break;
519        case 'v':                               // print control chars
520            if (arg[2] != NUL)
521                usage(EXIT_FAILURE);
522            only_printable = FALSE;
523            break;
524        case '8':                               // print 8-bit chars
525            if (arg[2] != NUL)
526                usage(EXIT_FAILURE);
527            ISOlatin1 = TRUE;
528            break;
529        case '1':
530        case '2':
531        case 'B':
532        case 'd':
533        case 'm':
534        case 'p':
535            if (arg[2] != NUL)
536                usage(EXIT_FAILURE);
537        case '#':
538        case 'F':
539        case 'H':
540        case 'l':
541            return;
542        default:
543            usage(EXIT_FAILURE);
544    }
545    arg[0] = NUL;
546}
547
548/*
549 * Set an option of the command line. This option will be applied
550 * to all files that will be found in the rest of the command line.
551 * The -H option is the only exception: it is applied only to the
552 * file.
553 */
554static void set_positional_option(char *arg) {
555    int copies;
556    int lines;
557    float size;
558
559    switch (arg[1]) {
560        case NUL:                               // global option
561            break;
562        case '#':                               // n copies
563            if (sscanf(&arg[2], "%d", &copies) != 1 || copies <= 0)
564                fprintf(stderr, "Bad number of copies: '%s'. Ignored\n", &arg[2]);
565            else
566                copies_number = copies;
567            printf("/#copies %d def\n", copies_number);
568            break;
569        case '1':                               // 1 logical page per sheet
570            if (arg[2] != NUL)
571                usage(EXIT_FAILURE);
572            new_twinpages = FALSE;
573            break;
574        case '2':                               // twin pages
575            if (arg[2] != NUL)
576                usage(EXIT_FAILURE);
577            new_twinpages = TRUE;
578            break;
579        case 'B':
580            new_fontweight = BOLD;              // use bold font
581            break;
582        case 'd':                               // print current date/time
583            printdate = TRUE;
584            break;
585        case 'F':                               // change font size
586            if (arg[2] == NUL || sscanf(&arg[2], "%f", &size) != 1 || size == 0.0) {
587                fprintf(stderr, "Wrong value for option -F: '%s'. Ignored\n",
588                        &arg[2]);
589                break;
590            }
591            new_fontsize = size;
592            break;
593        case 'H':                               // header text
594            header_text = arg+2;
595            break;
596        case 'l':
597            if (arg[2] == NUL) {                // landscape format
598                new_landscape = TRUE;
599                break;
600            }
601            // set lines per page
602            // Useful with preformatted files. Scaling is automatically
603            // done when necessary.
604            if (sscanf(&arg[2], "%d", &lines) != 1
605                || lines < 0 || lines > MAX_LINES)
606            {
607                fprintf(stderr, "Wrong value for option -l: '%s'. Ignored\n",
608                        &arg[2]);
609                break;
610            }
611            new_linesrequest = lines;
612            break;
613        case 'm':                               // Process file as a man
614            new_linesrequest = MAN_LINES;
615            numbering = FALSE;
616            break;
617        case 'n':                               // number file lines
618            if (arg[2] == NUL) {
619                numbering = TRUE;
620                break;
621            }
622            switch (arg[2]) {
623                case 'B':                       // disable bold text
624                    new_fontweight = NORMAL;
625                    break;
626                case 'd':                       // don't print date/time
627                    printdate = FALSE;
628                    break;
629#if defined(SYSV) || defined(BSD)
630                case 'L':                       // no login name in footer
631                    login_id = FALSE;
632                    break;
633#endif
634                case 'l':                       // portrait format
635                    new_landscape = FALSE;
636                    break;
637                case 'm':                       // stop processing as a man
638                    new_linesrequest = 0;
639                    break;
640                case 'n':                       // don't number lines
641                    numbering = FALSE;
642                    break;
643                case 'p':                       // landscape format
644                    new_landscape = TRUE;
645                    break;
646                case 's':                       // no surrounding border
647                    no_border = TRUE;
648                    break;
649                case 'u':                       // no filename in footer
650                    filename_footer = FALSE;
651                    break;
652                default:
653                    usage(EXIT_FAILURE);
654            }
655            break;
656        case 'p':                               // portrait format
657            if (arg[2] != NUL)
658                usage(EXIT_FAILURE);
659            new_landscape = FALSE;
660            break;
661        case 's':                               // surrounding border
662            if (arg[2] != NUL)
663                usage(EXIT_FAILURE);
664            no_border = FALSE;
665            break;
666        default:
667            usage(EXIT_FAILURE);
668    }
669}
670
671
672//**************************************************************
673//                      Service routines
674//**************************************************************
675
676/*
677 * This routine buffers a line of input, release one character at a time
678 * or a whole sequence of characters with some meaning like bold sequences
679 * produced by nroff (no others sequences are recognized by the moment):
680 *        <c><\b><c><\b><c><\b><c>
681 */
682static int mygetc(int *statusp) {
683#define BUFFER_SIZE     512
684    static int curr = 0;
685    static int size = 0;
686    static unsigned char buffer[BUFFER_SIZE+1];
687    int c;
688
689    *statusp = IS_ROMAN;
690
691    // Read a new line, if necessary
692    if (curr >= size) {
693        if (fgets((char *)buffer, BUFFER_SIZE+1, stdin) == NULL)
694            return  EOF;
695        size = strlen((char *)buffer);
696        if (size < BUFFER_SIZE && buffer[size-1] != '\n') {
697            buffer[size] = '\n';
698            buffer[++size] = '\0';
699        }
700        curr = 0;
701    }
702    if (buffer[curr+1] != '\b')         // this is not a special sequence
703        return  buffer[curr++];
704
705    // Check if it is a bold sequence
706    c = buffer[curr++];
707    if (c               == buffer[curr+1] &&
708        buffer[curr]    == buffer[curr+2] &&
709        c               == buffer[curr+3] &&
710        buffer[curr]    == buffer[curr+4] &&
711        c               == buffer[curr+5])
712    {
713        *statusp = IS_BOLD;
714        curr += 6;
715    }
716
717    // Return the first character of the sequence
718    return  c;
719}
720
721/*
722 * Test if we have a binary file.
723 */
724static int is_binaryfile(char *name) {
725    if (chars > 120 || pages > 1) {
726        first_page = FALSE;
727        if (chars && !print_binaries && (nonprinting_chars*100 / chars) >= 60) {
728            fprintf(stderr, "%s is a binary file: printing aborted\n", name);
729            return TRUE;
730        }
731    }
732    return FALSE;
733}
734
735/*
736 * Cut long filenames.
737 */
738static void cut_filename(char *old_name, char *new_name) {
739    char *p;
740    int   i;
741    char *separator;
742
743    if ((i = strlen(old_name)) <= MAXFILENAME) {
744        strcpy(new_name, old_name);
745        return;
746    }
747    p = old_name + (i-1);
748    separator = NULL;
749    i = 1;
750    while (p >= old_name && i < MAXFILENAME) {
751        if (*p == DIR_SEP)
752            separator = p;
753        p--;
754        i++;
755    }
756    if (separator != NULL)
757        p = separator;
758    else if (p >= old_name)
759        while (p >= old_name && *p != DIR_SEP) p--;
760
761    for (i = 0, p++; *p != NUL; i++)
762        *new_name++ = *p++;
763    *new_name = NUL;
764}
765
766/*
767 * Print a char in a form accepted by postscript printers.
768 */
769static int printchar(unsigned char c) {
770
771    if (c >= ' ' && c < 0177) {
772        if (c == '(' || c == ')' || c == '\\')
773            putchar('\\');
774        putchar(c);
775        return 0;
776    }
777
778    if (ISOlatin1 && (c > 0177)) {
779        printf("\\%o", c);
780        return 0;
781    }
782
783    if (only_printable) {
784        putchar(' ');
785        return 1;
786    }
787
788    if (c > 0177) {
789        printf("M-");
790        c &= 0177;
791    }
792    if (c < ' ') {
793        putchar('^');
794        if ((c = c + '@') == '(' || c == ')' || c == '\\')
795            putchar('\\');
796        putchar(c);
797    }
798    else if (c == 0177)
799        printf("^?");
800    else {
801        if (c == '(' || c == ')' || c == '\\')
802            putchar('\\');
803        putchar(c);
804    }
805
806    return 1;
807}
808
809/*
810 * Begins a new logical page.
811 */
812static void skip_page() {
813    if (twinpages == FALSE || sheetside == 0) {
814        printf("%%%%Page: %d %d\n", sheets+1, sheets+1);
815        printf("/pagesave save def\n");
816        // Reinitialize state variables for each new sheet
817        print_page_prologue(0);
818    }
819    startpage();
820}
821
822/*
823 * Fold a line too long.
824 */
825static int fold_line(char *name) {
826    column = 0;
827    printf(") s\n");
828    if (++line >= linesperpage) {
829        endpage();
830        skip_page();
831        if (first_page && is_binaryfile(name))
832            return FALSE;
833        line = 0;
834    }
835    if (numbering)
836        printf("(    +");
837    else
838        printf("( ");
839
840    return TRUE;
841}
842
843/*
844 * Cut a textline too long to the size of a page line.
845 */
846static int cut_line() {
847    int c;
848    int status;
849
850    while ((c = mygetc(&status)) != EOF && c != '\n' && c != '\f') ;
851    return c;
852}
853
854
855//**************************************************************
856//                      "Postscript" routines.
857//**************************************************************
858
859/*
860 * Print a physical page.
861 */
862static void printpage() {
863    sheetside = 0;
864    sheets++;
865    printf("/sd 0 def\n");
866    if (no_border == FALSE)
867        printf("%d sn\n", sheets - (restart ? old_sheets : 0));
868    if (printdate)
869        printf("cd\n");
870    if (filename_footer && landscape)
871        printf("fnf\n");
872#if defined(SYSV) || defined(BSD)
873    if (login_id)
874        printf("lg lgp\n");
875#endif
876    printf("pagesave restore\n");
877    printf("showpage\n");
878}
879
880/*
881 * Prints page header and page border and
882 * initializes printing of the file lines.
883 */
884void startpage() {
885    if (sheetside == 0) {
886#ifdef RECTO_VERSO_PRINTING
887        if (rectoverso && (sheets & 0x1)) {
888            // Shift to left backside pages.
889            printf("rm neg 0 translate\n");
890        }
891#endif
892        if (landscape) {
893            printf("sw 0 translate\n");
894            printf("90 rotate\n");
895        }
896    }
897    pages++;
898    if (no_header == FALSE)
899        printf("%d hp\n", pages - old_pages);
900    if (no_border == FALSE) {
901        printf("border\n");
902        if (no_header == FALSE)
903            printf("hborder\n");
904    }
905    printf("/x0 x %d get bm add def\n", sheetside);
906    printf("/y0 y %d get bm bfs add %s add sub def\n",
907           sheetside, no_header ? "0" : "hs");
908    printf("x0 y0 moveto\n");
909    printf("bf setfont\n");
910}
911
912/*
913 * Terminates printing, flushing last page.
914 */
915static void cleanup() {
916    if (twinpages && sheetside == 1)
917        printpage();
918#ifdef RECTO_VERSO_PRINTING
919    if (!twinfiles && rectoverso && (sheets & 0x1) != 0) {
920        sheetside = 0;
921        sheets++;
922        printf("%%%%Page: %d %d\n", sheets, sheets);
923        printf("showpage\n");
924    }
925#endif
926}
927
928/*
929 * Adds a sheet number to the page (footnote) and prints the formatted
930 * page (physical impression). Activated at the end of each source page.
931 */
932void endpage() {
933    if (twinpages && sheetside == 0) {
934        sheetside = 1;
935        printf("/sd 1 def\n");
936    }
937    else
938        printpage();
939}
940
941
942//**************************************************************
943//              Printing a file
944//**************************************************************
945
946/*
947 * Print the file prologue.
948 */
949static void init_file_printing(char *name, char *title) {
950    int new_format, new_font;
951    char *string;
952    int lines;
953    float char_width;
954    struct stat statbuf;
955
956    // Print last page of previous file, if necessary
957    if (pages > 0 && !twinfiles)
958        cleanup();
959
960    // Initialize variables related to the format
961    new_format = FALSE;
962    if (new_landscape != landscape || new_twinpages != twinpages) {
963        landscape = new_landscape;
964        twinpages = new_twinpages;
965        new_format = TRUE;
966    }
967
968    // Initialize variables related to the header
969    if (no_header && name == title)
970        header_size = 0.0;
971    else {
972        if (landscape || twinpages)
973            header_size = LANDSCAPE_HEADER * PIXELS_INCH;
974        else
975            header_size = PORTRAIT_HEADER * PIXELS_INCH;
976        cut_filename(title, current_filename);
977    }
978
979    // Initialize variables related to the font size
980    new_font = FALSE;
981    if (fontsize != new_fontsize || new_format ||
982        lines_requested != new_linesrequest || fontweight != new_fontweight)
983    {
984        if (new_fontsize == 0.0 || (fontsize == new_fontsize && new_format))
985            new_fontsize = landscape ? 6.8 : twinpages ? 6.4 : 9.0;
986        if (lines_requested != new_linesrequest) {
987            if ((lines_requested = new_linesrequest) != 0) {
988                // Scale fontsize
989                if (landscape)
990                    lines = (int)((page_width-header_size) / new_fontsize) - 1;
991                else if (twinpages)
992                    lines = (int)(((page_height - 2*header_size) / 2) / new_fontsize) - 2;
993                else
994                    lines = (int)((page_height-header_size) / new_fontsize) - 1;
995                new_fontsize *= (float)lines / (float)lines_requested;
996            }
997        }
998        fontsize = new_fontsize;
999        fontweight = new_fontweight;
1000        new_font = TRUE;
1001    }
1002
1003    // Initialize file printing, if there is any change
1004    if (new_format || new_font) {
1005        char_width = 0.6 * fontsize;
1006        if (landscape) {
1007            linesperpage = (int)((page_width - header_size) / fontsize) - 1;
1008            if (! twinpages)
1009                columnsperline = (int)(page_height / char_width) - 1;
1010            else
1011                columnsperline = (int)((page_height / 2) / char_width) - 1;
1012        }
1013        else {
1014            if (!twinpages)
1015                linesperpage = (int)((page_height - header_size) / fontsize) - 1;
1016            else
1017                linesperpage = (int)(((page_height - 2*header_size) / 2) / fontsize)
1018                    - 2;
1019            columnsperline = (int)(page_width / char_width) - 1;
1020        }
1021        if (lines_requested > 0)
1022            linesperpage = lines_requested;
1023        if (linesperpage <= 0 || columnsperline <= 0) {
1024            fprintf(stderr, "Font %g too big !!\n", fontsize);
1025            exit(EXIT_FAILURE);
1026        }
1027    }
1028
1029    // Retrieve file modification date and hour
1030    if (fstat(fileno(stdin), &statbuf) == -1) {
1031        fprintf(stderr, "Error getting file modification time\n");
1032        exit(EXIT_FAILURE);
1033    }
1034    // Do we have a pipe?
1035    if (S_ISFIFO(statbuf.st_mode))
1036        strcpy(filedate, currentdate);
1037    else {
1038        string = ctime(&statbuf.st_mtime);
1039        sprintf(filedate, "%.6s %.4s %.5s", string+4, string+20, string+11);
1040    }
1041}
1042
1043/*
1044 * Print the prologue necessary for printing each physical page.
1045 * Adobe convention for page independence is enforced through this routine.
1046 */
1047void print_page_prologue(int side) {
1048    // side: Logical page to print (left/right)
1049
1050    // General format
1051    printf("/twp %s def\n", twinpages ? "true" : "false");
1052    printf("/fnfs %d def\n", landscape ? 11 : twinpages ? 10 : 15);
1053    printf("/dfs fnfs 0.8 mul def\n");
1054    printf("/df /Helvetica dfs getfont def\n");
1055    printf("/dw df setfont td stringwidth pop def\n");
1056    printf("/sfnf filenmfontname fnfs getfont def\n");
1057    printf("/hm fnfs 0.25 mul def\n");
1058    // Header size
1059    if (header_size == 0.0)
1060        printf("/hs 0.0 def\n");
1061    else
1062        printf("/hs %g inch def\n",
1063               landscape || twinpages ? LANDSCAPE_HEADER : PORTRAIT_HEADER);
1064    // Font sizes
1065    printf("/bfs %g def\n", fontsize);
1066    printf("/bdf /Courier-Bold bfs getfont def\n");
1067    printf("/bm bfs 0.7 mul def\n");
1068    printf("/bf %s bfs getfont def\n",
1069           fontweight == NORMAL ? "/CourierBack" : "/Courier-Bold");
1070    // Page attributes
1071    printf("/l %d def\n", linesperpage);
1072    printf("/c %d def\n", columnsperline);
1073    printf("/pw\n");
1074    printf("   bf setfont (0) stringwidth pop c mul bm dup add add\n");
1075    printf("   def\n");
1076    printf("/ph\n");
1077    printf("   bfs l mul bm dup add add hs add\n");
1078    printf("   def\n");
1079    printf("/fns\n");
1080    printf("      pw\n");
1081    printf("      fnfs 4 mul dw add (Page 999) stringwidth pop add\n");
1082    printf("    sub\n");
1083    printf("  def\n");
1084    printf("/tm margin twp {3} {2} ifelse div def\n");
1085    printf("/sd %d def\n", side);
1086    if (landscape) {
1087        printf("/y [ rm ph add bm add\n");
1088        printf("          dup ] def\n");
1089        printf("/sny dfs dfs add def\n");
1090        printf("/snx sh tm dfs add sub def\n");
1091        printf("/dy sny def\n");
1092        printf("/dx tm dfs add def\n");
1093        if (twinpages) {
1094            printf("/x [ tm                     %% left page\n");
1095            printf("          dup 2 mul pw add  %% right page\n");
1096            printf("        ] def\n");
1097        }
1098        else {
1099            printf("/x [ tm dup ] def\n");
1100        }
1101        printf("/scx sh 2 div def\n");
1102    }
1103    else {
1104        printf("/x [ lm dup ] def\n");
1105        printf("/sny tm dfs 2 mul sub def\n");
1106        printf("/snx sw rm sub dfs sub def\n");
1107        printf("/dy sny def\n");
1108        printf("/dx lm def\n");
1109        if (twinpages) {
1110            printf("/y [ tm ph add 2 mul %% up\n");
1111            printf("          tm ph add  %% down\n");
1112            printf("        ] def\n");
1113        }
1114        else {
1115            printf("\n%% Only one logical page\n");
1116            printf("/y [ sh tm sub dup ] def\n");
1117        }
1118        printf("/scx sw 2 div def\n");
1119    }
1120    printf("/fny dy def\n");
1121    printf("/fnx scx def\n");
1122    printf("/ly fnfs 2 div y sd get add def\n");
1123    printf("/lx snx def\n");
1124    printf("/d (%s) def\n", filedate);
1125    printf("( %s ) fn\n", current_filename);
1126}
1127
1128/*
1129 * Print one file.
1130 */
1131static void print_file(char *name, char *header) {
1132    int c;
1133    int nchars;
1134    int start_line, start_page;
1135    int continue_exit;
1136    int status, new_status;
1137
1138    // Reinitialize postscript variables depending on positional options
1139    init_file_printing(name, header == NULL ? name : header);
1140
1141    // If we are in compact mode and the file beginning is to be printed
1142    // in the middle of a twinpage, we have to print a new page prologue
1143    if (twinfiles && sheetside == 1)
1144        print_page_prologue(1);
1145
1146    /*
1147     * Boolean to indicates that previous char is \n (or interpreted \f)
1148     * and a new page would be started, if more text follows
1149     */
1150    start_page = FALSE;
1151
1152    /*
1153     * Printing binary files is not very useful. We stop printing
1154     * if we detect one of these files. Our heuristic to detect them:
1155     * if 75% characters of first page are non-printing characters,
1156     * the file is a binary file.
1157     * Option -b force binary files impression.
1158     */
1159    nonprinting_chars = chars = 0;
1160
1161    // Initialize printing variables
1162    column = 0;
1163    line = line_number = 0;
1164    first_page = TRUE;
1165    start_line = TRUE;
1166    prefix_width = numbering ? 6 : 1;
1167
1168    // Start printing
1169    skip_page();
1170
1171    // Process each character of the file
1172    status = IS_ROMAN;
1173    c = mygetc(&new_status);
1174    while (c != EOF) {
1175        /*
1176         * Preprocessing (before printing):
1177         * - TABs expansion (see interpret option)
1178         * - FF and BS interpretation
1179         * - replace non printable characters by a space or a char sequence
1180         *   like:
1181         *     ^X for ascii codes < 0x20 (X = [@, A, B, ...])
1182         *     ^? for del char
1183         *     M-c for ascii codes > 0x3f
1184         * - prefix parents and backslash ['(', ')', '\'] by backslash
1185         *   (escape character in postscript)
1186         */
1187        // Form feed
1188        if (c == '\f' && interpret) {
1189            // Close current line
1190            if (!start_line) {
1191                printf(") s\n");
1192                start_line = TRUE;
1193            }
1194            // start a new page ?
1195            if (start_page)
1196                skip_page();
1197            // Close current page and begin another
1198            endpage();
1199            start_page = TRUE;
1200            // Verification for binary files
1201            if (first_page && is_binaryfile(name))
1202                return;
1203            line = 0;
1204            column = 0;
1205            if ((c = mygetc(&new_status)) == EOF)
1206                break;
1207        }
1208
1209        // Start a new line ?
1210        if (start_line) {
1211            if (start_page) {
1212                // only if there is something to print!
1213                skip_page();
1214                start_page = FALSE;
1215            }
1216            if (numbering)
1217                printf("(%4d|", ++line_number);
1218            else
1219                printf("( ");
1220            start_line = FALSE;
1221        }
1222
1223        // Is a new font ? This feature is used only to detect bold
1224        // sequences produced by nroff (man pages), in connexion with
1225        // mygetc.
1226        if (status != new_status) {
1227            printf(")\n");
1228            printf("%s", status == IS_ROMAN ? "b" : "st");
1229            printf(" (");
1230            status = new_status;
1231        }
1232
1233        // Interpret each character
1234        switch (c) {
1235            case '\b':
1236                if (!interpret)
1237                    goto print;
1238                // A backspace is converted to 2 chars ('\b'). These chars
1239                // with the Courier backspace font produce correct under-
1240                // lined strings.
1241                if (column)
1242                    column--;
1243                putchar('\\');
1244                putchar('b');
1245                break;
1246            case '\n':
1247                column = 0;
1248                start_line = TRUE;
1249                printf(") s\n");
1250                if (++line >= linesperpage) {
1251                    endpage();
1252                    start_page = TRUE;
1253                    if (first_page && is_binaryfile(name))
1254                        return;
1255                    line = 0;
1256                }
1257                break;
1258            case '\t':
1259                if (interpret) {
1260                    continue_exit = FALSE;
1261                    do {
1262                        if (++column + prefix_width > columnsperline) {
1263                            if (folding) {
1264                                if (fold_line(name) == FALSE)
1265                                    return;
1266                            }
1267                            else {
1268                                c = cut_line();
1269                                continue_exit = TRUE;
1270                                break;
1271                            }
1272                        }
1273                        putchar(' ');
1274                    } while (column % column_width);
1275                    if (continue_exit)
1276                        continue;
1277                    break;
1278                }
1279            default:
1280            print :
1281                if (only_printable) {
1282                    nchars = 1;
1283                }
1284                else if (! ISOlatin1) {
1285                    nchars = c > 0177 ? 2 : 0;
1286                    nchars += (c&0177) < ' ' || (c&0177) == 0177 ? 2 : 1;
1287                }
1288                else {
1289                    nchars = c < ' ' || (c >= 0177 && c < 144) ? 2 : 1;
1290                }
1291
1292                if (prefix_width + (column += nchars) > columnsperline) {
1293                    if (folding) {
1294                        if (fold_line(name) == FALSE) {
1295                            return;
1296                        }
1297                    }
1298                    else {
1299                        c = cut_line();
1300                        new_status = IS_ROMAN;
1301                        continue;
1302                    }
1303                }
1304                nonprinting_chars += printchar(c);
1305                chars++;
1306                break;
1307        }
1308        c = mygetc(&new_status);
1309    }
1310
1311    if (!start_line)
1312        printf(") s\n");
1313    if (!start_page)
1314        endpage();
1315}
1316
1317
1318//**************************************************************
1319//              Print a postscript prologue for a2ps.
1320//**************************************************************
1321
1322/*
1323 * Print the a2ps prologue.
1324 */
1325static void print_prologue() {
1326    int             c;
1327    FILE           *f = NULL;
1328    char           *datestring;
1329#if defined(SYSV) || defined(BSD)
1330    char           *logname, *host;
1331    int             rt;
1332#endif
1333#if defined(SYSV)
1334    struct utsname  snames;
1335#endif
1336
1337    // Retrieve date and hour
1338#if defined(__STDC__)
1339    time_t date;
1340
1341    if (time(&date) == -1) {
1342        fprintf(stderr, "Error calculating time\n");
1343        exit(EXIT_FAILURE);
1344    }
1345    datestring = ctime(&date);
1346#else
1347#ifdef BSD
1348    struct timeval date;
1349    struct tm *p;
1350
1351    (void) gettimeofday(&date, (struct timezone *)0);
1352    p = localtime(&date.tv_sec);
1353    datestring = asctime(p);
1354#else
1355#ifdef SYSV
1356    struct timeb date;
1357
1358    (void)ftime(&date);
1359    datestring = ctime(&date.time);
1360#else
1361
1362    datestring = "--- --- -- --:--:-- ----";
1363#endif
1364#endif
1365#endif
1366
1367#if defined(SYSV) || defined(BSD)
1368    // Retrieve user's login name and hostname
1369    logname = getlogin();
1370    host = (char *)malloc(MAX_HOSTNAME);
1371    if (host != NULL) {
1372#if defined(SYSV)
1373        if ((rt = uname(&snames)) == -1 || snames.nodename[0] == NULL) {
1374            free(host);
1375            host = NULL;
1376        }
1377        else
1378            strcpy(host, snames.nodename);
1379#else
1380        if ((rt = gethostname(host, MAX_HOSTNAME)) == -1 || host[0] == NULL) {
1381            free(host);
1382            host = NULL;
1383        }
1384#endif
1385    }
1386#endif
1387
1388    // Print a general prologue
1389    if (prologue == NULL)
1390        print_standard_prologue(datestring);
1391    else if ((f = fopen(prologue, "r")) != NULL) {
1392        // Header file printing
1393        while ((c = getc(f)) != EOF)
1394            putchar(c);
1395    }
1396    else {
1397        fprintf(stderr, "Postscript header missing: %s\n", prologue);
1398        exit(EXIT_FAILURE);
1399    }
1400
1401    // Completes the prologue with a2ps static variables
1402    printf("\n%% Initialize page description variables.\n");
1403    printf("/x0 0 def\n");
1404    printf("/y0 0 def\n");
1405    printf("/sh %g inch def\n", (double)HEIGHT);
1406    printf("/sw %g inch def\n", (double)WIDTH);
1407    printf("/margin %g inch def\n", (double)MARGIN);
1408    printf("/rm margin 3 div def\n");
1409    printf("/lm margin 2 mul 3 div def\n");
1410    printf("/d () def\n");
1411
1412    // And print them
1413    sprintf(currentdate, "%.6s %.4s %.5s",
1414            datestring+4, datestring+20, datestring+11);
1415    printf("/td (%s) def\n", currentdate);
1416
1417#if defined(SYSV) || defined(BSD)
1418    // Add the user's login name string to the Postscript output
1419    if (logname != NULL || host != NULL) {
1420        if (logname != NULL && host != NULL)
1421            printf("/lg (Printed by %s from %s) def\n", logname, host);
1422        else if (logname != NULL)
1423            printf("/lg (Printed by %s) def\n", logname);
1424        else
1425            printf("/lg (Printed from %s) def\n", host);
1426    }
1427
1428    // If the host string was allocated via malloc, release the memory
1429    if (host != NULL)
1430        free(host);
1431#endif
1432
1433    // Close prolog
1434    printf("%%%%EndProlog\n\n");
1435
1436    // Go on
1437    printf("/docsave save def\n");
1438    fclose(f);
1439}
1440
1441/*
1442 * Print the standard prologue.
1443 */
1444void print_standard_prologue(char *datestring) {
1445    printf("%%!PS-Adobe-3.0\n");
1446    printf("%%%%Creator: A2ps version %s\n", VERSION);
1447    printf("%%%%CreationDate: %.24s\n", datestring);
1448    printf("%%%%Pages: (atend)\n");
1449    printf("%%%%DocumentFonts: Courier Courier-Bold Helvetica Helvetica-Bold\n");
1450    printf("%%%%EndComments\n");
1451    printf("%% Copyright (c) 1993, 1994, Miguel Santana, M.Santana@frgu.bull.fr\n");
1452    printf("\n/$a2psdict 100 dict def\n");
1453    printf("$a2psdict begin\n");
1454    printf("\n%% General macros.\n");
1455    printf("/xdef {exch def} bind def\n");
1456    printf("/getfont {exch findfont exch scalefont} bind def\n");
1457
1458    if (ISOlatin1) {
1459        printf("\n%% Set up ISO Latin 1 character encoding\n");
1460        printf("/reencodeISO {\n");
1461        printf("        dup dup findfont dup length dict begin\n");
1462        printf("        { 1 index /FID ne { def }{ pop pop } ifelse\n");
1463        printf("        } forall\n");
1464        printf("        /Encoding ISOLatin1Encoding def\n");
1465        printf("        currentdict end definefont\n");
1466        printf("} def\n");
1467        printf("/Helvetica-Bold reencodeISO def\n");
1468        printf("/Helvetica reencodeISO def\n");
1469        printf("/Courier reencodeISO def\n");
1470        printf("/Courier-Bold reencodeISO def\n");
1471    }
1472
1473    printf("\n%% Create Courier backspace font\n");
1474    printf("/backspacefont {\n");
1475    printf("    /Courier findfont dup length dict begin\n");
1476    printf("    { %% forall\n");
1477    printf("        1 index /FID eq { pop pop } { def } ifelse\n");
1478    printf("    } forall\n");
1479    printf("    currentdict /UniqueID known { %% if\n");
1480    printf("        /UniqueID UniqueID 16#800000 xor def\n");
1481    printf("    } if\n");
1482    printf("    CharStrings length 1 add dict begin\n");
1483    printf("        CharStrings { def } forall\n");
1484    printf("        /backspace { -600 0 0 0 0 0 setcachedevice } bind def\n");
1485    printf("        currentdict\n");
1486    printf("    end\n");
1487    printf("    /CharStrings exch def\n");
1488    printf("    /Encoding Encoding 256 array copy def\n");
1489    printf("    Encoding 8 /backspace put\n");
1490    printf("    currentdict\n");
1491    printf("    end\n");
1492    printf("    definefont pop\n");
1493    printf("} bind def\n");
1494
1495    printf("\n%% FUNCTIONS\n");
1496    printf("\n%% Function filename: Initialize file printing.\n");
1497    printf("/fn\n");
1498    printf("{ /filenm xdef\n");
1499    printf("  /filenmwidth filenm stringwidth pop def\n");
1500    printf("  /filenmfont\n");
1501    printf("       filenmwidth fns gt\n");
1502    printf("       {\n");
1503    printf("           filenmfontname\n");
1504    printf("           fnfs fns mul filenmwidth div\n");
1505    printf("         getfont\n");
1506    printf("       }\n");
1507    printf("       { sfnf }\n");
1508    printf("     ifelse\n");
1509    printf("  def\n");
1510    printf("} bind def\n");
1511    printf("\n%% Function header: prints page header. no page\n");
1512    printf("%% is passed as argument.\n");
1513    printf("/hp\n");
1514    printf("  { x sd get  y sd get hs sub 1 add  moveto\n");
1515    printf("    df setfont\n");
1516    printf("    gsave\n");
1517    printf("      x sd get y sd get moveto\n");
1518    printf("      0 hs 2 div neg rmoveto \n");
1519    printf("      hs setlinewidth\n");
1520    printf("      0.95 setgray\n");
1521    printf("      pw 0 rlineto stroke\n");
1522    printf("    grestore\n");
1523    printf("    gsave\n");
1524    printf("      dfs hm rmoveto\n");
1525    printf("      d show                                %% date/hour\n");
1526    printf("    grestore\n");
1527    printf("    gsave\n");
1528    printf("      pnum cvs pop                          %% page pop up\n");
1529    printf("        pw (Page 999) stringwidth pop sub\n");
1530    printf("        hm\n");
1531    printf("      rmoveto\n");
1532    printf("      (Page ) show pnum show                %% page number\n");
1533    printf("    grestore\n");
1534    printf("    empty pnum copy pop\n");
1535    printf("    gsave\n");
1536    printf("      filenmfont setfont\n");
1537    printf("         fns filenm stringwidth pop sub 2 div dw add\n");
1538    printf("          bm 2 mul \n");
1539    printf("        add \n");
1540    printf("        hm\n");
1541    printf("      rmoveto\n");
1542    printf("        filenm show                 %% file name\n");
1543    printf("      grestore\n");
1544    printf("    } bind def\n");
1545    printf("\n%% Function border: prints border page\n");
1546    printf("/border \n");
1547    printf("{ x sd get y sd get moveto\n");
1548    printf("  gsave                             %% print four sides\n");
1549    printf("    0.7 setlinewidth                %% of the square\n");
1550    printf("    pw 0 rlineto\n");
1551    printf("    0 ph neg rlineto\n");
1552    printf("    pw neg 0 rlineto\n");
1553    printf("    closepath stroke\n");
1554    printf("  grestore\n");
1555    printf("} bind def\n");
1556    printf("\n%% Function hborder: completes border of the header.\n");
1557    printf("/hborder \n");
1558    printf("{ gsave\n");
1559    printf("    0.7 setlinewidth\n");
1560    printf("    0 hs neg rmoveto\n");
1561    printf("    pw 0 rlineto\n");
1562    printf("    stroke\n");
1563    printf("  grestore\n");
1564    printf("} bind def\n");
1565    printf("\n%% Function sheetnumber: prints the sheet number.\n");
1566    printf("/sn\n");
1567    printf("    { snx sny moveto\n");
1568    printf("      df setfont\n");
1569    printf("      pnum cvs\n");
1570    printf("      dup stringwidth pop (0) stringwidth pop sub neg 0 rmoveto show\n");
1571    printf("      empty pnum copy pop\n");
1572    printf("    } bind def\n");
1573    printf("\n%% Function loginprint: prints the login id of the requestor.\n");
1574    printf("/lgp\n");
1575    printf("    { lx ly moveto\n");
1576    printf("      df setfont\n");
1577    printf("      dup stringwidth pop neg 0 rmoveto show\n");
1578    printf("    } bind def\n");
1579    printf("\n%% Function currentdate: prints the current date.\n");
1580    printf("/cd\n");
1581    printf("    { dx dy moveto\n");
1582    printf("      df setfont\n");
1583    printf("      (Printed: ) show\n");
1584    printf("      td show\n");
1585    printf("    } bind def\n");
1586    printf("\n%% Function filename_footer: prints the file name at bottom of page.\n");
1587    printf("/fnf\n");
1588    printf("    { fnx fny moveto\n");
1589    printf("      df setfont\n");
1590    printf("      filenm center show\n");
1591    printf("    } bind def\n");
1592    printf("\n%% Function center: centers text.\n");
1593    printf("/center\n");
1594    printf("    { dup stringwidth pop\n");
1595    printf("      2 div neg 0 rmoveto\n");
1596    printf("    } bind def\n");
1597    printf("\n%% Function s: print a source line\n");
1598    printf("/s  { show\n");
1599    printf("      /y0 y0 bfs sub def\n");
1600    printf("      x0 y0 moveto\n");
1601    printf("    } bind def\n");
1602    printf("\n%% Functions b and st: change to bold or standard font\n");
1603    printf("/b  { show\n");
1604    printf("      bdf setfont\n");
1605    printf("    } bind def\n");
1606    printf("/st { show\n");
1607    printf("      bf setfont\n");
1608    printf("    } bind def\n");
1609    printf("\n%% Strings used to make easy printing numbers\n");
1610    printf("/pnum 12 string def\n");
1611    printf("/empty 12 string def\n");
1612    printf("\n%% Global initializations\n");
1613    printf("\n/CourierBack backspacefont\n");
1614    printf("/filenmfontname /Helvetica-Bold def\n");
1615    printf("/inch {72 mul} bind def\n");
1616
1617    printf("\n%%\n");
1618    printf("%% Meaning of some variables and functions (coded names)\n");
1619    printf("%%\n");
1620    printf("%%  twp:            twinpages?\n");
1621    printf("%%  sd:             sheet side\n");
1622    printf("%%  l:              line counter\n");
1623    printf("%%  c:              column counter\n");
1624    printf("%%  d:              date\n");
1625    printf("%%  td:             current date (for today)\n");
1626    printf("%%  lg:             login name\n");
1627    printf("%%  fn:             filename printing function\n");
1628    printf("%%  sn:             sheetnumber printing function\n");
1629    printf("%%  cd:             current date printing function\n");
1630    printf("%%  fnf:            filename footer printing function\n");
1631    printf("%%  lgp:            login printing function\n");
1632    printf("%%  hp:             header printing function\n");
1633    printf("%%  y:              y coordinate for the logical page\n");
1634    printf("%%  x:              x coordinate for the logical page\n");
1635    printf("%%  sny:            y coordinate for the sheet number\n");
1636    printf("%%  snx:            x coordinate for the sheet number\n");
1637    printf("%%  dy:             y coordinate for the date\n");
1638    printf("%%  dx:             x coordinate for the date\n");
1639    printf("%%  ly:             y coordinate for the login\n");
1640    printf("%%  lx:             x coordinate for the login\n");
1641    printf("%%  scx:            x coordinate for the sheet center\n");
1642    printf("%%  fny:            y coordinate for the filename (footer)\n");
1643    printf("%%  fnx:            x coordinate for the filename (footer)\n");
1644    printf("%%  fnfs:           filename font size\n");
1645    printf("%%  bfs:            body font size\n");
1646    printf("%%  dfs:            date font size\n");
1647    printf("%%  bfs:            body font size\n");
1648    printf("%%  df:             date font\n");
1649    printf("%%  bf:             body font\n");
1650    printf("%%  bdf:            bold font\n");
1651    printf("%%  sfnf:           standard filename font\n");
1652    printf("%%  dw:             date width\n");
1653    printf("%%  pw:             page width\n");
1654    printf("%%  sw:             sheet width\n");
1655    printf("%%  ph:             page height\n");
1656    printf("%%  sh:             sheet height\n");
1657    printf("%%  hm:             header margin\n");
1658    printf("%%  tm:             top margin\n");
1659    printf("%%  bm:             body margin\n");
1660    printf("%%  rm:             right margin\n");
1661    printf("%%  lm:             left margin\n");
1662    printf("%%  hs:             header size\n");
1663    printf("%%  fns:            filename size\n");
1664}
1665
1666
1667/*
1668 * Main routine for a2ps.
1669 */
1670int ARB_main(int argc, char *cargv[]) {
1671    char       **argv = (char**)cargv;
1672    int          narg;
1673    char        *arg;
1674    int          total;
1675#if LPR_PRINT
1676    int          fd[2];
1677    const char  *lpr_args[10];
1678#endif
1679
1680    // Process global options
1681    command = argv[0];
1682    arg = argv[narg = 1];
1683    while (narg < argc) {
1684        if (arg[0] == '-')
1685            set_global_option(arg);
1686        arg = argv[++narg];
1687    }
1688
1689#if LPR_PRINT
1690    // Start lpr process
1691    if (lpr_print) {
1692        if (pipe(fd) != 0) {
1693            fprintf(stderr, "Could not create pipe (Reason: %s)\n", strerror(errno));
1694            exit(EXIT_FAILURE);
1695        }
1696
1697        if (fork() == 0) {
1698            dup2(fd[0], 0);
1699            close(fd[0]); close(fd[1]);
1700            narg = 0;
1701            lpr_args[narg++] = LPR_COMMAND;
1702#ifdef LPR_OPT
1703            lpr_args[narg++] = LPR_OPT;
1704#endif
1705            if (lpr_opt)
1706                lpr_args[narg++] = lpr_opt;
1707#ifdef RECTO_VERSO_PRINTING
1708            if (rectoverso)
1709                lpr_args[narg++] = TWOSIDED;
1710            else
1711                lpr_args[narg++] = ONESIDED;
1712#endif
1713            lpr_args[narg] = (char *)0;
1714            execvp(LPR_COMMAND, (char**)lpr_args);
1715            fprintf(stderr, "Error starting lpr process \n");
1716            exit(EXIT_FAILURE);
1717        }
1718        dup2(fd[1], 1);
1719        close(fd[0]);
1720        close(fd[1]);
1721    }
1722#endif
1723
1724    // Initialize variables not depending of positional options
1725    landscape = twinpages = -1; // To force format switching
1726    fontsize = -1.0;                    // To force fontsize switching
1727    page_height = (double)(HEIGHT - MARGIN) * PIXELS_INCH;
1728    page_width = (double)(WIDTH - MARGIN) * PIXELS_INCH;
1729
1730    // Postscript prologue printing
1731    print_prologue();
1732
1733    // Print files designated or standard input
1734    arg = argv[narg = 1];
1735    while (narg < argc) {
1736        if (arg[0] != NUL) {
1737            if (arg[0] == '-')
1738                set_positional_option(arg);
1739            else {
1740                if (freopen(arg, "r", stdin) == NULL) {
1741                    fprintf(stderr, "Error opening %s\n", arg);
1742                    cleanup();
1743                    printf("\n%%%%Trailer\ndocsave restore end\n\4");
1744                    exit(EXIT_FAILURE);
1745                }
1746                no_files = FALSE;
1747
1748                // Save counters values
1749                old_pages = pages;
1750                if (twinfiles && twinpages)
1751                    old_sheets = sheets;
1752                else
1753                    old_sheets = sheets + sheetside;
1754
1755                // Print the file
1756                print_file(arg, header_text);
1757
1758                // Print the number of pages and sheets printed
1759                if (no_summary == FALSE) {
1760                    total = pages - old_pages;
1761                    fprintf(stderr, "[%s: %d page%s on ", arg,
1762                            total, total == 1 ? "" : "s");
1763                    total = sheets - old_sheets + sheetside;
1764#ifdef RECTO_VERSO_PRINTING
1765                    if (rectoverso)
1766                        total = (total+1) / 2;
1767#endif
1768                    fprintf(stderr, "%d sheet%s]\n", total, total == 1 ? "" : "s");
1769                }
1770
1771                // Reinitialize header title
1772                header_text = NULL;
1773            }
1774        }
1775        arg = argv[++narg];
1776    }
1777    if (no_files)
1778        print_file((char*)"stdin", header_text);
1779
1780    // Print the total number of pages printed
1781    if (no_summary == FALSE && pages != old_pages) {
1782        fprintf(stderr, "[Total: %d page%s on ", pages, pages == 1 ? "" : "s");
1783        total = sheets + sheetside;
1784#ifdef RECTO_VERSO_PRINTING
1785        if (rectoverso)
1786            total = (total+1) / 2;
1787#endif
1788        fprintf(stderr, "%d sheet%s]\n", total, total == 1 ? "" : "s");
1789    }
1790
1791    // And stop
1792    cleanup();
1793    printf("\n%%%%Trailer\n");
1794    printf("%%%%Pages: %d\n", sheets + sheetside);
1795    printf("docsave restore end\n");
1796
1797    exit(EXIT_SUCCESS);
1798}
Note: See TracBrowser for help on using the repository browser.