xref: /illumos-gate/usr/src/cmd/lp/filter/postscript/postio/ifdef.c (revision d2a70789f056fc6c9ce3ab047b52126d80b0e3da)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 /*
33  *
34  * Conditionally compiled routines for setting up and reading the line. Things
35  * were getting out of hand with all the ifdefs, and even though this defeats
36  * part of the purpose of conditional complilation directives, I think it's easier
37  * to follow this way. Thanks to Alan Buckwalter for the System V DKHOST code.
38  *
39  * postio now can be run as separate read and write processes, but requires that
40  * you write a procedure called resetline() and perhaps modify readline() some.
41  * I've already tested the code on System V and it seems to work. Ninth Edition
42  * and BSD code may be missing.
43  *
44  * By request I've changed the way some of the setupline() procedures (eg. in the
45  * System V implementation) handle things when no line has been given. If line is
46  * NULL the new setupline() procedures try to continue, assuming whoever called
47  * postio connected stdout to the printer. Things will only work if we can read
48  * and write stdout!
49  *
50  */
51 
52 
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <fcntl.h>
56 #include <signal.h>
57 #include <sys/types.h>
58 #include <errno.h>
59 
60 #include "ifdef.h"			/* conditional header file inclusion */
61 #include "gen.h"			/* general purpose definitions */
62 
63 FILE	*fp_ttyi = NULL, *fp_ttyo;
64 char	*ptr = mesg;
65 extern FILE *fp_log;
66 
67 
68 /*****************************************************************************/
69 
70 
71 #ifdef SYSV
72 void
73 setupline(void)
74 {
75     struct termio	termio;
76     struct termios	termios;
77     char buf[100];
78 
79 
80 /*
81  *
82  * Line initialization for SYSV. For now if no line is given (ie. line == NULL )
83  * we continue on as before using stdout as ttyi and ttyo. Doesn't work when we're
84  * running in interactive mode or forcing stuff that comes back from the printer
85  * to stdout. Both cases are now caught by a test that's been added to routine
86  * initialize(). The change is primarily for the version of lp that's available
87  * with SVR3.2.
88  *
89  */
90 
91 #ifdef DKHOST
92     if ( line != NULL && *line != '/' )  {
93 	if ( strncmp(line, "DK:", 3) == 0 )
94 	    line += 3;
95 	dkhost_connect();
96     } else
97 #endif
98 
99     if ( line == NULL ) {
100 	ttyi = fileno(stdout);
101     }
102     else if ( (ttyi = open(line, O_RDWR)) == -1 )
103 	error(FATAL, "can't open %s", line);
104 
105     if ( (ttyo = dup(ttyi)) == -1 ) {
106 	error(FATAL, "can't dup file descriptor for %s", line);
107     }
108 
109     if ( fcntl(ttyi, F_SETFL, O_NDELAY) == -1 ) {
110 	error(FATAL, "fcntl error - F_SETFL");
111     }
112 
113     if ( ioctl(ttyi, TCGETS, &termios) < 0 ) {
114     	if ( ioctl(ttyi, TCGETA, &termio) == -1 ) {
115 		error(FATAL, "ioctl error - TCGETA");
116     	}
117     	stopbits = (stopbits == 1) ? 0 : CSTOPB;
118 
119     	termio.c_iflag = IXON | IGNCR;
120     	termio.c_oflag = 0;
121     	termio.c_cflag = HUPCL | CREAD | CS8 | stopbits |
122 		((line != NULL) ? baudrate : (termio.c_cflag & CBAUD));
123     	termio.c_lflag = 0;
124     	termio.c_cc[VMIN] = termio.c_cc[VTIME] = 0;
125     	if ( ioctl(ttyi, TCSETA, &termio) == -1 ) {
126 		error(FATAL, "ioctl error - TCSETA");
127 	}
128     } else {
129     	stopbits = (stopbits == 1) ? 0 : CSTOPB;
130 
131     	termios.c_iflag = IXON | IGNCR;
132     	termios.c_oflag = 0;
133     	termios.c_cflag = HUPCL | CREAD | CS8 | stopbits |
134 		((line != NULL) ? baudrate : cfgetospeed(&termios));
135     	termios.c_lflag = 0;
136     	termios.c_cc[VMIN] = termios.c_cc[VTIME] = 0;
137     	if ( ioctl(ttyi, TCSETS, &termios) == -1 ) {
138 		error(FATAL, "ioctl error - TCSETS");
139 	}
140     }
141 
142     if ( ioctl(ttyi, TCFLSH, 2) == -1 ) {
143 	error(FATAL, "ioctl error - TCFLSH");
144     }
145     fp_ttyi = fdopen(ttyi, "r");
146 
147     if ( line == NULL ) {
148 	line = "stdout";
149     }
150 
151 }   /* End of setupline */
152 
153 
154 /*****************************************************************************/
155 
156 
157 int
158 resetline(void)
159 {
160 
161 
162     int			flags;		/* for turning O_NDELAY off */
163     struct termio	termio;		/* so we can reset flow control */
164 
165 
166 /*
167  *
168  * Only used if we're running the program as separate read and write processes.
169  * Called from split() after the initial connection has been made and returns
170  * TRUE if two processes should work. Don't know if the O_NDELAY stuff is really
171  * needed, but setting c_cc[VMIN] to 1 definitely is. If we leave it be (as a 0)
172  * the read in readline() won't block!
173  *
174  */
175 
176 
177     if ( (flags = fcntl(ttyi, F_GETFL, 0)) == -1 )
178 	error(FATAL, "fcntl error - F_GETFL");
179 
180     flags &= ~O_NDELAY;
181 
182     if ( fcntl(ttyi, F_SETFL, flags) == -1 )
183 	error(FATAL, "fcntl error - F_SETFL");
184 
185     if ( ioctl(ttyi, TCGETA, &termio) == -1 )
186 	error(FATAL, "ioctl error - TCGETA");
187 
188     termio.c_iflag &= ~IXANY;
189     termio.c_iflag |= IXON | IXOFF;
190     termio.c_cc[VMIN] = 1;
191     termio.c_cc[VTIME] = 0;
192 
193     if ( ioctl(ttyi, TCSETA, &termio) == -1 )
194 	error(FATAL, "ioctl error - TCSETA");
195 
196     return(TRUE);
197 
198 }   /* End of resetline */
199 
200 
201 /*****************************************************************************/
202 
203 
204 void
205 setupstdin(int mode)
206     /* what to do with stdin settings */
207 {
208     struct termio		termio;
209 
210     static int			saved = FALSE;
211     static struct termio	oldtermio;
212 
213 
214 /*
215  *
216  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
217  * stdin. Expect something like raw mode with no echo will be set up. Explicit
218  * code to ensure blocking reads probably isn't needed because blocksize is set
219  * to 1 when we're in interactive mode, but I've included it anyway.
220  *
221  */
222 
223 
224     if ( interactive == TRUE )
225 	switch ( mode )  {
226 	    case 0:
227 		if ( isatty(0) != 1 )
228 		    error(FATAL, "stdin not a terminal - can't run interactive mode");
229 		if ( ioctl(0, TCGETA, &oldtermio) == -1 )
230 		    error(FATAL, "can't save terminal settings");
231 		saved = TRUE;
232 		break;
233 
234 	    case 1:
235 		termio = oldtermio;
236 		termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
237 		termio.c_cc[VMIN] = 1;
238 		termio.c_cc[VTIME] = 0;
239 		ioctl(0, TCSETA, &termio);
240 		break;
241 
242 	    case 2:
243 		if ( saved == TRUE )
244 		    ioctl(0, TCSETA, &oldtermio);
245 		break;
246 	}   /* End switch */
247 
248 }   /* End of setupstdin */
249 
250 
251 /*****************************************************************************/
252 
253 
254 int
255 readline(void)
256 {
257 
258 
259     int		n;			/* read() return value */
260     int		ch;			/* for interactive mode */
261 
262     static int	tries = 0;		/* consecutive times read returned 0 */
263 
264 
265 /*
266  *
267  * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
268  * or until no more characters are available. Characters are put in mesg[], the
269  * string is terminated with '\0' when we're done with a line and TRUE is returned
270  * to the caller. If complete line wasn't available FALSE is returned. Interactive
271  * mode should loop here forever, except during start(), echoing characters to
272  * stdout. If it happens to leave FALSE should be returned. The non-blocking read
273  * gets us out until split() is called.
274  *
275  * Some users (apparently just on 3B2 DKHOST systems) have had problems with the
276  * two process implementation that's forced me to kludge things up some. When a
277  * printer (on those systems) is turned off while postio is transmitting files
278  * the write process hangs in writeblock() (postio.c) - it's typically in the
279  * middle of a write() call, while the read() call (below) continually returns 0.
280  * In the original code readline() returned FALSE when read() returned 0 and we
281  * get into a loop that never ends - because the write process is hung. In the
282  * one process implementation having read return 0 is legitimate because the line
283  * is opened for no delay, but with two processes the read() blocks and a return
284  * value of 0 should never occur. From my point of view the real problem is that
285  * the write() call hangs on 3B2 DKHOST systems and apparently doesn't anywhere
286  * else. If the write returned anything less than or equal to 0 writeblock() would
287  * shut things down. The kludge I've implemented counts the number of consecutive
288  * times read() returns a 0 and if it exceeds a limit (100) the read process will
289  * shut things down. In fact one return of 0 from read() when we're in the two
290  * process mode is undoubtedly sufficient and no counting should be necessary!!!
291  * Moving the check to getstatus() should also work and is probably where things
292  * belong.
293  *
294  */
295 
296     if ( interactive == FALSE )  {
297 	while ( (n = read(ttyi, ptr, 1)) != 0 )  {
298 	    if ( n < 0 )
299 		if ( errno == EINTR )
300 		    continue;
301 		else error(FATAL, "error reading %s", line);
302 	    tries = 0;
303 	    if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
304 		*(ptr+1) = '\0';
305 		if ( *ptr == '\004' )
306 		    strcpy(ptr, "%%[ status: endofjob ]%%\n");
307 		ptr = mesg;
308 		return(TRUE);
309 	    }   /* End if */
310 	    ptr++;
311 	}   /* End while */
312 	if ( canread == TRUE && canwrite == FALSE )	/* read process kludge */
313 	    if ( ++tries > 100 )
314 		error(FATAL, "printer appears to be offline - shutting down");
315 	return(FALSE);
316     }	/* End if */
317 
318     if ( canwrite == TRUE )		/* don't block during start() */
319 	return(FALSE);
320 
321     while ( (ch = getc(fp_ttyi)) != EOF )
322 	putc(ch, stdout);
323     return(FALSE);
324 
325 }   /* End of readline */
326 #endif
327 
328 
329 /*****************************************************************************/
330 
331 
332 #ifdef V9
333 #include <ipc.h>
334 
335 char	tbuf[256];			/* temporary input buffer */
336 char	*nptr = tbuf;			/* next character comes from here */
337 char	*eptr = tbuf;			/* one past the last character in tbuf */
338 
339 
340 setupline()
341 
342 
343 {
344 
345 
346     struct sgttyb	sgtty;
347     struct ttydevb	ttydev;		/* for setting up the line */
348     static struct tchars	tchar = { '\377',	/* interrupt */
349 					  '\377',	/* quit */
350 					  '\021',	/* start output */
351 					  '\023',	/* stop output */
352 					  '\377',	/* end-of-file */
353 					  '\377'	/* input delimiter */
354 					};
355 
356 /*
357  *
358  * Line initialization for V9.
359  *
360  */
361 
362 
363     if ( line == NULL )  {
364 	ttyi = ttyo = 1;
365 	return;
366     }	/* End if */
367 
368     if ( strncmp(line, "/cs", 3) == 0 ) {
369 	if ((ttyi = ipcopen(line, "")) < 0) {
370 		sleep(5);	/* wait for Datakit to hangup */
371 		if ((ttyi = ipcopen(line, "")) < 0)
372 			error(FATAL, "can't ipcopen %s", line);
373 	}
374     } else if ( (ttyi = open(line, O_RDWR)) == -1 )
375 	error(FATAL, "can't open %s", line);
376 
377     if ( (ttyo = dup(ttyi)) == -1 )
378 	error(FATAL, "can't dup file descriptor for %s", line);
379 
380     if ( ioctl(ttyi, FIOPUSHLD, &tty_ld) == -1 )
381 	error(FATAL, "ioctl error - FIOPUSHLD");
382 
383     if ( ioctl(ttyi, TIOCGDEV, &ttydev) == -1 )
384 	error(FATAL, "ioctl error - TIOCGDEV");
385 
386     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
387 	error(FATAL, "ioctl error - TIOCGETP");
388 
389     sgtty.sg_flags &= ~ECHO;
390     sgtty.sg_flags &= ~CRMOD;
391     sgtty.sg_flags |= CBREAK;
392     ttydev.ispeed = baudrate;
393     ttydev.ospeed = baudrate;
394 
395     if ( ioctl(ttyi, TIOCSDEV, &ttydev) == -1 )
396 	error(FATAL, "ioctl error - TIOCSDEV");
397 
398     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
399 	error(FATAL, "ioctl error - TIOCSETP");
400 
401     if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
402 	error(FATAL, "ioctl error - TIOCSETC");
403 
404     fp_ttyi = fdopen(ttyi, "r");
405 
406 }   /* End of setupline */
407 
408 
409 /*****************************************************************************/
410 
411 
412 resetline()
413 
414 
415 {
416 
417 
418     struct sgttyb	sgtty;
419 
420 
421 /*
422  *
423  * Only used if we're running the program as separate read and write processes.
424  * Called from split() after the initial connection has been made and returns
425  * TRUE if two processes should work. Haven't tested or even compiled the stuff
426  * for separate read and write processes on Ninth Edition systems - no guarantees
427  * even though we return TRUE!
428  *
429  */
430 
431 
432     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
433 	error(FATAL, "ioctl error - TIOCGETP");
434 
435     sgtty.sg_flags |= TANDEM;
436 
437     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
438 	error(FATAL, "ioctl error - TIOCSETP");
439 
440     return(TRUE);
441 
442 }   /* End of resetline */
443 
444 
445 /*****************************************************************************/
446 
447 
448 setupstdin(mode)
449 
450 
451     int		mode;			/* what to do with stdin settings */
452 
453 
454 {
455 
456 
457     struct sgttyb		sgtty;
458 
459     static int			saved = FALSE;
460     static struct sgttyb	oldsgtty;
461 
462 
463 /*
464  *
465  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
466  * stdin. Expect something like raw mode with no echo will be set up. Need to make
467  * sure interrupt and quit still work - they're the only good way to exit when
468  * we're running interactive mode. I haven't tested or even compiled this code
469  * so there are no guarantees.
470  *
471  */
472 
473 
474     if ( interactive == TRUE )
475 	switch ( mode )  {
476 	    case 0:
477 		if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
478 		    error(FATAL, "can't save terminal settings");
479 		saved = TRUE;
480 		break;
481 
482 	    case 1:
483 		sgtty = oldsgtty;
484 		sgtty.sg_flags &= ~ECHO;
485 		sgtty.sg_flags |= CBREAK;
486 		ioctl(0, TIOCSETP, &sgtty);
487 		break;
488 
489 	    case 2:
490 		if ( saved == TRUE )
491 		    ioctl(0, TIOCSETP, &oldsgtty);
492 		break;
493 	}   /* End switch */
494 
495 }   /* End of setupstdin */
496 
497 
498 /*****************************************************************************/
499 
500 
501 readline()
502 
503 
504 {
505 
506 
507     int		n;			/* read() return value */
508     int		ch;			/* for interactive mode */
509 
510 
511 /*
512  *
513  * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
514  * and transfers each line to the mesg[] array. Everything available on ttyi is
515  * initially stored in tbuf[] and a line at a time is transferred from there to
516  * mesg[]. The string in mesg[] is terminated with a '\0' and TRUE is returned to
517  * the caller when we find a newline, EOF, or reach the end of the mesg[] array.
518  * If nothing is available on ttyi we return FALSE if a single process is being
519  * used for reads and writes, while in the two process implementation we force a
520  * one character read. Interactive mode loops here forever, except during start(),
521  * echoing everything that comes back on ttyi to stdout. The performance of a
522  * simple getc/putc loop for interactive mode was unacceptable when run under mux
523  * and has been replaced by more complicated code. When layers wasn't involved
524  * the getc/putc loop worked well.
525  *
526  */
527 
528 
529     if ( interactive == FALSE )  {
530 	while ( 1 )  {
531 	    while ( nptr < eptr )  {	/* grab characters from tbuf */
532 		*ptr = *nptr++;
533 		if ( *ptr == '\r' ) continue;
534 		if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
535 		    *(ptr+1) = '\0';
536 		    if ( *ptr == '\004' )
537 			strcpy(ptr, "%%[ status: endofjob ]%%\n");
538 		    ptr = mesg;
539 		    return(TRUE);
540 		}   /* End if */
541 		++ptr;
542 	    }	/* End for */
543 
544 	    nptr = eptr = tbuf;
545 	    if ( ioctl(ttyi, FIONREAD, &n) < 0 )
546 		if ( errno == EINTR )
547 		    continue;
548 		else error(FATAL, "ioctl error - FIONREAD");
549 	    if ( n <= 0 )
550 		if ( canwrite == TRUE )
551 		    return(FALSE);
552 	    n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
553 	    if ( (n = read(ttyi, tbuf, n)) < 0 )
554 		if ( errno == EINTR )
555 		    continue;
556 		else error(FATAL, "error reading line %s", line);
557 	    else eptr = nptr + n;
558 	}   /* End while */
559     }	/* End if */
560 
561     if ( canwrite == TRUE )		/* don't block during start() */
562 	return(FALSE);
563 
564     while ( 1 )  {			/* only interactive mode gets here */
565 	if ( ioctl(ttyi, FIONREAD, &n) < 0 )
566 	    error(FATAL, "ioctl error - FIONREAD");
567 	n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
568 	if ( (n = read(ttyi, tbuf, n)) < 0 )
569 	    error(FATAL, "error reading line %s", line);
570 	else if ( n == 0 )		/* should not happen */
571 	    error(FATAL, "end of file in interactive mode");
572 	if ( write(1, tbuf, n) != n )
573 	    error(FATAL, "error writing to stdout");
574     }	/* End while */
575 
576     return(FALSE);
577 
578 }   /* End of readline */
579 #endif
580 
581 
582 /*****************************************************************************/
583 
584 
585 #ifdef BSD4_2
586 setupline()
587 
588 
589 {
590 
591 
592     struct sgttyb	sgtty;
593     static struct tchars	tchar = { '\377',	/* interrupt */
594 					  '\377',	/* quit */
595 					  '\021',	/* start output */
596 					  '\023',	/* stop output */
597 					  '\377',	/* end-of-file */
598 					  '\377'	/* input delimiter */
599 					};
600     long	lmodes;
601     int		disc = NTTYDISC;
602 
603 
604 /*
605  *
606  * Line initialization for BSD4_2. As in the System V code, if no line is given
607  * (ie. line == NULL) we continue on as before using stdout as ttyi and ttyo.
608  *
609  */
610 
611 
612     if ( line == NULL )
613 	ttyi = fileno(stdout);
614     else if ( (ttyi = open(line, O_RDWR)) == -1 )
615 	error(FATAL, "can't open %s", line);
616 
617     if ( (ttyo = dup(ttyi)) == -1 )
618 	error(FATAL, "can't dup file descriptor for %s", line);
619 
620     if (ioctl(ttyi, TIOCSETD, &disc) == -1 )
621 	error(FATAL, "ioctl error - TIOCSETD");
622 
623     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
624 	error(FATAL, "ioctl error - TIOCGETP");
625 
626     if ( ioctl(ttyi, TIOCLGET, &lmodes) == -1 )
627 	error(FATAL, "ioctl error - TIOCLGET");
628 
629     sgtty.sg_flags &= ~ECHO;
630     sgtty.sg_flags &= ~CRMOD;
631     sgtty.sg_flags |= CBREAK;
632     sgtty.sg_ispeed = baudrate;
633     sgtty.sg_ospeed = baudrate;
634     lmodes |= LDECCTQ;
635 
636     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
637 	error(FATAL, "ioctl error - TIOCSETP");
638 
639     if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
640 	error(FATAL, "ioctl error - TIOCSETC");
641 
642     if ( ioctl(ttyi, TIOCLSET, &lmodes) == -1 )
643 	error(FATAL, "ioctl error - TIOCLSET");
644 
645     fp_ttyi = fdopen(ttyi, "r");
646 
647 }   /* End of setupline */
648 
649 
650 /*****************************************************************************/
651 
652 
653 resetline()
654 
655 
656 {
657 
658 
659     struct sgttyb	sgtty;
660 
661 
662 /*
663  *
664  * Only used if we're running the program as separate read and write processes.
665  * Called from split() after the initial connection has been made and returns
666  * TRUE if two processes should work. Haven't tested or even compiled the stuff
667  * for separate read and write processes on Berkeley systems - no guarantees
668  * even though we return TRUE!
669  *
670  */
671 
672 
673     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
674 	error(FATAL, "ioctl error - TIOCGETP");
675 
676     sgtty.sg_flags |= TANDEM;
677 
678     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
679 	error(FATAL, "ioctl error - TIOCSETP");
680 
681     return(TRUE);
682 
683 }   /* End of resetline */
684 
685 
686 /*****************************************************************************/
687 
688 
689 setupstdin(mode)
690 
691 
692     int		mode;			/* what to do with stdin settings */
693 
694 
695 {
696 
697 
698     struct sgttyb		sgtty;
699 
700     static int			saved = FALSE;
701     static struct sgttyb	oldsgtty;
702 
703 
704 /*
705  *
706  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
707  * stdin. Expect something like raw mode with no echo will be set up. Need to make
708  * sure interrupt and quit still work - they're the only good way to exit when
709  * we're running interactive mode. I haven't tested or even compiled this code
710  * so there are no guarantees.
711  *
712  */
713 
714 
715     if ( interactive == TRUE )
716 	switch ( mode )  {
717 	    case 0:
718 		if ( isatty(0) != 1 )
719 		    error(FATAL, "stdin not a terminal - can't run interactive mode");
720 		if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
721 		    error(FATAL, "can't save terminal settings");
722 		saved = TRUE;
723 		break;
724 
725 	    case 1:
726 		sgtty = oldsgtty;
727 		sgtty.sg_flags &= ~ECHO;
728 		sgtty.sg_flags |= CBREAK;
729 		ioctl(0, TIOCSETP, &sgtty);
730 		break;
731 
732 	    case 2:
733 		if ( saved == TRUE )
734 		    ioctl(0, TIOCSETP, &oldsgtty);
735 		break;
736 	}   /* End switch */
737 
738 }   /* End of setupstdin */
739 
740 
741 /*****************************************************************************/
742 
743 
744 readline()
745 
746 
747 {
748 
749 
750     int		n;			/* read() return value */
751     int		ch;			/* for interactive mode */
752 
753 
754 /*
755  *
756  * Reads characters coming back from the printer on ttyo up to a newline (or EOF)
757  * or until no more characters are available. Characters are put in mesg[], the
758  * string is terminated with '\0' when we're done with a line and TRUE is returned
759  * to the caller. If complete line wasn't available FALSE is returned. Interactive
760  * mode should loop here forever, except during start(), echoing characters to
761  * stdout. If it happens to leave FALSE should be returned. Probably should read
762  * everything available on ttyi into a temporary buffer and work from there rather
763  * than reading one character at a time.
764  *
765  */
766 
767 
768     if ( interactive == FALSE )  {
769 	while ( 1 )  {
770 	    if ( ioctl(ttyi, FIONREAD, &n) < 0 )
771 		if ( errno == EINTR )
772 		    continue;
773 		else error(FATAL, "ioctl error - FIONREAD");
774 	    if ( n <= 0 )
775 		if ( canwrite == TRUE )
776 		    return(FALSE);
777 		else n = 1;
778 	    for ( ; n > 0; n-- )  {
779 		/*if ( read(ttyi, ptr, 1) < 0 )*/
780 		if ( (*ptr = getc(fp_ttyi)) == EOF )
781 		    if ( errno == EINTR )
782 			continue;
783 		    else error(FATAL, "error reading %s", line);
784 		if ( *ptr == '\r' ) continue;
785 		if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
786 		    *(ptr+1) = '\0';
787 		    if ( *ptr == '\004' )
788 			strcpy(ptr, "%%[ status: endofjob ]%%\n");
789 		    ptr = mesg;
790 		    return(TRUE);
791 		}   /* End if */
792 		++ptr;
793 	    }	/* End for */
794 	}   /* End while */
795     }	/* End if */
796 
797     if ( canwrite == TRUE )		/* don't block during start() */
798 	return(FALSE);
799 
800     while ( (ch = getc(fp_ttyi)) != EOF )
801 	putc(ch, stdout);
802     return(FALSE);
803 
804 }   /* End of readline */
805 
806 
807 /*****************************************************************************/
808 
809 
810 /*	@(#)strspn.c	1.2	*/
811 /*LINTLIBRARY*/
812 /*
813  * Return the number of characters in the maximum leading segment
814  * of string which consists solely of characters from charset.
815  */
816 int
817 strspn(string, charset)
818 char	*string;
819 register char	*charset;
820 {
821 	register char *p, *q;
822 
823 	for(q=string; *q != '\0'; ++q) {
824 		for(p=charset; *p != '\0' && *p != *q; ++p)
825 			;
826 		if(*p == '\0')
827 			break;
828 	}
829 	return(q-string);
830 }
831 
832 /*	@(#)strpbrk.c	1.2	*/
833 /*LINTLIBRARY*/
834 /*
835  * Return ptr to first occurance of any character from `brkset'
836  * in the character string `string'; NULL if none exists.
837  */
838 
839 char *
840 strpbrk(string, brkset)
841 register char *string, *brkset;
842 {
843 	register char *p;
844 
845 	do {
846 		for(p=brkset; *p != '\0' && *p != *string; ++p)
847 			;
848 		if(*p != '\0')
849 			return(string);
850 	}
851 	while(*string++);
852 	return((char*)0);
853 }
854 
855 /*	@(#)strtok.c	1.2	*/
856 /*	3.0 SID #	1.2	*/
857 /*LINTLIBRARY*/
858 /*
859  * uses strpbrk and strspn to break string into tokens on
860  * sequentially subsequent calls.  returns NULL when no
861  * non-separator characters remain.
862  * `subsequent' calls are calls with first argument NULL.
863  */
864 
865 
866 extern int strspn();
867 extern char *strpbrk();
868 
869 char *
870 strtok(string, sepset)
871 char	*string, *sepset;
872 {
873 	register char	*p, *q, *r;
874 	static char	*savept;
875 
876 	/*first or subsequent call*/
877 	p = (string == (char*)0)? savept: string;
878 
879 	if(p == 0)		/* return if no tokens remaining */
880 		return((char*)0);
881 
882 	q = p + strspn(p, sepset);	/* skip leading separators */
883 
884 	if(*q == '\0')		/* return if no tokens remaining */
885 		return((char*)0);
886 
887 	if((r = strpbrk(q, sepset)) == (char*)0)	/* move past token */
888 		savept = 0;	/* indicate this is last token */
889 	else {
890 		*r = '\0';
891 		savept = ++r;
892 	}
893 	return(q);
894 }
895 #endif
896 
897 
898 /*****************************************************************************/
899 
900 
901 #ifdef DKHOST
902 
903 short	dkrmode[3] = {DKR_TIME, 0, 0};
904 
905 dkhost_connect()
906 
907 
908 {
909 
910 
911     int		ofd;			/* for saving and restoring stderr */
912     int		dfd;
913     int		retrytime = 5;
914 
915 
916 /*
917  *
918  * Tries to connect to a Datakit destination. The extra stuff I've added to save
919  * and later restore stderr is primarily for our spooling setup at Murray Hill.
920  * postio is usually called with stderr directed to a file that will be returned
921  * to the user when the job finishes printing. Problems encountered by dkdial(),
922  * like busy messages, go to stderr but don't belong in the user's mail. They'll
923  * be temporarily directed to the log file. After we've connected stderr will be
924  * restored.
925  *
926  */
927 
928 
929     if ( *line == '\0' )
930 	error(FATAL, "incomplete Datakit line");
931 
932     if ( fp_log != stderr )  {		/* save stderr - redirect dkdial errors */
933 	ofd = dup(2);
934 	close(2);
935 	dup(fileno(fp_log));
936     }	/* End if */
937 
938     while ( (dfd = ttyi = dkdial(line)) < 0 )  {
939 	if ( retrytime < 0 )
940 	    error(FATAL, "can't connect to %s", line);
941 	sleep(retrytime++);
942 	if ( retrytime > 60 )
943 	    retrytime = 60;
944     }	/* End while */
945 
946     if ( fp_log != stderr )  {		/* restore stderr */
947 	close(2);
948 	dup(ofd);
949 	close(ofd);
950     }	/* End if */
951 
952     if ( ioctl(ttyi, DIOCRMODE, dkrmode) == -1 )
953 	error(FATAL, "ioctl error - DIOCRMODE");
954 
955     line = dtnamer(dkminor(ttyi));
956 
957     if ( (ttyi = open(line, O_RDWR)) == -1 )
958 	error(FATAL, "can't open %s", line);
959 
960     close(dfd);
961 
962 }   /* End of dkhost_connect */
963 #endif
964 
965 
966 /*****************************************************************************/
967 
968