BSD 4_4 release
[unix-history] / usr / src / lib / libterm / termcap.c
index e29f96c..708ccfa 100644 (file)
@@ -1,12 +1,49 @@
+/*
+ * Copyright (c) 1980, 1993
+ *     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
 #ifndef lint
-static char sccsid[] = "@(#)termcap.c  4.2 (Berkeley) %G%";
-#endif
+static char sccsid[] = "@(#)termcap.c  8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
 
 
-#define        BUFSIZ          1024
-#define MAXHOP         32      /* max number of tc= indirections */
-#define        E_TERMCAP       "/etc/termcap"
+#define        PBUFSIZ         512     /* max length of filename path */
+#define        PVECSIZ         32      /* max number of names in path */
 
 
+#include <stdio.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pathnames.h"
+
 /*
  * termcap - routines for dealing with the terminal capability data base
  *
 /*
  * termcap - routines for dealing with the terminal capability data base
  *
@@ -21,185 +58,87 @@ static char sccsid[] = "@(#)termcap.c      4.2 (Berkeley) %G%";
  * doesn't, and because living w/o it is not hard.
  */
 
  * doesn't, and because living w/o it is not hard.
  */
 
-static char *tbuf;
-static int hopcount;   /* detect infinite loops in termcap, init 0 */
-char   *tskip();
-char   *tgetstr();
-char   *tdecode();
-char   *getenv();
+static char *tbuf;     /* termcap buffer */
 
 /*
 
 /*
- * Get an entry for terminal name in buffer bp,
- * from the termcap file.  Parse is very rudimentary;
- * we just notice escaped newlines.
+ * Get an entry for terminal name in buffer bp from the termcap file.
  */
  */
+int
 tgetent(bp, name)
        char *bp, *name;
 {
 tgetent(bp, name)
        char *bp, *name;
 {
+       register char *p;
        register char *cp;
        register char *cp;
-       register int c;
-       register int i = 0, cnt = 0;
-       char ibuf[BUFSIZ];
-       char *cp2;
-       int tf;
-
+       char  *dummy;
+       char **fname;
+       char  *home;
+       int    i;
+       char   pathbuf[PBUFSIZ];        /* holds raw path of filenames */
+       char  *pathvec[PVECSIZ];        /* to point to names in pathbuf */
+       char **pvec;                    /* holds usable tail of path vector */
+       char  *termpath;
+
+       fname = pathvec;
+       pvec = pathvec;
        tbuf = bp;
        tbuf = bp;
-       tf = 0;
-#ifndef V6
+       p = pathbuf;
        cp = getenv("TERMCAP");
        /*
         * 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
        cp = getenv("TERMCAP");
        /*
         * 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.
+        * has to already have the newlines crunched out.  If TERMCAP
+        * does not hold a file name then a path of names is searched
+        * instead.  The path is found in the TERMPATH variable, or
+        * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
         */
         */
-       if (cp && *cp) {
-               if (*cp!='/') {
-                       cp2 = getenv("TERM");
-                       if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
-                               strcpy(bp,cp);
-                               return(tnchktc());
-                       } else {
-                               tf = open(E_TERMCAP, 0);
-                       }
-               } else
-                       tf = open(cp, 0);
+       if (!cp || *cp != '/') {        /* no TERMCAP or it holds an entry */
+               if (termpath = getenv("TERMPATH"))
+                       strncpy(pathbuf, termpath, PBUFSIZ);
+               else {
+                       if (home = getenv("HOME")) {    /* set up default */
+                               p += strlen(home);      /* path, looking in */
+                               strcpy(pathbuf, home);  /* $HOME first */
+                               *p++ = '/';
+                       }       /* if no $HOME look in current directory */
+                       strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));
+               }
        }
        }
