summaryrefslogtreecommitdiffstats
path: root/xpa/word.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpa/word.c')
-rw-r--r--xpa/word.c1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/xpa/word.c b/xpa/word.c
new file mode 100644
index 0000000..2d60eb0
--- /dev/null
+++ b/xpa/word.c
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory
+ */
+
+/*
+ * word.c -- token parser, pattern matcher, macro expander,
+ * and other word-related routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <word.h>
+
+/* SAOMOD_CTYPE -- work around Slackware/RedHat incompatibility */
+#ifdef linux
+#ifdef isalnum
+#undef isalnum
+#define isalnum(c) (isalpha(c)||isdigit(c))
+#endif
+#endif
+
+/* **************************************************************************
+ *
+ *
+ * PRIVATE ROUTINES AND DATA
+ *
+ *
+ * **************************************************************************/
+
+/* word */
+#define MAXDELIM 256
+#define MAXDTABLES 1024
+#define BUFINC 5000
+
+static char lastd;
+static char dtable[MAXDELIM];
+static char *dtables[MAXDTABLES];
+static int ndtable=0;
+
+/* tmatch */
+#define ALL '*'
+#define ANY '?'
+#define RANGE '['
+#define ENDRANGE ']'
+#define RANGEDELIM '-'
+#define NOTRANGE '~'
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: checkrange (from tmatch)
+ *
+ * Purpose: see if character is in specified range
+ *
+ * Returns: 1 if in range, otherwise 0
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static int
+checkrange (char *xtemplate, int *ptr, int c)
+#else
+static int checkrange(xtemplate, ptr, c)
+ char *xtemplate;
+ int *ptr;
+ int c;
+#endif
+{
+ int inrange, notrange;
+ char lorange, hirange;
+ int tptr;
+
+ tptr = *ptr;
+ /* make sure we have a close bracket */
+ if( strchr(&xtemplate[tptr], ENDRANGE) == NULL )
+ return(0);
+ /* check for negation - match if not in range */
+ if( xtemplate [tptr+1] == NOTRANGE ){
+ notrange = 1; tptr++;
+ }
+ else
+ notrange = 0;
+ /* start pessimistically */
+ inrange = 0;
+ /* point past RANGE character */
+ tptr++;
+ while( xtemplate[tptr] != ENDRANGE ){
+ /* get lo range */
+ lorange = xtemplate[tptr];
+ /* and hi range */
+ tptr++;
+ if( xtemplate[tptr] != RANGEDELIM )
+ hirange = lorange;
+ else{
+ tptr++;hirange = xtemplate[tptr];tptr++;
+ }
+ if( (c>=lorange) && (c<=hirange) ){
+ inrange = 1; break;
+ }
+ }
+ /* only exclusive OR of inrange and notrange is ok */
+ if( (inrange ^ notrange) ==0 )
+ return(0);
+ else{
+ *ptr = strchr(&xtemplate[tptr],']') - xtemplate + 1;
+ return(1);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: addstring (from macro)
+ *
+ * Purpose: add a string to a buffer
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static void
+addstring (char **buf, int *blen, int *maxlen, char *str)
+#else
+static void addstring(buf, blen, maxlen, str)
+ char **buf;
+ int *blen;
+ int *maxlen;
+ char *str;
+#endif
+{
+ int slen;
+
+ slen = strlen(str) + 1;
+ while( (*blen + slen) >= *maxlen ){
+ *maxlen += BUFINC;
+ *buf = (char *)xrealloc(*buf, *maxlen);
+ }
+ strcat(*buf, str);
+ *blen += slen;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: addchar (from macro)
+ *
+ * Purpose: add a single char to a buffer
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static void
+addchar (char **buf, int *blen, int *maxlen, int c)
+#else
+static void addchar(buf, blen, maxlen, c)
+ char **buf;
+ int *blen;
+ int *maxlen;
+ int c;
+#endif
+{
+ char tbuf[2];
+
+ tbuf[0] = c;
+ tbuf[1] = '\0';
+ addstring(buf, blen, maxlen, tbuf);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: lookupkeywords (from macro)
+ *
+ * Purpose: lookup a name in a list of keywords
+ *
+ * Returns: return the associated value or NULL
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static char *
+lookupkeywords (char *name, char **keyword, char **value, int nkey)
+#else
+static char *lookupkeywords(name, keyword, value, nkey)
+ char *name;
+ char **keyword;
+ char **value;
+ int nkey;
+#endif
+{
+ int i;
+ for(i=0; i<nkey; i++){
+ if( !strcmp(name, keyword[i]) )
+ return(value[i]);
+ }
+ return(NULL);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: hexval (from strtoul16)
+ *
+ * Purpose: return the int value corresponding to a hex character
+ *
+ * Returns: hex value or -1 if the character is not legal hex
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static int
+hexval (int c)
+#else
+static int hexval(c)
+ int c;
+#endif
+{
+ switch(c){
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'A': return 10;
+ case 'a': return 10;
+ case 'B': return 11;
+ case 'b': return 11;
+ case 'C': return 12;
+ case 'c': return 12;
+ case 'D': return 13;
+ case 'd': return 13;
+ case 'E': return 14;
+ case 'e': return 14;
+ case 'F': return 15;
+ case 'f': return 15;
+ default: return -1;
+ }
+}
+
+/* **************************************************************************
+ *
+ *
+ * PUBLIC ROUTINES
+ *
+ *
+ * **************************************************************************/
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: word
+ *
+ * Purpose: a simple spaced parser
+ *
+ * Returns: 1 if word was found, else 0
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+word (char *lbuf, char *tbuf, int *lptr)
+#else
+int word(lbuf, tbuf, lptr)
+ char *lbuf;
+ char *tbuf;
+ int *lptr;
+#endif
+{
+ int ip;
+ int i;
+ char quotes;
+
+ /* reset last delimiter */
+ lastd='\0';
+
+ /* null out the output string */
+ *tbuf = '\0';
+
+ /* if no string was specified, just return */
+ if( lbuf == NULL )
+ return(0);
+
+ /* just a more convenient pointer ... */
+ ip = *lptr;
+
+ /* if we are at the end of string, just return */
+ if( lbuf[ip] == '\0' )
+ return(0);
+
+ /* skip over white space */
+ while( isspace((int)lbuf[ip]) || (dtable[(int)lbuf[ip]]>0) ){
+ if( lbuf[ip] == '\0' ){
+ *lptr = ip;
+ return(0);
+ }
+ else
+ ip++;
+ }
+
+ /* check for an explicit quote */
+ quotes = '\0';
+ if( lbuf[ip] == '"' ){
+ quotes = '"';
+ lastd = '"';
+ }
+ if( lbuf[ip] == '\'' ){
+ quotes = '\'';
+ lastd = '\'';
+ }
+
+ /* grab next token */
+ if( quotes != '\0' ){
+ /* bump past quotes */
+ ip++;
+ /* grab up to next quotes -- but skip escaped quotes */
+ for(i=0; lbuf[ip] != '\0'; i++, ip++){
+ if( (lbuf[ip] == quotes) && (lbuf[ip-1] != '\\') )
+ break;
+ else
+ tbuf[i] = lbuf[ip];
+ }
+ }
+ else{
+ /* grab up to next whitespace */
+ for(i=0;
+ lbuf[ip] && !isspace((int)lbuf[ip]) && (dtable[(int)lbuf[ip]]==0);
+ i++, ip++)
+ tbuf[i] = lbuf[ip];
+ /* save this delimiter */
+ lastd = lbuf[ip];
+ }
+ /* bump past delimiter (but not null terminator) */
+ if( lbuf[ip] )
+ ip++;
+
+ /* null terminate */
+ tbuf[i] = '\0';
+
+ /* got something */
+ *lptr = ip;
+ return(1);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: newdtable
+ *
+ * Purpose: save the current delim table and init a new one
+ *
+ * Returns: 1 if another delim table can be allocated, 0 otherwise
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+newdtable (char *s)
+#else
+int newdtable(s)
+ char *s;
+#endif
+{
+ int i;
+ char *cur;
+
+ if( ndtable >= MAXDTABLES ){
+ fprintf(stderr, "ERROR: no more delimiter tables available\n");
+ return(0);
+ }
+ /* save another dtable */
+ ndtable++;
+ /* allocate new space for this table */
+ dtables[ndtable-1] = (char *)xmalloc(MAXDELIM);
+ cur = dtables[ndtable-1];
+ /* copy and zero the old table */
+ for(i=0; i<MAXDELIM; i++){
+ cur[i] = dtable[i];
+ dtable[i] = 0;
+ }
+ /* add delims to the new table */
+ if( s != NULL ){
+ for(; *s; s++)
+ dtable[(int)*s] = 1;
+ }
+ return(1);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: freedtable
+ *
+ * Purpose: restore last delim table as the current
+ *
+ * Returns: 1 if there is a table to restore, else 0
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+freedtable (void)
+#else
+int freedtable()
+#endif
+{
+ int i;
+ char *cur;
+
+ if( ndtable <= 0 ){
+ fprintf(stderr, "ERROR: no delimiter tables to restore\n");
+ return(0);
+ }
+ cur = dtables[ndtable-1];
+ /* copy the restored table into 'current' */
+ for(i=0; i<MAXDELIM; i++){
+ dtable[i] = cur[i];
+ }
+ /* free up this dtable */
+ xfree((void *)cur);
+ /* one less dtable to worry about */
+ ndtable--;
+ return(1);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: newdelim
+ *
+ * Purpose: add a string delimiters to the parse table
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+void
+newdelim (char *s)
+#else
+void newdelim(s)
+ char *s;
+#endif
+{
+ if( s != NULL ){
+ for(; *s; s++)
+ dtable[(int)*s] = 1;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: freedelim
+ *
+ * Purpose: remove delims from current delim table
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+void
+freedelim (char *s)
+#else
+void freedelim(s)
+ char *s;
+#endif
+{
+ int i;
+
+ if( s ){
+ for(; *s; s++)
+ if( dtable[(int)*s] > 0 )
+ dtable[(int)*s] -= 1;
+ }
+ else{
+ for(i=0; i<MAXDELIM; i++)
+ if( dtable[i] > 0 )
+ dtable[i] -= 1;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: lastdelim
+ *
+ * Purpose: return the last delimiter
+ *
+ * Returns: delim character
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+lastdelim (void)
+#else
+int lastdelim()
+#endif
+{
+ return((int)lastd);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: tmatch
+ *
+ * Purpose: match string to a template
+ *
+ * the legal meta characters in a template are just like the
+ * C-shell meta characters, i.e:
+ * ? match any character, but there must be one
+ * * match anything, or nothing
+ * [<c>...] match an inclusive set
+ *
+ *
+ * Returns: non-zero if match, zero otherwise
+
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+tmatch (char *string, char *xtemplate)
+#else
+int tmatch(string, xtemplate)
+ char *string;
+ char *xtemplate;
+#endif
+{
+ char *lastmeta=0;
+ char *nonabsorbed=0;
+ int sptr=0;
+ int tptr=0;
+
+ /* loop through string and template */
+ while( (xtemplate[tptr] != '\0') || (string[sptr] != '\0') ){
+ /* if exact match, just bump both pointers */
+ if( string[sptr] == xtemplate[tptr] ){
+ sptr++; tptr++; continue;
+ }
+ /* if range character, check ranges */
+ if( xtemplate[tptr] == RANGE ){
+ if( checkrange(xtemplate, &tptr, string[sptr]) == 0 ){
+ /* no match - was there a meta character before */
+ if( lastmeta == 0 ) return(0);
+ /* if so, back up to it and try again */
+ xtemplate = lastmeta; tptr=0;
+ /* begin checking at the non-absorbed point */
+ string = nonabsorbed; sptr=0;
+ continue;
+ }
+ /* got a match, so bump past */
+ else{
+ sptr++; continue;
+ }
+ }
+ /* if ANY, any character if fine, but there must be one */
+ if( xtemplate[tptr] == ANY ){
+ if( string[sptr] == '\0' )
+ return(0);
+ else{
+ sptr++; tptr++; continue;
+ }
+ }
+ /* if ALL, we can match anything */
+ if( xtemplate[tptr] == ALL ){
+ /* remember where the * is */
+ lastmeta = &xtemplate[tptr];
+ tptr++;
+ /* no more template after this means a win */
+ if( xtemplate[tptr] == '\0' ) return(1);
+ /* if the next template char is not a meta,
+ we skip up to its match in the string */
+ if( xtemplate[tptr] == RANGE){
+ while( checkrange(xtemplate, &tptr, string[sptr]) == 0 ){
+ /* missing the next template char */
+ if( string[sptr] == '\0' ) return(0);
+ sptr++;
+ }
+ /* remember the first non-absorbed character */
+ nonabsorbed = &string[sptr];nonabsorbed++;
+ sptr++;
+ continue;
+ }
+ /* skip past characters, if next template char is not a meta */
+ else if( xtemplate[tptr] != ANY && xtemplate[tptr] != ALL ){
+ while(string[sptr] != xtemplate[tptr]){
+ /* not finding the next template char
+ is bad */
+ if( string[sptr] == '\0' ) return(0);
+ sptr++;
+ }
+ /* remember the first non-absorbed character */
+ nonabsorbed = &string[sptr];nonabsorbed++;
+ continue;
+ }
+ else{
+ /* remember the first non-absorbed character */
+ nonabsorbed = &string[sptr];nonabsorbed++;
+ continue;
+ }
+ }
+ /* no match, no meta char - see if we once had a meta */
+ else{
+ if( lastmeta == 0 ) return(0);
+ /* if so, back up to it and try again */
+ xtemplate = lastmeta; tptr=0;
+ /* begin checking at the non-absorbed point */
+ string = nonabsorbed; sptr=0;
+ continue;
+ }
+ }
+ /* matched to the nulls - we win */
+ return(1);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: keyword
+ *
+ * Purpose: look for a keyword=<value> string inside another string,
+ * remove and return the <value> in another buffer
+ *
+ * Returns: len if keyword was found, 0 otherwise
+ *
+ * NB: ibuf cannot be static, as it is modified in place
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+keyword (char *ibuf, char *key, char *obuf, int maxlen)
+#else
+int keyword(ibuf, key, obuf, maxlen)
+ char *ibuf;
+ char *key;
+ char *obuf;
+ int maxlen;
+#endif
+{
+ int len;
+ int qlev;
+ char *s;
+ char *t;
+ char *u;
+ char *v;
+ char *iptr;
+ char quote;
+
+ /* if we have no input string, we are done */
+ if( (ibuf == NULL) || (*ibuf == '\0') ){
+ return(0);
+ }
+
+ /* start out pessimistically */
+ *obuf = '\0';
+ iptr = ibuf;
+
+ /* maxlen generally is 1 more than we can handle */
+ maxlen--;
+
+ /* keep trying */
+ while( *iptr ){
+ /* look for key from current position */
+ if( (s = (char *)strstr(iptr, key)) == NULL )
+ return(0);
+ /* if we found a key, we need to make sure ... */
+ /* it must be preceeded by beginning of string, beginning of bracket,
+ or by a "," from previous keyword */
+ if( (s == ibuf) || (*(s-1) == ',') || (*(s-1) == '[') ){
+ /* it can be followed by spaces ... */
+ t = s + strlen(key);
+ while( isspace((int)*t) )
+ t++;
+ /* but must be followed by an "=" */
+ if( *t == '=' ){
+ t++;
+ /* skip spaces again */
+ while( isspace((int)*t) )
+ t++;
+ /* this is where the actual value part of the string begins */
+ u = t;
+ /* this will be where it ends */
+ v = t;
+ /* gather up everything to the next "," or end of filter */
+ if( (*t == '"') || (*t == '\'') || (*t == '(') || (*t == '[') ){
+ switch(*t){
+ case '"':
+ case '\'':
+ quote = *t;
+ break;
+ case '(':
+ quote = ')';
+ break;
+ case '[':
+ quote = ']';
+ break;
+ }
+ /* bump past opening quote char */
+ t++; u++; v++;
+ while( *t && (*t != quote) ){
+ t++; v++;
+ }
+ if( *t == quote ){
+ t++;
+ }
+ }
+ else{
+ qlev = 0;
+ while( *t &&
+ ((qlev != 0) || (*t != ',')) &&
+ ((qlev != 0) || (*t != ']')) ){
+ if( *t == '[' )
+ qlev++;
+ else if( *t == ']' )
+ qlev--;
+ t++; v++;
+ }
+ }
+ len = MIN(maxlen, v - u);
+ strncpy(obuf, u, len);
+ obuf[len] = '\0';
+ /* remove keyword=value string from the original buffer */
+ /* first remove preceding comma, if necessary */
+ if( (s > ibuf) && (*(s-1) == ',') )
+ s--;
+ /* but leave 1 comma in place */
+ else if( *t == ',' )
+ t++;
+ /* now overwrite original from where the keyword started */
+ memmove(s, t, strlen(t)+1);
+ return(len);
+ }
+ }
+ /* start next search just past this one */
+ iptr = s+1;
+ }
+ return(0);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: macro
+ *
+ * Purpose: expand a macro using a client's callback
+ *
+ * Returns: expanded macro as an allocated string
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+char *
+macro (char *icmd, char **keyword, char **value, int nkey,
+ MacroCB client_callback, void *client_data)
+#else
+char *macro(icmd, keyword, value, nkey, client_callback, client_data)
+ char *icmd;
+ char **keyword;
+ char **value;
+ int nkey;
+ MacroCB client_callback;
+ void *client_data;
+#endif
+{
+ int i, j;
+ int maxlen;
+ char brace;
+ char *result;
+ char tbuf[1000];
+ char tbuf1[1000];
+ char *s;
+ char *ip;
+ char *mip;
+
+ /* make a new string using the command as a base, but substituting
+ for "$" values as needed */
+ result = (char *)xmalloc(BUFINC+1);
+ maxlen = BUFINC;
+ *result = '\0';
+ for(i=0, ip=icmd; *ip; ip++){
+ if( *ip != '$' ){
+ addchar(&result, &i, &maxlen, *ip);
+ }
+ else{
+ /* save beginning of macro */
+ mip = ip;
+ /* skip past '$' */
+ ip++;
+ /* check for brace mode */
+ if( *ip == '{' ){
+ brace = '{';
+ ip++;
+ }
+ else if( *ip == '(' ){
+ brace = '(';
+ ip++;
+ }
+ else
+ brace = '\0';
+ /* get variable up to next non-alpha character or close brace */
+ for(*tbuf='\0', j=0; *ip; ip++ ){
+ /* if we are in brace mode, look for trailing brace */
+ if( brace && *ip == (brace == '(' ? ')' : '}') ){
+ ip++;
+ break;
+ }
+ /* else look for a non-alpha character */
+ else if( !isalnum((int)*ip) && *ip != '_'){
+ break;
+ }
+ else{
+ tbuf[j++] = *ip;
+ tbuf[j] = '\0';
+ }
+ }
+ /* back up so the outer loop adds this delimiting char to the output */
+ ip--;
+ /* search for keyword from the list */
+ if( (nkey > 0) &&
+ (s=lookupkeywords(tbuf, keyword, value, nkey)) != NULL ){
+ addstring(&result, &i, &maxlen, s);
+ }
+ /* execute the client routine to expand macros */
+ else if( (client_callback != NULL) &&
+ ((s=(*client_callback)(tbuf, client_data)) != NULL) ){
+ addstring(&result, &i, &maxlen, s);
+ }
+ /* look for an environment variable */
+ else if( (s = (char *)getenv(tbuf)) != NULL ){
+ addstring(&result, &i, &maxlen, s);
+ }
+ /* if we don't recognize this macro, put it back onto the string */
+ else{
+ int len;
+ len = ip - mip + 1;
+ strncpy(tbuf1, mip, len);
+ tbuf1[len] = '\0';
+ addstring(&result, &i, &maxlen, tbuf1);
+ }
+ }
+ }
+ /* null terminate and save the string */
+ result[i] = '\0';
+ result = (char *)xrealloc(result, i+1);
+ return(result);
+}
+
+/* **************************************************************************
+ *
+ * misc word routines
+ *
+ * **************************************************************************/
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: cluc
+ *
+ * Purpose: convert lower to upper case string in place
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+void
+cluc (char *s)
+#else
+void cluc(s)
+ char *s;
+#endif
+{
+ while(*s){
+ if( islower((int)*s) )
+ *s = toupper(*s);
+ s++;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: culc
+ *
+ * Purpose: convert upper to lower case string in place
+ *
+ * Returns:
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+void
+culc (char *s)
+#else
+void culc(s)
+ char *s;
+#endif
+{
+ while(*s){
+ if( isupper((int)*s) )
+ *s = tolower(*s);
+ s++;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: nowhite
+ *
+ * Purpose: removes all beginning and ending white space from string
+ *
+ * Returns: returns the number of characters
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+nowhite (
+ char *c, /* buffer to be cleaned */
+ char *cr /* buffer for returned string */
+)
+#else
+int nowhite(c,cr)
+char *c; /* buffer to be cleaned */
+char *cr; /* buffer for returned string */
+#endif
+{
+ char *cr0; /* initial value of cr */
+ int n; /* the number of characters */
+
+ /* skip leading white space */
+ while(*c && isspace((int)*c))
+ c++;
+ /* copy up to the null */
+ cr0 = cr;
+ while(*c)
+ *cr++ = *c++;
+ n = cr - cr0; /* the number of characters */
+ *cr-- = '\0'; /* Null and point to the last character */
+ /* remove trailing white space */
+ while( n && isspace((int)*cr) ){
+ *cr-- = '\0';
+ n--;
+ }
+ return(n);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: nocr
+ *
+ * Purpose: remove trailing <CR> from a string (in place)
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+void
+nocr (char *s)
+#else
+void nocr(s)
+ char *s;
+#endif
+{
+ int len;
+
+ if( (s==NULL) || (*s=='\0') )
+ return;
+ len = strlen(s);
+ if( s[len-1] == '\n' )
+ s[len-1] = '\0';
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: istrue
+ *
+ * Purpose: check if a string is "true" or "yes" or "on"
+ *
+ * Returns: 1 if true string, 0 otherwise
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+istrue (char *s)
+#else
+int istrue(s)
+ char *s;
+#endif
+{
+ char *t;
+ int result;
+
+ if( (s==NULL) || (*s=='\0') )
+ return(0);
+ t = (char *)xmalloc(strlen(s)+1);
+ nowhite(s, t);
+ culc(t);
+ result = (!strcmp(t, "true") || !strcmp(t, "yes") ||
+ !strcmp(t, "on") || !strcmp(t, "1") );
+ xfree(t);
+ return(result);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: isfalse
+ *
+ * Purpose: check if a string is "false" or "no" or "off"
+ *
+ * Returns: 1 if false string, 0 otherwise
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+int
+isfalse (char *s)
+#else
+int isfalse(s)
+ char *s;
+#endif
+{
+ char *t;
+ int result;
+
+ if( (s==NULL) || (*s=='\0') )
+ return(0);
+ t = (char *)xmalloc(strlen(s)+1);
+ nowhite(s, t);
+ culc(t);
+ result = (!strcmp(t, "false") || !strcmp(t, "no") ||
+ !strcmp(t, "off") || !strcmp(t, "0") );
+ xfree(t);
+ return(result);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: strtoul16
+ *
+ * Purpose: convert a string to an unsigned long hex value
+ *
+ * Returns: converted hex value (end of converted string is in t)
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+unsigned long strtoul16 (char *s, char **t)
+#else
+unsigned long strtoul16(s, t)
+ char *s;
+ char **t;
+#endif
+{
+ unsigned long v=0;
+ int h;
+
+ while ( *s != ' ' &&
+ *s != '\n' &&
+ *s != '\r' &&
+ *s != '\0' ){
+ v *= 16;
+ if( (h = hexval(*s)) >= 0 ){
+ v += h;
+ s++;
+ }
+ else{
+ break;
+ }
+ }
+ if( t != NULL )
+ *t = s;
+ return(v);
+}