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