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.4 (Berkeley) 4/3/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;
  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 (eraseln && !dumb) {
 737:             column = 1 + (column | 7);
 738:             tputs (eraseln, 1, putch);
 739:             promptlen = 0;
 740:         }
 741:         else {
 742:             for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) {
 743:             *p++ = ' ';
 744:             }
 745:             if (column >= promptlen) promptlen = 0;
 746:         }
 747:         }
 748:         else
 749:         column = 1 + (column | 7);
 750:     else if (c == '\b' && column > 0)
 751:         column--;
 752:     else if (c == '\r')
 753:         column = 0;
 754:     else if (c == '\f' && stop_opt) {
 755:         p[-1] = '^';
 756:         *p++ = 'L';
 757:         column += 2;
 758:         Pause++;
 759:     }
 760:     else if (c == EOF) {
 761:         *length = p - Line;
 762:         return (column);
 763:     }
 764:     else if (c >= ' ' && c != RUBOUT)
 765:         column++;
 766:     if (column >= Mcol && fold_opt) break;
 767:     c = Getc (f);
 768:     }
 769:     if (column >= Mcol && Mcol > 0) {
 770:     if (!Wrap) {
 771:         *p++ = '\n';
 772:     }
 773:     }
 774:     colflg = column == Mcol && fold_opt;
 775:     *length = p - Line;
 776:     *p = 0;
 777:     return (column);
 778: }
 779: 
 780: /*
 781: ** Erase the rest of the prompt, assuming we are starting at column col.
 782: */
 783: 
 784: erase (col)
 785: register int col;
 786: {
 787: 
 788:     if (promptlen == 0)
 789:     return;
 790:     if (hard) {
 791:     putchar ('\n');
 792:     }
 793:     else {
 794:     if (col == 0)
 795:         putchar ('\r');
 796:     if (!dumb && eraseln)
 797:         tputs (eraseln, 1, putch);
 798:     else
 799:         for (col = promptlen - col; col > 0; col--)
 800:         putchar (' ');
 801:     }
 802:     promptlen = 0;
 803: }
 804: 
 805: /*
 806: ** Erase the current line entirely
 807: */
 808: 
 809: kill_line ()
 810: {
 811:     erase (0);
 812:     if (!eraseln || dumb) putchar ('\r');
 813: }
 814: 
 815: /*
 816:  * force clear to end of line
 817:  */
 818: cleareol()
 819: {
 820:     tputs(eraseln, 1, putch);
 821: }
 822: 
 823: clreos()
 824: {
 825:     tputs(EodClr, 1, putch);
 826: }
 827: 
 828: /*
 829: **  Print string and return number of characters
 830: */
 831: 
 832: pr(s1)
 833: char    *s1;
 834: {
 835:     register char   *s;
 836:     register char   c;
 837: 
 838:     for (s = s1; c = *s++; )
 839:     putchar(c);
 840:     return (s - s1 - 1);
 841: }
 842: 
 843: 
 844: /* Print a buffer of n characters */
 845: 
 846: prbuf (s, n)
 847: register char *s;
 848: register int n;
 849: {
 850:     register char c;            /* next output character */
 851:     register int state;         /* next output char's UL state */
 852: #define wouldul(s,n)    ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
 853: 
 854:     while (--n >= 0)
 855:     if (!ul_opt)
 856:         putchar (*s++);
 857:     else {
 858:         if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) {
 859:         s++;
 860:         continue;
 861:         }
 862:         if (state = wouldul(s, n)) {
 863:         c = (*s == '_')? s[2] : *s ;
 864:         n -= 2;
 865:         s += 3;
 866:         } else
 867:         c = *s++;
 868:         if (state != pstate) {
 869:         if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1))
 870:             state = 1;
 871:         else
 872:             tputs(state ? ULenter : ULexit, 1, putch);
 873:         }
 874:         if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0)
 875:             putchar(c);
 876:         if (state && *chUL) {
 877:         pr(chBS);
 878:         tputs(chUL, 1, putch);
 879:         }
 880:         pstate = state;
 881:     }
 882: }
 883: 
 884: /*
 885: **  Clear the screen
 886: */
 887: 
 888: doclear()
 889: {
 890:     if (Clear && !hard) {
 891:     tputs(Clear, 1, putch);
 892: 
 893:     /* Put out carriage return so that system doesn't
 894: 	** get confused by escape sequences when expanding tabs
 895: 	*/
 896:     putchar ('\r');
 897:     promptlen = 0;
 898:     }
 899: }
 900: 
 901: /*
 902:  * Go to home position
 903:  */
 904: home()
 905: {
 906:     tputs(Home,1,putch);
 907: }
 908: 
 909: static int lastcmd, lastarg, lastp;
 910: static int lastcolon;
 911: char shell_line[132];
 912: 
 913: /*
 914: ** Read a command and do it. A command consists of an optional integer
 915: ** argument followed by the command character.  Return the number of lines
 916: ** to display in the next screenful.  If there is nothing more to display
 917: ** in the current file, zero is returned.
 918: */
 919: 
 920: command (filename, f)
 921: char *filename;
 922: register FILE *f;
 923: {
 924:     register int nlines;
 925:     register int retval;
 926:     register char c;
 927:     char colonch;
 928:     FILE *helpf;
 929:     int done;
 930:     char comchar, cmdbuf[80], *p;
 931: 
 932: #define ret(val) retval=val;done++;break
 933: 
 934:     done = 0;
 935:     if (!errors)
 936:     prompt (filename);
 937:     else
 938:     errors = 0;
 939:     if (MBIT == RAW && slow_tty) {
 940:     otty.sg_flags |= MBIT;
 941:     stty(fileno(stderr), &otty);
 942:     }
 943:     for (;;) {
 944:     nlines = number (&comchar);
 945:     lastp = colonch = 0;
 946:     if (comchar == '.') {   /* Repeat last command */
 947:         lastp++;
 948:         comchar = lastcmd;
 949:         nlines = lastarg;
 950:         if (lastcmd == ':')
 951:             colonch = lastcolon;
 952:     }
 953:     lastcmd = comchar;
 954:     lastarg = nlines;
 955:     if (comchar == otty.sg_erase) {
 956:         kill_line ();
 957:         prompt (filename);
 958:         continue;
 959:     }
 960:     switch (comchar) {
 961:     case ':':
 962:         retval = colon (filename, colonch, nlines);
 963:         if (retval >= 0)
 964:         done++;
 965:         break;
 966:     case 'b':
 967:     case ctrl(B):
 968:         {
 969:         register int initline;
 970: 
 971:         if (no_intty) {
 972:             write(2, &bell, 1);
 973:             return (-1);
 974:         }
 975: 
 976:         if (nlines == 0) nlines++;
 977: 
 978:         putchar ('\r');
 979:         erase (0);
 980:         printf ("\n");
 981:         if (clreol)
 982:             cleareol ();
 983:         printf ("...back %d page", nlines);
 984:         if (nlines > 1)
 985:             pr ("s\n");
 986:         else
 987:             pr ("\n");
 988: 
 989:         if (clreol)
 990:             cleareol ();
 991:         pr ("\n");
 992: 
 993:         initline = Currline - dlines * (nlines + 1);
 994:         if (! noscroll)
 995:             --initline;
 996:         if (initline < 0) initline = 0;
 997:         Fseek(f, 0L);
 998:         Currline = 0;   /* skiplns() will make Currline correct */
 999:         skiplns(initline, f);
1000:         if (! noscroll) {
1001:             ret(dlines + 1);
1002:         }
1003:         else {
1004:             ret(dlines);
1005:         }
1006:         }
1007:     case ' ':
1008:     case 'z':
1009:         if (nlines == 0) nlines = dlines;
1010:         else if (comchar == 'z') dlines = nlines;
1011:         ret (nlines);
1012:     case 'd':
1013:     case ctrl(D):
1014:         if (nlines != 0) nscroll = nlines;
1015:         ret (nscroll);
1016:     case 'q':
1017:     case 'Q':
1018:         end_it ();
1019:     case 's':
1020:     case 'f':
1021:         if (nlines == 0) nlines++;
1022:         if (comchar == 'f')
1023:         nlines *= dlines;
1024:         putchar ('\r');
1025:         erase (0);
1026:         printf ("\n");
1027:         if (clreol)
1028:         cleareol ();
1029:         printf ("...skipping %d line", nlines);
1030:         if (nlines > 1)
1031:         pr ("s\n");
1032:         else
1033:         pr ("\n");
1034: 
1035:         if (clreol)
1036:         cleareol ();
1037:         pr ("\n");
1038: 
1039:         while (nlines > 0) {
1040:         while ((c = Getc (f)) != '\n')
1041:             if (c == EOF) {
1042:             retval = 0;
1043:             done++;
1044:             goto endsw;
1045:             }
1046:             Currline++;
1047:             nlines--;
1048:         }
1049:         ret (dlines);
1050:     case '\n':
1051:         if (nlines != 0)
1052:         dlines = nlines;
1053:         else
1054:         nlines = 1;
1055:         ret (nlines);
1056:     case '\f':
1057:         if (!no_intty) {
1058:         doclear ();
1059:         Fseek (f, screen_start.chrctr);
1060:         Currline = screen_start.line;
1061:         ret (dlines);
1062:         }
1063:         else {
1064:         write (2, &bell, 1);
1065:         break;
1066:         }
1067:     case '\'':
1068:         if (!no_intty) {
1069:         kill_line ();
1070:         pr ("\n***Back***\n\n");
1071:         Fseek (f, context.chrctr);
1072:         Currline = context.line;
1073:         ret (dlines);
1074:         }
1075:         else {
1076:         write (2, &bell, 1);
1077:         break;
1078:         }
1079:     case '=':
1080:         kill_line ();
1081:         promptlen = printd (Currline);
1082:         fflush (stdout);
1083:         break;
1084:     case 'n':
1085:         lastp++;
1086:     case '/':
1087:         if (nlines == 0) nlines++;
1088:         kill_line ();
1089:         pr ("/");
1090:         promptlen = 1;
1091:         fflush (stdout);
1092:         if (lastp) {
1093:         write (2,"\r", 1);
1094:         search (NULL, f, nlines);   /* Use previous r.e. */
1095:         }
1096:         else {
1097:         ttyin (cmdbuf, 78, '/');
1098:         write (2, "\r", 1);
1099:         search (cmdbuf, f, nlines);
1100:         }
1101:         ret (dlines-1);
1102:     case '!':
1103:         do_shell (filename);
1104:         break;
1105:     case '?':
1106:     case 'h':
1107:         if ((helpf = fopen (HELPFILE, "r")) == NULL)
1108:         error ("Can't open help file");
1109:         if (noscroll) doclear ();
1110:         copy_file (helpf);
1111:         fclose (helpf);
1112:         prompt (filename);
1113:         break;
1114:     case 'v':   /* This case should go right before default */
1115:         if (!no_intty) {
1116:         kill_line ();
1117:         cmdbuf[0] = '+';
1118:         scanstr (Currline - dlines < 0 ? 0
1119:                 : Currline - (dlines + 1) / 2, &cmdbuf[1]);
1120:         pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
1121:         execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
1122:         break;
1123:         }
1124:     default:
1125:         if (dum_opt) {
1126:         kill_line ();
1127:         if (Senter && Sexit) {
1128:             tputs (Senter, 1, putch);
1129:             promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch);
1130:             tputs (Sexit, 1, putch);
1131:         }
1132:         else
1133:             promptlen = pr ("[Press 'h' for instructions.]");
1134:         fflush (stdout);
1135:         }
1136:         else
1137:         write (2, &bell, 1);
1138:         break;
1139:     }
1140:     if (done) break;
1141:     }
1142:     putchar ('\r');
1143: endsw:
1144:     inwait = 0;
1145:     notell++;
1146:     if (MBIT == RAW && slow_tty) {
1147:     otty.sg_flags &= ~MBIT;
1148:     stty(fileno(stderr), &otty);
1149:     }
1150:     return (retval);
1151: }
1152: 
1153: char ch;
1154: 
1155: /*
1156:  * Execute a colon-prefixed command.
1157:  * Returns <0 if not a command that should cause
1158:  * more of the file to be printed.
1159:  */
1160: 
1161: colon (filename, cmd, nlines)
1162: char *filename;
1163: int cmd;
1164: int nlines;
1165: {
1166:     if (cmd == 0)
1167:         ch = readch ();
1168:     else
1169:         ch = cmd;
1170:     lastcolon = ch;
1171:     switch (ch) {
1172:     case 'f':
1173:         kill_line ();
1174:         if (!no_intty)
1175:             promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline);
1176:         else
1177:             promptlen = printf ("[Not a file] line %d", Currline);
1178:         fflush (stdout);
1179:         return (-1);
1180:     case 'n':
1181:         if (nlines == 0) {
1182:             if (fnum >= nfiles - 1)
1183:                 end_it ();
1184:             nlines++;
1185:         }
1186:         putchar ('\r');
1187:         erase (0);
1188:         skipf (nlines);
1189:         return (0);
1190:     case 'p':
1191:         if (no_intty) {
1192:             write (2, &bell, 1);
1193:             return (-1);
1194:         }
1195:         putchar ('\r');
1196:         erase (0);
1197:         if (nlines == 0)
1198:             nlines++;
1199:         skipf (-nlines);
1200:         return (0);
1201:     case '!':
1202:         do_shell (filename);
1203:         return (-1);
1204:     case 'q':
1205:     case 'Q':
1206:         end_it ();
1207:     default:
1208:         write (2, &bell, 1);
1209:         return (-1);
1210:     }
1211: }
1212: 
1213: /*
1214: ** Read a decimal number from the terminal. Set cmd to the non-digit which
1215: ** terminates the number.
1216: */
1217: 
1218: number(cmd)
1219: char *cmd;
1220: {
1221:     register int i;
1222: 
1223:     i = 0; ch = otty.sg_kill;
1224:     for (;;) {
1225:         ch = readch ();
1226:         if (ch >= '0' && ch <= '9')
1227:             i = i*10 + ch - '0';
1228:         else if (ch == otty.sg_kill)
1229:             i = 0;
1230:         else {
1231:             *cmd = ch;
1232:             break;
1233:         }
1234:     }
1235:     return (i);
1236: }
1237: 
1238: do_shell (filename)
1239: char *filename;
1240: {
1241:     char cmdbuf[80];
1242: 
1243:     kill_line ();
1244:     pr ("!");
1245:     fflush (stdout);
1246:     promptlen = 1;
1247:     if (lastp)
1248:         pr (shell_line);
1249:     else {
1250:         ttyin (cmdbuf, 78, '!');
1251:         if (expand (shell_line, cmdbuf)) {
1252:             kill_line ();
1253:             promptlen = printf ("!%s", shell_line);
1254:         }
1255:     }
1256:     fflush (stdout);
1257:     write (2, "\n", 1);
1258:     promptlen = 0;
1259:     shellp = 1;
1260:     execute (filename, shell, shell, "-c", shell_line, 0);
1261: }
1262: 
1263: /*
1264: ** Search for nth ocurrence of regular expression contained in buf in the file
1265: */
1266: 
1267: search (buf, file, n)
1268: char buf[];
1269: FILE *file;
1270: register int n;
1271: {
1272:     long startline = Ftell (file);
1273:     register long line1 = startline;
1274:     register long line2 = startline;
1275:     register long line3 = startline;
1276:     register int lncount;
1277:     int saveln, rv, re_exec();
1278:     char *s, *re_comp();
1279: 
1280:     context.line = saveln = Currline;
1281:     context.chrctr = startline;
1282:     lncount = 0;
1283:     if ((s = re_comp (buf)) != 0)
1284:     error (s);
1285:     while (!feof (file)) {
1286:     line3 = line2;
1287:     line2 = line1;
1288:     line1 = Ftell (file);
1289:     rdline (file);
1290:     lncount++;
1291:     if ((rv = re_exec (Line)) == 1)
1292:         if (--n == 0) {
1293:             if (lncount > 3 || (lncount > 1 && no_intty))
1294:             {
1295:             pr ("\n");
1296:             if (clreol)
1297:                 cleareol ();
1298:             pr("...skipping\n");
1299:             }
1300:             if (!no_intty) {
1301:             Currline -= (lncount >= 3 ? 3 : lncount);
1302:             Fseek (file, line3);
1303:             if (noscroll)
1304:                 if (clreol) {
1305:                 home ();
1306:                 cleareol ();
1307:                 }
1308:                 else
1309:                 doclear ();
1310:             }
1311:             else {
1312:             kill_line ();
1313:             if (noscroll)
1314:                 if (clreol) {
1315:                     home ();
1316:                     cleareol ();
1317:                 }
1318:                 else
1319:                 doclear ();
1320:             pr (Line);
1321:             putchar ('\n');
1322:             }
1323:             break;
1324:         }
1325:     else if (rv == -1)
1326:         error ("Regular expression botch");
1327:     }
1328:     if (feof (file)) {
1329:     if (!no_intty) {
1330:         file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */
1331:         Currline = saveln;
1332:         Fseek (file, startline);
1333:     }
1334:     else {
1335:         pr ("\nPattern not found\n");
1336:         end_it ();
1337:     }
1338:     error ("Pattern not found");
1339:     }
1340: }
1341: 
1342: execute (filename, cmd, args)
1343: char *filename;
1344: char *cmd, *args;
1345: {
1346:     int id;
1347:     int n;
1348: 
1349:     fflush (stdout);
1350:     reset_tty ();
1351:     for (n = 10; (id = fork ()) < 0 && n > 0; n--)
1352:         sleep (5);
1353:     if (id == 0) {
1354:         if (!isatty(0)) {
1355:         close(0);
1356:         open("/dev/tty", 0);
1357:         }
1358:         execv (cmd, &args);
1359:         write (2, "exec failed\n", 12);
1360:         exit (1);
1361:     }
1362:     if (id > 0) {
1363:         signal (SIGINT, SIG_IGN);
1364:         signal (SIGQUIT, SIG_IGN);
1365:         if (catch_susp)
1366:         signal(SIGTSTP, SIG_DFL);
1367:         while (wait(0) > 0);
1368:         signal (SIGINT, end_it);
1369:         signal (SIGQUIT, onquit);
1370:         if (catch_susp)
1371:         signal(SIGTSTP, onsusp);
1372:     } else
1373:         write(2, "can't fork\n", 11);
1374:     set_tty ();
1375:     pr ("------------------------\n");
1376:     prompt (filename);
1377: }
1378: /*
1379: ** Skip n lines in the file f
1380: */
1381: 
1382: skiplns (n, f)
1383: register int n;
1384: register FILE *f;
1385: {
1386:     register char c;
1387: 
1388:     while (n > 0) {
1389:     while ((c = Getc (f)) != '\n')
1390:         if (c == EOF)
1391:         return;
1392:         n--;
1393:         Currline++;
1394:     }
1395: }
1396: 
1397: /*
1398: ** Skip nskip files in the file list (from the command line). Nskip may be
1399: ** negative.
1400: */
1401: 
1402: skipf (nskip)
1403: register int nskip;
1404: {
1405:     if (nskip == 0) return;
1406:     if (nskip > 0) {
1407:     if (fnum + nskip > nfiles - 1)
1408:         nskip = nfiles - fnum - 1;
1409:     }
1410:     else if (within)
1411:     ++fnum;
1412:     fnum += nskip;
1413:     if (fnum < 0)
1414:     fnum = 0;
1415:     pr ("\n...Skipping ");
1416:     pr ("\n");
1417:     if (clreol)
1418:     cleareol ();
1419:     pr ("...Skipping ");
1420:     pr (nskip > 0 ? "to file " : "back to file ");
1421:     pr (fnames[fnum]);
1422:     pr ("\n");
1423:     if (clreol)
1424:     cleareol ();
1425:     pr ("\n");
1426:     --fnum;
1427: }
1428: 
1429: /*----------------------------- Terminal I/O -------------------------------*/
1430: 
1431: initterm ()
1432: {
1433:     char    buf[TBUFSIZ];
1434:     static char clearbuf[TBUFSIZ];
1435:     char    *clearptr, *padstr;
1436:     int     ldisc;
1437:     int     lmode;
1438:     char    *term;
1439:     int     tgrp;
1440:     struct winsize win;
1441: 
1442: retry:
1443:     if (!(no_tty = gtty(fileno(stdout), &otty))) {
1444:     if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) {
1445:         perror("TIOCLGET");
1446:         exit(1);
1447:     }
1448:     docrterase = ((lmode & LCRTERA) != 0);
1449:     docrtkill = ((lmode & LCRTKIL) != 0);
1450:     /*
1451: 	 * Wait until we're in the foreground before we save the
1452: 	 * the terminal modes.
1453: 	 */
1454:     if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
1455:         perror("TIOCGPGRP");
1456:         exit(1);
1457:     }
1458:     if (tgrp != getpgrp(0)) {
1459:         kill(0, SIGTTOU);
1460:         goto retry;
1461:     }
1462:     if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) {
1463:         dumb++; ul_opt = 0;
1464:     }
1465:     else {
1466:         if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
1467:         Lpp = tgetnum("li");
1468:         Mcol = tgetnum("co");
1469:         } else {
1470:         if ((Lpp = win.ws_row) == 0)
1471:             Lpp = tgetnum("li");
1472:         if ((Mcol = win.ws_col) == 0)
1473:             Mcol = tgetnum("co");
1474:         }
1475:         if ((Lpp <= 0) || tgetflag("hc")) {
1476:         hard++; /* Hard copy terminal */
1477:         Lpp = 24;
1478:         }
1479:         if (Mcol <= 0)
1480:         Mcol = 80;
1481: 
1482:         if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
1483:         noscroll++;
1484:         Wrap = tgetflag("am");
1485:         bad_so = tgetflag ("xs");
1486:         clearptr = clearbuf;
1487:         eraseln = tgetstr("ce",&clearptr);
1488:         Clear = tgetstr("cl", &clearptr);
1489:         Senter = tgetstr("so", &clearptr);
1490:         Sexit = tgetstr("se", &clearptr);
1491:         if ((soglitch = tgetnum("sg")) < 0)
1492:         soglitch = 0;
1493: 
1494:         /*
1495: 	     *  Set up for underlining:  some terminals don't need it;
1496: 	     *  others have start/stop sequences, still others have an
1497: 	     *  underline char sequence which is assumed to move the
1498: 	     *  cursor forward one character.  If underline sequence
1499: 	     *  isn't available, settle for standout sequence.
1500: 	     */
1501: 
1502:         if (tgetflag("ul") || tgetflag("os"))
1503:         ul_opt = 0;
1504:         if ((chUL = tgetstr("uc", &clearptr)) == NULL )
1505:         chUL = "";
1506:         if (((ULenter = tgetstr("us", &clearptr)) == NULL ||
1507:              (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) {
1508:             if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) {
1509:             ULenter = "";
1510:             ULexit = "";
1511:         } else
1512:             ulglitch = soglitch;
1513:         } else {
1514:         if ((ulglitch = tgetnum("ug")) < 0)
1515:             ulglitch = 0;
1516:         }
1517: 
1518:         if (padstr = tgetstr("pc", &clearptr))
1519:         PC = *padstr;
1520:         Home = tgetstr("ho",&clearptr);
1521:         if (Home == 0 || *Home == '\0')
1522:         {
1523:         if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
1524:             strcpy(cursorhome, tgoto(cursorm, 0, 0));
1525:             Home = cursorhome;
1526:            }
1527:         }
1528:         EodClr = tgetstr("cd", &clearptr);
1529:         if ((chBS = tgetstr("bc", &clearptr)) == NULL)
1530:         chBS = "\b";
1531: 
1532:     }
1533:     if ((shell = getenv("SHELL")) == NULL)
1534:         shell = "/bin/sh";
1535:     }
1536:     no_intty = gtty(fileno(stdin), &otty);
1537:     gtty(fileno(stderr), &otty);
1538:     savetty = otty;
1539:     ospeed = otty.sg_ospeed;
1540:     slow_tty = ospeed < B1200;
1541:     hardtabs = (otty.sg_flags & TBDELAY) != XTABS;
1542:     if (!no_tty) {
1543:     otty.sg_flags &= ~ECHO;
1544:     if (MBIT == CBREAK || !slow_tty)
1545:         otty.sg_flags |= MBIT;
1546:     }
1547: }
1548: 
1549: readch ()
1550: {
1551:     char ch;
1552:     extern int errno;
1553: 
1554:     if (read (2, &ch, 1) <= 0)
1555:         if (errno != EINTR)
1556:             exit(0);
1557:         else
1558:             ch = otty.sg_kill;
1559:     return (ch);
1560: }
1561: 
1562: static char BS = '\b';
1563: static char *BSB = "\b \b";
1564: static char CARAT = '^';
1565: #define ERASEONECHAR \
1566:     if (docrterase) \
1567:     write (2, BSB, sizeof(BSB)); \
1568:     else \
1569:     write (2, &BS, sizeof(BS));
1570: 
1571: ttyin (buf, nmax, pchar)
1572: char buf[];
1573: register int nmax;
1574: char pchar;
1575: {
1576:     register char *sptr;
1577:     register char ch;
1578:     register int slash = 0;
1579:     int maxlen;
1580:     char cbuf;
1581: 
1582:     sptr = buf;
1583:     maxlen = 0;
1584:     while (sptr - buf < nmax) {
1585:     if (promptlen > maxlen) maxlen = promptlen;
1586:     ch = readch ();
1587:     if (ch == '\\') {
1588:         slash++;
1589:     }
1590:     else if ((ch == otty.sg_erase) && !slash) {
1591:         if (sptr > buf) {
1592:         --promptlen;
1593:         ERASEONECHAR
1594:         --sptr;
1595:         if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
1596:             --promptlen;
1597:             ERASEONECHAR
1598:         }
1599:         continue;
1600:         }
1601:         else {
1602:         if (!eraseln) promptlen = maxlen;
1603:         longjmp (restore, 1);
1604:         }
1605:     }
1606:     else if ((ch == otty.sg_kill) && !slash) {
1607:         if (hard) {
1608:         show (ch);
1609:         putchar ('\n');
1610:         putchar (pchar);
1611:         }
1612:         else {
1613:         putchar ('\r');
1614:         putchar (pchar);
1615:         if (eraseln)
1616:             erase (1);
1617:         else if (docrtkill)
1618:             while (promptlen-- > 1)
1619:             write (2, BSB, sizeof(BSB));
1620:         promptlen = 1;
1621:         }
1622:         sptr = buf;
1623:         fflush (stdout);
1624:         continue;
1625:     }
1626:     if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
1627:         ERASEONECHAR
1628:         --sptr;
1629:     }
1630:     if (ch != '\\')
1631:         slash = 0;
1632:     *sptr++ = ch;
1633:     if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1634:         ch += ch == RUBOUT ? -0100 : 0100;
1635:         write (2, &CARAT, 1);
1636:         promptlen++;
1637:     }
1638:     cbuf = ch;
1639:     if (ch != '\n' && ch != ESC) {
1640:         write (2, &cbuf, 1);
1641:         promptlen++;
1642:     }
1643:     else
1644:         break;
1645:     }
1646:     *--sptr = '\0';
1647:     if (!eraseln) promptlen = maxlen;
1648:     if (sptr - buf >= nmax - 1)
1649:     error ("Line too long");
1650: }
1651: 
1652: expand (outbuf, inbuf)
1653: char *outbuf;
1654: char *inbuf;
1655: {
1656:     register char *instr;
1657:     register char *outstr;
1658:     register char ch;
1659:     char temp[200];
1660:     int changed = 0;
1661: 
1662:     instr = inbuf;
1663:     outstr = temp;
1664:     while ((ch = *instr++) != '\0')
1665:     switch (ch) {
1666:     case '%':
1667:         if (!no_intty) {
1668:         strcpy (outstr, fnames[fnum]);
1669:         outstr += strlen (fnames[fnum]);
1670:         changed++;
1671:         }
1672:         else
1673:         *outstr++ = ch;
1674:         break;
1675:     case '!':
1676:         if (!shellp)
1677:         error ("No previous command to substitute for");
1678:         strcpy (outstr, shell_line);
1679:         outstr += strlen (shell_line);
1680:         changed++;
1681:         break;
1682:     case '\\':
1683:         if (*instr == '%' || *instr == '!') {
1684:         *outstr++ = *instr++;
1685:         break;
1686:         }
1687:     default:
1688:         *outstr++ = ch;
1689:     }
1690:     *outstr++ = '\0';
1691:     strcpy (outbuf, temp);
1692:     return (changed);
1693: }
1694: 
1695: show (ch)
1696: register char ch;
1697: {
1698:     char cbuf;
1699: 
1700:     if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
1701:     ch += ch == RUBOUT ? -0100 : 0100;
1702:     write (2, &CARAT, 1);
1703:     promptlen++;
1704:     }
1705:     cbuf = ch;
1706:     write (2, &cbuf, 1);
1707:     promptlen++;
1708: }
1709: 
1710: error (mess)
1711: char *mess;
1712: {
1713:     if (clreol)
1714:     cleareol ();
1715:     else
1716:     kill_line ();
1717:     promptlen += strlen (mess);
1718:     if (Senter && Sexit) {
1719:     tputs (Senter, 1, putch);
1720:     pr(mess);
1721:     tputs (Sexit, 1, putch);
1722:     }
1723:     else
1724:     pr (mess);
1725:     fflush(stdout);
1726:     errors++;
1727:     longjmp (restore, 1);
1728: }
1729: 
1730: 
1731: set_tty ()
1732: {
1733:     otty.sg_flags |= MBIT;
1734:     otty.sg_flags &= ~ECHO;
1735:     stty(fileno(stderr), &otty);
1736: }
1737: 
1738: reset_tty ()
1739: {
1740:     if (pstate) {
1741:     tputs(ULexit, 1, putch);
1742:     fflush(stdout);
1743:     pstate = 0;
1744:     }
1745:     otty.sg_flags |= ECHO;
1746:     otty.sg_flags &= ~MBIT;
1747:     stty(fileno(stderr), &savetty);
1748: }
1749: 
1750: rdline (f)
1751: register FILE *f;
1752: {
1753:     register char c;
1754:     register char *p;
1755: 
1756:     p = Line;
1757:     while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
1758:     *p++ = c;
1759:     if (c == '\n')
1760:     Currline++;
1761:     *p = '\0';
1762: }
1763: 
1764: /* Come here when we get a suspend signal from the terminal */
1765: 
1766: onsusp ()
1767: {
1768:     /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
1769:     signal(SIGTTOU, SIG_IGN);
1770:     reset_tty ();
1771:     fflush (stdout);
1772:     signal(SIGTTOU, SIG_DFL);
1773:     /* Send the TSTP signal to suspend our process group */
1774:     signal(SIGTSTP, SIG_DFL);
1775:     sigsetmask(0);
1776:     kill (0, SIGTSTP);
1777:     /* Pause for station break */
1778: 
1779:     /* We're back */
1780:     signal (SIGTSTP, onsusp);
1781:     set_tty ();
1782:     if (inwait)
1783:         longjmp (restore);
1784: }

