[comp.sources.misc] v16i069: generic capability database routines., Part01/01

sjg@zen.void.oz.au (Simon J. Gerraty) (01/12/91)

Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
Posting-number: Volume 16, Issue 69
Archive-name: cap/part01

facility analagous to termcap(3X) but in a slightly more general
manner.   These routines can be used to extract entries from
files that follow the termcap(5),printcap(5) format.

cap_getent() will search up to MAX_DBASE files for an entry and
follows ":tc=like:" pointers.  The header section of cap.c
includes the documentation.

--------------------(cut)--------------------
echo x - cap.c
sed 's/^X//' >cap.c <<'*-*-END-of-cap.c-*-*'
X/* NAME:
X *      cap.c - generic capability database facility.
X *
X * SYNOPSIS:
X *      int cap_getent(char *buf, char *name);
X *      int cap_ngetent(char *buf, char *name, int nbytes);
X *      char *cap_getstr(char *id, char **area);
X *      int cap_getnum(char *id);
X *      int cap_getflag(char *id);
X *
X * DESCRIPTION:
X *      The cap module provides functions similar to termcap(3X).
X *      It is more general however.  An application can 
X *      initialize *_cap_database[0-MAX_DBASE] to a list of 
X *      database files to search for cap entries.
X *
X *      Each file refered to by _cap_database[n] is expected to 
X *      follow the layout of /etc/termcap.  If _cap_database[0] 
X *      is not initialized the package "should" behave like the 
X *      equivalent termcap facilities.
X *      
X *      An application must call cap_getent or cap_ngetent 
X *      before calling any of the other functions.  cap_getent 
X *      simply calls cap_ngetent with an assumed size of the 
X *      buffer provided by the application.  The buffer passed 
X *      to cap_ngetent must remain valid for all subsequent 
X *      calls to this module.
X *      
X *      cap_ngetent will "follow" a ":tc=like:" at the end of an 
X *      an entry using recursive calls to cap_ngetent.  If the 
X *      "like" entry is not found in any of the files refered to 
X *      by *_cap_database[] it is left as ":tc=like:".
X *
X *
X * RETURN VALUE:
X *      cap_getent 1==success, 0==entry not found, -1==error.
X *      cap_ngetent nbytes copied==success, 0==entry not found, -1==error.
X *      cap_getstr str==success, NULL==failure.
X *      cap_getnum num=success, -1==failure.
X *      cap_getflag  1==success, 0==not found
X *
X * FILES:
X *      /etc/termcap     default database
X *
X * SEE ALSO:
X *      termcap(3X), termcap(5), printcap(5).
X *
X * BUGS:
X *      cap_get{str,num,flag} do not tolerate any spaces between 
X *      the : and the name.  That is ":tc=like:" is ok, but 
X *      ": tc=like:" is not, nor is ":tc =like:".  Whether this 
X *      is a bug or a feature is a bit subjective :-)
X *      
X *      cap_getstr does not interperate the content of the 
X *      string capability found in any way.  (unlike tgetstr(3)).
X *      
X * AMENDED:
X *      91/01/08  16:58:12  (sjg)
X *
X * RELEASED:
X *      91/01/08  16:58:15  v1.8
X *
X * SCCSID:
X *      @(#)cap.c  1.8  91/01/08  16:58:12  (sjg)
X *
X *      Copyright (c) 1989 Simon J. Gerraty.
X *
X *      This is free software.  It comes with NO WARRANTY.
X *      Permission to use, modify and distribute this source code 
X *      is granted subject to the following conditions.
X *      1/ that that the above copyright notice and this notice 
X *      are preserved in all copies and that due credit be given 
X *      to the author.  
X *      2/ that any changes to this code are clearly commented 
X *      as such so that the author does get blamed for bugs 
X *      other than his own.
X *      
X *      Please send copies of changes and bug-fixes to:
X *      sjg@zen.void.oz.au
X *                                                                
X */
X#ifndef lint
Xstatic char  sccs_id[] = "@(#)cap.c     1.8  91/01/08  16:58:12  (sjg)";
X#endif
X
X/* include files */
X#include <stdio.h>
X#ifdef __STDC__
X# include <stdlib.h>
X#endif
X#ifdef USG
X# include <string.h>
X#else
X# include <strings.h>
X# define strchr index
X# define strrchr rindex
X#endif /* USG */
X
X#define EXTERN
X#include "cap.h"
X#undef EXTERN
X
X/* some useful #defines */
X#define ENTRY
X#define LOCAL static
X#define TRUE  1
X#define FALSE 0
X
X#if defined(__STDC__) || defined(PROTO)
X# define _P_(p) p
X#else
X# define _P_(p) ()
X#endif
X
X/* manifest constants */
X
X/* macros */
X
X/* globals */
Xstatic char	capname[CAP_NAMESZ + 1];
X
X
X/* external variable declarations */
X
X/* function prototypes */
Xextern char *getenv	_P_((char *));
Xextern char *strstr	_P_((const char *s1, const char *s2));
X  
X
X
X/* functions */
X
X
X/* NAME:
X *      cap_getent - look for capability description
X *
X * SYNOPSIS:
X *      int cap_getent(char *buf, char *name);
X *
X * DESCRIPTION:
X *      Look for cap entry "name" in either /etc/termcap, the 
X *      environment or the files listed in *_cap_database[].
X *      If an entry is found it is copied to "buf".
X *      ":tc=like:" entries cause a recursive call to cap_ngetent.
X *      
X * RETURN VALUE:
X *      1==success, 0==entry not found, -1==failure
X */
X
XENTRY int
Xcap_getent(buf, name)
X  char 	*buf;
X  char	*name;
X{
X  register int	i;
X  
X  return (((i = cap_ngetent(buf, name, (CAP_BUFSZ - 1))) > 0)
X	  ? 1 : i);
X}
X
X
X/* NAME:
X *      cap_ngetent - look for capability description
X *
X * SYNOPSIS:
X *      int cap_ngetent(char *buf, char *name, int nbytes);
X *
X * DESCRIPTION:
X *      Look for cap entry "name" in either /etc/termcap, the 
X *      environment or the files listed in *_cap_database[].
X *      If an entry is found it is copied to "buf" up to a 
X *      maximum of "nbytes".
X *      ":tc=like:" entries cause a recursive call to cap_ngetent.
X *      
X * RETURN VALUE:
X *      nbytes copied==success, 0==entry not found, -1==failure
X */
X
XENTRY int
Xcap_ngetent(buf, name, nbytes)
X  char 	*buf;
X  char	*name;
X  int	nbytes;
X{
X  static	callcnt = 0;		/* check if we're recursing */
X  register char	*rcp;
X  register int	len;
X  FILE		*fp;
X  char		*cp;
X  char		tc_name[CAP_NAMESZ + 1];
X  int		finished = FALSE;
X  int		found = FALSE;
X  int		max = nbytes;
X  int		i = 0;
X  
X  if (max <= 0)
X    return -1;
X  if (callcnt == 0)
X  {
X    if (_cap_database[0] == NULL)
X    {
X      if ((rcp = getenv("TERMCAP")) != NULL)
X      {
X	if (*rcp == '/')
X	  _cap_database[0] = rcp;
X	else
X	  if (strncmp(getenv("TERM"), name, strlen(name)))
X	    _cap_database[0] = "/etc/termcap";
X	_cap_database[1] = NULL;
X      }
X      else
X	return -1;		/* nothing to work with */
X    }
X    _cap_buf = buf;			/* needed by other functions */
X    if (_cap_database[0] == NULL)
X    {
X      /*
X       * we have a cap entry in the environment
X       */
X      (void) strncpy(buf, rcp, nbytes);
X      buf[nbytes] = '\0';
X      return (strlen(buf));
X    }
X  }
X  /*
X   * we have to look up "name" in the database file(s).
X   */
X  for (i = 0; max > 0 && found == FALSE &&
X       i < MAX_DBASE && _cap_database[i]; i++)
X  {
X    if ((fp = fopen(_cap_database[i], "r")) == NULL)
X      continue ;			/* try next one */
X    cp = buf;
X    rcp = buf;
X    finished = FALSE;
X    
X    while (!(finished))
X    {
X      if (max <= 0 || (fgets(cp, max, fp) == NULL))
X	finished = TRUE;
X      else
X      {
X	len = strlen(cp);
X	rcp = cp;
X	while (*rcp == ' ' || *rcp == '\t')
X	  rcp++;
X	if (*rcp && *rcp != '\n' && *rcp != '#')
X	{
X	  /* not a comment or blank */
X	  if (!found)
X	    if (*rcp != ':')	/* start of an entry */
X	    {
X	      register char *rcp2;
X
X	      /*
X	       * be sure that the names match
X	       * not part of another tc=
X	       */
X	      if (rcp2 = strchr(rcp, ':'))
X		*rcp2 = '\0';
X	      found = (strstr(rcp, name) != NULL);
X	      if (found && rcp2)
X	      {
X		*rcp2 = ':';
X		if (callcnt)
X		  /*
X		   * We are a recursive call,
X		   * we don't want the name part or the ':'.
X		   */
X		  rcp = ++rcp2;
X	      }
X	    }
X	  if (found)
X	  {
X	    if (rcp != cp)
X	      rcp = strcpy(cp, rcp);
X	    len = strlen(rcp);
X	    if (rcp[len - 2] == '\\') /* more to get */
X	    {
X	      len -= 2;		/* lose the \ and \n */
X	      rcp[len] = '\0';
X	      cp = &rcp[len];
X	    }
X	    else
X	      finished = TRUE;
X	    max -= len;
X	  }
X	}
X      }
X    }
X    (void) fclose(fp);
X  }
X  if (found)
X  {
X    /*
X     * allow for tc=termtype
X     * as the last entry.
X     */
X    cp = tc_name;
X    if ((name = cap_getstr("tc", &cp)) != NULL)
X    {
X      if ((rcp = strstr(buf, ":tc=")) != NULL)
X      {
X	callcnt++;
X	if ((len = cap_ngetent(++rcp, name, max)) <= 0)
X	  (void) sprintf(rcp, "tc=%s\n", tc_name);
X	else
X	  max -= len;
X	callcnt--;
X      }
X    }
X  }
X  buf[nbytes] = '\0';
X  if (max < 0)
X    max = 0;
X  return (found ? nbytes - max : 0);
X}
X
X
X/* NAME:
X *      cap_getstr - get a string capability
X *
X * SYNOPSIS:
X *      cap_getstr()
X *
X * DESCRIPTION:
X *      Look for an item ":id=str:" in the buffer pointed to by 
X *      _cap_buf.  If found copy "str" into the buffer at "area" 
X *      and advance "area".  If all ok return a pointer to "str" 
X *      within the user's buffer (ie. the previous value of 
X *      "*area". 
X *      
X *      Unlike tgetstr(3), this function does not interperate 
X *      the contents of "str" in anyway.
X *
X * RETURN VALUE:
X *      str==success, -1==failure
X */
X
XENTRY char *
Xcap_getstr(id, area)
X  char	*id;
X  char	**area;
X{
X  register char	*rcp;
X  register int	len;
X  
X  (void) sprintf(capname, ":%s=", id);
X  if ((rcp = strstr(_cap_buf, capname)) != NULL)
X  {
X    rcp += strlen(capname);
X    len = strcspn(rcp, ":\n");
X    rcp = strncpy((*area), rcp, len);
X    (*area)[len] = '\0';
X    *area += ++len;
X    return rcp;
X  }
X  return NULL;
X}
X
X
X/* NAME:
X *      cap_getnum - get a numeric capability
X *
X * SYNOPSIS:
X *      cap_getnum()
X *
X * DESCRIPTION:
X *      This function looks for an item ":id#num:" in the buffer 
X *      pointer to by _cap_buf.  If found it returns "num" 
X *      otherwise -1.
X *
X * RETURN VALUE:
X *      num==success, -1==failure
X */
X
XENTRY int
Xcap_getnum(id)
X  char	*id;
X{
X  register char	*rcp;
X  
X  (void) sprintf(capname, ":%s#", id);
X  if ((rcp = strstr(_cap_buf, capname)) != NULL)
X  {
X    rcp += strlen(capname);
X    return (atoi(rcp));
X  }
X  return -1;
X}
X
X
X/* NAME:
X *      cap_getflag - check for presence of capability
X *
X * SYNOPSIS:
X *      cap_getflag()
X *
X * DESCRIPTION:
X *      This function simply looks for any item that matches the 
X *      RE ":id[:=#]" in the buffer pointed to by _cap_buf.  
X *      That is, it will return TRUE as soon as it finds a 
X *      boolean, numeric or string capability with the right 
X *      name "id".
X *
X * RETURN VALUE:
X *      1==found, 0==not found
X */
X
XENTRY int
Xcap_getflag(id)
X  char	*id;
X{
X  register char	*rcp;
X  
X  (void) sprintf(capname, ":%s", id);
X  if ((rcp = strstr(_cap_buf, capname)) != NULL)
X  {
X    rcp += strlen(capname);
X    return (strcspn(rcp, "=#:\n") == 0);
X  }
X  return 0;
X}
X
X/* This lot (for GNU-Emacs) goes at the end of the file. */
X/* 
X * Local Variables:
X * version-control:t
X * comment-column:40
X * End:
X */
*-*-END-of-cap.c-*-*
echo x - cap.h
sed 's/^X//' >cap.h <<'*-*-END-of-cap.h-*-*'
X/* NAME:
X *      cap.h - definitions for cap module
X *
X * SYNOPSIS:
X *      int cap_getent(char *buf, char *name);
X *      int cap_ngetent(char *buf, char *name, int nbytes);
X *      int cap_getnum(char *id);
X *      int cap_getflag(char *id);
X *      char *cap_getstr(char *id, char **area);
X *
X * DESCRIPTION:
X *      The cap module provides functions similar to termcap(3X).
X *      Refer to the documentation in cap.c for full description.
X *
X * SEE ALSO:
X *      cap.c
X *
X * AMENDED:
X *      91/01/04  13:20:04  (sjg)
X *
X * RELEASED:
X *      91/01/04  13:20:06  v1.4
X *
X * SCCSID:
X *      @(#)cap.h  1.4  91/01/04  13:20:04  (sjg)
X *
X *      Copyright (c) 1989 Simon J. Gerraty.
X *
X *      This is free software.  It comes with NO WARRANTY.
X *      Permission to use, modify and distribute this source code 
X *      is granted subject to the following conditions.
X *      1/ that that the above copyright notice and this notice 
X *      are preserved in all copies and that due credit be given 
X *      to the author.  
X *      2/ that any changes to this code are clearly commented 
X *      as such so that the author does get blamed for bugs 
X *      other than his own.
X *      
X *      Please send copies of changes and bug-fixes to:
X *      sjg@zen.void.oz.au
X */
X
X/* some useful #defines */
X#ifndef EXTERN
X# define EXTERN extern
X# define EXTERN_DEFINED
X#endif
X
X#define ENTRY
X#define LOCAL static
X#define TRUE  1
X#define FALSE 0
X
X#if defined(__STDC__) || defined(PROTO)
X# define _P_(p) p
X#else
X# define _P_(p) ()
X#endif
X
X/* manifest constants */
X#define MAX_DBASE 10
X#define CAP_BUFSZ 1024
X#define CAP_NAMESZ 50
X
X/* struct / union */
X
X/* macros */
X
X/* external variable declarations */
XEXTERN char	*_cap_database[MAX_DBASE];
XEXTERN char	*_cap_buf;
X
X/* function prototypes */
X
XENTRY int 	cap_getent	_P_((char *buf, char *name));
XENTRY int 	cap_ngetent	_P_((char *buf, char *name, int nbytes));
XENTRY int 	cap_getnum	_P_((char *id));
XENTRY int 	cap_getflag	_P_((char *id));
XENTRY char 	*cap_getstr	_P_((char *id, char **area));
X
X
X
X/* This lot goes at the END */
X/* be sure not to interfere with anyone else's idea about EXTERN */
X#ifdef EXTERN_DEFINED
X# undef EXTERN_DEFINED
X# undef EXTERN
X#endif
X/*
X * Local Variables:
X * version-control:t
X * comment-column:40
X * End:
X */
*-*-END-of-cap.h-*-*
exit

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.