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