Defined functions

Sprintf defined in line 620; used 2 times
argscan defined in line 283; used 2 times
checkf defined in line 327; used 2 times
chgwinsz defined in line 498; used 3 times
cleareol defined in line 818; used 17 times
clreos defined in line 823; used 5 times
colon defined in line 1161; used 1 times
command defined in line 920; used 2 times
copy_file defined in line 539; used 3 times
do_shell defined in line 1238; used 2 times
doclear defined in line 888; used 8 times
end_it defined in line 521; used 7 times
erase defined in line 784; used 11 times
error defined in line 1710; used 6 times
execute defined in line 1342; used 2 times
expand defined in line 1652; used 1 times
getline defined in line 703; used 1 times
home defined in line 904; used 5 times
initterm defined in line 1431; used 1 times
kill_line defined in line 809; used 13 times
main defined in line 110; never used
number defined in line 1218; used 1 times
onquit defined in line 474; used 5 times
onsusp defined in line 1766; used 4 times
pr defined in line 832; used 34 times
prbuf defined in line 846; used 2 times
printd defined in line 595; used 3 times
printf defined in line 550; used 14 times
prompt defined in line 663; used 4 times
putch defined in line 384; used 16 times
rdline defined in line 1750; used 1 times
readch defined in line 1549; used 3 times
reset_tty defined in line 1738; used 4 times
scanstr defined in line 611; used 1 times
screen defined in line 396; used 2 times
search defined in line 1267; used 4 times
set_tty defined in line 1731; used 2 times
show defined in line 1695; used 1 times
skipf defined in line 1402; used 2 times
skiplns defined in line 1382; used 3 times
strlen defined in line 631; used 4 times
tailequ defined in line 646; used 1 times
ttyin defined in line 1571; used 2 times

