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

Defined functions

tdecode defined in line 299; used 2 times
tgetent defined in line 33; used 4 times
tgetflag defined in line 248; used 1 times
tgetnum defined in line 215; used 1 times
tgetstr defined in line 274; used 6 times
tnamatch defined in line 169; used 1 times
tnchktc defined in line 122; used 2 times
tskip defined in line 195; used 4 times

Defined variables

hopcount defined in line 22; used 1 times
tbuf defined in line 21; used 11 times

Defined macros

BUFSIZ defined in line 2; used 6 times
MAXHOP defined in line 3; used 1 times
Last modified: 1983-08-04
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 974
Valid CSS Valid XHTML 1.0 Strict