386BSD 0.1 development
[unix-history] / usr / src / usr.bin / tip / remcap.c
index a3c7ceb..c573569 100644 (file)
-/*     remcap.c        4.1     81/05/09        */
-/* Copyright (c) 1979 Regents of the University of California */
-#define        BUFSIZ  512
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)remcap.c   5.5 (Berkeley) 2/2/91";
+#endif /* not lint */
 
 
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <fcntl.h>
 #include <ctype.h>
 #include <ctype.h>
+#include "pathnames.h"
+
+#ifndef BUFSIZ
+#define        BUFSIZ          1024
+#endif
+#define MAXHOP         32              /* max number of tc= indirections */
+
+#define        tgetent         rgetent
+#define        tnchktc         rnchktc
+#define        tnamatch        rnamatch
+#define        tgetnum         rgetnum
+#define        tgetflag        rgetflag
+#define        tgetstr         rgetstr
+#define        E_TERMCAP       RM = _PATH_REMOTE
+#define V_TERMCAP      "REMOTE"
+#define V_TERM         "HOST"
+
+char   *RM;
+
 /*
 /*
- * remcap - routines for dealing with the remote host description
- *         data base
+ * termcap - routines for dealing with the terminal capability data base
  *
  * BUG:                Should use a "last" pointer in tbuf, so that searching
  *             for capabilities alphabetically would not be a n**2/2
  *             process when large numbers of capabilities are given.
  *
  * BUG:                Should use a "last" pointer in tbuf, so that searching
  *             for capabilities alphabetically would not be a n**2/2
  *             process when large numbers of capabilities are given.
+ * Note:       If we add a last pointer now we will screw up the
+ *             tc capability. We really should compile termcap.
  *
  * Essentially all the work here is scanning and decoding escapes
  *
  * Essentially all the work here is scanning and decoding escapes
- * in string capabilities.*/
+ * in string capabilities.  We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
 
 
-static char *rbuf;
-char   *rskip();
-char   *rgetstr();
-char   *rdecode();
+static char *tbuf;
+static int hopcount;   /* detect infinite loops in termcap, init 0 */
+char   *tskip();
+char   *tgetstr();
+char   *tdecode();
 char   *getenv();
 char   *getenv();
-char   *RM;            /* remote file */
+static char *remotefile;
 
 /*
 
 /*
- * Get an entry for host name in buffer bp,
- * from the remcap file.  Parse is very rudimentary;
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file.  Parse is very rudimentary;
  * we just notice escaped newlines.
  */
  * we just notice escaped newlines.
  */
