source: trunk/TOOLS/arb_a2ps.c

Last change on this file was 19442, checked in by westram, 15 months ago
  • reactivate implicit-fallthrough warnings and fix code.
  • 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 NULp
148#define NULp            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 = NULp;           // Options to lpr
321static char *header_text = NULp;       // Allow for different header text
322static float header_size;              // Size of the page header
323static char *prologue = NULp;          // 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 = NULp;             // 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 && 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            break; // silence warning (never reached)
408        case 'b':                               // print binary files
409            if (arg[2] != NUL)
410                usage(EXIT_FAILURE);
411            print_binaries = TRUE;
412            break;
413        case 'c':                               // allow two files per sheet
414            if (arg[2] != NUL)
415                usage(EXIT_FAILURE);
416            twinfiles = TRUE;
417            break;
418        case 'f':                               // fold lines too large
419            if (arg[2] != NUL)
420                usage(EXIT_FAILURE);
421            folding = TRUE;
422            break;
423        case 'I':                               // include this file as a2ps prologue
424            if (arg[2] == NUL)
425                usage(EXIT_FAILURE);
426            prologue = arg+2;
427            break;
428        case 'i':                               // interpret control chars
429            if (arg[2] != NUL)
430                usage(EXIT_FAILURE);
431            interpret = TRUE;
432            break;
433        case 'n':
434            if (arg[2] == NUL)
435                return;
436            if (arg[3] != NUL)
437                usage(EXIT_FAILURE);
438            switch (arg[2]) {
439                case 'b':                       // don't print binaries
440                    print_binaries = FALSE;
441                    break;
442                case 'c':                       // don't allow 2 files/sheet
443                    twinfiles = FALSE;
444                    break;
445                case 'f':                       // cut lines too long
446                    folding = FALSE;
447                    break;
448                case 'H':                       // don't print header
449                    no_header = TRUE;
450                    break;
451                case 'i':                       // don't interpret ctrl chars
452                    interpret = FALSE;
453                    break;
454#if LPR_PRINT
455                case 'P':                       // don't lpr
456                    lpr_print = FALSE;
457                    break;
458#endif
459                case 'r':                       // don't restart sheet number
460                    restart = FALSE;
461                    break;
462                case 'v':                       // only printable chars
463                    only_printable = TRUE;
464                    break;
465                case '8':                       // don't print 8-bit chars
466                    ISOlatin1 = FALSE;
467                    break;
468                case 'B':
469                case 'd':
470                case 'L':
471                case 'm':
472                case 'n':
473                case 's':
474                case 'u':
475                    if (arg[3] != NUL)
476                        usage(EXIT_FAILURE);
477                    return;
478                default:
479                    usage(EXIT_FAILURE);
480            }
481            break;
482#if LPR_PRINT
483        case 'P':                                       // fork a process to print
484            if (arg[2] != NUL) {
485                lpr_opt = (char *)malloc(strlen(arg)+1);
486                strcpy(lpr_opt, arg);
487            }
488            lpr_print = TRUE;
489            break;
490#endif
491        case 'q':                                       // don't print a summary
492            no_summary = TRUE;
493            break;
494        case 'r':                                       // restart sheet number
495            if (arg[2] != NUL)
496                usage(EXIT_FAILURE);
497            restart = TRUE;
498            break;
499        case 's':
500            if (arg[2] == NUL)
501                return;
502#ifdef RECTO_VERSO_PRINTING
503            if (arg[3] == NUL) {
504                if (arg[2] == '1') {            // one-sided printing
505                    rectoverso = FALSE;
506                    break;
507                }
508                if (arg[2] == '2') {            // two-sided printing
509                    rectoverso = TRUE;
510                    break;
511                }
512            }
513#endif
514            usage(EXIT_FAILURE);
515            break;
516        case 't':                               // set tab size
517            if (arg[2] == NUL || (column_width = atoi(arg+2)) <= 0)
518                usage(EXIT_FAILURE);
519            break;
520        case 'v':                               // print control chars
521            if (arg[2] != NUL)
522                usage(EXIT_FAILURE);
523            only_printable = FALSE;
524            break;
525        case '8':                               // print 8-bit chars
526            if (arg[2] != NUL)
527                usage(EXIT_FAILURE);
528            ISOlatin1 = TRUE;
529            break;
530        case '1':
531        case '2':
532        case 'B':
533        case 'd':
534        case 'm':
535        case 'p':
536            if (arg[2] != NUL)
537                usage(EXIT_FAILURE);
538        case '#':
539        case 'F':
540        case 'H':
541        case 'l':
542            return;
543        default:
544            usage(EXIT_FAILURE);
545    }
546    arg[0] = NUL;
547}
548
549/*
550 * Set an option of the command line. This option will be applied
551 * to all files that will be found in the rest of the command line.
552 * The -H option is the only exception: it is applied only to the
553 * file.
554 */
555static void set_positional_option(char *arg) {
556    int copies;
557    int lines;
558    float size;
559
560    switch (arg[1]) {
561        case NUL:                               // global option
562            break;
563        case '#':                               // n copies
564            if (sscanf(&arg[2], "%d", &copies) != 1 || copies <= 0)
565                fprintf(stderr, "Bad number of copies: '%s'. Ignored\n", &arg[2]);
566            else
567                copies_number = copies;
568            printf("/#copies %d def\n", copies_number);
569            break;
570        case '1':                               // 1 logical page per sheet
571            if (arg[2] != NUL)
572                usage(EXIT_FAILURE);
573            new_twinpages = FALSE;
574            break;
575        case '2':                               // twin pages
576            if (arg[2] != NUL)
577                usage(EXIT_FAILURE);
578            new_twinpages = TRUE;
579            break;
580        case 'B':
581            new_fontweight = BOLD;              // use bold font
582            break;
583        case 'd':                               // print current date/time
584            printdate = TRUE;
585            break;
586        case 'F':                               // change font size
587            if (arg[2] == NUL || sscanf(&arg[2], "%f", &size) != 1 || size == 0.0) {
588                fprintf(stderr, "Wrong value for option -F: '%s'. Ignored\n",
589                        &arg[2]);
590                break;
591            }
592            new_fontsize = size;
593            break;
594        case 'H':                               // header text
595            header_text = arg+2;
596            break;
597        case 'l':
598            if (arg[2] == NUL) {                // landscape format
599                new_landscape = TRUE;
600                break;
601            }
602            // set lines per page
603            // Useful with preformatted files. Scaling is automatically
604            // done when necessary.
605            if (sscanf(&arg[2], "%d", &lines) != 1
606                || lines < 0 || lines > MAX_LINES)
607            {
608                fprintf(stderr, "Wrong value for option -l: '%s'. Ignored\n",
609                        &arg[2]);
610                break;
611            }
612            new_linesrequest = lines;
613            break;
614        case 'm':                               // Process file as a man
615            new_linesrequest = MAN_LINES;
616            numbering = FALSE;
617            break;
618        case 'n':                               // number file lines
619            if (arg[2] == NUL) {
620                numbering = TRUE;
621                break;
622            }
623            switch (arg[2]) {
624                case 'B':                       // disable bold text
625                    new_fontweight = NORMAL;
626                    break;
627                case 'd':                       // don't print date/time
628                    printdate = FALSE;
629                    break;
630#if defined(SYSV) || defined(BSD)
631                case 'L':                       // no login name in footer
632                    login_id = FALSE;
633                    break;
634#endif
635                case 'l':                       // portrait format
636                    new_landscape = FALSE;
637                    break;
638                case 'm':                       // stop processing as a man
639                    new_linesrequest = 0;
640                    break;
641                case 'n':                       // don't number lines
642                    numbering = FALSE;
643                    break;
644                case 'p':                       // landscape format
645                    new_landscape = TRUE;
646                    break;
647                case 's':                       // no surrounding border
648                    no_border = TRUE;
649                    break;
650                case 'u':                       // no filename in footer
651                    filename_footer = FALSE;
652                    break;
653                default:
654                    usage(EXIT_FAILURE);
655            }
656            break;
657        case 'p':                               // portrait format
658            if (arg[2] != NUL)
659                usage(EXIT_FAILURE);
660            new_landscape = FALSE;
661            break;
662        case 's':                               // surrounding border
663            if (arg[2] != NUL)
664                usage(EXIT_FAILURE);
665            no_border = FALSE;
666            break;
667        default:
668            usage(EXIT_FAILURE);
669    }
670}
671
672
673//**************************************************************
674//                      Service routines
675//**************************************************************
676
677/*
678 * This routine buffers a line of input, release one character at a time
679 * or a whole sequence of characters with some meaning like bold sequences
680 * produced by nroff (no others sequences are recognized by the moment):
681 *        <c><\b><c><\b><c><\b><c>
682 */
683static int mygetc(int *statusp) {
684#define BUFFER_SIZE     512
685    static int curr = 0;
686    static int size = 0;
687    static unsigned char buffer[BUFFER_SIZE+1];
688    int c;
689
690    *statusp = IS_ROMAN;
691
692    // Read a new line, if necessary
693    if (curr >= size) {
694        if (!fgets((char *)buffer, BUFFER_SIZE+1, stdin))
695            return  EOF;
696        size = strlen((char *)buffer);
697        if (size < BUFFER_SIZE && buffer[size-1] != '\n') {
698            buffer[size] = '\n';
699            buffer[++size] = '\0';
700        }
701        curr = 0;
702    }
703    if (buffer[curr+1] != '\b')         // this is not a special sequence
704        return  buffer[curr++];
705
706    // Check if it is a bold sequence
707    c = buffer[curr++];
708    if (c               == buffer[curr+1] &&
709        buffer[curr]    == buffer[curr+2] &&
710        c               == buffer[curr+3] &&
711        buffer[curr]    == buffer[curr+4] &&
712        c               == buffer[curr+5])
713    {
714        *statusp = IS_BOLD;
715        curr += 6;
716    }
717
718    // Return the first character of the sequence
719    return  c;
720}
721
722/*
723 * Test if we have a binary file.
724 */
725static int is_binaryfile(char *name) {
726    if (chars > 120 || pages > 1) {
727        first_page = FALSE;
728        if (chars && !print_binaries && (nonprinting_chars*100 / chars) >= 60) {
729            fprintf(stderr, "%s is a binary file: printing aborted\n", name);
730            return TRUE;
731        }
732    }
733    return FALSE;
734}
735
736/*
737 * Cut long filenames.
738 */
739static void cut_filename(char *old_name, char *new_name) {
740    char *p;
741    int   i;
742    char *separator;
743
744    if ((i = strlen(old_name)) <= MAXFILENAME) {
745        strcpy(new_name, old_name);
746        return;
747    }
748    p = old_name + (i-1);
749    separator = NULp;
750    i = 1;
751    while (p >= old_name && i < MAXFILENAME) {
752        if (*p == DIR_SEP)
753            separator = p;
754        p--;
755        i++;
756    }
757    if (separator)
758        p = separator;
759    else if (p >= old_name)
760        while (p >= old_name && *p != DIR_SEP) p--;
761
762    for (i = 0, p++; *p != NUL; i++)
763        *new_name++ = *p++;
764    *new_name = NUL;
765}
766
767/*
768 * Print a char in a form accepted by postscript printers.
769 */
770static int printchar(unsigned char c) {
771
772    if (c >= ' ' && c < 0177) {
773        if (c == '(' || c == ')' || c == '\\')
774            putchar('\\');
775        putchar(c);
776        return 0;
777    }
778
779    if (ISOlatin1 && (c > 0177)) {
780        printf("\\%o", c);
781        return 0;
782    }
783
784    if (only_printable) {
785        putchar(' ');
786        return 1;
787    }
788
789    if (c > 0177) {
790        printf("M-");
791        c &= 0177;
792    }
793    if (c < ' ') {
794        putchar('^');
795        if ((c = c + '@') == '(' || c == ')' || c == '\\')
796            putchar('\\');
797        putchar(c);
798    }
799    else if (c == 0177)
800        printf("^?");
801    else {
802        if (c == '(' || c == ')' || c == '\\')
803            putchar('\\');
804        putchar(c);
805    }
806
807    return 1;
808}
809
810/*
811 * Begins a new logical page.
812 */
813static void skip_page() {
814    if (twinpages == FALSE || sheetside == 0) {
815        printf("%%%%Page: %d %d\n", sheets+1, sheets+1);
816        printf("/pagesave save def\n");
817        // Reinitialize state variables for each new sheet
818        print_page_prologue(0);
819    }
820    startpage();
821}
822
823/*
824 * Fold a line too long.
825 */
826static int fold_line(char *name) {
827    column = 0;
828    printf(") s\n");
829    if (++line >= linesperpage) {
830        endpage();
831        skip_page();
832        if (first_page && is_binaryfile(name))
833            return FALSE;
834        line = 0;
835    }
836    if (numbering)
837        printf("(    +");
838    else
839        printf("( ");
840
841    return TRUE;
842}
843
844/*
845 * Cut a textline too long to the size of a page line.
846 */
847static int cut_line() {
848    int c;
849    int status;
850
851    while ((c = mygetc(&status)) != EOF && c != '\n' && c != '\f') ;
852    return c;
853}
854
855
856//**************************************************************
857//                      "Postscript" routines.
858//**************************************************************
859
860/*
861 * Print a physical page.
862 */
863static void printpage() {
864    sheetside = 0;
865    sheets++;
866    printf("/sd 0 def\n");
867    if (no_border == FALSE)
868        printf("%d sn\n", sheets - (restart ? old_sheets : 0));
869    if (printdate)
870        printf("cd\n");
871    if (filename_footer && landscape)
872        printf("fnf\n");
873#if defined(SYSV) || defined(BSD)
874    if (login_id)
875        printf("lg lgp\n");
876#endif
877    printf("pagesave restore\n");
878    printf("showpage\n");
879}
880
881/*
882 * Prints page header and page border and
883 * initializes printing of the file lines.
884 */
885void startpage() {
886    if (sheetside == 0) {
887#ifdef RECTO_VERSO_PRINTING
888        if (rectoverso && (sheets & 0x1)) {
889            // Shift to left backside pages.
890            printf("rm neg 0 translate\n");
891        }
892#endif
893        if (landscape) {
894            printf("sw 0 translate\n");
895            printf("90 rotate\n");
896        }
897    }
898    pages++;
899    if (no_header == FALSE)
900        printf("%d hp\n", pages - old_pages);
901    if (no_border == FALSE) {
902        printf("border\n");
903        if (no_header == FALSE)
904            printf("hborder\n");
905    }
906    printf("/x0 x %d get bm add def\n", sheetside);
907    printf("/y0 y %d get bm bfs add %s add sub def\n",
908           sheetside, no_header ? "0" : "hs");
909    printf("x0 y0 moveto\n");
910    printf("bf setfont\n");
911}
912
913/*
914 * Terminates printing, flushing last page.
915 */
916static void cleanup() {
917    if (twinpages && sheetside == 1)
918        printpage();
919#ifdef RECTO_VERSO_PRINTING
920    if (!twinfiles && rectoverso && (sheets & 0x1) != 0) {
921        sheetside = 0;
922        sheets++;
923        printf("%%%%Page: %d %d\n", sheets, sheets);
924        printf("showpage\n");
925    }
926#endif
927}
928
929/*
930 * Adds a sheet number to the page (footnote) and prints the formatted
931 * page (physical impression). Activated at the end of each source page.
932 */
933void endpage() {
934    if (twinpages && sheetside == 0) {
935        sheetside = 1;
936        printf("/sd 1 def\n");
937    }
938    else
939        printpage();
940}
941
942
943//**************************************************************
944//              Printing a file
945//**************************************************************
946
947/*
948 * Print the file prologue.
949 */
950static void init_file_printing(char *name, char *title) {
951    int new_format, new_font;
952    char *string;
953    int lines;
954    float char_width;
955    struct stat statbuf;
956
957    // Print last page of previous file, if necessary
958    if (pages > 0 && !twinfiles)
959        cleanup();
960
961    // Initialize variables related to the format
962    new_format = FALSE;
963    if (new_landscape != landscape || new_twinpages != twinpages) {
964        landscape = new_landscape;
965        twinpages = new_twinpages;
966        new_format = TRUE;
967    }
968
969    // Initialize variables related to the header
970    if (no_header && name == title)
971        header_size = 0.0;
972    else {
973        if (landscape || twinpages)
974            header_size = LANDSCAPE_HEADER * PIXELS_INCH;
975        else
976            header_size = PORTRAIT_HEADER * PIXELS_INCH;
977        cut_filename(title, current_filename);
978    }
979
980    // Initialize variables related to the font size
981    new_font = FALSE;
982    if (fontsize != new_fontsize || new_format ||
983        lines_requested != new_linesrequest || fontweight != new_fontweight)
984    {
985        if (new_fontsize == 0.0 || (fontsize == new_fontsize && new_format)) {
986            new_fontsize = landscape ? 6.8 : twinpages ? 6.4 : 9.0;
987        }
988        if (lines_requested != new_linesrequest) {
989            if ((lines_requested = new_linesrequest) != 0) {
990                // Scale fontsize
991                if (landscape)       lines = (int)((page_width-header_size) / new_fontsize) - 1;
992                else if (twinpages)  lines = (int)(((page_height - 2*header_size) / 2) / new_fontsize) - 2;
993                else                 lines = (int)((page_height-header_size) / new_fontsize) - 1;
994                new_fontsize *= (float)lines / (float)lines_requested;
995            }
996        }
997        fontsize = new_fontsize;
998        fontweight = new_fontweight;
999        new_font = TRUE;
1000    }
1001
1002    // Initialize file printing, if there is any change
1003    if (new_format || new_font) {
1004        char_width = 0.6 * fontsize;
1005        if (landscape) {
1006            linesperpage = (int)((page_width - header_size) / fontsize) - 1;
1007            if (! twinpages)
1008                columnsperline = (int)(page_height / char_width) - 1;
1009            else
1010                columnsperline = (int)((page_height / 2) / char_width) - 1;
1011        }
1012        else {
1013            if (!twinpages)
1014                linesperpage = (int)((page_height - header_size) / fontsize) - 1;
1015            else
1016                linesperpage = (int)(((page_height - 2*header_size) / 2) / fontsize)
1017                    - 2;
1018            columnsperline = (int)(page_width / char_width) - 1;
1019        }
1020        if (lines_requested > 0)
1021            linesperpage = lines_requested;
1022        if (linesperpage <= 0 || columnsperline <= 0) {
1023            fprintf(stderr, "Font %g too big !!\n", fontsize);
1024            exit(EXIT_FAILURE);
1025        }
1026    }
1027
1028    // Retrieve file modification date and hour
1029    if (fstat(fileno(stdin), &statbuf) == -1) {
1030        fprintf(stderr, "Error getting file modification time\n");
1031        exit(EXIT_FAILURE);
1032    }
1033    // Do we have a pipe?
1034    if (S_ISFIFO(statbuf.st_mode))
1035        strcpy(filedate, currentdate);
1036    else {
1037        string = ctime(&statbuf.st_mtime);
1038        sprintf(filedate, "%.6s %.4s %.5s", string+4, string+20, string+11);
1039    }
1040}
1041
1042/*
1043 * Print the prologue necessary for printing each physical page.
1044 * Adobe convention for page independence is enforced through this routine.
1045 */
1046void print_page_prologue(int side) {
1047    // side: Logical page to print (left/right)
1048
1049    // General format
1050    printf("/twp %s def\n", twinpages ? "true" : "false");
1051    printf("/fnfs %d def\n", landscape ? 11 : twinpages ? 10 : 15);
1052    printf("/dfs fnfs 0.8 mul def\n");
1053    printf("/df /Helvetica dfs getfont def\n");
1054    printf("/dw df setfont td stringwidth pop def\n");
1055    printf("/sfnf filenmfontname fnfs getfont def\n");
1056    printf("/hm fnfs 0.25 mul def\n");
1057    // Header size
1058    if (header_size == 0.0)
1059        printf("/hs 0.0 def\n");
1060    else
1061        printf("/hs %g inch def\n",
1062               landscape || twinpages ? LANDSCAPE_HEADER : PORTRAIT_HEADER);
1063    // Font sizes
1064    printf("/bfs %g def\n", fontsize);
1065    printf("/bdf /Courier-Bold bfs getfont def\n");
1066    printf("/bm bfs 0.7 mul def\n");
1067    printf("/bf %s bfs getfont def\n",
1068           fontweight == NORMAL ? "/CourierBack" : "/Courier-Bold");
1069    // Page attributes
1070    printf("/l %d def\n", linesperpage);
1071    printf("/c %d def\n", columnsperline);
1072    printf("/pw\n");
1073    printf("   bf setfont (0) stringwidth pop c mul bm dup add add\n");
1074    printf("   def\n");
1075    printf("/ph\n");
1076    printf("   bfs l mul bm dup add add hs add\n");
1077    printf("   def\n");
1078    printf("/fns\n");
1079    printf("      pw\n");
1080    printf("      fnfs 4 mul dw add (Page 999) stringwidth pop add\n");
1081    printf("    sub\n");
1082    printf("  def\n");
1083    printf("/tm margin twp {3} {2} ifelse div def\n");
1084    printf("/sd %d def\n", side);
1085    if (landscape) {
1086        printf("/y [ rm ph add bm add\n");
1087        printf("          dup ] def\n");
1088        printf("/sny dfs dfs add def\n");
1089        printf("/snx sh tm dfs add sub def\n");
1090        printf("/dy sny def\n");
1091        printf("/dx tm dfs add def\n");
1092        if (twinpages) {
1093            printf("/x [ tm                     %% left page\n");
1094            printf("          dup 2 mul pw add  %% right page\n");
1095            printf("        ] def\n");
1096        }
1097        else {
1098            printf("/x [ tm dup ] def\n");
1099        }
1100        printf("/scx sh 2 div def\n");
1101    }
1102    else {
1103        printf("/x [ lm dup ] def\n");
1104        printf("/sny tm dfs 2 mul sub def\n");
1105        printf("/snx sw rm sub dfs sub def\n");
1106        printf("/dy sny def\n");
1107        printf("/dx lm def\n");
1108        if (twinpages) {
1109            printf("/y [ tm ph add 2 mul %% up\n");
1110            printf("          tm ph add  %% down\n");
1111            printf("        ] def\n");
1112        }
1113        else {
1114            printf("\n%% Only one logical page\n");
1115            printf("/y [ sh tm sub dup ] def\n");
1116        }
1117        printf("/scx sw 2 div def\n");
1118    }
1119    printf("/fny dy def\n");
1120    printf("/fnx scx def\n");
1121    printf("/ly fnfs 2 div y sd get add def\n");
1122    printf("/lx snx def\n");
1123    printf("/d (%s) def\n", filedate);
1124    printf("( %s ) fn\n", current_filename);
1125}
1126
1127/*
1128 * Print one file.
1129 */
1130static void print_file(char *name, char *header) {
1131    int c;
1132    int nchars;
1133    int start_line, start_page;
1134    int continue_exit;
1135    int status, new_status;
1136
1137    // Reinitialize postscript variables depending on positional options
1138    init_file_printing(name, header ? header : name);
1139
1140    // If we are in compact mode and the file beginning is to be printed
1141    // in the middle of a twinpage, we have to print a new page prologue
1142    if (twinfiles && sheetside == 1)
1143        print_page_prologue(1);
1144
1145    /*
1146     * Boolean to indicates that previous char is \n (or interpreted \f)
1147     * and a new page would be started, if more text follows
1148     */
1149    start_page = FALSE;
1150
1151    /*
1152     * Printing binary files is not very useful. We stop printing
1153     * if we detect one of these files. Our heuristic to detect them:
1154     * if 75% characters of first page are non-printing characters,
1155     * the file is a binary file.
1156     * Option -b force binary files impression.
1157     */
1158    nonprinting_chars = chars = 0;
1159
1160    // Initialize printing variables
1161    column = 0;
1162    line = line_number = 0;
1163    first_page = TRUE;
1164    start_line = TRUE;
1165    prefix_width = numbering ? 6 : 1;
1166
1167    // Start printing
1168    skip_page();
1169
1170    // Process each character of the file
1171    status = IS_ROMAN;
1172    c = mygetc(&new_status);
1173    while (c != EOF) {
1174        /*
1175         * Preprocessing (before printing):
1176         * - TABs expansion (see interpret option)
1177         * - FF and BS interpretation
1178         * - replace non printable characters by a space or a char sequence
1179         *   like:
1180         *     ^X for ascii codes < 0x20 (X = [@, A, B, ...])
1181         *     ^? for del char
1182         *     M-c for ascii codes > 0x3f
1183         * - prefix parents and backslash ['(', ')', '\'] by backslash
1184         *   (escape character in postscript)
1185         */
1186        // Form feed
1187        if (c == '\f' && interpret) {
1188            // Close current line
1189            if (!start_line) {
1190                printf(") s\n");
1191                start_line = TRUE;
1192            }
1193            // start a new page ?
1194            if (start_page)
1195                skip_page();
1196            // Close current page and begin another
1197            endpage();
1198            start_page = TRUE;
1199            // Verification for binary files
1200            if (first_page && is_binaryfile(name))
1201                return;
1202            line = 0;
1203            column = 0;
1204            if ((c = mygetc(&new_status)) == EOF)
1205                break;
1206        }
1207
1208        // Start a new line ?
1209        if (start_line) {
1210            if (start_page) {
1211                // only if there is something to print!
1212                skip_page();
1213                start_page = FALSE;
1214            }
1215            if (numbering)
1216                printf("(%4d|", ++line_number);
1217            else
1218                printf("( ");
1219            start_line = FALSE;
1220        }
1221
1222        // Is a new font ? This feature is used only to detect bold
1223        // sequences produced by nroff (man pages), in connexion with
1224        // mygetc.
1225        if (status != new_status) {
1226            printf(")\n");
1227            printf("%s", status == IS_ROMAN ? "b" : "st");
1228            printf(" (");
1229            status = new_status;
1230        }
1231
1232        // Interpret each character
1233        switch (c) {
1234            case '\b':
1235                if (!interpret)
1236                    goto print;
1237                // A backspace is converted to 2 chars ('\b'). These chars
1238                // with the Courier backspace font produce correct under-
1239                // lined strings.
1240                if (column)
1241                    column--;
1242                putchar('\\');
1243                putchar('b');
1244                break;
1245            case '\n':
1246                column = 0;
1247                start_line = TRUE;
1248                printf(") s\n");
1249                if (++line >= linesperpage) {
1250                    endpage();
1251                    start_page = TRUE;
1252                    if (first_page && is_binaryfile(name))
1253                        return;
1254                    line = 0;
1255                }
1256                break;
1257            case '\t':
1258                if (interpret) {
1259                    continue_exit = FALSE;
1260                    do {
1261                        if (++column + prefix_width > columnsperline) {
1262                            if (folding) {
1263                                if (fold_line(name) == FALSE)
1264                                    return;
1265                            }
1266                            else {
1267                                c = cut_line();
1268                                continue_exit = TRUE;
1269                                break;
1270                            }
1271                        }
1272                        putchar(' ');
1273                    } while (column % column_width);
1274                    if (continue_exit)
1275                        continue;
1276                    break;
1277                }
1278                __attribute__ ((fallthrough)); // implicit fallthrough
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 = NULp;
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) {
1372#if defined(SYSV)
1373        if ((rt = uname(&snames)) == -1 || !snames.nodename[0]) {
1374            free(host);
1375            host = NULp;
1376        }
1377        else
1378            strcpy(host, snames.nodename);
1379#else
1380        if ((rt = gethostname(host, MAX_HOSTNAME)) == -1 || !host[0]) {
1381            free(host);
1382            host = NULp;
1383        }
1384#endif
1385    }
1386#endif
1387
1388    // Print a general prologue
1389    if (!prologue)
1390        print_standard_prologue(datestring);
1391    else if ((f = fopen(prologue, "r"))) {
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 || host) {
1420        if (logname && host)
1421            printf("/lg (Printed by %s from %s) def\n", logname, host);
1422        else if (logname)
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)
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    if (f) 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)) {
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 = NULp;
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.