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

Defined functions

getent defined in line 97; used 5 times
tdecode defined in line 355; used 2 times
tgetent defined in line 64; never used
tgetflag defined in line 304; never used
tgetnum defined in line 271; never used
tgetstr defined in line 330; never used
tnamatch defined in line 225; never used
tnchktc defined in line 173; never used
tskip defined in line 251; used 4 times

Defined variables

RM defined in line 35; used 2 times
hopcount defined in line 52; used 1 times
remotefile defined in line 57; used 5 times
sccsid defined in line 8; never used
tbuf defined in line 51; used 11 times

Defined macros

BUFSIZ defined in line 20; used 9 times
E_TERMCAP defined in line 31; used 2 times
MAXHOP defined in line 22; used 1 times
SYSREMOTE defined in line 23; used 6 times
V_TERM defined in line 33; used 1 times
V_TERMCAP defined in line 32; used 1 times
  • in line 70
tgetent defined in line 25; never used
tgetflag defined in line 29; never used
tgetnum defined in line 28; never used
tgetstr defined in line 30; used 1 times
  • in line 54
tnamatch defined in line 27; used 1 times
tnchktc defined in line 26; used 2 times
Last modified: 1985-04-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1730
Valid CSS Valid XHTML 1.0 Strict