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). */
- /* Modifid by tml@tik.vtt.fi */
- /* 13) Simplified *a lot*. Produce conforming PostScript. */
- /* Use getopt. */
- /* */
- /************************************************************************/
-
- /*
- * 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>
- #include <string.h>
- #include <sys/types.h>
- #include <time.h>
-
- #ifndef PROLOGUE
- #define PROLOGUE "./a2ps.prologue"
- #endif
-
- /* A4 paper size */
-
- #define MM_PER_INCH 25.4
-
- #ifndef WIDTH
- #define WIDTH (210/MM_PER_INCH)
- #endif
-
- #ifndef HEIGHT
- #define HEIGHT (297/MM_PER_INCH)
- #endif
-
- #ifndef MARGIN
- #define MARGIN (15/MM_PER_INCH)
- #endif
-
- /* The portrait header is tuned to produce 80 columns */
- #define PORTRAIT_HEADER 0.9
- #define LANDSCAPE_HEADER 0.5
- #define POINTS_PER_INCH 72
- #define MAXFILENAME 20
- #define FALSE 0
- #define TRUE 1
-
- static int fold_line();
- static void print_file();
- static char cut_line();
- static int printchar();
- static void skip_page();
- static void header_and_prologue();
-
- static char *titlestring;
- static char dictid[100];
-
- static char *curfilename;
- static int column = 0; /* Column number (in current line) */
- static int line = 0; /* Line number (in current page) */
- static int first_page; /* First page for a file */
- static int nonprinting_chars, chars; /* Number of nonprinting and total chars */
- static int pages = 0; /* Number of logical pages printed */
- static int filepage; /* Number of page of curent file */
- static int linesperpage = 0; /* Lines per page */
- static int columnsperline; /* Characters per output line */
- /* */
- static double font_size = 0.0; /* Size of a char for body font */
- static int folding = TRUE; /* Line folding option */
- static int restart = TRUE; /* Restart page number at each file option */
- static int only_printable = FALSE; /* Replace non printable char by space option */
- static int interpret = TRUE; /* Interpret TAB, FF and BS chars option */
- static int print_binaries = FALSE; /* Force printing for binary files */
- static int landscape = FALSE; /* Otherwise portrait format sheets */
- static int no_border = FALSE; /* TRUE if user don't want the border */
- static int no_header = FALSE; /* TRUE if user don't want the header */
- static int column_width = 8; /* default column tab width (8) */
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- double char_width, header_size;
- double page_height, page_width;
- int i;
- extern double atof();
- int c;
- extern char *optarg;
- extern int optind;
-
- /* Option processing */
- while ((c = getopt(argc, argv, "bcf:hil:nt:vw")) != EOF)
- switch (c) {
- case 'b': /* print binary files */
- print_binaries = TRUE;
- break;
- case 'c': /* cut long lines */
- folding = FALSE;
- break;
- case 'f': /* change font size */
- if ((font_size = atof(optarg)) == 0.0) {
- fprintf(stderr, "Invalid font size (-f option)\n");
- exit(2);
- }
- break;
- case 'h':
- no_header = TRUE;
- break;
- case 'i': /* don't interpret ctrl chars */
- interpret = FALSE;
- break;
- case 'l':
- if ((linesperpage = atoi(optarg)) == 0) {
- fprintf(stderr, "Invalid page length (-l option)\n");
- exit(2);
- }
- break;
- case 't': /* set tab size */
- if ((column_width = atoi(optind)) <= 0) {
- fprintf(stderr, "Invalid tab width (-t option)\n");
- exit(2);
- }
- break;
- case 'v': /* print control chars */
- only_printable = FALSE;
- break;
- case 'w': /* landscape format */
- landscape = TRUE;
- break;
-
- default:
- usage:
- fprintf(stderr,"Usage: %s [options] [f1 f2 ... fn]\n", argv[0]);
- fprintf(stderr," -f num\t(font size)\n");
- fprintf(stderr," -h\t(print this information)\n");
- fprintf(stderr," -i\t(don't interpret tab, bs and ff chars)\n");
- fprintf(stderr," -n\t(don't number line files)\n");
- fprintf(stderr," -p\t(print in portrait mode)\n");
- fprintf(stderr," -tn\t(set tab size to n)\n");
- fprintf(stderr," -v\t(show non-printing chars in a clear form)\n");
- exit(0);
- }
-
- sprintf(dictid, "a2ps-%d", time((time_t*)0));
-
- page_height = (HEIGHT - 2*MARGIN) * POINTS_PER_INCH;
- page_width = (WIDTH - 2*MARGIN) * POINTS_PER_INCH;
- if (landscape) {
- header_size = no_header ? 0.0 : LANDSCAPE_HEADER * POINTS_PER_INCH;
- if (linesperpage == 0)
- linesperpage = 66;
- if (font_size == 0)
- font_size = ((page_width - header_size) / linesperpage);
- char_width = 0.6 * font_size;
- columnsperline = (page_height / char_width) - 1;
- } else {
- header_size = no_header ? 0.0 : PORTRAIT_HEADER * POINTS_PER_INCH;
- if (linesperpage == 0)
- linesperpage = 66;
- if (font_size == 0)
- font_size = ((page_height - header_size) / linesperpage);
- char_width = 0.6 * font_size;
- columnsperline = (page_width / char_width) - 1;
- }
- if (linesperpage * font_size - 1 /* -1 to compensate for rounding errors */
- > (landscape ? page_width : page_height) - header_size) {
- fprintf(stderr, "Font too big or too many lines per page\n");
- exit(2);
- }
-
- if (optind == argc - 1)
- titlestring = argv[optind];
- else
- titlestring = "a2ps listing";
-
- /* Header printing (postcript prolog) */
- header_and_prologue();
-
- /* Print files designated or standard input */
- if (optind >= argc)
- print_file("");
- else {
- for ( ; optind < argc; optind++) {
- if (freopen(argv[optind], "r", stdin) == NULL)
- fprintf(stderr, "Error opening %s\n", argv[optind]);
- else
- print_file(argv[optind]);
- }
- }
-
- printf("\n\
- %%%%Trailer\n\
- %%%%Pages: %d\n",
- pages);
- return 0;
- }
-
- static 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;
-
- filepage = 0;
-
- /*
- * 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 backslash-octal sequence
- * - prefix parents and backslash ['(', ')', '\'] by backslash
- * (escape character in postcript)
- */
- column = 0;
- line = 0;
- start_line = TRUE;
-
- if (strlen(name) > MAXFILENAME) {
- cut_filename(name, new_name);
- curfilename = name = new_name;
- } else
- curfilename = name;
-
- 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("grestore end showpage\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 ;
- }
- printf("gsave ( ");
- start_line = FALSE;
- }
-
- /* Interpret each character */
- switch (c) {
- case '\b':
- if (!interpret)
- goto print;
- if (column)
- column--;
- printf(") bs (");
- break;
- case '\n':
- column = 0;
- start_line = TRUE;
- printf(") s\n");
- if (++line >= linesperpage) {
- printf("grestore end showpage\n");
- start_page = TRUE ;
- if (first_page && is_binaryfile(name))
- return;
- line = 0;
- }
- break;
- case '\t':
- if (interpret) {
- continue_exit = FALSE;
- do {
- if (++column >= 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 < ' ' || c >= 0177) ? 4 : 1;
- if ((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("grestore end showpage\n");
- }
-
- /*
- * Cut long filenames.
- */
- static int
- cut_filename(old_name, new_name)
- char *old_name, *new_name;
- {
- register char *p;
- register int i;
-
- p = strrchr(old_name, '/');
- if (!p)
- p = old_name;
-
- for (i = 0, p++; *p != NULL && i < MAXFILENAME; i++)
- *new_name++ = *p++;
- *new_name = NULL;
- }
-
- /*
- * Fold a line too long.
- */
- static int
- fold_line(name)
- char *name;
- {
- column = 0;
- printf(") s\n");
- if (++line >= linesperpage) {
- printf("grestore end showpage\n");
- if (first_page && is_binaryfile(name))
- return FALSE;
- skip_page();
- line = 0;
- }
- printf("gsave ( ");
-
- return TRUE;
- }
-
- /*
- * Cut a textline too long to the size of a page line.
- */
- static 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.
- */
- static 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;
- }
-
- printf("\\134%o", c);
- return 1;
- }
-
- /*
- * Begins a new physical page.
- */
- static void
- skip_page()
- {
- char *p;
-
- pages++;
- filepage++;
- printf("\
- %%%%Page: %d %d\n\
- %s begin\n\
- /pagenum %d def\n",
- pages, pages, dictid, filepage);
- putchar('(');
- for (p = curfilename; *p;)
- printchar(*p++);
- printf(") setfilename gsave startpage\n");
- }
-
- /*
- * Test if we have a binary file.
- */
- static int
- 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;
- }
-
- static void
- header_and_prologue()
- {
- register int c;
- FILE *prologue;
- char *datestring;
- time_t date;
-
- if ((prologue = fopen(PROLOGUE, "r")) == NULL) {
- fprintf(stderr, "Poscript header missing\n");
- exit(1);
- }
-
- /* Retrieve date and hour */
- if (time(&date) == -1) {
- perror("time:");
- exit(1);
- }
- datestring = ctime(&date);
-
- /* Conforming header and prologue */
- printf("\
- %%!PS-Adobe-2.0\n\
- %%%%Title: %s\n\
- %%%%Creator: a2ps 4.0(tml)\n\
- %%%%CreationDate: %s\
- %%%%Pages: (atend)\n\
- %%%%BoundingBox: %d %d %d %d\n\
- %%%%DocumentFonts: Helvetica-Bold Helvetica Courier\n\
- %%%%EndComments\n\
- /%s 100 dict def\n\
- %% Initialize page description variables.\n\
- %s begin\n\
- /inch {72 mul} bind def\n\
- /landscape %s def\n\
- /sheetheight %g inch def\n\
- /sheetwidth %g inch def\n\
- /margin %g inch def\n\
- /noborder %s def\n",
- titlestring,
- datestring,
- (int) (MARGIN*72), (int) (MARGIN*72),
- (int) ((WIDTH-MARGIN)*72), (int) ((HEIGHT-MARGIN)*72),
- dictid,
- dictid,
- landscape ? "true" : "false",
- HEIGHT, WIDTH, MARGIN,
- no_border ? "true" : "false");
- if (no_header)
- printf("\
- /noheader true def\n\
- /headersize 0.0 def\n");
- else
- printf("\
- /noheader false def\n\
- /headersize %g inch def\n", landscape ? LANDSCAPE_HEADER : PORTRAIT_HEADER);
- printf("\
- /bodyfontsize %g def\n\
- /lines %d def\n\
- /columns %d def\n\
- /date (%.6s %.4s %.8s) def\n",
- font_size,
- linesperpage,
- columnsperline,
- datestring+4, datestring+20, datestring+11);
-
- /* Prologue */
- printf("%%%%BeginFile: %s\n", PROLOGUE);
- while ((c = getc(prologue)) != EOF)
- putchar(c);
- fclose(prologue);
- printf("%%%%EndFile\n");
-
- printf("end\n%%%%EndProlog\n\n");
- }
-