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