Annotation of 43BSDTahoe/usr.lib/libtermlib/termcap.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: static char sccsid[] = "@(#)termcap.c  5.2 (Berkeley) 9/11/87";
                      9: #endif not lint
                     10: 
                     11: #define        BUFSIZ          1024
                     12: #define MAXHOP         32      /* max number of tc= indirections */
                     13: #define        PBUFSIZ         512     /* max length of filename path */
                     14: #define        PVECSIZ         32      /* max number of names in path */
                     15: #define DEF_PATH       ".termcap /etc/termcap"
                     16: 
                     17: #include <ctype.h>
                     18: /*
                     19:  * termcap - routines for dealing with the terminal capability data base
                     20:  *
                     21:  * BUG:                Should use a "last" pointer in tbuf, so that searching
                     22:  *             for capabilities alphabetically would not be a n**2/2
                     23:  *             process when large numbers of capabilities are given.
                     24:  * Note:       If we add a last pointer now we will screw up the
                     25:  *             tc capability. We really should compile termcap.
                     26:  *
                     27:  * Essentially all the work here is scanning and decoding escapes
                     28:  * in string capabilities.  We don't use stdio because the editor
                     29:  * doesn't, and because living w/o it is not hard.
                     30:  */
                     31: 
                     32: static char *tbuf;
                     33: static int hopcount;   /* detect infinite loops in termcap, init 0 */
                     34: static char pathbuf[PBUFSIZ];          /* holds raw path of filenames */
                     35: static char *pathvec[PVECSIZ];         /* to point to names in pathbuf */
                     36: static char **pvec;                    /* holds usable tail of path vector */
                     37: char   *tskip();
                     38: char   *tgetstr();
                     39: char   *tdecode();
                     40: char   *getenv();
                     41: 
                     42: /*
                     43:  * Get an entry for terminal name in buffer bp from the termcap file.
                     44:  */
                     45: tgetent(bp, name)
                     46:        char *bp, *name;
                     47: {
                     48:        register char *p;
                     49:        register char *cp;
                     50:        register int c;
                     51:        char *term, *home, *termpath;
                     52:        char **fname = pathvec;
                     53: 
                     54:        pvec = pathvec;
                     55:        tbuf = bp;
                     56:        p = pathbuf;
                     57: #ifndef V6
                     58:        cp = getenv("TERMCAP");
                     59:        /*
                     60:         * TERMCAP can have one of two things in it. It can be the
                     61:         * name of a file to use instead of /etc/termcap. In this
                     62:         * case it better start with a "/". Or it can be an entry to
                     63:         * use so we don't have to read the file. In this case it
                     64:         * has to already have the newlines crunched out.  If TERMCAP
                     65:         * does not hold a file name then a path of names is searched
                     66:         * instead.  The path is found in the TERMPATH variable, or
                     67:         * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
                     68:         */
                     69:        if (!cp || *cp != '/') {        /* no TERMCAP or it holds an entry */
                     70:                if (termpath = getenv("TERMPATH"))
                     71:                        strncpy(pathbuf, termpath, PBUFSIZ);
                     72:                else {
                     73:                        if (home = getenv("HOME")) {    /* set up default */
                     74:                                p += strlen(home);      /* path, looking in */
                     75:                                strcpy(pathbuf, home);  /* $HOME first */
                     76:                                *p++ = '/';
                     77:                        }       /* if no $HOME look in current directory */
                     78:                        strncpy(p, DEF_PATH, PBUFSIZ - (p - pathbuf));
                     79:                }
                     80:        }
                     81:        else                            /* user-defined name in TERMCAP */
                     82:                strncpy(pathbuf, cp, PBUFSIZ);  /* still can be tokenized */
                     83: #else
                     84:        strncpy(pathbuf, "/etc/termcap", PBUFSIZ);
                     85: #endif
                     86:        *fname++ = pathbuf;     /* tokenize path into vector of names */
                     87:        while (*++p)
                     88:                if (*p == ' ' || *p == ':') {
                     89:                        *p = '\0';
                     90:                        while (*++p)
                     91:                                if (*p != ' ' && *p != ':')
                     92:                                        break;
                     93:                        if (*p == '\0')
                     94:                                break;
                     95:                        *fname++ = p;
                     96:                        if (fname >= pathvec + PVECSIZ) {
                     97:                                fname--;
                     98:                                break;
                     99:                        }
                    100:                }
                    101:        *fname = (char *) 0;                    /* mark end of vector */
                    102:        if (cp && *cp && *cp != '/') {
                    103:                tbuf = cp;
                    104:                c = tnamatch(name);
                    105:                tbuf = bp;
                    106:                if (c) {
                    107:                        strcpy(bp,cp);
                    108:                        return (tnchktc());
                    109:                }
                    110:        }
                    111:        return (tfindent(bp, name));    /* find terminal entry in path */
                    112: }
                    113: 
                    114: /*
                    115:  * tfindent - reads through the list of files in pathvec as if they were one
                    116:  * continuous file searching for terminal entries along the way.  It will
                    117:  * participate in indirect recursion if the call to tnchktc() finds a tc=
                    118:  * field, which is only searched for in the current file and files ocurring
                    119:  * after it in pathvec.  The usable part of this vector is kept in the global
                    120:  * variable pvec.  Terminal entries may not be broken across files.  Parse is
                    121:  * very rudimentary; we just notice escaped newlines.
                    122:  */
                    123: tfindent(bp, name)
                    124:        char *bp, *name;
                    125: {
                    126:        register char *cp;
                    127:        register int c;
                    128:        register int i, cnt;
                    129:        char ibuf[BUFSIZ];
                    130:        int opencnt = 0;
                    131:        int tf;
                    132: 
                    133:        tbuf = bp;
                    134: nextfile:
                    135:        i = cnt = 0;
                    136:        while (*pvec && (tf = open(*pvec, 0)) < 0)
                    137:                pvec++;
                    138:        if (!*pvec)
                    139:                return (opencnt ? 0 : -1);
                    140:        opencnt++;
                    141:        for (;;) {
                    142:                cp = bp;
                    143:                for (;;) {
                    144:                        if (i == cnt) {
                    145:                                cnt = read(tf, ibuf, BUFSIZ);
                    146:                                if (cnt <= 0) {
                    147:                                        close(tf);
                    148:                                        pvec++;
                    149:                                        goto nextfile;
                    150:                                }
                    151:                                i = 0;
                    152:                        }
                    153:                        c = ibuf[i++];
                    154:                        if (c == '\n') {
                    155:                                if (cp > bp && cp[-1] == '\\'){
                    156:                                        cp--;
                    157:                                        continue;
                    158:                                }
                    159:                                break;
                    160:                        }
                    161:                        if (cp >= bp+BUFSIZ) {
                    162:                                write(2,"Termcap entry too long\n", 23);
                    163:                                break;
                    164:                        } else
                    165:                                *cp++ = c;
                    166:                }
                    167:                *cp = 0;
                    168: 
                    169:                /*
                    170:                 * The real work for the match.
                    171:                 */
                    172:                if (tnamatch(name)) {
                    173:                        close(tf);
                    174:                        return(tnchktc());
                    175:                }
                    176:        }
                    177: }
                    178: 
                    179: /*
                    180:  * tnchktc: check the last entry, see if it's tc=xxx. If so,
                    181:  * recursively find xxx and append that entry (minus the names)
                    182:  * to take the place of the tc=xxx entry. This allows termcap
                    183:  * entries to say "like an HP2621 but doesn't turn on the labels".
                    184:  * Note that this works because of the left to right scan.
                    185:  */
                    186: tnchktc()
                    187: {
                    188:        register char *p, *q;
                    189:        char tcname[16];        /* name of similar terminal */
                    190:        char tcbuf[BUFSIZ];
                    191:        char *holdtbuf = tbuf;
                    192:        int l;
                    193: 
                    194:        p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
                    195:        while (*--p != ':')
                    196:                if (p<tbuf) {
                    197:                        write(2, "Bad termcap entry\n", 18);
                    198:                        return (0);
                    199:                }
                    200:        p++;
                    201:        /* p now points to beginning of last field */
                    202:        if (p[0] != 't' || p[1] != 'c')
                    203:                return(1);
                    204:        strcpy(tcname,p+3);
                    205:        q = tcname;
                    206:        while (*q && *q != ':')
                    207:                q++;
                    208:        *q = 0;
                    209:        if (++hopcount > MAXHOP) {
                    210:                write(2, "Infinite tc= loop\n", 18);
                    211:                return (0);
                    212:        }
                    213:        if (tfindent(tcbuf, tcname) != 1) {
                    214:                hopcount = 0;           /* unwind recursion */
                    215:                return(0);
                    216:        }
                    217:        for (q=tcbuf; *q != ':'; q++)
                    218:                ;
                    219:        l = p - holdtbuf + strlen(q);
                    220:        if (l > BUFSIZ) {
                    221:                write(2, "Termcap entry too long\n", 23);
                    222:                q[BUFSIZ - (p-tbuf)] = 0;
                    223:        }
                    224:        strcpy(p, q+1);
                    225:        tbuf = holdtbuf;
                    226:        hopcount = 0;                   /* unwind recursion */
                    227:        return(1);
                    228: }
                    229: 
                    230: /*
                    231:  * Tnamatch deals with name matching.  The first field of the termcap
                    232:  * entry is a sequence of names separated by |'s, so we compare
                    233:  * against each such name.  The normal : terminator after the last
                    234:  * name (before the first field) stops us.
                    235:  */
                    236: tnamatch(np)
                    237:        char *np;
                    238: {
                    239:        register char *Np, *Bp;
                    240: 
                    241:        Bp = tbuf;
                    242:        if (*Bp == '#')
                    243:                return(0);
                    244:        for (;;) {
                    245:                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
                    246:                        continue;
                    247:                if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
                    248:                        return (1);
                    249:                while (*Bp && *Bp != ':' && *Bp != '|')
                    250:                        Bp++;
                    251:                if (*Bp == 0 || *Bp == ':')
                    252:                        return (0);
                    253:                Bp++;
                    254:        }
                    255: }
                    256: 
                    257: /*
                    258:  * Skip to the next field.  Notice that this is very dumb, not
                    259:  * knowing about \: escapes or any such.  If necessary, :'s can be put
                    260:  * into the termcap file in octal.
                    261:  */
                    262: static char *
                    263: tskip(bp)
                    264:        register char *bp;
                    265: {
                    266: 
                    267:        while (*bp && *bp != ':')
                    268:                bp++;
                    269:        if (*bp == ':')
                    270:                bp++;
                    271:        return (bp);
                    272: }
                    273: 
                    274: /*
                    275:  * Return the (numeric) option id.
                    276:  * Numeric options look like
                    277:  *     li#80
                    278:  * i.e. the option string is separated from the numeric value by
                    279:  * a # character.  If the option is not found we return -1.
                    280:  * Note that we handle octal numbers beginning with 0.
                    281:  */
                    282: tgetnum(id)
                    283:        char *id;
                    284: {
                    285:        register int i, base;
                    286:        register char *bp = tbuf;
                    287: 
                    288:        for (;;) {
                    289:                bp = tskip(bp);
                    290:                if (*bp == 0)
                    291:                        return (-1);
                    292:                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                    293:                        continue;
                    294:                if (*bp == '@')
                    295:                        return(-1);
                    296:                if (*bp != '#')
                    297:                        continue;
                    298:                bp++;
                    299:                base = 10;
                    300:                if (*bp == '0')
                    301:                        base = 8;
                    302:                i = 0;
                    303:                while (isdigit(*bp))
                    304:                        i *= base, i += *bp++ - '0';
                    305:                return (i);
                    306:        }
                    307: }
                    308: 
                    309: /*
                    310:  * Handle a flag option.
                    311:  * Flag options are given "naked", i.e. followed by a : or the end
                    312:  * of the buffer.  Return 1 if we find the option, or 0 if it is
                    313:  * not given.
                    314:  */
                    315: tgetflag(id)
                    316:        char *id;
                    317: {
                    318:        register char *bp = tbuf;
                    319: 
                    320:        for (;;) {
                    321:                bp = tskip(bp);
                    322:                if (!*bp)
                    323:                        return (0);
                    324:                if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
                    325:                        if (!*bp || *bp == ':')
                    326:                                return (1);
                    327:                        else if (*bp == '@')
                    328:                                return(0);
                    329:                }
                    330:        }
                    331: }
                    332: 
                    333: /*
                    334:  * Get a string valued option.
                    335:  * These are given as
                    336:  *     cl=^Z
                    337:  * Much decoding is done on the strings, and the strings are
                    338:  * placed in area, which is a ref parameter which is updated.
                    339:  * No checking on area overflow.
                    340:  */
                    341: char *
                    342: tgetstr(id, area)
                    343:        char *id, **area;
                    344: {
                    345:        register char *bp = tbuf;
                    346: 
                    347:        for (;;) {
                    348:                bp = tskip(bp);
                    349:                if (!*bp)
                    350:                        return (0);
                    351:                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                    352:                        continue;
                    353:                if (*bp == '@')
                    354:                        return(0);
                    355:                if (*bp != '=')
                    356:                        continue;
                    357:                bp++;
                    358:                return (tdecode(bp, area));
                    359:        }
                    360: }
                    361: 
                    362: /*
                    363:  * Tdecode does the grung work to decode the
                    364:  * string capability escapes.
                    365:  */
                    366: static char *
                    367: tdecode(str, area)
                    368:        register char *str;
                    369:        char **area;
                    370: {
                    371:        register char *cp;
                    372:        register int c;
                    373:        register char *dp;
                    374:        int i;
                    375: 
                    376:        cp = *area;
                    377:        while ((c = *str++) && c != ':') {
                    378:                switch (c) {
                    379: 
                    380:                case '^':
                    381:                        c = *str++ & 037;
                    382:                        break;
                    383: 
                    384:                case '\\':
                    385:                        dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
                    386:                        c = *str++;
                    387: nextc:
                    388:                        if (*dp++ == c) {
                    389:                                c = *dp++;
                    390:                                break;
                    391:                        }
                    392:                        dp++;
                    393:                        if (*dp)
                    394:                                goto nextc;
                    395:                        if (isdigit(c)) {
                    396:                                c -= '0', i = 2;
                    397:                                do
                    398:                                        c <<= 3, c |= *str++ - '0';
                    399:                                while (--i && isdigit(*str));
                    400:                        }
                    401:                        break;
                    402:                }
                    403:                *cp++ = c;
                    404:        }
                    405:        *cp++ = 0;
                    406:        str = *area;
                    407:        *area = cp;
                    408:        return (str);
                    409: }

unix.superglobalmegacorp.com

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