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

unix.superglobalmegacorp.com

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