|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.