-rgetent(bp, name)
+tgetent(bp, name)
        char *bp, *name;
 {
        char *bp, *name;
 {
-       register char *cp;
+       char lbuf[BUFSIZ], *cp, *p;
+       int rc1, rc2;
+
+       remotefile = cp = getenv(V_TERMCAP);
+       if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) {
+               remotefile = cp = _PATH_REMOTE;
+               return (getent(bp, name, cp));
+       } else {
+               if ((rc1 = getent(bp, name, cp)) != 1)
+                       *bp = '\0';
+               remotefile = cp = _PATH_REMOTE;
+               rc2 = getent(lbuf, name, cp);
+               if (rc1 != 1 && rc2 != 1)
+                       return (rc2);
+               if (rc2 == 1) {
+                       p = lbuf;
+                       if (rc1 == 1)
+                               while (*p++ != ':')
+                                       ;
+                       if (strlen(bp) + strlen(p) > BUFSIZ) {
+                               write(2, "Remcap entry too long\n", 23);
+                               return (-1);
+                       }
+                       strcat(bp, p);
+               }
+               tbuf = bp;
+               return (1);
+       }
+}
+
+getent(bp, name, cp)
+       char *bp, *name, *cp;
+{
        register int c;
        register int i = 0, cnt = 0;
        register int c;
        register int i = 0, cnt = 0;
-       char ibuf[BUFSIZ];
+       char ibuf[BUFSIZ], *cp2;
        int tf;
 
        int tf;
 
-       rbuf = bp;
-       if ((RM = getenv("REMOTE")) == (char *)0)
-               RM = "/etc/remote";
-       if ((tf = open(RM, 0)) < 0)
+       tbuf = bp;
+       tf = 0;
+       /*
+        * TERMCAP can have one of two things in it. It can be the
+        * name of a file to use instead of /etc/termcap. In this
+        * case it better start with a "/". Or it can be an entry to
+        * use so we don't have to read the file. In this case it
+        * has to already have the newlines crunched out.
+        */
+       if (cp && *cp) {
+               if (*cp!='/') {
+                       cp2 = getenv(V_TERM);
+                       if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
+                               strcpy(bp,cp);
+                               return (tnchktc());
+                       } else
+                               tf = open(E_TERMCAP, O_RDONLY);
+               } else
+                       tf = open(RM = cp, O_RDONLY);
+       }
+       if (tf == 0)
+               tf = open(E_TERMCAP, O_RDONLY);
+       if (tf < 0)
                return (-1);
        for (;;) {
                cp = bp;
                return (-1);
        for (;;) {
                cp = bp;
@@ -53,38 +167,97 @@ rgetent(bp, name)
                        }
                        c = ibuf[i++];
                        if (c == '\n') {
                        }
                        c = ibuf[i++];
                        if (c == '\n') {
-                               if (cp > bp && cp[-1] == '\\'){
+                               if (cp > bp && cp[-1] == '\\') {
                                        cp--;
                                        continue;
                                }
                                break;
                        }
                                        cp--;
                                        continue;
                                }
                                break;
                        }
-                       *cp++ = c;
+                       if (cp >= bp+BUFSIZ) {
+                               write(2,"Remcap entry too long\n", 23);
+                               break;
+                       } else
+                               *cp++ = c;
                }
                *cp = 0;
 
                /*
                 * The real work for the match.
                 */
                }
                *cp = 0;
 
                /*
                 * The real work for the match.
                 */
-               if (rnamatch(name)) {
+               if (tnamatch(name)) {
                        close(tf);
                        close(tf);
-                       return (1);
+                       return (tnchktc());
                }
        }
 }
 
 /*
                }
        }
 }
 
 /*
- * Rnamatch deals with name matching.  The first field of the remcap
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+       register char *p, *q;
+       char tcname[16];        /* name of similar terminal */
+       char tcbuf[BUFSIZ];
+       char *holdtbuf = tbuf;
+       int l;
+       char *cp;
+
+       p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
+       while (*--p != ':')
+               if (p<tbuf) {
+                       write(2, "Bad remcap entry\n", 18);
+                       return (0);
+               }
+       p++;
+       /* p now points to beginning of last field */
+       if (p[0] != 't' || p[1] != 'c')
+               return (1);
+       strcpy(tcname, p+3);
+       q = tcname;
+       while (*q && *q != ':')
+               q++;
+       *q = 0;
+       if (++hopcount > MAXHOP) {
+               write(2, "Infinite tc= loop\n", 18);
+               return (0);
+       }
+       if (getent(tcbuf, tcname, remotefile) != 1) {
+               if (strcmp(remotefile, _PATH_REMOTE) == 0)
+                       return (0);
+               else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1)
+                       return (0);
+       }
+       for (q = tcbuf; *q++ != ':'; )
+               ;
+       l = p - holdtbuf + strlen(q);
+       if (l > BUFSIZ) {
+               write(2, "Remcap entry too long\n", 23);
+               q[BUFSIZ - (p-holdtbuf)] = 0;
+       }
+       strcpy(p, q);
+       tbuf = holdtbuf;
+       return (1);
+}
+
+/*
+ * Tnamatch deals with name matching.  The first field of the termcap
  * entry is a sequence of names separated by |'s, so we compare
  * against each such name.  The normal : terminator after the last
  * name (before the first field) stops us.
  */
  * entry is a sequence of names separated by |'s, so we compare
  * against each such name.  The normal : terminator after the last
  * name (before the first field) stops us.
  */
