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