17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23f928ce67Sceastha  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24f928ce67Sceastha  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27f928ce67Sceastha /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28f928ce67Sceastha /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * postprint - PostScript translator for ASCII files.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * A simple program that translates ASCII files into PostScript. All it really
357c478bd9Sstevel@tonic-gate  * does is expand tabs and backspaces, handle character quoting, print text lines,
367c478bd9Sstevel@tonic-gate  * and control when pages are started based on the requested number of lines per
377c478bd9Sstevel@tonic-gate  * page.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * The PostScript prologue is copied from *prologue before any of the input files
407c478bd9Sstevel@tonic-gate  * are translated. The program expects that the following procedures are defined
417c478bd9Sstevel@tonic-gate  * in that file:
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  *	setup
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  *	  mark ... setup -
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *	    Handles special initialization stuff that depends on how the program
487c478bd9Sstevel@tonic-gate  *	    was called. Expects to find a mark followed by key/value pairs on the
497c478bd9Sstevel@tonic-gate  *	    stack. The def operator is applied to each pair up to the mark, then
507c478bd9Sstevel@tonic-gate  *	    the default state is set up.
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  *	pagesetup
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  *	  page pagesetup -
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  *	    Does whatever is needed to set things up for the next page. Expects
577c478bd9Sstevel@tonic-gate  *	    to find the current page number on the stack.
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  *	l
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  *	  string l -
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  *	    Prints string starting in the first column and then goes to the next
647c478bd9Sstevel@tonic-gate  *	    line.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  *	L
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  *	  mark string column string column ... L mark
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  *	    Prints each string on the stack starting at the horizontal position
717c478bd9Sstevel@tonic-gate  *	    selected by column. Used when tabs and spaces can be sufficiently well
727c478bd9Sstevel@tonic-gate  *	    compressed to make the printer overhead worthwhile. Always used when
737c478bd9Sstevel@tonic-gate  *	    we have to back up.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  *	done
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  *	  done
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  *	    Makes sure the last page is printed. Only needed when we're printing
807c478bd9Sstevel@tonic-gate  *	    more than one page on each sheet of paper.
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  * Almost everything has been changed in this version of postprint. The program
837c478bd9Sstevel@tonic-gate  * is more intelligent, especially about tabs, spaces, and backspacing, and as a
847c478bd9Sstevel@tonic-gate  * result output files usually print faster. Output files also now conform to
857c478bd9Sstevel@tonic-gate  * Adobe's file structuring conventions, which is undoubtedly something I should
867c478bd9Sstevel@tonic-gate  * have done in the first version of the program. If the number of lines per page
877c478bd9Sstevel@tonic-gate  * is set to 0, which can be done using the -l option, pointsize will be used to
887c478bd9Sstevel@tonic-gate  * guess a reasonable value. The estimate is based on the values of LINESPP,
897c478bd9Sstevel@tonic-gate  * POINTSIZE, and pointsize, and assumes LINESPP lines would fit on a page if
907c478bd9Sstevel@tonic-gate  * we printed in size POINTSIZE. Selecting a point size using the -s option and
917c478bd9Sstevel@tonic-gate  * adding -l0 to the command line forces the guess to be made.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * Many default values, like the magnification and orientation, are defined in
947c478bd9Sstevel@tonic-gate  * the prologue, which is where they belong. If they're changed (by options), an
957c478bd9Sstevel@tonic-gate  * appropriate definition is made after the prologue is added to the output file.
967c478bd9Sstevel@tonic-gate  * The -P option passes arbitrary PostScript through to the output file. Among
977c478bd9Sstevel@tonic-gate  * other things it can be used to set (or change) values that can't be accessed by
987c478bd9Sstevel@tonic-gate  * other options.
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #include <stdio.h>
1047c478bd9Sstevel@tonic-gate #include <signal.h>
1057c478bd9Sstevel@tonic-gate #include <ctype.h>
1067c478bd9Sstevel@tonic-gate #include <fcntl.h>
1077c478bd9Sstevel@tonic-gate #include <unistd.h>
108*e4fb8a5fSToomas Soome #include <string.h>
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #include "comments.h"			/* PostScript file structuring comments */
1117c478bd9Sstevel@tonic-gate #include "gen.h"			/* general purpose definitions */
1127c478bd9Sstevel@tonic-gate #include "path.h"			/* for the prologue */
1137c478bd9Sstevel@tonic-gate #include "ext.h"			/* external variable declarations */
1147c478bd9Sstevel@tonic-gate #include "postprint.h"			/* a few special definitions */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate char	*optnames = "a:c:e:f:l:m:n:o:p:r:s:t:x:y:A:C:J:L:P:R:DI";
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate char	*prologue = POSTPRINT;		/* default PostScript prologue */
1207c478bd9Sstevel@tonic-gate char	*formfile = FORMFILE;		/* stuff for multiple pages per sheet */
1217c478bd9Sstevel@tonic-gate char	*locale = NULL;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate int	formsperpage = 1;		/* page images on each piece of paper */
1247c478bd9Sstevel@tonic-gate int	copies = 1;			/* and this many copies of each sheet */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate int	linespp = LINESPP;		/* number of lines per page */
1277c478bd9Sstevel@tonic-gate int	pointsize = POINTSIZE;		/* in this point size */
1287c478bd9Sstevel@tonic-gate int	tabstops = TABSTOPS;		/* tabs set at these columns */
1297c478bd9Sstevel@tonic-gate int	crmode = 0;			/* carriage return mode - 0, 1, or 2 */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate int	col = 1;			/* next character goes in this column */
1327c478bd9Sstevel@tonic-gate int	line = 1;			/* on this line */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate int	stringcount = 0;		/* number of strings on the stack */
1357c478bd9Sstevel@tonic-gate int	stringstart = 1;		/* column where current one starts */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate Fontmap	fontmap[] = FONTMAP;		/* for translating font names */
1387c478bd9Sstevel@tonic-gate char	*fontname = "Courier";		/* use this PostScript font */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate int	page = 0;			/* page we're working on */
1417c478bd9Sstevel@tonic-gate int	printed = 0;			/* printed this many pages */
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate FILE	*fp_in = stdin;			/* read from this file */
1447c478bd9Sstevel@tonic-gate FILE	*fp_out = stdout;		/* and write stuff here */
1457c478bd9Sstevel@tonic-gate FILE	*fp_acct = NULL;		/* for accounting data */
1467c478bd9Sstevel@tonic-gate 
147f928ce67Sceastha static void account(void);
148f928ce67Sceastha static void arguments(void);
149f928ce67Sceastha static void done(void);
150f928ce67Sceastha static void endline(void);
151f928ce67Sceastha static void formfeed(void);
152f928ce67Sceastha static void header(void);
153f928ce67Sceastha static void init_signals(void);
154f928ce67Sceastha static void newline(void);
155f928ce67Sceastha static void options(void);
156f928ce67Sceastha static void oput(int);
157f928ce67Sceastha static void redirect(int);
158f928ce67Sceastha static void setup(void);
159f928ce67Sceastha static void spaces(int);
160f928ce67Sceastha static void startline(void);
161f928ce67Sceastha static void text(void);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /*****************************************************************************/
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
166f928ce67Sceastha int
main(int agc,char * agv[])167f928ce67Sceastha main(int agc, char *agv[])
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  *
1727c478bd9Sstevel@tonic-gate  * A simple program that translates ASCII files into PostScript. If there's more
1737c478bd9Sstevel@tonic-gate  * than one input file, each begins on a new page.
1747c478bd9Sstevel@tonic-gate  *
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate     argc = agc;				/* other routines may want them */
1797c478bd9Sstevel@tonic-gate     argv = agv;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate     prog_name = argv[0];		/* really just for error messages */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     init_signals();			/* sets up interrupt handling */
1847c478bd9Sstevel@tonic-gate     header();				/* PostScript header and prologue */
1857c478bd9Sstevel@tonic-gate     setup();				/* for PostScript */
1867c478bd9Sstevel@tonic-gate     arguments();			/* followed by each input file */
1877c478bd9Sstevel@tonic-gate     done();				/* print the last page etc. */
1887c478bd9Sstevel@tonic-gate     account();				/* job accounting data */
1897c478bd9Sstevel@tonic-gate 
190f928ce67Sceastha     return (x_stat);			/* not much could be wrong */
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate }   /* End of main */
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*****************************************************************************/
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 
198f928ce67Sceastha static void
init_signals(void)199f928ce67Sceastha init_signals(void)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate     void	interrupt();		/* signal handler */
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  * Makes sure we handle interrupts.
2067c478bd9Sstevel@tonic-gate  *
2077c478bd9Sstevel@tonic-gate  */
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     if ( signal(SIGINT, interrupt) == SIG_IGN )  {
2117c478bd9Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
2127c478bd9Sstevel@tonic-gate 	signal(SIGQUIT, SIG_IGN);
2137c478bd9Sstevel@tonic-gate 	signal(SIGHUP, SIG_IGN);
2147c478bd9Sstevel@tonic-gate     } else {
2157c478bd9Sstevel@tonic-gate 	signal(SIGHUP, interrupt);
2167c478bd9Sstevel@tonic-gate 	signal(SIGQUIT, interrupt);
2177c478bd9Sstevel@tonic-gate     }   /* End else */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate     signal(SIGTERM, interrupt);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate }   /* End of init_signals */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*****************************************************************************/
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 
227f928ce67Sceastha static void
header(void)228f928ce67Sceastha header(void)
2297c478bd9Sstevel@tonic-gate {
2307c478bd9Sstevel@tonic-gate     int		ch;			/* return value from getopt() */
2317c478bd9Sstevel@tonic-gate     int		old_optind = optind;	/* for restoring optind - should be 1 */
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate /*
2347c478bd9Sstevel@tonic-gate  *
2357c478bd9Sstevel@tonic-gate  * Scans the option list looking for things, like the prologue file, that we need
2367c478bd9Sstevel@tonic-gate  * right away but could be changed from the default. Doing things this way is an
2377c478bd9Sstevel@tonic-gate  * attempt to conform to Adobe's latest file structuring conventions. In particular
2387c478bd9Sstevel@tonic-gate  * they now say there should be nothing executed in the prologue, and they have
2397c478bd9Sstevel@tonic-gate  * added two new comments that delimit global initialization calls. Once we know
2407c478bd9Sstevel@tonic-gate  * where things really are we write out the job header, follow it by the prologue,
2417c478bd9Sstevel@tonic-gate  * and then add the ENDPROLOG and BEGINSETUP comments.
2427c478bd9Sstevel@tonic-gate  *
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate     while ( (ch = getopt(argc, argv, optnames)) != EOF )
2477c478bd9Sstevel@tonic-gate 	if ( ch == 'L' )
2487c478bd9Sstevel@tonic-gate 	    prologue = optarg;
2497c478bd9Sstevel@tonic-gate 	else if ( ch == '?' )
2507c478bd9Sstevel@tonic-gate 	    error(FATAL, "");
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate     optind = old_optind;		/* get ready for option scanning */
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", CONFORMING);
2557c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %s\n", CREATOR, "%M%");
2567c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %s\n", VERSION, "%I%");
2577c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
2587c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %s\n", PAGES, ATEND);
2597c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", ENDCOMMENTS);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate     options();				/* handle the command line options */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate     if ( cat(prologue) == FALSE )
2647c478bd9Sstevel@tonic-gate 	error(FATAL, "can't read %s", prologue);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", ENDPROLOG);
2677c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", BEGINSETUP);
2687c478bd9Sstevel@tonic-gate     fprintf(stdout, "mark\n");
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate }   /* End of header */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*****************************************************************************/
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 
276f928ce67Sceastha static void
options(void)277f928ce67Sceastha options(void)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate     int		ch;			/* return value from getopt() */
2807c478bd9Sstevel@tonic-gate     int		euro = 0;
2817c478bd9Sstevel@tonic-gate     extern char *getenv(char *);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  *
2867c478bd9Sstevel@tonic-gate  * Reads and processes the command line options. Added the -P option so arbitrary
2877c478bd9Sstevel@tonic-gate  * PostScript code can be passed through. Expect it could be useful for changing
2887c478bd9Sstevel@tonic-gate  * definitions in the prologue for which options have not been defined.
2897c478bd9Sstevel@tonic-gate  *
2907c478bd9Sstevel@tonic-gate  * Although any PostScript font can be used, things will only work well for
2917c478bd9Sstevel@tonic-gate  * constant width fonts.
2927c478bd9Sstevel@tonic-gate  *
2937c478bd9Sstevel@tonic-gate  */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     if  (((locale = getenv("LC_MONETARY")) != NULL) ||
2967c478bd9Sstevel@tonic-gate          ((locale = getenv("LANG")) != NULL)) {
2977c478bd9Sstevel@tonic-gate         char *tmp = NULL;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate         /* if there is a locale specific prologue, use it as the default */
3007c478bd9Sstevel@tonic-gate         if ((tmp = calloc(1, strlen(POSTPRINT) + strlen(locale) + 2)) != NULL) {
3017c478bd9Sstevel@tonic-gate             sprintf(tmp, "%s-%s", POSTPRINT, locale);
3027c478bd9Sstevel@tonic-gate             if (access(tmp, R_OK) == 0)
3037c478bd9Sstevel@tonic-gate                     prologue = tmp;
3047c478bd9Sstevel@tonic-gate             else
3057c478bd9Sstevel@tonic-gate                     free(tmp);
3067c478bd9Sstevel@tonic-gate         }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate         /* if the locale has 8859-15 or euro in it, add the symbol to font */
3097c478bd9Sstevel@tonic-gate         if ((strstr(locale, "8859-15") != NULL) ||
3107c478bd9Sstevel@tonic-gate 	    (strstr(locale, "euro") != NULL))
3117c478bd9Sstevel@tonic-gate 		euro = 1;
3127c478bd9Sstevel@tonic-gate     }
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate     while ( (ch = getopt(argc, argv, optnames)) != EOF )  {
3157c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3167c478bd9Sstevel@tonic-gate 	fprintf(stderr, " Opt: %c, arg: %s\n", ch, optarg);
3177c478bd9Sstevel@tonic-gate #endif
3187c478bd9Sstevel@tonic-gate 	switch ( ch )  {
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	    case 'a':			/* aspect ratio */
3217c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/aspectratio %s def\n", optarg);
3227c478bd9Sstevel@tonic-gate 		    break;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	    case 'c':			/* copies */
3257c478bd9Sstevel@tonic-gate 		    copies = atoi(optarg);
3267c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/#copies %s store\n", optarg);
3277c478bd9Sstevel@tonic-gate 		    break;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	    case 'e':			/* should we add the euro ? */
3307c478bd9Sstevel@tonic-gate 		    euro = (strcasecmp(optarg, "on") == 0);
3317c478bd9Sstevel@tonic-gate 		    break;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	    case 'f':			/* use this PostScript font */
3347c478bd9Sstevel@tonic-gate 		    fontname = get_font(optarg);
3357c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/font /%s def\n", fontname);
3367c478bd9Sstevel@tonic-gate 		    break;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	    case 'l':			/* lines per page */
3397c478bd9Sstevel@tonic-gate 		    linespp = atoi(optarg);
3407c478bd9Sstevel@tonic-gate 		    break;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	    case 'm':			/* magnification */
3437c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/magnification %s def\n", optarg);
3447c478bd9Sstevel@tonic-gate 		    break;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	    case 'n':			/* forms per page */
3477c478bd9Sstevel@tonic-gate 		    formsperpage = atoi(optarg);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		    if (formsperpage <= 0) {
3507c478bd9Sstevel@tonic-gate 			/* set default value */
3517c478bd9Sstevel@tonic-gate 			formsperpage = 1;
3527c478bd9Sstevel@tonic-gate 		    }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/formsperpage %d def\n", formsperpage);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		    break;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	    case 'o':			/* output page list */
3597c478bd9Sstevel@tonic-gate 		    out_list(optarg);
3607c478bd9Sstevel@tonic-gate 		    break;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	    case 'p':			/* landscape or portrait mode */
3637c478bd9Sstevel@tonic-gate 		    if ( *optarg == 'l' )
3647c478bd9Sstevel@tonic-gate 			fprintf(stdout, "/landscape true def\n");
3657c478bd9Sstevel@tonic-gate 		    else fprintf(stdout, "/landscape false def\n");
3667c478bd9Sstevel@tonic-gate 		    break;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	    case 'r':			/* carriage return mode */
3697c478bd9Sstevel@tonic-gate 		    crmode = atoi(optarg);
3707c478bd9Sstevel@tonic-gate 		    break;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	    case 's':			/* point size */
3737c478bd9Sstevel@tonic-gate 		    pointsize = atoi(optarg);
3747c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/pointsize %s def\n", optarg);
3757c478bd9Sstevel@tonic-gate 		    break;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	    case 't':			/* tabstops */
3787c478bd9Sstevel@tonic-gate 		    tabstops = atoi(optarg);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		    if (tabstops <= 0) {
3817c478bd9Sstevel@tonic-gate 			/* set default */
3827c478bd9Sstevel@tonic-gate 			tabstops = TABSTOPS;
3837c478bd9Sstevel@tonic-gate 		    }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		    break;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	    case 'x':			/* shift things horizontally */
3887c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/xoffset %s def\n", optarg);
3897c478bd9Sstevel@tonic-gate 		    break;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	    case 'y':			/* and vertically on the page */
3927c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "/yoffset %s def\n", optarg);
3937c478bd9Sstevel@tonic-gate 		    break;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	    case 'A':			/* force job accounting */
3967c478bd9Sstevel@tonic-gate 	    case 'J':
3977c478bd9Sstevel@tonic-gate 		    if ( (fp_acct = fopen(optarg, "a")) == NULL )
3987c478bd9Sstevel@tonic-gate 			error(FATAL, "can't open accounting file %s", optarg);
3997c478bd9Sstevel@tonic-gate 		    break;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	    case 'C':			/* copy file straight to output */
4027c478bd9Sstevel@tonic-gate 		    if ( cat(optarg) == FALSE )
4037c478bd9Sstevel@tonic-gate 			error(FATAL, "can't read %s", optarg);
4047c478bd9Sstevel@tonic-gate 		    break;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	    case 'L':			/* PostScript prologue file */
4077c478bd9Sstevel@tonic-gate 		    prologue = optarg;
4087c478bd9Sstevel@tonic-gate 		    break;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	    case 'P':			/* PostScript pass through */
4117c478bd9Sstevel@tonic-gate 		    fprintf(stdout, "%s\n", optarg);
4127c478bd9Sstevel@tonic-gate 		    break;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	    case 'R':			/* special global or page level request */
4157c478bd9Sstevel@tonic-gate 		    saverequest(optarg);
4167c478bd9Sstevel@tonic-gate 		    break;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	    case 'D':			/* debug flag */
4197c478bd9Sstevel@tonic-gate 		    debug = ON;
4207c478bd9Sstevel@tonic-gate 		    break;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	    case 'I':			/* ignore FATAL errors */
4237c478bd9Sstevel@tonic-gate 		    ignore = ON;
4247c478bd9Sstevel@tonic-gate 		    break;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	    case '?':			/* don't understand the option */
4277c478bd9Sstevel@tonic-gate 		    error(FATAL, "");
4287c478bd9Sstevel@tonic-gate 		    break;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	    default:			/* don't know what to do for ch */
4317c478bd9Sstevel@tonic-gate 		    error(FATAL, "missing case for option %c\n", ch);
4327c478bd9Sstevel@tonic-gate 		    break;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	}   /* End switch */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate     }   /* End while */
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate     if (euro != 0)
4397c478bd9Sstevel@tonic-gate 	fprintf(stdout, "/must-add-euro-to-font true def\n");
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate     argc -= optind;			/* get ready for non-option args */
4427c478bd9Sstevel@tonic-gate     argv += optind;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate }   /* End of options */
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*****************************************************************************/
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 
get_font(name)4507c478bd9Sstevel@tonic-gate char *get_font(name)
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate     char	*name;			/* name the user asked for */
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate     int		i;			/* for looking through fontmap[] */
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate  *
4647c478bd9Sstevel@tonic-gate  * Called from options() to map a user's font name into a legal PostScript name.
4657c478bd9Sstevel@tonic-gate  * If the lookup fails *name is returned to the caller. That should let you choose
4667c478bd9Sstevel@tonic-gate  * any PostScript font, although things will only work well for constant width
4677c478bd9Sstevel@tonic-gate  * fonts.
4687c478bd9Sstevel@tonic-gate  *
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate     for ( i = 0; fontmap[i].name != NULL; i++ )
4737c478bd9Sstevel@tonic-gate 	if ( strcmp(name, fontmap[i].name) == 0 )
4747c478bd9Sstevel@tonic-gate 	    return(fontmap[i].val);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate     return(name);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate }   /* End of get_font */
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*****************************************************************************/
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 
484f928ce67Sceastha static void
setup(void)485f928ce67Sceastha setup(void)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate  *
4907c478bd9Sstevel@tonic-gate  * Handles things that must be done after the options are read but before the
4917c478bd9Sstevel@tonic-gate  * input files are processed. linespp (lines per page) can be set using the -l
4927c478bd9Sstevel@tonic-gate  * option. If it's not positive we calculate a reasonable value using the
4937c478bd9Sstevel@tonic-gate  * requested point size - assuming LINESPP lines fit on a page in point size
4947c478bd9Sstevel@tonic-gate  * POINTSIZE.
4957c478bd9Sstevel@tonic-gate  *
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate     writerequest(0, stdout);		/* global requests eg. manual feed */
4997c478bd9Sstevel@tonic-gate     fprintf(stdout, "setup\n");
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate     if ( formsperpage > 1 )  {
5027c478bd9Sstevel@tonic-gate 	if ( cat(formfile) == FALSE )
5037c478bd9Sstevel@tonic-gate 	    error(FATAL, "can't read %s", formfile);
5047c478bd9Sstevel@tonic-gate 	fprintf(stdout, "%d setupforms\n", formsperpage);
5057c478bd9Sstevel@tonic-gate     }	/* End if */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", ENDSETUP);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate     if ( linespp <= 0 )
5107c478bd9Sstevel@tonic-gate 	linespp = LINESPP * POINTSIZE / pointsize;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate }   /* End of setup */
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /*****************************************************************************/
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 
518f928ce67Sceastha static void
arguments(void)519f928ce67Sceastha arguments(void)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  *
5247c478bd9Sstevel@tonic-gate  * Makes sure all the non-option command line arguments are processed. If we get
5257c478bd9Sstevel@tonic-gate  * here and there aren't any arguments left, or if '-' is one of the input files
5267c478bd9Sstevel@tonic-gate  * we'll translate stdin.
5277c478bd9Sstevel@tonic-gate  *
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate     if ( argc < 1 )
5317c478bd9Sstevel@tonic-gate 	text();
5327c478bd9Sstevel@tonic-gate     else {				/* at least one argument is left */
5337c478bd9Sstevel@tonic-gate 	while ( argc > 0 )  {
5347c478bd9Sstevel@tonic-gate 	    if ( strcmp(*argv, "-") == 0 )
5357c478bd9Sstevel@tonic-gate 		fp_in = stdin;
5367c478bd9Sstevel@tonic-gate 	    else if ( (fp_in = fopen(*argv, "r")) == NULL )
5377c478bd9Sstevel@tonic-gate 		error(FATAL, "can't open %s", *argv);
5387c478bd9Sstevel@tonic-gate 	    text();
5397c478bd9Sstevel@tonic-gate 	    if ( fp_in != stdin )
5407c478bd9Sstevel@tonic-gate 		fclose(fp_in);
5417c478bd9Sstevel@tonic-gate 	    argc--;
5427c478bd9Sstevel@tonic-gate 	    argv++;
5437c478bd9Sstevel@tonic-gate 	}   /* End while */
5447c478bd9Sstevel@tonic-gate     }   /* End else */
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate }   /* End of arguments */
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate /*****************************************************************************/
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 
552f928ce67Sceastha static void
done(void)553f928ce67Sceastha done(void)
5547c478bd9Sstevel@tonic-gate {
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate  *
5587c478bd9Sstevel@tonic-gate  * Finished with all the input files, so mark the end of the pages with a TRAILER
5597c478bd9Sstevel@tonic-gate  * comment, make sure the last page prints, and add things like the PAGES comment
5607c478bd9Sstevel@tonic-gate  * that can only be determined after all the input files have been read.
5617c478bd9Sstevel@tonic-gate  *
5627c478bd9Sstevel@tonic-gate  */
5637c478bd9Sstevel@tonic-gate     if (printed % formsperpage != 0) {	/* pad to ENDPAGE */
5647c478bd9Sstevel@tonic-gate 	while (printed % formsperpage) {
5657c478bd9Sstevel@tonic-gate 	    printed++;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "save\n");
5687c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "mark\n");
5697c478bd9Sstevel@tonic-gate 	    writerequest(printed, stdout);
5707c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "%d pagesetup\n", printed);
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "cleartomark\n");
5737c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "showpage\n");
5747c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "restore\n");
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 	fprintf(stdout, "%s %d %d\n", ENDPAGE, page, printed);
5777c478bd9Sstevel@tonic-gate     }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s", TRAILER);
5807c478bd9Sstevel@tonic-gate     fprintf(stdout, "done\n");
5817c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
5827c478bd9Sstevel@tonic-gate     fprintf(stdout, "%s %d\n", PAGES, printed);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate }   /* End of done */
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*****************************************************************************/
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 
590f928ce67Sceastha static void
account(void)591f928ce67Sceastha account(void)
5927c478bd9Sstevel@tonic-gate {
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate /*
5957c478bd9Sstevel@tonic-gate  *
5967c478bd9Sstevel@tonic-gate  * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
5977c478bd9Sstevel@tonic-gate  * requested using the -A or -J options.
5987c478bd9Sstevel@tonic-gate  *
5997c478bd9Sstevel@tonic-gate  */
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate     if ( fp_acct != NULL )
6027c478bd9Sstevel@tonic-gate 	fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate }   /* End of account */
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate /*****************************************************************************/
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 
610f928ce67Sceastha static void
text(void)611f928ce67Sceastha text(void)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate     int		ch;			/* next input character */
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  *
6177c478bd9Sstevel@tonic-gate  * Translates *fp_in into PostScript. All we do here is handle newlines, tabs,
6187c478bd9Sstevel@tonic-gate  * backspaces, and quoting of special characters. All other unprintable characters
6197c478bd9Sstevel@tonic-gate  * are totally ignored. The redirect(-1) call forces the initial output to go to
6207c478bd9Sstevel@tonic-gate  * /dev/null. It's done to force the stuff that formfeed() does at the end of
6217c478bd9Sstevel@tonic-gate  * each page to /dev/null rather than the real output file.
6227c478bd9Sstevel@tonic-gate  *
6237c478bd9Sstevel@tonic-gate  */
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate     redirect(-1);			/* get ready for the first page */
6277c478bd9Sstevel@tonic-gate     formfeed();				/* force PAGE comment etc. */
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate     while ( (ch = getc(fp_in)) != EOF )
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	switch ( ch )  {
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	    case '\n':
6347c478bd9Sstevel@tonic-gate 		    newline();
6357c478bd9Sstevel@tonic-gate 		    break;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	    case '\t':
6387c478bd9Sstevel@tonic-gate 	    case '\b':
6397c478bd9Sstevel@tonic-gate 	    case ' ':
6407c478bd9Sstevel@tonic-gate 		    spaces(ch);
6417c478bd9Sstevel@tonic-gate 		    break;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	    case '\014':
6447c478bd9Sstevel@tonic-gate 		    formfeed();
6457c478bd9Sstevel@tonic-gate 		    break;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	    case '\r':
6487c478bd9Sstevel@tonic-gate 		    if ( crmode == 1 )
6497c478bd9Sstevel@tonic-gate 			spaces(ch);
6507c478bd9Sstevel@tonic-gate 		    else if ( crmode == 2 )
6517c478bd9Sstevel@tonic-gate 			newline();
6527c478bd9Sstevel@tonic-gate 		    break;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	    case '(':
6557c478bd9Sstevel@tonic-gate 	    case ')':
6567c478bd9Sstevel@tonic-gate 	    case '\\':
6577c478bd9Sstevel@tonic-gate 		    startline();
6587c478bd9Sstevel@tonic-gate 		    putc('\\', fp_out);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate  *
6627c478bd9Sstevel@tonic-gate  * Fall through to the default case.
6637c478bd9Sstevel@tonic-gate  *
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	    default:
6677c478bd9Sstevel@tonic-gate 		    if ( isascii(ch) && isprint(ch) )
6687c478bd9Sstevel@tonic-gate 			oput(ch);
6697c478bd9Sstevel@tonic-gate 		    else {
6707c478bd9Sstevel@tonic-gate #define isintlprint(ch)	((ch)&0x80)
6717c478bd9Sstevel@tonic-gate #define isss(ch)	0
6727c478bd9Sstevel@tonic-gate 			if (isintlprint(ch) || isss(ch)) {
6737c478bd9Sstevel@tonic-gate 				startline();
6747c478bd9Sstevel@tonic-gate 				fprintf(fp_out, "\\%03o", 0xFF&ch);
6757c478bd9Sstevel@tonic-gate 				col++;
6767c478bd9Sstevel@tonic-gate 			}
6777c478bd9Sstevel@tonic-gate 		    }
6787c478bd9Sstevel@tonic-gate 		    break;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	}   /* End switch */
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate     formfeed();				/* next file starts on a new page? */
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate }   /* End of text */
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*****************************************************************************/
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 
690f928ce67Sceastha static void
formfeed(void)691f928ce67Sceastha formfeed(void)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate  *
6967c478bd9Sstevel@tonic-gate  * Called whenever we've finished with the last page and want to get ready for the
6977c478bd9Sstevel@tonic-gate  * next one. Also used at the beginning and end of each input file, so we have to
6987c478bd9Sstevel@tonic-gate  * be careful about what's done. The first time through (up to the redirect() call)
6997c478bd9Sstevel@tonic-gate  * output goes to /dev/null.
7007c478bd9Sstevel@tonic-gate  *
7017c478bd9Sstevel@tonic-gate  * Adobe now recommends that the showpage operator occur after the page level
7027c478bd9Sstevel@tonic-gate  * restore so it can be easily redefined to have side-effects in the printer's VM.
7037c478bd9Sstevel@tonic-gate  * Although it seems reasonable I haven't implemented it, because it makes other
7047c478bd9Sstevel@tonic-gate  * things, like selectively setting manual feed or choosing an alternate paper
7057c478bd9Sstevel@tonic-gate  * tray, clumsy - at least on a per page basis.
7067c478bd9Sstevel@tonic-gate  *
7077c478bd9Sstevel@tonic-gate  */
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate     if ( fp_out == stdout )		/* count the last page */
7117c478bd9Sstevel@tonic-gate 	printed++;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate     endline();				/* print the last line */
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate     fprintf(fp_out, "cleartomark\n");
7167c478bd9Sstevel@tonic-gate     fprintf(fp_out, "showpage\n");
7177c478bd9Sstevel@tonic-gate     fprintf(fp_out, "restore\n");
7187c478bd9Sstevel@tonic-gate     if (printed % formsperpage == 0)
7197c478bd9Sstevel@tonic-gate 	fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate     if ( ungetc(getc(fp_in), fp_in) == EOF )
7227c478bd9Sstevel@tonic-gate 	redirect(-1);
7237c478bd9Sstevel@tonic-gate     else redirect(++page);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate     if (printed % formsperpage == 0)
7267c478bd9Sstevel@tonic-gate 	fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
7277c478bd9Sstevel@tonic-gate     fprintf(fp_out, "save\n");
7287c478bd9Sstevel@tonic-gate     fprintf(fp_out, "mark\n");
7297c478bd9Sstevel@tonic-gate     writerequest(printed+1, fp_out);
7307c478bd9Sstevel@tonic-gate     fprintf(fp_out, "%d pagesetup\n", printed+1);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate     line = 1;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate }   /* End of formfeed */
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /*****************************************************************************/
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 
740f928ce67Sceastha static void
newline(void)741f928ce67Sceastha newline(void)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate  *
7467c478bd9Sstevel@tonic-gate  * Called when we've read a newline character. The call to startline() ensures
7477c478bd9Sstevel@tonic-gate  * that at least an empty string is on the stack.
7487c478bd9Sstevel@tonic-gate  *
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate     startline();
7527c478bd9Sstevel@tonic-gate     endline();				/* print the current line */
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate     if ( ++line > linespp )		/* done with this page */
7557c478bd9Sstevel@tonic-gate 	formfeed();
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate }   /* End of newline */
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate /*****************************************************************************/
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 
763f928ce67Sceastha static void
spaces(int ch)764f928ce67Sceastha spaces(int ch)
765f928ce67Sceastha     /* next input character */
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate     int		endcol;			/* ending column */
7687c478bd9Sstevel@tonic-gate     int		i;			/* final distance - in spaces */
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate  *
7727c478bd9Sstevel@tonic-gate  * Counts consecutive spaces, tabs, and backspaces and figures out where the next
7737c478bd9Sstevel@tonic-gate  * string should start. Once that's been done we try to choose an efficient way
7747c478bd9Sstevel@tonic-gate  * to output the required number of spaces. The choice is between using procedure
7757c478bd9Sstevel@tonic-gate  * l with a single string on the stack and L with several string and column pairs.
7767c478bd9Sstevel@tonic-gate  * We usually break even, in terms of the size of the output file, if we need four
7777c478bd9Sstevel@tonic-gate  * consecutive spaces. More means using L decreases the size of the file. For now
7787c478bd9Sstevel@tonic-gate  * if there are less than 6 consecutive spaces we just add them to the current
7797c478bd9Sstevel@tonic-gate  * string, otherwise we end that string, follow it by its starting position, and
7807c478bd9Sstevel@tonic-gate  * begin a new one that starts at endcol. Backspacing is always handled this way.
7817c478bd9Sstevel@tonic-gate  *
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate     startline();			/* so col makes sense */
7867c478bd9Sstevel@tonic-gate     endcol = col;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate     do {
7897c478bd9Sstevel@tonic-gate 	if ( ch == ' ' )
7907c478bd9Sstevel@tonic-gate 	    endcol++;
7917c478bd9Sstevel@tonic-gate 	else if ( ch == '\t' )
7927c478bd9Sstevel@tonic-gate 	    endcol += tabstops - ((endcol - 1) % tabstops);
7937c478bd9Sstevel@tonic-gate 	else if ( ch == '\b' )
7947c478bd9Sstevel@tonic-gate 	    endcol--;
7957c478bd9Sstevel@tonic-gate 	else if ( ch == '\r' )
7967c478bd9Sstevel@tonic-gate 	    endcol = 1;
7977c478bd9Sstevel@tonic-gate 	else break;
7987c478bd9Sstevel@tonic-gate     } while ( ch = getc(fp_in) );	/* if ch is 0 we'd quit anyway */
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate     ungetc(ch, fp_in);			/* wasn't a space, tab, or backspace */
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate     if ( endcol < 1 )			/* can't move past left edge */
8037c478bd9Sstevel@tonic-gate 	endcol = 1;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate     if ( (i = endcol - col) >= 0 && i < 6 )
8067c478bd9Sstevel@tonic-gate 	for ( ; i > 0; i-- )
8077c478bd9Sstevel@tonic-gate 	    oput((int)' ');
8087c478bd9Sstevel@tonic-gate     else {
8097c478bd9Sstevel@tonic-gate 	fprintf(fp_out, ")%d(", stringstart-1);
8107c478bd9Sstevel@tonic-gate 	stringcount++;
8117c478bd9Sstevel@tonic-gate 	col = stringstart = endcol;
8127c478bd9Sstevel@tonic-gate     }	/* End else */
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate }   /* End of spaces */
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate /*****************************************************************************/
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 
820f928ce67Sceastha static void
startline(void)821f928ce67Sceastha startline(void)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate  *
8267c478bd9Sstevel@tonic-gate  * Called whenever we want to be certain we're ready to start pushing characters
8277c478bd9Sstevel@tonic-gate  * into an open string on the stack. If stringcount is positive we've already
8287c478bd9Sstevel@tonic-gate  * started, so there's nothing to do. The first string starts in column 1.
8297c478bd9Sstevel@tonic-gate  *
8307c478bd9Sstevel@tonic-gate  */
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate     if ( stringcount < 1 )  {
8347c478bd9Sstevel@tonic-gate 	putc('(', fp_out);
8357c478bd9Sstevel@tonic-gate 	stringstart = col = 1;
8367c478bd9Sstevel@tonic-gate 	stringcount = 1;
8377c478bd9Sstevel@tonic-gate     }	/* End if */
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate }   /* End of startline */
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate /*****************************************************************************/
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 
845f928ce67Sceastha static void
endline(void)846f928ce67Sceastha endline(void)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate  *
8527c478bd9Sstevel@tonic-gate  * Generates a call to the PostScript procedure that processes all the text on
8537c478bd9Sstevel@tonic-gate  * the stack - provided stringcount is positive. If one string is on the stack
8547c478bd9Sstevel@tonic-gate  * the fast procedure (ie. l) is used to print the line, otherwise the slower
8557c478bd9Sstevel@tonic-gate  * one that processes string and column pairs is used.
8567c478bd9Sstevel@tonic-gate  *
8577c478bd9Sstevel@tonic-gate  */
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate     if ( stringcount == 1 )
8617c478bd9Sstevel@tonic-gate 	fprintf(fp_out, ")l\n");
8627c478bd9Sstevel@tonic-gate     else if ( stringcount > 1 )
8637c478bd9Sstevel@tonic-gate 	fprintf(fp_out, ")%d L\n", stringstart-1);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate     stringcount = 0;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate }   /* End of endline */
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate /*****************************************************************************/
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 
873f928ce67Sceastha static void
oput(int ch)874f928ce67Sceastha oput(int ch)
875f928ce67Sceastha     /* next output character */
8767c478bd9Sstevel@tonic-gate {
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate  *
8807c478bd9Sstevel@tonic-gate  * Responsible for adding all printing characters from the input file to the
8817c478bd9Sstevel@tonic-gate  * open string on top of the stack. The only other characters that end up in
8827c478bd9Sstevel@tonic-gate  * that string are the quotes required for special characters. Some simple
8837c478bd9Sstevel@tonic-gate  * changes here and in spaces could make line wrapping possible. Doing a good
8847c478bd9Sstevel@tonic-gate  * job would probably force lots of printer dependent stuff into the program,
8857c478bd9Sstevel@tonic-gate  * so I haven't bothered with it. Could also change the prologue, or perhaps
8867c478bd9Sstevel@tonic-gate  * write a different one, that uses kshow instead of show to display strings.
8877c478bd9Sstevel@tonic-gate  *
8887c478bd9Sstevel@tonic-gate  */
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate     startline();
8927c478bd9Sstevel@tonic-gate     putc(ch, fp_out);
8937c478bd9Sstevel@tonic-gate     col++;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate }   /* End of oput */
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate /*****************************************************************************/
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 
901f928ce67Sceastha static void
redirect(int pg)902f928ce67Sceastha redirect(int pg)
903f928ce67Sceastha     /* next page we're printing */
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate     static FILE	*fp_null = NULL;	/* if output is turned off */
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate  *
9097c478bd9Sstevel@tonic-gate  * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
9107c478bd9Sstevel@tonic-gate  * otherwise output goes to stdout.
9117c478bd9Sstevel@tonic-gate  *
9127c478bd9Sstevel@tonic-gate  */
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate     if ( pg >= 0 && in_olist(pg) == ON )
9167c478bd9Sstevel@tonic-gate 	fp_out = stdout;
9177c478bd9Sstevel@tonic-gate     else if ( (fp_out = fp_null) == NULL )
9187c478bd9Sstevel@tonic-gate 	fp_out = fp_null = fopen("/dev/null", "w");
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate }   /* End of redirect */
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate /*****************************************************************************/
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 
926