|
|
1.1 ! root 1: static char *SCCS_ID = "@(#)more.c 4.1 (Berkeley) 10/16/80"; ! 2: /* ! 3: ** more.c - General purpose tty output filter and file perusal program ! 4: ** ! 5: ** by Eric Shienbrood, UC Berkeley ! 6: */ ! 7: ! 8: #include <whoami.h> ! 9: #ifdef V6 ! 10: #include <retrofit.h> ! 11: #endif ! 12: #include <stdio.h> ! 13: #include <ctype.h> ! 14: #include <signal.h> ! 15: #include <errno.h> ! 16: #include <sgtty.h> ! 17: #include <setjmp.h> ! 18: #include <sys/types.h> ! 19: #include <sys/dir.h> ! 20: #include <sys/stat.h> ! 21: #include <local/uparm.h> ! 22: ! 23: /* Help file will eventually go in libpath(more.help) on all systems */ ! 24: ! 25: #ifdef INGRES ! 26: #define VI "/usr/bin/vi" ! 27: #define HELPFILE "/mntp/doucette/more/more.help" ! 28: #endif ! 29: ! 30: #ifndef INGRES ! 31: #ifndef HELPFILE ! 32: #define HELPFILE libpath(more.help) ! 33: #endif ! 34: #define VI binpath(vi) ! 35: #endif ! 36: ! 37: #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) ! 38: #define Ftell(f) file_pos ! 39: #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) ! 40: #define Getc(f) (++file_pos, getc(f)) ! 41: #define Ungetc(c,f) (--file_pos, ungetc(c,f)) ! 42: ! 43: #ifdef V6 ! 44: #define MBIT RAW ! 45: #define CBREAK ~RAW ! 46: #else ! 47: #define MBIT CBREAK ! 48: #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) ! 49: #endif ! 50: ! 51: #define TBUFSIZ 1024 ! 52: #define LINSIZ 256 ! 53: #define ctrl(letter) ('letter' & 077) ! 54: #define RUBOUT '\177' ! 55: #define ESC '\033' ! 56: #define QUIT '\034' ! 57: ! 58: struct sgttyb otty; ! 59: long file_pos, file_size; ! 60: int fnum, no_intty, no_tty, slow_tty; ! 61: int dum_opt, dlines, onquit(), end_it(); ! 62: #ifdef SIGTSTP ! 63: int onsusp(); ! 64: #endif ! 65: int nscroll = 11; /* Number of lines scrolled by 'd' */ ! 66: int fold_opt = 1; /* Fold long lines */ ! 67: int stop_opt = 1; /* Stop after form feeds */ ! 68: int promptlen; ! 69: int Currline; /* Line we are currently at */ ! 70: int startup = 1; ! 71: int firstf = 1; ! 72: int notell = 1; ! 73: int bad_so; /* True if overwriting does not turn off standout */ ! 74: int inwait, Pause, errors; ! 75: int within; /* true if we are within a file, ! 76: false if we are between files */ ! 77: int hard, dumb, noscroll, hardtabs; ! 78: int catch_susp; /* We should catch the SIGTSTP signal */ ! 79: char **fnames; /* The list of file names */ ! 80: int nfiles; /* Number of files left to process */ ! 81: char *shell; /* The name of the shell to use */ ! 82: int shellp; /* A previous shell command exists */ ! 83: char ch; ! 84: jmp_buf restore; ! 85: char obuf[BUFSIZ]; /* stdout buffer */ ! 86: char Line[LINSIZ]; /* Line buffer */ ! 87: int Lpp = 24; /* lines per page */ ! 88: char *Clear; /* clear screen */ ! 89: char *eraseln; /* erase line */ ! 90: char *Senter, *Sexit;/* enter and exit standout mode */ ! 91: char *tgetstr(); ! 92: int Mcol = 80; /* number of columns */ ! 93: int Wrap = 1; /* set if automargins */ ! 94: long fseek(); ! 95: struct { ! 96: long chrctr, line; ! 97: } context, screen_start; ! 98: extern char PC; /* pad character */ ! 99: extern short ospeed; ! 100: ! 101: ! 102: main(argc, argv) ! 103: int argc; ! 104: char *argv[]; ! 105: { ! 106: register FILE *f; ! 107: register char *s; ! 108: register char *p; ! 109: register char ch; ! 110: register int left; ! 111: int prnames = 0; ! 112: int initopt = 0; ! 113: int srchopt = 0; ! 114: int clearit = 0; ! 115: int initline; ! 116: char initbuf[80]; ! 117: FILE *checkf(); ! 118: ! 119: nfiles = argc; ! 120: fnames = argv; ! 121: initterm (); ! 122: while (--nfiles > 0) { ! 123: if ((ch = (*++fnames)[0]) == '-') { ! 124: for (s = fnames[0] + 1, dlines = 0; *s != '\0'; s++) ! 125: if (isdigit(*s)) ! 126: dlines = dlines*10 + *s - '0'; ! 127: else if (*s == 'd') ! 128: dum_opt = 1; ! 129: else if (*s == 'l') ! 130: stop_opt = 0; ! 131: else if (*s == 'f') ! 132: fold_opt = 0; ! 133: } ! 134: else if (ch == '+') { ! 135: s = *fnames; ! 136: if (*++s == '/') { ! 137: srchopt++; ! 138: for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) ! 139: *p++ = *s++; ! 140: *p = '\0'; ! 141: } ! 142: else { ! 143: initopt++; ! 144: for (initline = 0; *s != '\0'; s++) ! 145: if (isdigit (*s)) ! 146: initline = initline*10 + *s -'0'; ! 147: --initline; ! 148: } ! 149: } ! 150: else break; ! 151: } ! 152: if (dlines == 0) ! 153: dlines = Lpp - (noscroll ? 1 : 2); ! 154: left = dlines; ! 155: if (nfiles > 1) ! 156: prnames++; ! 157: if (!no_intty && nfiles == 0) { ! 158: fputs("Usage: ",stderr); ! 159: fputs(argv[0],stderr); ! 160: fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); ! 161: exit(1); ! 162: } ! 163: else ! 164: f = stdin; ! 165: if (!no_tty) { ! 166: signal(SIGQUIT, onquit); ! 167: signal(SIGINT, end_it); ! 168: #ifdef SIGTSTP ! 169: if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { ! 170: signal(SIGTSTP, onsusp); ! 171: catch_susp++; ! 172: } ! 173: #endif ! 174: stty (2, &otty); ! 175: } ! 176: if (no_intty) { ! 177: if (no_tty) ! 178: copy_file (stdin); ! 179: else { ! 180: if ((ch = Getc (f)) == '\f') ! 181: doclear (); ! 182: else { ! 183: Ungetc (ch, f); ! 184: if (noscroll) ! 185: doclear (); ! 186: } ! 187: if (srchopt) ! 188: search (initbuf, stdin, 1); ! 189: else if (initopt) ! 190: skiplns (initline, stdin); ! 191: screen (stdin, left); ! 192: } ! 193: no_intty = 0; ! 194: prnames++; ! 195: firstf = 0; ! 196: } ! 197: ! 198: while (fnum < nfiles) { ! 199: if ((f = checkf (fnames[fnum], &clearit)) != NULL) { ! 200: context.line = context.chrctr = 0; ! 201: Currline = 0; ! 202: if (firstf) setjmp (restore); ! 203: if (firstf) { ! 204: firstf = 0; ! 205: if (srchopt) ! 206: search (initbuf, f, 1); ! 207: else if (initopt) ! 208: skiplns (initline, f); ! 209: } ! 210: else if (fnum < nfiles && !no_tty) { ! 211: setjmp (restore); ! 212: left = command (fnames[fnum], f); ! 213: } ! 214: if (left != 0) { ! 215: if (noscroll || clearit) ! 216: doclear (); ! 217: if (prnames) { ! 218: if (bad_so) ! 219: erase (0); ! 220: pr("::::::::::::::"); ! 221: if (promptlen > 14) ! 222: erase (14); ! 223: printf ("\n%s\n::::::::::::::\n", fnames[fnum]); ! 224: if (left > Lpp - 4) ! 225: left = Lpp - 4; ! 226: } ! 227: if (no_tty) ! 228: copy_file (f); ! 229: else { ! 230: within++; ! 231: screen(f, left); ! 232: within = 0; ! 233: } ! 234: } ! 235: setjmp (restore); ! 236: fflush(stdout); ! 237: fclose(f); ! 238: screen_start.line = screen_start.chrctr = 0L; ! 239: context.line = context.chrctr = 0L; ! 240: } ! 241: fnum++; ! 242: firstf = 0; ! 243: } ! 244: reset_tty (); ! 245: exit(0); ! 246: } ! 247: ! 248: /* ! 249: ** Check whether the file named by fs is an ASCII file which the user may ! 250: ** access. If it is, return the opened file. Otherwise return NULL. ! 251: */ ! 252: ! 253: FILE * ! 254: checkf (fs, clearfirst) ! 255: register char *fs; ! 256: int *clearfirst; ! 257: { ! 258: struct stat stbuf; ! 259: register FILE *f; ! 260: char c; ! 261: ! 262: if (stat (fs, &stbuf) == -1) { ! 263: fflush(stdout); ! 264: perror(fs); ! 265: return (NULL); ! 266: } ! 267: if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { ! 268: printf("\n*** %s: directory ***\n\n", fs); ! 269: return (NULL); ! 270: } ! 271: if ((f=Fopen(fs, "r")) == NULL) { ! 272: fflush(stdout); ! 273: perror(fs); ! 274: return (NULL); ! 275: } ! 276: c = Getc(f); ! 277: ! 278: /* Try to see whether it is an ASCII file */ ! 279: ! 280: switch ((c | *f->_ptr << 8) & 0177777) { ! 281: case 0405: ! 282: case 0407: ! 283: case 0410: ! 284: case 0411: ! 285: case 0413: ! 286: case 0177545: ! 287: printf("\n******** %s: Not a text file ********\n\n", fs); ! 288: fclose (f); ! 289: return (NULL); ! 290: default: ! 291: break; ! 292: } ! 293: if (c == '\f') ! 294: *clearfirst = 1; ! 295: else { ! 296: *clearfirst = 0; ! 297: Ungetc (c, f); ! 298: } ! 299: if ((file_size = stbuf.st_size) == 0) ! 300: file_size = 0x7fffffffffffffffL; ! 301: return (f); ! 302: } ! 303: ! 304: /* ! 305: ** A real function, for the tputs routine in termlib ! 306: */ ! 307: ! 308: putch (ch) ! 309: char ch; ! 310: { ! 311: putchar (ch); ! 312: } ! 313: ! 314: /* ! 315: ** Print out the contents of the file f, one screenful at a time. ! 316: */ ! 317: ! 318: #define STOP -10 ! 319: ! 320: screen (f, num_lines) ! 321: register FILE *f; ! 322: register int num_lines; ! 323: { ! 324: register int c; ! 325: register int nchars; ! 326: int length; ! 327: ! 328: for (;;) { ! 329: while (num_lines > 0 && !Pause) { ! 330: if ((nchars = getline (f, &length)) == EOF) ! 331: return; ! 332: if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) ! 333: erase (0); ! 334: prbuf (Line, length); ! 335: if (nchars < promptlen) ! 336: erase (nchars); /* erase () sets promptlen to 0 */ ! 337: else promptlen = 0; ! 338: if (nchars < Mcol || !fold_opt) ! 339: putchar('\n'); ! 340: if (nchars == STOP) ! 341: break; ! 342: num_lines--; ! 343: } ! 344: fflush(stdout); ! 345: if ((c = Getc(f)) == EOF) ! 346: return; ! 347: Ungetc (c, f); ! 348: setjmp (restore); ! 349: Pause = 0; startup = 0; ! 350: if ((num_lines = command (NULL, f)) == 0) ! 351: return; ! 352: if (hard && promptlen > 0) ! 353: erase (0); ! 354: if (noscroll && num_lines == dlines) ! 355: doclear (); ! 356: screen_start.line = Currline; ! 357: screen_start.chrctr = Ftell (f); ! 358: } ! 359: } ! 360: ! 361: /* ! 362: ** Come here if a quit signal is received ! 363: */ ! 364: ! 365: onquit() ! 366: { ! 367: signal(SIGQUIT, SIG_IGN); ! 368: if (!inwait) { ! 369: putchar ('\n'); ! 370: if (!startup) { ! 371: signal(SIGQUIT, onquit); ! 372: longjmp (restore, 1); ! 373: } ! 374: else ! 375: Pause++; ! 376: } ! 377: else if (!dum_opt && notell) { ! 378: write (2, "[Use q or Q to quit]", 20); ! 379: promptlen += 20; ! 380: notell = 0; ! 381: } ! 382: signal(SIGQUIT, onquit); ! 383: } ! 384: ! 385: /* ! 386: ** Clean up terminal state and exit. Also come here if interrupt signal received ! 387: */ ! 388: ! 389: end_it () ! 390: { ! 391: ! 392: reset_tty (); ! 393: if (promptlen > 0) { ! 394: kill_line (); ! 395: fflush (stdout); ! 396: } ! 397: else ! 398: write (2, "\n", 1); ! 399: _exit(0); ! 400: } ! 401: ! 402: copy_file(f) ! 403: register FILE *f; ! 404: { ! 405: register int c; ! 406: ! 407: while ((c = getc(f)) != EOF) ! 408: putchar(c); ! 409: } ! 410: ! 411: /* Simplified printf function */ ! 412: ! 413: printf (fmt, args) ! 414: register char *fmt; ! 415: int args; ! 416: { ! 417: register int *argp; ! 418: register char ch; ! 419: register int ccount; ! 420: ! 421: ccount = 0; ! 422: argp = &args; ! 423: while (*fmt) { ! 424: while ((ch = *fmt++) != '%') { ! 425: if (ch == '\0') ! 426: return (ccount); ! 427: ccount++; ! 428: putchar (ch); ! 429: } ! 430: switch (*fmt++) { ! 431: case 'd': ! 432: ccount += printd (*argp); ! 433: break; ! 434: case 's': ! 435: ccount += pr ((char *)*argp); ! 436: break; ! 437: case '%': ! 438: ccount++; ! 439: argp--; ! 440: putchar ('%'); ! 441: break; ! 442: case '0': ! 443: return (ccount); ! 444: default: ! 445: break; ! 446: } ! 447: ++argp; ! 448: } ! 449: return (ccount); ! 450: ! 451: } ! 452: ! 453: /* ! 454: ** Print an integer as a string of decimal digits, ! 455: ** returning the length of the print representation. ! 456: */ ! 457: ! 458: printd (n) ! 459: int n; ! 460: { ! 461: int a, nchars; ! 462: ! 463: if (a = n/10) ! 464: nchars = 1 + printd(a); ! 465: else ! 466: nchars = 1; ! 467: putchar (n % 10 + '0'); ! 468: return (nchars); ! 469: } ! 470: ! 471: /* Put the print representation of an integer into a string */ ! 472: static char *sptr; ! 473: ! 474: scanstr (n, str) ! 475: int n; ! 476: char *str; ! 477: { ! 478: sptr = str; ! 479: sprintf (n); ! 480: *sptr = '\0'; ! 481: } ! 482: ! 483: sprintf (n) ! 484: { ! 485: int a; ! 486: ! 487: if (a = n/10) ! 488: sprintf (a); ! 489: *sptr++ = n % 10 + '0'; ! 490: } ! 491: ! 492: static char bell = ctrl(G); ! 493: ! 494: strlen (s) ! 495: char *s; ! 496: { ! 497: register char *p; ! 498: ! 499: p = s; ! 500: while (*p++) ! 501: ; ! 502: return (p - s - 1); ! 503: } ! 504: ! 505: /* See whether the last component of the path name "path" is equal to the ! 506: ** string "string" ! 507: */ ! 508: ! 509: tailequ (path, string) ! 510: char *path; ! 511: register char *string; ! 512: { ! 513: register char *tail; ! 514: ! 515: tail = path + strlen(path); ! 516: while (tail >= path) ! 517: if (*(--tail) == '/') ! 518: break; ! 519: ++tail; ! 520: while (*tail++ == *string++) ! 521: if (*tail == '\0') ! 522: return(1); ! 523: return(0); ! 524: } ! 525: ! 526: prompt (filename) ! 527: char *filename; ! 528: { ! 529: if (promptlen > 0) ! 530: kill_line (); ! 531: if (!hard) { ! 532: promptlen = 8; ! 533: if (Senter && Sexit) ! 534: tputs (Senter, 1, putch); ! 535: pr("--More--"); ! 536: if (filename != NULL) { ! 537: promptlen += printf ("(Next file: %s)", filename); ! 538: } ! 539: else if (!no_intty) { ! 540: promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); ! 541: } ! 542: if (dum_opt) { ! 543: promptlen += pr("[Hit space to continue, Rubout to abort]"); ! 544: } ! 545: if (Senter && Sexit) ! 546: tputs (Sexit, 1, putch); ! 547: fflush(stdout); ! 548: } ! 549: else ! 550: write (2, &bell, 1); ! 551: inwait++; ! 552: } ! 553: ! 554: /* ! 555: ** Get a logical line ! 556: */ ! 557: ! 558: getline(f, length) ! 559: register FILE *f; ! 560: int *length; ! 561: { ! 562: register int c; ! 563: register char *p; ! 564: register int column; ! 565: static int colflg; ! 566: ! 567: p = Line; ! 568: column = 0; ! 569: c = Getc (f); ! 570: if (colflg && c == '\n') { ! 571: Currline++; ! 572: c = Getc (f); ! 573: } ! 574: while (p < &Line[LINSIZ - 1]) { ! 575: if (c == EOF) { ! 576: if (p > Line) { ! 577: *p = '\0'; ! 578: *length = p - Line; ! 579: return (column); ! 580: } ! 581: *length = p - Line; ! 582: return (EOF); ! 583: } ! 584: if (c == '\n') { ! 585: Currline++; ! 586: break; ! 587: } ! 588: *p++ = c; ! 589: if (c == '\t') ! 590: if (hardtabs && column < promptlen && !hard) { ! 591: if (eraseln && !dumb) { ! 592: column = 1 + (column | 7); ! 593: tputs (eraseln, 1, putch); ! 594: promptlen = 0; ! 595: } ! 596: else { ! 597: for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { ! 598: *p++ = ' '; ! 599: } ! 600: if (column >= promptlen) promptlen = 0; ! 601: } ! 602: } ! 603: else ! 604: column = 1 + (column | 7); ! 605: else if (c == '\b') ! 606: column--; ! 607: else if (c == '\r') ! 608: column = 0; ! 609: else if (c == '\f' && stop_opt) { ! 610: p[-1] = '^'; ! 611: *p++ = 'L'; ! 612: column += 2; ! 613: Pause++; ! 614: } ! 615: else if (c == EOF) { ! 616: *length = p - Line; ! 617: return (column); ! 618: } ! 619: else if (c >= ' ' && c != RUBOUT) ! 620: column++; ! 621: if (column >= Mcol && fold_opt) break; ! 622: c = Getc (f); ! 623: } ! 624: if (column >= Mcol && Mcol > 0) { ! 625: if (!Wrap) { ! 626: *p++ = '\n'; ! 627: } ! 628: } ! 629: colflg = column == Mcol && fold_opt; ! 630: *length = p - Line; ! 631: *p = 0; ! 632: return (column); ! 633: } ! 634: ! 635: /* ! 636: ** Erase the rest of the prompt, assuming we are starting at column col. ! 637: */ ! 638: ! 639: erase (col) ! 640: register int col; ! 641: { ! 642: ! 643: if (promptlen == 0) ! 644: return; ! 645: if (hard) { ! 646: putchar ('\n'); ! 647: } ! 648: else { ! 649: if (col == 0) ! 650: putchar ('\r'); ! 651: if (!dumb && eraseln) ! 652: tputs (eraseln, 1, putch); ! 653: else ! 654: for (col = promptlen - col; col > 0; col--) ! 655: putchar (' '); ! 656: } ! 657: promptlen = 0; ! 658: } ! 659: ! 660: /* ! 661: ** Erase the current line entirely ! 662: */ ! 663: ! 664: kill_line () ! 665: { ! 666: erase (0); ! 667: if (!eraseln || dumb) putchar ('\r'); ! 668: } ! 669: ! 670: /* ! 671: ** Print string and return number of characters ! 672: */ ! 673: ! 674: pr(s1) ! 675: char *s1; ! 676: { ! 677: register char *s; ! 678: register char c; ! 679: ! 680: for (s = s1; c = *s++; ) ! 681: putchar(c); ! 682: return (s - s1 - 1); ! 683: } ! 684: ! 685: ! 686: /* Print a buffer of n characters */ ! 687: ! 688: prbuf (s, n) ! 689: register char *s; ! 690: register int n; ! 691: { ! 692: while (n-- > 0) ! 693: putchar (*s++); ! 694: } ! 695: ! 696: /* ! 697: ** Clear the screen ! 698: */ ! 699: ! 700: doclear() ! 701: { ! 702: if (Clear && !hard) { ! 703: tputs(Clear, 1, putch); ! 704: ! 705: /* Put out carriage return so that system doesn't ! 706: ** get confused by escape sequences when expanding tabs ! 707: */ ! 708: putchar ('\r'); ! 709: promptlen = 0; ! 710: } ! 711: } ! 712: ! 713: static int lastcmd, lastarg, lastp; ! 714: static int lastcolon; ! 715: char shell_line[132]; ! 716: ! 717: /* ! 718: ** Read a command and do it. A command consists of an optional integer ! 719: ** argument followed by the command character. Return the number of lines ! 720: ** to display in the next screenful. If there is nothing more to display ! 721: ** in the current file, zero is returned. ! 722: */ ! 723: ! 724: command (filename, f) ! 725: char *filename; ! 726: register FILE *f; ! 727: { ! 728: register int nlines; ! 729: register int retval; ! 730: register char c; ! 731: char colonch; ! 732: FILE *helpf; ! 733: int done; ! 734: char comchar, cmdbuf[80], *p; ! 735: ! 736: #define ret(val) retval=val;done++;break ! 737: ! 738: done = 0; ! 739: if (!errors) ! 740: prompt (filename); ! 741: else ! 742: errors = 0; ! 743: if (MBIT == RAW && slow_tty) { ! 744: otty.sg_flags |= MBIT; ! 745: stty(2, &otty); ! 746: } ! 747: for (;;) { ! 748: nlines = number (&comchar); ! 749: lastp = colonch = 0; ! 750: if (comchar == '.') { /* Repeat last command */ ! 751: lastp++; ! 752: comchar = lastcmd; ! 753: nlines = lastarg; ! 754: if (lastcmd == ':') ! 755: colonch = lastcolon; ! 756: } ! 757: lastcmd = comchar; ! 758: lastarg = nlines; ! 759: if (comchar == otty.sg_erase) { ! 760: kill_line (); ! 761: prompt (filename); ! 762: continue; ! 763: } ! 764: switch (comchar) { ! 765: case ':': ! 766: retval = colon (filename, colonch, nlines); ! 767: if (retval >= 0) ! 768: done++; ! 769: break; ! 770: case ' ': ! 771: case 'z': ! 772: if (nlines == 0) nlines = dlines; ! 773: else if (comchar == 'z') dlines = nlines; ! 774: ret (nlines); ! 775: case 'd': ! 776: case ctrl(D): ! 777: if (nlines != 0) nscroll = nlines; ! 778: ret (nscroll); ! 779: case RUBOUT: ! 780: case 'q': ! 781: case 'Q': ! 782: end_it (); ! 783: case 's': ! 784: case 'f': ! 785: if (nlines == 0) nlines++; ! 786: if (comchar == 'f') ! 787: nlines *= dlines; ! 788: putchar ('\r'); ! 789: erase (0); ! 790: printf("\n...skipping %d line", nlines); ! 791: if (nlines > 1) ! 792: pr("s\n\n"); ! 793: else ! 794: pr("\n\n"); ! 795: while (nlines > 0) { ! 796: while ((c = Getc (f)) != '\n') ! 797: if (c == EOF) { ! 798: retval = 0; ! 799: done++; ! 800: goto endsw; ! 801: } ! 802: Currline++; ! 803: nlines--; ! 804: } ! 805: ret (dlines); ! 806: case '\n': ! 807: if (nlines != 0) ! 808: dlines = nlines; ! 809: else ! 810: nlines = 1; ! 811: ret (nlines); ! 812: case '\f': ! 813: if (!no_intty) { ! 814: doclear (); ! 815: Fseek (f, screen_start.chrctr); ! 816: Currline = screen_start.line; ! 817: ret (dlines); ! 818: } ! 819: else { ! 820: write (2, &bell, 1); ! 821: break; ! 822: } ! 823: case '\'': ! 824: if (!no_intty) { ! 825: kill_line (); ! 826: pr ("\n***Back***\n\n"); ! 827: Fseek (f, context.chrctr); ! 828: Currline = context.line; ! 829: ret (dlines); ! 830: } ! 831: else { ! 832: write (2, &bell, 1); ! 833: break; ! 834: } ! 835: case '=': ! 836: kill_line (); ! 837: promptlen = printd (Currline); ! 838: fflush (stdout); ! 839: break; ! 840: case 'n': ! 841: lastp++; ! 842: case '/': ! 843: if (nlines == 0) nlines++; ! 844: kill_line (); ! 845: pr ("/"); ! 846: promptlen = 1; ! 847: fflush (stdout); ! 848: if (lastp) { ! 849: write (2,"\r", 1); ! 850: search (NULL, f, nlines); /* Use previous r.e. */ ! 851: } ! 852: else { ! 853: ttyin (cmdbuf, 78, '/'); ! 854: write (2, "\r", 1); ! 855: search (cmdbuf, f, nlines); ! 856: } ! 857: ret (dlines); ! 858: case '!': ! 859: do_shell (filename); ! 860: break; ! 861: case 'h': ! 862: if ((helpf = fopen (HELPFILE, "r")) == NULL) ! 863: error ("Can't open help file"); ! 864: if (noscroll) doclear (); ! 865: copy_file (helpf); ! 866: close (helpf); ! 867: prompt (filename); ! 868: break; ! 869: case 'v': /* This case should go right before default */ ! 870: if (!no_intty) { ! 871: kill_line (); ! 872: cmdbuf[0] = '+'; ! 873: scanstr (Currline, &cmdbuf[1]); ! 874: pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); ! 875: execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); ! 876: break; ! 877: } ! 878: default: ! 879: write (2, &bell, 1); ! 880: break; ! 881: } ! 882: if (done) break; ! 883: } ! 884: putchar ('\r'); ! 885: endsw: ! 886: inwait = 0; ! 887: notell++; ! 888: if (MBIT == RAW && slow_tty) { ! 889: otty.sg_flags &= ~MBIT; ! 890: stty(2, &otty); ! 891: } ! 892: return (retval); ! 893: } ! 894: ! 895: char ch; ! 896: ! 897: /* ! 898: * Execute a colon-prefixed command. ! 899: * Returns <0 if not a command that should cause ! 900: * more of the file to be printed. ! 901: */ ! 902: ! 903: colon (filename, cmd, nlines) ! 904: char *filename; ! 905: int cmd; ! 906: int nlines; ! 907: { ! 908: if (cmd == 0) ! 909: ch = readch (); ! 910: else ! 911: ch = cmd; ! 912: lastcolon = ch; ! 913: switch (ch) { ! 914: case 'f': ! 915: kill_line (); ! 916: if (!no_intty) ! 917: promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); ! 918: else ! 919: promptlen = printf ("[Not a file] line %d", Currline); ! 920: fflush (stdout); ! 921: return (-1); ! 922: case 'n': ! 923: if (nlines == 0) { ! 924: if (fnum >= nfiles - 1) ! 925: end_it (); ! 926: nlines++; ! 927: } ! 928: putchar ('\r'); ! 929: erase (0); ! 930: skipf (nlines); ! 931: return (0); ! 932: case 'p': ! 933: if (no_intty) { ! 934: write (2, &bell, 1); ! 935: return (-1); ! 936: } ! 937: putchar ('\r'); ! 938: erase (0); ! 939: if (nlines == 0) ! 940: nlines++; ! 941: skipf (-nlines); ! 942: return (0); ! 943: case '!': ! 944: do_shell (filename); ! 945: return (-1); ! 946: case 'q': ! 947: case 'Q': ! 948: end_it (); ! 949: default: ! 950: write (2, &bell, 1); ! 951: return (-1); ! 952: } ! 953: } ! 954: ! 955: /* ! 956: ** Read a decimal number from the terminal. Set cmd to the non-digit which ! 957: ** terminates the number. ! 958: */ ! 959: ! 960: number(cmd) ! 961: char *cmd; ! 962: { ! 963: register int i; ! 964: ! 965: i = 0; ch = otty.sg_kill; ! 966: for (;;) { ! 967: ch = readch (); ! 968: if (ch >= '0' && ch <= '9') ! 969: i = i*10 + ch - '0'; ! 970: else if (ch == otty.sg_kill) ! 971: i = 0; ! 972: else { ! 973: *cmd = ch; ! 974: break; ! 975: } ! 976: } ! 977: return (i); ! 978: } ! 979: ! 980: do_shell (filename) ! 981: char *filename; ! 982: { ! 983: char cmdbuf[80]; ! 984: ! 985: kill_line (); ! 986: pr ("!"); ! 987: fflush (stdout); ! 988: promptlen = 1; ! 989: if (lastp) ! 990: pr (shell_line); ! 991: else { ! 992: ttyin (cmdbuf, 78, '!'); ! 993: if (expand (shell_line, cmdbuf)) { ! 994: kill_line (); ! 995: promptlen = printf ("!%s", shell_line); ! 996: } ! 997: } ! 998: fflush (stdout); ! 999: write (2, "\n", 1); ! 1000: promptlen = 0; ! 1001: shellp = 1; ! 1002: execute (filename, shell, shell, "-c", shell_line, 0); ! 1003: } ! 1004: ! 1005: /* ! 1006: ** Search for nth ocurrence of regular expression contained in buf in the file ! 1007: */ ! 1008: ! 1009: search (buf, file, n) ! 1010: char buf[]; ! 1011: FILE *file; ! 1012: register int n; ! 1013: { ! 1014: long startline = Ftell (file); ! 1015: register long line1 = startline; ! 1016: register long line2 = startline; ! 1017: register long line3 = startline; ! 1018: register int lncount; ! 1019: int saveln, rv, re_exec(); ! 1020: char *s, *re_comp(); ! 1021: ! 1022: context.line = saveln = Currline; ! 1023: context.chrctr = startline; ! 1024: lncount = 0; ! 1025: if ((s = re_comp (buf)) != 0) ! 1026: error (s); ! 1027: while (!feof (file)) { ! 1028: line3 = line2; ! 1029: line2 = line1; ! 1030: line1 = Ftell (file); ! 1031: rdline (file); ! 1032: lncount++; ! 1033: if ((rv = re_exec (Line)) == 1) ! 1034: if (--n == 0) { ! 1035: if (lncount > 3 || (lncount > 1 && no_intty)) ! 1036: pr ("\n...skipping\n"); ! 1037: if (!no_intty) { ! 1038: Currline -= (lncount >= 3 ? 3 : lncount); ! 1039: Fseek (file, line3); ! 1040: } ! 1041: else { ! 1042: kill_line (); ! 1043: pr (Line); ! 1044: putchar ('\n'); ! 1045: } ! 1046: break; ! 1047: } ! 1048: else if (rv == -1) ! 1049: error ("Regular expression botch"); ! 1050: } ! 1051: if (feof (file)) { ! 1052: if (!no_intty) { ! 1053: #ifdef V6 ! 1054: file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ ! 1055: #endif ! 1056: Currline = saveln; ! 1057: Fseek (file, startline); ! 1058: } ! 1059: else { ! 1060: pr ("\nPattern not found\n"); ! 1061: end_it (); ! 1062: } ! 1063: error ("Pattern not found"); ! 1064: } ! 1065: } ! 1066: ! 1067: execute (filename, cmd, args) ! 1068: char *filename; ! 1069: char *cmd, *args; ! 1070: { ! 1071: int id; ! 1072: ! 1073: fflush (stdout); ! 1074: reset_tty (); ! 1075: while ((id = fork ()) < 0) ! 1076: sleep (5); ! 1077: if (id == 0) { ! 1078: execv (cmd, &args); ! 1079: write (2, "exec failed\n", 12); ! 1080: exit (1); ! 1081: } ! 1082: signal (SIGINT, SIG_IGN); ! 1083: signal (SIGQUIT, SIG_IGN); ! 1084: #ifdef SIGTSTP ! 1085: if (catch_susp) ! 1086: signal(SIGTSTP, SIG_DFL); ! 1087: #endif ! 1088: wait (0); ! 1089: signal (SIGINT, end_it); ! 1090: signal (SIGQUIT, onquit); ! 1091: #ifdef SIGTSTP ! 1092: if (catch_susp) ! 1093: signal(SIGTSTP, onsusp); ! 1094: #endif ! 1095: set_tty (); ! 1096: pr ("------------------------\n"); ! 1097: prompt (filename); ! 1098: } ! 1099: /* ! 1100: ** Skip n lines in the file f ! 1101: */ ! 1102: ! 1103: skiplns (n, f) ! 1104: register int n; ! 1105: register FILE *f; ! 1106: { ! 1107: register char c; ! 1108: ! 1109: while (n > 0) { ! 1110: while ((c = Getc (f)) != '\n') ! 1111: if (c == EOF) ! 1112: return; ! 1113: n--; ! 1114: Currline++; ! 1115: } ! 1116: } ! 1117: ! 1118: /* ! 1119: ** Skip nskip files in the file list (from the command line). Nskip may be ! 1120: ** negative. ! 1121: */ ! 1122: ! 1123: skipf (nskip) ! 1124: register int nskip; ! 1125: { ! 1126: if (nskip == 0) return; ! 1127: if (nskip > 0) { ! 1128: if (fnum + nskip > nfiles - 1) ! 1129: nskip = nfiles - fnum - 1; ! 1130: } ! 1131: else if (within) ! 1132: ++fnum; ! 1133: fnum += nskip; ! 1134: if (fnum < 0) ! 1135: fnum = 0; ! 1136: pr ("\n...Skipping "); ! 1137: pr (nskip > 0 ? "to file " : "back to file "); ! 1138: pr (fnames[fnum]); ! 1139: pr ("\n\n"); ! 1140: --fnum; ! 1141: } ! 1142: ! 1143: /*----------------------------- Terminal I/O -------------------------------*/ ! 1144: ! 1145: initterm () ! 1146: { ! 1147: char buf[TBUFSIZ]; ! 1148: char clearbuf[100]; ! 1149: char *clearptr, *padstr; ! 1150: char *getenv(); ! 1151: int ldisc; ! 1152: ! 1153: setbuf(stdout, obuf); ! 1154: if (!(no_tty = gtty(1, &otty))) { ! 1155: if (tgetent(buf, getenv("TERM")) <= 0) { ! 1156: dumb++; ! 1157: } ! 1158: else { ! 1159: if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) { ! 1160: hard++; /* Hard copy terminal */ ! 1161: Lpp = 24; ! 1162: } ! 1163: if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) ! 1164: noscroll++; ! 1165: if ((Mcol = tgetnum("co")) < 0) ! 1166: Mcol = 80; ! 1167: Wrap = tgetflag("am"); ! 1168: bad_so = tgetflag ("xs"); ! 1169: clearptr = clearbuf; ! 1170: eraseln = tgetstr("ce",&clearptr); ! 1171: Clear = tgetstr("cl", &clearptr); ! 1172: Senter = tgetstr("so", &clearptr); ! 1173: Sexit = tgetstr("se", &clearptr); ! 1174: if (padstr = tgetstr("pc", &clearptr)) ! 1175: PC = *padstr; ! 1176: } ! 1177: if ((shell = getenv("SHELL")) == NULL) ! 1178: shell = "/bin/sh"; ! 1179: } ! 1180: no_intty = gtty(0, &otty); ! 1181: gtty(2, &otty); ! 1182: ospeed = otty.sg_ospeed; ! 1183: slow_tty = ospeed < B1200; ! 1184: hardtabs = !(otty.sg_flags & XTABS); ! 1185: if (!no_tty) { ! 1186: otty.sg_flags &= ~ECHO; ! 1187: if (MBIT == CBREAK || !slow_tty) ! 1188: otty.sg_flags |= MBIT; ! 1189: } ! 1190: } ! 1191: ! 1192: readch () ! 1193: { ! 1194: char ch; ! 1195: extern int errno; ! 1196: ! 1197: if (read (2, &ch, 1) <= 0) ! 1198: if (errno != EINTR) ! 1199: exit(0); ! 1200: else ! 1201: ch = otty.sg_kill; ! 1202: return (ch); ! 1203: } ! 1204: ! 1205: static char BS = '\b'; ! 1206: static char CARAT = '^'; ! 1207: ! 1208: ttyin (buf, nmax, pchar) ! 1209: char buf[]; ! 1210: register int nmax; ! 1211: char pchar; ! 1212: { ! 1213: register char *sptr; ! 1214: register char ch; ! 1215: register int slash = 0; ! 1216: int maxlen; ! 1217: char cbuf; ! 1218: ! 1219: sptr = buf; ! 1220: maxlen = 0; ! 1221: while (sptr - buf < nmax) { ! 1222: if (promptlen > maxlen) maxlen = promptlen; ! 1223: ch = readch (); ! 1224: if (ch == '\\') { ! 1225: slash++; ! 1226: } ! 1227: else if ((ch == otty.sg_erase) && !slash) { ! 1228: if (sptr > buf) { ! 1229: --promptlen; ! 1230: write (2, &BS, 1); ! 1231: --sptr; ! 1232: if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { ! 1233: --promptlen; ! 1234: write (2, &BS, 1); ! 1235: } ! 1236: continue; ! 1237: } ! 1238: else { ! 1239: if (!eraseln) promptlen = maxlen; ! 1240: longjmp (restore, 1); ! 1241: } ! 1242: } ! 1243: else if ((ch == otty.sg_kill) && !slash) { ! 1244: if (hard) { ! 1245: show (ch); ! 1246: putchar ('\n'); ! 1247: putchar (pchar); ! 1248: } ! 1249: else { ! 1250: putchar ('\r'); ! 1251: putchar (pchar); ! 1252: if (eraseln) ! 1253: erase (1); ! 1254: promptlen = 1; ! 1255: } ! 1256: sptr = buf; ! 1257: fflush (stdout); ! 1258: continue; ! 1259: } ! 1260: if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { ! 1261: write (2, &BS, 1); ! 1262: --sptr; ! 1263: } ! 1264: if (ch != '\\') ! 1265: slash = 0; ! 1266: *sptr++ = ch; ! 1267: if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { ! 1268: ch += ch == RUBOUT ? -0100 : 0100; ! 1269: write (2, &CARAT, 1); ! 1270: promptlen++; ! 1271: } ! 1272: cbuf = ch; ! 1273: if (ch != '\n' && ch != ESC) { ! 1274: write (2, &cbuf, 1); ! 1275: promptlen++; ! 1276: } ! 1277: else ! 1278: break; ! 1279: } ! 1280: *--sptr = '\0'; ! 1281: if (!eraseln) promptlen = maxlen; ! 1282: if (sptr - buf >= nmax - 1) ! 1283: error ("Line too long"); ! 1284: } ! 1285: ! 1286: expand (outbuf, inbuf) ! 1287: char *outbuf; ! 1288: char *inbuf; ! 1289: { ! 1290: register char *instr; ! 1291: register char *outstr; ! 1292: register char ch; ! 1293: char temp[200]; ! 1294: int changed = 0; ! 1295: ! 1296: instr = inbuf; ! 1297: outstr = temp; ! 1298: while ((ch = *instr++) != '\0') ! 1299: switch (ch) { ! 1300: case '%': ! 1301: if (!no_intty) { ! 1302: strcpy (outstr, fnames[fnum]); ! 1303: outstr += strlen (fnames[fnum]); ! 1304: changed++; ! 1305: } ! 1306: else ! 1307: *outstr++ = ch; ! 1308: break; ! 1309: case '!': ! 1310: if (!shellp) ! 1311: error ("No previous command to substitute for"); ! 1312: strcpy (outstr, shell_line); ! 1313: outstr += strlen (shell_line); ! 1314: changed++; ! 1315: break; ! 1316: case '\\': ! 1317: if (*instr == '%' || *instr == '!') { ! 1318: *outstr++ = *instr++; ! 1319: break; ! 1320: } ! 1321: default: ! 1322: *outstr++ = ch; ! 1323: } ! 1324: *outstr++ = '\0'; ! 1325: strcpy (outbuf, temp); ! 1326: return (changed); ! 1327: } ! 1328: ! 1329: show (ch) ! 1330: register char ch; ! 1331: { ! 1332: char cbuf; ! 1333: ! 1334: if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { ! 1335: ch += ch == RUBOUT ? -0100 : 0100; ! 1336: write (2, &CARAT, 1); ! 1337: promptlen++; ! 1338: } ! 1339: cbuf = ch; ! 1340: write (2, &cbuf, 1); ! 1341: promptlen++; ! 1342: } ! 1343: ! 1344: error (mess) ! 1345: char *mess; ! 1346: { ! 1347: kill_line (); ! 1348: promptlen += strlen (mess); ! 1349: if (Senter && Sexit) { ! 1350: tputs (Senter, 1, putch); ! 1351: pr(mess); ! 1352: tputs (Sexit, 1, putch); ! 1353: } ! 1354: else ! 1355: pr (mess); ! 1356: fflush(stdout); ! 1357: errors++; ! 1358: longjmp (restore, 1); ! 1359: } ! 1360: ! 1361: ! 1362: set_tty () ! 1363: { ! 1364: otty.sg_flags |= MBIT; ! 1365: otty.sg_flags &= ~ECHO; ! 1366: stty(2, &otty); ! 1367: } ! 1368: ! 1369: reset_tty () ! 1370: { ! 1371: otty.sg_flags |= ECHO; ! 1372: otty.sg_flags &= ~MBIT; ! 1373: stty(2, &otty); ! 1374: } ! 1375: ! 1376: rdline (f) ! 1377: register FILE *f; ! 1378: { ! 1379: register char c; ! 1380: register char *p; ! 1381: ! 1382: p = Line; ! 1383: while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) ! 1384: *p++ = c; ! 1385: if (c == '\n') ! 1386: Currline++; ! 1387: *p = '\0'; ! 1388: } ! 1389: ! 1390: /* Come here when we get a suspend signal from the terminal */ ! 1391: ! 1392: #ifdef SIGTSTP ! 1393: onsusp () ! 1394: { ! 1395: reset_tty (); ! 1396: fflush (stdout); ! 1397: /* Send the TSTP signal to suspend our process group */ ! 1398: kill (0, SIGTSTP); ! 1399: /* Pause for station break */ ! 1400: ! 1401: /* We're back */ ! 1402: signal (SIGTSTP, onsusp); ! 1403: set_tty (); ! 1404: if (inwait) ! 1405: longjmp (restore); ! 1406: } ! 1407: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.