home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* */
- /* Description: Ascii to PostScript printer program. */
- /* File: imag:/users/local/a2ps/a2ps.c */
- /* Created: Mon Nov 28 15:22:15 1988 by miguel@imag (Miguel Santana) */
- /* Version: 2.0 */
- /* */
- /* Edit history: */
- /* 1) Derived of shell program written by evan@csli (Evan Kirshenbaum). */
- /* Written in C for improve speed execution and portability. Many */
- /* improvements have been added. */
- /* Fixes by Oscar Nierstrasz @ cui.uucp: */
- /* 2) Fixed incorrect handling of stdin (removed error if no file names)*/
- /* 3) Added start_page variable to eliminate blank pages printed for */
- /* files that are exactly multiples of 132 lines (e.g., man pages) */
- /* Modified by miguel@imag: */
- /* 4) Added new options at installation : sheet format (height/width in */
- /* inches), page format (number of columns per line and of lines per */
- /* page). */
- /* Modified by miguel@imag: */
- /* 5) Added new option to print n copies of a same document. */
- /* 6) Cut long filenames if don't fit in the page header. */
- /* Modified by Tim Clark (T.Clark@warwick.ac.uk): */
- /* 7) Two additional modes of printing (portrait and wide format modes) */
- /* 8) Fixed to cope with filenames which contain a character which must */
- /* be escaped in a PostScript string. */
- /* Modified by miguel@imag.fr to */
- /* 9) Add new option to suppress heading printing. */
- /* 10) Add new option to suppress page surrounding border printing. */
- /* 11) Add new option to change font size. Number of lines and columns */
- /* are now automatically adjusted, depending on font size and */
- /* printing mode used. */
- /* 12) Minor changes (best layout, usage message, etc). */
- /* */
- /************************************************************************/
-
- /*
- * Copyright (c) 1988, Miguel Santana, miguel@imag.imag.fr
- *
- * Permission is granted to copy and distribute this file in modified
- * or unmodified form, for noncommercial use, provided (a) this copyright
- * notice is preserved, (b) no attempt is made to restrict redistribution
- * of this file, and (c) this file is not distributed as part of any
- * collection whose redistribution is restricted by a compilation copyright.
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef ANSIC
- #include <sys/types.h>
- #include <time.h>
- #else
- #ifdef BSD
- #include <sys/time.h>
- #else
- #ifdef SYSV
- #include <sys/types.h>
- #include <sys/timeb.h>
- #include <time.h>
- #else
- error !
- #endif
- #endif
- #endif
-
- #ifndef HEADER_PS
- #define HEADER_PS "./header.ps"
- #endif
-
- #ifndef WIDTH
- #define WIDTH 8.27
- #endif
-
- #ifndef HEIGHT
- #define HEIGHT 11.64
- #endif
-
- #ifndef MARGIN
- #define MARGIN 1.2
- #endif
-
- #ifndef DIR_SEP
- #define DIR_SEP '/'
- #endif
-
- #define PORTRAIT_HEADER 0.29
- #define LANDSCAPE_HEADER 0.22
- #define PIXELS_INCH 72
- #define MAXFILENAME 20
- #define FALSE 0
- #define TRUE 1
-
- int fold_line();
- void print_file();
- char cut_line();
- int printchar();
- void skip_page();
-
-
- int column = 0; /* Column number (in current line) */
- int line = 0; /* Line number (in current page) */
- int line_number = 0; /* Source line number */
- int first_page; /* First page for a file */
- int nonprinting_chars, chars; /* Number of nonprinting and total chars */
- int prefix_width; /* Width in characters for line prefix */
- int pages = 0; /* Number of logical pages printed */
- int sheets = 0; /* Number of physical pages printed */
- int linesperpage; /* Lines per page */
- int columnsperline; /* Characters per output line */
-
- double font_size = 0.0; /* Size of a char for body font */
- int numbering = TRUE; /* Line numbering option */
- int folding = TRUE; /* Line folding option */
- int restart = TRUE; /* Restart page number at each file option */
- int only_printable = FALSE; /* Replace non printable char by space option */
- int interpret = TRUE; /* Interpret TAB, FF and BS chars option */
- int print_binaries = FALSE; /* Force printing for binary files */
- int copies_number = 1; /* Number of copies to print */
- int landscape = TRUE; /* Otherwise portrait format sheets */
- int wide_pages = FALSE; /* TRUE implies landscape, not twinpage */
- int twinpage = TRUE; /* 2 pages per sheet if true, 1 otherwise */
- int no_border = FALSE; /* TRUE if user don't want the border */
- int no_header = FALSE; /* TRUE if user don't want the header */
- int column_width = 8; /* default column tab width (8) */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- register int narg;
- register char *arg;
- double char_width, header_size;
- double page_height, page_width;
- int i;
- extern double atof();
-
- /* Option processing */
- arg = argv[narg = 1];
- while (narg < argc && arg[0] == '-')
- {
- switch (arg[1])
- {
- case '?': /* help */
- goto usage;
- case '#': /* n copies */
- copies_number = 0;
- arg += 2;
- while (*arg != NULL && isdigit(*arg))
- copies_number = copies_number*10 + (*arg++ - '0');
- if (*arg != NULL || copies_number <= 0)
- goto usage;
- break;
- case 'b': /* print binary files */
- if (arg[2] != NULL)
- goto usage;
- print_binaries = TRUE;
- break;
- case 'f': /* change font size */
- if (arg[2] == NULL) {
- folding = TRUE;
- break;
- }
- if ((font_size = atof(&arg[2])) == 0.0) {
- fprintf(stderr, "Wrong value for option -s\n");
- exit(1);
- }
- break;
- case 'h': /* help */
- goto usage;
- case 'i': /* interpret control chars */
- if (arg[2] != NULL)
- goto usage;
- interpret = TRUE;
- break;
- case 'n': /* number file lines */
- if (arg[2] == NULL)
- {
- numbering = TRUE;
- break;
- }
- if (arg[3] != NULL)
- goto usage;
- switch (arg[2])
- {
- case 'b': /* don't print binaries */
- print_binaries = FALSE;
- break;
- case 'f': /* cut lines too long */
- folding = FALSE;
- break;
- case 'h': /* don't print header */
- no_header = TRUE;
- break;
- case 'i': /* don't interpret ctrl chars */
- interpret = FALSE;
- break;
- case 'n': /* don't number lines */
- numbering = FALSE;
- break;
- case 'p': /* landscape format */
- landscape = TRUE;
- break;
- case 'r': /* don't restart sheet number */
- restart = FALSE;
- break;
- case 's': /* no surrounding border */
- no_border = TRUE;
- break;
- case 'v': /* only printable chars */
- only_printable = TRUE;
- break;
- case 'w': /* twin pages */
- wide_pages = FALSE;
- break;
- default:
- goto usage;
- }
- break;
- case 'p': /* portrait format */
- if (arg[2] != NULL)
- goto usage;
- if (wide_pages) {
- fprintf(stderr, "a2ps: options -p and -w are incompatible\n");
- exit(1);
- }
- landscape = FALSE;
- break;
- case 'r': /* restart sheet number */
- if (arg[2] != NULL)
- goto usage;
- restart = TRUE;
- break;
- case 't': /* set tab size */
- if (arg[2] == NULL || (column_width = atoi(arg+2)) <= 0)
- goto usage;
- break;
- case 'v': /* print control chars */
- if (arg[2] != NULL)
- goto usage;
- only_printable = FALSE;
- break;
- case 'w': /* wide format */
- if (arg[2] != NULL)
- goto usage;
- if (!landscape) {
- fprintf(stderr, "a2ps: options -p and -w are incompatible\n");
- exit(1);
- }
- wide_pages = TRUE;
- break;
- default:
- usage:
- fprintf(stderr,"Usage: %s [options] [f1 f2 ... fn]\n", argv[0]);
- fprintf(stderr,"options = -#num\t(number of copies to print)\n");
- fprintf(stderr," -?\t(print this information)\n");
- fprintf(stderr," -f\t(fold lines too large)\n");
- fprintf(stderr," -fnum\t(font size, num is a float number)\n");
- fprintf(stderr," -h\t(print this information)\n");
- fprintf(stderr," -i\t(interpret tab, bs and ff chars)\n");
- fprintf(stderr," -n\t(number line files)\n");
- fprintf(stderr," -p\t(print in portrait mode)\n");
- fprintf(stderr," -r\t(restart page number after each file)\n");
- fprintf(stderr," -tn\t(set tab size to n)\n");
- fprintf(stderr," -v\t(show non-printing chars in a clear form)\n");
- fprintf(stderr," -w\t(print in wide format)\n");
- fprintf(stderr," -nb\t(don't force printing binary files)\n");
- fprintf(stderr," -nf\t(don't fold lines)\n");
- fprintf(stderr," -nh\t(don't print the header)\n");
- fprintf(stderr," -ni\t(don't interpret special chars)\n");
- fprintf(stderr," -nn\t(don't number output lines)\n");
- fprintf(stderr," -np\t(don't print in portrait format)\n");
- fprintf(stderr," -nr\t(don't restart page number)\n");
- fprintf(stderr," -ns\t(don't print surrounding borders)\n");
- fprintf(stderr," -nv\t(replace non-printing chars by space)\n");
- fprintf(stderr," -nw\t(don't print in wide format)\n");
- exit(1);
- }
- arg = argv[++narg];
- }
- if (arg != NULL && strcmp(arg, "?") == 0)
- goto usage;
-
- twinpage = landscape && !wide_pages;
- if (font_size == 0.0)
- font_size = landscape ? 6.8 : 9.0;
- page_height = (HEIGHT - MARGIN) * PIXELS_INCH;
- page_width = (WIDTH - MARGIN) * PIXELS_INCH;
- char_width = 0.6 * font_size;
- if (landscape) {
- header_size = no_header ? 0.0 : LANDSCAPE_HEADER * PIXELS_INCH;
- linesperpage = ((page_width - header_size) / font_size) - 1;
- if (wide_pages)
- columnsperline = (page_height / char_width) - 1;
- else
- columnsperline = ((page_height / 2) / char_width) - 1;
- }
- else {
- header_size = no_header ? 0.0 : PORTRAIT_HEADER * PIXELS_INCH;
- linesperpage = ((page_height - header_size) / font_size) - 1;
- columnsperline = (page_width / char_width) - 1;
- }
- if (linesperpage <= 0 || columnsperline <= 0) {
- fprintf(stderr, "Font %g too big !!\n", font_size);
- exit(1);
- }
-
- /* Header printing (postcript prolog) */
- print_header();
-
- /* Print files designated or standard input */
- prefix_width = numbering ? 6 : 1;
- if (narg >= argc)
- print_file("stdin");
- else
- {
- while (narg < argc)
- {
- if (freopen(arg, "r", stdin) == NULL)
- {
- fprintf(stderr, "Error opening %s\n", arg);
- printf("\n%%%%Trailer\ncleanup\ndocsave restore end\n");
- exit(1);
- }
- print_file(arg);
- arg = argv[++narg];
- }
- }
-
- printf("\n%%%%Trailer\ncleanup\ndocsave restore end\n");
- }
-
- void print_file(name)
- char *name;
- {
- register int c;
- int start_line, continue_exit;
- int char_width;
- int start_page;
- char new_name[MAXFILENAME+1];
- char *p;
-
- /*
- * Boolean to indicates that previous char is \n (or interpreted \f)
- * and a new page would be started, if more text follows
- */
- start_page = FALSE;
-
- /*
- * Printing binary files is not very useful. We stop printing
- * if we detect one of these files. Our heuristic to detect them:
- * if 50% characters of first page are non-printing characters,
- * the file is a binary file.
- * Option -b force binary files impression.
- */
- first_page = TRUE;
- nonprinting_chars = chars = 0;
-
- /*
- * Preprocessing (before printing):
- * - TABs expansion (see interpret option)
- * - FF and BS interpretation
- * - replace non printable characters by a space or a char sequence
- * like:
- * ^X for ascii codes < 0x20 (X = [@, A, B, ...])
- * ^? for del char
- * M-c for ascii codes > 0x3f
- * - prefix parents and backslash ['(', ')', '\'] by backslash
- * (escape character in postcript)
- */
- column = 0;
- line = line_number = 0;
- start_line = TRUE;
-
- if (strlen(name) > MAXFILENAME) {
- cut_filename(name, new_name);
- name = new_name;
- }
- putchar('(');
- for (p = name; *p != NULL;)
- printchar(*p++);
- printf(") newfile\n");
-
- if (restart)
- printf("/sheet 1 def\n");
-
- pages = 0;
- skip_page();
-
- c = getchar();
- while (c != EOF)
- {
- /* Form feed */
- if (c == '\f' && interpret)
- {
- /* Close current line */
- if (!start_line)
- {
- printf(") s\n");
- start_line = TRUE;
- }
- /* start a new page ? */
- if (start_page)
- skip_page();
- /* Close current page and begin another */
- printf("endpage\n") ;
- start_page = TRUE;
- /* Verification for binary files */
- if (first_page && is_binaryfile(name))
- return;
- line = 0;
- if ((c = getchar()) == EOF)
- break;
- }
-
- /* Start a new line? */
- if (start_line)
- {
- if (start_page)
- { /* only if there is something to print! */
- skip_page();
- start_page = FALSE ;
- }
- if (numbering)
- printf("(%-5d ", ++line_number);
- else
- printf("( ");
- start_line = FALSE;
- }
-
- /* Interpret each character */
- switch (c)
- {
- case '\b':
- if (!interpret)
- goto print;
- if (column)
- column--;
- putchar(c);
- break;
- case '\n':
- column = 0;
- start_line = TRUE;
- printf(") s\n");
- if (++line >= linesperpage)
- {
- printf("endpage\n");
- start_page = TRUE ;
- if (first_page && is_binaryfile(name))
- return;
- line = 0;
- }
- break;
- case '\t':
- if (interpret)
- {
- continue_exit = FALSE;
- do
- {
- if (++column + prefix_width > columnsperline)
- if (folding)
- {
- if (fold_line(name) == FALSE)
- return;
- }
- else
- {
- c = cut_line();
- continue_exit = TRUE;
- break;
- }
- putchar(' ');
- } while (column % column_width);
- if (continue_exit)
- continue;
- break;
- }
- default:
- print:
- if (only_printable)
- char_width = 1;
- else
- {
- char_width = c > 0177 ? 2 : 0;
- char_width += c < ' ' || c == 0177 ? 2 : 1;
- }
- if (prefix_width + (column += char_width) > columnsperline)
- if (folding)
- {
- if (fold_line(name) == FALSE)
- return;
- }
- else
- {
- c = cut_line();
- continue;
- }
- nonprinting_chars += printchar(c);
- chars++;
- break;
- }
- c = getchar();
- }
-
- if (!start_line)
- printf(") s\n");
- if (!start_page)
- printf("endpage\n");
- }
-
- /*
- * Cut long filenames.
- */
- int cut_filename(old_name, new_name)
- char *old_name, *new_name;
- {
- register char *p;
- register int i;
-
- p = old_name + (strlen(old_name)-1);
- while (p >= old_name && *p != DIR_SEP) p--;
-
- for (i = 0, p++; *p != NULL && i < MAXFILENAME; i++)
- *new_name++ = *p++;
- *new_name = NULL;
- }
-
- /*
- * Fold a line too long.
- */
- int fold_line(name)
- char *name;
- {
- column = 0;
- printf(") s\n");
- if (++line >= linesperpage)
- {
- printf("endpage\n");
- skip_page();
- if (first_page && is_binaryfile(name))
- return FALSE;
- line = 0;
- }
- if (numbering)
- printf("( ");
- else
- printf("( ");
-
- return TRUE;
- }
-
- /*
- * Cut a textline too long to the size of a page line.
- */
- char cut_line()
- {
- char c;
-
- while ((c = getchar()) != EOF && c != '\n' && c != '\f');
- return c;
- }
-
- /*
- * Print a char in a form accept by postscript printers.
- */
- int printchar(c)
- unsigned char c;
- {
- if (c >= ' ' && c < 0177)
- {
- if (c == '(' || c == ')' || c == '\\')
- putchar('\\');
- putchar(c);
- return 0;
- }
-
- if (only_printable)
- {
- putchar(' ');
- return 1;
- }
-
- if (c > 0177)
- {
- printf("M-");
- c &= 0177;
- }
- if (c < ' ')
- {
- putchar('^');
- if ((c = c + '@') == '(' || c == ')' || c == '\\')
- putchar('\\');
- putchar(c);
- }
- else if (c == 0177)
- printf("^?");
- else
- putchar(c);
-
- return 1;
- }
-
- /*
- * Begins a new physical page.
- */
- void skip_page()
- {
- pages++;
- if (twinpage == FALSE || (pages & 0x1))
- {
- sheets++;
- printf("%%%%Page: %d %d\n", sheets, sheets);
- }
- printf("startpage\n");
- }
-
- /*
- * Test if we have a binary file.
- */
- is_binaryfile(name)
- char *name;
- {
- first_page = FALSE;
- if (!print_binaries && (nonprinting_chars*100 / chars) >= 75)
- {
- fprintf(stderr, "%s is a binary file: printing aborted\n", name);
- return TRUE;
- }
- return FALSE;
- }
-
- print_header()
- {
- register int c;
- FILE *f;
- char *string;
- #ifdef ANSIC
- time_t date;
- #else
- #ifdef BSD
- struct timeval date;
- struct tm *p;
- #else
- #ifdef SYSV
- struct timeb date;
- #endif
- #endif
- #endif
-
- if ((f = fopen(HEADER_PS, "r")) == NULL)
- {
- fprintf(stderr, "Poscript header missing\n");
- exit(1);
- }
-
- /* Initialize some postcript variables */
- printf("%%! a2ps 3.0\n\n");
- printf("/$a2psdict 100 dict def\n");
- printf("$a2psdict begin\n");
- printf("%% Initialize page description variables.\n");
- printf("/inch {72 mul} bind def\n");
- printf("/landscape %s def\n", landscape ? "true" : "false");
- printf("/twinpage %s def\n", twinpage ? "true" : "false");
- printf("/sheetheight %g inch def\n", HEIGHT);
- printf("/sheetwidth %g inch def\n", WIDTH);
- printf("/margin %g inch def\n", MARGIN);
- printf("/noborder %s def\n", no_border ? "true" : "false");
- if (no_header) {
- printf("/noheader true def\n");
- printf("/headersize 0.0 def\n");
- }
- else {
- printf("/noheader false def\n");
- printf("/headersize %g inch def\n",
- landscape ? LANDSCAPE_HEADER : PORTRAIT_HEADER);
- }
- printf("/bodyfontsize %g def\n", font_size);
- printf("/lines %d def\n", linesperpage);
- printf("/columns %d def\n", columnsperline);
-
- /* Retrieve date and hour */
- #ifdef ANSIC
- if (time(&date) == -1)
- {
- fprintf(stderr, "Error calculing time\n");
- exit(1);
- }
- string = ctime(&date);
-
- /* and print them */
- printf("/date (%.6s %.4s %.8s) def\n", string+4, string+20, string+11);
- #else
- #ifdef BSD
- (void) gettimeofday(&date, (struct timezone *)0);
- p = localtime(&date.tv_sec);
- string = asctime(p);
-
- /* and print them */
- printf("/date (%.6s %.4s %.8s) def\n", string+4, string+20, string+11);
- #else
- #ifdef SYSV
- (void)ftime(&date);
- string = ctime(&date.time);
- printf("/date (%.6s %.4s %.8s) def\n", string+4, string+20, string+11);
- #endif
- #endif
- #endif
-
- /* Header file printing */
- while ((c = getc(f)) != EOF)
- putchar(c);
-
-
- /* Close prolog */
- printf("%%%%EndProlog\n\n");
-
- /* Ask for printing n copies */
- if (copies_number > 1)
- printf("/#copies %d def\n", copies_number);
-
- /* Go on */
- printf("/docsave save def\n");
- printf("startdoc\n");
- }
-