Annotation of 3BSD/cmd/more.c, revision 1.1.1.1

1.1       root        1: #include <whoami.h>
                      2: #include <stdio.h>
                      3: #include <signal.h>
                      4: #include <sgtty.h>
                      5: #include <setjmp.h>
                      6: #include <sys/types.h>
                      7: #include <sys/dir.h>
                      8: #include <sys/stat.h>
                      9: 
                     10: #ifdef CORY
                     11: #define MBIT RAW
                     12: #else
                     13: #include <ctype.h>
                     14: #define MBIT CBREAK
                     15: #endif
                     16: 
                     17: #define TBUFSIZ        1024
                     18: #define LINSIZ 256
                     19: #define ctrl(letter)   ('letter' & 077)
                     20: #define RUBOUT '\177'
                     21: #define ESC    '\033'
                     22: #define QUIT   '\034'
                     23: 
                     24: struct sgttyb  otty;
                     25: int            fnum, no_intty, no_tty, slow_tty;
                     26: int            dum_opt, dlines, onquit(), end_it();
                     27: int            stop_opt = 1;
                     28: int            promptlen;
                     29: int            startup = 1;
                     30: int            firstf = 1;
                     31: int            notell = 1;
                     32: int            inwait, pause, errors;
                     33: int            within; /* true if we are within a file,
                     34:                        false if we are between files */
                     35: int            hard, dumb, noscroll, hardtabs;
                     36: char           **fnames;
                     37: int            nfiles;
                     38: char           *shell;
                     39: char           ch;
                     40: jmp_buf                restore;
                     41: char           obuf[BUFSIZ];   /* stdout buffer */
                     42: char           Line[LINSIZ];
                     43: int            Lpp = 24;       /* lines per page */
                     44: char           *Clear;         /* clear screen */
                     45: char           *eraseln;       /* erase line */
                     46: char           *Senter, *Sexit;/* enter and exit standout mode */
                     47: char           *tgetstr();
                     48: int            Mcol = 80;      /* number of columns */
                     49: int            Wrap = 1;       /* set if automargins */
                     50: extern char    PC;             /* pad character */
                     51: extern short   ospeed;
                     52: 
                     53: 
                     54: main(argc, argv)
                     55: int argc;
                     56: char *argv[];
                     57: {
                     58:     register FILE      *f;
                     59:     register char      *s;
                     60:     register char      *p;
                     61:     register char      ch;
                     62:     register int       left;
                     63:     int                        prnames = 0; 
                     64:     int                        initopt = 0;
                     65:     int                        srchopt = 0;
                     66:     int                        initline;
                     67:     char               buf[TBUFSIZ];
                     68:     char               clearbuf[100];
                     69:     char               initbuf[80];
                     70:     char               *clearptr;
                     71:     char               *getenv();
                     72:     FILE               *checkf();
                     73: 
                     74:     nfiles = argc;
                     75:     fnames = argv;
                     76:     /* Put terminal setup stuff in separate procedure ?? (From here...) */
                     77:     setbuf(stdout, obuf);
                     78:     if (!(no_tty = gtty(1, &otty))) {
                     79:        if (tgetent(buf, getenv("TERM")) <= 0) {
                     80:            dumb++;
                     81:        }
                     82:        else {
                     83:            if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) {
                     84:                hard++; /* Hard copy terminal */
                     85:                Lpp = 24;
                     86:            }
                     87:            if (!hard && tgetflag("ns"))
                     88:                noscroll++;
                     89:            if ((Mcol = tgetnum("co")) < 0)
                     90:                Mcol = 80;
                     91:            Wrap = tgetflag("am");
                     92:            clearptr = clearbuf;
                     93:            eraseln = tgetstr("ce",&clearptr);
                     94:            Clear = tgetstr("cl", &clearptr);
                     95:            Senter = tgetstr("so", &clearptr);
                     96:            Sexit = tgetstr("se", &clearptr);
                     97:            PC = *tgetstr("pc", &clearptr);
                     98:        }
                     99:        if ((shell = getenv("SHELL")) == NULL)
                    100:            shell = "/bin/sh";
                    101:     }
                    102:     no_intty = gtty(0, &otty);
                    103:     gtty(2, &otty);
                    104:     ospeed = otty.sg_ospeed;
                    105:     slow_tty = ospeed < B1200;
                    106:     hardtabs =  !(otty.sg_flags & XTABS);
                    107:     if (!no_tty) {
                    108:        otty.sg_flags &= ~ECHO;
                    109:        if (MBIT == CBREAK || !slow_tty)
                    110:            otty.sg_flags |= MBIT;
                    111:     }
                    112:     /* ... until here or so */
                    113:     while (--nfiles > 0) {
                    114:        if ((ch = (*++fnames)[0]) == '-') {
                    115:            for (s = fnames[0] + 1, dlines = 0; *s != '\0'; s++)
                    116:                if (isdigit(*s))
                    117:                    dlines = dlines*10 + *s - '0';
                    118:                else if (*s == 'd')
                    119:                    dum_opt = 1;
                    120:                else if (*s == 'l')
                    121:                    stop_opt = 0;
                    122:        }
                    123:        else if (ch == '+') {
                    124:            s = *fnames;
                    125:            if (*++s == '/') {
                    126:                srchopt++;
                    127:                for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
                    128:                    *p++ = *s++;
                    129:                *p = '\0';
                    130:            }
                    131:            else {
                    132:                initopt++;
                    133:                for (initline = 0; *s != '\0'; s++)
                    134:                    if (isdigit (*s))
                    135:                        initline = initline*10 + *s -'0';
                    136:                --initline;
                    137:            }
                    138:        }
                    139:        else break;
                    140:     }
                    141:     if (dlines == 0)
                    142:        dlines = Lpp - 2;
                    143:     left = dlines;
                    144:     if (nfiles > 1)
                    145:        prnames++;
                    146:     if (!no_intty && nfiles == 0) {
                    147:        fputs("Usage: ",stderr);
                    148:        fputs(argv[0],stderr);
                    149:        fputs(" [-dn] name1 name2 ...\n",stderr);
                    150:        exit(1);
                    151:     }
                    152:     else
                    153:        f = stdin;
                    154:     if (!no_tty) {
                    155:        signal(SIGQUIT, onquit);
                    156:        signal(SIGINT, end_it);
                    157:        stty (2, &otty);
                    158:     }
                    159:     if (no_intty) {
                    160:        if (no_tty)
                    161:            copy_file (stdin);
                    162:        else {
                    163:            if (srchopt)
                    164:                search (initbuf, stdin, 1);
                    165:            else if (initopt)
                    166:                skiplns (initline, stdin);
                    167:            screen (stdin, left);
                    168:        }
                    169:        end_it ();
                    170:     }
                    171: 
                    172:     while (fnum < nfiles) {
                    173:        if ((f = checkf (fnames[fnum])) != NULL) {
                    174:            if (firstf) setjmp (restore);
                    175:            if (firstf) {
                    176:                firstf = 0;
                    177:                if (srchopt)
                    178:                    search (initbuf, f, 1);
                    179:                else if (initopt)
                    180:                    skiplns (initline, f);
                    181:            }
                    182:            else if (fnum < nfiles && !no_tty) {
                    183:                setjmp (restore);
                    184:                left = command (fnames[fnum], f);
                    185:            }
                    186:            if (left != 0) {
                    187:                if (prnames) {
                    188:                    pr("::::::::::::::");
                    189:                    if (promptlen > 14)
                    190:                        erase (14);
                    191:                    putchar ('\n');
                    192:                    pr(fnames[fnum]);
                    193:                    pr("\n::::::::::::::\n");
                    194:                    if (left > Lpp - 4)
                    195:                        left = Lpp - 4;
                    196:                }
                    197:                if (no_tty)
                    198:                    copy_file (f);
                    199:                else {
                    200:                    within++;
                    201:                    screen(f, left);
                    202:                    within = 0;
                    203:                }
                    204:            }
                    205:            setjmp (restore);
                    206:            fflush(stdout);
                    207:            fclose(f);
                    208:        }
                    209:        fnum++;
                    210:        firstf = 0;
                    211:     }
                    212:     otty.sg_flags |= ECHO;
                    213:     otty.sg_flags &= ~MBIT;
                    214:     stty(2, &otty);
                    215:     exit(0);
                    216: }
                    217: 
                    218: /*
                    219: ** Check whether the file named by fs is an ASCII file which the user may
                    220: ** access.  If it is, return the opened file. Otherwise return NULL.
                    221: */
                    222: 
                    223: FILE *
                    224: checkf (fs)
                    225: register char *fs;
                    226: {
                    227: #ifdef CORY
                    228:     int space[3];      /* Why doesn't libretro have a V7 stat? */
                    229: #endif
                    230:     struct stat stbuf;
                    231:     register FILE *f;
                    232:     char c;
                    233: 
                    234:     if (stat (fs, &stbuf) == -1) {
                    235:        fflush(stdout);
                    236:        perror(fs);
                    237:        return (NULL);
                    238:     }
                    239:     if (stbuf.st_mode & S_IFDIR) {
                    240:        pr("\n*** ");
                    241:        pr(fs);
                    242:        pr(": directory ***\n\n");
                    243:        return (NULL);
                    244:     }
                    245:     if ((f=fopen(fs, "r")) == NULL) {
                    246:        fflush(stdout);
                    247:        perror(fs);
                    248:        return (NULL);
                    249:     }
                    250:     c = getc(f);
                    251: 
                    252:     /* Try to see whether it is an ASCII file */
                    253: 
                    254:     switch ((c | *f->_ptr << 8) & 0177777) {
                    255:     case 0405:
                    256:     case 0407:
                    257:     case 0410:
                    258:     case 0411:
                    259:     case 0177545:
                    260:        pr("\n******** ");
                    261:        pr(fs);
                    262:        pr(": Not a text file ********\n\n");
                    263:        fclose (f);
                    264:        return (NULL);
                    265:     default:
                    266:        break;
                    267:     }
                    268:     if (c == '\f') {
                    269:        c = 0;
                    270:        doclear ();
                    271:     }
                    272:     ungetc (c, f);
                    273:     return (f);
                    274: }
                    275: 
                    276: /*
                    277: ** A real function, for the tputs routine in termlib
                    278: */
                    279: 
                    280: putch (ch)
                    281: register char ch;
                    282: {
                    283:     putchar (ch);
                    284: }
                    285: 
                    286: /*
                    287: ** Print out the contents of the file f, one screenful at a time.
                    288: */
                    289: 
                    290: #define STOP -10
                    291: 
                    292: screen (f, num_lines)
                    293: register FILE *f;
                    294: register int num_lines;
                    295: {
                    296:     register int c;
                    297:     int nchars;
                    298: 
                    299:     for (;;) {
                    300:        while (num_lines > 0 && !pause) {
                    301:            if ((nchars = getline (f)) == EOF)
                    302:                return;
                    303:            if (Senter && *Senter == ' ' && promptlen > 0)
                    304:                erase (0);
                    305:            pr (Line);
                    306:            if (nchars < promptlen)
                    307:                erase (nchars); /* erase () sets promptlen to 0 */
                    308:            else promptlen = 0;
                    309:            if (nchars < Mcol)
                    310:                putchar('\n');
                    311:            if (nchars == STOP)
                    312:                break;
                    313:            num_lines--;
                    314:        }
                    315:        fflush(stdout);
                    316:        if ((c = getc(f)) == EOF) {
                    317:            if (noscroll)
                    318:                doclear();
                    319:            else
                    320:                erase (0);
                    321:            return;
                    322:        }
                    323:        ungetc (c, f);
                    324:        setjmp (restore);
                    325:        pause = 0; startup = 0;
                    326:        if ((num_lines = command (NULL, f)) == 0)
                    327:            return;
                    328:     }
                    329: }
                    330: 
                    331: /*
                    332: ** Come here if a quit signal is received
                    333: */
                    334: 
                    335: onquit()
                    336: {
                    337:     signal(SIGQUIT, SIG_IGN);
                    338:     if (!inwait) {
                    339:        putchar ('\n');
                    340:        if (!startup) {
                    341:            signal(SIGQUIT, onquit);
                    342:            longjmp (restore, 1);
                    343:        }
                    344:        else
                    345:            pause++;
                    346:     }
                    347:     else if (!dum_opt && notell) {
                    348:        write (2, "[Use q or Q to quit]", 20);
                    349:        promptlen += 20;
                    350:        notell = 0;
                    351:     }
                    352:     signal(SIGQUIT, onquit);
                    353: }
                    354: 
                    355: /*
                    356: ** Clean up terminal state and exit. Also come here if interrupt signal received
                    357: */
                    358: 
                    359: end_it ()
                    360: {
                    361: 
                    362:     otty.sg_flags &= ~MBIT;
                    363:     otty.sg_flags |= ECHO;
                    364:     stty(2, &otty);
                    365:     if (promptlen > 0)
                    366:        kill_line ();
                    367:     else
                    368:        putchar ('\n');
                    369:     exit(0);
                    370: }
                    371: 
                    372: copy_file(f)
                    373: register FILE *f;
                    374: {
                    375:     register int c;
                    376: 
                    377:     while ((c = getc(f)) != EOF)
                    378:        putchar(c);
                    379: }
                    380: 
                    381: 
                    382: printd (n)
                    383: register int n;
                    384: {
                    385:     register int a;
                    386: 
                    387:     if (a = n/10)
                    388:        printd(a);
                    389:     putchar(n % 10 + '0');
                    390: }
                    391: 
                    392: static char bell = ctrl(G);
                    393: 
                    394: strlen (s)
                    395: char *s;
                    396: {
                    397:     register char *p;
                    398: 
                    399:     p = s;
                    400:     while (*p++)
                    401:        ;
                    402:     return (p - s - 1);
                    403: }
                    404: 
                    405: prompt (filename)
                    406: char *filename;
                    407: {
                    408:     if (promptlen > 0)
                    409:        kill_line ();
                    410:     if (!hard) {
                    411:        promptlen = 8;
                    412:        if (Senter && Sexit)
                    413:            tputs (Senter, 1, putch);
                    414:        pr("--More--");
                    415:        if (filename != NULL) {
                    416:            pr("(Next file: ");
                    417:            pr(filename);
                    418:            putchar(')');
                    419:            promptlen += 13 + strlen(filename);
                    420:        }
                    421:        if (dum_opt) {
                    422:            pr("[Hit space to continue, Rubout to abort]");
                    423:            promptlen += 40;
                    424:        }
                    425:        if (Senter && Sexit)
                    426:            tputs (Sexit, 1, putch);
                    427:        fflush(stdout);
                    428:     }
                    429:     else
                    430:        write (2, &bell, 1);
                    431:     inwait++;
                    432: }
                    433: 
                    434: /*
                    435: ** Get a logical line
                    436: */
                    437: 
                    438: getline(f)
                    439: register FILE *f;
                    440: {
                    441:     register char      c;
                    442:     register char      *p;
                    443:     register int       column;
                    444:     register int       i;
                    445:     static int         colflg;
                    446: 
                    447:     p = Line;
                    448:     i = column = 0;
                    449:     c = getc (f);
                    450:     if (colflg && c == '\n') c = getc (f);
                    451:     for (i = 1; i < LINSIZ; i++) {
                    452:        if (c == EOF) {
                    453:            if (p > Line) {
                    454:                *p = '\0';
                    455:                return (column);
                    456:            }
                    457:            return (EOF);
                    458:        }
                    459:        if (c == '\n')
                    460:            break;
                    461:        *p++ = c;
                    462:        if (c == '\t')
                    463:            if (hardtabs && column < promptlen && !hard) {
                    464:                if (eraseln && !dumb) {
                    465:                    tputs (eraseln, 1, putch);
                    466:                    promptlen = 0;
                    467:                }
                    468:                else {
                    469:                    for (--p; column & 7; column++)
                    470:                        *p++ = ' ';
                    471:                    if (column >= promptlen) promptlen = 0;
                    472:                }
                    473:            }
                    474:            else
                    475:                column = 1 + (column | 7);
                    476:        else if (c == '\b')
                    477:            column--;
                    478:        else if (c == '\r')
                    479:            column = 0;
                    480:        else if (c == '\f' && stop_opt) {
                    481:                p[-1] = '^';
                    482:                *p++ = 'L';
                    483:                break;
                    484:        }
                    485:        else if (c == EOF)
                    486:            return (column);
                    487:        else if (c >= ' ')
                    488:            column++;
                    489:        if (column >= Mcol) break;
                    490:        c = getc (f);
                    491:     }
                    492:     if (Mcol > 0 && column >= Mcol) {
                    493:        if (!Wrap) {
                    494:            *p++ = '\n';
                    495:            i++;
                    496:        }
                    497:     }
                    498:     colflg = (column == Mcol) || c == '\f';
                    499:     *p = 0;
                    500:     if (c == '\f' && stop_opt)
                    501:        return (STOP);
                    502:     return (column);
                    503: }
                    504: 
                    505: /*
                    506: ** Erase the rest of the prompt, assuming we are starting column col.
                    507: */
                    508: 
                    509: erase (col)
                    510: register int col;
                    511: {
                    512: 
                    513:     if (hard || promptlen == 0)
                    514:        return;
                    515:     if (col == 0)
                    516:        putchar ('\r');
                    517:     if (!dumb && eraseln)
                    518:        tputs (eraseln, 1, putch);
                    519:     else
                    520:        for (col = promptlen - col; col > 0; col--)
                    521:            putchar (' ');
                    522:     promptlen = 0;
                    523: }
                    524: 
                    525: /*
                    526: ** Erase the current line entirely
                    527: */
                    528: 
                    529: kill_line ()
                    530: {
                    531:     erase (0);
                    532:     if (!eraseln || dumb) putchar ('\r');
                    533: }
                    534: 
                    535: /*
                    536: **  Print string
                    537: */
                    538: 
                    539: pr(s1)
                    540: char   *s1;
                    541: {
                    542:     register char      *s;
                    543:     register char      c;
                    544: 
                    545:     for (s = s1; c = *s++; )
                    546:        putchar(c);
                    547: }
                    548: 
                    549: /*
                    550: **  Clear the screen
                    551: */
                    552: 
                    553: doclear()
                    554: {
                    555:     if (Clear && Lpp > 0)
                    556:        tputs(Clear, 1, putch);
                    557: }
                    558: 
                    559: 
                    560: /*
                    561: ** Read a command and do it. A command consists of an optional integer
                    562: ** argument followed by the command character.  Return the number of lines
                    563: ** to display in the next screenful.  If there is nothing more to display
                    564: ** in the current file, zero is returned.
                    565: */
                    566: 
                    567: command (filename, f)
                    568: char *filename;
                    569: register FILE *f;
                    570: {
                    571:     register int nlines;
                    572:     register int retval;
                    573:     register char c;
                    574:     int id, done;
                    575:     char comchar, cmdbuf[80], *p;
                    576: 
                    577: #define ret(val) retval=val;done++;break
                    578: 
                    579:     done = 0;
                    580:     if (!errors)
                    581:        prompt (filename);
                    582:     else
                    583:        errors = 0;
                    584:     if (MBIT == RAW && slow_tty) {
                    585:        otty.sg_flags |= MBIT;
                    586:        stty(2, &otty);
                    587:     }
                    588:     for (;;) {
                    589:        nlines = number (&comchar);
                    590:        switch (comchar) {
                    591:        case ' ':
                    592:        case 'z':
                    593:            if (nlines == 0) nlines = dlines;
                    594:            else if (comchar == 'z') dlines = nlines;
                    595:            ret (nlines);
                    596:        case 'd':
                    597:        case ctrl(D):
                    598:            ret (11);
                    599:        case RUBOUT:
                    600:        case 'q':
                    601:        case 'Q':
                    602:            end_it ();
                    603:        case 's':
                    604:        case 'f':
                    605:            if (nlines == 0) nlines++;
                    606:            if (comchar == 'f')
                    607:                nlines *= dlines;
                    608:            putchar ('\r');
                    609:            erase (0);
                    610:            pr("\n...skipping ");
                    611:            printd(nlines);
                    612:            pr(" line");
                    613:            if (nlines > 1)
                    614:                pr("s\n\n");
                    615:            else
                    616:                pr("\n\n");
                    617:            while (nlines > 0) {
                    618:                while ((c = getc (f)) != '\n')
                    619:                    if (c == EOF) {
                    620:                        retval = 0;
                    621:                        done++;
                    622:                        goto endsw;
                    623:                    }
                    624:                    nlines--;
                    625:            }
                    626:            ret (dlines);
                    627:            break;
                    628:        case '\n':
                    629:            ret (1);
                    630:        case 'n':
                    631:            if (nlines == 0)
                    632:                nlines++;
                    633:            putchar ('\r');
                    634:            erase (0);
                    635:            skipf (nlines);
                    636:            ret (0);
                    637:        case 'p':
                    638:            if (no_intty) {
                    639:                write (2, &bell, 1);
                    640:                break;
                    641:            }
                    642:            putchar ('\r');
                    643:            erase (0);
                    644:            if (nlines == 0)
                    645:                nlines++;
                    646:            skipf (-nlines);
                    647:            ret (0);
                    648:        case '/':
                    649:            kill_line ();
                    650:            pr ("/");
                    651:            promptlen = 1;
                    652:            fflush (stdout);
                    653:            ttyin (cmdbuf, 78, '/');
                    654:            if (nlines == 0) nlines++;
                    655:            write (2, "\r", 1);
                    656:            search (cmdbuf, f, nlines);
                    657:            ret (dlines);
                    658:        case '!':
                    659:            kill_line ();
                    660:            pr ("!");
                    661:            promptlen = 1;
                    662:            fflush (stdout);
                    663:            ttyin (cmdbuf, 78, '!');
                    664:            write (2, "\n", 1);
                    665:            promptlen = 0;
                    666:            otty.sg_flags |= ECHO;
                    667:            otty.sg_flags &= ~MBIT;
                    668:            stty(2, &otty);
                    669:            while ((id = fork ()) < 0)
                    670:                ;
                    671:            if (id == 0) {
                    672:                execl (shell, shell, "-c", cmdbuf, 0);
                    673:                write (2, "exec failed\n", 12);
                    674:                exit (1);
                    675:            }
                    676:            signal (SIGINT, SIG_IGN);
                    677:            signal (SIGQUIT, SIG_IGN);
                    678:            wait (0);
                    679:            signal (SIGINT, end_it);
                    680:            signal (SIGQUIT, onquit);
                    681:            otty.sg_flags |= MBIT;
                    682:            otty.sg_flags &= ~ECHO;
                    683:            stty(2, &otty);
                    684:            pr ("----------\n(continue)\n");
                    685:            fflush (stdout);
                    686:            break;
                    687:        default:
                    688:            write (2, &bell, 1);
                    689:            break;
                    690:        }
                    691:        if (done) break;
                    692:     }
                    693:     putchar ('\r');
                    694: endsw:
                    695:     inwait = 0;
                    696:     notell++;
                    697:     if (MBIT == RAW && slow_tty) {
                    698:        otty.sg_flags &= ~MBIT;
                    699:        stty(2, &otty);
                    700:     }
                    701:     return (retval);
                    702: }
                    703: 
                    704: char ch;
                    705: 
                    706: /*
                    707: ** Read a decimal number from the terminal. Set cmd to the non-digit which
                    708: ** terminates the number.
                    709: */
                    710: 
                    711: number(cmd)
                    712: char *cmd;
                    713: {
                    714:     register int i;
                    715: 
                    716:     i = 0; ch = otty.sg_kill;
                    717:     for (;;) {
                    718:        read (2, &ch, 1);
                    719:        if (ch >= '0' && ch <= '9')
                    720:            i = i*10 + ch - '0';
                    721:        else if (ch == otty.sg_kill)
                    722:            i = 0;
                    723:        else {
                    724:            *cmd = ch;
                    725:            break;
                    726:        }
                    727:     }
                    728:     return (i);
                    729: }
                    730: 
                    731: /*
                    732: ** Skip n lines in the file f
                    733: */
                    734: 
                    735: skiplns (n, f)
                    736: register int n;
                    737: register FILE *f;
                    738: {
                    739:     register char c;
                    740: 
                    741:     while (n > 0) {
                    742:        while ((c = getc (f)) != '\n')
                    743:            if (c == EOF)
                    744:                return;
                    745:            n--;
                    746:     }
                    747: }
                    748: 
                    749: /*
                    750: ** Skip nskip files in the file list (from the command line). Nskip may be
                    751: ** negative.
                    752: */
                    753: 
                    754: skipf (nskip)
                    755: register int nskip;
                    756: {
                    757:     if (nskip == 0) return;
                    758:     if (nskip > 0) {
                    759:        if (fnum > nfiles - 1)
                    760:            end_it ();
                    761:     }
                    762:     else if (within)
                    763:        ++fnum;
                    764:     fnum += nskip;
                    765:     if (fnum < 0)
                    766:        fnum = 0;
                    767:     else if (fnum > nfiles - 1)
                    768:        fnum = nfiles -1;
                    769:     pr ("\n...Skipping ");
                    770:     pr (nskip > 0 ? "to file " : "back to file ");
                    771:     pr (fnames[fnum]);
                    772:     pr ("\n\n");
                    773:     --fnum;
                    774: }
                    775: 
                    776: readch ()
                    777: {
                    778:     char ch;
                    779: 
                    780:     read (2, &ch, 1);
                    781:     return (ch);
                    782: }
                    783: 
                    784: static char BS = '\b';
                    785: static char CARAT = '^';
                    786: 
                    787: ttyin (buf, nmax, pchar)
                    788: char buf[];
                    789: register int nmax;
                    790: char pchar;
                    791: {
                    792:     register char *sptr;
                    793:     register char ch;
                    794:     register int slash = 0;
                    795:     int        maxlen;
                    796:     char cbuf;
                    797: 
                    798:     sptr = buf;
                    799:     maxlen = 0;
                    800:     while (sptr - buf < nmax) {
                    801:        if (promptlen > maxlen) maxlen = promptlen;
                    802:        ch = readch ();
                    803:        if (ch == '\\') {
                    804:            slash++;
                    805:        }
                    806:        else if (ch == otty.sg_erase && !slash) {
                    807:            if (sptr > buf) {
                    808:                --promptlen;
                    809:                write (2, &BS, 1);
                    810:                --sptr;
                    811:                if (*sptr < ' ' && *sptr != '\n') {
                    812:                    --promptlen;
                    813:                    write (2, &BS, 1);
                    814:                }
                    815:                continue;
                    816:            }
                    817:            else {
                    818:                if (!eraseln) promptlen = maxlen;
                    819:                longjmp (restore, 1);
                    820:            }
                    821:        }
                    822:        else if (ch == otty.sg_kill && !slash) {
                    823:            if (hard)
                    824:                pr (" XXX\n");
                    825:            else {
                    826:                putchar ('\r');
                    827:                putchar (pchar);
                    828:                if (eraseln)
                    829:                    erase (1);
                    830:                promptlen = 1;
                    831:                sptr = buf;
                    832:            }
                    833:            fflush (stdout);
                    834:            continue;
                    835:        }
                    836:        if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
                    837:            write (2, &BS, 1);
                    838:            --sptr;
                    839:        }
                    840:        if (ch != '\\')
                    841:            slash = 0;
                    842:        *sptr++ = ch;
                    843:        if (ch < ' ' && ch != '\n' && ch != ESC) {
                    844:            ch += 0100;
                    845:            write (2, &CARAT, 1);
                    846:            promptlen++;
                    847:        }
                    848:        cbuf = ch;
                    849:        if (ch != '\n' && ch != ESC) {
                    850:            write (2, &cbuf, 1);
                    851:            promptlen++;
                    852:        }
                    853:        else break;
                    854:     }
                    855:     *--sptr = '\0';
                    856:     if (!eraseln) promptlen = maxlen;
                    857:     if (sptr - buf >= nmax - 1)
                    858:        error ("Line too long");
                    859: }
                    860: 
                    861: /*
                    862: ** Search for nth ocurrence of regular expression contained in buf in the file
                    863: */
                    864: 
                    865: search (buf, file, n)
                    866: char buf[];
                    867: FILE *file;
                    868: register int n;
                    869: {
                    870:     long startline = ftell (file);
                    871:     register long line1 = startline;
                    872:     register long line2 = startline;
                    873:     register long line3 = startline;
                    874:     register int lncount;
                    875: 
                    876:     lncount = 0;
                    877:     compile (buf);
                    878:     while (!feof (file)) {
                    879:        line3 = line2;
                    880:        line2 = line1;
                    881:        line1 = ftell (file);
                    882:        rdline (file);
                    883:        lncount++;
                    884:        if (execute (Line))
                    885:                if (--n == 0) {
                    886:                    if (lncount > 3 || (lncount > 1 && no_intty))
                    887:                        pr ("\n...skipping\n");
                    888:                    if (!no_intty)
                    889:                        fseek (file, line3, 0);
                    890:                    else {
                    891:                        kill_line ();
                    892:                        pr (Line);
                    893:                        putchar ('\n');
                    894:                    }
                    895:                    break;
                    896:                }
                    897:     }
                    898:     if (feof (file)) {
                    899:        if (!no_intty) {
                    900: #ifdef CORY
                    901:            file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */
                    902: #endif
                    903:            fseek (file, startline, 0);
                    904:        }
                    905:        else {
                    906:            pr ("\nPattern not found\n");
                    907:            end_it ();
                    908:        }
                    909:        error ("Pattern not found");
                    910:     }
                    911: }
                    912: 
                    913: /*
                    914:  * The following are adapted from the editor
                    915:  */
                    916: 
                    917: /*
                    918:  * Internal form of regular expressions.
                    919:  */
                    920: #define        CBRA    1       /* left \( bracket */
                    921: #define        CCHR    2       /* a particular character */
                    922: #define        CDOT    4       /* any char (.) */
                    923: #define        CCL     6       /* begin class ([) */
                    924: #define        NCCL    8       /* begin not class ([^) */
                    925: #define        CDOL    10      /* end of line ($) */
                    926: #define        CEOF    11      /* end of pattern */
                    927: #define        CKET    12      /* right \) bracket */
                    928: #define        CBACK   14      /* repeat previous match (\1, etc on lhs) */
                    929: 
                    930: #define        STAR    01      /* or'ed with some symbols to indicate * suffix */
                    931:  
                    932: #define        NBRA    5       /* max # of \( \) pairs */
                    933: 
                    934: char expbuf[BUFSIZ];
                    935: char *braslist[NBRA];
                    936: char *braelist[NBRA];
                    937: int nbra;
                    938: int circfl;
                    939: char *loc1;
                    940: char *loc2;
                    941: char *locs;
                    942: 
                    943: 
                    944: /*
                    945:  * compile: convert typed in regular expression into internal form.
                    946:  * eof is the char that delimits the r.e.
                    947:  * General structure of compiled r.e. in expbuf: A sequence of codes
                    948:  * from #defines above (CCHR, CDOT, etc). Some of these take arguments
                    949:  * which follow in line (e.g. CCHR is followed by the particular character
                    950:  * it is required to match.) CEOF terminates the r.e.
                    951:  */
                    952: compile(inbuf)
                    953: char inbuf[];
                    954: {
                    955:        register char c;
                    956:        register char *ep;
                    957:        register char *bp = inbuf;
                    958:        char *lastep;
                    959:        char bracket[NBRA], *bracketp;
                    960:        int cclcnt;
                    961: 
                    962: /* comerr: compilation error. Don't leave half baked r.e. around. */
                    963: #define comerr(msg) {expbuf[0] = 0; nbra = 0; error(msg); }
                    964:        ep = expbuf;
                    965:        bracketp = bracket;
                    966:        if ((c = *bp++) == '\0') {
                    967:                /* null r.e.: just re-use last r.e., which is still there */
                    968:                if (*ep==0)
                    969:                        error("No previous regular expression");
                    970:                return;
                    971:        }
                    972:        nbra = 0;
                    973:        /* circfl: true if have ^ (anchored search). */
                    974:        circfl = 0;
                    975:        if (c == '^') {
                    976:                c = *bp++;
                    977:                circfl++;
                    978:        }
                    979:        lastep = 0;
                    980:        --bp;
                    981:        for (;;) {      /* for each character in the r.e. */
                    982:                if (ep >= &expbuf[BUFSIZ])
                    983:                        comerr("r.e. too long");
                    984:                c = *bp++;
                    985:                if (c == '\0') {
                    986:                        /* Hit trailing delim: clean up and quit */
                    987:                        if (bracketp != bracket)
                    988:                                comerr("unmatched \\(");
                    989:                        *ep++ = CEOF;
                    990:                        *ep++ = 0;
                    991:                        return;
                    992:                }
                    993:                if (c!='*')
                    994:                        lastep = ep;
                    995:                switch (c) {
                    996: 
                    997:                case '\\':
                    998:                        if ((c = *bp++)=='(') {
                    999:                                /* \(: start of subexpression */
                   1000:                                if (nbra >= NBRA)
                   1001:                                        comerr("too many \\(\\) pairs");
                   1002:                                *bracketp++ = nbra;
                   1003:                                *ep++ = CBRA;
                   1004:                                *ep++ = nbra++;
                   1005:                                continue;
                   1006:                        }
                   1007:                        if (c == ')') {
                   1008:                                /* \): end of sub exp */
                   1009:                                if (bracketp <= bracket)
                   1010:                                        comerr("unmatched \\)");
                   1011:                                *ep++ = CKET;
                   1012:                                *ep++ = *--bracketp;
                   1013:                                continue;
                   1014:                        }
                   1015:                        if (c>='1' && c<'1'+NBRA) {
                   1016:                                /* \1, \2, ...: rematch previous subexp */
                   1017:                                *ep++ = CBACK;
                   1018:                                *ep++ = c-'1';
                   1019:                                continue;
                   1020:                        }
                   1021:                        /* Otherwise just force that char, not specially */
                   1022:                        *ep++ = CCHR;
                   1023:                        if (c=='\n')
                   1024:                                /* Newlines can't possibly be in lines */
                   1025:                                comerr("multi line r.e. not allowed");
                   1026:                        *ep++ = c;
                   1027:                        continue;
                   1028: 
                   1029:                case '.':
                   1030:                        /* .: match any character */
                   1031:                        *ep++ = CDOT;
                   1032:                        continue;
                   1033: 
                   1034:                case '*':
                   1035:                        /* *: Repeat last char indefinitely */
                   1036:                        if (lastep==0 || *lastep==CBRA || *lastep==CKET)
                   1037:                                /* Not that smart, so treat * as nonspecial */
                   1038:                                goto defchar;
                   1039:                        *lastep |= STAR;
                   1040:                        continue;
                   1041: 
                   1042:                case '$':
                   1043:                        /* $: match end of line */
                   1044:                        if (*bp != '\0')
                   1045:                                /* $ only special at end of r.e. */
                   1046:                                goto defchar;
                   1047:                        *ep++ = CDOL;
                   1048:                        continue;
                   1049: 
                   1050:                case '[':
                   1051:                        /*
                   1052:                         * [...]: any of chars enclosed in brackets.
                   1053:                         * Compiled form: CCL or NCCL, # of possible chars,
                   1054:                         * then each char. -'s are expanded.
                   1055:                         */
                   1056:                        *ep++ = CCL;
                   1057:                        *ep++ = 0;
                   1058:                        cclcnt = 1;
                   1059:                        if ((c = *bp++) == '^') {
                   1060:                                /* [^...]: reverse sense of match */
                   1061:                                c = *bp++;
                   1062:                                ep[-2] = NCCL;
                   1063:                        }
                   1064:                        do {    /* for each char in brackets */
                   1065:                                if (c=='\n')
                   1066:                                        comerr("missing ]");
                   1067:                                if (c == '-' && ep[-1] != 0) {
                   1068:                                        /* form ...a-z... but [- not special */
                   1069:                                        if ((c = *bp++) == ']') {
                   1070:                                                /* -] not special either */
                   1071:                                                *ep++ = '-';
                   1072:                                                cclcnt++;
                   1073:                                                break;
                   1074:                                        }
                   1075:                                        while (ep[-1]<c) {
                   1076:                                                /* insert all chars between */
                   1077:                                                *ep = ep[-1]+1;
                   1078:                                                ep++;
                   1079:                                                cclcnt++;
                   1080:                                                if (ep>=&expbuf[BUFSIZ])
                   1081:                                                        comerr("Too long");
                   1082:                                        }
                   1083:                                }
                   1084:                                *ep++ = c;
                   1085:                                cclcnt++;
                   1086:                                if (ep >= &expbuf[BUFSIZ])
                   1087:                                        comerr("Too long");
                   1088:                        } while ((c = *bp++) != ']');
                   1089:                        lastep[1] = cclcnt;     /* backpatch count */
                   1090:                        continue;
                   1091: 
                   1092:                defchar:
                   1093:                default:
                   1094:                        /*
                   1095:                         * An ordinary char or one treated as ordinary.
                   1096:                         * Store CCHR followed by that char, rather than
                   1097:                         * just the char. This causes most r.e.'s to take
                   1098:                         * up about twice the space you would expect.
                   1099:                         * On the other hand, it makes r.e.'s beautifully
                   1100:                         * portable, even though the codes could be real
                   1101:                         * characters.
                   1102:                         */
                   1103:                        *ep++ = CCHR;
                   1104:                        *ep++ = c;
                   1105:                }
                   1106:        }
                   1107: }
                   1108: 
                   1109: /*
                   1110:  * execute: look for the compiled r.e. on line addr.
                   1111:  * gf is 0 if this is the first time on this line, otherwise nonzero.
                   1112:  * If not first, start looking at locs, otherwise at beg of linebuf.
                   1113:  * loc1 and loc2 are set to the ends of the pattern found, if any.
                   1114:  * 1 is returned if successful, otherwise 0.
                   1115:  */
                   1116: execute(lptr)
                   1117: char *lptr;
                   1118: {
                   1119:        register char *p1, *p2;
                   1120:        register int c;
                   1121: 
                   1122:        for (c=0; c<NBRA; c++) {
                   1123:                braslist[c] = 0;
                   1124:                braelist[c] = 0;
                   1125:        }
                   1126:        p1 = lptr;
                   1127:        p2 = expbuf;
                   1128:        if (circfl) {
                   1129:                /* anchored search (^): just try one advance. */
                   1130:                loc1 = p1;
                   1131:                return(advance(p1, p2));
                   1132:        }
                   1133:        /* fast check for first character */
                   1134:        if (*p2==CCHR) {
                   1135:                c = p2[1];
                   1136:                do {
                   1137:                        if (*p1!=c)
                   1138:                                continue;
                   1139:                        if (advance(p1, p2)) {
                   1140:                                loc1 = p1;
                   1141:                                return(1);
                   1142:                        }
                   1143:                } while (*p1++);
                   1144:                return(0);
                   1145:        }
                   1146:        /* regular algorithm, try advance starting at each char position. */
                   1147:        do {
                   1148:                if (advance(p1, p2)) {
                   1149:                        loc1 = p1;
                   1150:                        return(1);
                   1151:                }
                   1152:        } while (*p1++);
                   1153:        return(0);
                   1154: }
                   1155: 
                   1156: /*
                   1157:  * advance: does an anchored search for expression starting at ep,
                   1158:  * looking in line starting at lp. Returns 1 if matches, else 0.
                   1159:  * If found, loc2 is set to end of pattern.
                   1160:  */
                   1161: advance(lp, ep)
                   1162: register char *ep, *lp;
                   1163: {
                   1164:        register char *curlp;
                   1165:        int i;
                   1166: 
                   1167:        for (;;) switch (*ep++) {       /* for each code in r.e., look at it..*/
                   1168: 
                   1169:        case CCHR:
                   1170:                if (*ep++ == *lp++)
                   1171:                        continue;
                   1172:                return(0);
                   1173: 
                   1174:        case CDOT:
                   1175:                if (*lp++)
                   1176:                        continue;
                   1177:                return(0);
                   1178: 
                   1179:        case CDOL:
                   1180:                if (*lp==0)
                   1181:                        continue;
                   1182:                return(0);
                   1183: 
                   1184:        case CEOF:
                   1185:                loc2 = lp;
                   1186:                return(1);
                   1187: 
                   1188:        case CCL:
                   1189:                if (cclass(ep, *lp++, 1)) {
                   1190:                        ep += *ep;
                   1191:                        continue;
                   1192:                }
                   1193:                return(0);
                   1194: 
                   1195:        case NCCL:
                   1196:                if (cclass(ep, *lp++, 0)) {
                   1197:                        ep += *ep;
                   1198:                        continue;
                   1199:                }
                   1200:                return(0);
                   1201: 
                   1202:        case CBRA:
                   1203:                braslist[*ep++] = lp;
                   1204:                continue;
                   1205: 
                   1206:        case CKET:
                   1207:                braelist[*ep++] = lp;
                   1208:                continue;
                   1209: 
                   1210:        case CBACK:
                   1211:                if (braelist[i = *ep++]==0)
                   1212:                        error("bad back reference");
                   1213:                if (backref(i, lp)) {
                   1214:                        lp += braelist[i] - braslist[i];
                   1215:                        continue;
                   1216:                }
                   1217:                return(0);
                   1218: 
                   1219:        case CBACK|STAR:
                   1220:                if (braelist[i = *ep++] == 0)
                   1221:                        error("bad back reference");
                   1222:                curlp = lp;
                   1223:                while (backref(i, lp))
                   1224:                        lp += braelist[i] - braslist[i];
                   1225:                while (lp >= curlp) {
                   1226:                        if (advance(lp, ep))
                   1227:                                return(1);
                   1228:                        lp -= braelist[i] - braslist[i];
                   1229:                }
                   1230:                continue;
                   1231: 
                   1232:        case CDOT|STAR:
                   1233:                curlp = lp;
                   1234:                while (*lp++)
                   1235:                        ;
                   1236:                goto star;
                   1237: 
                   1238:        case CCHR|STAR:
                   1239:                curlp = lp;
                   1240:                while (*lp++ == *ep)
                   1241:                        ;
                   1242:                ep++;
                   1243:                goto star;
                   1244: 
                   1245:        case CCL|STAR:
                   1246:        case NCCL|STAR:
                   1247:                curlp = lp;
                   1248:                while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)))
                   1249:                        ;
                   1250:                ep += *ep;
                   1251:                goto star;
                   1252: 
                   1253:        star:
                   1254:                /*
                   1255:                 * star: special treatment. We have found as many of them
                   1256:                 * as there are to find. Maybe this was too many, as dictated
                   1257:                 * by what follows in the pattern. Try, starting from the
                   1258:                 * end, to recursively advance after each char found,
                   1259:                 * and return after first successful advance (thus finding
                   1260:                 * largest possible string that matches).
                   1261:                 */
                   1262:                do {
                   1263:                        lp--;
                   1264:                        if (lp==locs)
                   1265:                                break;
                   1266:                        if (advance(lp, ep))
                   1267:                                return(1);
                   1268:                } while (lp > curlp);
                   1269:                /* star failed at all attempts, so whole pattern fails. */
                   1270:                return(0);
                   1271: 
                   1272:        default:
                   1273:                longjmp (restore, 1);
                   1274:        }
                   1275: }
                   1276: 
                   1277: /*
                   1278:  * backref: checks to see that text starting at lp matches previous
                   1279:  * sub-expression #i. Returns 1 if successful, else 0. (Used for \k
                   1280:  * on lhs.)
                   1281:  */
                   1282: backref(i, lp)
                   1283: register int i;
                   1284: register char *lp;
                   1285: {
                   1286:        register char *bp;
                   1287: 
                   1288:        bp = braslist[i];
                   1289:        while (*bp++ == *lp++)
                   1290:                if (bp >= braelist[i])
                   1291:                        return(1);
                   1292:        return(0);
                   1293: }
                   1294: 
                   1295: /*
                   1296:  * cclass: check to see if character c is in class starting at set.
                   1297:  * ([...] construction on lhs of r.e.) af is sense of success/failure:
                   1298:  * af=1 is normal (success returns 1), af=0 is reversed for [^ (success
                   1299:  * returns 0).
                   1300:  */
                   1301: int
                   1302: cclass(set, c, af)
                   1303: register char *set, c;
                   1304: int af;
                   1305: {
                   1306:        register n;
                   1307: 
                   1308:        if (c==0)
                   1309:                return(0);
                   1310:        n = *set++;
                   1311:        while (--n)
                   1312:                if (*set++ == c)
                   1313:                        return(af);
                   1314:        return(!af);
                   1315: }
                   1316: 
                   1317: error (mess)
                   1318: char *mess;
                   1319: {
                   1320:     if (promptlen > 0)
                   1321:        if (hard)
                   1322:            putchar ('\n');
                   1323:        else
                   1324:            kill_line ();
                   1325:     promptlen += strlen (mess);
                   1326:     if (Senter && Sexit) {
                   1327:        tputs (Senter, 1, putch);
                   1328:        pr(mess);
                   1329:        tputs (Sexit, 1, putch);
                   1330:     }
                   1331:     else
                   1332:        pr (mess);
                   1333:     if (hard)
                   1334:        putchar ('\n');
                   1335:     fflush(stdout);
                   1336:     errors++;
                   1337:     longjmp (restore, 1);
                   1338: }
                   1339: 
                   1340: rdline (f)
                   1341: register FILE *f;
                   1342: {
                   1343:     register char c;
                   1344:     register char *p;
                   1345: 
                   1346:     p = Line;
                   1347:     while ((c = getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
                   1348:        *p++ = c;
                   1349:     *p = '\0';
                   1350: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.