source: tags/cvs_2_svn/TOOLS/arb_a2ps.c

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