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

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

unix.superglobalmegacorp.com

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