-       if (tf==0)
-               tf = open(E_TERMCAP, 0);
-#else
-       tf = open(E_TERMCAP, 0);
-#endif
-       if (tf < 0)
-               return (-1);
-       for (;;) {
-               cp = bp;
-               for (;;) {
-                       if (i == cnt) {
-                               cnt = read(tf, ibuf, BUFSIZ);
-                               if (cnt <= 0) {
-                                       close(tf);
-                                       return (0);
-                               }
-                               i = 0;
-                       }
-                       c = ibuf[i++];
-                       if (c == '\n') {
-                               if (cp > bp && cp[-1] == '\\'){
-                                       cp--;
-                                       continue;
-                               }
+       else                            /* user-defined name in TERMCAP */
+               strncpy(pathbuf, cp, PBUFSIZ);  /* still can be tokenized */
+
+       *fname++ = pathbuf;     /* tokenize path into vector of names */
+       while (*++p)
+               if (*p == ' ' || *p == ':') {
+                       *p = '\0';
+                       while (*++p)
+                               if (*p != ' ' && *p != ':')
+                                       break;
+                       if (*p == '\0')
                                break;
                                break;
-                       }
-                       if (cp >= bp+BUFSIZ) {
-                               write(2,"Termcap entry too long\n", 23);
+                       *fname++ = p;
+                       if (fname >= pathvec + PVECSIZ) {
+                               fname--;
                                break;
                                break;
-                       } else
-                               *cp++ = c;
-               }
-               *cp = 0;
-
-               /*
-                * The real work for the match.
-                */
-               if (tnamatch(name)) {
-                       close(tf);
-                       return(tnchktc());
-               }
-       }
-}
-
-/*
- * 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;
-
-       p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
-       while (*--p != ':')
-               if (p<tbuf) {
-                       write(2, "Bad termcap 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 (tgetent(tcbuf, tcname) != 1)
-               return(0);
-       for (q=tcbuf; *q != ':'; q++)
-               ;
-       l = p - holdtbuf + strlen(q);
-       if (l > BUFSIZ) {
-               write(2, "Termcap entry too long\n", 23);
-               q[BUFSIZ - (p-tbuf)] = 0;
-       }
-       strcpy(p, q+1);
-       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.
- */
-tnamatch(np)
-       char *np;
-{
-       register char *Np, *Bp;
-
-       Bp = tbuf;
-       if (*Bp == '#')
-               return(0);
-       for (;;) {
-               for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
-                       continue;
-               if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
-                       return (1);
-               while (*Bp && *Bp != ':' && *Bp != '|')
-                       Bp++;
-               if (*Bp == 0 || *Bp == ':')
-                       return (0);
-               Bp++;
-       }
-}
-
-/*
- * 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 termcap file in octal.
- */
-static char *
-tskip(bp)
-       register char *bp;
-{
-
-       while (*bp && *bp != ':')
-               bp++;
-       if (*bp == ':')
-               bp++;
-       return (bp);
+       *fname = (char *) 0;                    /* mark end of vector */
+       if (cp && *cp && *cp != '/')
+               if (cgetset(cp) < 0)
+                       return(-2);
+
+       i = cgetent(&dummy, pathvec, name);      
+       
+       if (i == 0)
+               strcpy(bp, dummy);
+       
+       if (dummy)
+               free(dummy);
+       /* no tc reference loop return code in libterm XXX */
+       if (i == -3)
+               return(-1);
+       return(i + 1);
 }
 
 /*
 }
 
 /*
@@ -210,31 +149,16 @@ tskip(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.
  */
+int
 tgetnum(id)
        char *id;
 {
 tgetnum(id)
        char *id;
 {
-       register int i, base;
-       register char *bp = tbuf;
+       long num;
 
 
-       for (;;) {
-               bp = tskip(bp);
-               if (*bp == 0)
-                       return (-1);
-               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
-                       continue;
-               if (*bp == '@')
-                       return(-1);
-               if (*bp != '#')
-                       continue;
-               bp++;
-               base = 10;
-               if (*bp == '0')
-                       base = 8;
-               i = 0;
-               while (isdigit(*bp))
-                       i *= base, i += *bp++ - '0';
-               return (i);
-       }
+       if (cgetnum(tbuf, id, &num) == 0)
+               return(num);
+       else
+               return(-1);
 }
 
 /*
 }
 
 /*
@@ -243,22 +167,11 @@ tgetnum(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.
  */
+int
 tgetflag(id)
        char *id;
 {
 tgetflag(id)
        char *id;
 {
-       register char *bp = tbuf;
-
-       for (;;) {
-               bp = tskip(bp);
-               if (!*bp)
-                       return (0);
-               if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
-                       if (!*bp || *bp == ':')
-                               return (1);
-                       else if (*bp == '@')
-                               return(0);
-               }
-       }
+       return(cgetcap(tbuf, id, ':') != NULL);
 }
 
 /*
 }
 
 /*
@@ -273,68 +186,23 @@ char *
 tgetstr(id, area)
        char *id, **area;
 {
 tgetstr(id, area)
        char *id, **area;
 {
-       register char *bp = tbuf;
-
-       for (;;) {
-               bp = tskip(bp);
-               if (!*bp)
-                       return (0);
-               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
-                       continue;
-               if (*bp == '@')
-                       return(0);
-               if (*bp != '=')
-                       continue;
-               bp++;
-               return (tdecode(bp, area));
-       }
-}
-
-/*
- * Tdecode does the grung work to decode the
- * string capability escapes.
- */
-static char *
-tdecode(str, area)
-       register char *str;
-       char **area;
-{
-       register char *cp;
-       register int c;
-       register char *dp;
+       char ids[3];
+       char *s;
        int i;
        int i;
-
-       cp = *area;
-       while ((c = *str++) && c != ':') {
-               switch (c) {
-
-               case '^':
-                       c = *str++ & 037;
-                       break;
-
-               case '\\':
-                       dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
-                       c = *str++;
-nextc:
-                       if (*dp++ == c) {
-                               c = *dp++;
-                               break;
-                       }
-                       dp++;
-                       if (*dp)
-                               goto nextc;
-                       if (isdigit(c)) {
-                               c -= '0', i = 2;
-                               do
-                                       c <<= 3, c |= *str++ - '0';
-                               while (--i && isdigit(*str));
-                       }
-                       break;
-               }
-               *cp++ = c;
-       }
-       *cp++ = 0;
-       str = *area;
-       *area = cp;
-       return (str);
+       
+       /*
+        * XXX
+        * This is for all the boneheaded programs that relied on tgetstr
+        * to look only at the first 2 characters of the string passed...
+        */
+       *ids = *id;
+       ids[1] = id[1];
+       ids[2] = '\0';
+
+       if ((i = cgetstr(tbuf, ids, &s)) < 0)
+               return NULL;
+       
+       strcpy(*area, s);
+       *area += i + 1;
+       return(s);
 }
 }