[BACK]Return to termcap.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libterm

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libterm/Attic/termcap.c between version 1.6 and 1.39

version 1.6, 1995/02/27 10:18:54 version 1.39, 2001/10/31 21:52:17
Line 33 
Line 33 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
   #include <sys/cdefs.h>
 #ifndef lint  #ifndef lint
 #if 0  #if 0
 static char sccsid[] = "@(#)termcap.c   8.1 (Berkeley) 6/4/93";  static char sccsid[] = "@(#)termcap.c   8.1 (Berkeley) 6/4/93";
 #else  #else
 static char rcsid[] = "$NetBSD$";  __RCSID("$NetBSD$");
 #endif  #endif
 #endif /* not lint */  #endif /* not lint */
   
 #define PBUFSIZ         512     /* max length of filename path */  
 #define PVECSIZ         32      /* max number of names in path */  
   
 #include <stdio.h>  #include <sys/types.h>
   #include <sys/param.h>
   #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
   #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   #include <termcap.h>
   #include <errno.h>
 #include "pathnames.h"  #include "pathnames.h"
   #include "termcap_private.h"
   
   #define PBUFSIZ         MAXPATHLEN      /* max length of filename path */
   #define PVECSIZ         32              /* max number of names in path */
   
 /*  /*
  * termcap - routines for dealing with the terminal capability data base   * termcap - routines for dealing with the terminal capability data base
Line 65  static char rcsid[] = "$NetBSD$";
Line 73  static char rcsid[] = "$NetBSD$";
  */   */
   
 static  char *tbuf;     /* termcap buffer */  static  char *tbuf;     /* termcap buffer */
   static  struct tinfo *fbuf;     /* untruncated termcap buffer */
   
 /*  /*
  * Get an entry for terminal name in buffer bp from the termcap file.   * Set the termcap entry to the arbitrary string passed in, this can
    * be used to provide a "dummy" termcap entry if a real one does not
    * exist.  This function will malloc the buffer and space for the
    * string.  If an error occurs return -1 otherwise return 0.
  */   */
 int  int
 tgetent(bp, name)  t_setinfo(struct tinfo **bp, const char *entry)
         char *bp, *name;  
 {  {
         register char *p;          char capability[256], *cap_ptr;
         register char *cp;          size_t limit;
         char  *dummy;  
           _DIAGASSERT(bp != NULL);
           _DIAGASSERT(entry != NULL);
   
           if ((*bp = malloc(sizeof(struct tinfo))) == NULL)
                   return -1;
   
           if (((*bp)->info = (char *) malloc(strlen(entry) + 1)) == NULL)
                   return -1;
   
           strcpy((*bp)->info, entry);
   
           cap_ptr = capability;
           limit = 255;
           (*bp)->up = t_getstr(*bp, "up", &cap_ptr, &limit);
           if ((*bp)->up)
                   (*bp)->up = strdup((*bp)->up);
           cap_ptr = capability;
           limit = 255;
           (*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit);
           if ((*bp)->bc)
                   (*bp)->bc = strdup((*bp)->bc);
   
           return 0;
   }
   
   /*
    * Get an extended entry for the terminal name.  This differs from
    * tgetent only in a) the buffer is malloc'ed for the caller and
    * b) the termcap entry is not truncated to 1023 characters.
    */
   
   int
   t_getent(bp, name)
           struct tinfo **bp;
           const char *name;
   {
           char  *p;
           char  *cp;
         char **fname;          char **fname;
         char  *home;          char  *home;
         int    i;          int    i, did_getset;
           size_t limit;
         char   pathbuf[PBUFSIZ];        /* holds raw path of filenames */          char   pathbuf[PBUFSIZ];        /* holds raw path of filenames */
         char  *pathvec[PVECSIZ];        /* to point to names in pathbuf */          char  *pathvec[PVECSIZ];        /* to point to names in pathbuf */
         char **pvec;                    /* holds usable tail of path vector */  
         char  *termpath;          char  *termpath;
           char  capability[256], *cap_ptr;
   
   
           _DIAGASSERT(bp != NULL);
           _DIAGASSERT(name != NULL);
   
           if ((*bp = malloc(sizeof(struct tinfo))) == NULL) return 0;
   
         fname = pathvec;          fname = pathvec;
         pvec = pathvec;  
         tbuf = bp;  
         p = pathbuf;          p = pathbuf;
         cp = getenv("TERMCAP");          cp = getenv("TERMCAP");
         /*          /*
          * TERMCAP can have one of two things in it. It can be the           * 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           * name of a file to use instead of
          * case it better start with a "/". Or it can be an entry to           * /usr/share/misc/termcap. In this case it better start with
          * use so we don't have to read the file. In this case it           * a "/". Or it can be an entry to use so we don't have to
          * has to already have the newlines crunched out.  If TERMCAP           * read the file. In this case cgetset() withh crunch out the
          * does not hold a file name then a path of names is searched           * newlines.  If TERMCAP does not hold a file name then a path
          * instead.  The path is found in the TERMPATH variable, or           * of names is searched instead.  The path is found in the
          * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.           * TERMPATH variable, or becomes _PATH_DEF ("$HOME/.termcap
            * /usr/share/misc/termcap") if no TERMPATH exists.
          */           */
         if (!cp || *cp != '/') {        /* no TERMCAP or it holds an entry */          if (!cp || *cp != '/') {        /* no TERMCAP or it holds an entry */
                 if (termpath = getenv("TERMPATH"))                  if ((termpath = getenv("TERMPATH")) != NULL)
                         strncpy(pathbuf, termpath, PBUFSIZ);                          (void)strlcpy(pathbuf, termpath, sizeof(pathbuf));
                 else {                  else {
                         if (home = getenv("HOME")) {    /* set up default */                          if ((home = getenv("HOME")) != NULL) {
                                   /* set up default */
                                 p += strlen(home);      /* path, looking in */                                  p += strlen(home);      /* path, looking in */
                                 strcpy(pathbuf, home);  /* $HOME first */                                  (void)strlcpy(pathbuf, home,
                                 *p++ = '/';                                      sizeof(pathbuf)); /* $HOME first */
                                   if ((p - pathbuf) < sizeof(pathbuf) - 1)
                                       *p++ = '/';
                         }       /* if no $HOME look in current directory */                          }       /* if no $HOME look in current directory */
                         strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf));                          if ((p - pathbuf) < sizeof(pathbuf) - 1) {
                               (void)strlcpy(p, _PATH_DEF,
                                   sizeof(pathbuf) - (p - pathbuf));
                           }
                 }                  }
         }          }
         else                            /* user-defined name in TERMCAP */          else {
                 strncpy(pathbuf, cp, PBUFSIZ);  /* still can be tokenized */                  /* user-defined name in TERMCAP; still can be tokenized */
                   (void)strlcpy(pathbuf, cp, sizeof(pathbuf));
           }
   
         *fname++ = pathbuf;     /* tokenize path into vector of names */          *fname++ = pathbuf;     /* tokenize path into vector of names */
         while (*++p)          while (*++p)
