# 2.11BSD#431 - /usr/src/usr.sbin/lpr/printcap.c

##### Functions

    endprent          X
    getprent          X
    tgetent           X
    tgetflag          X
    tgetnum           X
    tgetstr           X
    tnamatch          X
    tnchktc           X

##### Macros

    BUFSIZ            X
    E_TERMCAP         X
    MAXHOP            X
    PRINTCAP          X
    V6                X
    tdecode           X
    tgetent           X
    tgetflag          X
    tgetnum           X
    tgetstr           X
    tnamatch          X
    tnchktc           X
    tskip             X

       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: }

#### Defined functions

endprent defined in line 100; used 1 times

- in /usr/src/usr.sbin/lpr/lpd.c line 386

getprent defined in line 59; used 11 times

- in /usr/src/usr.sbin/lpr/cmds.c line 34, 129, 263, 325, 397, 507, 548, 610, 712, 934
- in /usr/src/usr.sbin/lpr/lpd.c line 375

tdecode defined in line 372; never used
tgetent defined in line 111; used 1 times

- in /usr/src/usr.sbin/lpr/lpq.c line 191

tgetflag defined in line 321; never used
tgetnum defined in line 288; never used
tgetstr defined in line 347; used 3 times

- in /usr/src/usr.sbin/lpr/lpq.c line 54, 193-194(2)

tnamatch defined in line 242; never used
tnchktc defined in line 195; never used
tskip defined in line 268; never used

#### Defined variables

hopcount defined in line 49; used 1 times

- in line 218

sccsid defined in line 8; never used
tbuf defined in line 48; used 15 times

- in line 66, 74, 85-90(2), 121, 200-205(4), 229-232(2), 247, 292, 324, 351

#### Defined macros

BUFSIZ defined in line 11; used 7 times

- in line 90, 117, 155, 170, 199, 227-229(2)

E_TERMCAP defined in line 43; used 5 times

- in line 42, 64, 139, 145-147(2)

MAXHOP defined in line 12; used 1 times

- in line 218

PRINTCAP defined in line 30; used 1 times

- in line 32

V6 defined in line 44; used 1 times

- in line 123

tdecode defined in line 39; used 2 times

- in line 52, 364

tgetent defined in line 33; used 1 times

- in line 222

tgetflag defined in line 38; never used
tgetnum defined in line 37; never used
tgetstr defined in line 35; used 1 times

- in line 51

tnamatch defined in line 41; used 1 times

- in line 181

tnchktc defined in line 40; used 2 times

- in line 137, 183

tskip defined in line 34; used 4 times

- in line 50, 295, 327, 354

Last modified: 1987-02-18 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1831 |