home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
source
/
a2ps30.zoo
/
a2ps30
/
a2ps.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-23
|
18KB
|
725 lines
/************************************************************************/
/* */
/* 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");
}