home *** CD-ROM | disk | FTP | other *** search
-
- /* vi: set tabstop=4 : */
-
- /*
- * lwf - Convert ASCII text to PostScript
- *
- * Usage:
- * lwf [-d] [-i#] [-l] [-m] [-olist] [-p[str]] [-P filename] [-s#] [-t#]
- * [-v] [file ...]
- *
- * Options:
- * -d Debug mode
- * -i# Indent each line # inches (so much for metric)
- * -l Landscape instead of Portrait
- * -m Use 3 hole punch margins
- * -olist Only print pages in the specified range
- * -p[str] Use pr to print, passing optional string
- * -P filename Copy prologue from filename instead of default
- * -r Toggle page reversal flag (see Makefile)
- * -s# Use point size #
- * -t# Spaces between tab stops is # characters
- * -v Verbose
- * -S Standalone mode (print header page, use EOF's)
- *
- * If no files are specified, stdin is used.
- * Form feeds handled
- * Backspacing with underlining (or overprinting) works
- * The output conforms to Adobe 2.0
- *
- * Problems:
- * - assumes fixed-width (non-proportional) font in some places
- * - can't back up (using backspaces) over tabs
- * - assumes 8.5 x 11.0 paper
- *
- * BJB - Jun/87
- * ========================================================================
- *
- * Permission is given to freely copy and distribute this software provided:
- *
- * 1) You do not sell it,
- * 2) You do not use it for commercial advantage, and
- * 3) This notice accompanies the distribution
- *
- * Copyright (c) 1988
- * Barry Brachman
- * Dept. of Computer Science
- * Univ. of British Columbia
- * Vancouver, B.C. V6T 1W5
- *
- * .. {ihnp4!alberta, uw-beaver, uunet}!ubc-vision!ubc-csgrads!brachman
- * brachman@grads.cs.ubc.cdn
- * brachman%ubc.csnet@csnet-relay.arpa
- * brachman@ubc.csnet
- * ========================================================================
- */
-
- #include <sys/file.h>
- #include <ctype.h>
- #include <pwd.h>
- #include <stdio.h>
-
- #define min(a, b) ((a) < (b) ? (a) : (b))
-
- /*
- * Configurable...
- * BUFOUT should be fairly large
- */
- #define BUFIN 1024 /* maximum length of an input line */
- #define BUFOUT (BUFIN * 5)
- #define MAXPAGES 10000 /* maximum number of pages per job */
- #define DEFAULT_TAB_SIZE 8
- #define DEFAULT_POINT_SIZE 10
- #ifndef PROLOGUE
- #define PROLOGUE "/usr/local/lib/lwf.prologue"
- #endif
- #ifndef REVERSE
- #define REVERSE 0
- #endif
- #ifndef PR
- #define PR "/bin/pr"
- #endif
-
- #ifdef SYSV
- #define rindex strrchr
- #endif
-
- /*
- * As mentioned in the man page, /bin/pr doesn't handle formfeeds correctly
- * when doing multicolumn formatting
- * Instead of starting a new column or page it passes a formfeed through,
- * causing pr and lwf to get out-of-synch with regard to the current
- * location on the page
- * If your pr behaves this way (4.[23] does, SYSV doesn't), define PRBUG so
- * that fgetline() will filter out these bogus formfeeds while preserving
- * the column structuring
- */
- #ifndef SYSV
- #define PRBUG 1
- #endif
-
- /*
- * PostScript command strings defined in the prologue file
- */
- #define BACKSPACE "B"
- #define ENDPAGE "EP"
- #define LINETO "L"
- #define MOVETO "M"
- #define NEWPATH "NP"
- #define SHOW "S"
- #define STARTPAGE "SP"
- #define STARTHPAGE "SHP"
- #define STARTLPAGE "SLP"
- #define STROKE "ST"
- #define TAB "T"
-
- /*
- * Conformance requires that no PostScript line exceed 256 characters
- */
- #define MAX_OUTPUT_LINE_LENGTH 256
-
- #define TEXTFONT "Courier"
- #define HEADERFONT "Times-Roman"
- #define HEADERPS 18 /* header page point size */
-
- #define PORTRAIT_START_Y 768 /* first row (Y coord) on each page */
- #define LANDSCAPE_START_Y 576
- #define START_X 25 /* position of start of each line */
- #define START_Y_HEADER 700 /* first row (Y coord) of header */
- #define THREE_HOLE_X 1.0 /* portrait x offset (inches) 3 hole */
- #define THREE_HOLE_Y 0.5 /* landscape y offset (inches) 3 hole */
-
- #define MAX_X 612
- #define MAX_Y 792
-
- #define SEP_CHAR '\001' /* pr column separator character */
-
- #define PS_EOF 04
-
- #define NPSIZES 6
- struct psize {
- int size; /* point size */
- double charsperinch; /* approx. char width, for Courier */
- int portrait_page_length; /* page length in lines */
- int portrait_cols; /* maximum # of chars per line */
- int landscape_page_length;
- int landscape_cols;
- } psize[NPSIZES] = {
- 7, 17.0, 108, 135, 80, 181,
- 8, 15.0, 94, 118, 70, 159,
- 9, 14.0, 84, 105, 62, 141,
- 10, 12.0, 75, 94, 56, 127,
- 11, 11.0, 68, 86, 51, 115,
- 12, 10.0, 62, 79, 46, 106
- };
-
- #define USAGE \
- "[-d] [-i#] [-l] [-m] [-olist] [-p[str]] [-r] [-s#] [-t#] [-v] [-S] [file ...]"
-
- long page_map[MAXPAGES]; /* offset of first byte of each page */
- int page_count;
-
- int lines_per_page;
- int columns;
- int point_size;
- int start_x, start_y;
- int ncopies;
-
- char bufin[BUFIN]; /* input buffer */
- char bufout[BUFOUT]; /* used for page reversal and output buffering */
-
- char *currentdate, *username;
- char hostname[32];
-
- int row;
- char *range;
- int tabstop;
- char *propts;
-
- int dflag, lflag, mflag, pflag, rflag, vflag, Sflag;
-
- char *strcpy();
- char *fgetline();
- char *sprintf();
-
- char *prologue;
- char *progname;
-
- char *version = "lwf V2.0 brachman@ubc.csnet 21-Feb-88";
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- register int i, j, first_file;
- char *pc;
- struct psize *p, *get_psize();
- double offset, atof();
- char *rindex();
- FILE *infile, *popen();
- double ceil();
-
- if ((pc = rindex(argv[0], '/')) != (char *) NULL)
- progname = pc + 1;
- else
- progname = argv[0];
- range = ":";
- propts = "";
- tabstop = DEFAULT_TAB_SIZE;
- page_count = 0;
- ncopies = 1;
- offset = 0.0;
- prologue = PROLOGUE;
- p = get_psize(DEFAULT_POINT_SIZE);
- rflag = REVERSE;
-
- for (i = 1; i < argc && argv[i][0] == '-'; i++) {
- switch (argv[i][1]) {
- case 'c':
- ncopies = atof(&argv[i][2]);
- if (ncopies <= 0) {
- fatal("number of copies must be > 0");
- /*NOTREACHED*/
- }
- break;
- case 'd':
- dflag = 1;
- break;
- case 'i':
- offset = atof(&argv[i][2]);
- if (offset < 0.0 || offset >= 8.5) {
- fatal("bad indent");
- /*NOTREACHED*/
- }
- break;
- case 'l':
- lflag = 1;
- break;
- case 'm':
- mflag = 1;
- break;
- case 'o':
- range = &argv[i][2];
- if (checkrange(range)) {
- fatal("bad range specification");
- /*NOTREACHED*/
- }
- break;
- case 'p':
- pflag = 1;
- propts = &argv[i][2];
- break;
- case 'P':
- if (++i == argc) {
- fatal("missing filename after -P");
- /*NOTREACHED*/
- }
- prologue = argv[i];
- break;
- case 'r':
- rflag = !rflag;
- break;
- case 's':
- j = atoi(&argv[i][2]);
- if ((p = get_psize(j)) == (struct psize *) NULL) {
- fatal("bad point size");
- /*NOTREACHED*/
- }
- break;
- case 't':
- tabstop = atoi(&argv[i][2]);
- if (tabstop < 1) {
- fatal("bad tabstop");
- /*NOTREACHED*/
- }
- break;
- case 'v':
- vflag = 1;
- break;
- case 'S':
- Sflag = 1;
- break;
- default:
- (void) fprintf(stderr, "Usage: %s %s\n", progname, USAGE);
- exit(1);
- }
- }
-
- /*
- * Check that all files are readable
- * This is so that no output at all is produced if any file is not
- * readable in case the output is being piped to a printer
- */
- for (j = i; j < argc; j++) {
- if (access(argv[j], R_OK) == -1) {
- fatal("cannot access %s", argv[j]);
- /*NOTREACHED*/
- }
- }
-
- point_size = p->size;
-
- if (lflag) {
- start_y = LANDSCAPE_START_Y;
- start_x = START_X + (int) (offset * 72.27);
- lines_per_page = p->landscape_page_length;
- columns = p->landscape_cols - (int) ceil(offset * p->charsperinch);
- if (mflag) {
- int nlines;
-
- nlines = (int) ceil((THREE_HOLE_Y * 72.27) / point_size);
- start_y -= (nlines * point_size);
- lines_per_page -= nlines;
- columns -= (int) ceil(THREE_HOLE_Y * p->charsperinch);
- }
- }
- else {
- start_y = PORTRAIT_START_Y;
- lines_per_page = p->portrait_page_length;
- start_x = START_X;
- if (mflag)
- offset += THREE_HOLE_X;
- start_x += (int) (offset * 72.27);
- columns = p->portrait_cols - (int) ceil(offset * p->charsperinch);
- }
- if (vflag) {
- (void) fprintf(stderr, "%s\n\n", version);
- (void) fprintf(stderr, "Lines/page = %d\n", lines_per_page);
- (void) fprintf(stderr, "Columns = %d\n", columns);
- (void) fprintf(stderr, "X-offset = %5.2f inches\n", offset);
- }
-
- setup();
- preamble();
-
- first_file = i;
-
- if (!rflag && Sflag)
- header(argc - first_file, argv + first_file);
-
- if (i == argc) { /* no files on command line */
- infile = stdin;
- if (pflag) {
- build_prcmd(bufin, "");
- if ((infile = popen(bufin, "r")) == (FILE *) NULL) {
- fatal("popen failed");
- /*NOTREACHED*/
- }
- }
- if (vflag)
- (void) fprintf(stderr, "printing stdin\n");
- print(infile);
- if (pflag)
- (void) pclose(infile);
- }
-
- /*
- * If page reversal is performed, process the file arguments right to left,
- * oth. left to right
- * If the correct flag is used for the printer the first file argument
- * will be on top in the printer's output tray when the paper is removed
- */
- if (rflag)
- j = argc - 1;
- else
- j = i;
- while (i < argc) {
- infile = stdin;
- if (pflag) {
- build_prcmd(bufin, argv[j]);
- if ((infile = popen(bufin, "r")) == (FILE *) NULL) {
- fatal("popen failed");
- /*NOTREACHED*/
- }
- }
- else {
- if (freopen(argv[j], "r", stdin) == (FILE *) NULL) {
- fatal("can't open %s", argv[j]);
- /*NOTREACHED*/
- }
- }
- if (vflag)
- (void) fprintf(stderr, "printing %s\n", argv[j]);
- print(infile);
- if (pflag)
- (void) pclose(infile);
- if (rflag)
- j--;
- else
- j++;
- i++;
- }
-
- if (rflag && Sflag)
- header(argc - first_file, argv + first_file);
-
- (void) printf("%%%%Trailer\n");
- (void) printf("%%%%Pages: %d\n", page_count);
- if (Sflag)
- (void) putc(PS_EOF, stdout);
-
- if (fflush(stdout) == EOF) {
- fatal("write error on stdout");
- /*NOTREACHED*/
- }
- exit(0);
- }
-
- /*
- * Return a pointer to the point size structure for the
- * specified point size
- */
- struct psize *
- get_psize(size)
- int size;
- {
- register int i;
-
- for (i = 0; i < NPSIZES; i++)
- if (psize[i].size == size)
- break;
- if (i == NPSIZES)
- return((struct psize *) NULL);
- return(&psize[i]);
- }
-
- /*
- * Initial lines sent to the LaserWriter
- * This stuff is sent to stdout since we don't want it to be reversed
- * Generates the PostScript header and includes the prologue file
- * There is limited checking for I/O errors here
- * When the standard prologue is being used we probably should verify
- * that it is the correct version (via %%BeginProcSet)
- */
- preamble()
- {
- FILE *fp;
-
- if ((fp = fopen(prologue, "r")) == (FILE *) NULL) {
- fatal("can't open prologue file `%s'", prologue);
- /*NOTREACHED*/
- }
-
- if (Sflag)
- (void) putc(PS_EOF, stdout);
-
- (void) printf("%%!PS-Adobe-2.0\n");
- (void) printf("%%%%Creator: %s on %s\n", progname, hostname);
- (void) printf("%%%%CreationDate: %s\n", currentdate);
- (void) printf("%%%%For: %s\n", username);
- (void) printf("%%%%DocumentFonts: %s", TEXTFONT);
- if (Sflag)
- (void) printf(" %s\n", HEADERFONT);
- else
- (void) printf("\n");
- (void) printf("%%%%Pages: (atend)\n");
-
- while (fgets(bufin, sizeof(bufin), fp) != (char *) NULL)
- fputs(bufin, stdout);
- (void) fclose(fp);
- if (ferror(stdout) || fflush(stdout) == EOF) {
- fatal("write error on stdout");
- /*NOTREACHED*/
- }
- }
-
- /*
- * Generate a command, in the specified buffer, to print the given file
- * according to the options in effect
- */
- build_prcmd(buf, file)
- char *buf, *file;
- {
-
- #ifdef SYSV
- (void) sprintf(buf, "%s -e%d -w%d -l%d -s%c %s %s",
- PR, tabstop, columns, lines_per_page, SEP_CHAR, propts, file);
- #else
- (void) sprintf(buf, "%s -w%d -l%d -s%c %s %s",
- PR, columns, lines_per_page, SEP_CHAR, propts, file);
- #endif
- if (vflag)
- (void) fprintf(stderr, "pr cmd: %s\n", buf);
- }
-
- /*
- * Print a file
- *
- * The input stream may be stdin, a file, or a pipe
- * If page reversal is being performed, the output goes to a temporary file and
- * then reverse() is called to do the page reversal to stdout
- */
- print(infile)
- FILE *infile;
- {
- register int eof, pagenum, r;
- register char *p;
- FILE *outfile;
- char *mktemp();
-
- if (rflag) {
- static char bigbuf[BUFOUT];
-
- page_map[0] = 0L;
- (void) sprintf(bufin, "/tmp/%sXXXXXX", progname);
- if (vflag)
- (void) fprintf(stderr, "temp will be: %s ... ", bufin);
- p = mktemp(bufin);
- if (vflag)
- (void) fprintf(stderr, "%s\n", p);
- if ((outfile = fopen(p, "w+")) == (FILE *) NULL) {
- (void) fprintf(stderr, "%s: can't create %s\n", progname, p);
- cleanup();
- /*NOTREACHED*/
- }
- setbuffer(outfile, bigbuf, sizeof(bigbuf));
- if (!dflag)
- (void) unlink(p);
- else
- (void) fprintf(stderr, "will not unlink %s\n", p);
- }
- else
- outfile = stdout;
-
- pagenum = 1;
- eof = 0;
- while (!eof) {
- row = start_y;
- if ((r = inrange(pagenum, range)) == -1) {
- cleanup();
- /*NOTREACHED*/
- }
- else if (r == 1)
- eof = printpage(infile, outfile);
- else if (r == 0)
- eof = flushpage(infile);
- else {
- fatal("bad inrange result");
- /*NOTREACHED*/
- }
- pagenum++;
- }
- if (row != start_y)
- endpage(outfile);
- if (vflag)
- (void) fprintf(stderr, "\n");
- if (fflush(outfile) == EOF) {
- fatal("write error while flushing output");
- /*NOTREACHED*/
- }
- if (rflag) {
- reverse(outfile);
- (void) fclose(outfile);
- }
- }
-
- /*
- * Process the next page
- * Return 1 on EOF, 0 oth.
- */
- printpage(infile, outfile)
- FILE *infile, *outfile;
- {
- register int lineno;
-
- if (ungetc(getc(infile), infile) == EOF)
- return(1);
-
- startpage(page_count + 1, outfile);
- for (lineno = 0; lineno < lines_per_page; lineno++) {
- if (fgetline(bufin, sizeof(bufin), infile) == (char *) NULL)
- return(1);
- if (bufin[0] == '\f')
- break;
- if (bufin[0] != '\0') {
- (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- proc(bufin, outfile);
- }
- row -= point_size;
- }
- endpage(outfile);
- return(0);
- }
-
- /*
- * The next page will not be printed; just consume the input and discard
- * Don't change xrow since we don't want an endpage()
- */
- flushpage(infile)
- FILE *infile;
- {
- register int lineno, xrow;
-
- xrow = row;
- for (lineno = 0; lineno < lines_per_page; lineno++) {
- if (fgetline(bufin, sizeof(bufin), infile) == (char *) NULL)
- return(1);
- if (bufin[0] == '\f')
- break;
- xrow -= point_size;
- }
- return(0);
- }
-
- /*
- * Start a new page
- */
- startpage(n, outfile)
- int n;
- FILE *outfile;
- {
-
- (void) fprintf(outfile, "%%%%Page: ? %d\n", n);
- (void) fprintf(outfile, "%d /%s %s\n",
- point_size, TEXTFONT, lflag ? STARTLPAGE : STARTPAGE);
- }
-
- /*
- * A page has been written to the temp file
- * Record the start of the next page
- * Terminate the page and indicate the start of the next
- */
- endpage(outfile)
- FILE *outfile;
- {
- long ftell();
-
- if (page_count == MAXPAGES) {
- fatal("pagelimit (%d) reached", MAXPAGES);
- /*NOTREACHED*/
- }
- (void) fprintf(outfile, "%d %s\n", ncopies, ENDPAGE);
- if (rflag) {
- if (fflush(outfile) == EOF) {
- fatal("write error while flushing page");
- /*NOTREACHED*/
- }
- page_map[++page_count] = ftell(outfile);
- }
- else
- page_count++;
- if (vflag)
- (void) fprintf(stderr, "x");
- }
-
- /*
- * Print the pages to stdout in reverse order
- * Assumes that the number of characters per page can be contained in an int
- */
- reverse(outfile)
- FILE *outfile;
- {
- register int i;
- int bytecount, nbytes;
- long lseek();
-
- if (vflag)
- (void) fprintf(stderr, "\nreversing %d page%s\n", page_count,
- page_count > 1 ? "s" : "");
- if (dflag) {
- for (i = 0; i <= page_count; i++)
- (void) fprintf(stderr, "[%ld]\n", page_map[i]);
- }
- for (i = page_count - 1; i >= 0; i--) {
- if (fseek(outfile, page_map[i], 0) == -1L) {
- fatal("seek error");
- /*NOTREACHED*/
- }
- nbytes = (int) (page_map[i + 1] - page_map[i]);
- while (nbytes > 0) {
- bytecount = min(nbytes, sizeof(bufout));
- if (fread(bufout, 1, bytecount, outfile) != bytecount) {
- fatal("read error while reversing pages");
- /*NOTREACHED*/
- }
- if (fwrite(bufout, 1, bytecount, stdout) != bytecount) {
- fatal("write error while reversing pages");
- /*NOTREACHED*/
- }
- nbytes -= bytecount;
- }
- }
- }
-
- /*
- * Process a line of input, escaping characters when necessary and handling
- * tabs
- *
- * The output is improved somewhat by coalescing consecutive tabs and
- * backspaces and eliminating tabs at the end of a line
- *
- * Overprinting (presumably most often used in underlining) can be far from
- * optimal; in particular the way nroff underlines by sequences like
- * "_\ba_\bb_\bc" creates a large volume of PostScript. This isn't too
- * serious since a lot of nroff underlining is unlikely.
- *
- * Since a newline is generated for each call there will be more
- * newlines in the output than is necessary
- */
- proc(in, outfile)
- char *in;
- FILE *outfile;
- {
- register int i;
- register char *last, *p, *q;
- int currentp, instr, tabc, tabto;
- char *savep;
- static int colskip, ncols;
- static int seen_sep = 0;
-
- currentp = 0;
- instr = 0;
- tabto = 0;
- last = bufout + MAX_OUTPUT_LINE_LENGTH - 20; /* subtract slop factor */
-
- q = bufout;
- *q = '\0';
- for (p = in; *p != '\0'; p++) {
- switch (*p) {
- case SEP_CHAR:
- /*
- * This assumes that the input buffer contains the entire line
- * oth. the column count will be off
- * Also, the input stream must be formatted into a constant number
- * of columns oth. it would be necessary to scan each line to
- * count SEP_CHARs (which is not hard but could be slow)
- */
- if (!seen_sep) { /* discern number of columns */
- seen_sep = 1;
- ncols = 2; /* there are at least two columns... */
- savep = p++;
- while (*p != '\0') {
- if (*p++ == SEP_CHAR)
- ncols++;
- }
- p = savep;
- colskip = columns / ncols;
- if (vflag)
- (void) fprintf(stderr, "Using %d columns\n", ncols);
- }
- if (instr) {
- (void) sprintf(q, ")%s ", SHOW);
- q += strlen(q);
- instr = 0;
- }
- tabto += (colskip - currentp);
- currentp = 0;
- break;
- case '\t':
- /*
- * Count the number of tabs that immediately follow the one we're
- * looking at
- */
- tabc = 0;
- while (*(p + 1) == '\t') {
- p++;
- tabc++;
- }
- if (currentp > 0) { /* not beginning of line */
- i = tabstop - (currentp % tabstop) + tabc * tabstop;
- if (instr) {
- (void) sprintf(q, ")%s ", SHOW);
- q += strlen(q);
- instr = 0;
- }
- }
- else
- i = (tabc + 1) * tabstop;
- tabto += i;
- currentp += i;
- break;
- case '\b':
- *q = '\0';
- (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- /* backspacing over tabs doesn't work... */
- if (tabto != 0) {
- fatal("attempt to backspace over a tab");
- /*NOTREACHED*/
- }
- p++;
- for (i = 1; *p == '\b'; p++)
- i++;
- if (currentp - i < 0) {
- fatal("too many backspaces");
- /*NOTREACHED*/
- }
- if (!instr) {
- fatal("bad backspacing");
- /*NOTREACHED*/
- }
- if (i == 1) /* frequent case gets special attention */
- (void) sprintf(bufout, "%s (", BACKSPACE);
- else
- (void) sprintf(bufout, "-%d %s (", i, TAB);
- currentp -= i;
- q = bufout + strlen(bufout);
- p--;
- break;
- case '\f':
- tabto = 0; /* optimizes */
- *q = '\0';
- if (instr)
- (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- else
- (void) fprintf(outfile, "%s\n", bufout);
- endpage(outfile);
- startpage(page_count + 1, outfile);
- row = start_y;
- (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- q = bufout;
- currentp = 0;
- instr = 0;
- break;
- case '\r':
- tabto = 0; /* optimizes */
- if (instr) {
- *q = '\0';
- (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- instr = 0;
- q = bufout;
- }
- (void) fprintf(outfile, "%d %d %s\n", start_x, row, MOVETO);
- currentp = 0;
- break;
- case '\\':
- case '(':
- case ')':
- if (!instr) {
- if (tabto) {
- (void) sprintf(q, "%d %s ", tabto, TAB);
- q += strlen(q);
- tabto = 0;
- }
- *q++ = '(';
- instr = 1;
- }
- *q++ = '\\';
- *q++ = *p;
- currentp++;
- break;
- default:
- /*
- * According to the PostScript Language Manual, PostScript files
- * can contain only "the printable subset of the ASCII character
- * set (plus the newline marker)".
- */
- if (!isascii(*p) || !isprint(*p)) {
- fatal("bad character in input");
- /*NOTREACHED*/
- }
- if (!instr) {
- if (tabto) {
- (void) sprintf(q, "%d %s ", tabto, TAB);
- q += strlen(q);
- tabto = 0;
- }
- *q++ = '(';
- instr = 1;
- }
- *q++ = *p;
- currentp++;
- break;
- }
- if (q >= last) {
- *q = '\0';
- if (instr)
- (void) fprintf(outfile, "%s)%s\n", bufout, SHOW);
- else
- (void) fprintf(outfile, "%s\n", bufout);
- q = bufout;
- instr = 0;
- }
- }
- if (instr) {
- (void) sprintf(q, ")%s", SHOW);
- q += strlen(q);
- }
- else
- *q = '\0';
- if (q >= last) {
- fatal("bufout overflow");
- /*NOTREACHED*/
- }
- if (bufout[0] != '\0')
- (void) fprintf(outfile, "%s\n", bufout);
- }
-
- /*
- * Find out who the user is, etc.
- * Possible system dependencies here...
- */
- setup()
- {
- int len;
- char *p;
- long t, time();
- int gethostname();
- char *ctime(), *getlogin(), *malloc();
- struct passwd *pw, *getpwuid();
-
- if ((p = getlogin()) == (char *) NULL) {
- if ((pw = getpwuid(getuid())) == (struct passwd *) NULL)
- p = "Whoknows";
- else
- p = pw->pw_name;
- endpwent();
- }
- username = (char *) malloc((unsigned) (strlen(p) + 1));
- (void) strcpy(username, p);
-
- #ifdef HOSTNAME
- (void) strncpy(hostname, HOSTNAME, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = '\0';
- #else
- (void) gethostname(hostname, sizeof(hostname));
- #endif
-
- t = time((long *) 0);
- p = ctime(&t);
- len = strlen(p);
- *(p + len - 1) = '\0'; /* zap the newline character */
- currentdate = (char *) malloc((unsigned) len);
- (void) strcpy(currentdate, p);
- }
-
- /*
- * Print a header page
- * Assumes setup() has already been called to fill in the user, host, etc.
- * Uses HEADERFONT in HEADERPS point
- */
- header(nfiles, files)
- int nfiles;
- char **files;
- {
- register int i;
- register char *p;
-
- if (vflag) {
- (void) fprintf(stderr, "printing header\n");
- (void) fprintf(stderr, "%d file%s are:\n", nfiles,
- nfiles > 1 ? "s" : "");
- if (nfiles == 0)
- (void) fprintf(stderr, "\tstdin\n");
- for (i = 0; i < nfiles; i++)
- (void) fprintf(stderr, "\t%s\n", files[i]);
- }
-
- (void) fprintf(stdout, "%%%%Page: ? %d\n", ++page_count);
- (void) fprintf(stdout, "%d /%s %s\n", HEADERPS, HEADERFONT, STARTHPAGE);
-
- /*
- * The header sheet looks like:
- *
- * ----------------------------
- * ----------------------------
- *
- * User:
- * Host:
- * Date:
- * Files:
- *
- * ----------------------------
- * ----------------------------
- */
- row = START_Y_HEADER;
- (void) printf("%s %d %d %s\n", NEWPATH, START_X, row, MOVETO);
- (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- row -= 6;
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- row -= 24;
- (void) printf("%s\n", STROKE);
-
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) sprintf(bufin, "User: %s", username);
- proc(bufin, stdout);
- row -= 24;
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) sprintf(bufin, "Host: %s", hostname);
- proc(bufin, stdout);
- row -= 24;
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) sprintf(bufin, "Date: %s", currentdate);
- proc(bufin, stdout);
- row -= 24;
-
- if (nfiles == 0) {
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) sprintf(bufin, "File: <stdin>");
- proc(bufin, stdout);
- }
- else {
- register int len, max, sum;
-
- /*
- * If the list of files is "too long" we'll only print as many as
- * possible
- * Arbitrary chop off point is 50 characters
- * (assume bufin is bigger than this)
- */
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) sprintf(bufin, "File%s: ", nfiles > 1 ? "s" : "");
- p = bufin + (sum = strlen(bufin));
- max = 50;
- for (i = 0; i < nfiles - 1; i++) {
- sum += (len = strlen(files[i]) + 1);
- if (sum >= max)
- break;
- (void) sprintf(p, "%s,", files[i]);
- p += len;
- }
- sum += (len = strlen(files[i]) + 1);
- if (sum < max)
- (void) sprintf(p, "%s", files[i]);
- else
- (void) strcpy(p, "...");
- proc(bufin, stdout);
- }
-
- row -= 12;
- (void) printf("%s %d %d %s\n", NEWPATH, START_X, row, MOVETO);
- (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- row -= 6;
- (void) printf("%d %d %s\n", START_X, row, MOVETO);
- (void) printf("%d %d %s\n", START_X + 400, row, LINETO);
- (void) printf("%s\n", STROKE);
- (void) printf("1 %s\n", ENDPAGE);
- if (fflush(stdout) == EOF) {
- fatal("write error on stdout");
- /*NOTREACHED*/
- }
- }
-
- /*
- * Special version of fgets
- * Read until a formfeed, newline, or overflow
- * If a formfeed is the first character, return it immediately
- * If a formfeed is found after the first character, replace it by a newline
- * and push the formfeed back onto the input stream
- * A special case is a formfeed followed by a newline in which case the
- * newline is ignored
- * The input buffer will be null-terminated and will *not* end with a newline
- * The buffer size n includes the null
- */
- char *
- fgetline(s, n, iop)
- char *s;
- int n;
- register FILE *iop;
- {
- register int ch;
- register char *cs;
-
- if (n < 2) {
- fatal("fgetline called with bad buffer size!?");
- /*NOTREACHED*/
- }
-
- cs = s;
- n--; /* the null */
-
- /*
- * Check out the special cases
- */
- if ((ch = getc(iop)) == EOF)
- return((char *) NULL);
- if (ch == '\f') {
- #ifdef PRBUG
- if (pflag) {
- /*
- * Filter out the formfeeds
- */
- do {
- if (ch == '\f')
- continue;
- if (ch == '\n')
- break;
- *cs++ = ch;
- n--;
- } while (n > 0 && (ch = getc(iop)) != EOF);
- if (ch == EOF) {
- if (ungetc(ch, iop) == EOF && !feof(iop)) {
- /* Shouldn't happen since a getc() was just done */
- fatal("fgetline - ungetc failed");
- /*NOTREACHED*/
- }
- }
- else if (ch != '\n') {
- fatal("fgetline - input line too long");
- /*NOTREACHED*/
- }
- *cs = '\0';
- return(s);
- }
- #endif
- if ((ch = getc(iop)) != '\n') {
- /*
- * If EOF was just read it will be noticed next time through
- */
- if (ungetc(ch, iop) == EOF && !feof(iop)) {
- /* Shouldn't happen since a getc() was just done */
- fatal("fgetline - ungetc failed");
- /*NOTREACHED*/
- }
- }
- *cs++ = '\f';
- *cs = '\0';
- return(s);
- }
-
- /*
- * Check for "weird" input characters is made in proc()
- */
- while (n-- > 0) {
- if (ch == '\f' || ch == '\n')
- break;
- *cs++ = ch;
- if ((ch = getc(iop)) == EOF)
- break;
- }
-
- if (ch == EOF && cs == s) /* Nothing was read */
- return((char *) NULL);
- if (ch == '\f') {
- if (ungetc(ch, iop) == EOF)
- (void) fprintf(stderr, "fgetline - can't ungetc??\n");
- }
- else if (ch != '\n' && ch != EOF) {
- fatal("fgetline - input line too long");
- /*NOTREACHED*/
- }
- *cs = '\0';
- return(s);
- }
-
- /*VARARGS*/
- fatal(s, a, b, c, d, e, f, g, h, i, j)
- char *s;
- {
-
- (void) fprintf(stderr, "%s: ", progname);
- (void) fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j);
- (void) fprintf(stderr, "\n");
- cleanup();
- /*NOTREACHED*/
- }
-
- /*
- * Clean up and exit after an error
- */
- cleanup()
- {
-
- exit(1);
- }
-
-