-rnamatch(np)
+tnamatch(np)
        char *np;
 {
        register char *Np, *Bp;
 
        char *np;
 {
        register char *Np, *Bp;
 
-       Bp = rbuf;
+       Bp = tbuf;
+       if (*Bp == '#')
+               return (0);
        for (;;) {
                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
                        continue;
        for (;;) {
                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
                        continue;
@@ -101,10 +274,10 @@ rnamatch(np)
 /*
  * Skip to the next field.  Notice that this is very dumb, not
  * knowing about \: escapes or any such.  If necessary, :'s can be put
 /*
  * Skip to the next field.  Notice that this is very dumb, not
  * knowing about \: escapes or any such.  If necessary, :'s can be put
- * into the printcap file in octal.
+ * into the termcap file in octal.
  */
 static char *
  */
 static char *
-rskip(bp)
+tskip(bp)
        register char *bp;
 {
 
        register char *bp;
 {
 
@@ -123,18 +296,20 @@ rskip(bp)
  * a # character.  If the option is not found we return -1.
  * Note that we handle octal numbers beginning with 0.
  */
  * a # character.  If the option is not found we return -1.
  * Note that we handle octal numbers beginning with 0.
  */
-rgetnum(id)
+tgetnum(id)
        char *id;
 {
        register int i, base;
        char *id;
 {
        register int i, base;
-       register char *bp = rbuf;
+       register char *bp = tbuf;
 
        for (;;) {
 
        for (;;) {
-               bp = rskip(bp);
+               bp = tskip(bp);
                if (*bp == 0)
                        return (-1);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
                if (*bp == 0)
                        return (-1);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
+               if (*bp == '@')
+                       return (-1);
                if (*bp != '#')
                        continue;
                bp++;
                if (*bp != '#')
                        continue;
                bp++;
@@ -154,17 +329,21 @@ rgetnum(id)
  * of the buffer.  Return 1 if we find the option, or 0 if it is
  * not given.
  */
  * of the buffer.  Return 1 if we find the option, or 0 if it is
  * not given.
  */
-rgetflag(id)
+tgetflag(id)
        char *id;
 {
        char *id;
 {
-       register char *bp = rbuf;
+       register char *bp = tbuf;
 
        for (;;) {
 
        for (;;) {
-               bp = rskip(bp);
+               bp = tskip(bp);
                if (!*bp)
                        return (0);
                if (!*bp)
                        return (0);
-               if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1] && (!*bp || *bp == ':'))
-                       return (1);
+               if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+                       if (!*bp || *bp == ':')
+                               return (1);
+                       else if (*bp == '@')
+                               return (0);
+               }
        }
 }
 
        }
 }
 
@@ -177,21 +356,23 @@ rgetflag(id)
  * No checking on area overflow.
  */
 char *
  * No checking on area overflow.
  */
 char *
-rgetstr(id, area)
+tgetstr(id, area)
        char *id, **area;
 {
        char *id, **area;
 {
-       register char *bp = rbuf;
+       register char *bp = tbuf;
 
        for (;;) {
 
        for (;;) {
-               bp = rskip(bp);
+               bp = tskip(bp);
                if (!*bp)
                        return (0);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
                if (!*bp)
                        return (0);
                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
                        continue;
+               if (*bp == '@')
+                       return (0);
                if (*bp != '=')
                        continue;
                bp++;
                if (*bp != '=')
                        continue;
                bp++;
-               return (rdecode(bp, area));
+               return (tdecode(bp, area));
        }
 }
 
        }
 }
 
@@ -199,8 +380,8 @@ rgetstr(id, area)
  * Tdecode does the grung work to decode the
  * string capability escapes.
  */
  * Tdecode does the grung work to decode the
  * string capability escapes.
  */
-char *
-rdecode(str, area)
+static char *
+tdecode(str, area)
        register char *str;
        char **area;
 {
        register char *str;
        char **area;
 {