perlman (06/10/82)
.TH VARPAK 3CSL "January 20, 1982" .SH NAME varpak \- string variable handling routines .SH SYNOPSIS .nf #include <varpak.h> extern char varchar, escchar; extern VAR *stdvar; vsetvar (variables, name, value) VAR *variables; char *name, *value; setvar (name, value) char *name, *value; vlsetvar (variables, line) VAR *variables; char *line; lsetvar (line) char *line; vreadvar (variables, filename) VAR *variables; char *filename; readvar (file) char *file; vusetvar (variables) VAR *variables; usetvar (); char *vgetvar (variables, name) VAR *variables; char *name; char *getvar (name) char *name; vtruevar (variables, name) VAR *variables; char *name; truevar (name) char *name; char *vsubvar (variables, string) VAR *variables; char *string; char *subvar (string) char *string; vtravar (variables, func) VAR *variables; extern func (); travar (func) extern func (); func (variable) VAR *variable; vwritevar (variables, file) VAR *variables; char *file; writevar (file) char *file; .fi .br .SH DESCRIPTION These functions provide a general purpose set of tools for developing a user interface in which options are set with variables. All the functions use the VAR datatype defined in <varpak.h> and set and retrieve the values of variables set by name. A variable name is any uninterrupted string of alphanumeric characters, including the underscore. A variable's value can be any string of characters including variables names preceded by the variable accessing character, the above mentioned "varchar," whose default value is the dollar sign, '$'. If the variable accessing character is to be part of a variable's value, it should be preceded by the variable escape character, the above mentioned "escchar," whose default value is the backslash, '\\'. The escape character is also useful to include leading blank space in a variable's value. Usually, it is necessary to add an escape character before the escape character, a bad feature of such characters. For each function, there is a simpler version defined as a macro in <varpak.h>. Using the macros saves the programmer from having to learn about and use the VAR datatype. These simpler macros assume the standard VAR, \fIstdvar\fR, which is hidden from the programmer, is to be used. \fIVsetvar\fR sets the variable \fIname\fR to \fIvalue\fR. If \fIvalue\fR contains any variables, identified by preceding their names with the variable accessing character, which by default is the dollar sign, '$', then \fIvgetvar\fR substitutes their values. If these variables have no values, a null string is substituted in their place. \fIVsetvar\fR is used by all the functions setting variables and so determines how all the other functions work. If the name of the variable being set is "readvar" then \fIvsetvar\fR calls \fIvreadvar\fR to read from the file named by the value argument to \fIvsetvar\fR. If the value is NULL, then the file read from is the standard input, and the user is allowed to set variables interactively. If the name of the variable being set is "writevar" then \fIvsetvar\fR calls \fIvwritevar\fR to write all the variable so far set to the file named by the value argument to \fIvsetvar\fR. If the value is NULL, then the file written to is the standard output. \fIVlsetvar\fI sets variables with a single argument, a line of the form: .ce NAME = VALUE which gets interpreted and passed off to \fIvsetvar\fR as: .ce vsetvar (variables, "NAME", "VALUE"); Leading blank space around an optional variable accessing character is ignored, as is any blank space around the optional equal sign. \fIVreadvar\fR reads variables from a file. The lines of the file are read by \fIvlsetvar\fR, which, in turn, are interpreted by \fIvsetvar\fR. \fIVusetvar\fR interacts with users at their terminal, which is assumed to have the right tty status (ECHO + COOKED modes, see \fIstty(2)\fR). Users are prompted for names and values and are given the option to see the values of variables so far set, and abort if that is desired. While setting variables interactively, users can read from files of variables by setting the pseudo variable called "readvar" or write to a file by setting the pseudo variable called writevar. \fIVgetvar\fR is the basic function for getting the values of variables. It returns a char pointer to the value of its named variable argument if it exists, otherwise, it returns a NULL pointer. \fIVtruevar\fR is useful for determining whether a Boolean variable is true or false. If the variable named is unset, \fIvtruevar\fR returns 0 (false), and if it is set, but has no value, then it returns 1 (true). For all the follwoing values, \fIvtruevar\fR returns 1, and except for previous notes, 0. .ce true yes t y 1 \fIVwritevar\fR writes all the set variables' names and values to the named file, and to the standard output if the named file is NULL. It can be called from within a variable setting file, read by \fIvreadvar\fR, or from within the interactive variable setting function, \fIvusetvar\fR, by setting the pseudo variable, "writevar." \fIVwritevar\fR uses the function \fIvtravar\fR to traverse the variables of its VAR pointer argument. \fIVtravar\fR can be used to apply some function to each entry in a set of variables. \fIVsubvar\fR does variable substitution, sometimes called interpolation. \fIVsubvar\fR copies its string argument verbatim except where it sees the variable accessing character, the so-called "varchar" (by default, the dollar sign, '$'), mentioned above, in which case it looks after the $ and substitutes the value of the variable of the name it finds. This substitution can be avoided by preceding the $ by the variable escape character, the so-called "varchar (default value is the backslash, '\\'). .SH EXAMPLE .PP The following main program will read in variables from its first argument, then let the user print and set them interactively, and finally print them out to the second argument. .nf .in 1.5i #include <varpak.h> main (argc, argv) char **argv; { readvar (argv[1]); usetvar (); writevar (argv[2]); } .in 0 .fi .SH DIAGNOSTICS .PP The functions tend to do their work silently, returning zero or NULL when nothing can be found. .SH SEE\ ALSO .PP The Interface Arsenal: Software Tools for User Interface Development Varpak Reference Guide. .SH AUTHOR Gary Perlman =M=A=K=E=F=I=L=E===================================================== varpak: varpak.o cc -c varpak.o echo "nothin' to it" =V=A=R=P=A=K=.=H===================================================== #include <stdio.h> #include <ctype.h> extern char escchar; extern char varchar; typedef struct varpair { char *name, *value; struct varpair *left, *right; } VAR; extern VAR *stdvar; char *vsubvar (); /* variables, string */ int vsetvar (); /* variables, name, value */ int vusetvar (); /* variables */ int vlsetvar (); /* variables, line */ VAR *newvar (); /* name, value */ int vreadvar (); /* variables, file */ int vtruevar (); /* variables, name */ char *vgetvar (); /* variables, name */ int vwritevar (); /* variables, file */ extern vfreevar (); /* variables */ extern vtravar (); /* func (VAR *) */ #define subvar(s) vsubvar(stdvar,s) #define setvar(n,v) vsetvar(stdvar,n,v) #define freevar() vfreevar(stdvar); #define usetvar() vusetvar(stdvar) #define lsetvar(line) vlsetvar(stdvar,line) #define readvar(f) vreadvar(stdvar,f) #define truevar(n) vtruevar(stdvar,n) #define getvar(n) vgetvar(stdvar,n) #define writevar(f) vwritevar(stdvar,f) #define travar(f) vtravar(stdvar,f) =V=A=R=P=A=K=.=C=================================================== #include <stdio.h> #include <ctype.h> char escchar = '\\'; char varchar = '$'; typedef struct varpair { char *name, *value; struct varpair *left, *right; } VAR; VAR initstdvar, *stdvar = &initstdvar; char *vsubvar (); /* variables, string */ int vsetvar (); /* variables, name, value */ int vusetvar (); /* variables */ int vlsetvar (); /* variables, line */ VAR *newvar (); /* name, value */ int vreadvar (); /* variables, file */ int vtruevar (); /* variables, name */ char *vgetvar (); /* variables, name */ extern vwritevar (); /* variables */ char *fgetline (); /* s, ioptr */ extern vfreevar (); /* variables */ #define skipspace(s) while(isspace(*s))s++; #define isvarname(c) (isalnum(c)||c=='_') #define copy(s) (strcpy(malloc((unsigned)strlen(s)+1),s)) char *strcpy (), *malloc (); VAR * newvar (name, value) char *name, *value; { VAR *newvar = (VAR *) calloc (1, sizeof (VAR)); if (newvar) { if (name) newvar->name = copy (name); if (value) newvar->value = copy (value); } return (newvar); } vfreevar (variables) VAR *variables; { if (variables == NULL) return; if (variables->name) free (variables->name); if (variables->value) free (variables->value); vfreevar (variables->left); vfreevar (variables->right); free (variables); } vsetvar (variables, name, value) VAR *variables; char *name, *value; { int cmp; if (variables == NULL || name == NULL || *name == NULL) return (0); value = vsubvar (variables, value); if (vtruevar (variables, "DEBUG")) printf ("vsetvar: '%s'='%s'\n", name, value); if (!strcmp (name, "readvar")) return (vreadvar (variables, value)); if (!strcmp (name, "writevar")) return (vwritevar (variables, value)); if (variables->name == NULL) { variables->name = copy (name); variables->value = copy (value); return (variables->name && variables->value); } while (variables) if ((cmp = strcmp (name, variables->name)) > 0) if (variables->right == NULL) return ((variables->right = newvar (name, value)) != NULL); else variables = variables->right; else if (cmp < 0) if (variables->left == NULL) return ((variables->left = newvar (name, value)) != NULL); else variables = variables->left; else /* match */ { free (variables->value); return ((variables->value = copy (value)) != NULL); } } vlsetvar (variables, lineptr) VAR *variables; char *lineptr; { char namebuf[BUFSIZ], *nameptr; char *ptr; if (!variables || !lineptr) return (0); if (vtruevar (variables, "DEBUG")) printf ("vlsetvar: '%s'\n", lineptr); skipspace (lineptr); if (*lineptr == varchar) { lineptr++; skipspace (lineptr); } if (!*lineptr) return (1); nameptr = namebuf; *nameptr = NULL; while (isvarname (*lineptr)) *nameptr++ = *lineptr++; *nameptr = NULL; skipspace (lineptr); if (*lineptr == '=') lineptr++; skipspace (lineptr); ptr = lineptr; while (*ptr) ptr++; if (ptr > lineptr && (*(ptr-1) == '\n')) *(ptr-1) = NULL; return (vsetvar (variables, namebuf, lineptr)); } char * fgetline (s, ioptr) register char *s; FILE *ioptr; { char *base = s; *s = NULL; while ((*s = fgetc (ioptr)) != EOF) if (*s == escchar) *s++ = fgetc (ioptr); else if (*s == '\n') break; else s++; if (*s == EOF && s == base) return (NULL); *s = NULL; return (base); } vreadvar (variables, filename) VAR *variables; char *filename; { char line[BUFSIZ]; FILE *ioptr, *fopen (); if (variables == NULL) return (0); if (vtruevar (variables, "DEBUG")) printf ("vreadvar: '%s'\n", filename); if (filename == NULL || *filename == NULL) { while (vusetvar (variables)); return (1); } if ((ioptr = fopen (filename, "r")) == NULL) return (0); while (fgetline (line, ioptr)) if (vlsetvar (variables, line) == 0) { fclose (ioptr); return (0); } fclose (ioptr); return (1); } char * vgetvar (variables, varname) VAR *variables; char *varname; { int cmp; while (variables) if ((cmp = strcmp (varname, variables->name)) > 0) variables = variables->right; else if (cmp < 0) variables = variables->left; else return (variables->value); return (NULL); } truth (s) char *s; { if (!s) return (0); if (*s == NULL) return (1); if (strlen (s) == 1) switch (*s) { case '1': case 'y': case 't': return (1); } return (!strcmp (s, "true") || !strcmp (s, "yes")); } vtruevar (variables, varname) VAR *variables; char *varname; { char *val; if (!varname || !variables) return (0); if ((val = vgetvar (variables, varname)) == NULL) return (0); return (truth (val)); } char * vsubvar (variables, s) VAR *variables; char *s; { static char vsubvar[BUFSIZ]; char *interptr = vsubvar; char varname[BUFSIZ], *ptr; extern char varchar, escchar; *vsubvar = NULL; if (!variables) return (s); while (*s) if (*s == varchar) { s++; ptr = varname; while (isvarname (*s)) *ptr++ = *s++; *ptr = NULL; if (ptr = vgetvar (variables, varname)) { strcpy (interptr, ptr); while (*interptr) interptr++; } } else if (*s == escchar) { s++; *interptr++ = *s++; } else *interptr++ = *s++; *interptr = NULL; return (vsubvar); } vtravar (variables, func) VAR *variables; int (*func)(); { if (variables == NULL) return; vtravar (variables->left, func); (*func) (variables); vtravar (variables->right, func); } FILE *pvarioptr; vwritevar (variables, filename) VAR *variables; char *filename; { extern vprintvar (); if (variables == NULL) return (0); if (filename == NULL || *filename == NULL) pvarioptr = stdout; else if ((pvarioptr = fopen (filename, "w")) == NULL) return (0); vtravar (variables, vprintvar); if (pvarioptr != stdout) fclose (pvarioptr); } vprintvar (variables) VAR *variables; { fprintf (pvarioptr, "%15s = ", variables->name); fprintf (pvarioptr, "%s\n", *variables->value ? variables->value : "(null)"); } vusetvar (variables) VAR *variables; { char name[BUFSIZ], value[BUFSIZ]; char *vptr; char *noeffect = "(RETURN to abort)"; if (variables == NULL) return (0); printf ("enter variable name (RETURN for list): "); gets (name); if (*name == NULL) { vwritevar (variables, NULL); printf ("enter variable name, %s: ", noeffect); gets (name); if (*name == NULL) return (0); } if (vptr = vgetvar (variables, name)) { printf ("%c%s = %s\n", varchar, name, vptr); printf ("enter new value %s: ", noeffect); } else printf ("enter value %s: ", noeffect); gets (value); if (*value == NULL) return (0); if (vsetvar (variables, name, value) == 0) return (0); printf ("%c%s = %s\n", varchar, name, vgetvar (variables, name)); return (1); }