# 2.11BSD#431 - /usr/src/usr.bin/tip/remcap.c

##### Functions

    getent            X
    tgetent           X
    tgetflag          X
    tgetnum           X
    tgetstr           X
    tnamatch          X
    tnchktc           X

##### Variables

    RM                X

##### Macros

    BUFSIZ            X
    E_TERMCAP         X
    MAXHOP            X
    SYSREMOTE         X
    V_TERM            X
    V_TERMCAP         X
    tgetent           X
    tgetflag          X
    tgetnum           X
    tgetstr           X
    tnamatch          X
    tnchktc           X

       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: #if !defined(lint) && defined(DOSCCS)
       8: static char sccsid[] = "@(#)remcap.c	5.1.1 (2.11BSD) 1997/5/2";
       9: #endif
      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:     while (*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: }

#### Defined functions

getent defined in line 97; used 5 times

- in line 73-78(3), 201-204(2)

tdecode defined in line 355; used 2 times

- in line 55, 347

tgetent defined in line 64; never used
tgetflag defined in line 304; never used
tgetnum defined in line 271; never used
tgetstr defined in line 330; never used
tnamatch defined in line 225; never used
tnchktc defined in line 173; never used
tskip defined in line 251; used 4 times

- in line 53, 278, 310, 337

#### Defined variables

RM defined in line 35; used 2 times

- in line 31, 123

hopcount defined in line 52; used 1 times

- in line 197

remotefile defined in line 57; used 5 times

- in line 70-77(3), 201-202(2)

sccsid defined in line 8; never used
tbuf defined in line 51; used 11 times

- in line 92, 105, 178-184(4), 215, 230, 275, 307, 334

#### Defined macros

BUFSIZ defined in line 20; used 9 times

- in line 19, 67, 86, 102, 133, 148, 177, 210-212(2)

E_TERMCAP defined in line 31; used 2 times

- in line 121-126(2)

MAXHOP defined in line 22; used 1 times

- in line 197

SYSREMOTE defined in line 23; used 6 times

- in line 31, 71-77(3), 202-204(2)

V_TERM defined in line 33; used 1 times

- in line 116

V_TERMCAP defined in line 32; used 1 times

- in line 70

tgetent defined in line 25; never used
tgetflag defined in line 29; never used
tgetnum defined in line 28; never used
tgetstr defined in line 30; used 1 times

- in line 54

tnamatch defined in line 27; used 1 times

- in line 159

tnchktc defined in line 26; used 2 times

- in line 119, 161

Last modified: 1997-05-02 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1786 |