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

unix.superglobalmegacorp.com

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