Annotation of 43BSDReno/lib/libterm/termcap.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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