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