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

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 808; used 17 times
clreos defined in line 813; used 5 times
colon defined in line 1151; used 1 times
command defined in line 910; used 2 times
copy_file defined in line 539; used 3 times
do_shell defined in line 1228; used 2 times
doclear defined in line 878; used 8 times
end_it defined in line 521; used 7 times
erase defined in line 774; used 11 times
error defined in line 1699; used 6 times
execute defined in line 1332; used 2 times
expand defined in line 1641; used 1 times
getline defined in line 693; used 1 times
home defined in line 894; used 5 times
initterm defined in line 1421; used 1 times
kill_line defined in line 799; used 13 times
main defined in line 110; never used
number defined in line 1208; used 1 times
onquit defined in line 474; used 5 times
onsusp defined in line 1755; used 4 times
pr defined in line 822; used 34 times
prbuf defined in line 836; used 2 times
printd defined in line 595; used 3 times
printf defined in line 550; used 14 times
prompt defined in line 653; used 4 times
putch defined in line 384; used 16 times
rdline defined in line 1739; used 1 times
readch defined in line 1539; used 3 times
reset_tty defined in line 1727; used 4 times
scanstr defined in line 611; used 1 times
screen defined in line 396; used 2 times
search defined in line 1257; used 4 times
set_tty defined in line 1720; used 2 times
show defined in line 1684; used 1 times
skipf defined in line 1392; used 2 times
skiplns defined in line 1372; used 3 times
tailequ defined in line 636; used 1 times
ttyin defined in line 1560; used 2 times

Defined variables

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

Defined macros

ERASEONECHAR defined in line 1554; used 3 times
ESC defined in line 53; used 3 times
Fopen defined in line 40; used 1 times
Fseek defined in line 42; used 5 times
Ftell defined in line 41; used 3 times
Getc defined in line 43; used 9 times
HELPFILE defined in line 37; used 1 times
LINSIZ defined in line 50; used 4 times
MBIT defined in line 46; used 8 times
QUIT defined in line 54; never used
RUBOUT defined in line 52; used 6 times
STOP defined in line 394; used 1 times
TBUFSIZ defined in line 49; used 2 times
Ungetc defined in line 44; used 3 times
VI defined in line 38; used 1 times
ctrl defined in line 51; used 3 times
ret defined in line 922; used 9 times
stty defined in line 47; used 5 times
wouldul defined in line 842; used 3 times
Last modified: 1997-10-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 11357
Valid CSS Valid XHTML 1.0 Strict