Annotation of 42BSD/usr.lib/lpr/printcap.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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