1*13278Ssam #ifndef lint 2*13278Ssam static char sccsid[] = "@(#)remcap.c 4.8 (Berkeley) 06/25/83"; 34003Ssam #endif 43694Sroot 53694Sroot /* 63805Ssam * remcap - routines for dealing with the remote host data base 73694Sroot * 8*13278Ssam * derived from termcap 93805Ssam */ 10*13278Ssam #include <sys/file.h> 11*13278Ssam #include <ctype.h> 123805Ssam 13*13278Ssam #ifndef BUFSIZ 14*13278Ssam #define BUFSIZ 1024 15*13278Ssam #endif 16*13278Ssam #define MAXHOP 32 /* max number of tc= indirections */ 17*13278Ssam #define SYSREMOTE "/etc/remote" /* system remote file */ 18*13278Ssam 193805Ssam #define tgetent rgetent 203805Ssam #define tnchktc rnchktc 213805Ssam #define tnamatch rnamatch 223805Ssam #define tgetnum rgetnum 233805Ssam #define tgetflag rgetflag 243805Ssam #define tgetstr rgetstr 2513138Sralph #define E_TERMCAP RM = SYSREMOTE 263808Ssam #define V_TERMCAP "REMOTE" 273808Ssam #define V_TERM "HOST" 283808Ssam 293805Ssam char *RM; 303805Ssam 313805Ssam /* 323805Ssam * termcap - routines for dealing with the terminal capability data base 333805Ssam * 343694Sroot * BUG: Should use a "last" pointer in tbuf, so that searching 353694Sroot * for capabilities alphabetically would not be a n**2/2 363694Sroot * process when large numbers of capabilities are given. 373805Ssam * Note: If we add a last pointer now we will screw up the 383805Ssam * tc capability. We really should compile termcap. 393694Sroot * 403694Sroot * Essentially all the work here is scanning and decoding escapes 413805Ssam * in string capabilities. We don't use stdio because the editor 423805Ssam * doesn't, and because living w/o it is not hard. 433805Ssam */ 443694Sroot 453805Ssam static char *tbuf; 463805Ssam static int hopcount; /* detect infinite loops in termcap, init 0 */ 473805Ssam char *tskip(); 483805Ssam char *tgetstr(); 493805Ssam char *tdecode(); 503694Sroot char *getenv(); 51*13278Ssam static char *remotefile; 523694Sroot 533694Sroot /* 543805Ssam * Get an entry for terminal name in buffer bp, 553805Ssam * from the termcap file. Parse is very rudimentary; 563694Sroot * we just notice escaped newlines. 573694Sroot */ 583805Ssam tgetent(bp, name) 593694Sroot char *bp, *name; 603694Sroot { 61*13278Ssam char lbuf[BUFSIZ], *cp, *p; 62*13278Ssam int rc1, rc2; 6313138Sralph 6413138Sralph remotefile = cp = getenv(V_TERMCAP); 6513138Sralph if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) { 6613138Sralph remotefile = cp = SYSREMOTE; 67*13278Ssam return (getent(bp, name, cp)); 6813138Sralph } else { 6913138Sralph if ((rc1 = getent(bp, name, cp)) != 1) 7013138Sralph *bp = '\0'; 7113138Sralph remotefile = cp = SYSREMOTE; 7213138Sralph rc2 = getent(lbuf, name, cp); 7313138Sralph if (rc1 != 1 && rc2 != 1) 74*13278Ssam return (rc2); 7513138Sralph if (rc2 == 1) { 7613138Sralph p = lbuf; 7713138Sralph if (rc1 == 1) 7813138Sralph while (*p++ != ':') 7913138Sralph ; 8013138Sralph if (strlen(bp) + strlen(p) > BUFSIZ) { 8113138Sralph write(2, "Remcap entry too long\n", 23); 82*13278Ssam return (-1); 8313138Sralph } 8413138Sralph strcat(bp, p); 8513138Sralph } 8613138Sralph tbuf = bp; 87*13278Ssam return (1); 8813138Sralph } 8913138Sralph } 9013138Sralph 9113138Sralph getent(bp, name, cp) 9213138Sralph char *bp, *name, *cp; 9313138Sralph { 943694Sroot register int c; 953694Sroot register int i = 0, cnt = 0; 96*13278Ssam char ibuf[BUFSIZ], *cp2; 973694Sroot int tf; 983694Sroot 993805Ssam tbuf = bp; 1003805Ssam tf = 0; 1013805Ssam /* 1023805Ssam * TERMCAP can have one of two things in it. It can be the 1033805Ssam * name of a file to use instead of /etc/termcap. In this 1043805Ssam * case it better start with a "/". Or it can be an entry to 1053805Ssam * use so we don't have to read the file. In this case it 1063805Ssam * has to already have the newlines crunched out. 1073805Ssam */ 1083805Ssam if (cp && *cp) { 1093805Ssam if (*cp!='/') { 1103808Ssam cp2 = getenv(V_TERM); 111*13278Ssam if (cp2 == (char *)0 || strcmp(name,cp2) == 0) { 1123805Ssam strcpy(bp,cp); 113*13278Ssam return (tnchktc()); 114*13278Ssam } else 115*13278Ssam tf = open(E_TERMCAP, O_RDONLY); 1163805Ssam } else 117*13278Ssam tf = open(RM = cp, O_RDONLY); 1183805Ssam } 119*13278Ssam if (tf == 0) 120*13278Ssam tf = open(E_TERMCAP, O_RDONLY); 1213805Ssam if (tf < 0) 1223694Sroot return (-1); 1233694Sroot for (;;) { 1243694Sroot cp = bp; 1253694Sroot for (;;) { 1263694Sroot if (i == cnt) { 1273694Sroot cnt = read(tf, ibuf, BUFSIZ); 1283694Sroot if (cnt <= 0) { 1293694Sroot close(tf); 1303694Sroot return (0); 1313694Sroot } 1323694Sroot i = 0; 1333694Sroot } 1343694Sroot c = ibuf[i++]; 1353694Sroot if (c == '\n') { 13613138Sralph if (cp > bp && cp[-1] == '\\') { 1373694Sroot cp--; 1383694Sroot continue; 1393694Sroot } 1403694Sroot break; 1413694Sroot } 1423805Ssam if (cp >= bp+BUFSIZ) { 14313138Sralph write(2,"Remcap entry too long\n", 23); 1443805Ssam break; 1453805Ssam } else 1463805Ssam *cp++ = c; 1473694Sroot } 1483694Sroot *cp = 0; 1493694Sroot 1503694Sroot /* 1513694Sroot * The real work for the match. 1523694Sroot */ 1533805Ssam if (tnamatch(name)) { 1543694Sroot close(tf); 155*13278Ssam return (tnchktc()); 1563694Sroot } 1573694Sroot } 1583694Sroot } 1593694Sroot 1603694Sroot /* 1613805Ssam * tnchktc: check the last entry, see if it's tc=xxx. If so, 1623805Ssam * recursively find xxx and append that entry (minus the names) 1633805Ssam * to take the place of the tc=xxx entry. This allows termcap 1643805Ssam * entries to say "like an HP2621 but doesn't turn on the labels". 1653805Ssam * Note that this works because of the left to right scan. 1663805Ssam */ 1673805Ssam tnchktc() 1683805Ssam { 1693805Ssam register char *p, *q; 1703805Ssam char tcname[16]; /* name of similar terminal */ 1713805Ssam char tcbuf[BUFSIZ]; 1723805Ssam char *holdtbuf = tbuf; 1733805Ssam int l; 17413138Sralph char *cp; 1753805Ssam 1763805Ssam p = tbuf + strlen(tbuf) - 2; /* before the last colon */ 1773805Ssam while (*--p != ':') 1783805Ssam if (p<tbuf) { 17913138Sralph write(2, "Bad remcap entry\n", 18); 1803805Ssam return (0); 1813805Ssam } 1823805Ssam p++; 1833805Ssam /* p now points to beginning of last field */ 1843805Ssam if (p[0] != 't' || p[1] != 'c') 185*13278Ssam return (1); 18613138Sralph strcpy(tcname, p+3); 1873805Ssam q = tcname; 18813138Sralph while (*q && *q != ':') 1893805Ssam q++; 1903805Ssam *q = 0; 1913805Ssam if (++hopcount > MAXHOP) { 1923805Ssam write(2, "Infinite tc= loop\n", 18); 1933805Ssam return (0); 1943805Ssam } 19513138Sralph if (getent(tcbuf, tcname, remotefile) != 1) { 19613138Sralph if (strcmp(remotefile, SYSREMOTE) == 0) 197*13278Ssam return (0); 19813138Sralph else if (getent(tcbuf, tcname, SYSREMOTE) != 1) 199*13278Ssam return (0); 20013138Sralph } 20113138Sralph for (q = tcbuf; *q++ != ':'; ) 2023805Ssam ; 2033805Ssam l = p - holdtbuf + strlen(q); 2043805Ssam if (l > BUFSIZ) { 20513138Sralph write(2, "Remcap entry too long\n", 23); 20613138Sralph q[BUFSIZ - (p-holdtbuf)] = 0; 2073805Ssam } 20813138Sralph strcpy(p, q); 2093805Ssam tbuf = holdtbuf; 210*13278Ssam return (1); 2113805Ssam } 2123805Ssam 2133805Ssam /* 2143805Ssam * Tnamatch deals with name matching. The first field of the termcap 2153694Sroot * entry is a sequence of names separated by |'s, so we compare 2163694Sroot * against each such name. The normal : terminator after the last 2173694Sroot * name (before the first field) stops us. 2183694Sroot */ 2193805Ssam tnamatch(np) 2203694Sroot char *np; 2213694Sroot { 2223694Sroot register char *Np, *Bp; 2233694Sroot 2243805Ssam Bp = tbuf; 2253805Ssam if (*Bp == '#') 226*13278Ssam return (0); 2273694Sroot for (;;) { 2283694Sroot for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 2293694Sroot continue; 2303694Sroot if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 2313694Sroot return (1); 2323694Sroot while (*Bp && *Bp != ':' && *Bp != '|') 2333694Sroot Bp++; 2343694Sroot if (*Bp == 0 || *Bp == ':') 2353694Sroot return (0); 2363694Sroot Bp++; 2373694Sroot } 2383694Sroot } 2393694Sroot 2403694Sroot /* 2413694Sroot * Skip to the next field. Notice that this is very dumb, not 2423694Sroot * knowing about \: escapes or any such. If necessary, :'s can be put 2433805Ssam * into the termcap file in octal. 2443694Sroot */ 2453694Sroot static char * 2463805Ssam tskip(bp) 2473694Sroot register char *bp; 2483694Sroot { 2493694Sroot 2503694Sroot while (*bp && *bp != ':') 2513694Sroot bp++; 2523694Sroot if (*bp == ':') 2533694Sroot bp++; 2543694Sroot return (bp); 2553694Sroot } 2563694Sroot 2573694Sroot /* 2583694Sroot * Return the (numeric) option id. 2593694Sroot * Numeric options look like 2603694Sroot * li#80 2613694Sroot * i.e. the option string is separated from the numeric value by 2623694Sroot * a # character. If the option is not found we return -1. 2633694Sroot * Note that we handle octal numbers beginning with 0. 2643694Sroot */ 2653805Ssam tgetnum(id) 2663694Sroot char *id; 2673694Sroot { 2683694Sroot register int i, base; 2693805Ssam register char *bp = tbuf; 2703694Sroot 2713694Sroot for (;;) { 2723805Ssam bp = tskip(bp); 2733694Sroot if (*bp == 0) 2743694Sroot return (-1); 2753694Sroot if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 2763694Sroot continue; 2773805Ssam if (*bp == '@') 278*13278Ssam return (-1); 2793694Sroot if (*bp != '#') 2803694Sroot continue; 2813694Sroot bp++; 2823694Sroot base = 10; 2833694Sroot if (*bp == '0') 2843694Sroot base = 8; 2853694Sroot i = 0; 2863694Sroot while (isdigit(*bp)) 2873694Sroot i *= base, i += *bp++ - '0'; 2883694Sroot return (i); 2893694Sroot } 2903694Sroot } 2913694Sroot 2923694Sroot /* 2933694Sroot * Handle a flag option. 2943694Sroot * Flag options are given "naked", i.e. followed by a : or the end 2953694Sroot * of the buffer. Return 1 if we find the option, or 0 if it is 2963694Sroot * not given. 2973694Sroot */ 2983805Ssam tgetflag(id) 2993694Sroot char *id; 3003694Sroot { 3013805Ssam register char *bp = tbuf; 3023694Sroot 3033694Sroot for (;;) { 3043805Ssam bp = tskip(bp); 3053694Sroot if (!*bp) 3063694Sroot return (0); 3073805Ssam if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 3083805Ssam if (!*bp || *bp == ':') 3093805Ssam return (1); 3103805Ssam else if (*bp == '@') 311*13278Ssam return (0); 3123805Ssam } 3133694Sroot } 3143694Sroot } 3153694Sroot 3163694Sroot /* 3173694Sroot * Get a string valued option. 3183694Sroot * These are given as 3193694Sroot * cl=^Z 3203694Sroot * Much decoding is done on the strings, and the strings are 3213694Sroot * placed in area, which is a ref parameter which is updated. 3223694Sroot * No checking on area overflow. 3233694Sroot */ 3243694Sroot char * 3253805Ssam tgetstr(id, area) 3263694Sroot char *id, **area; 3273694Sroot { 3283805Ssam register char *bp = tbuf; 3293694Sroot 3303694Sroot for (;;) { 3313805Ssam bp = tskip(bp); 3323694Sroot if (!*bp) 3333694Sroot return (0); 3343694Sroot if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 3353694Sroot continue; 3363805Ssam if (*bp == '@') 337*13278Ssam return (0); 3383694Sroot if (*bp != '=') 3393694Sroot continue; 3403694Sroot bp++; 3413805Ssam return (tdecode(bp, area)); 3423694Sroot } 3433694Sroot } 3443694Sroot 3453694Sroot /* 3463694Sroot * Tdecode does the grung work to decode the 3473694Sroot * string capability escapes. 3483694Sroot */ 3493805Ssam static char * 3503805Ssam tdecode(str, area) 3513694Sroot register char *str; 3523694Sroot char **area; 3533694Sroot { 3543694Sroot register char *cp; 3553694Sroot register int c; 3563694Sroot register char *dp; 3573694Sroot int i; 3583694Sroot 3593694Sroot cp = *area; 3603694Sroot while ((c = *str++) && c != ':') { 3613694Sroot switch (c) { 3623694Sroot 3633694Sroot case '^': 3643694Sroot c = *str++ & 037; 3653694Sroot break; 3663694Sroot 3673694Sroot case '\\': 3683694Sroot dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 3693694Sroot c = *str++; 3703694Sroot nextc: 3713694Sroot if (*dp++ == c) { 3723694Sroot c = *dp++; 3733694Sroot break; 3743694Sroot } 3753694Sroot dp++; 3763694Sroot if (*dp) 3773694Sroot goto nextc; 3783694Sroot if (isdigit(c)) { 3793694Sroot c -= '0', i = 2; 3803694Sroot do 3813694Sroot c <<= 3, c |= *str++ - '0'; 3823694Sroot while (--i && isdigit(*str)); 3833694Sroot } 3843694Sroot break; 3853694Sroot } 3863694Sroot *cp++ = c; 3873694Sroot } 3883694Sroot *cp++ = 0; 3893694Sroot str = *area; 3903694Sroot *area = cp; 3913694Sroot return (str); 3923694Sroot } 393