1 /*- 2 * Copyright (c) 1980 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)more.c 5.28 (Berkeley) 03/01/93"; 16 #endif /* not lint */ 17 18 /* 19 ** more.c - General purpose tty output filter and file perusal program 20 ** 21 ** by Eric Shienbrood, UC Berkeley 22 ** 23 ** modified by Geoff Peck, UCB to add underlining, single spacing 24 ** modified by John Foderaro, UCB to add -c and MORE environment variable 25 */ 26 27 #include <sys/param.h> 28 #include <sys/stat.h> 29 #include <sys/file.h> 30 #include <signal.h> 31 #include <errno.h> 32 #include <sgtty.h> 33 #include <setjmp.h> 34 #include <a.out.h> 35 #include <varargs.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <ctype.h> 39 #include "pathnames.h" 40 41 #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 42 #define Ftell(f) file_pos 43 #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 44 #define Getc(f) (++file_pos, getc(f)) 45 #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 46 47 #define MBIT CBREAK 48 #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 49 50 #define TBUFSIZ 1024 51 #define LINSIZ 256 52 #define ctrl(letter) (letter & 077) 53 #define RUBOUT '\177' 54 #define ESC '\033' 55 #define QUIT '\034' 56 57 struct sgttyb otty, savetty; 58 long file_pos, file_size; 59 int fnum, no_intty, no_tty, slow_tty; 60 int dum_opt, dlines; 61 void chgwinsz(), end_it(), onquit(), onsusp(); 62 int nscroll = 11; /* Number of lines scrolled by 'd' */ 63 int fold_opt = 1; /* Fold long lines */ 64 int stop_opt = 1; /* Stop after form feeds */ 65 int ssp_opt = 0; /* Suppress white space */ 66 int ul_opt = 1; /* Underline as best we can */ 67 int promptlen; 68 int Currline; /* Line we are currently at */ 69 int startup = 1; 70 int firstf = 1; 71 int notell = 1; 72 int docrterase = 0; 73 int docrtkill = 0; 74 int bad_so; /* True if overwriting does not turn off standout */ 75 int inwait, Pause, errors; 76 int within; /* true if we are within a file, 77 false if we are between files */ 78 int hard, dumb, noscroll, hardtabs, clreol, eatnl; 79 int catch_susp; /* We should catch the SIGTSTP signal */ 80 char **fnames; /* The list of file names */ 81 int nfiles; /* Number of files left to process */ 82 char *shell; /* The name of the shell to use */ 83 int shellp; /* A previous shell command exists */ 84 char ch; 85 jmp_buf restore; 86 char Line[LINSIZ]; /* Line buffer */ 87 int Lpp = 24; /* lines per page */ 88 char *Clear; /* clear screen */ 89 char *eraseln; /* erase line */ 90 char *Senter, *Sexit;/* enter and exit standout mode */ 91 char *ULenter, *ULexit; /* enter and exit underline mode */ 92 char *chUL; /* underline character */ 93 char *chBS; /* backspace character */ 94 char *Home; /* go to home */ 95 char *cursorm; /* cursor movement */ 96 char cursorhome[40]; /* contains cursor movement to home */ 97 char *EodClr; /* clear rest of screen */ 98 char *tgetstr(); 99 int Mcol = 80; /* number of columns */ 100 int Wrap = 1; /* set if automargins */ 101 int soglitch; /* terminal has standout mode glitch */ 102 int ulglitch; /* terminal has underline mode glitch */ 103 int pstate = 0; /* current UL state */ 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 char *rindex(); 176 177 p = rindex(argv[0], '/'); 178 fputs("usage: ",stderr); 179 fputs(p ? p + 1 : argv[0],stderr); 180 fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 181 exit(1); 182 } 183 else 184 f = stdin; 185 if (!no_tty) { 186 signal(SIGQUIT, onquit); 187 signal(SIGINT, end_it); 188 signal(SIGWINCH, chgwinsz); 189 if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 190 signal(SIGTSTP, onsusp); 191 catch_susp++; 192 } 193 stty (fileno(stderr), &otty); 194 } 195 if (no_intty) { 196 if (no_tty) 197 copy_file (stdin); 198 else { 199 if ((ch = Getc (f)) == '\f') 200 doclear(); 201 else { 202 Ungetc (ch, f); 203 if (noscroll && (ch != EOF)) { 204 if (clreol) 205 home (); 206 else 207 doclear (); 208 } 209 } 210 if (srchopt) 211 { 212 search (initbuf, stdin, 1); 213 if (noscroll) 214 left--; 215 } 216 else if (initopt) 217 skiplns (initline, stdin); 218 screen (stdin, left); 219 } 220 no_intty = 0; 221 prnames++; 222 firstf = 0; 223 } 224 225 while (fnum < nfiles) { 226 if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 227 context.line = context.chrctr = 0; 228 Currline = 0; 229 if (firstf) setjmp (restore); 230 if (firstf) { 231 firstf = 0; 232 if (srchopt) 233 { 234 search (initbuf, f, 1); 235 if (noscroll) 236 left--; 237 } 238 else if (initopt) 239 skiplns (initline, f); 240 } 241 else if (fnum < nfiles && !no_tty) { 242 setjmp (restore); 243 left = command (fnames[fnum], f); 244 } 245 if (left != 0) { 246 if ((noscroll || clearit) && (file_size != LONG_MAX)) 247 if (clreol) 248 home (); 249 else 250 doclear (); 251 if (prnames) { 252 if (bad_so) 253 erase (0); 254 if (clreol) 255 cleareol (); 256 pr("::::::::::::::"); 257 if (promptlen > 14) 258 erase (14); 259 prtf ("\n"); 260 if(clreol) cleareol(); 261 prtf("%s\n", fnames[fnum]); 262 if(clreol) cleareol(); 263 prtf("::::::::::::::\n"); 264 if (left > Lpp - 4) 265 left = Lpp - 4; 266 } 267 if (no_tty) 268 copy_file (f); 269 else { 270 within++; 271 screen(f, left); 272 within = 0; 273 } 274 } 275 setjmp (restore); 276 fflush(stdout); 277 fclose(f); 278 screen_start.line = screen_start.chrctr = 0L; 279 context.line = context.chrctr = 0L; 280 } 281 fnum++; 282 firstf = 0; 283 } 284 reset_tty (); 285 exit(0); 286 } 287 288 argscan(s) 289 char *s; 290 { 291 int seen_num = 0; 292 293 while (*s != '\0') { 294 switch (*s) { 295 case '0': case '1': case '2': 296 case '3': case '4': case '5': 297 case '6': case '7': case '8': 298 case '9': 299 if (!seen_num) { 300 dlines = 0; 301 seen_num = 1; 302 } 303 dlines = dlines*10 + *s - '0'; 304 break; 305 case 'd': 306 dum_opt = 1; 307 break; 308 case 'l': 309 stop_opt = 0; 310 break; 311 case 'f': 312 fold_opt = 0; 313 break; 314 case 'p': 315 noscroll++; 316 break; 317 case 'c': 318 clreol++; 319 break; 320 case 's': 321 ssp_opt = 1; 322 break; 323 case 'u': 324 ul_opt = 0; 325 break; 326 } 327 s++; 328 } 329 } 330 331 332 /* 333 ** Check whether the file named by fs is an ASCII file which the user may 334 ** access. If it is, return the opened file. Otherwise return NULL. 335 */ 336 337 FILE * 338 checkf (fs, clearfirst) 339 register char *fs; 340 int *clearfirst; 341 { 342 struct stat stbuf; 343 register FILE *f; 344 char c; 345 346 if (stat (fs, &stbuf) == -1) { 347 (void)fflush(stdout); 348 if (clreol) 349 cleareol (); 350 perror(fs); 351 return((FILE *)NULL); 352 } 353 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 354 prtf("\n*** %s: directory ***\n\n", fs); 355 return((FILE *)NULL); 356 } 357 if ((f = Fopen(fs, "r")) == NULL) { 358 (void)fflush(stdout); 359 perror(fs); 360 return((FILE *)NULL); 361 } 362 if (magic(f, fs)) 363 return((FILE *)NULL); 364 c = Getc(f); 365 *clearfirst = c == '\f'; 366 Ungetc (c, f); 367 if ((file_size = stbuf.st_size) == 0) 368 file_size = LONG_MAX; 369 return(f); 370 } 371 372 /* 373 * magic -- 374 * check for file magic numbers. This code would best be shared with 375 * the file(1) program or, perhaps, more should not try and be so smart? 376 */ 377 magic(f, fs) 378 FILE *f; 379 char *fs; 380 { 381 struct exec ex; 382 383 if (fread(&ex, sizeof(ex), 1, f) == 1) 384 switch(ex.a_magic) { 385 case OMAGIC: 386 case NMAGIC: 387 case ZMAGIC: 388 case 0405: 389 case 0411: 390 case 0177545: 391 prtf("\n******** %s: Not a text file ********\n\n", fs); 392 (void)fclose(f); 393 return(1); 394 } 395 (void)fseek(f, 0L, L_SET); /* rewind() not necessary */ 396 return(0); 397 } 398 399 /* 400 ** A real function, for the tputs routine in termlib 401 */ 402 403 putch (ch) 404 char ch; 405 { 406 putchar (ch); 407 } 408 409 /* 410 ** Print out the contents of the file f, one screenful at a time. 411 */ 412 413 #define STOP -10 414 415 screen (f, num_lines) 416 register FILE *f; 417 register int num_lines; 418 { 419 register int c; 420 register int nchars; 421 int length; /* length of current line */ 422 static int prev_len = 1; /* length of previous line */ 423 424 for (;;) { 425 while (num_lines > 0 && !Pause) { 426 if ((nchars = getline (f, &length)) == EOF) 427 { 428 if (clreol) 429 clreos(); 430 return; 431 } 432 if (ssp_opt && length == 0 && prev_len == 0) 433 continue; 434 prev_len = length; 435 if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 436 erase (0); 437 /* must clear before drawing line since tabs on some terminals 438 * do not erase what they tab over. 439 */ 440 if (clreol) 441 cleareol (); 442 prbuf (Line, length); 443 if (nchars < promptlen) 444 erase (nchars); /* erase () sets promptlen to 0 */ 445 else promptlen = 0; 446 /* is this needed? 447 * if (clreol) 448 * cleareol(); /* must clear again in case we wrapped * 449 */ 450 if (nchars < Mcol || !fold_opt) 451 prbuf("\n", 1); /* will turn off UL if necessary */ 452 if (nchars == STOP) 453 break; 454 num_lines--; 455 } 456 if (pstate) { 457 tputs(ULexit, 1, putch); 458 pstate = 0; 459 } 460 fflush(stdout); 461 if ((c = Getc(f)) == EOF) 462 { 463 if (clreol) 464 clreos (); 465 return; 466 } 467 468 if (Pause && clreol) 469 clreos (); 470 Ungetc (c, f); 471 setjmp (restore); 472 Pause = 0; startup = 0; 473 if ((num_lines = command (NULL, f)) == 0) 474 return; 475 if (hard && promptlen > 0) 476 erase (0); 477 if (noscroll && num_lines >= dlines) 478 { 479 if (clreol) 480 home(); 481 else 482 doclear (); 483 } 484 screen_start.line = Currline; 485 screen_start.chrctr = Ftell (f); 486 } 487 } 488 489 /* 490 ** Come here if a quit signal is received 491 */ 492 493 void 494 onquit() 495 { 496 signal(SIGQUIT, SIG_IGN); 497 if (!inwait) { 498 putchar ('\n'); 499 if (!startup) { 500 signal(SIGQUIT, onquit); 501 longjmp (restore, 1); 502 } 503 else 504 Pause++; 505 } 506 else if (!dum_opt && notell) { 507 write (2, "[Use q or Q to quit]", 20); 508 promptlen += 20; 509 notell = 0; 510 } 511 signal(SIGQUIT, onquit); 512 } 513 514 /* 515 ** Come here if a signal for a window size change is received 516 */ 517 518 void 519 chgwinsz() 520 { 521 struct winsize win; 522 523 (void) signal(SIGWINCH, SIG_IGN); 524 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 525 if (win.ws_row != 0) { 526 Lpp = win.ws_row; 527 nscroll = Lpp/2 - 1; 528 if (nscroll <= 0) 529 nscroll = 1; 530 dlines = Lpp - (noscroll ? 1 : 2); 531 } 532 if (win.ws_col != 0) 533 Mcol = win.ws_col; 534 } 535 (void) signal(SIGWINCH, chgwinsz); 536 } 537 538 /* 539 ** Clean up terminal state and exit. Also come here if interrupt signal received 540 */ 541 542 void 543 end_it () 544 { 545 546 reset_tty (); 547 if (clreol) { 548 putchar ('\r'); 549 clreos (); 550 fflush (stdout); 551 } 552 else if (!clreol && (promptlen > 0)) { 553 kill_line (); 554 fflush (stdout); 555 } 556 else 557 write (2, "\n", 1); 558 _exit(0); 559 } 560 561 copy_file(f) 562 register FILE *f; 563 { 564 register int c; 565 566 while ((c = getc(f)) != EOF) 567 putchar(c); 568 } 569 570 /* Simplified printf function */ 571 572 prtf (fmt, va_alist) 573 register char *fmt; 574 va_dcl 575 { 576 va_list ap; 577 register char ch; 578 register int ccount; 579 580 ccount = 0; 581 va_start(ap); 582 while (*fmt) { 583 while ((ch = *fmt++) != '%') { 584 if (ch == '\0') 585 return (ccount); 586 ccount++; 587 putchar (ch); 588 } 589 switch (*fmt++) { 590 case 'd': 591 ccount += printd (va_arg(ap, int)); 592 break; 593 case 's': 594 ccount += pr (va_arg(ap, char *)); 595 break; 596 case '%': 597 ccount++; 598 putchar ('%'); 599 break; 600 case '0': 601 return (ccount); 602 default: 603 break; 604 } 605 } 606 va_end(ap); 607 return (ccount); 608 609 } 610 611 /* 612 ** Print an integer as a string of decimal digits, 613 ** returning the length of the print representation. 614 */ 615 616 printd (n) 617 int n; 618 { 619 int a, nchars; 620 621 if (a = n/10) 622 nchars = 1 + printd(a); 623 else 624 nchars = 1; 625 putchar (n % 10 + '0'); 626 return (nchars); 627 } 628 629 /* Put the print representation of an integer into a string */ 630 static char *sptr; 631 632 scanstr (n, str) 633 int n; 634 char *str; 635 { 636 sptr = str; 637 Sprintf (n); 638 *sptr = '\0'; 639 } 640 641 Sprintf (n) 642 { 643 int a; 644 645 if (a = n/10) 646 Sprintf (a); 647 *sptr++ = n % 10 + '0'; 648 } 649 650 static char bell = ctrl('G'); 651 652 /* See whether the last component of the path name "path" is equal to the 653 ** string "string" 654 */ 655 656 tailequ (path, string) 657 char *path; 658 register char *string; 659 { 660 register char *tail; 661 662 tail = path + strlen(path); 663 while (tail >= path) 664 if (*(--tail) == '/') 665 break; 666 ++tail; 667 while (*tail++ == *string++) 668 if (*tail == '\0') 669 return(1); 670 return(0); 671 } 672 673 prompt (filename) 674 char *filename; 675 { 676 if (clreol) 677 cleareol (); 678 else if (promptlen > 0) 679 kill_line (); 680 if (!hard) { 681 promptlen = 8; 682 if (Senter && Sexit) { 683 tputs (Senter, 1, putch); 684 promptlen += (2 * soglitch); 685 } 686 if (clreol) 687 cleareol (); 688 pr("--More--"); 689 if (filename != NULL) { 690 promptlen += prtf ("(Next file: %s)", filename); 691 } 692 else if (!no_intty) { 693 promptlen += prtf ("(%d%%)", (int)((file_pos * 100) / file_size)); 694 } 695 if (dum_opt) { 696 promptlen += pr("[Press space to continue, 'q' to quit.]"); 697 } 698 if (Senter && Sexit) 699 tputs (Sexit, 1, putch); 700 if (clreol) 701 clreos (); 702 fflush(stdout); 703 } 704 else 705 write (2, &bell, 1); 706 inwait++; 707 } 708 709 /* 710 ** Get a logical line 711 */ 712 713 getline(f, length) 714 register FILE *f; 715 int *length; 716 { 717 register int c; 718 register char *p; 719 register int column; 720 static int colflg; 721 722 p = Line; 723 column = 0; 724 c = Getc (f); 725 if (colflg && c == '\n') { 726 Currline++; 727 c = Getc (f); 728 } 729 while (p < &Line[LINSIZ - 1]) { 730 if (c == EOF) { 731 if (p > Line) { 732 *p = '\0'; 733 *length = p - Line; 734 return (column); 735 } 736 *length = p - Line; 737 return (EOF); 738 } 739 if (c == '\n') { 740 Currline++; 741 break; 742 } 743 *p++ = c; 744 if (c == '\t') 745 if (!hardtabs || column < promptlen && !hard) { 746 if (hardtabs && eraseln && !dumb) { 747 column = 1 + (column | 7); 748 tputs (eraseln, 1, putch); 749 promptlen = 0; 750 } 751 else { 752 for (--p; p < &Line[LINSIZ - 1];) { 753 *p++ = ' '; 754 if ((++column & 7) == 0) 755 break; 756 } 757 if (column >= promptlen) promptlen = 0; 758 } 759 } 760 else 761 column = 1 + (column | 7); 762 else if (c == '\b' && column > 0) 763 column--; 764 else if (c == '\r') 765 column = 0; 766 else if (c == '\f' && stop_opt) { 767 p[-1] = '^'; 768 *p++ = 'L'; 769 column += 2; 770 Pause++; 771 } 772 else if (c == EOF) { 773 *length = p - Line; 774 return (column); 775 } 776 else if (c >= ' ' && c != RUBOUT) 777 column++; 778 if (column >= Mcol && fold_opt) break; 779 c = Getc (f); 780 } 781 if (column >= Mcol && Mcol > 0) { 782 if (!Wrap) { 783 *p++ = '\n'; 784 } 785 } 786 colflg = column == Mcol && fold_opt; 787 if (colflg && eatnl && Wrap) { 788 *p++ = '\n'; /* simulate normal wrap */ 789 } 790 *length = p - Line; 791 *p = 0; 792 return (column); 793 } 794 795 /* 796 ** Erase the rest of the prompt, assuming we are starting at column col. 797 */ 798 799 erase (col) 800 register int col; 801 { 802 803 if (promptlen == 0) 804 return; 805 if (hard) { 806 putchar ('\n'); 807 } 808 else { 809 if (col == 0) 810 putchar ('\r'); 811 if (!dumb && eraseln) 812 tputs (eraseln, 1, putch); 813 else 814 for (col = promptlen - col; col > 0; col--) 815 putchar (' '); 816 } 817 promptlen = 0; 818 } 819 820 /* 821 ** Erase the current line entirely 822 */ 823 824 kill_line () 825 { 826 erase (0); 827 if (!eraseln || dumb) putchar ('\r'); 828 } 829 830 /* 831 * force clear to end of line 832 */ 833 cleareol() 834 { 835 tputs(eraseln, 1, putch); 836 } 837 838 clreos() 839 { 840 tputs(EodClr, 1, putch); 841 } 842 843 /* 844 ** Print string and return number of characters 845 */ 846 847 pr(s1) 848 char *s1; 849 { 850 register char *s; 851 register char c; 852 853 for (s = s1; c = *s++; ) 854 putchar(c); 855 return (s - s1 - 1); 856 } 857 858 859 /* Print a buffer of n characters */ 860 861 prbuf (s, n) 862 register char *s; 863 register int n; 864 { 865 register char c; /* next output character */ 866 register int state; /* next output char's UL state */ 867 #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 868 869 while (--n >= 0) 870 if (!ul_opt) 871 putchar (*s++); 872 else { 873 if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 874 s++; 875 continue; 876 } 877 if (state = wouldul(s, n)) { 878 c = (*s == '_')? s[2] : *s ; 879 n -= 2; 880 s += 3; 881 } else 882 c = *s++; 883 if (state != pstate) { 884 if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 885 state = 1; 886 else 887 tputs(state ? ULenter : ULexit, 1, putch); 888 } 889 if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 890 putchar(c); 891 if (state && *chUL) { 892 pr(chBS); 893 tputs(chUL, 1, putch); 894 } 895 pstate = state; 896 } 897 } 898 899 /* 900 ** Clear the screen 901 */ 902 903 doclear() 904 { 905 if (Clear && !hard) { 906 tputs(Clear, 1, putch); 907 908 /* Put out carriage return so that system doesn't 909 ** get confused by escape sequences when expanding tabs 910 */ 911 putchar ('\r'); 912 promptlen = 0; 913 } 914 } 915 916 /* 917 * Go to home position 918 */ 919 home() 920 { 921 tputs(Home,1,putch); 922 } 923 924 static int lastcmd, lastarg, lastp; 925 static int lastcolon; 926 char shell_line[132]; 927 928 /* 929 ** Read a command and do it. A command consists of an optional integer 930 ** argument followed by the command character. Return the number of lines 931 ** to display in the next screenful. If there is nothing more to display 932 ** in the current file, zero is returned. 933 */ 934 935 command (filename, f) 936 char *filename; 937 register FILE *f; 938 { 939 register int nlines; 940 register int retval; 941 register char c; 942 char colonch; 943 FILE *helpf; 944 int done; 945 char comchar, cmdbuf[80], *p; 946 947 #define ret(val) retval=val;done++;break 948 949 done = 0; 950 if (!errors) 951 prompt (filename); 952 else 953 errors = 0; 954 if (MBIT == RAW && slow_tty) { 955 otty.sg_flags |= MBIT; 956 stty(fileno(stderr), &otty); 957 } 958 for (;;) { 959 nlines = number (&comchar); 960 lastp = colonch = 0; 961 if (comchar == '.') { /* Repeat last command */ 962 lastp++; 963 comchar = lastcmd; 964 nlines = lastarg; 965 if (lastcmd == ':') 966 colonch = lastcolon; 967 } 968 lastcmd = comchar; 969 lastarg = nlines; 970 if (comchar == otty.sg_erase) { 971 kill_line (); 972 prompt (filename); 973 continue; 974 } 975 switch (comchar) { 976 case ':': 977 retval = colon (filename, colonch, nlines); 978 if (retval >= 0) 979 done++; 980 break; 981 case 'b': 982 case ctrl('B'): 983 { 984 register int initline; 985 986 if (no_intty) { 987 write(2, &bell, 1); 988 return (-1); 989 } 990 991 if (nlines == 0) nlines++; 992 993 putchar ('\r'); 994 erase (0); 995 prtf ("\n"); 996 if (clreol) 997 cleareol (); 998 prtf ("...back %d page", nlines); 999 if (nlines > 1) 1000 pr ("s\n"); 1001 else 1002 pr ("\n"); 1003 1004 if (clreol) 1005 cleareol (); 1006 pr ("\n"); 1007 1008 initline = Currline - dlines * (nlines + 1); 1009 if (! noscroll) 1010 --initline; 1011 if (initline < 0) initline = 0; 1012 Fseek(f, 0L); 1013 Currline = 0; /* skiplns() will make Currline correct */ 1014 skiplns(initline, f); 1015 if (! noscroll) { 1016 ret(dlines + 1); 1017 } 1018 else { 1019 ret(dlines); 1020 } 1021 } 1022 case ' ': 1023 case 'z': 1024 if (nlines == 0) nlines = dlines; 1025 else if (comchar == 'z') dlines = nlines; 1026 ret (nlines); 1027 case 'd': 1028 case ctrl('D'): 1029 if (nlines != 0) nscroll = nlines; 1030 ret (nscroll); 1031 case 'q': 1032 case 'Q': 1033 end_it (); 1034 case 's': 1035 case 'f': 1036 if (nlines == 0) nlines++; 1037 if (comchar == 'f') 1038 nlines *= dlines; 1039 putchar ('\r'); 1040 erase (0); 1041 prtf ("\n"); 1042 if (clreol) 1043 cleareol (); 1044 prtf ("...skipping %d line", nlines); 1045 if (nlines > 1) 1046 pr ("s\n"); 1047 else 1048 pr ("\n"); 1049 1050 if (clreol) 1051 cleareol (); 1052 pr ("\n"); 1053 1054 while (nlines > 0) { 1055 while ((c = Getc (f)) != '\n') 1056 if (c == EOF) { 1057 retval = 0; 1058 done++; 1059 goto endsw; 1060 } 1061 Currline++; 1062 nlines--; 1063 } 1064 ret (dlines); 1065 case '\n': 1066 if (nlines != 0) 1067 dlines = nlines; 1068 else 1069 nlines = 1; 1070 ret (nlines); 1071 case '\f': 1072 if (!no_intty) { 1073 doclear (); 1074 Fseek (f, screen_start.chrctr); 1075 Currline = screen_start.line; 1076 ret (dlines); 1077 } 1078 else { 1079 write (2, &bell, 1); 1080 break; 1081 } 1082 case '\'': 1083 if (!no_intty) { 1084 kill_line (); 1085 pr ("\n***Back***\n\n"); 1086 Fseek (f, context.chrctr); 1087 Currline = context.line; 1088 ret (dlines); 1089 } 1090 else { 1091 write (2, &bell, 1); 1092 break; 1093 } 1094 case '=': 1095 kill_line (); 1096 promptlen = printd (Currline); 1097 fflush (stdout); 1098 break; 1099 case 'n': 1100 lastp++; 1101 case '/': 1102 if (nlines == 0) nlines++; 1103 kill_line (); 1104 pr ("/"); 1105 promptlen = 1; 1106 fflush (stdout); 1107 if (lastp) { 1108 write (2,"\r", 1); 1109 search (NULL, f, nlines); /* Use previous r.e. */ 1110 } 1111 else { 1112 ttyin (cmdbuf, 78, '/'); 1113 write (2, "\r", 1); 1114 search (cmdbuf, f, nlines); 1115 } 1116 ret (dlines-1); 1117 case '!': 1118 do_shell (filename); 1119 break; 1120 case '?': 1121 case 'h': 1122 if ((helpf = fopen (HELPFILE, "r")) == NULL) 1123 error ("Can't open help file"); 1124 if (noscroll) doclear (); 1125 copy_file (helpf); 1126 fclose (helpf); 1127 prompt (filename); 1128 break; 1129 case 'v': /* This case should go right before default */ 1130 if (!no_intty) { 1131 kill_line (); 1132 cmdbuf[0] = '+'; 1133 scanstr (Currline - dlines < 0 ? 0 1134 : Currline - (dlines + 1) / 2, &cmdbuf[1]); 1135 pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 1136 execute (filename, _PATH_VI, "vi", cmdbuf, fnames[fnum], 0); 1137 break; 1138 } 1139 default: 1140 if (dum_opt) { 1141 kill_line (); 1142 if (Senter && Sexit) { 1143 tputs (Senter, 1, putch); 1144 promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 1145 tputs (Sexit, 1, putch); 1146 } 1147 else 1148 promptlen = pr ("[Press 'h' for instructions.]"); 1149 fflush (stdout); 1150 } 1151 else 1152 write (2, &bell, 1); 1153 break; 1154 } 1155 if (done) break; 1156 } 1157 putchar ('\r'); 1158 endsw: 1159 inwait = 0; 1160 notell++; 1161 if (MBIT == RAW && slow_tty) { 1162 otty.sg_flags &= ~MBIT; 1163 stty(fileno(stderr), &otty); 1164 } 1165 return (retval); 1166 } 1167 1168 char ch; 1169 1170 /* 1171 * Execute a colon-prefixed command. 1172 * Returns <0 if not a command that should cause 1173 * more of the file to be printed. 1174 */ 1175 1176 colon (filename, cmd, nlines) 1177 char *filename; 1178 int cmd; 1179 int nlines; 1180 { 1181 if (cmd == 0) 1182 ch = readch (); 1183 else 1184 ch = cmd; 1185 lastcolon = ch; 1186 switch (ch) { 1187 case 'f': 1188 kill_line (); 1189 if (!no_intty) 1190 promptlen = prtf ("\"%s\" line %d", fnames[fnum], Currline); 1191 else 1192 promptlen = prtf ("[Not a file] line %d", Currline); 1193 fflush (stdout); 1194 return (-1); 1195 case 'n': 1196 if (nlines == 0) { 1197 if (fnum >= nfiles - 1) 1198 end_it (); 1199 nlines++; 1200 } 1201 putchar ('\r'); 1202 erase (0); 1203 skipf (nlines); 1204 return (0); 1205 case 'p': 1206 if (no_intty) { 1207 write (2, &bell, 1); 1208 return (-1); 1209 } 1210 putchar ('\r'); 1211 erase (0); 1212 if (nlines == 0) 1213 nlines++; 1214 skipf (-nlines); 1215 return (0); 1216 case '!': 1217 do_shell (filename); 1218 return (-1); 1219 case 'q': 1220 case 'Q': 1221 end_it (); 1222 default: 1223 write (2, &bell, 1); 1224 return (-1); 1225 } 1226 } 1227 1228 /* 1229 ** Read a decimal number from the terminal. Set cmd to the non-digit which 1230 ** terminates the number. 1231 */ 1232 1233 number(cmd) 1234 char *cmd; 1235 { 1236 register int i; 1237 1238 i = 0; ch = otty.sg_kill; 1239 for (;;) { 1240 ch = readch (); 1241 if (ch >= '0' && ch <= '9') 1242 i = i*10 + ch - '0'; 1243 else if (ch == otty.sg_kill) 1244 i = 0; 1245 else { 1246 *cmd = ch; 1247 break; 1248 } 1249 } 1250 return (i); 1251 } 1252 1253 do_shell (filename) 1254 char *filename; 1255 { 1256 char cmdbuf[80]; 1257 1258 kill_line (); 1259 pr ("!"); 1260 fflush (stdout); 1261 promptlen = 1; 1262 if (lastp) 1263 pr (shell_line); 1264 else { 1265 ttyin (cmdbuf, 78, '!'); 1266 if (expand (shell_line, cmdbuf)) { 1267 kill_line (); 1268 promptlen = prtf ("!%s", shell_line); 1269 } 1270 } 1271 fflush (stdout); 1272 write (2, "\n", 1); 1273 promptlen = 0; 1274 shellp = 1; 1275 execute (filename, shell, shell, "-c", shell_line, 0); 1276 } 1277 1278 /* 1279 ** Search for nth ocurrence of regular expression contained in buf in the file 1280 */ 1281 1282 search (buf, file, n) 1283 char buf[]; 1284 FILE *file; 1285 register int n; 1286 { 1287 long startline = Ftell (file); 1288 register long line1 = startline; 1289 register long line2 = startline; 1290 register long line3 = startline; 1291 register int lncount; 1292 int saveln, rv, re_exec(); 1293 char *s, *re_comp(); 1294 1295 context.line = saveln = Currline; 1296 context.chrctr = startline; 1297 lncount = 0; 1298 if ((s = re_comp (buf)) != 0) 1299 error (s); 1300 while (!feof (file)) { 1301 line3 = line2; 1302 line2 = line1; 1303 line1 = Ftell (file); 1304 rdline (file); 1305 lncount++; 1306 if ((rv = re_exec (Line)) == 1) 1307 if (--n == 0) { 1308 if (lncount > 3 || (lncount > 1 && no_intty)) 1309 { 1310 pr ("\n"); 1311 if (clreol) 1312 cleareol (); 1313 pr("...skipping\n"); 1314 } 1315 if (!no_intty) { 1316 Currline -= (lncount >= 3 ? 3 : lncount); 1317 Fseek (file, line3); 1318 if (noscroll) 1319 if (clreol) { 1320 home (); 1321 cleareol (); 1322 } 1323 else 1324 doclear (); 1325 } 1326 else { 1327 kill_line (); 1328 if (noscroll) 1329 if (clreol) { 1330 home (); 1331 cleareol (); 1332 } 1333 else 1334 doclear (); 1335 pr (Line); 1336 putchar ('\n'); 1337 } 1338 break; 1339 } 1340 else if (rv == -1) 1341 error ("Regular expression botch"); 1342 } 1343 if (feof (file)) { 1344 if (!no_intty) { 1345 /* file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 1346 Currline = saveln; 1347 Fseek (file, startline); 1348 } 1349 else { 1350 pr ("\nPattern not found\n"); 1351 end_it (); 1352 } 1353 error ("Pattern not found"); 1354 } 1355 } 1356 1357 /*VARARGS2*/ 1358 execute (filename, cmd, va_alist) 1359 char *filename; 1360 char *cmd; 1361 va_dcl 1362 { 1363 int id; 1364 int n; 1365 va_list argp; 1366 1367 fflush (stdout); 1368 reset_tty (); 1369 for (n = 10; (id = fork ()) < 0 && n > 0; n--) 1370 sleep (5); 1371 if (id == 0) { 1372 if (!isatty(0)) { 1373 close(0); 1374 open("/dev/tty", 0); 1375 } 1376 va_start(argp); 1377 execv (cmd, argp); 1378 write (2, "exec failed\n", 12); 1379 exit (1); 1380 va_end(argp); /* balance {}'s for some UNIX's */ 1381 } 1382 if (id > 0) { 1383 signal (SIGINT, SIG_IGN); 1384 signal (SIGQUIT, SIG_IGN); 1385 if (catch_susp) 1386 signal(SIGTSTP, SIG_DFL); 1387 while (wait(0) > 0); 1388 signal (SIGINT, end_it); 1389 signal (SIGQUIT, onquit); 1390 if (catch_susp) 1391 signal(SIGTSTP, onsusp); 1392 } else 1393 write(2, "can't fork\n", 11); 1394 set_tty (); 1395 pr ("------------------------\n"); 1396 prompt (filename); 1397 } 1398 /* 1399 ** Skip n lines in the file f 1400 */ 1401 1402 skiplns (n, f) 1403 register int n; 1404 register FILE *f; 1405 { 1406 register char c; 1407 1408 while (n > 0) { 1409 while ((c = Getc (f)) != '\n') 1410 if (c == EOF) 1411 return; 1412 n--; 1413 Currline++; 1414 } 1415 } 1416 1417 /* 1418 ** Skip nskip files in the file list (from the command line). Nskip may be 1419 ** negative. 1420 */ 1421 1422 skipf (nskip) 1423 register int nskip; 1424 { 1425 if (nskip == 0) return; 1426 if (nskip > 0) { 1427 if (fnum + nskip > nfiles - 1) 1428 nskip = nfiles - fnum - 1; 1429 } 1430 else if (within) 1431 ++fnum; 1432 fnum += nskip; 1433 if (fnum < 0) 1434 fnum = 0; 1435 pr ("\n...Skipping "); 1436 pr ("\n"); 1437 if (clreol) 1438 cleareol (); 1439 pr ("...Skipping "); 1440 pr (nskip > 0 ? "to file " : "back to file "); 1441 pr (fnames[fnum]); 1442 pr ("\n"); 1443 if (clreol) 1444 cleareol (); 1445 pr ("\n"); 1446 --fnum; 1447 } 1448 1449 /*----------------------------- Terminal I/O -------------------------------*/ 1450 1451 initterm () 1452 { 1453 char buf[TBUFSIZ]; 1454 static char clearbuf[TBUFSIZ]; 1455 char *clearptr, *padstr; 1456 int ldisc; 1457 int lmode; 1458 char *term; 1459 int tgrp; 1460 struct winsize win; 1461 char *tgoto(); 1462 1463 retry: 1464 if (!(no_tty = ioctl(fileno(stdout), TIOCGETP, &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 = ioctl(fileno(stdin), TIOCGETP, &otty); 1560 (void)ioctl(fileno(stderr), TIOCGETP, &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 void 1793 onsusp () 1794 { 1795 /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 1796 signal(SIGTTOU, SIG_IGN); 1797 reset_tty (); 1798 fflush (stdout); 1799 signal(SIGTTOU, SIG_DFL); 1800 /* Send the TSTP signal to suspend our process group */ 1801 signal(SIGTSTP, SIG_DFL); 1802 sigsetmask(0); 1803 kill (0, SIGTSTP); 1804 /* Pause for station break */ 1805 1806 /* We're back */ 1807 signal (SIGTSTP, onsusp); 1808 set_tty (); 1809 if (inwait) 1810 longjmp (restore, 1); 1811 } 1812