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