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