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
getprent defined in line 59; used 11 times
tdecode defined in line 372; never used
tgetent defined in line 111; used 1 times
tgetflag defined in line 321; never used
tgetnum defined in line 288; never used
tgetstr defined in line 347; used 3 times
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
sccsid defined in line 8; never used
tbuf defined in line 48; used 15 times

Defined macros

BUFSIZ defined in line 11; used 7 times
E_TERMCAP defined in line 43; used 5 times
MAXHOP defined in line 12; used 1 times
PRINTCAP defined in line 30; used 1 times
  • in line 32
V6 defined in line 44; used 1 times
tdecode defined in line 39; used 2 times
tgetent defined in line 33; used 1 times
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
tnchktc defined in line 40; used 2 times
tskip defined in line 34; used 4 times
Last modified: 1987-02-18
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4057
Valid CSS Valid XHTML 1.0 Strict