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