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