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

unix.superglobalmegacorp.com

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