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