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