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