1*7dd7cddfSDavid du Colombier /*
2*7dd7cddfSDavid du Colombier *
3*7dd7cddfSDavid du Colombier * postio - RS-232 serial interface for PostScript printers
4*7dd7cddfSDavid du Colombier *
5*7dd7cddfSDavid du Colombier * A simple program that manages input and output for PostScript printers. Much
6*7dd7cddfSDavid du Colombier * has been added and changed from early versions of the program, but the basic
7*7dd7cddfSDavid du Colombier * philosophy is still the same. Don't send real data until we're certain we've
8*7dd7cddfSDavid du Colombier * connected to a PostScript printer that's in the idle state and try to hold the
9*7dd7cddfSDavid du Colombier * connection until the job is completely done. It's more work than you might
10*7dd7cddfSDavid du Colombier * expect is necessary, but should provide a reasonably reliable spooler interface
11*7dd7cddfSDavid du Colombier * that can return error indications to the caller via the program's exit status.
12*7dd7cddfSDavid du Colombier *
13*7dd7cddfSDavid du Colombier * I've added code that will let you split the program into separate read/write
14*7dd7cddfSDavid du Colombier * processes. Although it's not the default it should be useful if you have a file
15*7dd7cddfSDavid du Colombier * that will be returning useful data from the printer. The two process stuff was
16*7dd7cddfSDavid du Colombier * laid down on top of the single process code and both methods still work. The
17*7dd7cddfSDavid du Colombier * implementation isn't as good as it could be, but didn't require many changes
18*7dd7cddfSDavid du Colombier * to the original program (despite the fact that there are now many differences).
19*7dd7cddfSDavid du Colombier *
20*7dd7cddfSDavid du Colombier * By default the program still runs as a single process. The -R2 option forces
21*7dd7cddfSDavid du Colombier * separate read and write processes after the intial connection is made. If you
22*7dd7cddfSDavid du Colombier * want that as the default initialize splitme (below) to TRUE. In addition the
23*7dd7cddfSDavid du Colombier * -t option that's used to force stuff not recognized as status reports to stdout
24*7dd7cddfSDavid du Colombier * also tries to run as two processes (by setting splitme to TRUE). It will only
25*7dd7cddfSDavid du Colombier * work if the required code (ie. resetline() in ifdef.c) has been implemented
26*7dd7cddfSDavid du Colombier * for your Unix system. I've only tested the System V code.
27*7dd7cddfSDavid du Colombier *
28*7dd7cddfSDavid du Colombier * Code needed to support interactive mode has also been added, although again it's
29*7dd7cddfSDavid du Colombier * not as efficient as it could be. It depends on the system dependent procedures
30*7dd7cddfSDavid du Colombier * resetline() and setupstdin() (file ifdef.c) and for now is only guaranteed to
31*7dd7cddfSDavid du Colombier * work on System V. Can be requested using the -i option.
32*7dd7cddfSDavid du Colombier *
33*7dd7cddfSDavid du Colombier * Quiet mode (-q option) is also new, but was needed for some printers connected
34*7dd7cddfSDavid du Colombier * to RADIAN. If you're running in quiet mode no status requests will be sent to
35*7dd7cddfSDavid du Colombier * the printer while files are being transmitted (ie. in send()).
36*7dd7cddfSDavid du Colombier *
37*7dd7cddfSDavid du Colombier * The program expects to receive printer status lines that look like,
38*7dd7cddfSDavid du Colombier *
39*7dd7cddfSDavid du Colombier * %%[ status: idle; source: serial 25 ]%%
40*7dd7cddfSDavid du Colombier * %%[ status: waiting; source: serial 25 ]%%
41*7dd7cddfSDavid du Colombier * %%[ status: initializing; source: serial 25 ]%%
42*7dd7cddfSDavid du Colombier * %%[ status: busy; source: serial 25 ]%%
43*7dd7cddfSDavid du Colombier * %%[ status: printing; source: serial 25 ]%%
44*7dd7cddfSDavid du Colombier * %%[ status: PrinterError: out of paper; source: serial 25 ]%%
45*7dd7cddfSDavid du Colombier * %%[ status: PrinterError: no paper tray; source: serial 25 ]%%
46*7dd7cddfSDavid du Colombier *
47*7dd7cddfSDavid du Colombier * although this list isn't complete. Sending a '\024' (control T) character forces
48*7dd7cddfSDavid du Colombier * the return of a status report. PostScript errors detected on the printer result
49*7dd7cddfSDavid du Colombier * in the immediate transmission of special error messages that look like,
50*7dd7cddfSDavid du Colombier *
51*7dd7cddfSDavid du Colombier * %%[ Error: undefined; OffendingCommand: xxx ]%%
52*7dd7cddfSDavid du Colombier * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
53*7dd7cddfSDavid du Colombier *
54*7dd7cddfSDavid du Colombier * although we only use the Error and Flushing keywords. Finally conditions, like
55*7dd7cddfSDavid du Colombier * being out of paper, result in other messages being sent back from the printer
56*7dd7cddfSDavid du Colombier * over the communications line. Typical PrinterError messages look like,
57*7dd7cddfSDavid du Colombier *
58*7dd7cddfSDavid du Colombier * %%[ PrinterError: out of paper; source: serial 25 ]%%
59*7dd7cddfSDavid du Colombier * %%[ PrinterError: paper jam; source: serial 25 ]%%
60*7dd7cddfSDavid du Colombier *
61*7dd7cddfSDavid du Colombier * although we only use the PrinterError keyword rather than trying to recognize
62*7dd7cddfSDavid du Colombier * all possible printer errors.
63*7dd7cddfSDavid du Colombier *
64*7dd7cddfSDavid du Colombier * The implications of using one process and only flow controlling data going to
65*7dd7cddfSDavid du Colombier * the printer are obvious. Job transmission should be reliable, but there can be
66*7dd7cddfSDavid du Colombier * data loss in stuff sent back from the printer. Usually that only caused problems
67*7dd7cddfSDavid du Colombier * with jobs designed to run on the printer and return useful data back over the
68*7dd7cddfSDavid du Colombier * communications line. If that's the kind of job you're sending call postio with
69*7dd7cddfSDavid du Colombier * the -t option. That should force the program to split into separate read and
70*7dd7cddfSDavid du Colombier * write processes and everything not bracketed by "%%[ " and " ]%%" strings goes
71*7dd7cddfSDavid du Colombier * to stdout. In otherwords the data you're expecting should be separated from the
72*7dd7cddfSDavid du Colombier * status stuff that goes to the log file (or stderr). The -R2 option does almost
73*7dd7cddfSDavid du Colombier * the same thing (ie. separate read and write processes), but everything that
74*7dd7cddfSDavid du Colombier * comes back from the printer goes to the log file (stderr by default) and you'll
75*7dd7cddfSDavid du Colombier * have to separate your data from any printer messages.
76*7dd7cddfSDavid du Colombier *
77*7dd7cddfSDavid du Colombier * A typical command line might be,
78*7dd7cddfSDavid du Colombier *
79*7dd7cddfSDavid du Colombier * postio -l /dev/tty01 -b 9600 -L log file1 file2
80*7dd7cddfSDavid du Colombier *
81*7dd7cddfSDavid du Colombier * where -l selects the line, -b sets the baud rate, and -L selects the printer
82*7dd7cddfSDavid du Colombier * log file. Since there's no default line, at least not right now, you'll always
83*7dd7cddfSDavid du Colombier * need to use the -l option, and if you don't choose a log file stderr will be
84*7dd7cddfSDavid du Colombier * used. If you have a program that will be returning data the command line might
85*7dd7cddfSDavid du Colombier * look like,
86*7dd7cddfSDavid du Colombier *
87*7dd7cddfSDavid du Colombier * postio -t -l/dev/tty01 -b9600 -Llog file >results
88*7dd7cddfSDavid du Colombier *
89*7dd7cddfSDavid du Colombier * Status stuff goes to file log while the data you're expecting back from the
90*7dd7cddfSDavid du Colombier * printer gets put in file results.
91*7dd7cddfSDavid du Colombier *
92*7dd7cddfSDavid du Colombier */
93*7dd7cddfSDavid du Colombier
94*7dd7cddfSDavid du Colombier #include <stdio.h>
95*7dd7cddfSDavid du Colombier #include <ctype.h>
96*7dd7cddfSDavid du Colombier #include <fcntl.h>
97*7dd7cddfSDavid du Colombier #include <signal.h>
98*7dd7cddfSDavid du Colombier #include <sys/types.h>
99*7dd7cddfSDavid du Colombier #include <errno.h>
100*7dd7cddfSDavid du Colombier
101*7dd7cddfSDavid du Colombier #include "ifdef.h" /* conditional compilation stuff */
102*7dd7cddfSDavid du Colombier #include "gen.h" /* general purpose definitions */
103*7dd7cddfSDavid du Colombier #include "postio.h" /* some special definitions */
104*7dd7cddfSDavid du Colombier
105*7dd7cddfSDavid du Colombier char **argv; /* global so everyone can use them */
106*7dd7cddfSDavid du Colombier int argc;
107*7dd7cddfSDavid du Colombier
108*7dd7cddfSDavid du Colombier char *prog_name = ""; /* really just for error messages */
109*7dd7cddfSDavid du Colombier int x_stat = 0; /* program exit status */
110*7dd7cddfSDavid du Colombier int debug = OFF; /* debug flag */
111*7dd7cddfSDavid du Colombier int ignore = OFF; /* what's done for FATAL errors */
112*7dd7cddfSDavid du Colombier
113*7dd7cddfSDavid du Colombier char *line = NULL; /* printer is on this tty line */
114*7dd7cddfSDavid du Colombier short baudrate = BAUDRATE; /* and running at this baud rate */
115*7dd7cddfSDavid du Colombier Baud baudtable[] = BAUDTABLE; /* converts strings to termio values */
116*7dd7cddfSDavid du Colombier
117*7dd7cddfSDavid du Colombier int stopbits = 1; /* number of stop bits */
118*7dd7cddfSDavid du Colombier int tostdout = FALSE; /* non-status stuff goes to stdout? */
119*7dd7cddfSDavid du Colombier int quiet = FALSE; /* no status queries in send() if TRUE */
120*7dd7cddfSDavid du Colombier int interactive = FALSE; /* interactive mode */
121*7dd7cddfSDavid du Colombier char *postbegin = POSTBEGIN; /* preceeds all the input files */
122*7dd7cddfSDavid du Colombier int useslowsend = FALSE; /* not recommended! */
123*7dd7cddfSDavid du Colombier int sendctrlC = TRUE; /* interrupt with ctrl-C when BUSY */
124*7dd7cddfSDavid du Colombier int window_size = -1; /* for Datakit - use -w */
125*7dd7cddfSDavid du Colombier
126*7dd7cddfSDavid du Colombier char *block = NULL; /* input file buffer */
127*7dd7cddfSDavid du Colombier int blocksize = BLOCKSIZE; /* and its size in bytes */
128*7dd7cddfSDavid du Colombier int head = 0; /* block[head] is the next character */
129*7dd7cddfSDavid du Colombier int tail = 0; /* one past the last byte in block[] */
130*7dd7cddfSDavid du Colombier
131*7dd7cddfSDavid du Colombier int splitme = FALSE; /* into READ and WRITE processes if TRUE */
132*7dd7cddfSDavid du Colombier int whatami = READWRITE; /* a READ or WRITE process - or both */
133*7dd7cddfSDavid du Colombier int canread = TRUE; /* allow reads */
134*7dd7cddfSDavid du Colombier int canwrite = TRUE; /* and writes if TRUE */
135*7dd7cddfSDavid du Colombier int otherpid = -1; /* who gets signals if greater than 1 */
136*7dd7cddfSDavid du Colombier int joinsig = SIGTRAP; /* reader gets this when writing is done */
137*7dd7cddfSDavid du Colombier int writedone = FALSE; /* and then sets this to TRUE */
138*7dd7cddfSDavid du Colombier
139*7dd7cddfSDavid du Colombier char mesg[MESGSIZE]; /* exactly what came back on ttyi */
140*7dd7cddfSDavid du Colombier char sbuf[MESGSIZE]; /* for parsing the message */
141*7dd7cddfSDavid du Colombier int next = 0; /* next character goes in mesg[next] */
142*7dd7cddfSDavid du Colombier char *mesgptr = NULL; /* printer message starts here in mesg[] */
143*7dd7cddfSDavid du Colombier char *endmesg = NULL; /* as far as readline() can go in mesg[] */
144*7dd7cddfSDavid du Colombier
145*7dd7cddfSDavid du Colombier Status status[] = STATUS; /* for converting status strings */
146*7dd7cddfSDavid du Colombier int nostatus = NOSTATUS; /* default getstatus() return value */
147*7dd7cddfSDavid du Colombier
148*7dd7cddfSDavid du Colombier int currentstate = NOTCONNECTED; /* what's happening START, SEND, or DONE */
149*7dd7cddfSDavid du Colombier
150*7dd7cddfSDavid du Colombier int ttyi = 0; /* input */
151*7dd7cddfSDavid du Colombier int ttyo = 2; /* and output file descriptors */
152*7dd7cddfSDavid du Colombier
153*7dd7cddfSDavid du Colombier FILE *fp_log = stderr; /* log file for stuff from the printer */
154*7dd7cddfSDavid du Colombier
155*7dd7cddfSDavid du Colombier /*****************************************************************************/
156*7dd7cddfSDavid du Colombier
main(agc,agv)157*7dd7cddfSDavid du Colombier main(agc, agv)
158*7dd7cddfSDavid du Colombier
159*7dd7cddfSDavid du Colombier int agc;
160*7dd7cddfSDavid du Colombier char *agv[];
161*7dd7cddfSDavid du Colombier
162*7dd7cddfSDavid du Colombier {
163*7dd7cddfSDavid du Colombier
164*7dd7cddfSDavid du Colombier /*
165*7dd7cddfSDavid du Colombier *
166*7dd7cddfSDavid du Colombier * A simple program that manages input and output for PostScript printers. Can run
167*7dd7cddfSDavid du Colombier * as a single process or as separate read/write processes. What's done depends on
168*7dd7cddfSDavid du Colombier * the value assigned to splitme when split() is called.
169*7dd7cddfSDavid du Colombier *
170*7dd7cddfSDavid du Colombier */
171*7dd7cddfSDavid du Colombier
172*7dd7cddfSDavid du Colombier argc = agc; /* other routines may want them */
173*7dd7cddfSDavid du Colombier argv = agv;
174*7dd7cddfSDavid du Colombier
175*7dd7cddfSDavid du Colombier prog_name = argv[0]; /* really just for error messages */
176*7dd7cddfSDavid du Colombier
177*7dd7cddfSDavid du Colombier init_signals(); /* sets up interrupt handling */
178*7dd7cddfSDavid du Colombier options(); /* get command line options */
179*7dd7cddfSDavid du Colombier initialize(); /* must be done after options() */
180*7dd7cddfSDavid du Colombier start(); /* make sure the printer is ready */
181*7dd7cddfSDavid du Colombier split(); /* into read/write processes - maybe */
182*7dd7cddfSDavid du Colombier arguments(); /* then send each input file */
183*7dd7cddfSDavid du Colombier done(); /* wait until the printer is finished */
184*7dd7cddfSDavid du Colombier cleanup(); /* make sure the write process stops */
185*7dd7cddfSDavid du Colombier
186*7dd7cddfSDavid du Colombier exit(x_stat); /* everything probably went OK */
187*7dd7cddfSDavid du Colombier
188*7dd7cddfSDavid du Colombier } /* End of main */
189*7dd7cddfSDavid du Colombier
190*7dd7cddfSDavid du Colombier /*****************************************************************************/
191*7dd7cddfSDavid du Colombier
init_signals()192*7dd7cddfSDavid du Colombier init_signals()
193*7dd7cddfSDavid du Colombier
194*7dd7cddfSDavid du Colombier {
195*7dd7cddfSDavid du Colombier
196*7dd7cddfSDavid du Colombier void interrupt(); /* handles them if we catch signals */
197*7dd7cddfSDavid du Colombier
198*7dd7cddfSDavid du Colombier /*
199*7dd7cddfSDavid du Colombier *
200*7dd7cddfSDavid du Colombier * Makes sure we handle interrupts. The proper way to kill the program, if
201*7dd7cddfSDavid du Colombier * necessary, is to do a kill -15. That forces a call to interrupt(), which in
202*7dd7cddfSDavid du Colombier * turn tries to reset the printer and then exits with a non-zero status. If the
203*7dd7cddfSDavid du Colombier * program is running as two processes, sending SIGTERM to either the parent or
204*7dd7cddfSDavid du Colombier * child should clean things up.
205*7dd7cddfSDavid du Colombier *
206*7dd7cddfSDavid du Colombier */
207*7dd7cddfSDavid du Colombier
208*7dd7cddfSDavid du Colombier if ( signal(SIGINT, interrupt) == SIG_IGN ) {
209*7dd7cddfSDavid du Colombier signal(SIGINT, SIG_IGN);
210*7dd7cddfSDavid du Colombier signal(SIGQUIT, SIG_IGN);
211*7dd7cddfSDavid du Colombier signal(SIGHUP, SIG_IGN);
212*7dd7cddfSDavid du Colombier } else {
213*7dd7cddfSDavid du Colombier signal(SIGHUP, interrupt);
214*7dd7cddfSDavid du Colombier signal(SIGQUIT, interrupt);
215*7dd7cddfSDavid du Colombier } /* End else */
216*7dd7cddfSDavid du Colombier
217*7dd7cddfSDavid du Colombier signal(SIGTERM, interrupt);
218*7dd7cddfSDavid du Colombier
219*7dd7cddfSDavid du Colombier } /* End of init_sig */
220*7dd7cddfSDavid du Colombier
221*7dd7cddfSDavid du Colombier /*****************************************************************************/
222*7dd7cddfSDavid du Colombier
options()223*7dd7cddfSDavid du Colombier options()
224*7dd7cddfSDavid du Colombier
225*7dd7cddfSDavid du Colombier {
226*7dd7cddfSDavid du Colombier
227*7dd7cddfSDavid du Colombier int ch; /* return value from getopt() */
228*7dd7cddfSDavid du Colombier char *optnames = "b:cil:qs:tw:B:L:P:R:SDI";
229*7dd7cddfSDavid du Colombier
230*7dd7cddfSDavid du Colombier extern char *optarg; /* used by getopt() */
231*7dd7cddfSDavid du Colombier extern int optind;
232*7dd7cddfSDavid du Colombier
233*7dd7cddfSDavid du Colombier /*
234*7dd7cddfSDavid du Colombier *
235*7dd7cddfSDavid du Colombier * Reads and processes the command line options. The -R2, -t, and -i options all
236*7dd7cddfSDavid du Colombier * force separate read and write processes by eventually setting splitme to TRUE
237*7dd7cddfSDavid du Colombier * (check initialize()). The -S option is not recommended and should only be used
238*7dd7cddfSDavid du Colombier * as a last resort!
239*7dd7cddfSDavid du Colombier *
240*7dd7cddfSDavid du Colombier */
241*7dd7cddfSDavid du Colombier
242*7dd7cddfSDavid du Colombier while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
243*7dd7cddfSDavid du Colombier switch ( ch ) {
244*7dd7cddfSDavid du Colombier case 'b': /* baud rate string */
245*7dd7cddfSDavid du Colombier baudrate = getbaud(optarg);
246*7dd7cddfSDavid du Colombier break;
247*7dd7cddfSDavid du Colombier
248*7dd7cddfSDavid du Colombier case 'c': /* no ctrl-C's */
249*7dd7cddfSDavid du Colombier sendctrlC = FALSE;
250*7dd7cddfSDavid du Colombier break;
251*7dd7cddfSDavid du Colombier
252*7dd7cddfSDavid du Colombier case 'i': /* interactive mode */
253*7dd7cddfSDavid du Colombier interactive = TRUE;
254*7dd7cddfSDavid du Colombier break;
255*7dd7cddfSDavid du Colombier
256*7dd7cddfSDavid du Colombier case 'l': /* printer line */
257*7dd7cddfSDavid du Colombier line = optarg;
258*7dd7cddfSDavid du Colombier break;
259*7dd7cddfSDavid du Colombier
260*7dd7cddfSDavid du Colombier case 'q': /* no status queries - for RADIAN? */
261*7dd7cddfSDavid du Colombier quiet = TRUE;
262*7dd7cddfSDavid du Colombier break;
263*7dd7cddfSDavid du Colombier
264*7dd7cddfSDavid du Colombier case 's': /* use 2 stop bits - for UNISON? */
265*7dd7cddfSDavid du Colombier if ( (stopbits = atoi(optarg)) < 1 || stopbits > 2 )
266*7dd7cddfSDavid du Colombier stopbits = 1;
267*7dd7cddfSDavid du Colombier break;
268*7dd7cddfSDavid du Colombier
269*7dd7cddfSDavid du Colombier case 't': /* non-status stuff goes to stdout */
270*7dd7cddfSDavid du Colombier tostdout = TRUE;
271*7dd7cddfSDavid du Colombier break;
272*7dd7cddfSDavid du Colombier
273*7dd7cddfSDavid du Colombier case 'w': /* Datakit window size */
274*7dd7cddfSDavid du Colombier window_size = atoi(optarg);
275*7dd7cddfSDavid du Colombier break;
276*7dd7cddfSDavid du Colombier
277*7dd7cddfSDavid du Colombier case 'B': /* set the job buffer size */
278*7dd7cddfSDavid du Colombier if ( (blocksize = atoi(optarg)) <= 0 )
279*7dd7cddfSDavid du Colombier blocksize = BLOCKSIZE;
280*7dd7cddfSDavid du Colombier break;
281*7dd7cddfSDavid du Colombier
282*7dd7cddfSDavid du Colombier case 'L': /* printer log file */
283*7dd7cddfSDavid du Colombier if ( (fp_log = fopen(optarg, "w")) == NULL ) {
284*7dd7cddfSDavid du Colombier fp_log = stderr;
285*7dd7cddfSDavid du Colombier error(NON_FATAL, "can't open log file %s", optarg);
286*7dd7cddfSDavid du Colombier } /* End if */
287*7dd7cddfSDavid du Colombier break;
288*7dd7cddfSDavid du Colombier
289*7dd7cddfSDavid du Colombier case 'P': /* initial PostScript code */
290*7dd7cddfSDavid du Colombier postbegin = optarg;
291*7dd7cddfSDavid du Colombier break;
292*7dd7cddfSDavid du Colombier
293*7dd7cddfSDavid du Colombier case 'R': /* run as one or two processes */
294*7dd7cddfSDavid du Colombier if ( atoi(optarg) == 2 )
295*7dd7cddfSDavid du Colombier splitme = TRUE;
296*7dd7cddfSDavid du Colombier else splitme = FALSE;
297*7dd7cddfSDavid du Colombier break;
298*7dd7cddfSDavid du Colombier
299*7dd7cddfSDavid du Colombier case 'S': /* slow and kludged up version of send */
300*7dd7cddfSDavid du Colombier useslowsend = TRUE;
301*7dd7cddfSDavid du Colombier break;
302*7dd7cddfSDavid du Colombier
303*7dd7cddfSDavid du Colombier case 'D': /* debug flag */
304*7dd7cddfSDavid du Colombier debug = ON;
305*7dd7cddfSDavid du Colombier break;
306*7dd7cddfSDavid du Colombier
307*7dd7cddfSDavid du Colombier case 'I': /* ignore FATAL errors */
308*7dd7cddfSDavid du Colombier ignore = ON;
309*7dd7cddfSDavid du Colombier break;
310*7dd7cddfSDavid du Colombier
311*7dd7cddfSDavid du Colombier case '?': /* don't understand the option */
312*7dd7cddfSDavid du Colombier error(FATAL, "");
313*7dd7cddfSDavid du Colombier break;
314*7dd7cddfSDavid du Colombier
315*7dd7cddfSDavid du Colombier default: /* don't know what to do for ch */
316*7dd7cddfSDavid du Colombier error(FATAL, "missing case for option %c\n", ch);
317*7dd7cddfSDavid du Colombier break;
318*7dd7cddfSDavid du Colombier } /* End switch */
319*7dd7cddfSDavid du Colombier } /* End while */
320*7dd7cddfSDavid du Colombier
321*7dd7cddfSDavid du Colombier argc -= optind; /* get ready for non-option args */
322*7dd7cddfSDavid du Colombier argv += optind;
323*7dd7cddfSDavid du Colombier
324*7dd7cddfSDavid du Colombier } /* End of options */
325*7dd7cddfSDavid du Colombier
326*7dd7cddfSDavid du Colombier /*****************************************************************************/
327*7dd7cddfSDavid du Colombier
getbaud(rate)328*7dd7cddfSDavid du Colombier getbaud(rate)
329*7dd7cddfSDavid du Colombier
330*7dd7cddfSDavid du Colombier char *rate; /* string representing the baud rate */
331*7dd7cddfSDavid du Colombier
332*7dd7cddfSDavid du Colombier {
333*7dd7cddfSDavid du Colombier
334*7dd7cddfSDavid du Colombier int i; /* for looking through baudtable[] */
335*7dd7cddfSDavid du Colombier
336*7dd7cddfSDavid du Colombier /*
337*7dd7cddfSDavid du Colombier *
338*7dd7cddfSDavid du Colombier * Called from options() to convert a baud rate string into an appropriate termio
339*7dd7cddfSDavid du Colombier * value. *rate is looked up in baudtable[] and if it's found, the corresponding
340*7dd7cddfSDavid du Colombier * value is returned to the caller.
341*7dd7cddfSDavid du Colombier *
342*7dd7cddfSDavid du Colombier */
343*7dd7cddfSDavid du Colombier
344*7dd7cddfSDavid du Colombier for ( i = 0; baudtable[i].rate != NULL; i++ )
345*7dd7cddfSDavid du Colombier if ( strcmp(rate, baudtable[i].rate) == 0 )
346*7dd7cddfSDavid du Colombier return(baudtable[i].val);
347*7dd7cddfSDavid du Colombier
348*7dd7cddfSDavid du Colombier error(FATAL, "don't recognize baud rate %s", rate);
349*7dd7cddfSDavid du Colombier
350*7dd7cddfSDavid du Colombier } /* End of getbaud */
351*7dd7cddfSDavid du Colombier
352*7dd7cddfSDavid du Colombier /*****************************************************************************/
353*7dd7cddfSDavid du Colombier
initialize()354*7dd7cddfSDavid du Colombier initialize()
355*7dd7cddfSDavid du Colombier
356*7dd7cddfSDavid du Colombier {
357*7dd7cddfSDavid du Colombier
358*7dd7cddfSDavid du Colombier /*
359*7dd7cddfSDavid du Colombier *
360*7dd7cddfSDavid du Colombier * Initialization, a few checks, and a call to setupline() (file ifdef.c) to open
361*7dd7cddfSDavid du Colombier * and configure the communications line. Settings for interactive mode always
362*7dd7cddfSDavid du Colombier * take precedence. The setupstdin() call with an argument of 0 saves the current
363*7dd7cddfSDavid du Colombier * terminal settings if interactive mode has been requested - otherwise nothing's
364*7dd7cddfSDavid du Colombier * done. Unbuffering stdout (via the setbuf() call) isn't really needed on System V
365*7dd7cddfSDavid du Colombier * since it's flushed whenever terminal input is requested. It's more efficient if
366*7dd7cddfSDavid du Colombier * we buffer the stdout (on System V) but safer (for other versions of Unix) if we
367*7dd7cddfSDavid du Colombier * include the setbuf() call.
368*7dd7cddfSDavid du Colombier *
369*7dd7cddfSDavid du Colombier */
370*7dd7cddfSDavid du Colombier
371*7dd7cddfSDavid du Colombier whatami = READWRITE; /* always run start() as one process */
372*7dd7cddfSDavid du Colombier canread = canwrite = TRUE;
373*7dd7cddfSDavid du Colombier
374*7dd7cddfSDavid du Colombier if ( tostdout == TRUE ) /* force separate read/write processes */
375*7dd7cddfSDavid du Colombier splitme = TRUE;
376*7dd7cddfSDavid du Colombier
377*7dd7cddfSDavid du Colombier if ( interactive == TRUE ) { /* interactive mode settings always win */
378*7dd7cddfSDavid du Colombier quiet = FALSE;
379*7dd7cddfSDavid du Colombier tostdout = FALSE;
380*7dd7cddfSDavid du Colombier splitme = TRUE;
381*7dd7cddfSDavid du Colombier blocksize = 1;
382*7dd7cddfSDavid du Colombier postbegin = NULL;
383*7dd7cddfSDavid du Colombier useslowsend = FALSE;
384*7dd7cddfSDavid du Colombier nostatus = INTERACTIVE;
385*7dd7cddfSDavid du Colombier setbuf(stdout, NULL);
386*7dd7cddfSDavid du Colombier } /* End if */
387*7dd7cddfSDavid du Colombier
388*7dd7cddfSDavid du Colombier if ( useslowsend == TRUE ) { /* last resort only - not recommended */
389*7dd7cddfSDavid du Colombier quiet = FALSE;
390*7dd7cddfSDavid du Colombier splitme = FALSE;
391*7dd7cddfSDavid du Colombier if ( blocksize > 1024 ) /* don't send too much all at once */
392*7dd7cddfSDavid du Colombier blocksize = 1024;
393*7dd7cddfSDavid du Colombier } /* End if */
394*7dd7cddfSDavid du Colombier
395*7dd7cddfSDavid du Colombier if ( tostdout == TRUE && fp_log == stderr )
396*7dd7cddfSDavid du Colombier fp_log = NULL;
397*7dd7cddfSDavid du Colombier
398*7dd7cddfSDavid du Colombier if ( line == NULL && (interactive == TRUE || tostdout == TRUE) )
399*7dd7cddfSDavid du Colombier error(FATAL, "a printer line must be supplied - use the -l option");
400*7dd7cddfSDavid du Colombier
401*7dd7cddfSDavid du Colombier if ( (block = malloc(blocksize)) == NULL )
402*7dd7cddfSDavid du Colombier error(FATAL, "no memory");
403*7dd7cddfSDavid du Colombier
404*7dd7cddfSDavid du Colombier endmesg = mesg + sizeof mesg - 2; /* one byte from last position in mesg */
405*7dd7cddfSDavid du Colombier
406*7dd7cddfSDavid du Colombier setupline(); /* configure the communications line */
407*7dd7cddfSDavid du Colombier setupstdin(0); /* save current stdin terminal settings */
408*7dd7cddfSDavid du Colombier
409*7dd7cddfSDavid du Colombier } /* End of initialize */
410*7dd7cddfSDavid du Colombier
411*7dd7cddfSDavid du Colombier /*****************************************************************************/
412*7dd7cddfSDavid du Colombier
start()413*7dd7cddfSDavid du Colombier start()
414*7dd7cddfSDavid du Colombier
415*7dd7cddfSDavid du Colombier {
416*7dd7cddfSDavid du Colombier
417*7dd7cddfSDavid du Colombier /*
418*7dd7cddfSDavid du Colombier *
419*7dd7cddfSDavid du Colombier * Tries to put the printer in the IDLE state before anything important is sent.
420*7dd7cddfSDavid du Colombier * Run as a single process no matter what has been assigned to splitme. Separate
421*7dd7cddfSDavid du Colombier * read and write processes, if requested, will be created after we're done here.
422*7dd7cddfSDavid du Colombier *
423*7dd7cddfSDavid du Colombier */
424*7dd7cddfSDavid du Colombier
425*7dd7cddfSDavid du Colombier logit("printer startup\n");
426*7dd7cddfSDavid du Colombier
427*7dd7cddfSDavid du Colombier currentstate = START;
428*7dd7cddfSDavid du Colombier clearline();
429*7dd7cddfSDavid du Colombier
430*7dd7cddfSDavid du Colombier while ( 1 )
431*7dd7cddfSDavid du Colombier switch ( getstatus(1) ) {
432*7dd7cddfSDavid du Colombier case IDLE:
433*7dd7cddfSDavid du Colombier case INTERACTIVE:
434*7dd7cddfSDavid du Colombier if ( postbegin != NULL && *postbegin != '\0' )
435*7dd7cddfSDavid du Colombier Write(ttyo, postbegin, strlen(postbegin));
436*7dd7cddfSDavid du Colombier clearline();
437*7dd7cddfSDavid du Colombier return;
438*7dd7cddfSDavid du Colombier
439*7dd7cddfSDavid du Colombier case BUSY:
440*7dd7cddfSDavid du Colombier if ( sendctrlC == TRUE ) {
441*7dd7cddfSDavid du Colombier Write(ttyo, "\003", 1);
442*7dd7cddfSDavid du Colombier Rest(1);
443*7dd7cddfSDavid du Colombier } /* End if */
444*7dd7cddfSDavid du Colombier break;
445*7dd7cddfSDavid du Colombier
446*7dd7cddfSDavid du Colombier case WAITING:
447*7dd7cddfSDavid du Colombier case ERROR:
448*7dd7cddfSDavid du Colombier case FLUSHING:
449*7dd7cddfSDavid du Colombier Write(ttyo, "\004", 1);
450*7dd7cddfSDavid du Colombier Rest(1);
451*7dd7cddfSDavid du Colombier break;
452*7dd7cddfSDavid du Colombier
453*7dd7cddfSDavid du Colombier case PRINTERERROR:
454*7dd7cddfSDavid du Colombier Rest(15);
455*7dd7cddfSDavid du Colombier break;
456*7dd7cddfSDavid du Colombier
457*7dd7cddfSDavid du Colombier case DISCONNECT:
458*7dd7cddfSDavid du Colombier error(FATAL, "Disconnected - printer may be offline");
459*7dd7cddfSDavid du Colombier break;
460*7dd7cddfSDavid du Colombier
461*7dd7cddfSDavid du Colombier case ENDOFJOB:
462*7dd7cddfSDavid du Colombier case UNKNOWN:
463*7dd7cddfSDavid du Colombier clearline();
464*7dd7cddfSDavid du Colombier break;
465*7dd7cddfSDavid du Colombier
466*7dd7cddfSDavid du Colombier default:
467*7dd7cddfSDavid du Colombier Rest(1);
468*7dd7cddfSDavid du Colombier break;
469*7dd7cddfSDavid du Colombier } /* End switch */
470*7dd7cddfSDavid du Colombier
471*7dd7cddfSDavid du Colombier } /* End of start */
472*7dd7cddfSDavid du Colombier
473*7dd7cddfSDavid du Colombier /*****************************************************************************/
474*7dd7cddfSDavid du Colombier
split()475*7dd7cddfSDavid du Colombier split()
476*7dd7cddfSDavid du Colombier
477*7dd7cddfSDavid du Colombier {
478*7dd7cddfSDavid du Colombier
479*7dd7cddfSDavid du Colombier int pid;
480*7dd7cddfSDavid du Colombier void interrupt();
481*7dd7cddfSDavid du Colombier
482*7dd7cddfSDavid du Colombier /*
483*7dd7cddfSDavid du Colombier *
484*7dd7cddfSDavid du Colombier * If splitme is TRUE we fork a process, make the parent handle reading, and let
485*7dd7cddfSDavid du Colombier * the child take care of writing. resetline() (file ifdef.c) contains all the
486*7dd7cddfSDavid du Colombier * system dependent code needed to reset the communications line for separate
487*7dd7cddfSDavid du Colombier * read and write processes. For now it's expected to return TRUE or FALSE and
488*7dd7cddfSDavid du Colombier * that value controls whether we try the fork. I've only tested the two process
489*7dd7cddfSDavid du Colombier * stuff for System V. Other versions of resetline() may just be dummy procedures
490*7dd7cddfSDavid du Colombier * that always return FALSE. If the fork() failed previous versions continued as
491*7dd7cddfSDavid du Colombier * a single process, although the implementation wasn't quite right, but I've now
492*7dd7cddfSDavid du Colombier * decided to quit. The main reason is a Datakit channel may be configured to
493*7dd7cddfSDavid du Colombier * flow control data in both directions, and if we run postio over that channel
494*7dd7cddfSDavid du Colombier * as a single process we likely will end up in deadlock.
495*7dd7cddfSDavid du Colombier *
496*7dd7cddfSDavid du Colombier */
497*7dd7cddfSDavid du Colombier
498*7dd7cddfSDavid du Colombier if ( splitme == TRUE )
499*7dd7cddfSDavid du Colombier if ( resetline() == TRUE ) {
500*7dd7cddfSDavid du Colombier pid = getpid();
501*7dd7cddfSDavid du Colombier signal(joinsig, interrupt);
502*7dd7cddfSDavid du Colombier if ( (otherpid = fork()) == -1 )
503*7dd7cddfSDavid du Colombier error(FATAL, "can't fork");
504*7dd7cddfSDavid du Colombier else if ( otherpid == 0 ) {
505*7dd7cddfSDavid du Colombier whatami = WRITE;
506*7dd7cddfSDavid du Colombier nostatus = WRITEPROCESS;
507*7dd7cddfSDavid du Colombier otherpid = pid;
508*7dd7cddfSDavid du Colombier setupstdin(1);
509*7dd7cddfSDavid du Colombier } else whatami = READ;
510*7dd7cddfSDavid du Colombier } else if ( interactive == TRUE || tostdout == TRUE )
511*7dd7cddfSDavid du Colombier error(FATAL, "can't create two process - check resetline()");
512*7dd7cddfSDavid du Colombier else error(NON_FATAL, "running as a single process - check resetline()");
513*7dd7cddfSDavid du Colombier
514*7dd7cddfSDavid du Colombier canread = (whatami & READ) ? TRUE : FALSE;
515*7dd7cddfSDavid du Colombier canwrite = (whatami & WRITE) ? TRUE : FALSE;
516*7dd7cddfSDavid du Colombier
517*7dd7cddfSDavid du Colombier } /* End of split */
518*7dd7cddfSDavid du Colombier
519*7dd7cddfSDavid du Colombier /*****************************************************************************/
520*7dd7cddfSDavid du Colombier
arguments()521*7dd7cddfSDavid du Colombier arguments()
522*7dd7cddfSDavid du Colombier
523*7dd7cddfSDavid du Colombier {
524*7dd7cddfSDavid du Colombier
525*7dd7cddfSDavid du Colombier int fd_in; /* next input file */
526*7dd7cddfSDavid du Colombier
527*7dd7cddfSDavid du Colombier /*
528*7dd7cddfSDavid du Colombier *
529*7dd7cddfSDavid du Colombier * Makes sure all the non-option command line arguments are processed. If there
530*7dd7cddfSDavid du Colombier * aren't any arguments left when we get here we'll send stdin. Input files are
531*7dd7cddfSDavid du Colombier * only read and sent to the printer if canwrite is TRUE. Checking it here means
532*7dd7cddfSDavid du Colombier * we won't have to do it in send(). If interactive mode is TRUE we'll stay here
533*7dd7cddfSDavid du Colombier * forever sending stdin when we run out of files - exit with a break. Actually
534*7dd7cddfSDavid du Colombier * the loop is bogus and used at most once when we're in interactive mode because
535*7dd7cddfSDavid du Colombier * stdin is in a pseudo raw mode and the read() in readblock() should never see
536*7dd7cddfSDavid du Colombier * the end of file.
537*7dd7cddfSDavid du Colombier *
538*7dd7cddfSDavid du Colombier */
539*7dd7cddfSDavid du Colombier
540*7dd7cddfSDavid du Colombier if ( canwrite == TRUE )
541*7dd7cddfSDavid du Colombier do /* loop is for interactive mode */
542*7dd7cddfSDavid du Colombier if ( argc < 1 )
543*7dd7cddfSDavid du Colombier send(fileno(stdin), "pipe.end");
544*7dd7cddfSDavid du Colombier else {
545*7dd7cddfSDavid du Colombier while ( argc > 0 ) {
546*7dd7cddfSDavid du Colombier if ( (fd_in = open(*argv, O_RDONLY)) == -1 )
547*7dd7cddfSDavid du Colombier error(FATAL, "can't open %s", *argv);
548*7dd7cddfSDavid du Colombier send(fd_in, *argv);
549*7dd7cddfSDavid du Colombier close(fd_in);
550*7dd7cddfSDavid du Colombier argc--;
551*7dd7cddfSDavid du Colombier argv++;
552*7dd7cddfSDavid du Colombier } /* End while */
553*7dd7cddfSDavid du Colombier } /* End else */
554*7dd7cddfSDavid du Colombier while ( interactive == TRUE );
555*7dd7cddfSDavid du Colombier
556*7dd7cddfSDavid du Colombier } /* End of arguments */
557*7dd7cddfSDavid du Colombier
558*7dd7cddfSDavid du Colombier /*****************************************************************************/
559*7dd7cddfSDavid du Colombier
send(fd_in,name)560*7dd7cddfSDavid du Colombier send(fd_in, name)
561*7dd7cddfSDavid du Colombier
562*7dd7cddfSDavid du Colombier int fd_in; /* next input file */
563*7dd7cddfSDavid du Colombier char *name; /* and it's pathname */
564*7dd7cddfSDavid du Colombier
565*7dd7cddfSDavid du Colombier {
566*7dd7cddfSDavid du Colombier
567*7dd7cddfSDavid du Colombier /*
568*7dd7cddfSDavid du Colombier *
569*7dd7cddfSDavid du Colombier * Sends file *name to the printer. There's nothing left here that depends on
570*7dd7cddfSDavid du Colombier * sending and receiving status reports, although it can be reassuring to know
571*7dd7cddfSDavid du Colombier * the printer is responding and processing our job. Only the writer gets here
572*7dd7cddfSDavid du Colombier * in the two process implementation, and in that case split() has reset nostatus
573*7dd7cddfSDavid du Colombier * to WRITEPROCESS and that's what getstatus() always returns. For now we accept
574*7dd7cddfSDavid du Colombier * the IDLE state and ENDOFJOB as legitimate and ignore the INITIALIZING state.
575*7dd7cddfSDavid du Colombier *
576*7dd7cddfSDavid du Colombier */
577*7dd7cddfSDavid du Colombier
578*7dd7cddfSDavid du Colombier if ( interactive == FALSE )
579*7dd7cddfSDavid du Colombier logit("sending file %s\n", name);
580*7dd7cddfSDavid du Colombier
581*7dd7cddfSDavid du Colombier currentstate = SEND;
582*7dd7cddfSDavid du Colombier
583*7dd7cddfSDavid du Colombier if ( useslowsend == TRUE ) {
584*7dd7cddfSDavid du Colombier slowsend(fd_in);
585*7dd7cddfSDavid du Colombier return;
586*7dd7cddfSDavid du Colombier } /* End if */
587*7dd7cddfSDavid du Colombier
588*7dd7cddfSDavid du Colombier while ( readblock(fd_in) )
589*7dd7cddfSDavid du Colombier switch ( getstatus(0) ) {
590*7dd7cddfSDavid du Colombier case IDLE:
591*7dd7cddfSDavid du Colombier case BUSY:
592*7dd7cddfSDavid du Colombier case WAITING:
593*7dd7cddfSDavid du Colombier case PRINTING:
594*7dd7cddfSDavid du Colombier case ENDOFJOB:
595*7dd7cddfSDavid du Colombier case PRINTERERROR:
596*7dd7cddfSDavid du Colombier case UNKNOWN:
597*7dd7cddfSDavid du Colombier case NOSTATUS:
598*7dd7cddfSDavid du Colombier case WRITEPROCESS:
599*7dd7cddfSDavid du Colombier case INTERACTIVE:
600*7dd7cddfSDavid du Colombier writeblock();
601*7dd7cddfSDavid du Colombier break;
602*7dd7cddfSDavid du Colombier
603*7dd7cddfSDavid du Colombier case ERROR:
604*7dd7cddfSDavid du Colombier fprintf(stderr, "%s", mesg); /* for csw */
605*7dd7cddfSDavid du Colombier error(USER_FATAL, "PostScript Error");
606*7dd7cddfSDavid du Colombier break;
607*7dd7cddfSDavid du Colombier
608*7dd7cddfSDavid du Colombier case FLUSHING:
609*7dd7cddfSDavid du Colombier error(USER_FATAL, "Flushing Job");
610*7dd7cddfSDavid du Colombier break;
611*7dd7cddfSDavid du Colombier
612*7dd7cddfSDavid du Colombier case DISCONNECT:
613*7dd7cddfSDavid du Colombier error(FATAL, "Disconnected - printer may be offline");
614*7dd7cddfSDavid du Colombier break;
615*7dd7cddfSDavid du Colombier } /* End switch */
616*7dd7cddfSDavid du Colombier
617*7dd7cddfSDavid du Colombier } /* End of send */
618*7dd7cddfSDavid du Colombier
619*7dd7cddfSDavid du Colombier /*****************************************************************************/
620*7dd7cddfSDavid du Colombier
done()621*7dd7cddfSDavid du Colombier done()
622*7dd7cddfSDavid du Colombier
623*7dd7cddfSDavid du Colombier {
624*7dd7cddfSDavid du Colombier
625*7dd7cddfSDavid du Colombier int sleeptime = 15; /* for 'out of paper' etc. */
626*7dd7cddfSDavid du Colombier
627*7dd7cddfSDavid du Colombier /*
628*7dd7cddfSDavid du Colombier *
629*7dd7cddfSDavid du Colombier * Tries to stay connected to the printer until we're reasonably sure the job is
630*7dd7cddfSDavid du Colombier * complete. It's the only way we can recover error messages or data generated by
631*7dd7cddfSDavid du Colombier * the PostScript program and returned over the communication line. Actually doing
632*7dd7cddfSDavid du Colombier * it correctly for all possible PostScript jobs is more difficult that it might
633*7dd7cddfSDavid du Colombier * seem. For example if we've sent several jobs, each with their own EOF mark, then
634*7dd7cddfSDavid du Colombier * waiting for ENDOFJOB won't guarantee all the jobs have completed. Even waiting
635*7dd7cddfSDavid du Colombier * for IDLE isn't good enough. Checking for the WAITING state after all the files
636*7dd7cddfSDavid du Colombier * have been sent and then sending an EOF may be the best approach, but even that
637*7dd7cddfSDavid du Colombier * won't work all the time - we could miss it or might not get there. Even sending
638*7dd7cddfSDavid du Colombier * our own special PostScript job after all the input files has it's own different
639*7dd7cddfSDavid du Colombier * set of problems, but probably could work (perhaps by printing a fake status
640*7dd7cddfSDavid du Colombier * message or just not timing out). Anyway it's probably not worth the trouble so
641*7dd7cddfSDavid du Colombier * for now we'll quit if writedone is TRUE and we get ENDOFJOB or IDLE.
642*7dd7cddfSDavid du Colombier *
643*7dd7cddfSDavid du Colombier * If we're running separate read and write processes the reader gets here after
644*7dd7cddfSDavid du Colombier * after split() while the writer goes to send() and only gets here after all the
645*7dd7cddfSDavid du Colombier * input files have been transmitted. When they're both here the writer sends the
646*7dd7cddfSDavid du Colombier * reader signal joinsig and that forces writedone to TRUE in the reader. At that
647*7dd7cddfSDavid du Colombier * point the reader can begin looking for an indication of the end of the job.
648*7dd7cddfSDavid du Colombier * The writer hangs around until the reader kills it (usually in cleanup()) sending
649*7dd7cddfSDavid du Colombier * occasional status requests.
650*7dd7cddfSDavid du Colombier *
651*7dd7cddfSDavid du Colombier */
652*7dd7cddfSDavid du Colombier
653*7dd7cddfSDavid du Colombier if ( canwrite == TRUE )
654*7dd7cddfSDavid du Colombier logit("waiting for end of job\n");
655*7dd7cddfSDavid du Colombier
656*7dd7cddfSDavid du Colombier currentstate = DONE;
657*7dd7cddfSDavid du Colombier writedone = (whatami == READWRITE) ? TRUE : FALSE;
658*7dd7cddfSDavid du Colombier
659*7dd7cddfSDavid du Colombier while ( 1 ) {
660*7dd7cddfSDavid du Colombier switch ( getstatus(1) ) {
661*7dd7cddfSDavid du Colombier
662*7dd7cddfSDavid du Colombier case WRITEPROCESS:
663*7dd7cddfSDavid du Colombier if ( writedone == FALSE ) {
664*7dd7cddfSDavid du Colombier sendsignal(joinsig);
665*7dd7cddfSDavid du Colombier Write(ttyo, "\004", 1);
666*7dd7cddfSDavid du Colombier writedone = TRUE;
667*7dd7cddfSDavid du Colombier sleeptime = 1;
668*7dd7cddfSDavid du Colombier } /* End if */
669*7dd7cddfSDavid du Colombier Rest(sleeptime++);
670*7dd7cddfSDavid du Colombier break;
671*7dd7cddfSDavid du Colombier
672*7dd7cddfSDavid du Colombier case WAITING:
673*7dd7cddfSDavid du Colombier Write(ttyo, "\004", 1);
674*7dd7cddfSDavid du Colombier Rest(1);
675*7dd7cddfSDavid du Colombier sleeptime = 15;
676*7dd7cddfSDavid du Colombier break;
677*7dd7cddfSDavid du Colombier
678*7dd7cddfSDavid du Colombier case IDLE:
679*7dd7cddfSDavid du Colombier case ENDOFJOB:
680*7dd7cddfSDavid du Colombier if ( writedone == TRUE ) {
681*7dd7cddfSDavid du Colombier logit("job complete\n");
682*7dd7cddfSDavid du Colombier return;
683*7dd7cddfSDavid du Colombier } /* End if */
684*7dd7cddfSDavid du Colombier break;
685*7dd7cddfSDavid du Colombier
686*7dd7cddfSDavid du Colombier case BUSY:
687*7dd7cddfSDavid du Colombier case PRINTING:
688*7dd7cddfSDavid du Colombier case INTERACTIVE:
689*7dd7cddfSDavid du Colombier sleeptime = 15;
690*7dd7cddfSDavid du Colombier break;
691*7dd7cddfSDavid du Colombier
692*7dd7cddfSDavid du Colombier case PRINTERERROR:
693*7dd7cddfSDavid du Colombier Rest(sleeptime++);
694*7dd7cddfSDavid du Colombier break;
695*7dd7cddfSDavid du Colombier
696*7dd7cddfSDavid du Colombier case ERROR:
697*7dd7cddfSDavid du Colombier fprintf(stderr, "%s", mesg); /* for csw */
698*7dd7cddfSDavid du Colombier error(USER_FATAL, "PostScript Error");
699*7dd7cddfSDavid du Colombier return;
700*7dd7cddfSDavid du Colombier
701*7dd7cddfSDavid du Colombier case FLUSHING:
702*7dd7cddfSDavid du Colombier error(USER_FATAL, "Flushing Job");
703*7dd7cddfSDavid du Colombier return;
704*7dd7cddfSDavid du Colombier
705*7dd7cddfSDavid du Colombier case DISCONNECT:
706*7dd7cddfSDavid du Colombier error(FATAL, "Disconnected - printer may be offline");
707*7dd7cddfSDavid du Colombier return;
708*7dd7cddfSDavid du Colombier
709*7dd7cddfSDavid du Colombier default:
710*7dd7cddfSDavid du Colombier Rest(1);
711*7dd7cddfSDavid du Colombier break;
712*7dd7cddfSDavid du Colombier } /* End switch */
713*7dd7cddfSDavid du Colombier
714*7dd7cddfSDavid du Colombier if ( sleeptime > 60 )
715*7dd7cddfSDavid du Colombier sleeptime = 60;
716*7dd7cddfSDavid du Colombier } /* End while */
717*7dd7cddfSDavid du Colombier
718*7dd7cddfSDavid du Colombier } /* End of done */
719*7dd7cddfSDavid du Colombier
720*7dd7cddfSDavid du Colombier /*****************************************************************************/
721*7dd7cddfSDavid du Colombier
cleanup()722*7dd7cddfSDavid du Colombier cleanup()
723*7dd7cddfSDavid du Colombier
724*7dd7cddfSDavid du Colombier {
725*7dd7cddfSDavid du Colombier
726*7dd7cddfSDavid du Colombier int w;
727*7dd7cddfSDavid du Colombier
728*7dd7cddfSDavid du Colombier /*
729*7dd7cddfSDavid du Colombier *
730*7dd7cddfSDavid du Colombier * Only needed if we're running separate read and write processes. Makes sure the
731*7dd7cddfSDavid du Colombier * write process is killed after the read process has successfully finished with
732*7dd7cddfSDavid du Colombier * all the jobs. sendsignal() returns a -1 if there's nobody to signal so things
733*7dd7cddfSDavid du Colombier * work when we're running a single process.
734*7dd7cddfSDavid du Colombier *
735*7dd7cddfSDavid du Colombier */
736*7dd7cddfSDavid du Colombier
737*7dd7cddfSDavid du Colombier while ( sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ;
738*7dd7cddfSDavid du Colombier
739*7dd7cddfSDavid du Colombier } /* End of cleanup */
740*7dd7cddfSDavid du Colombier
741*7dd7cddfSDavid du Colombier /*****************************************************************************/
742*7dd7cddfSDavid du Colombier
readblock(fd_in)743*7dd7cddfSDavid du Colombier readblock(fd_in)
744*7dd7cddfSDavid du Colombier
745*7dd7cddfSDavid du Colombier int fd_in; /* current input file */
746*7dd7cddfSDavid du Colombier
747*7dd7cddfSDavid du Colombier {
748*7dd7cddfSDavid du Colombier
749*7dd7cddfSDavid du Colombier static long blocknum = 1;
750*7dd7cddfSDavid du Colombier
751*7dd7cddfSDavid du Colombier /*
752*7dd7cddfSDavid du Colombier *
753*7dd7cddfSDavid du Colombier * Fills the input buffer with the next block, provided we're all done with the
754*7dd7cddfSDavid du Colombier * last one. Blocks from fd_in are stored in array block[]. head is the index
755*7dd7cddfSDavid du Colombier * of the next byte in block[] that's supposed to go to the printer. tail points
756*7dd7cddfSDavid du Colombier * one past the last byte in the current block. head is adjusted in writeblock()
757*7dd7cddfSDavid du Colombier * after each successful write, while head and tail are reset here each time
758*7dd7cddfSDavid du Colombier * a new block is read. Returns the number of bytes left in the current block.
759*7dd7cddfSDavid du Colombier * Read errors cause the program to abort. The fake status message that's put out
760*7dd7cddfSDavid du Colombier * in quiet mode is only so you can look at the log file and know something's
761*7dd7cddfSDavid du Colombier * happening - take it out if you want.
762*7dd7cddfSDavid du Colombier *
763*7dd7cddfSDavid du Colombier */
764*7dd7cddfSDavid du Colombier
765*7dd7cddfSDavid du Colombier if ( head >= tail ) { /* done with the last block */
766*7dd7cddfSDavid du Colombier if ( (tail = read(fd_in, block, blocksize)) == -1 )
767*7dd7cddfSDavid du Colombier error(FATAL, "error reading input file");
768*7dd7cddfSDavid du Colombier if ( quiet == TRUE && tail > 0 ) /* put out a fake message? */
769*7dd7cddfSDavid du Colombier logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++);
770*7dd7cddfSDavid du Colombier head = 0;
771*7dd7cddfSDavid du Colombier } /* End if */
772*7dd7cddfSDavid du Colombier
773*7dd7cddfSDavid du Colombier return(tail - head);
774*7dd7cddfSDavid du Colombier
775*7dd7cddfSDavid du Colombier } /* End of readblock */
776*7dd7cddfSDavid du Colombier
777*7dd7cddfSDavid du Colombier /*****************************************************************************/
778*7dd7cddfSDavid du Colombier
writeblock()779*7dd7cddfSDavid du Colombier writeblock()
780*7dd7cddfSDavid du Colombier
781*7dd7cddfSDavid du Colombier {
782*7dd7cddfSDavid du Colombier
783*7dd7cddfSDavid du Colombier int count; /* bytes successfully written */
784*7dd7cddfSDavid du Colombier
785*7dd7cddfSDavid du Colombier /*
786*7dd7cddfSDavid du Colombier *
787*7dd7cddfSDavid du Colombier * Called from send() when it's OK to send the next block to the printer. head
788*7dd7cddfSDavid du Colombier * is adjusted after the write, and the number of bytes that were successfully
789*7dd7cddfSDavid du Colombier * written is returned to the caller.
790*7dd7cddfSDavid du Colombier *
791*7dd7cddfSDavid du Colombier */
792*7dd7cddfSDavid du Colombier
793*7dd7cddfSDavid du Colombier if ( (count = write(ttyo, &block[head], tail - head)) == -1 )
794*7dd7cddfSDavid du Colombier error(FATAL, "error writing to %s", line);
795*7dd7cddfSDavid du Colombier else if ( count == 0 )
796*7dd7cddfSDavid du Colombier error(FATAL, "printer appears to be offline");
797*7dd7cddfSDavid du Colombier
798*7dd7cddfSDavid du Colombier head += count;
799*7dd7cddfSDavid du Colombier return(count);
800*7dd7cddfSDavid du Colombier
801*7dd7cddfSDavid du Colombier } /* End of writeblock */
802*7dd7cddfSDavid du Colombier
803*7dd7cddfSDavid du Colombier /*****************************************************************************/
804*7dd7cddfSDavid du Colombier
getstatus(t)805*7dd7cddfSDavid du Colombier getstatus(t)
806*7dd7cddfSDavid du Colombier
807*7dd7cddfSDavid du Colombier int t; /* sleep time after sending '\024' */
808*7dd7cddfSDavid du Colombier
809*7dd7cddfSDavid du Colombier {
810*7dd7cddfSDavid du Colombier
811*7dd7cddfSDavid du Colombier int gotline = FALSE; /* value returned by readline() */
812*7dd7cddfSDavid du Colombier int state = nostatus; /* representation of the current state */
813*7dd7cddfSDavid du Colombier int mesgch; /* to restore mesg[] when tostdout == TRUE */
814*7dd7cddfSDavid du Colombier
815*7dd7cddfSDavid du Colombier static int laststate = NOSTATUS; /* last state recognized */
816*7dd7cddfSDavid du Colombier
817*7dd7cddfSDavid du Colombier /*
818*7dd7cddfSDavid du Colombier *
819*7dd7cddfSDavid du Colombier * Looks for things coming back from the printer on the communications line, parses
820*7dd7cddfSDavid du Colombier * complete lines retrieved by readline(), and returns an integer representation
821*7dd7cddfSDavid du Colombier * of the current printer status to the caller. If nothing was available a status
822*7dd7cddfSDavid du Colombier * request (control T) is sent to the printer and nostatus is returned to the
823*7dd7cddfSDavid du Colombier * caller (provided quiet isn't TRUE). Interactive mode either never returns from
824*7dd7cddfSDavid du Colombier * readline() or returns FALSE.
825*7dd7cddfSDavid du Colombier *
826*7dd7cddfSDavid du Colombier */
827*7dd7cddfSDavid du Colombier
828*7dd7cddfSDavid du Colombier if ( canread == TRUE && (gotline = readline()) == TRUE ) {
829*7dd7cddfSDavid du Colombier state = parsemesg();
830*7dd7cddfSDavid du Colombier if ( state != laststate || state == UNKNOWN || mesgptr != mesg || debug == ON )
831*7dd7cddfSDavid du Colombier logit("%s", mesg);
832*7dd7cddfSDavid du Colombier
833*7dd7cddfSDavid du Colombier if ( tostdout == TRUE && currentstate != START ) {
834*7dd7cddfSDavid du Colombier mesgch = *mesgptr;
835*7dd7cddfSDavid du Colombier *mesgptr = '\0';
836*7dd7cddfSDavid du Colombier fprintf(stdout, "%s", mesg);
837*7dd7cddfSDavid du Colombier fflush(stdout);
838*7dd7cddfSDavid du Colombier *mesgptr = mesgch; /* for ERROR in send() and done() */
839*7dd7cddfSDavid du Colombier } /* End if */
840*7dd7cddfSDavid du Colombier return(laststate = state);
841*7dd7cddfSDavid du Colombier } /* End if */
842*7dd7cddfSDavid du Colombier
843*7dd7cddfSDavid du Colombier if ( (quiet == FALSE || currentstate != SEND) &&
844*7dd7cddfSDavid du Colombier (tostdout == FALSE || currentstate == START) && interactive == FALSE ) {
845*7dd7cddfSDavid du Colombier if ( Write(ttyo, "\024", 1) != 1 )
846*7dd7cddfSDavid du Colombier error(FATAL, "printer appears to be offline");
847*7dd7cddfSDavid du Colombier if ( t > 0 ) Rest(t);
848*7dd7cddfSDavid du Colombier } /* End if */
849*7dd7cddfSDavid du Colombier
850*7dd7cddfSDavid du Colombier return(nostatus);
851*7dd7cddfSDavid du Colombier
852*7dd7cddfSDavid du Colombier } /* End of getstatus */
853*7dd7cddfSDavid du Colombier
854*7dd7cddfSDavid du Colombier /*****************************************************************************/
855*7dd7cddfSDavid du Colombier
parsemesg()856*7dd7cddfSDavid du Colombier parsemesg()
857*7dd7cddfSDavid du Colombier
858*7dd7cddfSDavid du Colombier {
859*7dd7cddfSDavid du Colombier
860*7dd7cddfSDavid du Colombier char *e; /* end of printer message in mesg[] */
861*7dd7cddfSDavid du Colombier char *key, *val; /* keyword/value strings in sbuf[] */
862*7dd7cddfSDavid du Colombier char *p; /* for converting to lower case etc. */
863*7dd7cddfSDavid du Colombier int i; /* where *key was found in status[] */
864*7dd7cddfSDavid du Colombier
865*7dd7cddfSDavid du Colombier /*
866*7dd7cddfSDavid du Colombier *
867*7dd7cddfSDavid du Colombier * Parsing the lines that readline() stores in mesg[] is messy, and what's done
868*7dd7cddfSDavid du Colombier * here isn't completely correct nor as fast as it could be. The general format
869*7dd7cddfSDavid du Colombier * of lines that come back from the printer (assuming no data loss) is:
870*7dd7cddfSDavid du Colombier *
871*7dd7cddfSDavid du Colombier * str%%[ key: val; key: val; key: val ]%%\n
872*7dd7cddfSDavid du Colombier *
873*7dd7cddfSDavid du Colombier * where str can be most anything not containing a newline and printer reports
874*7dd7cddfSDavid du Colombier * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and
875*7dd7cddfSDavid du Colombier * end with a newline. Usually we'll have the string or printer report but not
876*7dd7cddfSDavid du Colombier * both. For most jobs the leading string will be empty, but could be anything
877*7dd7cddfSDavid du Colombier * generated on a printer and returned over the communications line using the
878*7dd7cddfSDavid du Colombier * PostScript print operator. I'll assume PostScript jobs are well behaved and
879*7dd7cddfSDavid du Colombier * never bracket their messages with "%%[ " and " ]%%" strings that delimit status
880*7dd7cddfSDavid du Colombier * or error messages.
881*7dd7cddfSDavid du Colombier *
882*7dd7cddfSDavid du Colombier * Printer reports consist of one or more key/val pairs, and what we're interested
883*7dd7cddfSDavid du Colombier * in (status or error indications) may not be the first pair in the list. In
884*7dd7cddfSDavid du Colombier * addition we'll sometimes want the value associated with a keyword (eg. when
885*7dd7cddfSDavid du Colombier * key = status) and other times we'll want the keyword (eg. when key = Error or
886*7dd7cddfSDavid du Colombier * Flushing). The last pair isn't terminated by a semicolon and a value string
887*7dd7cddfSDavid du Colombier * often contains many space separated words and it can even include colons in
888*7dd7cddfSDavid du Colombier * meaningful places. I've also decided to continue converting things to lower
889*7dd7cddfSDavid du Colombier * case before doing the lookup in status[]. The isupper() test is for Berkeley
890*7dd7cddfSDavid du Colombier * systems.
891*7dd7cddfSDavid du Colombier *
892*7dd7cddfSDavid du Colombier */
893*7dd7cddfSDavid du Colombier
894*7dd7cddfSDavid du Colombier if ( *(mesgptr = find("%%[ ", mesg)) != '\0' && *(e = find(" ]%%", mesgptr+4)) != '\0' ) {
895*7dd7cddfSDavid du Colombier strcpy(sbuf, mesgptr+4); /* don't change mesg[] */
896*7dd7cddfSDavid du Colombier sbuf[e-mesgptr-4] = '\0'; /* ignore the trailing " ]%%" */
897*7dd7cddfSDavid du Colombier
898*7dd7cddfSDavid du Colombier for ( key = strtok(sbuf, " :"); key != NULL; key = strtok(NULL, " :") ) {
899*7dd7cddfSDavid du Colombier if ( (val = strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0 )
900*7dd7cddfSDavid du Colombier key = val;
901*7dd7cddfSDavid du Colombier
902*7dd7cddfSDavid du Colombier for ( ; *key == ' '; key++ ) ; /* skip any leading spaces */
903*7dd7cddfSDavid du Colombier for ( p = key; *p; p++ ) /* convert to lower case */
904*7dd7cddfSDavid du Colombier if ( *p == ':' ) {
905*7dd7cddfSDavid du Colombier *p = '\0';
906*7dd7cddfSDavid du Colombier break;
907*7dd7cddfSDavid du Colombier } else if ( isupper(*p) ) *p = tolower(*p);
908*7dd7cddfSDavid du Colombier
909*7dd7cddfSDavid du Colombier for ( i = 0; status[i].state != NULL; i++ )
910*7dd7cddfSDavid du Colombier if ( strcmp(status[i].state, key) == 0 )
911*7dd7cddfSDavid du Colombier return(status[i].val);
912*7dd7cddfSDavid du Colombier } /* End for */
913*7dd7cddfSDavid du Colombier } else if ( strcmp(mesg, "CONVERSATION ENDED.\n") == 0 )
914*7dd7cddfSDavid du Colombier return(DISCONNECT);
915*7dd7cddfSDavid du Colombier
916*7dd7cddfSDavid du Colombier return(mesgptr == '\0' ? nostatus : UNKNOWN);
917*7dd7cddfSDavid du Colombier
918*7dd7cddfSDavid du Colombier } /* End of parsemesg */
919*7dd7cddfSDavid du Colombier
920*7dd7cddfSDavid du Colombier /*****************************************************************************/
921*7dd7cddfSDavid du Colombier
find(str1,str2)922*7dd7cddfSDavid du Colombier char *find(str1, str2)
923*7dd7cddfSDavid du Colombier
924*7dd7cddfSDavid du Colombier char *str1; /* look for this string */
925*7dd7cddfSDavid du Colombier char *str2; /* in this one */
926*7dd7cddfSDavid du Colombier
927*7dd7cddfSDavid du Colombier {
928*7dd7cddfSDavid du Colombier
929*7dd7cddfSDavid du Colombier char *s1, *s2; /* can't change str1 or str2 too fast */
930*7dd7cddfSDavid du Colombier
931*7dd7cddfSDavid du Colombier /*
932*7dd7cddfSDavid du Colombier *
933*7dd7cddfSDavid du Colombier * Looks for *str1 in string *str2. Returns a pointer to the start of the substring
934*7dd7cddfSDavid du Colombier * if it's found or to the end of string str2 otherwise.
935*7dd7cddfSDavid du Colombier *
936*7dd7cddfSDavid du Colombier */
937*7dd7cddfSDavid du Colombier
938*7dd7cddfSDavid du Colombier for ( ; *str2 != '\0'; str2++ ) {
939*7dd7cddfSDavid du Colombier for ( s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++ ) ;
940*7dd7cddfSDavid du Colombier if ( *s1 == '\0' )
941*7dd7cddfSDavid du Colombier break;
942*7dd7cddfSDavid du Colombier } /* End for */
943*7dd7cddfSDavid du Colombier
944*7dd7cddfSDavid du Colombier return(str2);
945*7dd7cddfSDavid du Colombier
946*7dd7cddfSDavid du Colombier } /* End of find */
947*7dd7cddfSDavid du Colombier
948*7dd7cddfSDavid du Colombier /*****************************************************************************/
949*7dd7cddfSDavid du Colombier
clearline()950*7dd7cddfSDavid du Colombier clearline()
951*7dd7cddfSDavid du Colombier
952*7dd7cddfSDavid du Colombier {
953*7dd7cddfSDavid du Colombier
954*7dd7cddfSDavid du Colombier /*
955*7dd7cddfSDavid du Colombier *
956*7dd7cddfSDavid du Colombier * Reads characters from the input line until nothing's left. Don't do anything if
957*7dd7cddfSDavid du Colombier * we're currently running separate read and write processes.
958*7dd7cddfSDavid du Colombier *
959*7dd7cddfSDavid du Colombier */
960*7dd7cddfSDavid du Colombier
961*7dd7cddfSDavid du Colombier if ( whatami == READWRITE )
962*7dd7cddfSDavid du Colombier while ( readline() != FALSE ) ;
963*7dd7cddfSDavid du Colombier
964*7dd7cddfSDavid du Colombier } /* End of clearline */
965*7dd7cddfSDavid du Colombier
966*7dd7cddfSDavid du Colombier /*****************************************************************************/
967*7dd7cddfSDavid du Colombier
sendsignal(sig)968*7dd7cddfSDavid du Colombier sendsignal(sig)
969*7dd7cddfSDavid du Colombier
970*7dd7cddfSDavid du Colombier int sig; /* this goes to the other process */
971*7dd7cddfSDavid du Colombier
972*7dd7cddfSDavid du Colombier {
973*7dd7cddfSDavid du Colombier
974*7dd7cddfSDavid du Colombier /*
975*7dd7cddfSDavid du Colombier *
976*7dd7cddfSDavid du Colombier * Sends signal sig to the other process if we're running as separate read and
977*7dd7cddfSDavid du Colombier * write processes. Returns the result of the kill if there's someone else to
978*7dd7cddfSDavid du Colombier * signal or -1 if we're running alone.
979*7dd7cddfSDavid du Colombier *
980*7dd7cddfSDavid du Colombier */
981*7dd7cddfSDavid du Colombier
982*7dd7cddfSDavid du Colombier if ( whatami != READWRITE && otherpid > 1 )
983*7dd7cddfSDavid du Colombier return(kill(otherpid, sig));
984*7dd7cddfSDavid du Colombier
985*7dd7cddfSDavid du Colombier return(-1);
986*7dd7cddfSDavid du Colombier
987*7dd7cddfSDavid du Colombier } /* End of sendsignal */
988*7dd7cddfSDavid du Colombier
989*7dd7cddfSDavid du Colombier /*****************************************************************************/
990*7dd7cddfSDavid du Colombier
interrupt(sig)991*7dd7cddfSDavid du Colombier void interrupt(sig)
992*7dd7cddfSDavid du Colombier
993*7dd7cddfSDavid du Colombier int sig; /* signal that we caught */
994*7dd7cddfSDavid du Colombier
995*7dd7cddfSDavid du Colombier {
996*7dd7cddfSDavid du Colombier
997*7dd7cddfSDavid du Colombier /*
998*7dd7cddfSDavid du Colombier *
999*7dd7cddfSDavid du Colombier * Caught a signal - all except joinsig cause the program to quit. joinsig is the
1000*7dd7cddfSDavid du Colombier * signal sent by the writer to the reader after all the jobs have been transmitted.
1001*7dd7cddfSDavid du Colombier * Used to tell the read process when it can start looking for the end of the job.
1002*7dd7cddfSDavid du Colombier *
1003*7dd7cddfSDavid du Colombier */
1004*7dd7cddfSDavid du Colombier
1005*7dd7cddfSDavid du Colombier signal(sig, SIG_IGN);
1006*7dd7cddfSDavid du Colombier
1007*7dd7cddfSDavid du Colombier if ( sig != joinsig ) {
1008*7dd7cddfSDavid du Colombier x_stat |= FATAL;
1009*7dd7cddfSDavid du Colombier if ( canread == TRUE )
1010*7dd7cddfSDavid du Colombier if ( interactive == FALSE )
1011*7dd7cddfSDavid du Colombier error(NON_FATAL, "signal %d abort", sig);
1012*7dd7cddfSDavid du Colombier else error(NON_FATAL, "quitting");
1013*7dd7cddfSDavid du Colombier quit(sig);
1014*7dd7cddfSDavid du Colombier } /* End if */
1015*7dd7cddfSDavid du Colombier
1016*7dd7cddfSDavid du Colombier writedone = TRUE;
1017*7dd7cddfSDavid du Colombier signal(joinsig, interrupt);
1018*7dd7cddfSDavid du Colombier
1019*7dd7cddfSDavid du Colombier } /* End of interrupt */
1020*7dd7cddfSDavid du Colombier
1021*7dd7cddfSDavid du Colombier /*****************************************************************************/
1022*7dd7cddfSDavid du Colombier
logit(mesg,a1,a2,a3)1023*7dd7cddfSDavid du Colombier logit(mesg, a1, a2, a3)
1024*7dd7cddfSDavid du Colombier
1025*7dd7cddfSDavid du Colombier char *mesg; /* control string */
1026*7dd7cddfSDavid du Colombier unsigned a1, a2, a3; /* and possible arguments */
1027*7dd7cddfSDavid du Colombier
1028*7dd7cddfSDavid du Colombier {
1029*7dd7cddfSDavid du Colombier
1030*7dd7cddfSDavid du Colombier /*
1031*7dd7cddfSDavid du Colombier *
1032*7dd7cddfSDavid du Colombier * Simple routine that's used to write a message to the log file.
1033*7dd7cddfSDavid du Colombier *
1034*7dd7cddfSDavid du Colombier */
1035*7dd7cddfSDavid du Colombier
1036*7dd7cddfSDavid du Colombier if ( mesg != NULL && fp_log != NULL ) {
1037*7dd7cddfSDavid du Colombier fprintf(fp_log, mesg, a1, a2, a3);
1038*7dd7cddfSDavid du Colombier fflush(fp_log);
1039*7dd7cddfSDavid du Colombier } /* End if */
1040*7dd7cddfSDavid du Colombier
1041*7dd7cddfSDavid du Colombier } /* End of logit */
1042*7dd7cddfSDavid du Colombier
1043*7dd7cddfSDavid du Colombier /*****************************************************************************/
1044*7dd7cddfSDavid du Colombier
error(kind,mesg,a1,a2,a3)1045*7dd7cddfSDavid du Colombier error(kind, mesg, a1, a2, a3)
1046*7dd7cddfSDavid du Colombier
1047*7dd7cddfSDavid du Colombier int kind; /* FATAL or NON_FATAL error */
1048*7dd7cddfSDavid du Colombier char *mesg; /* error message control string */
1049*7dd7cddfSDavid du Colombier unsigned a1, a2, a3; /* control string arguments */
1050*7dd7cddfSDavid du Colombier
1051*7dd7cddfSDavid du Colombier {
1052*7dd7cddfSDavid du Colombier
1053*7dd7cddfSDavid du Colombier FILE *fp_err;
1054*7dd7cddfSDavid du Colombier
1055*7dd7cddfSDavid du Colombier /*
1056*7dd7cddfSDavid du Colombier *
1057*7dd7cddfSDavid du Colombier * Called when we've run into some kind of program error. First *mesg is printed
1058*7dd7cddfSDavid du Colombier * using the control string arguments a?. If kind is FATAL and we're not ignoring
1059*7dd7cddfSDavid du Colombier * errors the program will be terminated. If mesg is NULL or *mesg is the NULL
1060*7dd7cddfSDavid du Colombier * string nothing will be printed.
1061*7dd7cddfSDavid du Colombier *
1062*7dd7cddfSDavid du Colombier */
1063*7dd7cddfSDavid du Colombier
1064*7dd7cddfSDavid du Colombier fp_err = (fp_log != NULL) ? fp_log : stderr;
1065*7dd7cddfSDavid du Colombier
1066*7dd7cddfSDavid du Colombier if ( mesg != NULL && *mesg != '\0' ) {
1067*7dd7cddfSDavid du Colombier fprintf(fp_err, "%s: ", prog_name);
1068*7dd7cddfSDavid du Colombier fprintf(fp_err, mesg, a1, a2, a3);
1069*7dd7cddfSDavid du Colombier putc('\n', fp_err);
1070*7dd7cddfSDavid du Colombier } /* End if */
1071*7dd7cddfSDavid du Colombier
1072*7dd7cddfSDavid du Colombier x_stat |= kind;
1073*7dd7cddfSDavid du Colombier
1074*7dd7cddfSDavid du Colombier if ( kind != NON_FATAL && ignore == OFF )
1075*7dd7cddfSDavid du Colombier quit(SIGTERM);
1076*7dd7cddfSDavid du Colombier
1077*7dd7cddfSDavid du Colombier } /* End of error */
1078*7dd7cddfSDavid du Colombier
1079*7dd7cddfSDavid du Colombier /*****************************************************************************/
1080*7dd7cddfSDavid du Colombier
quit(sig)1081*7dd7cddfSDavid du Colombier quit(sig)
1082*7dd7cddfSDavid du Colombier
1083*7dd7cddfSDavid du Colombier int sig;
1084*7dd7cddfSDavid du Colombier
1085*7dd7cddfSDavid du Colombier {
1086*7dd7cddfSDavid du Colombier
1087*7dd7cddfSDavid du Colombier int w;
1088*7dd7cddfSDavid du Colombier
1089*7dd7cddfSDavid du Colombier /*
1090*7dd7cddfSDavid du Colombier *
1091*7dd7cddfSDavid du Colombier * Makes sure everything is properly cleaned up if there's a signal or FATAL error
1092*7dd7cddfSDavid du Colombier * that should cause the program to terminate. The sleep by the write process is
1093*7dd7cddfSDavid du Colombier * to help give the reset sequence a chance to reach the printer before we break
1094*7dd7cddfSDavid du Colombier * the connection - primarily for printers connected to Datakit. There's a very
1095*7dd7cddfSDavid du Colombier * slight chance the reset sequence that's sent to the printer could get us stuck
1096*7dd7cddfSDavid du Colombier * here. Simplest solution is don't bother to send it - everything works without it.
1097*7dd7cddfSDavid du Colombier * Flushing ttyo would be better, but means yet another system dependent procedure
1098*7dd7cddfSDavid du Colombier * in ifdef.c! I'll leave things be for now.
1099*7dd7cddfSDavid du Colombier *
1100*7dd7cddfSDavid du Colombier * Obscure problem on PS-810 turbos says wait a bit after sending an interrupt.
1101*7dd7cddfSDavid du Colombier * Seem to remember the printer getting into a bad state immediately after the
1102*7dd7cddfSDavid du Colombier * top was opened when the toner light was on. A sleep after sending the ctrl-C
1103*7dd7cddfSDavid du Colombier * seemed to fix things.
1104*7dd7cddfSDavid du Colombier *
1105*7dd7cddfSDavid du Colombier */
1106*7dd7cddfSDavid du Colombier
1107*7dd7cddfSDavid du Colombier signal(sig, SIG_IGN);
1108*7dd7cddfSDavid du Colombier ignore = ON;
1109*7dd7cddfSDavid du Colombier
1110*7dd7cddfSDavid du Colombier while ( sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid && w != -1 ) ;
1111*7dd7cddfSDavid du Colombier
1112*7dd7cddfSDavid du Colombier setupstdin(2);
1113*7dd7cddfSDavid du Colombier
1114*7dd7cddfSDavid du Colombier if ( currentstate != NOTCONNECTED ) {
1115*7dd7cddfSDavid du Colombier if ( sendctrlC == TRUE ) {
1116*7dd7cddfSDavid du Colombier Write(ttyo, "\003", 1);
1117*7dd7cddfSDavid du Colombier Rest(1); /* PS-810 turbo problem?? */
1118*7dd7cddfSDavid du Colombier } /* End if */
1119*7dd7cddfSDavid du Colombier Write(ttyo, "\004", 1);
1120*7dd7cddfSDavid du Colombier } /* End if */
1121*7dd7cddfSDavid du Colombier
1122*7dd7cddfSDavid du Colombier alarm(0); /* prevents sleep() loop on V9 systems */
1123*7dd7cddfSDavid du Colombier Rest(2);
1124*7dd7cddfSDavid du Colombier
1125*7dd7cddfSDavid du Colombier exit(x_stat);
1126*7dd7cddfSDavid du Colombier
1127*7dd7cddfSDavid du Colombier } /* End of quit */
1128*7dd7cddfSDavid du Colombier
1129*7dd7cddfSDavid du Colombier /*****************************************************************************/
1130*7dd7cddfSDavid du Colombier
Rest(t)1131*7dd7cddfSDavid du Colombier Rest(t)
1132*7dd7cddfSDavid du Colombier
1133*7dd7cddfSDavid du Colombier int t;
1134*7dd7cddfSDavid du Colombier
1135*7dd7cddfSDavid du Colombier {
1136*7dd7cddfSDavid du Colombier
1137*7dd7cddfSDavid du Colombier /*
1138*7dd7cddfSDavid du Colombier *
1139*7dd7cddfSDavid du Colombier * Used to replace sleep() calls. Only needed if we're running the program as
1140*7dd7cddfSDavid du Colombier * a read and write process and don't want to have the read process sleep. Most
1141*7dd7cddfSDavid du Colombier * sleeps are in the code because of the non-blocking read used by the single
1142*7dd7cddfSDavid du Colombier * process implementation. Probably should be a macro.
1143*7dd7cddfSDavid du Colombier *
1144*7dd7cddfSDavid du Colombier */
1145*7dd7cddfSDavid du Colombier
1146*7dd7cddfSDavid du Colombier if ( t > 0 && canwrite == TRUE )
1147*7dd7cddfSDavid du Colombier sleep(t);
1148*7dd7cddfSDavid du Colombier
1149*7dd7cddfSDavid du Colombier } /* End of Rest */
1150*7dd7cddfSDavid du Colombier
1151*7dd7cddfSDavid du Colombier /*****************************************************************************/
1152*7dd7cddfSDavid du Colombier
Read(fd,buf,n)1153*7dd7cddfSDavid du Colombier Read(fd, buf, n)
1154*7dd7cddfSDavid du Colombier
1155*7dd7cddfSDavid du Colombier int fd;
1156*7dd7cddfSDavid du Colombier char *buf;
1157*7dd7cddfSDavid du Colombier int n;
1158*7dd7cddfSDavid du Colombier
1159*7dd7cddfSDavid du Colombier {
1160*7dd7cddfSDavid du Colombier
1161*7dd7cddfSDavid du Colombier int count;
1162*7dd7cddfSDavid du Colombier
1163*7dd7cddfSDavid du Colombier /*
1164*7dd7cddfSDavid du Colombier *
1165*7dd7cddfSDavid du Colombier * Used to replace some of the read() calls. Only needed if we're running separate
1166*7dd7cddfSDavid du Colombier * read and write processes. Should only be used to replace read calls on ttyi.
1167*7dd7cddfSDavid du Colombier * Always returns 0 to the caller if the process doesn't have its READ flag set.
1168*7dd7cddfSDavid du Colombier * Probably should be a macro.
1169*7dd7cddfSDavid du Colombier *
1170*7dd7cddfSDavid du Colombier */
1171*7dd7cddfSDavid du Colombier
1172*7dd7cddfSDavid du Colombier if ( canread == TRUE ) {
1173*7dd7cddfSDavid du Colombier if ( (count = read(fd, buf, n)) == -1 && errno == EINTR )
1174*7dd7cddfSDavid du Colombier count = 0;
1175*7dd7cddfSDavid du Colombier } else count = 0;
1176*7dd7cddfSDavid du Colombier
1177*7dd7cddfSDavid du Colombier return(count);
1178*7dd7cddfSDavid du Colombier
1179*7dd7cddfSDavid du Colombier } /* End of Read */
1180*7dd7cddfSDavid du Colombier
1181*7dd7cddfSDavid du Colombier /*****************************************************************************/
1182*7dd7cddfSDavid du Colombier
Write(fd,buf,n)1183*7dd7cddfSDavid du Colombier Write(fd, buf, n)
1184*7dd7cddfSDavid du Colombier
1185*7dd7cddfSDavid du Colombier int fd;
1186*7dd7cddfSDavid du Colombier char *buf;
1187*7dd7cddfSDavid du Colombier int n;
1188*7dd7cddfSDavid du Colombier
1189*7dd7cddfSDavid du Colombier {
1190*7dd7cddfSDavid du Colombier
1191*7dd7cddfSDavid du Colombier int count;
1192*7dd7cddfSDavid du Colombier
1193*7dd7cddfSDavid du Colombier /*
1194*7dd7cddfSDavid du Colombier *
1195*7dd7cddfSDavid du Colombier * Used to replace some of the write() calls. Again only needed if we're running
1196*7dd7cddfSDavid du Colombier * separate read and write processes. Should only be used to replace write calls
1197*7dd7cddfSDavid du Colombier * on ttyo. Always returns n to the caller if the process doesn't have its WRITE
1198*7dd7cddfSDavid du Colombier * flag set. Should also probably be a macro.
1199*7dd7cddfSDavid du Colombier *
1200*7dd7cddfSDavid du Colombier */
1201*7dd7cddfSDavid du Colombier
1202*7dd7cddfSDavid du Colombier if ( canwrite == TRUE ) {
1203*7dd7cddfSDavid du Colombier if ( (count = write(fd, buf, n)) == -1 && errno == EINTR )
1204*7dd7cddfSDavid du Colombier count = n;
1205*7dd7cddfSDavid du Colombier } else count = n;
1206*7dd7cddfSDavid du Colombier
1207*7dd7cddfSDavid du Colombier return(count);
1208*7dd7cddfSDavid du Colombier
1209*7dd7cddfSDavid du Colombier } /* End of Write */
1210*7dd7cddfSDavid du Colombier
1211*7dd7cddfSDavid du Colombier /*****************************************************************************/
1212*7dd7cddfSDavid du Colombier
1213