Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CF-1.1 library. Part01/03

0 views
Skip to first unread message

Jan-Piet Mens

unread,
Jan 18, 1993, 10:20:09 AM1/18/93
to
#! /bin/sh
#
# This is CF version 1.1 at patchlevel 1.
# Make a new directory for the CF sources, cd to it, and run kits 1 up
# to 3 through sh. When all 3 kits have been run, read README.
#
echo " "
echo "This is CF 1.1 at patchlevel 1, kit 1 (of 3):"
echo " End of kit 1 (of 3)"
echo "will echo at the end if this kit is complete."
export PATH || (echo "Please use sh to unpack this archive." ; kill $$)
mkdir hints nls 2>/dev/null
echo Extracting README
sed >README <<'!STUFFY!FUNK!' -e 's/X//'
XThis is CF version 1.1 PL0
X
XCF is a library of routines that can be incorporated into an application for
Xreading configuration profiles for an application. A sample configuration
Xprofile would be
X
X /* This is a comment , because the whole file runs through cpp */
X
X #ifdef unix
X # define tmpdir "/var/tmp"
X terminal-type = $TERM
X #endif
X temporary-storage = tmpdir # Must be large enough
X full-name = "Jan-Piet Mens" ; whatever
X +have-x-windows ; boolean TRUE
X -have-postscript ; boolean FALSE
X
X my-current-path = $PATH
X home = $HOME
X
X maximum-users = 99
X max-users = 24
X current-config-filename = __FILE__
X
XCF reads configuration profiles, passes them through the C-pre-processor
Xand parses the result according to a fixed set of rules. The resulting
Xvariables and values are stored in a safe place and may be retrieved
Xfor further processing.
X
XRead the file INSTALL for installation instructions, and the manual page
Xfor further info.
X
X -JP
!STUFFY!FUNK!
echo Extracting cf.n
sed >cf.n <<'!STUFFY!FUNK!' -e 's/X//'
X.TH CF 3
X.SH NAME
Xcf \- configuration library routines
X.de Ps \" Print start, for source code; $1 is indent (default 5 spaces)
X.br
X.sp
X.sp \\n(PDu
X.ns
X.nr pS \\n(.s \" Save current point size
X.nr vS \\n(.v \" Save current vertical spacing
X.nr pF \\n(.f \" Save current font
X.nr pI \\n(.i \" Save current indent
X.if t .ps 8
X.if t .vs 9
X.ft LP
X.ie !"\\$1"" .in +\\$1n
X.el .in +5n
X.nf
X.if t .ta 3.6m 7.2m 10.8m 14.4m 18m 21.6m 25.2m 28.8m 32.4m 36m 39.6m 43.2m 46.8m
X.if n .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n
X.br
X..
X.de Pe \" Printout end.
X.br
X.if "\\$1"" .sp \\n(PDu
X.ps \\n(pSu
X.vs \\n(vSu
X.ft \\n(pF
X.in \\n(pIu
X.rr pS
X.rr vS
X.rr pF
X.rr pI
X.fi
X..
X.SH SYNOPSIS
X.nf
X\fB
X#include <cf.h>
X
Xint cf_init(list)
XCFlist *list;
X
Xint cf_inst(name, type, min, max, value)
Xchar *name;
Xcf_et type;
Xlong min, max;
Xchar *value;
X
Xint cf_load(fname, ...)
Xchar *fname;
X
Xchar *cf_string(name)
Xchar *name;
X
Xchar cf_bool(name)
Xchar *name;
X
Xlong cf_long(name)
Xchar *name;
X
Xdouble cf_double(name)
Xchar *name;
X
Xint cf_printall(func)
Xint (*func)(cfsymbol *sp);
X
Xvoid cf_setflags(flags)
Xunsigned long flags;
X
Xunsigned long _cflags()
X\fR
X.fi
X.SH DESCRIPTION
X.B cf
Xis a library of routines which enable access to configuration profiles for
Xapplications. Such configuration profiles contains values for pre-defined
Xvariables which an application accesses to gather specific information. The
X.B cf
Xlibrary allows definitions of such configuration variables, and loads profiles
Xat run-time which may overwrite pre-defined values. The library runs the
Xprofiles that are loaded through the C preprocessor which in turn further
Xmaximises the flexibility of the profiles.
X.PP
XThe easiest way to use the
X.B cf
Xlibrary is to just create a configuration profile [see \fBPROFILES\fR below]
Xand write the application program using the
X.IR cf_string (),
X.IR cf_long (),
X.IR cf_bool (),
Xand
X.IR cf_double ()
Xroutines. This enables any configuration profile to be parsed by an application
Xprogram irrespective of which variables are set or not set. The usual modus
Xoperandi would be to use
X.IR cf_init ()
Xor
X.IR cf_inst ()
Xto define the expected variables with appropriate default values and then
Xcall
X.IR cf_load ()
Xwith a list of configuration profiles. This enables the library to check whether
Xvariables are legal.
X.SH ROUTINES
XThe following routines are available to the user of the
X.B cf
Xlibrary:
X.RS 1i
X.SS cf_init()
XThis routine expects a null-terminated list of configuration entries in
X.BR list .
XThe definition of a
X.B cfent
Xelement is
X.Ps
Xtypedef struct _cflist {
X char *name;
X cf_et type;
X long min;
X long max;
X char *val;
X} cfent;
X.Pe
X.B name
Xwill contain the name of the configuration variable, and
X.B type
Xa legal type out of
X.IR t_string ,
X.IR t_long ,
X.IR t_double ,
Xor
X.IR t_bool .
X.B min
Xand
X.B max
Xare the minimum and maximum legal values for the variable if
X.B type
Xis numeric, and otherwise will specify the minimum and maximum number
Xof characters if
X.B type
Xis
X.IR t_string .
X.Ps
X static cfent config[] = {
X { "path", t_str, 3, 30, "/u/local/bin"},
X { "file", t_str, 5, 5, "foobar"},
X { "maxusers", t_long,2, 10, "7"},
X { NULL, 0, 0}
X};
X.Pe
XNote how in the initialization all values are specified as strings.
X.SS cf_inst()
Xallows installation of additional configuration variables. Each of the four
Xarguments has the same meaning as the words in a
X.B cfent
Xstruct.
X.Ps
Xcf_inst("my-double", t_dbl, 0, 0, "145.78");
Xcf_inst("my-integer", t_long, 0, 999, "1002");
Xcf_inst("my-string", t_str, 10, 30, "Jan-Piet Mens");
Xcf_inst("my-bool", t_bol, 0, 1, "1");
X.Pe
X.SS cf_load()
Xloads each specified file name in turn. The list of files
X.B must
Xbe null-terminated.
X.Ps
Xcf_load("myconfig.cf", "yourconfig.cf", 0);
X.Pe
XConfiguration files are searched along a path-like environment variable called
X.BR CF_PATH .
XIf this is not set, they are searched along the path "__CF_DEFAULT_PATH__
Xwhich was set upon compilation of the library.
XEach configuration file that is read is first passed through the C preprocessor.
XIf a configuration variable is read from a file that has not previously been
Xinstalled by
X.IR cf_init ()
Xor
X.IR cf_inst (),
Xthe variable is installed anyway or the variable causes a fatal error. This
Xdepends on the setting of the configuration flags set via
X.IR cf_setflags ().
X.SS cf_string()
X.SS cf_long()
X.SS cf_double()
X.SS cf_bool()
XThese routines retrieve the value of the named configuration variable. If the
Xvariable does not exist, or if the type does not correspond to the routine,
Xa diagnostic is issued.
X.Ps
Xprintf("My name is: %s", cf_string("my-string"));
X
Xif (cf_bool("my-bool")) {
X do_this();
X}
Xelse {
X do_that();
X}
X.Pe
X.SS cf_setflags()
Xexpects a list of flags from the following set. These flags may be ored together
Xto produce the desired effect.
X.IP "\fBCF_REALNULL\fB"
XIf set,
X.IR cf_string ()
Xreturns NULL if the value is NULL. Otherwise the string "<<null>>" is returned.
X.IP "\fBCF_SILENT\fR"
XErrors will not be reported to stderr.
X.IP "\fBCF_ERREXIT\fR"
XIf an error occurs (like unkown config variable), the application will exit.
X.IP "\fBCF_IGNORE_U\fR"
XUnkown configuration variable loaded via
X.IR cf_load (),
Xwill be silently inserted into the set of config variables.
XIf this flag is not set, an unkown config variable produces a diagnostic.
Xwill
X.RE
X.SH PROFILES
XConfiguration profiles are read via the C preprocessor and parsed according
Xto the following rules.
XVirtual line are read ignoring comments - introduced by a hash symbol (#)
X or a semicolon (;) reaching to the end of the current line. Empty lines
Xare ignored.
XMultiple continuation lines intoduced by a backslash (\e) are read
Xinto one virtual line.
X.sp
XAppropriate character conversion escaped by a \e (as in C) is done,
Xand a \e followed by a newline is treated as a continuation
Xline which will be read into the same virtual line. If "vgets" sees a
Xquote ("), it will protect white space; otherwise white space
Xis skipped.
X.sp
XUnprotected $ characters will cause a search in the environment
Xfor the following name, i.e: $HOME will be expanded to the string
Xin the process environment [see environ(5)]. An undefined environment
Xvariable will return the string "<<undefined>>. If $-characters are to
Xbe literal, protect the $ by a backslash as in: \e$HOME.
X.sp
X.SH SAMPLE
X.Ps
X; this is a comment
X/* This is also a comment , because the whole file runs through cpp */
X
X#ifdef unix
X# define tmpdir "/var/tmp"
X terminal-type = $TERM
X#else
X# define tmpdir "C:\\DOS\\TMP"
X terminal-type = PC
X#endif
X
Xtemporary-storage = tmpdir # Must be large enough
Xfull-name = Jan-Piet Mens ; whatever
Xignore-characters = "#;/**/" ; note the quotes
X+bool-true ; boolean TRUE
X-bool-false ; boolean FALSE
X
X#ifdef LIMITED_CPP /* True if compiled with LIMITED_CPP */
X# define PATH CF_PATH
X#endif
X
Xmy-current-path = PATH
Xhome = $HOME
X
Xmaximum-users = 99
Xmax-users = 24
Xfile = netup
Xmy-integer: 999
Xcurrent-config-filename = __FILE__
X.Pe
X.SH DEFINES
XThe following pre-processor defines are built-in:
X.IP "\fBCF\fR"
Xindicates that the file is being processed by the configuration library.
X.SH ENVIRONMENT
X.IP "\fICF_PATH\fR"
Xcontains a colon separated list of directories for which configuration
Xprofiles should be searched. If this variable is not set, the default
Xpath (compiled-in) will be used [see FILES].
X.SH FILES
X.IP "\fI__CF_DEFAULT_PATH__\fR"
XThis is the default path that
X.IR cf_open ()
Xwill use if the file names given it do not begin with a slash (/) or with (./).
X.IR cf_open ()
Xwill search for configuration profiles along this path, trying each
Xcolon-separated component before giving up.
X.IP "\fI__CPP__\fR"
XThis is the name of the C pre-compiler that will prepare each configuration
Xprofile accessed by
X.IR cf_open ().
XThe only way to change this, is to re-compile the source of the library.
X.SH AUTHOR
XJan-Piet Mens - <j...@Logix.DE>
!STUFFY!FUNK!
echo Extracting vgets.c
sed >vgets.c <<'!STUFFY!FUNK!' -e 's/X//'
X/*
X * NAME:
X * vgets \- virtual gets
X * SYNOPSIS:
X * #include <stdio.h>
X * .br
X * extern long _vgets_linenumber;
X * .sp
X * char *vgets(fp)
X * FILE *fp;
X * DESCRIPTION:
X * "vgets" reads a virtual line from the open file in 'fp', ignoring
X * comments - introduced by a hash symbol (#) or a semicolon
X * (;) and which reach to the end of the current line - and ignoring
X * empty lines.
X * "vgets" reads multiple continuation lines into one virtual line,
X * allocating necessary memory as it goes along.
X * .sp
X * "vgets" does appropriate conversion of characters escaped by a \e
X * (as in C), and treats a \e followed by a newline as a continuation
X * line which will be read into the same virtual line. If "vgets" sees a
X * quote ("), it will protect over white space; otherwise white space
X * is skipped.
X * .sp
X * Unprotected $ characters will tell "vgets" to search the environment
X * for the following name, i.e: $HOME will be expanded to the string
X * in the process environment [see environ(5)]. An undefined environment
X * variable will return the string "<<undefined>>. If $-characters are to
X * be literal, protect the $ by a backslash as in: \e$HOME.
X * .sp
X * The global '_vgets_linenumber' points to the current virtual line
X * number as interpreted by "vgets". This line number is set to the
X * physical line number of the file 'fp' at the end of the virtual
X * line [see EXAMPLE].
X * EXAMPLE:
X * .nf
X * .in 0.5i
X * main()
X * {
X * FILE *fp = fopen("file", "r");
X * extern long _vgets_linenumber;
X * char *bp;
X *
X * while ((bp = vgets(fp)) != NULL)
X * printf("(%3ld) [%s]\n",_vgets_linenumber, bp);
X *
X * }
X * .fi
X * .in
X * SAMPLE-RUN:
X * The following input file is processed by above program.
X * .nf
X * .in 0.5i
X * 1 # This is a comment
X * 2 thirteen (13) is an integer # this is a comment
X * 3 fourty-\e
X * 4 seven is also \e
X * 5 an integer ; this is also a comment
X * 6 ; on the above line, white space is swallowed
X * 7 "On this line \e
X * 8 white space is \e
X * 9 kept "
X * 10
X * 11
X * 12
X * 13 The newline character \e\en produces a newline,
X * 14 whereas \en does a newline.
X * 15 This (\e#) is not a comment,
X * 16 and this "#" is not either.
X * 17 My home ($HOME) is my castle.
X * 18 My \$HOME = $HOME
X * 19 I am user: $LOGNAME
X * .in
X * .fi
X * would be returned as follows (the numbers in round brackets indicate
X * the virtual line number as reported in '_vgets_linenumber').
X * .nf
X * .in 0.5i
X * ( 2) [thirteen (13) is an integer]
X * ( 5) [fourty-seven is also an integer]
X * ( 9) ["On this line white space is kept "]
X * ( 13) [The newline character \n produces a newline,]
X * ( 14) [whereas
X * does a newline.]
X * ( 15) [This (#) is not a comment,]
X * ( 16) [and this "#" is not either.]
X * ( 17) [My home (/u/jpm) is my castle.]
X * ( 18) [My $HOME = /u/jpm]
X * ( 19) [I am user: jpm]
X * .in
X * .fi
X *
X * RETURN-VALUE:
X * The pointer returned by "vgets" points to a dynamic area which is
X * overwritten at each call. Although this area is dynamic, it may
X * not be free()d by the caller. At end of file, NULL is returned.
X * BUGS:
X * In my software ?
X * AUTHOR:
X * Jan-Piet Mens - <j...@Logix.DE>
X */
X
X#include <stdio.h>
X#include "config.h"
X#include <ctype.h>
X#ifdef I_STRING
X# include <string.h>
X#else
X# include <strings.h>
X#endif
X
X/*
X * $Header: /home/jpm/src/cf/RCS/vgets.c,v 1.1 1993/01/18 14:47:58 jpm Exp $
X *
X * $Log: vgets.c,v $
X * Revision 1.1 1993/01/18 14:47:58 jpm
X * Initial revision
X *
X * Revision 1.1 1993/01/15 09:35:27 jpm
X * Initial revision
X *
X *
X */
X
XMalloc_t realloc();
X#define CHUNK 1024 /* # of bytes to bump mem */
X#define error() {\
X fprintf(stderr, "vgets(): out of memory\n"); \
X exit(-1); }
X#define iscomment(c) (((c) == '#') || ((c) == ';')) /* Comment leader */
X#define isshchar(c) ((isalnum(c)) || ((c) == '_')) /* Environment name */
X
X /* Add a character C to line pointer LP. Handle overflow, by
X * re-allocating memory. This will ONLY work inside the main loop.
X */
X#define add(c) \
X *bp++ = c;\
X if (++count >= bytes) {\
X bytes += CHUNK;\
X if ((lp = (char *)realloc(lp, bytes)) == (char *)0)\
X error();\
X bp = lp + count;\
X }
X
X/*
X * This is available to the outside if needed.
X */
Xlong _vgets_linenumber = 0; /* Line number in input */
X
Xchar *vgets(fp)
XFILE *fp;
X{
X static char rcs_id[] = "@(#)$Id: vgets.c,v 1.1 1993/01/18 14:47:58 jpm Exp $";
X Malloc_t malloc();
X static char *lp = (char *)0;
X register char *bp;
X static unsigned long bytes = 0;
X unsigned long count = 0;
X int c, c1;
X static int inquote = 0;
X
X if (!lp) { /* First call */
X if ((lp = (char *)malloc(bytes = CHUNK)) == (char *)0)
X error();
X }
X
X bp = lp;
X ++_vgets_linenumber;
X while ((c = getc(fp)) != EOF) {
X
X /*
X * If we have a comment character, and it is not inside a
X * quote, run thru to the end of the line, discarding input.
X */
X
X if (!inquote && iscomment(c))
X while (((c = getc(fp)) != EOF) && (c != '\n'))
X /* nothing */ ;
X
X if (c == '\n') {
X *bp = '\0';
X if (bp == lp) { /* Empty line because comment */
X ++_vgets_linenumber;
X continue;
X }
X
X /*
X * Strip trailing white space. If the resulting line
X * is "empty", carry on... (don't return empties to
X * caller)
X */
X
X for (--bp; isspace(*bp); )
X *bp-- = '\0';
X if (bp <= lp) {
X ++_vgets_linenumber;
X bp = lp;
X continue;
X }
X return (lp);
X }
X else if (c == '$') { /* Environment variables */
X char varname[64], *vp = varname, *getenv(), *gp;
X
X while (((c = getc(fp)) != EOF) && (isshchar(c)))
X *vp++ = c;
X *vp = 0;
X ungetc(c, fp); /* 1 too many... */
X if ((gp = getenv(varname)) == (char *)0)
X gp = "<<undefined>>";
X while (gp && *gp) {
X add(*gp);
X gp++;
X }
X continue;
X }
X else if (c == '\\') { /* Continuation lines */
X c1 = getc(fp); /* get next char */
X if (c1 == '\n') { /* NL ? */
X ++_vgets_linenumber;
X if (!inquote) { /* Kill white space */
X do {
X c = getc(fp);
X if (c == '\n')
X ++_vgets_linenumber;
X } while (isspace(c));
X ungetc(c, fp);
X }
X continue;
X }
X ungetc(c1, fp); /* Oops! not continuation lin */
X c = backslash('\\', fp);
X }
X
X if (c == '"')
X inquote = !inquote;
X
X add(c);
X }
X if (bp != lp) { /* Left over after EOF ? */
X *bp = '\0';
X return (lp);
X }
X _vgets_linenumber = 0L;
X return ((char *)0);
X}
X
Xstatic int backslash(c, fp)
Xint c;
XFILE *fp;
X{
X static char transl[] = "a\7b\bf\bn\nr\rt\t";
X
X if (c != '\\')
X return (c);
X c = getc(fp);
X
X if (islower(c) && index(transl, c))
X return (index(transl, c))[1];
X return (c);
X}
X
X#ifdef TESTING
Xmain()
X{
X FILE *fp = fopen("file", "r");
X extern long _vgets_linenumber;
X
X char *bp;
X
X while ((bp = vgets(fp)) != NULL)
X printf("(%3ld) [%s]\n",_vgets_linenumber, bp);
X
X}
X#endif /* TESTING */
!STUFFY!FUNK!
echo Extracting conf.c
sed >conf.c <<'!STUFFY!FUNK!' -e 's/X//'
X#include <stdio.h>
X#include <ctype.h>
X#include "config.h"
X#ifdef I_STRING
X# include <string.h>
X#else
X# include <strings.h>
X#endif
X#include "cf.h"
X
X/*
X * $Header: /home/jpm/src/cf/RCS/conf.c,v 1.1 1993/01/18 14:47:48 jpm Exp $
X *
X * $Log: conf.c,v $
X * Revision 1.1 1993/01/18 14:47:48 jpm
X * Initial revision
X *
X * Revision 1.1 1993/01/15 09:34:09 jpm
X * Initial revision
X *
X *
X */
X
X#include "nls/cfnls.h"
X
X#if defined(__STDC__)
X# include <stdarg.h>
X#else
X# include <varargs.h>
X#endif
X
X#ifndef CF_DEFAULT_PATH
X# define CF_DEFAULT_PATH ".:/etc:/usr/local/lib"
X#endif
X
X#ifndef MAXPATHLEN
X# define MAXPATHLEN 256
X#endif
X
X#ifndef CPP
X# define CPP "/lib/cpp"
X#endif
X
Xnl_catd cat;
Xchar _filename[MAXPATHLEN]; /* Current config file */
Xextern long _vgets_linenumber; /* Current line number in config */
X
Xstatic void parse _(( FILE *fp ));
Xstatic int setup _(( char *s ));
Xstatic FILE *cf_fname _(( char *fname, char *mode ));
Xstatic char *stripwhite _(( char *s ));
Xstatic char *split _(( char **bp ));
X
Xint cf_init(list)
Xcfent *list;
X{
X static char rcs_id[] = "@(#)$Id: conf.c,v 1.1 1993/01/18 14:47:48 jpm Exp $";
X cfent *cl;
X
X for (cl = list; cl && cl->name; cl++) {
X TRACE(("cf_init: name=%s, type=%d", cl->name, cl->type));
X
X cf_inst(cl->name, cl->type, cl->min, cl->max, cl->val);
X }
X
X return (CF_OK);
X}
X
X/*
X * Load a set of configuration files. cf_load() is called with any amount of
X * strings, each being a config file. The list must be null-terminated as in
X * exec(2).
X */
X
X#if defined(__STDC__)
Xint cf_load(char *file, ...)
X#else
Xint cf_load(file, va_alist)
Xchar *file;
Xva_dcl
X#endif
X{
X va_list ap;
X char *files[MAX_CF_FILES];
X int n = 0, i;
X FILE *fp;
X extern int errno;
X
X#ifdef __STDC__
X va_start(ap, file);
X#else
X va_start(ap);
X#endif
X
X files[n++] = file;
X while ((files[n++] = va_arg(ap, char *)) != 0)
X ;
X va_end(ap);
X
X for (i = 0; i < (n-1); i++) {
X TRACE(("cf_load(%s)", files[i]));
X if ((fp = cf_fname(files[i], "r")) == (FILE *)0) {
X cf_error(nlm(cfSet, FileNotFound),
X files[i], errno, strerror(errno));
X continue; /* Won't reach if CF_ERREXIT set */
X }
X (void)fclose(fp);
X if ((fp = cpp_popen(CPP, _filename, 0)) == (FILE *)0) {
X cf_error(nlm(cfSet, CantStartCpp),
X CPP, errno, strerror(errno));
X continue;
X }
X parse(fp);
X cpp_pclose(fp);
X }
X return (CF_OK);
X}
X
X
Xstatic void parse(fp)
XFILE *fp;
X{
X char *bp;
X
X while ((bp = vgets(fp)) != (char *)0)
X setup(bp);
X
X}
X
Xstatic int setup(s)
Xchar *s;
X{
X char *tok, *val;
X char token[BUFSIZ], value[BUFSIZ];
X cfsymbol *sp;
X int rc = CF_ERR;
X double atof();
X long lv, atol();
X char var_is_true = 1;
X int n = strlen(s), is_bool = 0;
X
X TRACE(("setup(%s)", s));
X val = s;
X tok = split(&val);
X
X if (*tok == '-' || *tok == '+') /* Boolean */
X {
X var_is_true = (*tok == '-') ? 0 : 1;
X is_bool = 1;
X ++tok;
X }
X
X strcpy(token, stripwhite(tok));
X strcpy(value, stripwhite(val));
X
X TRACE(("\tsetup(%s, %s)", token, value));
X if ((sp = cf_lookup(token)) != (cfsymbol *)0) {
X switch (sp->sym.type) {
X case t_long:
X lv = atol(val);
X if ((_cmin(sp) <= lv) && (lv <= _cmax(sp)))
X _clong(sp) = lv;
X else cf_error(nlm(cfSet, Int2SB), token,
X _cmin(sp), _cmax(sp));
X break;
X case t_dbl:
X _cdouble(sp)= atof(val);
X break;
X case t_str:
X n = strlen(value);
X if ((n <= _cmin(sp)) && (n <= _cmax(sp)))
X {
X if (_cstring(sp) && *_cstring(sp))
X free(_cstring(sp));
X _cstring(sp) = _cf_strsave(value);
X }
X else {
X cf_error(nlm(cfSet, StrLen), token,
X _cmin(sp), _cmax(sp));
X }
X break;
X case t_bol:
X if (strspn(value, " \r\n\t") != strlen(value)) {
X
X /* Variable is boolean, but has a
X * value. Not possible!
X */
X cf_error(nlm(cfSet, BoolHasVal),
X token, _filename,
X _vgets_linenumber, value);
X }
X _cbool(sp) = var_is_true;
X break;
X }
X rc = CF_OK;
X }
X else {
X /*
X * Config not yet known. If flags specify that unkown configs
X * should be ignored, then just insert this one as a string,
X * (unless we know it is bool).
X * Otherwise produce a fatal error.
X */
X
X if ((_cflags() & CF_IGNORE_U) != CF_IGNORE_U) {
X cf_error(nlm(cfSet, UnkownConfVar),
X token, _filename, _vgets_linenumber);
X }
X else {
X if (is_bool)
X cf_inst(token, t_bol, 0, 1, (char *)&var_is_true);
X else
X cf_inst(token, t_str, 1, strlen(value), value);
X }
X }
X return (rc);
X}
X
X/*
X * Open file FNAME in MODE (same as fopen(3)), searching for FNAME over a
X * file path which is retrieved from the environment CF_PATH or the compiled-in
X * version in CF_DEFAULT_PATH. If FNAME begins with a dot or a slash, don't use
X * the path.
X */
X
Xstatic FILE *cf_fname(fname, mode)
Xchar *fname, *mode;
X{
X char *p, *getenv(), *pc;
X char path[MAXPATHLEN];
X char fullpath[MAXPATHLEN];
X FILE *fp;
X extern char _filename[];
X
X /*
X * If the first char is a slash or the first two chars are "./" then
X * just return the open (or not so open) file.
X */
X
X strcpy(_filename,fname);
X if (*fname == '/' || (fname[0] == '.' && fname[1] == '/'))
X return (fopen(fname, mode));
X
X if ((p = getenv("CF_PATH")) == (char *)0)
X p = CF_DEFAULT_PATH;
X
X /*
X * I have to save the content of `p', since it will be destroyed by
X * strtok().
X */
X
X strcpy(path, p);
X for (pc = strtok(path, ":"); pc != (char *)0; pc = strtok(NULL, ":"))
X {
X sprintf(fullpath, "%s/%s", pc, fname);
X TRACE(("Try: cf_fname(%s)", fullpath));
X if ((fp = fopen(fullpath, mode)) != (FILE *)0) {
X TRACE(("Succeeded: cf_fname(%s)", fullpath));
X strcpy(_filename, fullpath);
X return (fp);
X }
X }
X return ((FILE *)0);
X}
X
X#ifdef DEBUG
X#if defined(__STDC__)
Xvoid _cf_trace(char *fmt, ...)
X#else
Xvoid _cf_trace(fmt, va_alist)
Xva_dcl
X#endif
X{
X va_list ap;
X
X#ifdef __STDC__
X va_start(ap, fmt);
X#else
X va_start(ap);
X#endif
X
X vfprintf(stderr, fmt, ap);
X fprintf(stderr, "\n");
X fflush(stderr);
X va_end(ap);
X}
X#endif /* DEBUG */
X
Xstatic char *stripwhite(s)
Xchar *s;
X{
X static char buf[BUFSIZ];
X char *bp = buf;
X
X if (!s || !*s)
X return ("");
X *bp = '\0';
X
X while (s && *s && isspace(*s))
X ++s;
X while (s && *s)
X *bp++ = *s++;
X *bp = '\0';
X
X for (--bp; bp > buf; bp--) {
X if (isspace(*bp))
X *bp = '\0';
X else break;
X }
X return (buf);
X}
X
X/*
X * <white+><token><white+>[=]<white+><alnum+>
X */
X
X#define iskwchar(c) (isalnum(c) || c == '-' || c == '+')
X
Xstatic char *split(bp)
Xregister char **bp;
X{
X register char *name;
X
X for (name = *bp; isspace(*name); ++name) /* white+ */
X ;
X
X for (*bp = name; *++*bp && iskwchar(**bp););
X if (**bp)
X *(*bp)++ = '\0';
X for (; **bp && (isspace(**bp) || **bp == '=' || **bp == ':');++*bp);
X return (name);
X}
!STUFFY!FUNK!
echo Extracting nls/genincl.SH
sed >nls/genincl.SH <<'!STUFFY!FUNK!' -e 's/X//'
Xcase $CONFIG in
X'')
X if test ! -f config.sh; then
X ln ../config.sh . || \
X ln ../../config.sh . || \
X ln ../../../config.sh . || \
X ln ../../../../config.sh . || \
X (echo "Can't find config.sh."; exit 1)
X fi 2>/dev/null
X . ./config.sh
X ;;
Xesac
X: This forces SH files to create target in same directory as SH file.
X: This is so that make depend always knows where to find SH derivatives.
Xcase "$0" in
X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
Xesac
Xecho "Extracting genincl (with variable substitutions)"
X: This section of the file will have variable substitutions done on it.
X: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
X: Protect any dollar signs and backticks that you do not want interpreted
X: by putting a backslash in front. You may delete these comments.
X$spitshell >genincl <<!GROK!THIS!
X$startsh
X# @(#)GENINCL Generate .h file from NLS message base. <j...@Logix.DE>
X# Copyright Jan-Piet Mens, Logix GmbH, Wiesbaden, Germany
X# All rights reserved.
X#
X# ------------ CONFIGURATION SECTION -------------------------------------------
X
XAWK=$awk # The name of your ``awk'' interpreter (awk, nawk, gawk, mawk)
X!GROK!THIS!
X
X: In the following dollars and backticks do not need the extra backslash.
X$spitshell >>genincl <<'!NO!SUBS!'
XMACRO=nlm # The name of the macro for accessing messages
Xext=".m" # Deflt input-filename extension (Should be left alone)
X
X# ------------ END CONFIGURATION SECTION ---------------------------------------
X
Xtmpfile="/tmp/gen-i.$$"
Xtrap "rm -f ${tmpfile};" 1 2 15
Xusage() {
X cat <<! >&2
XUsage: $0 [-h] [-f] [-o includefile] [-d dir] msgfile${ext}
X
X -h Show this message
X -o file Write output into file (default is <msgfile>.h)
X If file is -, write to stdout
X -d dir Output file will be written to <dir>
X -f Force. Create output even if unchanged
X -v Show version
X <msgfile>${ext} Message file (as for gencat(1))
X!
X exit 9
X}
X
Xkopy() {
X if cp $1 $2 >/dev/null 2>&1 ; then
X :
X else
X echo "$0: Can't create output file [$2]" >&2
X rm -f ${tmpfile}
X exit 8
X fi
X}
X
Xoutput=""
Xdirectory="."
Xforce=""
X
Xwhile getopts "fd:vho:" c
Xdo
X case "$c" in
X f) force=TRUE;;
X d) directory="$OPTARG";;
X o) output="$OPTARG";;
X h) usage;;
X v) echo "GENINCL 1.2 by Jan-Piet Mens"; exit 0 ;;
X \?) usage;;
X esac
Xdone
Xshift `expr $OPTIND - 1`
X[ $# -ne 1 ] && { usage ; }
X
Xif [ ! -d "${directory}" ] ; then
X echo "$0: [${directory}] is not a directory" >&2
X exit 3
Xfi
X
Xmsgfile="`basename $1 ${ext}`"
Xmsgfile="${msgfile}${ext}"
Xif [ ! -f "${msgfile}" ] ; then
X echo "$0: Can't open file [${msgfile}]" >&2
X exit 2
Xfi
Xif [ -z "${output}" ] ; then
X output="${directory}/`basename ${msgfile} ${ext}`.h"
Xfi
X
X#
X# This is what our message file looks like:
X#
X# $set 1 Main_Program
X# $ HelloWorld
X# 1 Hello World, how are you ?
X# $ Tilton
X# 2 Bye bye Charlene
X#
X# $ comment
X# $ comment
X# $set 2 IO_errors
X# $ Enoent
X# 3 File not found
X# $ NoHost
X# 4 Can't access host [%s]
X#
X
X# Output conditional code at the top of the .h file for
X# definition of the access-macro to messages. Take into
X# account, that the output may not be processed by an
X# ANSI compiler
X
Xcat <<!--end-- > ${tmpfile}
X/* This file was generated automagically from ${msgfile}
X * Any modifications made here may disappear
X * Change the source and re-run $0
X */
X
X#if defined(HAS_CATOPEN) && defined(HAS_CATGETS)
X# include <nl_types.h>
X# ifndef ${MACRO}
X extern char *catgets();
X extern nl_catd catopen();
X# if defined(__STDC__)
X# define ${MACRO}(set, mno) catgets(cat, (set), (mno), mno##_DFLT)
X# else
X# define ${MACRO}(set, mno) catgets(cat, (set), (mno), mno/**/_DFLT)
X# endif /* __STDC__ */
X# endif /* ${MACRO} */
X#else /* !HAS_CATOPEN && !HAS_CATGETS */
X# ifndef ${MACRO}
X# define nl_catd int
X# define catopen(a, b) 0
X# define catclose(a) /* nothing */
X# if defined(__STDC__)
X# define ${MACRO}(set, mno) mno##_DFLT
X# else
X# define ${MACRO}(set, mno) mno/**/_DFLT
X# endif /* __STDC__ */
X# endif /* ${MACRO} */
X#endif /* HAS_CATOPEN && HAS_CATGETS */
X!--end--
X${AWK} '
XBEGIN {
X token="Identifier_missing_in_input_file"
X }
X
X # A '$set' at the begin of line specifies a SET. Get the number,
X # and output a define for it.
X # All other "$xxx" we ignore ...
X
X /^\$[^ ]/ {
X if ($1 == "$set") {
X if ($3 == "") {
X printf("#error Set number %d has no name in %s\n", $2, FILENAME);
X } else {
X printf("\n#define %sSet (%d)\n", $3, $2)
X }
X }
X continue;
X }
X
X # If we have a "$ " (dollar-space), it is a comment in the messages
X # input file. Use the first word after the comment as a define for
X # the message, whose number appears next.
X
X /^\$ / {
X token=$2
X next
X }
X
X # If we have a number followed by one space, it is a message.
X # Use the last token we found, and build a #define for it.
X # Then clear the token, so that we can introduce an error if the
X # author of the message file forgot to create a "$ token" input
X # line
X # For each token we define, we will also define a token_DFLT containing
X # the default message for catgets(3)
X
X /^[0-9][0-9]* / {
X mno=$1
X $1=""
X txt=$0
X sub("^[ ][ ]*", "", txt);
X printf("#define %s (%d) \n", token, mno);
X printf("#define %s_DFLT \"%s\"\n", token, txt);
X token="Identifier_missing_in_input_file"
X }
X
X' ${msgfile} >> ${tmpfile}
X
X# Should the output go to standard out ?
X
Xif [ "${output}" = "-" ] ; then
X cat ${tmpfile}
X rm -f ${tmpfile}
X exit 0
Xfi
X
X# If our temporary output does not differ from the already present .h file,
X# then we don't copy. This enables us to use the whole thing in a Makefile.
X# This may be overridden by the -f (force) flag
X
Xif [ "${force}" = "TRUE" ] ; then
X kopy ${tmpfile} ${output}
Xelse
X if cmp ${tmpfile} ${output} >/dev/null 2>&1 ; then
X :
X else
X kopy ${tmpfile} ${output}
X fi
Xfi
X
X# If we are called from make, we must touch the output file. This should
X# not be done though, if we call directly from the shell.
X
Xif [ -n "${MAKE}" -o -n "${MAKEFLAGS}" ] ; then
X :
Xelse
X touch ${output}
Xfi
Xrm -f ${tmpfile}
X
Xexit 0
X!NO!SUBS!
Xchmod 755 genincl
X$eunicefix genincl
!STUFFY!FUNK!
chmod +x nls/genincl.SH
echo Extracting nls/genincl.1
sed >nls/genincl.1 <<'!STUFFY!FUNK!' -e 's/X//'
X.TH GENINCL 1 "Logix GmbH" "Local User Commands"
X.SH NAME
Xgenincl \- generate include files from NLS message catalogues
X.SH SYNOPSIS
X.B genincl
X[
X.B -h
X] [
X.B -v
X] [
X.B -f
X] [
X.B -o
X.I outfile
X] [
X.B -d
X.I dir
X]
X.B msgfile
X.SH DESCRIPTION
X.I genincl
Xgenerates C header files from message an NLS (Native Language Support)
Xcatalogue given in
X.BR msgfile .
XThe name of the message file is implicitly specified as
X.IB msgfile .m
Xand
X.I genincl
Xproduces a default output file called
X.IB msgfile .h
Xwhich may be renamed with the
X.B -o
Xoption.
XThe simplest call to
X.I genincl
Xis then
X.PP
X.RS
Xgenincl ifile
X.RE
X.PP
Xwhich will generate an "ifile.h" from "ifile.m".
X.PP
XGenerated output files are stored in the directory given with
Xthe
X.B -d
Xoption, or in the current directory if none is specified. If
X.I genincl
Xdetects that no changes have occurred in the generated header file
Xwith respect to an existing header file, the output file will not be
Xwritten; this allows use of
X.I genincl
Xwith
X.IR make (1).
X.PP
X.SH OPERATION
X.I genincl
Xreads through the given
X.B msgfile
Xand produces
X.B #defines
Xaccording to the following rules:
X.in 1i
XIf a
X.B "$set"
Xkeyword is seen, the set number is used together with the comment behind it
Xto generate a define for a set.
X.sp
XFor each message in a set, two #defines are produced; the first contains the
Xmessage number, whereas the second contains a string which may be used as the
Xdefault string to be returned by
X.IR catgets (3C).
X.PP
XThe header file that is built, forsees use in a non-ANSI-C environment, as
Xwell as an environment in which the NLS routines do not exist. If the
Xprogram which includes the header file is compiled with
X.B "-DNO_NLS"
Xmacros will be generated which insert the default message, whithout calling
Xthe
X.IR catopen (),
X.IR catgets (),
Xand
X.IR catclose ()
Xroutines.
X.SH EXAMPLE
XA sample input file as normally given to
X.IR gencat :
X.PP
X.RS
X.nf
X$set 1 Main
X$ HelloWorld
X1 Hello World, how are you ?
X$ Tilton
X2 Bye bye Charlene
X
X$ This is a comment
X$set 2 IOERRS
X$ Enoent
X3 I cannot open your mailbox. Please check $MAIL
X$ NoHost
X4 Host [%s] is not responding. Try again ?
X.fi
X.RE
X.PP
XWhen
X.I genincl
Xis run on this input file, it produces the following output:
X.PP
X.RS
X.nf
X/* This file was generated automagically from gt.m
X * Any modifications made here may disappear
X * Change the source and re-run ./genincl
X */
X
X#ifndef NO_NLS
X# ifndef nlm
X# include <nl_types.h>
X
X extern char *catgets();
X extern nl_catd catopen();
X# if defined(__STDC__)
X# define nlm(set, mno) catgets(cat, (set), (mno), mno##_DFLT)
X# else
X# define nlm(set, mno) catgets(cat, (set), (mno), mno/**/_DFLT)
X# endif /* __STDC__ */
X# endif /* nlm */
X#else /* NO_NLS */
X# define nl_catd int
X# define catopen(a, b) 0
X# define catclose(a) /* nothing */
X# if defined(__STDC__)
X# define nlm(set, mno) mno##_DFLT
X# else
X# define nlm(set, mno) mno/**/_DFLT
X# endif /* __STDC__ */
X#endif /* NO_NLS */
X
X#define MainSet (1)
X#define HelloWorld (1)
X#define HelloWorld_DFLT "Hello World, how are you this morning ?"
X#define Tilton (2)
X#define Tilton_DFLT "Bye bye Charlene"
X
X#define IOERRSSet (2)
X#define Enoent (3)
X#define Enoent_DFLT "I cannot open your mailbox. Please check $MAIL"
X#define NoHost (4)
X#define NoHost_DFLT "Host [%s] is not responding. Try again ?"
X.fi
X.RE
X.PP
XOur sample application will be
X.PP
X.RS
X.nf
X#include <stdio.h>
X#include <nl_types.h>
X#include <fcntl.h>
X#include "gt.h"
X
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X nl_catd cat;
X char *msg;
X
X if ((cat = catopen("gt", O_RDONLY)) == (nl_catd)-1)
X (fprintf(stderr, "%s: Can't open message-catalogue\en",
X *argv));
X
X msg = nlm(MainSet, HelloWorld);
X puts(msg);
X
X msg = nlm(IOERRSSet, NoHost);
X puts(msg);
X
X catclose(cat);
X}
X
X.RE
X.PP
X.fi
XA sample
X.I makefile
Xfor putting all of the above together would look like this.
X.PP
X.RS
X.nf
XCC=cc
XCFLAGS=-O -I.
XGENINCL=genincl
X
Xall: prog messages.cat
X
Xprog: prog.o
X $(CC) $(CFLAGS) -o $@ $?
Xprog.o: prog.c message.h
X
X# Generate include file for application
Xmessage.h: message.m
X $(GENINCL) message.m
X
X# Generate NLS message catalogue
Xmessage.cat: message.m
X gencat -m message.cat message.m
X
Xclean:
X rm -f *.o message.h message.cat prog
X.fi
X.RE
X.SH OPTIONS
XThe following options are recognized:
X.IP "\fB-h\fR" 1.5i
XHelp. Show usage.
X.IP "\fB-v\fR" 1.5i
XVersion. Show version of
X.IR genincl .
X.IP "\fB-f\fR" 1.5i
XForce creation of an output file, even though
X.I genincl
Xhas discovered that the target has not changed with regard to the original.
XUse of this option is discouraged in makefiles.
X.IP "\fB-o\fR \fIoutfile\fR" 1.5i
XOutput file. Instead of producing a file called
X.IB msgfile .h
Xthe output file will be called
X.BR outfile .
XAs a special case, if
X.B outfile
Xconsists of a single dash, the output will be written to standard output.
X.IP "\fB-d\fR \fIdir\fR" 1.5i
XGenerated files are stored in the directory
X.I dir
Xor in the current directory if
X.I dir
Xis not given.
X.SH FILES
X.IP "\fBfile.m\fR" 1i
XInput files for
X.I genincl
Xconsist of text files which are usually given to
X.IR gencat (1).
X.IP "\fBfile.h\fR" 1i
X.I genincl
Xgenerates source code which is written into an include file for C.
X.SH AUTHOR
XJan-Piet Mens - <j...@Logix.DE>
X.SH SEE ALSO
X.IR gencat (1),
X.IR make (1),
X.IR catopen (3C),
X.IR catgets (3C)
!STUFFY!FUNK!
echo Extracting config_h.SH
sed >config_h.SH <<'!STUFFY!FUNK!' -e 's/X//'
Xcase $CONFIG in
X'')
X if test ! -f config.sh; then
X ln ../config.sh . || \
X ln ../../config.sh . || \
X ln ../../../config.sh . || \
X (echo "Can't find config.sh."; exit 1)
X fi 2>/dev/null
X . ./config.sh
X ;;
Xesac
Xcase "$0" in
X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
Xesac
Xecho "Extracting config.h (with variable substitutions)"
Xsed <<!GROK!THIS! >config.h -e 's!^#undef!/\*#define!'
X/*
X * This file was produced by running the config_h.SH script, which
X * gets its values from config.sh, which is generally produced by
X * running Configure.
X *
X * Feel free to modify any of this as the need arises. Note, however,
X * that running config.h.SH again will wipe out any changes you've made.
X * For a more permanent change edit config.sh and rerun config.h.SH.
X *
X * \$Id: config_h.SH,v 1.1 1993/01/18 14:48:08 jpm Exp $
X */
X
X/* Configuration time: $cf_time
X * Configured by: $cf_by
X * Target system: $myuname
X */
X
X#ifndef _config_h_
X#define _config_h_
X
X/* index:
X * This preprocessor symbol is defined, along with rindex, if the system
X * uses the strchr and strrchr routines instead.
X */
X#$d_index index strchr /**/
X
X/* strerror:
X * This preprocessor symbol is defined as a macro if strerror() is
X * not available to translate error numbers to strings but sys_errlist[]
X * array is there.
X */
X#$d_strerrm strerror(e) ((e)<0||(e)>=sys_nerr?"unknown":sys_errlist[e]) /**/
X
X/* I_FCNTL
X * This manifest constant tells the C program to include <fcntl.h>.
X */
X#$i_fcntl I_FCNTL /**/
X
X/* I_LIMITS:
X * This symbol, if defined, indicates to the C program that it should
X * include <limits.h> to get definition of symbols like WORD_BIT or
X * LONG_MAX, i.e. machine dependant limitations.
X */
X#$i_limits I_LIMITS /**/
X
X/* I_STRING:
X * This symbol, if defined, indicates to the C program that it should
X * include <string.h> (USG systems) instead of <strings.h> (BSD systems).
X */
X#$i_string I_STRING /**/
X
X/* Malloc_t
X * This symbol is the type of pointer returned by malloc and realloc.
X */
X#define Malloc_t $malloctype /**/
X
X/* Pid_t
X * This symbol holds the type used to declare process ids in the kernel.
X * It can be int, uint, pid_t, etc... It may be necessary to include
X * <sys/types.h> to get any typedef'ed information.
X */
X#define Pid_t $pidtype /* PID type */
X
X/* CAN_PROTOTYPE :
X * If defined, this macro indicates that the C compiler can handle
X * function prototypes.
X */
X/* DOTS :
X * This macro is used to specify the ... in function prototypes which
X * have arbitrary additional arguments.
X */
X/* NXT_ARG :
X * This macro is used to separate arguments in the declared argument list.
X */
X/* P_FUNC :
X * This macro is used to declare "private" (static) functions.
X * It takes three arguments: the function type and name, a parenthesized
X * traditional (comma separated) argument list, and the declared argument
X * list (in which arguments are separated with NXT_ARG, and additional
X * arbitrary arguments are specified with DOTS). For example:
X *
X * P_FUNC(int foo, (bar, baz), int bar NXT_ARG char *baz[])
X */
X/* P_FUNC_VOID :
X * This macro is used to declare "private" (static) functions that have
X * no arguments. The macro takes one argument: the function type and name.
X * For example:
X *
X * P_FUNC_VOID(int subr)
X */
X/* V_FUNC :
X * This macro is used to declare "public" (non-static) functions.
X * It takes three arguments: the function type and name, a parenthesized
X * traditional (comma separated) argument list, and the declared argument
X * list (in which arguments are separated with NXT_ARG, and additional
X * arbitrary arguments are specified with DOTS). For example:
X *
X * V_FUNC(int main, (argc, argv), int argc NXT_ARG char *argv[])
X */
X/* V_FUNC_VOID :
X * This macro is used to declare "public" (non-static) functions that have
X * no arguments. The macro takes one argument: the function type and name.
X * For example:
X *
X * V_FUNC_VOID(int fork)
X */
X/* _
X * This macro is used to declare function parameters for folks who want
X * to make declarations with prototypes using a different style than
X * the above macros. Use double parentheses. For example:
X *
X * int main _((int argc, char *argv[]));
X */
X#$prototype CAN_PROTOTYPE /**/
X#ifdef CAN_PROTOTYPE
X#define NXT_ARG ,
X#define DOTS , ...
X#define V_FUNC(name, arglist, args)name(args)
X#define P_FUNC(name, arglist, args)static name(args)
X#define V_FUNC_VOID(name)name(VOID)
X#define P_FUNC_VOID(name)static name(VOID)
X#define _(args) args
X#else
X#define NXT_ARG ;
X#define DOTS
X#define V_FUNC(name, arglist, args)name arglist args;
X#define P_FUNC(name, arglist, args)static name arglist args;
X#define V_FUNC_VOID(name)name()
X#define P_FUNC_VOID(name)static name()
X#define _(args) ()
X#endif
X
X#endif
X!GROK!THIS!
!STUFFY!FUNK!
echo Extracting symb.c
sed >symb.c <<'!STUFFY!FUNK!' -e 's/X//'
X#include <stdio.h>
X#include "config.h"
X#include "cf.h"
X#include "nls/cfnls.h"
X#ifdef __STDC__
X# include <stdarg.h>
X#else
X# include <varargs.h>
X#endif
X#ifdef I_FCNTL
X# include <fcntl.h>
X#endif
X#ifdef I_STRING
X# include <string.h>
X#else
X# include <strings.h>
X#endif
X
X/*
X * $Header: /home/jpm/src/cf/RCS/symb.c,v 1.1 1993/01/18 14:47:56 jpm Exp $
X *
X * $Log: symb.c,v $
X * Revision 1.1 1993/01/18 14:47:56 jpm
X * Initial revision
X *
X * Revision 1.1 1993/01/15 09:35:16 jpm
X * Initial revision
X *
X *
X */
X
Xextern nl_catd cat;
Xstatic unsigned long flags = (CF_ERREXIT);
Xstatic cfsymbol *symlist = NULL;
X
Xstatic char *null();
Xstatic char *xalloc();
Xextern void exit();
X
Xstatic void (*exitfunc)() = exit; /* Name of exit routine */
X
Xunsigned long _cflags()
X{
X return (flags);
X}
X
Xvoid cf_setflags(flagsval)
Xunsigned long flagsval;
X{
X static char rcs_id[] = "@(#)$Id: symb.c,v 1.1 1993/01/18 14:47:56 jpm Exp $";
X static char virgin = 1;
X
X if (virgin) {
X cat = catopen("cf", O_RDONLY);
X virgin = 0;
X }
X flags = flagsval;
X}
X
X/*
X * Output an error-message (printf-like) to stderr, and possibly quit the
X * program. If CF_SILENT is set, the error message will be supressed. If
X * CF_ERREXIT is not set, the application will continue.
X */
X
X#if defined(__STDC__)
Xvoid cf_error(char *fmt, ...)
X#else
Xvoid cf_error(fmt, va_alist)
Xchar *fmt;
Xva_dcl
X#endif
X{
X va_list ap;
X
X#if defined(__STDC__)
X va_start(ap, fmt);
X#else
X va_start(ap);
X#endif
X
X if ((flags & CF_SILENT) != CF_SILENT) {
X fprintf(stderr, "cf: ");
X vfprintf(stderr, fmt, ap);
X fflush(stderr);
X }
X va_end(ap);
X if ((flags & CF_ERREXIT) == CF_ERREXIT) {
X fprintf(stderr, "%s", nlm(cfSet, CFExiting));
X (*exitfunc)(1);
X }
X}
X
X/*
X * Install a value into they cfsymbol table
X */
X
Xint cf_inst(name, type, min, max, value)
Xchar *name;
Xcf_et type;
Xlong min, max;
Xchar *value;
X{
X cfsymbol *sp;
X long atol();
X double atof();
X
X sp = (cfsymbol *)xalloc(sizeof(cfsymbol));
X sp->sym.name = _cf_strsave(name);
X sp->sym.type = type;
X sp->sym.min = min;
X sp->sym.max = max;
X
X switch (type) {
X case t_long:
X sp->sym.val = (char *)xalloc(sizeof(long));
X _clong(sp) = atol(value);
X break;
X case t_dbl:
X sp->sym.val = (char *)xalloc(sizeof(double));
X _cdouble(sp) = atof(value);
X break;
X case t_str:
X _cstring(sp) = _cf_strsave(value);
X break;
X case t_bol:
X sp->sym.val = (char *)xalloc(sizeof(char));
X _cbool(sp) = atoi(value);
X break;
X }
X
X sp->next = symlist;
X symlist = sp;
X
X return (CF_OK);
X}
X
X/*
X * Lookup NAME in the symbol table, and return a cfsymbol pointer to it
X */
X
Xcfsymbol *cf_lookup(name)
Xchar *name;
X{
X cfsymbol *sp;
X
X for (sp = symlist; sp != (cfsymbol *)0; sp = sp->next) {
X if ((*name == *(sp->sym.name)) && !strcmp(name, sp->sym.name))
X return (sp);
X }
X return ((cfsymbol *)0);
X}
X
X/*
X * Return the string value of the config symbol NAME or null() if not
X * found.
X */
X
Xchar *cf_string(name)
Xchar *name;
X{
X cfsymbol *sp = cf_lookup(name);
X
X if (!sp)
X cf_error(nlm(cfSet, SymNotFound), name);
X if (_ctype(sp) != t_str)
X cf_error(nlm(cfSet, SymNotString), name);
X
X return ((sp) ? _cstring(sp) : null());
X}
X
Xchar cf_bool(name)
Xchar *name;
X{
X cfsymbol *sp = cf_lookup(name);
X
X if (!sp)
X cf_error(nlm(cfSet, SymNotFound), name);
X if (_ctype(sp) != t_bol)
X cf_error(nlm(cfSet, SymNotBool), name);
X
X return (_cbool(sp));
X}
X
Xlong cf_long(name)
Xchar *name;
X{
X cfsymbol *sp = cf_lookup(name);
X
X if (!sp)
X cf_error(nlm(cfSet, SymNotFound), name);
X if (_ctype(sp) != t_long)
X cf_error(nlm(cfSet, SymNotInt), name);
X
X return (_clong(sp));
X}
X
Xdouble cf_double(name)
Xchar *name;
X{
X cfsymbol *sp = cf_lookup(name);
X
X if (!sp)
X cf_error(nlm(cfSet, SymNotFound), name);
X if (_ctype(sp) != t_dbl)
X cf_error(nlm(cfSet, SymNotDouble), name);
X
X return (_cdouble(sp));
X}
X
X/*
X * For each element of the cfsymbol table, call FUNC() giving it a cfsymbol
X * pointer. If FUNC returns non-zero, stop.
X */
X
Xint cf_printall(func)
Xint (*func)();
X{
X cfsymbol *sp;
X
X for (sp = symlist; sp != (cfsymbol *)0; sp=sp->next) {
X if ((*func)(&(sp->sym)) != CF_OK)
X return (CF_ERR);
X }
X return (CF_OK);
X}
X
Xstatic char *xalloc(n)
Xunsigned int n;
X{
X Malloc_t malloc();
X
X char *p = (char *)malloc(n);
X
X if (!p)
X return ((char *)0);
X return (p);
X}
X
X/*
X * Return a null representation. If FLAGS has been set up accordingly, a
X * NULL value will be returned; otherwise a string "<<null>>"
X */
Xstatic char *null()
X{
X return ((flags & CF_REALNULL) ? (char *)0 : "<<null>>");
X}
X
Xchar *_cf_strsave(s)
Xchar *s;
X{
X char *p = xalloc(strlen(s)+1);
X
X strcpy(p, s);
X return (p);
X}
!STUFFY!FUNK!
echo Extracting Makefile.SH
sed >Makefile.SH <<'!STUFFY!FUNK!' -e 's/X//'
Xcase $CONFIG in
X'')
X if test ! -f config.sh; then
X ln ../config.sh . || \
X ln ../../config.sh . || \
X ln ../../../config.sh . || \
X ln ../../../../config.sh . || \
X (echo "Can't find config.sh."; exit 1)
X fi 2>/dev/null
X . ./config.sh
X ;;
Xesac
X: This forces SH files to create target in same directory as SH file.
X: This is so that make depend always knows where to find SH derivatives.
Xcase "$0" in
X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
Xesac
Xecho "Extracting Makefile (with variable substitutions)"
X: This section of the file will have variable substitutions done on it.
X: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
X: Protect any dollar signs and backticks that you do not want interpreted
X: by putting a backslash in front. You may delete these comments.
X$spitshell >Makefile <<!GROK!THIS!
XCPP = $cpp
XCC = $cc
XCCFLAGS = -I. -I$usrinc $ccflags $optimize
XOTHERLIBS = $libs
XRANLIB = $ranlib
XSED = $sed
XLIBDIR = $lib
XINCDIR = $inc
XMANEXT = $manext
XMANSRC = $mansrc
XCF_DEFAULT_PATH= $cf_default
X
X!GROK!THIS!
X
X: In the following dollars and backticks do not need the extra backslash.
X$spitshell >>Makefile <<'!NO!SUBS!'
X#########################################################################
X# set DEFS
X#
X# -DNO_NLS You don't have (or want) NLS support routines
X# -DLIMITED_CPP Your cpp complains about too many -D options
X# -DDEBUG Enables trace output (mainly for me :-)
XDEFS= -DLIMITED_CPP
X
XCFLAGS= $(CCFLAGS) $(DEFS) -I.\
X -DCF_DEFAULT_PATH=\"$(CF_DEFAULT_PATH)\" \
X -DCPP=\"$(CPP)\"
X
XLIB=libcf.a
XOBJ=\
X $(LIB)(conf.o)\
X $(LIB)(pipe.o)\
X $(LIB)(symb.o)\
X $(LIB)(vgets.o)
X
XINC= cf.h patchlevel.h config.h
X
Xall: language $(LIB) cftest cf.1
X
Xcftest: cftest.o $(LIB)
X $(CC) $(CCFLAGS) -o cftest cftest.o $(LIB) $(OTHERLIBS)
X
X$(LIB): $(OBJ)
X $(RANLIB) $(LIB)
X
X$(OBJ): $(INC) nls/cfnls.h
Xcftest.o: $(INC)
X
Xcf.1: cf.n
X $(SED) -e 's|__CF_DEFAULT_PATH__|$(CF_DEFAULT_PATH)|g' \
X -e 's|__CPP__|$(CPP)|g' < cf.n > cf.1
X
Xlanguage:
X (cd nls; make)
X
Xinstall: all
X test -d $(LIBDIR) || mkdir $(LIBDIR)
X cp $(LIB) $(LIBDIR)
X chmod 444 $(LIBDIR)/$(LIB)
X test -d $(INCDIR) || mkdir $(INCDIR)
X cp cf.h $(INCDIR)
X chmod 444 $(INCDIR)/cf.h
X test -z "$(MANSRC)" || test -d $(MANSRC) || mkdir $(MANSRC)
X test -z "$(MANSRC)" || cp cf.1 $(MANSRC)/cf.$(MANEXT)
X @echo "Please install NLS files by hand\n\t(see ./INSTALL)"
X
Xclean:
X cd nls && make clean
X rm -f *.o a.out core *# *~ *.orig *.rej cftest cf.1
X
Xclobber: clean
X rm -f $(LIB)
Xdistclean: clobber
X rm -f Wanted config.h config.sh Configure config_h.SH cppstdin Makefile\
X Obsolete cf.h
X cd nls && make distclean
X!NO!SUBS!
Xchmod 755 Makefile
X$eunicefix Makefile
!STUFFY!FUNK!
chmod +x Makefile.SH
echo Extracting demo.cf
sed >demo.cf <<'!STUFFY!FUNK!' -e 's/X//'
X; this is a comment
X/* This is also a comment , because the whole file runs through cpp */
X
X#ifdef unix
X# define tmpdir "/var/tmp"
X terminal-type = $TERM
X#else
X# define tmpdir "C:\\DOS\\TMP"
X terminal-type = PC
X#endif
X
Xtemporary-storage = tmpdir # Must be large enough
Xfull-name = Jan-Piet Mens ; whatever
Xignore-characters = "#;/**/" ; note the quotes
X+bool-true ; boolean TRUE
X-bool-false ; boolean FALSE
X
X#ifdef LIMITED_CPP /* True if compiled with LIMITED_CPP */
X# define PATH CF_PATH
X#endif
X
Xmy-current-path = PATH
Xhome = $HOME
X
Xmaximum-users = 99
Xmax-users = 24
Xfile = netup
Xmy-integer: 999
Xcurrent-config-filename = __FILE__
!STUFFY!FUNK!
echo Extracting hints/svr4.sh
sed >hints/svr4.sh <<'!STUFFY!FUNK!' -e 's/X//'
Xgencat=/usr/bin/gencat
Xawk=/usr/bin/nawk
Xmansrc=/usr/man/man3
Xmanext=3
!STUFFY!FUNK!
echo "End of kit 1 (of 3)"
echo " "
cat /dev/null >kit1isdone
run=''
config=''
for iskit in 1 2 3; do
if test -f kit${iskit}isdone; then
run="$run $iskit"
else
todo="$todo $iskit"
fi
done
case $todo in
'')
echo "You have run all your kits. Please read README and then type Configure."
chmod 755 Configure
rm -f kit*isdone
;;
*) echo "You have run$run."
echo "You still need to run$todo."
;;
esac
: Someone might mail this, so exit before signature...
exit 0
--
__ _____ __ __
| || _ \ | \/ | Logix GmbH +49-611-309797
__| || ___/ | | Moritzstrasse 50 j...@Logix.DE
|_____||__| |__||__| D-6200 Wiesbaden ...!uunet!mcsun!unido!logixwi!jpm
0 new messages