Annotation of 43BSD/usr.bin/tip/remcap.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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