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