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 /*
23*f928ce67Sceastha  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*f928ce67Sceastha /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*f928ce67Sceastha /*	  All Rights Reserved  	*/
29*f928ce67Sceastha 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * A simple program that can be used to filter jobs for PostScript
337c478bd9Sstevel@tonic-gate  * printers. It's a cleaned up version of usg_iox, that I assume was
347c478bd9Sstevel@tonic-gate  * written by Richard Flood.  The most important addition includes some
357c478bd9Sstevel@tonic-gate  * simple processing of printer status reports, usually obtained when
367c478bd9Sstevel@tonic-gate  * \024 is sent to the printer. The returned status lines look like:
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  *	%%[ status: idle; source serial 25 ]%%
407c478bd9Sstevel@tonic-gate  *	%%[ status: waiting; source serial 25 ]%%
417c478bd9Sstevel@tonic-gate  *	%%[ status: initializing; source serial 25 ]%%
427c478bd9Sstevel@tonic-gate  *	%%[ status: busy; source serial 25 ]%%
437c478bd9Sstevel@tonic-gate  *	%%[ status: printing; source serial 25 ]%%
447c478bd9Sstevel@tonic-gate  *	%%[ status: PrinterError: out of paper; source serial 25 ]%%
457c478bd9Sstevel@tonic-gate  *	%%[ status: PrinterError: no paper tray; source serial 25 ]%%
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  * although the list isn't meant to be complete.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * Other changes to the original program include the addition of
517c478bd9Sstevel@tonic-gate  * options that let you select the tty line, baud rate, and printer
527c478bd9Sstevel@tonic-gate  * log file. The program seems to work reasonably well, at least for
537c478bd9Sstevel@tonic-gate  * our QMS PS-800 printer, but could still use some work.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * There were a couple of serious mistakes in the first few versions of
567c478bd9Sstevel@tonic-gate  * postcomm.  Both were made in setting up flow control in routine
577c478bd9Sstevel@tonic-gate  * initialize(). Setting the IXANY flag in c_iflag was wrong, and
587c478bd9Sstevel@tonic-gate  * often caused problems when the printer transmitted a spontaneous
597c478bd9Sstevel@tonic-gate  * status report, which always happens when the paper runs out.
607c478bd9Sstevel@tonic-gate  * Things were kludged up to get around the problems, but they were
617c478bd9Sstevel@tonic-gate  * never exactly right, and probably could never be guaranteed to work
627c478bd9Sstevel@tonic-gate  * 100%.
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  * The other mistake was setting the IXOFF flag, again in c_iflag.
657c478bd9Sstevel@tonic-gate  * Although I never saw deadlock in the original versions of postcomm,
667c478bd9Sstevel@tonic-gate  * it could happen.  Apparently the IXANY and IXOFF flags combined to
677c478bd9Sstevel@tonic-gate  * make that an unlikely event.  Anyway both flags should normally be
687c478bd9Sstevel@tonic-gate  * turned off to ensure reliable transmission of jobs.
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  * The implications of only setting IXON are obvious. Job transmission
717c478bd9Sstevel@tonic-gate  * should be reliable, but data returned by the printer over the tty
727c478bd9Sstevel@tonic-gate  * line may get lost. That won't cause problems in postcomm, but there
737c478bd9Sstevel@tonic-gate  * may be occasions when you want to run a job and recover data
747c478bd9Sstevel@tonic-gate  * generated by the printer. The -t option sets the IXOFF, IXANY, and
757c478bd9Sstevel@tonic-gate  * IXON flags in c_iflag and causes send() to be far more careful about
767c478bd9Sstevel@tonic-gate  * when data is sent to the printer. In addition anything not
777c478bd9Sstevel@tonic-gate  * recognized as a status report is written on stdout. It seems to
787c478bd9Sstevel@tonic-gate  * work reasonably well, but it's slow and may hang or have flow
797c478bd9Sstevel@tonic-gate  * control problems. Only use the -t option when it's absolutely
807c478bd9Sstevel@tonic-gate  * necessary. A small block size, like 512, should also help.
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  * Using two processes, one for reads and the other for writes, may
837c478bd9Sstevel@tonic-gate  * eventually be needed. For now postcomm seems to do a good job
847c478bd9Sstevel@tonic-gate  * transmitting data, and the -t option is probably acceptable for
857c478bd9Sstevel@tonic-gate  * those few jobs that need to recover data from the printer.
867c478bd9Sstevel@tonic-gate  *
877c478bd9Sstevel@tonic-gate  * A typical command line might be:
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  *	postcomm -L log -t <file1 > device
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * where -L selects the printer log file and -t sends data from the
927c478bd9Sstevel@tonic-gate  * printer out to the printer.  If you don't choose a log file stderr
937c478bd9Sstevel@tonic-gate  * will be used and the information mailed or written to you.
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate #include <stdio.h>
987c478bd9Sstevel@tonic-gate #include <stdarg.h>
997c478bd9Sstevel@tonic-gate #include <ctype.h>
1007c478bd9Sstevel@tonic-gate #include <fcntl.h>
1017c478bd9Sstevel@tonic-gate #include <signal.h>
1027c478bd9Sstevel@tonic-gate #include <sys/types.h>
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate # define	OFF		0
1067c478bd9Sstevel@tonic-gate # define	ON		1
1077c478bd9Sstevel@tonic-gate # define	TRUE		1
1087c478bd9Sstevel@tonic-gate # define	FALSE		0
1097c478bd9Sstevel@tonic-gate # define	FATAL		1
1107c478bd9Sstevel@tonic-gate # define	NON_FATAL	0
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate #include "postcomm.h"		/* some special definitions */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate char	*prog_name = "postcomm";	/* just for error messages */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate int	debug = OFF;		/* debug flag */
1187c478bd9Sstevel@tonic-gate int	ignore = OFF;		/* what's done for FATAL errors */
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate char	*block = NULL;		/* input file buffer */
1227c478bd9Sstevel@tonic-gate int	blocksize = BLOCKSIZE;	/* and its size in bytes */
1237c478bd9Sstevel@tonic-gate int	head = 0;		/* block[head] is the next character */
1247c478bd9Sstevel@tonic-gate int	tail = 0;		/* one past the last byte in block[] */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate char	mesg[BUFSIZE];		/* exactly what came back on ttyi */
1277c478bd9Sstevel@tonic-gate char	sbuf[BUFSIZE];		/* for parsing the message */
1287c478bd9Sstevel@tonic-gate int	next = 0;		/* next character goes in sbuf[next] */
1297c478bd9Sstevel@tonic-gate Status	status[] = STATUS;	/* for converting status strings */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate int	stopbits = 1;		/* number of stop bits */
1327c478bd9Sstevel@tonic-gate int	tostdout = FALSE;	/* non-status stuff goes to stdout? */
1337c478bd9Sstevel@tonic-gate int	curfile = 0;		/* only needed when tostdout is TRUE */
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate char	*postbegin = POSTBEGIN;	/* preceeds all the input files */
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate int	ttyi;			/* input */
1387c478bd9Sstevel@tonic-gate int	ttyo = 2;		/* and output file descriptors */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate FILE	*fp_log = stderr;	/* log file for data from the printer */
141*f928ce67Sceastha 
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 
144*f928ce67Sceastha static void filter(void);
145*f928ce67Sceastha static int getstatus(int);
146*f928ce67Sceastha static void initialize(void);
147*f928ce67Sceastha static void options(int, char *[]);
148*f928ce67Sceastha static int readblock(int);
149*f928ce67Sceastha static int readline(void);
150*f928ce67Sceastha static void reset(void);
151*f928ce67Sceastha static int writeblock(void);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate void
logit(char * mesg,...)1547c478bd9Sstevel@tonic-gate logit(char *mesg, ...)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  *
1597c478bd9Sstevel@tonic-gate  * Simple routine that's used to write a message to the log file.
1607c478bd9Sstevel@tonic-gate  *
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate     if (mesg != NULL)
1657c478bd9Sstevel@tonic-gate     {
1667c478bd9Sstevel@tonic-gate 	va_list ap;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	va_start(ap, mesg);
1697c478bd9Sstevel@tonic-gate 	vfprintf(fp_log, mesg, ap);
1707c478bd9Sstevel@tonic-gate 	va_end(ap);
1717c478bd9Sstevel@tonic-gate 	fflush(fp_log);
1727c478bd9Sstevel@tonic-gate     }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate }   /* End of logit */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate void
error(int kind,char * mesg,...)1817c478bd9Sstevel@tonic-gate error(int kind, char *mesg, ...)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  *
1877c478bd9Sstevel@tonic-gate  * Called when we've run into some kind of program error. First *mesg is
1887c478bd9Sstevel@tonic-gate  * printed using the control string arguments a?. Then if kind is FATAL
1897c478bd9Sstevel@tonic-gate  * and we're not ignoring errors the program will be terminated.
1907c478bd9Sstevel@tonic-gate  *
1917c478bd9Sstevel@tonic-gate  * If mesg is NULL or *mesg is the NULL string nothing will be printed.
1927c478bd9Sstevel@tonic-gate  *
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate     if ( mesg != NULL  &&  *mesg != '\0' )  {
1977c478bd9Sstevel@tonic-gate 	va_list ap;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	fprintf(fp_log, "%s: ", prog_name);
2007c478bd9Sstevel@tonic-gate 	va_start(ap, mesg);
2017c478bd9Sstevel@tonic-gate 	vfprintf(fp_log, mesg, ap);
2027c478bd9Sstevel@tonic-gate 	va_end(ap);
2037c478bd9Sstevel@tonic-gate 	putc('\n', fp_log);
2047c478bd9Sstevel@tonic-gate     }	/* End if */
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate     if ( kind == FATAL  &&  ignore == OFF )  {
2077c478bd9Sstevel@tonic-gate 	write(ttyo, "\003\004", 2);
2087c478bd9Sstevel@tonic-gate 	exit(1);
2097c478bd9Sstevel@tonic-gate     }	/* End if */
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate }   /* End of error */
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 
217*f928ce67Sceastha int
main(int argc,char * argv[])218*f928ce67Sceastha main(int argc, char *argv[])
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate  *
2237c478bd9Sstevel@tonic-gate  * A simple program that manages input and output for PostScript
2247c478bd9Sstevel@tonic-gate  * printers. If you're sending a PostScript program that will be
2257c478bd9Sstevel@tonic-gate  * returning useful information add the -ot option to the lp(1) command
2267c478bd9Sstevel@tonic-gate  * line. Everything not recognized as a printer status report will go
2277c478bd9Sstevel@tonic-gate  * to stdout. The -ot option should only be used when needed! It's slow
2287c478bd9Sstevel@tonic-gate  * and doesn't use flow control properly, but it's probably the best
2297c478bd9Sstevel@tonic-gate  * that can be done using a single process for reading and writing.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate     prog_name = argv[0];	/* really just for error messages */
2337c478bd9Sstevel@tonic-gate 
234*f928ce67Sceastha     options(argc, argv);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate     initialize();		/* Set printer up for printing */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate     filter();
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate     reset();			/* wait 'til it's finished & reset it*/
2417c478bd9Sstevel@tonic-gate 
242*f928ce67Sceastha     return (0);		/* everything probably went OK */
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate }   /* End of main */
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 
250*f928ce67Sceastha static void
options(int argc,char * argv[])251*f928ce67Sceastha options(int argc, char *argv[])
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate     int		ch;			/* return value from getopt() */
2567c478bd9Sstevel@tonic-gate     char	*names = "tB:L:P:DI";
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate     extern char	*optarg;		/* used by getopt() */
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate  *
2627c478bd9Sstevel@tonic-gate  * Reads and processes the command line options.  The -t option should
2637c478bd9Sstevel@tonic-gate  * only be used when absolutely necessary.  It's slow and doesn't do
2647c478bd9Sstevel@tonic-gate  * flow control properly.  Selecting a small block size (eg. 512 or
2657c478bd9Sstevel@tonic-gate  * less) with with the -B option may help when you need the -t option.
2667c478bd9Sstevel@tonic-gate  *
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate     while ( (ch = getopt(argc, argv, names)) != EOF )
2717c478bd9Sstevel@tonic-gate     {
2727c478bd9Sstevel@tonic-gate 	switch ( ch )
2737c478bd9Sstevel@tonic-gate 	{
2747c478bd9Sstevel@tonic-gate 	    case 't':		/* non-status stuff goes to stdout */
2757c478bd9Sstevel@tonic-gate 		    tostdout = TRUE;
2767c478bd9Sstevel@tonic-gate 		    break;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	    case 'B':		/* set the job buffer size */
2797c478bd9Sstevel@tonic-gate 		    if ((blocksize = atoi(optarg)) <= 0)
2807c478bd9Sstevel@tonic-gate 			blocksize = BLOCKSIZE;
2817c478bd9Sstevel@tonic-gate 		    break;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	    case 'L':			/* printer log file */
2847c478bd9Sstevel@tonic-gate 		    if ((fp_log = fopen(optarg, "w")) == NULL)
2857c478bd9Sstevel@tonic-gate 		    {
2867c478bd9Sstevel@tonic-gate 			fp_log = stderr;
2877c478bd9Sstevel@tonic-gate 			error(NON_FATAL, "can't open log file %s",
2887c478bd9Sstevel@tonic-gate 								optarg);
2897c478bd9Sstevel@tonic-gate 		    }	/* End if */
2907c478bd9Sstevel@tonic-gate 		    break;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	    case 'P':			/* initial PostScript program */
2937c478bd9Sstevel@tonic-gate 		    postbegin = optarg;
2947c478bd9Sstevel@tonic-gate 		    break;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	    case 'D':			/* debug flag */
2977c478bd9Sstevel@tonic-gate 		    debug = ON;
2987c478bd9Sstevel@tonic-gate 		    break;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	    case 'I':			/* ignore FATAL errors */
3017c478bd9Sstevel@tonic-gate 		    ignore = ON;
3027c478bd9Sstevel@tonic-gate 		    break;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	    case '?':			/* don't understand the option */
3057c478bd9Sstevel@tonic-gate 		    error(FATAL, "");
3067c478bd9Sstevel@tonic-gate 		    break;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	    default:			/* don't know what to do for ch */
3097c478bd9Sstevel@tonic-gate 		    error(FATAL, "missing case for option %c\n", ch);
3107c478bd9Sstevel@tonic-gate 		    break;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	}   /* End switch */
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate     }   /* End while */
3157c478bd9Sstevel@tonic-gate }   /* End of options */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 
321*f928ce67Sceastha static void
initialize(void)322*f928ce67Sceastha initialize(void)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate     if ((block = malloc(blocksize)) == NULL)
3257c478bd9Sstevel@tonic-gate 	error(FATAL, "no memory");
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate     ttyi = fileno(stdout);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate     if ((ttyo = dup(ttyi)) == -1)
3307c478bd9Sstevel@tonic-gate 	error(FATAL, "can't dup file descriptor for stdout");
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  *
3347c478bd9Sstevel@tonic-gate  * Makes sure the printer is in the
3357c478bd9Sstevel@tonic-gate  * IDLE state before any real data is sent.
3367c478bd9Sstevel@tonic-gate  *
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate     logit("printer startup\n");
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate     while ( 1 )
3437c478bd9Sstevel@tonic-gate 	switch (getstatus(1))
3447c478bd9Sstevel@tonic-gate 	{
3457c478bd9Sstevel@tonic-gate 	    case IDLE:
3467c478bd9Sstevel@tonic-gate 		    if (postbegin != NULL)
3477c478bd9Sstevel@tonic-gate 			write(ttyo, postbegin, strlen(postbegin));
3487c478bd9Sstevel@tonic-gate 		    else
3497c478bd9Sstevel@tonic-gate 			write(ttyo, "\n", 1);
3507c478bd9Sstevel@tonic-gate 		    return;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	    case WAITING:
3537c478bd9Sstevel@tonic-gate 	    case BUSY:
3547c478bd9Sstevel@tonic-gate 	    case ERROR:
3557c478bd9Sstevel@tonic-gate 		    write(ttyo, "\003\004", 2);
3567c478bd9Sstevel@tonic-gate 		    sleep(1);
3577c478bd9Sstevel@tonic-gate 		    break;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	    case FLUSHING:
3607c478bd9Sstevel@tonic-gate 		    write(ttyo, "\004", 1);
3617c478bd9Sstevel@tonic-gate 		    sleep(1);
3627c478bd9Sstevel@tonic-gate 		    break;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	    case PRINTERERROR:
3657c478bd9Sstevel@tonic-gate 	    case INITIALIZING:
3667c478bd9Sstevel@tonic-gate 		    sleep(15);
3677c478bd9Sstevel@tonic-gate 		    break;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	    case DISCONNECT:
3707c478bd9Sstevel@tonic-gate 		    /* talk to spooler w/S_FAULT_ALERT */
3717c478bd9Sstevel@tonic-gate 		    error(FATAL, "printer appears to be offline");
3727c478bd9Sstevel@tonic-gate 		    break;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	    default:
3757c478bd9Sstevel@tonic-gate 		    sleep(1);
3767c478bd9Sstevel@tonic-gate 		    break;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	}   /* End switch */
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate }   /* End of initialize */
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 
386*f928ce67Sceastha static void
filter(void)387*f928ce67Sceastha filter(void)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate     static int	wflag = 0;	/* nonzero if we've written a block */
3907c478bd9Sstevel@tonic-gate     int		fd_in = fileno(stdin);
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  *
3947c478bd9Sstevel@tonic-gate  * Responsible for sending the next file to the printer.
3957c478bd9Sstevel@tonic-gate  * Most of the hard stuff is done in getstatus() and readline().
3967c478bd9Sstevel@tonic-gate  * All this routine really does is control what happens for the
3977c478bd9Sstevel@tonic-gate  * different printer states.
3987c478bd9Sstevel@tonic-gate  *
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate     logit("sending file\n");
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate     curfile++;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate     while (readblock(fd_in))
4077c478bd9Sstevel@tonic-gate 	switch (getstatus(0))
4087c478bd9Sstevel@tonic-gate 	{
4097c478bd9Sstevel@tonic-gate 	    case WAITING:
4107c478bd9Sstevel@tonic-gate 		    writeblock();
4117c478bd9Sstevel@tonic-gate 		    wflag = 1;
4127c478bd9Sstevel@tonic-gate 		    break;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	    case BUSY:
4157c478bd9Sstevel@tonic-gate 	    case PRINTING:
4167c478bd9Sstevel@tonic-gate 	    case PRINTERERROR:
4177c478bd9Sstevel@tonic-gate 		    if (tostdout == FALSE)
4187c478bd9Sstevel@tonic-gate 		    {
4197c478bd9Sstevel@tonic-gate 			writeblock();
4207c478bd9Sstevel@tonic-gate 			wflag = 1;
4217c478bd9Sstevel@tonic-gate 		    }
4227c478bd9Sstevel@tonic-gate 		    else
4237c478bd9Sstevel@tonic-gate 			sleep(1);
4247c478bd9Sstevel@tonic-gate 		    break;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	    case UNKNOWN:
4277c478bd9Sstevel@tonic-gate 		    if (tostdout == FALSE)
4287c478bd9Sstevel@tonic-gate 		    {
4297c478bd9Sstevel@tonic-gate 			writeblock();
4307c478bd9Sstevel@tonic-gate 			wflag = 1;
4317c478bd9Sstevel@tonic-gate 		    }
4327c478bd9Sstevel@tonic-gate 		    break;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	    case NOSTATUS:
4357c478bd9Sstevel@tonic-gate 		    if (tostdout == FALSE)
4367c478bd9Sstevel@tonic-gate 		    {
4377c478bd9Sstevel@tonic-gate 			if (wflag)
4387c478bd9Sstevel@tonic-gate 			    writeblock();
4397c478bd9Sstevel@tonic-gate 		    }
4407c478bd9Sstevel@tonic-gate 		    else
4417c478bd9Sstevel@tonic-gate 			sleep(1);
4427c478bd9Sstevel@tonic-gate 		    break;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	    case IDLE:
4457c478bd9Sstevel@tonic-gate 		    if (wflag)
4467c478bd9Sstevel@tonic-gate 			error(FATAL, "printer is idle");
4477c478bd9Sstevel@tonic-gate 		    write(ttyo, "\n", 1);
4487c478bd9Sstevel@tonic-gate 		    break;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	    case ERROR:
4517c478bd9Sstevel@tonic-gate 		    fprintf(stderr, "%s", mesg);	/* for csw */
4527c478bd9Sstevel@tonic-gate 		    error(FATAL, "PostScript error");
4537c478bd9Sstevel@tonic-gate 		    break;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	    case FLUSHING:
4567c478bd9Sstevel@tonic-gate 		    error(FATAL, "PostScript error");
4577c478bd9Sstevel@tonic-gate 		    break;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	    case INITIALIZING:
4607c478bd9Sstevel@tonic-gate 		    error(FATAL, "printer booting");
4617c478bd9Sstevel@tonic-gate 		    break;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	    case DISCONNECT:
4647c478bd9Sstevel@tonic-gate 		    error(FATAL, "printer appears to be offline");
4657c478bd9Sstevel@tonic-gate 		    break;
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	}   /* End switch */
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate }   /* End of print */
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 
475*f928ce67Sceastha static int
readblock(int fd_in)476*f928ce67Sceastha readblock(int fd_in)
477*f928ce67Sceastha     /* current input file */
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate  *
4827c478bd9Sstevel@tonic-gate  * Fills the input buffer with the next block, provided we're all done
4837c478bd9Sstevel@tonic-gate  * with the last one.  Blocks from fd_in are stored in array block[].
4847c478bd9Sstevel@tonic-gate  * Head is the index of the next byte in block[] that's supposed to go
4857c478bd9Sstevel@tonic-gate  * to the printer.   tail points one past the last byte in the current
4867c478bd9Sstevel@tonic-gate  * block.  head is adjusted in writeblock() after each successful
4877c478bd9Sstevel@tonic-gate  * write, while head and tail are reset here each time a new block is
4887c478bd9Sstevel@tonic-gate  * read.  Returns the number of bytes left in the current block.   Read
4897c478bd9Sstevel@tonic-gate  * errors cause the program to abort.
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  */
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate     if (head >= tail)
4947c478bd9Sstevel@tonic-gate     {		/* done with the last block */
4957c478bd9Sstevel@tonic-gate 	if ((tail = read(fd_in, block, blocksize)) == -1)
4967c478bd9Sstevel@tonic-gate 	    error(FATAL, "error reading input file");
4977c478bd9Sstevel@tonic-gate 	head = 0;
4987c478bd9Sstevel@tonic-gate     }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate     return(tail - head);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate }   /* End of readblock */
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 
508*f928ce67Sceastha static int
writeblock(void)509*f928ce67Sceastha writeblock(void)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate     int		count;		/* bytes successfully written */
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  *
5157c478bd9Sstevel@tonic-gate  * Called from send() when it's OK to send the next block to the
5167c478bd9Sstevel@tonic-gate  * printer. head is adjusted after the write, and the number of bytes
5177c478bd9Sstevel@tonic-gate  * that were successfully written is returned to the caller.
5187c478bd9Sstevel@tonic-gate  *
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate     if ((count = write(ttyo, &block[head], tail - head)) == -1)
5237c478bd9Sstevel@tonic-gate 	error(FATAL, "error writing to stdout");
5247c478bd9Sstevel@tonic-gate     else
5257c478bd9Sstevel@tonic-gate 	if (count == 0)
5267c478bd9Sstevel@tonic-gate 	    error(FATAL, "printer appears to be offline");
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate     head += count;
5297c478bd9Sstevel@tonic-gate     return(count);
5307c478bd9Sstevel@tonic-gate }   /* End of writeblock */
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 
536*f928ce67Sceastha static int
getstatus(int t)537*f928ce67Sceastha getstatus(int t)
538*f928ce67Sceastha     /* sleep time after sending '\024' */
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate     char	*state;		/* new printer state - from sbuf[] */
5417c478bd9Sstevel@tonic-gate     int		i;		/* index of new state in status[] */
5427c478bd9Sstevel@tonic-gate     static int	laststate = NOSTATUS;
5437c478bd9Sstevel@tonic-gate 				/* last state we found out about */
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate  *
5477c478bd9Sstevel@tonic-gate  * Sends a status request to the printer and tries to read the response.
5487c478bd9Sstevel@tonic-gate  * If an entire line is available readline() returns TRUE and the
5497c478bd9Sstevel@tonic-gate  * string in sbuf[] is parsed and converted into an integer code that
5507c478bd9Sstevel@tonic-gate  * represents the printer's state.  If readline() returns FALSE,
5517c478bd9Sstevel@tonic-gate  * meaning an entire line wasn't available, NOSTATUS is returned.
5527c478bd9Sstevel@tonic-gate  *
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate     if (readline() == TRUE)
5567c478bd9Sstevel@tonic-gate     {
5577c478bd9Sstevel@tonic-gate 	state = sbuf;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	if (strncmp(sbuf, "%%[", 3) == 0)
5607c478bd9Sstevel@tonic-gate 	{
5617c478bd9Sstevel@tonic-gate 	    strtok(sbuf, " ");		/* skip the leading "%%[ " */
5627c478bd9Sstevel@tonic-gate 	    if (strcmp(state = strtok(NULL, " :;"), "status") == 0)
5637c478bd9Sstevel@tonic-gate 		state = strtok(NULL, " :;");
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	for (i = 0; status[i].state != NULL; i++)
5677c478bd9Sstevel@tonic-gate 	    if (strcmp(state, status[i].state) == 0)
5687c478bd9Sstevel@tonic-gate 		break;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (status[i].val != laststate || debug == ON)
5717c478bd9Sstevel@tonic-gate 	    logit("%s", mesg);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (tostdout == TRUE && status[i].val == UNKNOWN && curfile > 0)
5747c478bd9Sstevel@tonic-gate 	    fprintf(stdout, "%s", mesg);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	return(laststate = status[i].val);
5777c478bd9Sstevel@tonic-gate     }	/* End if */
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate     if ( write(ttyo, "\024", 1) != 1 )
5807c478bd9Sstevel@tonic-gate 	error(FATAL, "printer appears to be offline");
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate     if ( t > 0 )
5837c478bd9Sstevel@tonic-gate 	sleep(t);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate     return(NOSTATUS);
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate }   /* End of getstatus */
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 
593*f928ce67Sceastha static void
reset(void)594*f928ce67Sceastha reset(void)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate     int		sleeptime = 15;		/* for 'out of paper' etc. */
5977c478bd9Sstevel@tonic-gate     int		senteof = FALSE;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate  *
6017c478bd9Sstevel@tonic-gate  * We're all done sending the input files, so we'll send an EOF to the
6027c478bd9Sstevel@tonic-gate  * printer and wait until it tells us it's done.
6037c478bd9Sstevel@tonic-gate  *
6047c478bd9Sstevel@tonic-gate  */
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate     logit("waiting for end of job\n");
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate     while (1)
6107c478bd9Sstevel@tonic-gate     {
6117c478bd9Sstevel@tonic-gate 	switch (getstatus(2))
6127c478bd9Sstevel@tonic-gate 	{
6137c478bd9Sstevel@tonic-gate 	    case WAITING:
6147c478bd9Sstevel@tonic-gate 		write(ttyo, "\004", 1);
6157c478bd9Sstevel@tonic-gate 		senteof = TRUE;
6167c478bd9Sstevel@tonic-gate 		sleeptime = 15;
6177c478bd9Sstevel@tonic-gate 		break;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	    case ENDOFJOB:
6207c478bd9Sstevel@tonic-gate 		if (senteof == TRUE)
6217c478bd9Sstevel@tonic-gate 		{
6227c478bd9Sstevel@tonic-gate 		    logit("job complete\n");
6237c478bd9Sstevel@tonic-gate 		    return;
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 		sleeptime = 15;
6267c478bd9Sstevel@tonic-gate 		break;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	    case BUSY:
6297c478bd9Sstevel@tonic-gate 	    case PRINTING:
6307c478bd9Sstevel@tonic-gate 		sleeptime = 15;
6317c478bd9Sstevel@tonic-gate 		sleep(1);
6327c478bd9Sstevel@tonic-gate 		break;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	    case PRINTERERROR:
6357c478bd9Sstevel@tonic-gate 		sleep(sleeptime++);
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	    case ERROR:
6397c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s", mesg);	/* for csw */
6407c478bd9Sstevel@tonic-gate 		error(FATAL, "PostScript error");
6417c478bd9Sstevel@tonic-gate 		return;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	    case FLUSHING:
6447c478bd9Sstevel@tonic-gate 		error(FATAL, "PostScript error");
6457c478bd9Sstevel@tonic-gate 		return;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	    case IDLE:
6487c478bd9Sstevel@tonic-gate 		error(FATAL, "printer is idle");
6497c478bd9Sstevel@tonic-gate 		return;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	    case INITIALIZING:
6527c478bd9Sstevel@tonic-gate 		error(FATAL, "printer booting");
6537c478bd9Sstevel@tonic-gate 		return;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	    case DISCONNECT:
6567c478bd9Sstevel@tonic-gate 		error(FATAL, "printer appears to be offline");
6577c478bd9Sstevel@tonic-gate 		return;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	    default:
6607c478bd9Sstevel@tonic-gate 		sleep(1);
6617c478bd9Sstevel@tonic-gate 		break;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	}   /* End switch */
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	if (sleeptime > 60)
6667c478bd9Sstevel@tonic-gate 	    sleeptime = 60;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate     }	/* End while */
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate }   /* End of reset */
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 
680*f928ce67Sceastha static int
readline(void)681*f928ce67Sceastha readline(void)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate     char	ch;			/* next character from ttyi */
6847c478bd9Sstevel@tonic-gate     int		n;			/* read() return value */
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate /*
6877c478bd9Sstevel@tonic-gate  *
6887c478bd9Sstevel@tonic-gate  * Reads the printer's tty line up to a newline (or EOF) or until no
6897c478bd9Sstevel@tonic-gate  * more characters are available. As characters are read they're
6907c478bd9Sstevel@tonic-gate  * converted to lower case and put in sbuf[next] until a newline (or
6917c478bd9Sstevel@tonic-gate  * EOF) are found. The string is then terminated with '\0', next is
6927c478bd9Sstevel@tonic-gate  * reset to zero, and TRUE is returned.
6937c478bd9Sstevel@tonic-gate  *
6947c478bd9Sstevel@tonic-gate  */
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate     while ((n = read(ttyi, &ch, 1)) != 0)
6987c478bd9Sstevel@tonic-gate     {
6997c478bd9Sstevel@tonic-gate 	if (n < 0)
7007c478bd9Sstevel@tonic-gate 	    error(FATAL, "error reading stdout");
7017c478bd9Sstevel@tonic-gate 	mesg[next] = ch;
7027c478bd9Sstevel@tonic-gate 	sbuf[next++] = tolower(ch);
7037c478bd9Sstevel@tonic-gate 	if (ch == '\n'  ||  ch == '\004')
7047c478bd9Sstevel@tonic-gate 	{
7057c478bd9Sstevel@tonic-gate 	    mesg[next] = sbuf[next] = '\0';
7067c478bd9Sstevel@tonic-gate 	    if (ch == '\004')
7077c478bd9Sstevel@tonic-gate 		sprintf(sbuf, "%%%%[ status: endofjob ]%%%%\n");
7087c478bd9Sstevel@tonic-gate 	    next = 0;
7097c478bd9Sstevel@tonic-gate 	    return(TRUE);
7107c478bd9Sstevel@tonic-gate 	}   /* End if */
7117c478bd9Sstevel@tonic-gate     }	/* End while */
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate     return(FALSE);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate }   /* End of readline */
716