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