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