1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)more.c 5.12 (Berkeley) 05/13/87"; 15 #endif not lint 16 17 /* 18 ** more.c - General purpose tty output filter and file perusal program 19 ** 20 ** by Eric Shienbrood, UC Berkeley 21 ** 22 ** modified by Geoff Peck, UCB to add underlining, single spacing 23 ** modified by John Foderaro, UCB to add -c and MORE environment variable 24 */ 25 26 #include <stdio.h> 27 #include <sys/types.h> 28 #include <ctype.h> 29 #include <signal.h> 30 #include <errno.h> 31 #include <sgtty.h> 32 #include <setjmp.h> 33 #include <sys/stat.h> 34 #include <sys/file.h> 35 #include <sys/exec.h> 36 37 #define HELPFILE "/usr/lib/more.help" 38 #define VI "/usr/ucb/vi" 39 40 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 41 #define Ftell(f) file_pos 42 #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 43 #define Getc(f) (++file_pos, getc(f)) 44 #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 45 46 #define MBIT CBREAK 47 #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 48 49 #define TBUFSIZ 1024 50 #define LINSIZ 256 51 #define ctrl(letter) ('letter' & 077) 52 #define RUBOUT '\177' 53 #define ESC '\033' 54 #define QUIT '\034' 55 56 struct sgttyb otty, savetty; 57 long file_pos, file_size; 58 int fnum, no_intty, no_tty, slow_tty; 59 int dum_opt, dlines, onquit(), end_it(), chgwinsz(); 60 int onsusp(); 61 int nscroll = 11; /* Number of lines scrolled by 'd' */ 62 int fold_opt = 1; /* Fold long lines */ 63 int stop_opt = 1; /* Stop after form feeds */ 64 int ssp_opt = 0; /* Suppress white space */ 65 int ul_opt = 1; /* Underline as best we can */ 66 int promptlen; 67 int Currline; /* Line we are currently at */ 68 int startup = 1; 69 int firstf = 1; 70 int notell = 1; 71 int docrterase = 0; 72 int docrtkill = 0; 73 int bad_so; /* True if overwriting does not turn off standout */ 74 int inwait, Pause, errors; 75 int within; /* true if we are within a file, 76 false if we are between files */ 77 int hard, dumb, noscroll, hardtabs, clreol, eatnl; 78 int catch_susp; /* We should catch the SIGTSTP signal */ 79 char **fnames; /* The list of file names */ 80 int nfiles; /* Number of files left to process */ 81 char *shell; /* The name of the shell to use */ 82 int shellp; /* A previous shell command exists */ 83 char ch; 84 jmp_buf restore; 85 char Line[LINSIZ]; /* Line buffer */ 86 int Lpp = 24; /* lines per page */ 87 char *Clear; /* clear screen */ 88 char *eraseln; /* erase line */ 89 char *Senter, *Sexit;/* enter and exit standout mode */ 90 char *ULenter, *ULexit; /* enter and exit underline mode */ 91 char *chUL; /* underline character */ 92 char *chBS; /* backspace character */ 93 char *Home; /* go to home */ 94 char *cursorm; /* cursor movement */ 95 char cursorhome[40]; /* contains cursor movement to home */ 96 char *EodClr; /* clear rest of screen */ 97 char *tgetstr(); 98 int Mcol = 80; /* number of columns */ 99 int Wrap = 1; /* set if automargins */ 100 int soglitch; /* terminal has standout mode glitch */ 101 int ulglitch; /* terminal has underline mode glitch */ 102 int pstate = 0; /* current UL state */ 103 long fseek(); 104 char *getenv(); 105 struct { 106 long chrctr, line; 107 } context, screen_start; 108 extern char PC; /* pad character */ 109 extern short ospeed; 110 111 112 main(argc, argv) 113 int argc; 114 char *argv[]; 115 { 116 register FILE *f; 117 register char *s; 118 register char *p; 119 register char ch; 120 register int left; 121 int prnames = 0; 122 int initopt = 0; 123 int srchopt = 0; 124 int clearit = 0; 125 int initline; 126 char initbuf[80]; 127 FILE *checkf(); 128 129 nfiles = argc; 130 fnames = argv; 131 initterm (); 132 nscroll = Lpp/2 - 1; 133 if (nscroll <= 0) 134 nscroll = 1; 135 if(s = getenv("MORE")) argscan(s); 136 while (--nfiles > 0) { 137 if ((ch = (*++fnames)[0]) == '-') { 138 argscan(*fnames+1); 139 } 140 else if (ch == '+') { 141 s = *fnames; 142 if (*++s == '/') { 143 srchopt++; 144 for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 145 *p++ = *s++; 146 *p = '\0'; 147 } 148 else { 149 initopt++; 150 for (initline = 0; *s != '\0'; s++) 151 if (isdigit (*s)) 152 initline = initline*10 + *s -'0'; 153 --initline; 154 } 155 } 156 else break; 157 } 158 /* allow clreol only if Home and eraseln and EodClr strings are 159 * defined, and in that case, make sure we are in noscroll mode 160 */ 161 if(clreol) 162 { 163 if((Home == NULL) || (*Home == '\0') || 164 (eraseln == NULL) || (*eraseln == '\0') || 165 (EodClr == NULL) || (*EodClr == '\0') ) 166 clreol = 0; 167 else noscroll = 1; 168 } 169 if (dlines == 0) 170 dlines = Lpp - (noscroll ? 1 : 2); 171 left = dlines; 172 if (nfiles > 1) 173 prnames++; 174 if (!no_intty && nfiles == 0) { 175 fputs("Usage: ",stderr); 176 fputs(argv[0],stderr); 177 fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 178 exit(1); 179 } 180 else 181 f = stdin; 182 if (!no_tty) { 183 signal(SIGQUIT, onquit); 184 signal(SIGINT, end_it); 185 signal(SIGWINCH, chgwinsz); 186 if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 187 signal(SIGTSTP, onsusp); 188 catch_susp++; 189 } 190 stty (fileno(stderr), &otty); 191 } 192 if (no_intty) { 193 if (no_tty) 194 copy_file (stdin); 195 else { 196 if ((ch = Getc (f)) == '\f') 197 doclear(); 198 else { 199 Ungetc (ch, f); 200 if (noscroll && (ch != EOF)) { 201 if (clreol) 202 home (); 203 else 204 doclear (); 205 } 206 } 207 if (srchopt) 208 { 209 search (initbuf, stdin, 1); 210 if (noscroll) 211 left--; 212 } 213 else if (initopt) 214 skiplns (initline, stdin); 215 screen (stdin, left); 216 } 217 no_intty = 0; 218 prnames++; 219 firstf = 0; 220 } 221 222 while (fnum < nfiles) { 223 if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 224 context.line = context.chrctr = 0; 225 Currline = 0; 226 if (firstf) setjmp (restore); 227 if (firstf) { 228 firstf = 0; 229 if (srchopt) 230 { 231 search (initbuf, f, 1); 232 if (noscroll) 233 left--; 234 } 235 else if (initopt) 236 skiplns (initline, f); 237 } 238 else if (fnum < nfiles && !no_tty) { 239 setjmp (restore); 240 left = command (fnames[fnum], f); 241 } 242 if (left != 0) { 243 if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 244 if (clreol) 245 home (); 246 else 247 doclear (); 248 if (prnames) { 249 if (bad_so) 250 erase (0); 251 if (clreol) 252 cleareol (); 253 pr("::::::::::::::"); 254 if (promptlen > 14) 255 erase (14); 256 printf ("\n"); 257 if(clreol) cleareol(); 258 printf("%s\n", fnames[fnum]); 259 if(clreol) cleareol(); 260 printf("::::::::::::::\n"); 261 if (left > Lpp - 4) 262 left = Lpp - 4; 263 } 264 if (no_tty) 265 copy_file (f); 266 else { 267 within++; 268 screen(f, left); 269 within = 0; 270 } 271 } 272 setjmp (restore); 273 fflush(stdout); 274 fclose(f); 275 screen_start.line = screen_start.chrctr = 0L; 276 context.line = context.chrctr = 0L; 277 } 278 fnum++; 279 firstf = 0; 280 } 281 reset_tty (); 282 exit(0); 283 } 284 285 argscan(s) 286 char *s; 287 { 288 for (dlines = 0; *s != '\0'; s++) 289 { 290 switch (*s) 291 { 292 case '0': case '1': case '2': 293 case '3': case '4': case '5': 294 case '6': case '7': case '8': 295 case '9': 296 dlines = dlines*10 + *s - '0'; 297 break; 298 case 'd': 299 dum_opt = 1; 300 break; 301 case 'l': 302 stop_opt = 0; 303 break; 304 case 'f': 305 fold_opt = 0; 306 break; 307 case 'p': 308 noscroll++; 309 break; 310 case 'c': 311 clreol++; 312 break; 313 case 's': 314 ssp_opt = 1; 315 break; 316 case 'u': 317 ul_opt = 0; 318 break; 319 } 320 } 321 } 322 323 324 /* 325 ** Check whether the file named by fs is an ASCII file which the user may 326 ** access. If it is, return the opened file. Otherwise return NULL. 327 */ 328 329 FILE * 330 checkf (fs, clearfirst) 331 register char *fs; 332 int *clearfirst; 333 { 334 struct stat stbuf; 335 register FILE *f; 336 char c; 337 338 if (stat (fs, &stbuf) == -1) { 339 fflush(stdout); 340 if (clreol) 341 cleareol (); 342 perror(fs); 343 return (NULL); 344 } 345 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 346 printf("\n*** %s: directory ***\n\n", fs); 347 return (NULL); 348 } 349 if ((f=Fopen(fs, "r")) == NULL) { 350 fflush(stdout); 351 perror(fs); 352 return (NULL); 353 } 354 /* Try to see whether it is an ASCII file */ 355 if (magic(f)) { 356 printf("\n******** %s: Not a text file ********\n\n", fs); 357 fclose (f); 358 return (NULL); 359 } 360 c = Getc(f); 361 if (c == '\f') 362 *clearfirst = 1; 363 else { 364 *clearfirst = 0; 365 Ungetc (c, f); 366 } 367 if ((file_size = stbuf.st_size) == 0) 368 file_size = 0x7fffffffffffffffL; 369 return (f); 370 } 371 372 /* 373 * Check for file magic numbers. This code would best 374 * be shared with the file(1) program or, perhaps, more 375 * should not try and be so smart? 376 */ 377 magic(f) 378 FILE *f; 379 { 380 long magic; 381 382 magic = getw(f); 383 if (ftell(f) < sizeof magic) 384 rewind(f); /* reset file position */ 385 else 386 fseek(f, -sizeof (magic), L_INCR); /* reset file position */ 387 return (magic == 0405 || magic == OMAGIC || magic == NMAGIC || 388 magic == 0411 || magic == ZMAGIC || magic == 0177545); 389 } 390 391 /* 392 ** A real function, for the tputs routine in termlib 393 */ 394 395 putch (ch) 396 char ch; 397 { 398 putchar (ch); 399 } 400 401 /* 402 ** Print out the contents of the file f, one screenful at a time. 403 */ 404 405 #define STOP -10 406 407 screen (f, num_lines) 408 register FILE *f; 409 register int num_lines; 410 { 411 register int c; 412 register int nchars; 413 int length; /* length of current line */ 414 static int prev_len = 1; /* length of previous line */ 415 416 for (;;) { 417 while (num_lines > 0 && !Pause) { 418 if ((nchars = getline (f, &length)) == EOF) 419 { 420 if (clreol) 421 clreos(); 422 return; 423 } 424 if (ssp_opt && length == 0 && prev_len == 0) 425 continue; 426 prev_len = length; 427 if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 428 erase (0); 429 /* must clear before drawing line since tabs on some terminals 430 * do not erase what they tab over. 431 */ 432 if (clreol) 433 cleareol (); 434 prbuf (Line, length); 435 if (nchars < promptlen) 436 erase (nchars); /* erase () sets promptlen to 0 */ 437 else promptlen = 0; 438 /* is this needed? 439 * if (clreol) 440 * cleareol(); /* must clear again in case we wrapped * 441 */ 442 if (nchars < Mcol || !fold_opt) 443 prbuf("\n", 1); /* will turn off UL if necessary */ 444 if (nchars == STOP) 445 break; 446 num_lines--; 447 } 448 if (pstate) { 449 tputs(ULexit, 1, putch); 450 pstate = 0; 451 } 452 fflush(stdout); 453 if ((c = Getc(f)) == EOF) 454 { 455 if (clreol) 456 clreos (); 457 return; 458 } 459 460 if (Pause && clreol) 461 clreos (); 462 Ungetc (c, f); 463 setjmp (restore); 464 Pause = 0; startup = 0; 465 if ((num_lines = command (NULL, f)) == 0) 466 return; 467 if (hard && promptlen > 0) 468 erase (0); 469 if (noscroll && num_lines >= dlines) 470 { 471 if (clreol) 472 home(); 473 else 474 doclear (); 475 } 476 screen_start.line = Currline; 477 screen_start.chrctr = Ftell (f); 478 } 479 } 480 481 /* 482 ** Come here if a quit signal is received 483 */ 484 485 onquit() 486 { 487 signal(SIGQUIT, SIG_IGN); 488 if (!inwait) { 489 putchar ('\n'); 490 if (!startup) { 491 signal(SIGQUIT, onquit); 492 longjmp (restore, 1); 493 } 494 else 495 Pause++; 496 } 497 else if (!dum_opt && notell) { 498 write (2, "[Use q or Q to quit]", 20); 499 promptlen += 20; 500 notell = 0; 501 } 502 signal(SIGQUIT, onquit); 503 } 504 505 /* 506 ** Come here if a signal for a window size change is received 507 */ 508 509 chgwinsz() 510 { 511 struct winsize win; 512 513 (void) signal(SIGWINCH, SIG_IGN); 514 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 515 if (win.ws_row != 0) { 516 Lpp = win.ws_row; 517 nscroll = Lpp/2 - 1; 518 if (nscroll <= 0) 519 nscroll = 1; 520 dlines = Lpp - (noscroll ? 1 : 2); 521 } 522 if (win.ws_col != 0) 523 Mcol = win.ws_col; 524 } 525 (void) signal(SIGWINCH, chgwinsz); 526 } 527 528 /* 529 ** Clean up terminal state and exit. Also come here if interrupt signal received 530 */ 531 532 end_it () 533 { 534 535 reset_tty (); 536 if (clreol) { 537 putchar ('\r'); 538 clreos (); 539 fflush (stdout); 540 } 541 else if (!clreol && (promptlen > 0)) { 542 kill_line (); 543 fflush (stdout); 544 } 545 else 546 write (2, "\n", 1); 547 _exit(0); 548 } 549 550 copy_file(f) 551 register FILE *f; 552 { 553 register int c; 554 555 while ((c = getc(f)) != EOF) 556 putchar(c); 557 } 558 559 /* Simplified printf function */ 560 561 printf (fmt, args) 562 register char *fmt; 563 int args; 564 { 565 register int *argp; 566 register char ch; 567 register int ccount; 568 569 ccount = 0; 570 argp = &args; 571 while (*fmt) { 572 while ((ch = *fmt++) != '%') { 573 if (ch == '\0') 574 return (ccount); 575 ccount++; 576 putchar (ch); 577 } 578 switch (*fmt++) { 579 case 'd': 580 ccount += printd (*argp); 581 break; 582 case 's': 583 ccount += pr ((char *)*argp); 584 break; 585 case '%': 586 ccount++; 587 argp--; 588 putchar ('%'); 589 break; 590 case '0': 591 return (ccount); 592 default: 593 break; 594 } 595 ++argp; 596 } 597 return (ccount); 598 599 } 600 601 /* 602 ** Print an integer as a string of decimal digits, 603 ** returning the length of the print representation. 604 */ 605 606 printd (n) 607 int n; 608 { 609 int a, nchars; 610 611 if (a = n/10) 612 nchars = 1 + printd(a); 613 else 614 nchars = 1; 615 putchar (n % 10 + '0'); 616 return (nchars); 617 } 618 619 /* Put the print representation of an integer into a string */ 620 static char *sptr; 621 622 scanstr (n, str) 623 int n; 624 char *str; 625 { 626 sptr = str; 627 Sprintf (n); 628 *sptr = '\0'; 629 } 630 631 Sprintf (n) 632 { 633 int a; 634 635 if (a = n/10) 636 Sprintf (a); 637 *sptr++ = n % 10 + '0'; 638 } 639 640 static char bell = ctrl(G); 641 642 strlen (s) 643 char *s; 644 { 645 register char *p; 646 647 p = s; 648 while (*p++) 649 ; 650 return (p - s - 1); 651 } 652 653 /* See whether the last component of the path name "path" is equal to the 654 ** string "string" 655 */ 656 657 tailequ (path, string) 658 char *path; 659 register char *string; 660 { 661 register char *tail; 662 663 tail = path + strlen(path); 664 while (tail >= path) 665 if (*(--tail) == '/') 666 break; 667 ++tail; 668 while (*tail++ == *string++) 669 if (*tail == '\0') 670 return(1); 671 return(0); 672 } 673 674 prompt (filename) 675 char *filename; 676 { 677 if (clreol) 678 cleareol (); 679 else if (promptlen > 0) 680 kill_line (); 681 if (!hard) { 682 promptlen = 8; 683 if (Senter && Sexit) { 684 tputs (Senter, 1, putch); 685 promptlen += (2 * soglitch); 686 } 687 if (clreol) 688 cleareol (); 689 pr("--More--"); 690 if (filename != NULL) { 691 promptlen += printf ("(Next file: %s)", filename); 692 } 693 else if (!no_intty) { 694 promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 695 } 696 if (dum_opt) { 697 promptlen += pr("[Press space to continue, 'q' to quit.]"); 698 } 699 if (Senter && Sexit) 700 tputs (Sexit, 1, putch); 701 if (clreol) 702 clreos (); 703 fflush(stdout); 704 } 705 else 706 write (2, &bell, 1); 707 inwait++; 708 } 709 710 /* 711 ** Get a logical line 712 */ 713 714 getline(f, length) 715 register FILE *f; 716 int *length; 717 { 718 register int c; 719 register char *p; 720 register int column; 721 static int colflg; 722 723 p = Line; 724 column = 0; 725 c = Getc (f); 726 if (colflg && c == '\n') { 727 Currline++; 728 c = Getc (f); 729 } 730 while (p < &Line[LINSIZ - 1]) { 731 if (c == EOF) { 732 if (p > Line) { 733 *p = '\0'; 734 *length = p - Line; 735 return (column); 736 } 737 *length = p - Line; 738 return (EOF); 739 } 740 if (c == '\n') { 741 Currline++; 742 break; 743 } 744 *p++ = c; 745 if (c == '\t') 746 if (!hardtabs || column < promptlen && !hard) { 747 if (hardtabs && eraseln && !dumb) { 748 column = 1 + (column | 7); 749 tputs (eraseln, 1, putch); 750 promptlen = 0; 751 } 752 else { 753 for (--p; p < &Line[LINSIZ - 1];) { 754 *p++ = ' '; 755 if ((++column & 7) == 0) 756 break; 757 } 758 if (column >= promptlen) promptlen = 0; 759 } 760 } 761 else 762 column = 1 + (column | 7); 763 else if (c == '\b' && column > 0) 764 column--; 765 else if (c == '\r') 766 column = 0; 767 else if (c == '\f' && stop_opt) { 768 p[-1] = '^'; 769 *p++ = 'L'; 770 column += 2; 771 Pause++; 772 } 773 else if (c == EOF) { 774 *length = p - Line; 775 return (column); 776 } 777 else if (c >= ' ' && c != RUBOUT) 778 column++; 779 if (column >= Mcol && fold_opt) break; 780 c = Getc (f); 781 } 782 if (column >= Mcol && Mcol > 0) { 783 if (!Wrap) { 784 *p++ = '\n'; 785 } 786 } 787 colflg = column == Mcol && fold_opt; 788 if (colflg && eatnl && Wrap) { 789 *p++ = '\n'; /* simulate normal wrap */ 790 } 791 *length = p - Line; 792 *p = 0; 793 return (column); 794 } 795 796 /* 797 ** Erase the rest of the prompt, assuming we are starting at column col. 798 */ 799 800 erase (col) 801 register int col; 802 { 803 804 if (promptlen == 0) 805 return; 806 if (hard) { 807 putchar ('\n'); 808 } 809 else { 810 if (col == 0) 811 putchar ('\r'); 812 if (!dumb && eraseln) 813 tputs (eraseln, 1, putch); 814 else 815 for (col = promptlen - col; col > 0; col--) 816 putchar (' '); 817 } 818 promptlen = 0; 819 } 820 821 /* 822 ** Erase the current line entirely 823 */ 824 825 kill_line () 826 { 827 erase (0); 828 if (!eraseln || dumb) putchar ('\r'); 829 } 830 831 /* 832 * force clear to end of line 833 */ 834 cleareol() 835 { 836 tputs(eraseln, 1, putch); 837 } 838 839 clreos() 840 { 841 tputs(EodClr, 1, putch); 842 } 843 844 /* 845 ** Print string and return number of characters 846 */ 847 848 pr(s1) 849 char *s1; 850 { 851 register char *s; 852 register char c; 853 854 for (s = s1; c = *s++; ) 855 putchar(c); 856 return (s - s1 - 1); 857 } 858 859 860 /* Print a buffer of n characters */ 861 862 prbuf (s, n) 863 register char *s; 864 register int n; 865 { 866 register char c; /* next output character */ 867 register int state; /* next output char's UL state */ 868 #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 869 870 while (--n >= 0) 871 if (!ul_opt) 872 putchar (*s++); 873 else { 874 if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 875 s++; 876 continue; 877 } 878 if (state = wouldul(s, n)) { 879 c = (*s == '_')? s[2] : *s ; 880 n -= 2; 881 s += 3; 882 } else 883 c = *s++; 884 if (state != pstate) { 885 if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 886 state = 1; 887 else 888 tputs(state ? ULenter : ULexit, 1, putch); 889 } 890 if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 891 putchar(c); 892 if (state && *chUL) { 893 pr(chBS); 894 tputs(chUL, 1, putch); 895 } 896 pstate = state; 897 } 898 } 899 900 /* 901 ** Clear the screen 902 */ 903 904 doclear() 905 { 906 if (Clear && !hard) { 907 tputs(Clear, 1, putch); 908 909 /* Put out carriage return so that system doesn't 910 ** get confused by escape sequences when expanding tabs 911 */ 912 putchar ('\r'); 913 promptlen = 0; 914 } 915 } 916 917 /* 918 * Go to home position 919 */ 920 home() 921 { 922 tputs(Home,1,putch); 923 } 924 925 static int lastcmd, lastarg, lastp; 926 static int lastcolon; 927 char shell_line[132]; 928 929 /* 930 ** Read a command and do it. A command consists of an optional integer 931 ** argument followed by the command character. Return the number of lines 932 ** to display in the next screenful. If there is nothing more to display 933 ** in the current file, zero is returned. 934 */ 935 936 command (filename, f) 937 char *filename; 938 register FILE *f; 939 { 940 register int nlines; 941 register int retval; 942 register char c; 943 char colonch; 944 FILE *helpf; 945 int done; 946 char comchar, cmdbuf[80], *p; 947 948 #define ret(val) retval=val;done++;break 949 950 done = 0; 951 if (!errors) 952 prompt (filename); 953 else 954 errors = 0; 955 if (MBIT == RAW && slow_tty) { 956 otty.sg_flags |= MBIT; 957 stty(fileno(stderr), &otty); 958 } 959 for (;;) { 960 nlines = number (&comchar); 961 lastp = colonch = 0; 962 if (comchar == '.') { /* Repeat last command */ 963 lastp++; 964 comchar = lastcmd; 965 nlines = lastarg; 966 if (lastcmd == ':') 967 colonch = lastcolon; 968 } 969 lastcmd = comchar; 970 lastarg = nlines; 971 if (comchar == otty.sg_erase) { 972 kill_line (); 973 prompt (filename); 974 continue; 975 } 976 switch (comchar) { 977 case ':': 978 retval = colon (filename, colonch, nlines); 979 if (retval >= 0) 980 done++; 981 break; 982 case 'b': 983 case ctrl(B): 984 { 985 register int initline; 986 987 if (no_intty) { 988 write(2, &bell, 1); 989 return (-1); 990 } 991 992 if (nlines == 0) nlines++; 993 994 putchar ('\r'); 995 erase (0); 996 printf ("\n"); 997 if (clreol) 998 cleareol (); 999 printf ("...back %d page", nlines); 1000 if (nlines > 1) 1001 pr ("s\n"); 1002 else 1003 pr ("\n"); 1004 1005 if (clreol) 1006 cleareol (); 1007 pr ("\n"); 1008 1009 initline = Currline - dlines * (nlines + 1); 1010 if (! noscroll) 1011 --initline; 1012 if (initline < 0) initline = 0; 1013 Fseek(f, 0L); 1014 Currline = 0; /* skiplns() will make Currline correct */ 1015 skiplns(initline, f); 1016 if (! noscroll) { 1017 ret(dlines + 1); 1018 } 1019 else { 1020 ret(dlines); 1021 } 1022 } 1023 case ' ': 1024 case 'z': 1025 if (nlines == 0) nlines = dlines; 1026 else if (comchar == 'z') dlines = nlines; 1027 ret (nlines); 1028 case 'd': 1029 case ctrl(D): 1030 if (nlines != 0) nscroll = nlines; 1031 ret (nscroll); 1032 case 'q': 1033 case 'Q': 1034 end_it (); 1035 case 's': 1036 case 'f': 1037 if (nlines == 0) nlines++; 1038 if (comchar == 'f') 1039 nlines *= dlines; 1040 putchar ('\r'); 1041 erase (0); 1042 printf ("\n"); 1043 if (clreol) 1044 cleareol (); 1045 printf ("...skipping %d line", nlines); 1046 if (nlines > 1) 1047 pr ("s\n"); 1048 else 1049 pr ("\n"); 1050 1051 if (clreol) 1052 cleareol (); 1053 pr ("\n"); 1054 1055 while (nlines > 0) { 1056 while ((c = Getc (f)) != '\n') 1057 if (c == EOF) { 1058 retval = 0; 1059 done++; 1060 goto endsw; 1061 } 1062 Currline++; 1063 nlines--; 1064 } 1065 ret (dlines); 1066 case '\n': 1067 if (nlines != 0) 1068 dlines = nlines; 1069 else 1070 nlines = 1; 1071 ret (nlines); 1072 case '\f': 1073 if (!no_intty) { 1074 doclear (); 1075 Fseek (f, screen_start.chrctr); 1076 Currline = screen_start.line; 1077 ret (dlines); 1078 } 1079 else { 1080 write (2, &bell, 1); 1081 break; 1082 } 1083 case '\'': 1084 if (!no_intty) { 1085 kill_line (); 1086 pr ("\n***Back***\n\n"); 1087 Fseek (f, context.chrctr); 1088 Currline = context.line; 1089 ret (dlines); 1090 } 1091 else { 1092 write (2, &bell, 1); 1093 break; 1094 } 1095 case '=': 1096 kill_line (); 1097 promptlen = printd (Currline); 1098 fflush (stdout); 1099 break; 1100 case 'n': 1101 lastp++; 1102 case '/': 1103 if (nlines == 0) nlines++; 1104 kill_line (); 1105 pr ("/"); 1106 promptlen = 1; 1107 fflush (stdout); 1108 if (lastp) { 1109 write (2,"\r", 1); 1110 search (NULL, f, nlines); /* Use previous r.e. */ 1111 } 1112 else { 1113 ttyin (cmdbuf, 78, '/'); 1114 write (2, "\r", 1); 1115 search (cmdbuf, f, nlines); 1116 } 1117 ret (dlines-1); 1118 case '!': 1119 do_shell (filename); 1120 break; 1121 case '?': 1122 case 'h': 1123 if ((helpf = fopen (HELPFILE, "r")) == NULL) 1124 error ("Can't open help file"); 1125 if (noscroll) doclear (); 1126 copy_file (helpf); 1127 fclose (helpf); 1128 prompt (filename); 1129 break; 1130 case 'v': /* This case should go right before default */ 1131 if (!no_intty) { 1132 kill_line (); 1133 cmdbuf[0] = '+'; 1134 scanstr (Currline - dlines < 0 ? 0 1135 : Currline - (dlines + 1) / 2, &cmdbuf[1]); 1136 pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 1137 execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 1138 break; 1139 } 1140 default: 1141 if (dum_opt) { 1142 kill_line (); 1143 if (Senter && Sexit) { 1144 tputs (Senter, 1, putch); 1145 promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 1146 tputs (Sexit, 1, putch); 1147 } 1148 else 1149 promptlen = pr ("[Press 'h' for instructions.]"); 1150 fflush (stdout); 1151 } 1152 else 1153 write (2, &bell, 1); 1154 break; 1155 } 1156 if (done) break; 1157 } 1158 putchar ('\r'); 1159 endsw: 1160 inwait = 0; 1161 notell++; 1162 if (MBIT == RAW && slow_tty) { 1163 otty.sg_flags &= ~MBIT; 1164 stty(fileno(stderr), &otty); 1165 } 1166 return (retval); 1167 } 1168 1169 char ch; 1170 1171 /* 1172 * Execute a colon-prefixed command. 1173 * Returns <0 if not a command that should cause 1174 * more of the file to be printed. 1175 */ 1176 1177 colon (filename, cmd, nlines) 1178 char *filename; 1179 int cmd; 1180 int nlines; 1181 { 1182 if (cmd == 0) 1183 ch = readch (); 1184 else 1185 ch = cmd; 1186 lastcolon = ch; 1187 switch (ch) { 1188 case 'f': 1189 kill_line (); 1190 if (!no_intty) 1191 promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 1192 else 1193 promptlen = printf ("[Not a file] line %d", Currline); 1194 fflush (stdout); 1195 return (-1); 1196 case 'n': 1197 if (nlines == 0) { 1198 if (fnum >= nfiles - 1) 1199 end_it (); 1200 nlines++; 1201 } 1202 putchar ('\r'); 1203 erase (0); 1204 skipf (nlines); 1205 return (0); 1206 case 'p': 1207 if (no_intty) { 1208 write (2, &bell, 1); 1209 return (-1); 1210 } 1211 putchar ('\r'); 1212 erase (0); 1213 if (nlines == 0) 1214 nlines++; 1215 skipf (-nlines); 1216 return (0); 1217 case '!': 1218 do_shell (filename); 1219 return (-1); 1220 case 'q': 1221 case 'Q': 1222 end_it (); 1223 default: 1224 write (2, &bell, 1); 1225 return (-1); 1226 } 1227 } 1228 1229 /* 1230 ** Read a decimal number from the terminal. Set cmd to the non-digit which 1231 ** terminates the number. 1232 */ 1233 1234 number(cmd) 1235 char *cmd; 1236 { 1237 register int i; 1238 1239 i = 0; ch = otty.sg_kill; 1240 for (;;) { 1241 ch = readch (); 1242 if (ch >= '0' && ch <= '9') 1243 i = i*10 + ch - '0'; 1244 else if (ch == otty.sg_kill) 1245 i = 0; 1246 else { 1247 *cmd = ch; 1248 break; 1249 } 1250 } 1251 return (i); 1252 } 1253 1254 do_shell (filename) 1255 char *filename; 1256 { 1257 char cmdbuf[80]; 1258 1259 kill_line (); 1260 pr ("!"); 1261 fflush (stdout); 1262 promptlen = 1; 1263 if (lastp) 1264 pr (shell_line); 1265 else { 1266 ttyin (cmdbuf, 78, '!'); 1267 if (expand (shell_line, cmdbuf)) { 1268 kill_line (); 1269 promptlen = printf ("!%s", shell_line); 1270 } 1271 } 1272 fflush (stdout); 1273 write (2, "\n", 1); 1274 promptlen = 0; 1275 shellp = 1; 1276 execute (filename, shell, shell, "-c", shell_line, 0); 1277 } 1278 1279 /* 1280 ** Search for nth ocurrence of regular expression contained in buf in the file 1281 */ 1282 1283 search (buf, file, n) 1284 char buf[]; 1285 FILE *file; 1286 register int n; 1287 { 1288 long startline = Ftell (file); 1289 register long line1 = startline; 1290 register long line2 = startline; 1291 register long line3 = startline; 1292 register int lncount; 1293 int saveln, rv, re_exec(); 1294 char *s, *re_comp(); 1295 1296 context.line = saveln = Currline; 1297 context.chrctr = startline; 1298 lncount = 0; 1299 if ((s = re_comp (buf)) != 0) 1300 error (s); 1301 while (!feof (file)) { 1302 line3 = line2; 1303 line2 = line1; 1304 line1 = Ftell (file); 1305 rdline (file); 1306 lncount++; 1307 if ((rv = re_exec (Line)) == 1) 1308 if (--n == 0) { 1309 if (lncount > 3 || (lncount > 1 && no_intty)) 1310 { 1311 pr ("\n"); 1312 if (clreol) 1313 cleareol (); 1314 pr("...skipping\n"); 1315 } 1316 if (!no_intty) { 1317 Currline -= (lncount >= 3 ? 3 : lncount); 1318 Fseek (file, line3); 1319 if (noscroll) 1320 if (clreol) { 1321 home (); 1322 cleareol (); 1323 } 1324 else 1325 doclear (); 1326 } 1327 else { 1328 kill_line (); 1329 if (noscroll) 1330 if (clreol) { 1331 home (); 1332 cleareol (); 1333 } 1334 else 1335 doclear (); 1336 pr (Line); 1337 putchar ('\n'); 1338 } 1339 break; 1340 } 1341 else if (rv == -1) 1342 error ("Regular expression botch"); 1343 } 1344 if (feof (file)) { 1345 if (!no_intty) { 1346 file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 1347 Currline = saveln; 1348 Fseek (file, startline); 1349 } 1350 else { 1351 pr ("\nPattern not found\n"); 1352 end_it (); 1353 } 1354 error ("Pattern not found"); 1355 } 1356 } 1357 1358 execute (filename, cmd, args) 1359 char *filename; 1360 char *cmd, *args; 1361 { 1362 int id; 1363 int n; 1364 1365 fflush (stdout); 1366 reset_tty (); 1367 for (n = 10; (id = fork ()) < 0 && n > 0; n--) 1368 sleep (5); 1369 if (id == 0) { 1370 if (!isatty(0)) { 1371 close(0); 1372 open("/dev/tty", 0); 1373 } 1374 execv (cmd, &args); 1375 write (2, "exec failed\n", 12); 1376 exit (1); 1377 } 1378 if (id > 0) { 1379 signal (SIGINT, SIG_IGN); 1380 signal (SIGQUIT, SIG_IGN); 1381 if (catch_susp) 1382 signal(SIGTSTP, SIG_DFL); 1383 while (wait(0) > 0); 1384 signal (SIGINT, end_it); 1385 signal (SIGQUIT, onquit); 1386 if (catch_susp) 1387 signal(SIGTSTP, onsusp); 1388 } else 1389 write(2, "can't fork\n", 11); 1390 set_tty (); 1391 pr ("------------------------\n"); 1392 prompt (filename); 1393 } 1394 /* 1395 ** Skip n lines in the file f 1396 */ 1397 1398 skiplns (n, f) 1399 register int n; 1400 register FILE *f; 1401 { 1402 register char c; 1403 1404 while (n > 0) { 1405 while ((c = Getc (f)) != '\n') 1406 if (c == EOF) 1407 return; 1408 n--; 1409 Currline++; 1410 } 1411 } 1412 1413 /* 1414 ** Skip nskip files in the file list (from the command line). Nskip may be 1415 ** negative. 1416 */ 1417 1418 skipf (nskip) 1419 register int nskip; 1420 { 1421 if (nskip == 0) return; 1422 if (nskip > 0) { 1423 if (fnum + nskip > nfiles - 1) 1424 nskip = nfiles - fnum - 1; 1425 } 1426 else if (within) 1427 ++fnum; 1428 fnum += nskip; 1429 if (fnum < 0) 1430 fnum = 0; 1431 pr ("\n...Skipping "); 1432 pr ("\n"); 1433 if (clreol) 1434 cleareol (); 1435 pr ("...Skipping "); 1436 pr (nskip > 0 ? "to file " : "back to file "); 1437 pr (fnames[fnum]); 1438 pr ("\n"); 1439 if (clreol) 1440 cleareol (); 1441 pr ("\n"); 1442 --fnum; 1443 } 1444 1445 /*----------------------------- Terminal I/O -------------------------------*/ 1446 1447 initterm () 1448 { 1449 char buf[TBUFSIZ]; 1450 static char clearbuf[TBUFSIZ]; 1451 char *clearptr, *padstr; 1452 int ldisc; 1453 int lmode; 1454 char *term; 1455 int tgrp; 1456 struct winsize win; 1457 1458 retry: 1459 if (!(no_tty = gtty(fileno(stdout), &otty))) { 1460 if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 1461 perror("TIOCLGET"); 1462 exit(1); 1463 } 1464 docrterase = ((lmode & LCRTERA) != 0); 1465 docrtkill = ((lmode & LCRTKIL) != 0); 1466 /* 1467 * Wait until we're in the foreground before we save the 1468 * the terminal modes. 1469 */ 1470 if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 1471 perror("TIOCGPGRP"); 1472 exit(1); 1473 } 1474 if (tgrp != getpgrp(0)) { 1475 kill(0, SIGTTOU); 1476 goto retry; 1477 } 1478 if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 1479 dumb++; ul_opt = 0; 1480 } 1481 else { 1482 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 1483 Lpp = tgetnum("li"); 1484 Mcol = tgetnum("co"); 1485 } else { 1486 if ((Lpp = win.ws_row) == 0) 1487 Lpp = tgetnum("li"); 1488 if ((Mcol = win.ws_col) == 0) 1489 Mcol = tgetnum("co"); 1490 } 1491 if ((Lpp <= 0) || tgetflag("hc")) { 1492 hard++; /* Hard copy terminal */ 1493 Lpp = 24; 1494 } 1495 if (tgetflag("xn")) 1496 eatnl++; /* Eat newline at last column + 1; dec, concept */ 1497 if (Mcol <= 0) 1498 Mcol = 80; 1499 1500 if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 1501 noscroll++; 1502 Wrap = tgetflag("am"); 1503 bad_so = tgetflag ("xs"); 1504 clearptr = clearbuf; 1505 eraseln = tgetstr("ce",&clearptr); 1506 Clear = tgetstr("cl", &clearptr); 1507 Senter = tgetstr("so", &clearptr); 1508 Sexit = tgetstr("se", &clearptr); 1509 if ((soglitch = tgetnum("sg")) < 0) 1510 soglitch = 0; 1511 1512 /* 1513 * Set up for underlining: some terminals don't need it; 1514 * others have start/stop sequences, still others have an 1515 * underline char sequence which is assumed to move the 1516 * cursor forward one character. If underline sequence 1517 * isn't available, settle for standout sequence. 1518 */ 1519 1520 if (tgetflag("ul") || tgetflag("os")) 1521 ul_opt = 0; 1522 if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 1523 chUL = ""; 1524 if (((ULenter = tgetstr("us", &clearptr)) == NULL || 1525 (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 1526 if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 1527 ULenter = ""; 1528 ULexit = ""; 1529 } else 1530 ulglitch = soglitch; 1531 } else { 1532 if ((ulglitch = tgetnum("ug")) < 0) 1533 ulglitch = 0; 1534 } 1535 1536 if (padstr = tgetstr("pc", &clearptr)) 1537 PC = *padstr; 1538 Home = tgetstr("ho",&clearptr); 1539 if (Home == 0 || *Home == '\0') 1540 { 1541 if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 1542 strcpy(cursorhome, tgoto(cursorm, 0, 0)); 1543 Home = cursorhome; 1544 } 1545 } 1546 EodClr = tgetstr("cd", &clearptr); 1547 if ((chBS = tgetstr("bc", &clearptr)) == NULL) 1548 chBS = "\b"; 1549 1550 } 1551 if ((shell = getenv("SHELL")) == NULL) 1552 shell = "/bin/sh"; 1553 } 1554 no_intty = gtty(fileno(stdin), &otty); 1555 gtty(fileno(stderr), &otty); 1556 savetty = otty; 1557 ospeed = otty.sg_ospeed; 1558 slow_tty = ospeed < B1200; 1559 hardtabs = (otty.sg_flags & TBDELAY) != XTABS; 1560 if (!no_tty) { 1561 otty.sg_flags &= ~ECHO; 1562 if (MBIT == CBREAK || !slow_tty) 1563 otty.sg_flags |= MBIT; 1564 } 1565 } 1566 1567 readch () 1568 { 1569 char ch; 1570 extern int errno; 1571 1572 errno = 0; 1573 if (read (2, &ch, 1) <= 0) 1574 if (errno != EINTR) 1575 end_it(); 1576 else 1577 ch = otty.sg_kill; 1578 return (ch); 1579 } 1580 1581 static char BS = '\b'; 1582 static char *BSB = "\b \b"; 1583 static char CARAT = '^'; 1584 #define ERASEONECHAR \ 1585 if (docrterase) \ 1586 write (2, BSB, sizeof(BSB)); \ 1587 else \ 1588 write (2, &BS, sizeof(BS)); 1589 1590 ttyin (buf, nmax, pchar) 1591 char buf[]; 1592 register int nmax; 1593 char pchar; 1594 { 1595 register char *sptr; 1596 register char ch; 1597 register int slash = 0; 1598 int maxlen; 1599 char cbuf; 1600 1601 sptr = buf; 1602 maxlen = 0; 1603 while (sptr - buf < nmax) { 1604 if (promptlen > maxlen) maxlen = promptlen; 1605 ch = readch (); 1606 if (ch == '\\') { 1607 slash++; 1608 } 1609 else if ((ch == otty.sg_erase) && !slash) { 1610 if (sptr > buf) { 1611 --promptlen; 1612 ERASEONECHAR 1613 --sptr; 1614 if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 1615 --promptlen; 1616 ERASEONECHAR 1617 } 1618 continue; 1619 } 1620 else { 1621 if (!eraseln) promptlen = maxlen; 1622 longjmp (restore, 1); 1623 } 1624 } 1625 else if ((ch == otty.sg_kill) && !slash) { 1626 if (hard) { 1627 show (ch); 1628 putchar ('\n'); 1629 putchar (pchar); 1630 } 1631 else { 1632 putchar ('\r'); 1633 putchar (pchar); 1634 if (eraseln) 1635 erase (1); 1636 else if (docrtkill) 1637 while (promptlen-- > 1) 1638 write (2, BSB, sizeof(BSB)); 1639 promptlen = 1; 1640 } 1641 sptr = buf; 1642 fflush (stdout); 1643 continue; 1644 } 1645 if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 1646 ERASEONECHAR 1647 --sptr; 1648 } 1649 if (ch != '\\') 1650 slash = 0; 1651 *sptr++ = ch; 1652 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1653 ch += ch == RUBOUT ? -0100 : 0100; 1654 write (2, &CARAT, 1); 1655 promptlen++; 1656 } 1657 cbuf = ch; 1658 if (ch != '\n' && ch != ESC) { 1659 write (2, &cbuf, 1); 1660 promptlen++; 1661 } 1662 else 1663 break; 1664 } 1665 *--sptr = '\0'; 1666 if (!eraseln) promptlen = maxlen; 1667 if (sptr - buf >= nmax - 1) 1668 error ("Line too long"); 1669 } 1670 1671 expand (outbuf, inbuf) 1672 char *outbuf; 1673 char *inbuf; 1674 { 1675 register char *instr; 1676 register char *outstr; 1677 register char ch; 1678 char temp[200]; 1679 int changed = 0; 1680 1681 instr = inbuf; 1682 outstr = temp; 1683 while ((ch = *instr++) != '\0') 1684 switch (ch) { 1685 case '%': 1686 if (!no_intty) { 1687 strcpy (outstr, fnames[fnum]); 1688 outstr += strlen (fnames[fnum]); 1689 changed++; 1690 } 1691 else 1692 *outstr++ = ch; 1693 break; 1694 case '!': 1695 if (!shellp) 1696 error ("No previous command to substitute for"); 1697 strcpy (outstr, shell_line); 1698 outstr += strlen (shell_line); 1699 changed++; 1700 break; 1701 case '\\': 1702 if (*instr == '%' || *instr == '!') { 1703 *outstr++ = *instr++; 1704 break; 1705 } 1706 default: 1707 *outstr++ = ch; 1708 } 1709 *outstr++ = '\0'; 1710 strcpy (outbuf, temp); 1711 return (changed); 1712 } 1713 1714 show (ch) 1715 register char ch; 1716 { 1717 char cbuf; 1718 1719 if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 1720 ch += ch == RUBOUT ? -0100 : 0100; 1721 write (2, &CARAT, 1); 1722 promptlen++; 1723 } 1724 cbuf = ch; 1725 write (2, &cbuf, 1); 1726 promptlen++; 1727 } 1728 1729 error (mess) 1730 char *mess; 1731 { 1732 if (clreol) 1733 cleareol (); 1734 else 1735 kill_line (); 1736 promptlen += strlen (mess); 1737 if (Senter && Sexit) { 1738 tputs (Senter, 1, putch); 1739 pr(mess); 1740 tputs (Sexit, 1, putch); 1741 } 1742 else 1743 pr (mess); 1744 fflush(stdout); 1745 errors++; 1746 longjmp (restore, 1); 1747 } 1748 1749 1750 set_tty () 1751 { 1752 otty.sg_flags |= MBIT; 1753 otty.sg_flags &= ~ECHO; 1754 stty(fileno(stderr), &otty); 1755 } 1756 1757 reset_tty () 1758 { 1759 if (no_tty) 1760 return; 1761 if (pstate) { 1762 tputs(ULexit, 1, putch); 1763 fflush(stdout); 1764 pstate = 0; 1765 } 1766 otty.sg_flags |= ECHO; 1767 otty.sg_flags &= ~MBIT; 1768 stty(fileno(stderr), &savetty); 1769 } 1770 1771 rdline (f) 1772 register FILE *f; 1773 { 1774 register char c; 1775 register char *p; 1776 1777 p = Line; 1778 while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 1779 *p++ = c; 1780 if (c == '\n') 1781 Currline++; 1782 *p = '\0'; 1783 } 1784 1785 /* Come here when we get a suspend signal from the terminal */ 1786 1787 onsusp () 1788 { 1789 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 1790 signal(SIGTTOU, SIG_IGN); 1791 reset_tty (); 1792 fflush (stdout); 1793 signal(SIGTTOU, SIG_DFL); 1794 /* Send the TSTP signal to suspend our process group */ 1795 signal(SIGTSTP, SIG_DFL); 1796 sigsetmask(0); 1797 kill (0, SIGTSTP); 1798 /* Pause for station break */ 1799 1800 /* We're back */ 1801 signal (SIGTSTP, onsusp); 1802 set_tty (); 1803 if (inwait) 1804 longjmp (restore); 1805 } 1806