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.