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