Defined variables

BS defined in line 1562; used 2 times
BSB defined in line 1563; used 4 times
CARAT defined in line 1564; used 2 times
Clear defined in line 85; used 3 times
Currline defined in line 65; used 20 times
EodClr defined in line 94; used 4 times
Home defined in line 91; used 7 times
Line defined in line 83; used 13 times
Lpp defined in line 84; used 12 times
Mcol defined in line 96; used 11 times
Pause defined in line 72; used 5 times
Senter defined in line 87; used 11 times
Sexit defined in line 87; used 9 times
ULenter defined in line 88; used 4 times
ULexit defined in line 88; used 6 times
Wrap defined in line 97; used 2 times
bad_so defined in line 71; used 3 times
bell defined in line 629; used 7 times
catch_susp defined in line 76; used 3 times
ch defined in line 1153; used 61 times
chBS defined in line 90; used 3 times
chUL defined in line 89; used 5 times
clreol defined in line 75; used 29 times
copyright defined in line 8; never used
cursorhome defined in line 93; used 2 times
cursorm defined in line 92; used 2 times
dlines defined in line 57; used 21 times
docrterase defined in line 69; used 2 times
docrtkill defined in line 70; used 2 times
dum_opt defined in line 57; used 4 times
dumb defined in line 75; used 4 times
eraseln defined in line 86; used 12 times
errors defined in line 72; used 3 times
file_pos defined in line 55; used 6 times
file_size defined in line 55; used 4 times
firstf defined in line 67; used 5 times
fnames defined in line 77; used 15 times
fnum defined in line 56; used 21 times
fold_opt defined in line 60; used 4 times
hard defined in line 75; used 8 times
hardtabs defined in line 75; used 2 times
inwait defined in line 72; used 4 times
lastarg defined in line 909; used 2 times
lastcmd defined in line 909; used 3 times
lastcolon defined in line 910; used 2 times
lastp defined in line 909; used 5 times
nfiles defined in line 78; used 9 times
no_intty defined in line 56; used 15 times
no_tty defined in line 56; used 6 times
noscroll defined in line 75; used 15 times
notell defined in line 68; used 3 times
nscroll defined in line 59; used 8 times
otty defined in line 54; used 26 times
promptlen defined in line 64; used 43 times
pstate defined in line 100; used 8 times
restore defined in line 82; used 8 times
savetty defined in line 54; used 2 times
sccsid defined in line 14; never used
shell defined in line 79; used 4 times
shell_line defined in line 911; used 6 times
shellp defined in line 80; used 2 times
slow_tty defined in line 56; used 4 times
soglitch defined in line 98; used 5 times
sptr defined in line 609; used 16 times
ssp_opt defined in line 62; used 2 times
startup defined in line 66; used 2 times
stop_opt defined in line 61; used 2 times
ul_opt defined in line 63; used 4 times
ulglitch defined in line 99; used 6 times
within defined in line 73; used 3 times

Defined macros

ERASEONECHAR defined in line 1565; used 3 times
ESC defined in line 51; used 3 times
Fopen defined in line 38; used 1 times
Fseek defined in line 40; used 5 times
Ftell defined in line 39; used 3 times
Getc defined in line 41; used 9 times
HELPFILE defined in line 35; used 1 times
LINSIZ defined in line 48; used 4 times
MBIT defined in line 44; used 8 times
QUIT defined in line 52; never used
RUBOUT defined in line 50; used 6 times
STOP defined in line 394; used 1 times
TBUFSIZ defined in line 47; used 2 times
Ungetc defined in line 42; used 3 times
VI defined in line 36; used 1 times
ctrl defined in line 49; used 3 times
ret defined in line 932; used 9 times
stty defined in line 45; used 5 times
wouldul defined in line 852; used 3 times
Last modified: 1986-04-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6177
Valid CSS Valid XHTML 1.0 Strict