Line 129  tgetent(bp, name)
Line 192  tgetent(bp, name)
                                 break;                                  break;
                         }                          }
                 }                  }
         *fname = (char *) 0;                    /* mark end of vector */          *fname = NULL;                  /* mark end of vector */
         if (cp && *cp && *cp != '/')  
           /*
            * try ignoring TERMCAP if it has a ZZ in it, we do this
            * because a TERMCAP with ZZ in it indicates the entry has been
            * exported by another program using the "old" interface, the
            * termcap entry has been truncated and ZZ points to an address
            * in the exporting programs memory space which is of no use
            * here - anyone who is exporting the termcap entry and then
            * reading it back again in the same program deserves to be
            * taken out, beaten up, dragged about, shot and then hurt some
            * more.
            */
           did_getset = 0;
           if (cp && *cp && *cp != '/' && strstr(cp, ":ZZ") == NULL) {
                   did_getset = 1;
                 if (cgetset(cp) < 0)                  if (cgetset(cp) < 0)
                         return (-2);                          return (-2);
           }
         dummy = NULL;  
         i = cgetent(&dummy, pathvec, name);  
   
         if (i == 0)  
                 strcpy(bp, dummy);  
   
         if (dummy)          /*
                 free(dummy);           * XXX potential security hole here in a set-id program if the
            * user had setup name to be built from a path they can not
            * normally read.
            */
           (*bp)->info = NULL;
           i = cgetent(&((*bp)->info), pathvec, name);
   
           /*
            * if we get an error and we skipped doing the cgetset before
            * we try with TERMCAP in place - we may be using a truncated
            * termcap entry but what else can one do?
            */
           if ((i < 0) && (did_getset == 0)) {
                   if (cp && *cp && *cp != '/')
                           if (cgetset(cp) < 0)
                                   return (-2);
                   i = cgetent(&((*bp)->info), pathvec, name);
           }
   
         /* no tc reference loop return code in libterm XXX */          /* no tc reference loop return code in libterm XXX */
         if (i == -3)          if (i == -3)
                 return (-1);                  return (-1);
   
             /* fill in t_goto capabilities - this prevents memory leaks
              * and is more efficient than fetching these capabilities
              * every time t_goto is called.
              */
           if (i >= 0) {
                   cap_ptr = capability;
                   limit = 255;
                   (*bp)->up = t_getstr(*bp, "up", &cap_ptr, &limit);
                   if ((*bp)->up)
                           (*bp)->up = strdup((*bp)->up);
                   cap_ptr = capability;
                   limit = 255;
                   (*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit);
                   if ((*bp)->bc)
                           (*bp)->bc = strdup((*bp)->bc);
           }
   
         return (i + 1);          return (i + 1);
 }  }
   
 /*  /*
    * Get an entry for terminal name in buffer bp from the termcap file.
    */
   int
   tgetent(bp, name)
           char *bp;
           const char *name;
   {
           int i, plen, elen, c;
           char *ptrbuf = NULL;
   
           i = t_getent(&fbuf, name);
   
           if (i == 1) {
                   /*
                    * stash the full buffer pointer as the ZZ capability
                    * in the termcap buffer passed.
                    */
                   plen = asprintf(&ptrbuf, ":ZZ=%p", fbuf->info);
                   (void)strlcpy(bp, fbuf->info, 1024);
                   elen = strlen(bp);
                   /*
                    * backup over the entry if the addition of the full
                    * buffer pointer will overflow the buffer passed.  We
                    * want to truncate the termcap entry on a capability
                    * boundary.
                    */
                   if ((elen + plen) > 1023) {
                           bp[1023 - plen] = '\0';
                           for (c = (elen - plen); c > 0; c--) {
                                   if (bp[c] == ':') {
                                           bp[c] = '\0';
                                           break;
                                   }
                           }
                   }
   
                   strcat(bp, ptrbuf);
                   tbuf = bp;
           }
   
           return i;
   }
   
   /*
  * Return the (numeric) option id.   * Return the (numeric) option id.
  * Numeric options look like   * Numeric options look like
  *      li#80   *      li#80
Line 157  tgetent(bp, name)
Line 309  tgetent(bp, name)
  * Note that we handle octal numbers beginning with 0.   * Note that we handle octal numbers beginning with 0.
  */   */
 int  int
 tgetnum(id)  t_getnum(info, id)
         char *id;          struct tinfo *info;
           const char *id;
 {  {
         long num;          long num;
   
         if (cgetnum(tbuf, id, &num) == 0)          _DIAGASSERT(info != NULL);
                 return (num);          _DIAGASSERT(id != NULL);
   
           if (cgetnum(info->info, id, &num) == 0)
                   return (int)(num);
         else          else
                 return (-1);                  return (-1);
 }  }
   
   int
   tgetnum(id)
           const char *id;
   {
           return t_getnum(fbuf, id);
   }
   
 /*  /*
  * Handle a flag option.   * Handle a flag option.
  * Flag options are given "naked", i.e. followed by a : or the end   * Flag options are given "naked", i.e. followed by a : or the end
  * of the buffer.  Return 1 if we find the option, or 0 if it is   * of the buffer.  Return 1 if we find the option, or 0 if it is
  * not given.   * not given.
  */   */
   int t_getflag(info, id)
           struct tinfo *info;
           const char *id;
   {
           _DIAGASSERT(info != NULL);
           _DIAGASSERT(id != NULL);
   
           return (cgetcap(info->info, id, ':') != NULL);
   }
   
 int  int
 tgetflag(id)  tgetflag(id)
         char *id;          const char *id;
 {  {
         return (cgetcap(tbuf, id, ':') != NULL);          return t_getflag(fbuf, id);
 }  }
   
 /*  /*
Line 187  tgetflag(id)
Line 360  tgetflag(id)
  *      cl=^Z   *      cl=^Z
  * Much decoding is done on the strings, and the strings are   * Much decoding is done on the strings, and the strings are
  * placed in area, which is a ref parameter which is updated.   * placed in area, which is a ref parameter which is updated.
  * No checking on area overflow.   * limit is the number of characters allowed to be put into
    * area, this is updated.
  */   */
 char *  char *
 tgetstr(id, area)  t_getstr(info, id, area, limit)
         char *id, **area;          struct tinfo *info;
           const char *id;
           char **area;
           size_t *limit;
 {  {
         char ids[3];  
         char *s;          char *s;
         int i;          int i;
   
           _DIAGASSERT(info != NULL);
           _DIAGASSERT(id != NULL);
           /* area may be NULL */
   
   
           if ((i = cgetstr(info->info, id, &s)) < 0) {
                   errno = ENOENT;
                   if ((area == NULL) && (limit != NULL))
                           *limit = 0;
                   return NULL;
           }
   
           if (area != NULL) {
                   /*
                    * check if there is room for the new entry to be put into
                    * area
                    */
                   if (limit != NULL && (*limit < i)) {
                           errno = E2BIG;
                           free(s);
                           return NULL;
                   }
   
                   (void)strcpy(*area, s);
                   free(s);
                   s = *area;
                   *area += i + 1;
                   if (limit != NULL) *limit -= i;
   
                   return (s);
           } else {
                   _DIAGASSERT(limit != NULL);
                   *limit = i;
                   free(s);
                   return NULL;
           }
   }
   
   /*
    * Get a string valued option.
    * These are given as
    *      cl=^Z
    * Much decoding is done on the strings, and the strings are
    * placed in area, which is a ref parameter which is updated.
    * No checking on area overflow.
    */
   char *
   tgetstr(id, area)
           const char *id;
           char **area;
   {
           struct tinfo dummy;
           char ids[3];
   
           _DIAGASSERT(id != NULL);
         /*          /*
          * XXX           * XXX
          * This is for all the boneheaded programs that relied on tgetstr           * This is for all the boneheaded programs that relied on tgetstr
          * to look only at the first 2 characters of the string passed...           * to look only at the first 2 characters of the string passed...
          */           */
         *ids = *id;          ids[0] = id[0];
         ids[1] = id[1];          ids[1] = id[1];
         ids[2] = '\0';          ids[2] = '\0';
   
         if ((i = cgetstr(tbuf, ids, &s)) < 0)          if ((id[0] == 'Z') && (id[1] == 'Z')) {
                   dummy.info = tbuf;
                   return t_getstr(&dummy, ids, area, NULL);
           }
           else
                   return t_getstr(fbuf, ids, area, NULL);
   }
   
   /*
    * Get a string valued option specified by id and append it to the
    * given buffer.  If bufptr is NULL then a new buffer is allocated, if
    * bufptr is non-NULL then extend the memory allocation to allow the
    * new string to be appended to the buffer.  The pointer area is
    * updated to point to the start of the new entry and this address is
    * also returned to the caller.  If the string is not found or a
    * memory allocation fails then NULL is returned and bufptr and area
    * are unchanged.
    *
    * XXX: This is horribly broken because realloc's can move memory and
    * invalidate attributes we've already returned. Only possible way to
    * fix it for now is to allocate a lot -- 8K, and leak if we need to
    * realloc. This API needs to be destroyed!.
    */
   #define BSIZE 8192
   char *
   t_agetstr(struct tinfo *info, const char *id, char **bufptr, char **area)
   {
           size_t new_size;
           char *new_buf;
   
           _DIAGASSERT(info != NULL);
           _DIAGASSERT(id != NULL);
           _DIAGASSERT(bufptr != NULL);
           _DIAGASSERT(area != NULL);
   
           t_getstr(info, id, NULL, &new_size);
   
             /* either the string is empty or the capability does not exist. */
           if (new_size == 0 || new_size > BSIZE)
                 return NULL;                  return NULL;
   
             /* check if we have a buffer, if not malloc one and fill it in. */
           if (*bufptr == NULL) {
                   if ((new_buf = (char *) malloc(BSIZE)) == NULL)
                           return NULL;
                   *bufptr = new_buf;
                   *area = new_buf;
           } else if (*area - *bufptr >= BSIZE - new_size) {
                   char buf[BSIZE];
                   char *b = buf;
                   size_t len = BSIZE;
                   /* Leak! */
                   return strdup(t_getstr(info, id, &b, &len));
           }
           return t_getstr(info, id, area, NULL);
   
   }
   
   /*
    * Free the buffer allocated by t_getent
    *
    */
   void
   t_freent(info)
           struct tinfo *info;
   {
           _DIAGASSERT(info != NULL);
           free(info->info);
           if (info->up != NULL)
                   free(info->up);
           if (info->bc != NULL)
                   free(info->bc);
           free(info);
   }
   
   /*
    * Get the terminal name string from the termcap entry.
    *
    */
   int
   t_getterm(info, area, limit)
           struct tinfo *info;
           char **area;
           size_t *limit;
   {
           char *endp;
           size_t count;
   
           _DIAGASSERT(info != NULL);
           if ((endp = strchr(info->info, ':')) == NULL) {
                   errno = EINVAL;
                   return -1;
           }
   
         strcpy(*area, s);  
         *area += i + 1;          count = endp - info->info + 1;
         return (s);          if (area == NULL) {
                   _DIAGASSERT(limit != NULL);
                   *limit = count;
                   return 0;
           } else {
                   if ((limit != NULL) && (count > *limit)) {
                           errno = E2BIG;
                           return -1;
                   }
   
                   (void)strlcpy(*area, info->info, count);
                   if (limit != NULL)
                           *limit -= count;
           }
   
           return 0;
 }  }

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.39

CVSweb <webmaster@jp.NetBSD.org>