Blame WWW/Library/Implementation/HTString.c

Packit f574b8
/*
Packit f574b8
 * $LynxId: HTString.c,v 1.74 2018/02/15 01:54:27 tom Exp $
Packit f574b8
 *
Packit f574b8
 *	Case-independent string comparison		HTString.c
Packit f574b8
 *
Packit f574b8
 *	Original version came with listserv implementation.
Packit f574b8
 *	Version TBL Oct 91 replaces one which modified the strings.
Packit f574b8
 *	02-Dec-91 (JFG) Added stralloccopy and stralloccat
Packit f574b8
 *	23 Jan 92 (TBL) Changed strallocc* to 8 char HTSAC* for VM and suchlike
Packit f574b8
 *	 6 Oct 92 (TBL) Moved WWW_TraceFlag in here to be in library
Packit f574b8
 *	15 Nov 98 (TD)  Added HTSprintf.
Packit f574b8
 */
Packit f574b8
Packit f574b8
#include <HTUtils.h>
Packit f574b8
Packit f574b8
#include <LYLeaks.h>
Packit f574b8
#include <LYUtils.h>
Packit f574b8
#include <LYStrings.h>
Packit f574b8
Packit f574b8
#ifdef USE_IGNORE_RC
Packit f574b8
int ignore_unused;
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifndef NO_LYNX_TRACE
Packit f574b8
BOOLEAN WWW_TraceFlag = 0;	/* Global trace flag for ALL W3 code */
Packit f574b8
int WWW_TraceMask = 0;		/* Global trace flag for ALL W3 code */
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifdef _WINDOWS
Packit f574b8
#undef VC
Packit f574b8
#define VC "2.14FM"
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifndef VC
Packit f574b8
#define VC "2.14"
Packit f574b8
#endif /* !VC */
Packit f574b8
Packit f574b8
const char *HTLibraryVersion = VC;	/* String for help screen etc */
Packit f574b8
Packit f574b8
/*
Packit f574b8
 *     strcasecomp8 is a variant of strcasecomp (below)
Packit f574b8
 *     ------------		    -----------
Packit f574b8
 *     but uses 8bit upper/lower case information
Packit f574b8
 *     from the current display charset.
Packit f574b8
 *     It returns 0 if exact match.
Packit f574b8
 */
Packit f574b8
int strcasecomp8(const char *a,
Packit f574b8
		 const char *b)
Packit f574b8
{
Packit f574b8
    const char *p = a;
Packit f574b8
    const char *q = b;
Packit f574b8
Packit f574b8
    for (; *p && *q; p++, q++) {
Packit f574b8
	int diff = UPPER8(*p, *q);
Packit f574b8
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    if (*p)
Packit f574b8
	return 1;		/* p was longer than q */
Packit f574b8
    if (*q)
Packit f574b8
	return -1;		/* p was shorter than q */
Packit f574b8
    return 0;			/* Exact match */
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 *     strncasecomp8 is a variant of strncasecomp (below)
Packit f574b8
 *     -------------		     ------------
Packit f574b8
 *     but uses 8bit upper/lower case information
Packit f574b8
 *     from the current display charset.
Packit f574b8
 *     It returns 0 if exact match.
Packit f574b8
 */
Packit f574b8
int strncasecomp8(const char *a,
Packit f574b8
		  const char *b,
Packit f574b8
		  int n)
Packit f574b8
{
Packit f574b8
    const char *p = a;
Packit f574b8
    const char *q = b;
Packit f574b8
Packit f574b8
    for (;; p++, q++) {
Packit f574b8
	int diff;
Packit f574b8
Packit f574b8
	if (p == (a + n))
Packit f574b8
	    return 0;		/*   Match up to n characters */
Packit f574b8
	if (!(*p && *q))
Packit f574b8
	    return (*p - *q);
Packit f574b8
	diff = UPPER8(*p, *q);
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    /*NOTREACHED */
Packit f574b8
}
Packit f574b8
Packit f574b8
#ifndef VM			/* VM has these already it seems */
Packit f574b8
/*	Strings of any length
Packit f574b8
 *	---------------------
Packit f574b8
 */
Packit f574b8
int strcasecomp(const char *a,
Packit f574b8
		const char *b)
Packit f574b8
{
Packit f574b8
    const char *p = a;
Packit f574b8
    const char *q = b;
Packit f574b8
Packit f574b8
    for (; *p && *q; p++, q++) {
Packit f574b8
	int diff = TOLOWER(*p) - TOLOWER(*q);
Packit f574b8
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    if (*p)
Packit f574b8
	return 1;		/* p was longer than q */
Packit f574b8
    if (*q)
Packit f574b8
	return -1;		/* p was shorter than q */
Packit f574b8
    return 0;			/* Exact match */
Packit f574b8
}
Packit f574b8
Packit f574b8
/*	With count limit
Packit f574b8
 *	----------------
Packit f574b8
 */
Packit f574b8
int strncasecomp(const char *a,
Packit f574b8
		 const char *b,
Packit f574b8
		 int n)
Packit f574b8
{
Packit f574b8
    const char *p = a;
Packit f574b8
    const char *q = b;
Packit f574b8
Packit f574b8
    for (;; p++, q++) {
Packit f574b8
	int diff;
Packit f574b8
Packit f574b8
	if (p == (a + n))
Packit f574b8
	    return 0;		/*   Match up to n characters */
Packit f574b8
	if (!(*p && *q))
Packit f574b8
	    return (*p - *q);
Packit f574b8
	diff = TOLOWER(*p) - TOLOWER(*q);
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    /*NOTREACHED */
Packit f574b8
}
Packit f574b8
#endif /* VM */
Packit f574b8
Packit f574b8
#define end_component(p) (*(p) == '.' || *(p) == '\0')
Packit f574b8
Packit f574b8
#ifdef DEBUG_ASTERISK
Packit f574b8
#define SHOW_ASTERISK CTRACE
Packit f574b8
#else
Packit f574b8
#define SHOW_ASTERISK(p)	/* nothing */
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#define SHOW_ASTERISK_NUM(a,b,c)  \
Packit f574b8
	SHOW_ASTERISK((tfp, "test @%d, '%s' vs '%s' (%d)\n", __LINE__, a,b,c))
Packit f574b8
Packit f574b8
#define SHOW_ASTERISK_TXT(a,b,c)  \
Packit f574b8
	SHOW_ASTERISK((tfp, "test @%d, '%s' vs '%s' %s\n", __LINE__, a,b,c))
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Compare names as described in RFC 2818: ignore case, allow wildcards. 
Packit f574b8
 * Return zero on a match, nonzero on mismatch -TD
Packit f574b8
 *
Packit f574b8
 * From RFC 2818:
Packit f574b8
 * Names may contain the wildcard character * which is considered to match any
Packit f574b8
 * single domain name component or component fragment.  E.g., *.a.com matches
Packit f574b8
 * foo.a.com but not bar.foo.a.com.  f*.com matches foo.com but not bar.com.
Packit f574b8
 */
Packit f574b8
int strcasecomp_asterisk(const char *a, const char *b)
Packit f574b8
{
Packit f574b8
    const char *p;
Packit f574b8
    int result = 0;
Packit f574b8
    int done = FALSE;
Packit f574b8
Packit f574b8
    while (!result && !done) {
Packit f574b8
	SHOW_ASTERISK_TXT(a, b, "main");
Packit f574b8
	if (*a == '*') {
Packit f574b8
	    p = b;
Packit f574b8
	    for (;;) {
Packit f574b8
		SHOW_ASTERISK_TXT(a, p, "loop");
Packit f574b8
		if (end_component(p)) {
Packit f574b8
		    if (end_component(a + 1)) {
Packit f574b8
			b = p - 1;
Packit f574b8
			result = 0;
Packit f574b8
		    } else {
Packit f574b8
			result = 1;
Packit f574b8
		    }
Packit f574b8
		    break;
Packit f574b8
		} else if (strcasecomp_asterisk(a + 1, p)) {
Packit f574b8
		    ++p;
Packit f574b8
		} else {
Packit f574b8
		    b = p - 1;
Packit f574b8
		    result = 0;	/* found a match starting at 'p' */
Packit f574b8
		    done = TRUE;
Packit f574b8
		    break;
Packit f574b8
		}
Packit f574b8
	    }
Packit f574b8
	    SHOW_ASTERISK_NUM(a, b, result);
Packit f574b8
	} else if (*b == '*') {
Packit f574b8
	    result = strcasecomp_asterisk(b, a);
Packit f574b8
	    SHOW_ASTERISK_NUM(a, b, result);
Packit f574b8
	    done = (result == 0);
Packit f574b8
	} else if (*a == '\0' || *b == '\0') {
Packit f574b8
	    result = (*a != *b);
Packit f574b8
	    SHOW_ASTERISK_NUM(a, b, result);
Packit f574b8
	    break;
Packit f574b8
	} else if (TOLOWER(UCH(*a)) != TOLOWER(UCH(*b))) {
Packit f574b8
	    result = 1;
Packit f574b8
	    SHOW_ASTERISK_NUM(a, b, result);
Packit f574b8
	    break;
Packit f574b8
	}
Packit f574b8
	++a;
Packit f574b8
	++b;
Packit f574b8
    }
Packit f574b8
    return result;
Packit f574b8
}
Packit f574b8
Packit f574b8
#ifdef DEBUG_ASTERISK
Packit f574b8
void mismatch_asterisk(void)
Packit f574b8
{
Packit f574b8
    /* *INDENT-OFF* */
Packit f574b8
    static struct {
Packit f574b8
	const char *a;
Packit f574b8
	const char *b;
Packit f574b8
	int	    code;
Packit f574b8
    } table[] = {
Packit f574b8
	{ "foo.bar",	 "*.*",	      0 },
Packit f574b8
	{ "foo.bar",	 "*.b*",      0 },
Packit f574b8
	{ "foo.bar",	 "*.ba*",     0 },
Packit f574b8
	{ "foo.bar",	 "*.bar*",    0 },
Packit f574b8
	{ "foo.bar",	 "*.*bar*",   0 },
Packit f574b8
	{ "foo.bar",	 "*.*.",      1 },
Packit f574b8
	{ "foo.bar",	 "fo*.b*",    0 },
Packit f574b8
	{ "*oo.bar",	 "fo*.b*",    0 },
Packit f574b8
	{ "*oo.bar.com", "fo*.b*",    1 },
Packit f574b8
	{ "*oo.bar.com", "fo*.b*m",   1 },
Packit f574b8
	{ "*oo.bar.com", "fo*.b*.c*", 0 },
Packit f574b8
    };
Packit f574b8
    /* *INDENT-ON* */
Packit f574b8
Packit f574b8
    unsigned n;
Packit f574b8
    int code;
Packit f574b8
Packit f574b8
    CTRACE((tfp, "mismatch_asterisk testing\n"));
Packit f574b8
    for (n = 0; n < TABLESIZE(table); ++n) {
Packit f574b8
	CTRACE((tfp, "-------%d\n", n));
Packit f574b8
	code = strcasecomp_asterisk(table[n].a, table[n].b);
Packit f574b8
	if (code != table[n].code) {
Packit f574b8
	    CTRACE((tfp, "mismatch_asterisk '%s' '%s' got %d, want %d\n",
Packit f574b8
		    table[n].a, table[n].b, code, table[n].code));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#ifdef NOT_ASCII
Packit f574b8
Packit f574b8
/*	Case-insensitive with ASCII collating sequence
Packit f574b8
 *	----------------
Packit f574b8
 */
Packit f574b8
int AS_casecomp(const char *p,
Packit f574b8
		const char *q)
Packit f574b8
{
Packit f574b8
    int diff;
Packit f574b8
Packit f574b8
    for (;; p++, q++) {
Packit f574b8
	if (!(*p && *q))
Packit f574b8
	    return (UCH(*p) - UCH(*q));
Packit f574b8
	diff = TOASCII(TOLOWER(*p))
Packit f574b8
	    - TOASCII(TOLOWER(*q));
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    /*NOTREACHED */
Packit f574b8
}
Packit f574b8
Packit f574b8
/*	With count limit and ASCII collating sequence
Packit f574b8
 *	----------------
Packit f574b8
 *	AS_cmp uses n == -1 to compare indefinite length.
Packit f574b8
 */
Packit f574b8
int AS_ncmp(const char *p,
Packit f574b8
	    const char *q,
Packit f574b8
	    unsigned int n)
Packit f574b8
{
Packit f574b8
    const char *a = p;
Packit f574b8
    int diff;
Packit f574b8
Packit f574b8
    for (; (unsigned) (p - a) < n; p++, q++) {
Packit f574b8
	if (!(*p && *q))
Packit f574b8
	    return (UCH(*p) - UCH(*q));
Packit f574b8
	diff = TOASCII(*p)
Packit f574b8
	    - TOASCII(*q);
Packit f574b8
	if (diff)
Packit f574b8
	    return diff;
Packit f574b8
    }
Packit f574b8
    return 0;			/*   Match up to n characters */
Packit f574b8
}
Packit f574b8
#endif /* NOT_ASCII */
Packit f574b8
Packit f574b8
/*	Allocate a new copy of a string, and returns it
Packit f574b8
*/
Packit f574b8
char *HTSACopy(char **dest,
Packit f574b8
	       const char *src)
Packit f574b8
{
Packit f574b8
    if (src != 0) {
Packit f574b8
	if (src != *dest) {
Packit f574b8
	    size_t size = strlen(src) + 1;
Packit f574b8
Packit f574b8
	    FREE(*dest);
Packit f574b8
	    *dest = (char *) malloc(size);
Packit f574b8
	    if (*dest == NULL)
Packit f574b8
		outofmem(__FILE__, "HTSACopy");
Packit f574b8
	    MemCpy(*dest, src, size);
Packit f574b8
	}
Packit f574b8
    } else {
Packit f574b8
	FREE(*dest);
Packit f574b8
    }
Packit f574b8
    return *dest;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*	String Allocate and Concatenate
Packit f574b8
*/
Packit f574b8
char *HTSACat(char **dest,
Packit f574b8
	      const char *src)
Packit f574b8
{
Packit f574b8
    if (src && *src && (src != *dest)) {
Packit f574b8
	if (*dest) {
Packit f574b8
	    size_t length = strlen(*dest);
Packit f574b8
Packit f574b8
	    *dest = (char *) realloc(*dest, length + strlen(src) + 1);
Packit f574b8
	    if (*dest == NULL)
Packit f574b8
		outofmem(__FILE__, "HTSACat");
Packit f574b8
	    strcpy(*dest + length, src);
Packit f574b8
	} else {
Packit f574b8
	    *dest = (char *) malloc(strlen(src) + 1);
Packit f574b8
	    if (*dest == NULL)
Packit f574b8
		outofmem(__FILE__, "HTSACat");
Packit f574b8
	    strcpy(*dest, src);
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    return *dest;
Packit f574b8
}
Packit f574b8
Packit f574b8
/* optimized for heavily realloc'd strings, store length inside */
Packit f574b8
Packit f574b8
#define EXTRA_TYPE size_t	/* type we use for length */
Packit f574b8
#define EXTRA_SIZE sizeof(void *)	/* alignment >= sizeof(EXTRA_TYPE) */
Packit f574b8
Packit f574b8
void HTSAFree_extra(char *s)
Packit f574b8
{
Packit f574b8
    free(s - EXTRA_SIZE);
Packit f574b8
}
Packit f574b8
Packit f574b8
/* never shrink */
Packit f574b8
char *HTSACopy_extra(char **dest,
Packit f574b8
		     const char *src)
Packit f574b8
{
Packit f574b8
    if (src != 0) {
Packit f574b8
	size_t srcsize = strlen(src) + 1;
Packit f574b8
	EXTRA_TYPE size = 0;
Packit f574b8
Packit f574b8
	if (*dest != 0) {
Packit f574b8
	    size = *(EXTRA_TYPE *) (void *) ((*dest) - EXTRA_SIZE);
Packit f574b8
	}
Packit f574b8
	if ((*dest == 0) || (size < srcsize)) {
Packit f574b8
	    FREE_extra(*dest);
Packit f574b8
	    size = srcsize * 2;	/* x2 step */
Packit f574b8
	    *dest = (char *) malloc(size + EXTRA_SIZE);
Packit f574b8
	    if (*dest == NULL)
Packit f574b8
		outofmem(__FILE__, "HTSACopy_extra");
Packit f574b8
	    *(EXTRA_TYPE *) (void *) (*dest) = size;
Packit f574b8
	    *dest += EXTRA_SIZE;
Packit f574b8
	}
Packit f574b8
	MemCpy(*dest, src, srcsize);
Packit f574b8
    } else {
Packit f574b8
	Clear_extra(*dest);
Packit f574b8
    }
Packit f574b8
    return *dest;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*	Find next Field
Packit f574b8
 *	---------------
Packit f574b8
 *
Packit f574b8
 * On entry,
Packit f574b8
 *	*pstr	points to a string containig white space separated
Packit f574b8
 *		field, optionlly quoted.
Packit f574b8
 *
Packit f574b8
 * On exit,
Packit f574b8
 *	*pstr	has been moved to the first delimiter past the
Packit f574b8
 *		field
Packit f574b8
 *		THE STRING HAS BEEN MUTILATED by a 0 terminator
Packit f574b8
 *
Packit f574b8
 *	returns a pointer to the first field
Packit f574b8
 */
Packit f574b8
char *HTNextField(char **pstr)
Packit f574b8
{
Packit f574b8
    char *p = *pstr;
Packit f574b8
    char *start = NULL;		/* start of field */
Packit f574b8
Packit f574b8
    if (p != NULL) {
Packit f574b8
	while (*p && WHITE(*p))
Packit f574b8
	    p++;		/* Strip white space */
Packit f574b8
	if (!*p) {
Packit f574b8
	    *pstr = p;
Packit f574b8
	} else {
Packit f574b8
	    if (*p == '"') {	/* quoted field */
Packit f574b8
		p++;
Packit f574b8
		start = p;
Packit f574b8
		for (; *p && *p != '"'; p++) {
Packit f574b8
		    if (*p == '\\' && p[1])
Packit f574b8
			p++;	/* Skip escaped chars */
Packit f574b8
		}
Packit f574b8
	    } else {
Packit f574b8
		start = p;
Packit f574b8
		while (*p && !WHITE(*p))
Packit f574b8
		    p++;	/* Skip first field */
Packit f574b8
	    }
Packit f574b8
	    if (*p)
Packit f574b8
		*p++ = '\0';
Packit f574b8
	    *pstr = p;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    return start;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*	Find next Token
Packit f574b8
 *	---------------
Packit f574b8
 *	Finds the next token in a string
Packit f574b8
 *	On entry,
Packit f574b8
 *	*pstr	points to a string to be parsed.
Packit f574b8
 *	delims	lists characters to be recognized as delimiters.
Packit f574b8
 *		If NULL, default is white space "," ";" or "=".
Packit f574b8
 *		The word can optionally be quoted or enclosed with
Packit f574b8
 *		chars from bracks.
Packit f574b8
 *		Comments surrrounded by '(' ')' are filtered out
Packit f574b8
 *		unless they are specifically reqested by including
Packit f574b8
 *		' ' or '(' in delims or bracks.
Packit f574b8
 *	bracks	lists bracketing chars.  Some are recognized as
Packit f574b8
 *		special, for those give the opening char.
Packit f574b8
 *		If NULL, defaults to <"> and "<" ">".
Packit f574b8
 *	found	points to location to fill with the ending delimiter
Packit f574b8
 *		found, or is NULL.
Packit f574b8
 *
Packit f574b8
 *	On exit,
Packit f574b8
 *	*pstr	has been moved to the first delimiter past the
Packit f574b8
 *		field
Packit f574b8
 *		THE STRING HAS BEEN MUTILATED by a 0 terminator
Packit f574b8
 *	found	points to the delimiter found unless it was NULL.
Packit f574b8
 *	Returns a pointer to the first word or NULL on error
Packit f574b8
 */
Packit f574b8
char *HTNextTok(char **pstr,
Packit f574b8
		const char *delims,
Packit f574b8
		const char *bracks,
Packit f574b8
		char *found)
Packit f574b8
{
Packit f574b8
    char *p = *pstr;
Packit f574b8
    char *start = NULL;
Packit f574b8
    BOOL get_blanks, skip_comments;
Packit f574b8
    BOOL get_comments;
Packit f574b8
    BOOL get_closing_char_too = FALSE;
Packit f574b8
    char closer;
Packit f574b8
Packit f574b8
    if (isEmpty(pstr))
Packit f574b8
	return NULL;
Packit f574b8
    if (!delims)
Packit f574b8
	delims = " ;,=";
Packit f574b8
    if (!bracks)
Packit f574b8
	bracks = "<\"";
Packit f574b8
Packit f574b8
    get_blanks = (BOOL) (!StrChr(delims, ' ') && !StrChr(bracks, ' '));
Packit f574b8
    get_comments = (BOOL) (StrChr(bracks, '(') != NULL);
Packit f574b8
    skip_comments = (BOOL) (!get_comments && !StrChr(delims, '(') && !get_blanks);
Packit f574b8
#define skipWHITE(c) (!get_blanks && WHITE(c))
Packit f574b8
Packit f574b8
    while (*p && skipWHITE(*p))
Packit f574b8
	p++;			/* Strip white space */
Packit f574b8
    if (!*p) {
Packit f574b8
	*pstr = p;
Packit f574b8
	if (found)
Packit f574b8
	    *found = '\0';
Packit f574b8
	return NULL;		/* No first field */
Packit f574b8
    }
Packit f574b8
    while (1) {
Packit f574b8
	/* Strip white space and other delimiters */
Packit f574b8
	while (*p && (skipWHITE(*p) || StrChr(delims, *p)))
Packit f574b8
	    p++;
Packit f574b8
	if (!*p) {
Packit f574b8
	    *pstr = p;
Packit f574b8
	    if (found)
Packit f574b8
		*found = *(p - 1);
Packit f574b8
	    return NULL;	/* No field */
Packit f574b8
	}
Packit f574b8
Packit f574b8
	if (*p == '(' && (skip_comments || get_comments)) {	/* Comment */
Packit f574b8
	    int comment_level = 0;
Packit f574b8
Packit f574b8
	    if (get_comments && !start)
Packit f574b8
		start = p + 1;
Packit f574b8
	    for (; *p && (*p != ')' || --comment_level > 0); p++) {
Packit f574b8
		if (*p == '(')
Packit f574b8
		    comment_level++;
Packit f574b8
		else if (*p == '"') {	/* quoted field within Comment */
Packit f574b8
		    for (p++; *p && *p != '"'; p++)
Packit f574b8
			if (*p == '\\' && *(p + 1))
Packit f574b8
			    p++;	/* Skip escaped chars */
Packit f574b8
		    if (!*p)
Packit f574b8
			break;	/* (invalid) end of string found, leave */
Packit f574b8
		}
Packit f574b8
		if (*p == '\\' && *(p + 1))
Packit f574b8
		    p++;	/* Skip escaped chars */
Packit f574b8
	    }
Packit f574b8
	    if (get_comments)
Packit f574b8
		break;
Packit f574b8
	    if (*p)
Packit f574b8
		p++;
Packit f574b8
	    if (get_closing_char_too) {
Packit f574b8
		if (!*p || (!StrChr(bracks, *p) && StrChr(delims, *p))) {
Packit f574b8
		    break;
Packit f574b8
		} else
Packit f574b8
		    get_closing_char_too = (BOOL) (StrChr(bracks, *p) != NULL);
Packit f574b8
	    }
Packit f574b8
	} else if (StrChr(bracks, *p)) {	/* quoted or bracketed field */
Packit f574b8
	    switch (*p) {
Packit f574b8
	    case '<':
Packit f574b8
		closer = '>';
Packit f574b8
		break;
Packit f574b8
	    case '[':
Packit f574b8
		closer = ']';
Packit f574b8
		break;
Packit f574b8
	    case '{':
Packit f574b8
		closer = '}';
Packit f574b8
		break;
Packit f574b8
	    case ':':
Packit f574b8
		closer = ';';
Packit f574b8
		break;
Packit f574b8
	    default:
Packit f574b8
		closer = *p;
Packit f574b8
	    }
Packit f574b8
	    if (!start)
Packit f574b8
		start = ++p;
Packit f574b8
	    for (; *p && *p != closer; p++)
Packit f574b8
		if (*p == '\\' && *(p + 1))
Packit f574b8
		    p++;	/* Skip escaped chars */
Packit f574b8
	    if (get_closing_char_too) {
Packit f574b8
		p++;
Packit f574b8
		if (!*p || (!StrChr(bracks, *p) && StrChr(delims, *p))) {
Packit f574b8
		    break;
Packit f574b8
		} else
Packit f574b8
		    get_closing_char_too = (BOOL) (StrChr(bracks, *p) != NULL);
Packit f574b8
	    } else
Packit f574b8
		break;		/* kr95-10-9: needs to stop here */
Packit f574b8
	} else {		/* Spool field */
Packit f574b8
	    if (!start)
Packit f574b8
		start = p;
Packit f574b8
	    while (*p && !skipWHITE(*p) && !StrChr(bracks, *p) &&
Packit f574b8
		   !StrChr(delims, *p))
Packit f574b8
		p++;
Packit f574b8
	    if (*p && StrChr(bracks, *p)) {
Packit f574b8
		get_closing_char_too = TRUE;
Packit f574b8
	    } else {
Packit f574b8
		if (*p == '(' && skip_comments) {
Packit f574b8
		    *pstr = p;
Packit f574b8
		    HTNextTok(pstr, NULL, "(", found);	/*      Advance pstr */
Packit f574b8
		    *p = '\0';
Packit f574b8
		    if (*pstr && **pstr)
Packit f574b8
			(*pstr)++;
Packit f574b8
		    return start;
Packit f574b8
		}
Packit f574b8
		break;		/* Got it */
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    if (found)
Packit f574b8
	*found = *p;
Packit f574b8
Packit f574b8
    if (*p)
Packit f574b8
	*p++ = '\0';
Packit f574b8
    *pstr = p;
Packit f574b8
    return start;
Packit f574b8
}
Packit f574b8
Packit f574b8
static char *HTAlloc(char *ptr, size_t length)
Packit f574b8
{
Packit f574b8
    if (ptr != 0)
Packit f574b8
	ptr = (char *) realloc(ptr, length);
Packit f574b8
    else
Packit f574b8
	ptr = (char *) malloc(length);
Packit f574b8
    if (ptr == 0)
Packit f574b8
	outofmem(__FILE__, "HTAlloc");
Packit f574b8
    return ptr;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * If SAVE_TIME_NOT_SPACE is defined, StrAllocVsprintf will hang on to
Packit f574b8
 * its temporary string buffers instead of allocating and freeing them
Packit f574b8
 * in each invocation.  They only grow and never shrink, and won't be
Packit f574b8
 * cleaned up on exit. - kw
Packit f574b8
 */
Packit f574b8
#if defined(_REENTRANT) || defined(_THREAD_SAFE) || defined(LY_FIND_LEAKS)
Packit f574b8
#undef SAVE_TIME_NOT_SPACE
Packit f574b8
#endif
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Replacement for sprintf, allocates buffer on the fly according to what's
Packit f574b8
 * needed for its arguments.  Unlike sprintf, this always concatenates to the
Packit f574b8
 * destination buffer, so we do not have to provide both flavors.
Packit f574b8
 */
Packit f574b8
typedef enum {
Packit f574b8
    Flags,
Packit f574b8
    Width,
Packit f574b8
    Prec,
Packit f574b8
    Type,
Packit f574b8
    Format
Packit f574b8
} PRINTF;
Packit f574b8
Packit f574b8
#define VA_INTGR(type) ival = (int)    va_arg((*ap), type)
Packit f574b8
#define VA_FLOAT(type) fval = (double) va_arg((*ap), type)
Packit f574b8
#define VA_POINT(type) pval = (char *) va_arg((*ap), type)
Packit f574b8
Packit f574b8
#define NUM_WIDTH 10		/* allow for width substituted for "*" in "%*s" */
Packit f574b8
		/* also number of chars assumed to be needed in addition
Packit f574b8
		   to a given precision in floating point formats */
Packit f574b8
Packit f574b8
#define GROW_EXPR(n) (((n) * 3) / 2)
Packit f574b8
#define GROW_SIZE 256
Packit f574b8
Packit f574b8
PUBLIC_IF_FIND_LEAKS char *StrAllocVsprintf(char **pstr,
Packit f574b8
					    size_t dst_len,
Packit f574b8
					    const char *fmt,
Packit f574b8
					    va_list * ap)
Packit f574b8
{
Packit f574b8
#ifdef HAVE_VASPRINTF
Packit f574b8
    /*
Packit f574b8
     * Use vasprintf() if we have it, since it is simplest.
Packit f574b8
     */
Packit f574b8
    char *result = 0;
Packit f574b8
    char *temp = 0;
Packit f574b8
Packit f574b8
    /* discard old destination if no length was given */
Packit f574b8
    if (pstr && !dst_len) {
Packit f574b8
	if (*pstr)
Packit f574b8
	    FREE(*pstr);
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if (vasprintf(&temp, fmt, *ap) >= 0) {
Packit f574b8
	if (dst_len != 0) {
Packit f574b8
	    size_t src_len = strlen(temp);
Packit f574b8
	    size_t new_len = dst_len + src_len + 1;
Packit f574b8
Packit f574b8
	    result = HTAlloc(pstr ? *pstr : 0, new_len);
Packit f574b8
	    if (result != 0) {
Packit f574b8
		strcpy(result + dst_len, temp);
Packit f574b8
	    }
Packit f574b8
	    (free) (temp);
Packit f574b8
	} else {
Packit f574b8
	    result = temp;
Packit f574b8
	    mark_malloced(temp, strlen(temp));
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if (pstr != 0)
Packit f574b8
	*pstr = result;
Packit f574b8
Packit f574b8
    return result;
Packit f574b8
#else /* !HAVE_VASPRINTF */
Packit f574b8
    /*
Packit f574b8
     * If vasprintf() is not available, this works - but does not implement
Packit f574b8
     * the POSIX '$' formatting character which may be used in some of the
Packit f574b8
     * ".po" files.
Packit f574b8
     */
Packit f574b8
#ifdef SAVE_TIME_NOT_SPACE
Packit f574b8
    static size_t tmp_len = 0;
Packit f574b8
    static size_t fmt_len = 0;
Packit f574b8
    static char *tmp_ptr = NULL;
Packit f574b8
    static char *fmt_ptr = NULL;
Packit f574b8
Packit f574b8
#else
Packit f574b8
    size_t tmp_len = GROW_SIZE;
Packit f574b8
    char *tmp_ptr = 0;
Packit f574b8
    char *fmt_ptr;
Packit f574b8
#endif /* SAVE_TIME_NOT_SPACE */
Packit f574b8
    size_t have, need;
Packit f574b8
    char *dst_ptr = *pstr;
Packit f574b8
    const char *format = fmt;
Packit f574b8
Packit f574b8
    if (isEmpty(fmt))
Packit f574b8
	return 0;
Packit f574b8
Packit f574b8
    need = strlen(fmt) + 1;
Packit f574b8
#ifdef SAVE_TIME_NOT_SPACE
Packit f574b8
    if (!fmt_ptr || fmt_len < need * NUM_WIDTH) {
Packit f574b8
	fmt_ptr = HTAlloc(fmt_ptr, fmt_len = need * NUM_WIDTH);
Packit f574b8
    }
Packit f574b8
    if (!tmp_ptr || tmp_len < GROW_SIZE) {
Packit f574b8
	tmp_ptr = HTAlloc(tmp_ptr, tmp_len = GROW_SIZE);
Packit f574b8
    }
Packit f574b8
#else
Packit f574b8
    if ((fmt_ptr = malloc(need * NUM_WIDTH)) == 0
Packit f574b8
	|| (tmp_ptr = malloc(tmp_len)) == 0) {
Packit f574b8
	outofmem(__FILE__, "StrAllocVsprintf");
Packit f574b8
    }
Packit f574b8
#endif /* SAVE_TIME_NOT_SPACE */
Packit f574b8
Packit f574b8
    if (dst_ptr == 0) {
Packit f574b8
	dst_ptr = HTAlloc(dst_ptr, have = GROW_SIZE + need);
Packit f574b8
    } else {
Packit f574b8
	have = strlen(dst_ptr) + 1;
Packit f574b8
	need += dst_len;
Packit f574b8
	if (have < need)
Packit f574b8
	    dst_ptr = HTAlloc(dst_ptr, have = GROW_SIZE + need);
Packit f574b8
    }
Packit f574b8
Packit f574b8
    while (*fmt != '\0') {
Packit f574b8
	if (*fmt == '%') {
Packit f574b8
	    static char dummy[] = "";
Packit f574b8
	    PRINTF state = Flags;
Packit f574b8
	    char *pval = dummy;	/* avoid const-cast */
Packit f574b8
	    double fval = 0.0;
Packit f574b8
	    int done = FALSE;
Packit f574b8
	    int ival = 0;
Packit f574b8
	    int prec = -1;
Packit f574b8
	    int type = 0;
Packit f574b8
	    int used = 0;
Packit f574b8
	    int width = -1;
Packit f574b8
	    size_t f = 0;
Packit f574b8
Packit f574b8
	    fmt_ptr[f++] = *fmt;
Packit f574b8
	    while (*++fmt != '\0' && !done) {
Packit f574b8
		fmt_ptr[f++] = *fmt;
Packit f574b8
Packit f574b8
		if (isdigit(UCH(*fmt))) {
Packit f574b8
		    int num = *fmt - '0';
Packit f574b8
Packit f574b8
		    if (state == Flags && num != 0)
Packit f574b8
			state = Width;
Packit f574b8
		    if (state == Width) {
Packit f574b8
			if (width < 0)
Packit f574b8
			    width = 0;
Packit f574b8
			width = (width * 10) + num;
Packit f574b8
		    } else if (state == Prec) {
Packit f574b8
			if (prec < 0)
Packit f574b8
			    prec = 0;
Packit f574b8
			prec = (prec * 10) + num;
Packit f574b8
		    }
Packit f574b8
		} else if (*fmt == '*') {
Packit f574b8
		    VA_INTGR(int);
Packit f574b8
Packit f574b8
		    if (state == Flags)
Packit f574b8
			state = Width;
Packit f574b8
		    if (state == Width) {
Packit f574b8
			width = ival;
Packit f574b8
		    } else if (state == Prec) {
Packit f574b8
			prec = ival;
Packit f574b8
		    }
Packit f574b8
		    sprintf(&fmt_ptr[--f], "%d", ival);
Packit f574b8
		    f = strlen(fmt_ptr);
Packit f574b8
		} else if (isalpha(UCH(*fmt))) {
Packit f574b8
		    done = TRUE;
Packit f574b8
		    switch (*fmt) {
Packit f574b8
		    case 'Z':	/* FALLTHRU */
Packit f574b8
		    case 'h':	/* FALLTHRU */
Packit f574b8
		    case 'l':	/* FALLTHRU */
Packit f574b8
		    case 'L':	/* FALLTHRU */
Packit f574b8
			done = FALSE;
Packit f574b8
			type = *fmt;
Packit f574b8
			break;
Packit f574b8
		    case 'o':	/* FALLTHRU */
Packit f574b8
		    case 'i':	/* FALLTHRU */
Packit f574b8
		    case 'd':	/* FALLTHRU */
Packit f574b8
		    case 'u':	/* FALLTHRU */
Packit f574b8
		    case 'x':	/* FALLTHRU */
Packit f574b8
		    case 'X':	/* FALLTHRU */
Packit f574b8
			if (type == 'l')
Packit f574b8
			    VA_INTGR(long);
Packit f574b8
Packit f574b8
			else if (type == 'Z')
Packit f574b8
			    VA_INTGR(size_t);
Packit f574b8
Packit f574b8
			else
Packit f574b8
			    VA_INTGR(int);
Packit f574b8
Packit f574b8
			used = 'i';
Packit f574b8
			break;
Packit f574b8
		    case 'f':	/* FALLTHRU */
Packit f574b8
		    case 'e':	/* FALLTHRU */
Packit f574b8
		    case 'E':	/* FALLTHRU */
Packit f574b8
		    case 'g':	/* FALLTHRU */
Packit f574b8
		    case 'G':	/* FALLTHRU */
Packit f574b8
			VA_FLOAT(double);
Packit f574b8
Packit f574b8
			used = 'f';
Packit f574b8
			break;
Packit f574b8
		    case 'c':
Packit f574b8
			VA_INTGR(int);
Packit f574b8
Packit f574b8
			used = 'c';
Packit f574b8
			break;
Packit f574b8
		    case 's':
Packit f574b8
			VA_POINT(char *);
Packit f574b8
Packit f574b8
			if (prec < 0)
Packit f574b8
			    prec = (int) strlen(pval);
Packit f574b8
			used = 's';
Packit f574b8
			break;
Packit f574b8
		    case 'p':
Packit f574b8
			VA_POINT(void *);
Packit f574b8
Packit f574b8
			used = 'p';
Packit f574b8
			break;
Packit f574b8
		    case 'n':
Packit f574b8
			VA_POINT(int *);
Packit f574b8
Packit f574b8
			used = 0;
Packit f574b8
			break;
Packit f574b8
		    default:
Packit f574b8
			CTRACE((tfp, "unknown format character '%c' in %s\n",
Packit f574b8
				*fmt, format));
Packit f574b8
			break;
Packit f574b8
		    }
Packit f574b8
		} else if (*fmt == '.') {
Packit f574b8
		    state = Prec;
Packit f574b8
		} else if (*fmt == '%') {
Packit f574b8
		    done = TRUE;
Packit f574b8
		    used = '%';
Packit f574b8
		}
Packit f574b8
	    }
Packit f574b8
	    fmt_ptr[f] = '\0';
Packit f574b8
Packit f574b8
	    if (prec > 0) {
Packit f574b8
		switch (used) {
Packit f574b8
		case 'f':
Packit f574b8
		    if (width < prec + NUM_WIDTH)
Packit f574b8
			width = prec + NUM_WIDTH;
Packit f574b8
		    /* FALLTHRU */
Packit f574b8
		case 'i':
Packit f574b8
		    /* FALLTHRU */
Packit f574b8
		case 'p':
Packit f574b8
		    if (width < prec + 2)
Packit f574b8
			width = prec + 2;	/* leading sign/space/zero, "0x" */
Packit f574b8
		    break;
Packit f574b8
		case 'c':
Packit f574b8
		    break;
Packit f574b8
		case '%':
Packit f574b8
		    break;
Packit f574b8
		default:
Packit f574b8
		    if (width < prec)
Packit f574b8
			width = prec;
Packit f574b8
		    break;
Packit f574b8
		}
Packit f574b8
	    }
Packit f574b8
	    if (width >= (int) tmp_len) {
Packit f574b8
		tmp_len = GROW_EXPR(tmp_len + width);
Packit f574b8
		tmp_ptr = HTAlloc(tmp_ptr, tmp_len);
Packit f574b8
	    }
Packit f574b8
Packit f574b8
	    switch (used) {
Packit f574b8
	    case 'i':
Packit f574b8
	    case 'c':
Packit f574b8
		sprintf(tmp_ptr, fmt_ptr, ival);
Packit f574b8
		break;
Packit f574b8
	    case 'f':
Packit f574b8
		sprintf(tmp_ptr, fmt_ptr, fval);
Packit f574b8
		break;
Packit f574b8
	    default:
Packit f574b8
		sprintf(tmp_ptr, fmt_ptr, pval);
Packit f574b8
		break;
Packit f574b8
	    }
Packit f574b8
	    need = dst_len + strlen(tmp_ptr) + 1;
Packit f574b8
	    if (need >= have) {
Packit f574b8
		dst_ptr = HTAlloc(dst_ptr, have = GROW_EXPR(need));
Packit f574b8
	    }
Packit f574b8
	    strcpy(dst_ptr + dst_len, tmp_ptr);
Packit f574b8
	    dst_len += strlen(tmp_ptr);
Packit f574b8
	} else {
Packit f574b8
	    if ((dst_len + 2) >= have) {
Packit f574b8
		dst_ptr = HTAlloc(dst_ptr, (have += GROW_SIZE));
Packit f574b8
	    }
Packit f574b8
	    dst_ptr[dst_len++] = *fmt++;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
Packit f574b8
#ifndef SAVE_TIME_NOT_SPACE
Packit f574b8
    FREE(tmp_ptr);
Packit f574b8
    FREE(fmt_ptr);
Packit f574b8
#endif
Packit f574b8
    dst_ptr[dst_len] = '\0';
Packit f574b8
    if (pstr)
Packit f574b8
	*pstr = dst_ptr;
Packit f574b8
    return (dst_ptr);
Packit f574b8
#endif /* HAVE_VASPRINTF */
Packit f574b8
}
Packit f574b8
#undef SAVE_TIME_NOT_SPACE
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Replacement for sprintf, allocates buffer on the fly according to what's
Packit f574b8
 * needed for its arguments.  Unlike sprintf, this always concatenates to the
Packit f574b8
 * destination buffer.
Packit f574b8
 */
Packit f574b8
/* Note: if making changes, also check the memory tracking version
Packit f574b8
 * LYLeakHTSprintf in LYLeaks.c. - kw */
Packit f574b8
#ifdef HTSprintf		/* if hidden by LYLeaks stuff */
Packit f574b8
#undef HTSprintf
Packit f574b8
#endif
Packit f574b8
char *HTSprintf(char **pstr, const char *fmt,...)
Packit f574b8
{
Packit f574b8
    char *result = 0;
Packit f574b8
    size_t inuse = 0;
Packit f574b8
    va_list ap;
Packit f574b8
Packit f574b8
    LYva_start(ap, fmt);
Packit f574b8
    {
Packit f574b8
	if (pstr != 0 && *pstr != 0)
Packit f574b8
	    inuse = strlen(*pstr);
Packit f574b8
	result = StrAllocVsprintf(pstr, inuse, fmt, &ap);
Packit f574b8
    }
Packit f574b8
    va_end(ap);
Packit f574b8
Packit f574b8
    return (result);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Replacement for sprintf, allocates buffer on the fly according to what's
Packit f574b8
 * needed for its arguments.  Like sprintf, this always resets the destination
Packit f574b8
 * buffer.
Packit f574b8
 */
Packit f574b8
/* Note: if making changes, also check the memory tracking version
Packit f574b8
 * LYLeakHTSprintf0 in LYLeaks.c. - kw */
Packit f574b8
#ifdef HTSprintf0		/* if hidden by LYLeaks stuff */
Packit f574b8
#undef HTSprintf0
Packit f574b8
#endif
Packit f574b8
char *HTSprintf0(char **pstr, const char *fmt,...)
Packit f574b8
{
Packit f574b8
    char *result = 0;
Packit f574b8
    va_list ap;
Packit f574b8
Packit f574b8
    LYva_start(ap, fmt);
Packit f574b8
    {
Packit f574b8
	result = StrAllocVsprintf(pstr, (size_t) 0, fmt, &ap);
Packit f574b8
    }
Packit f574b8
    va_end(ap);
Packit f574b8
Packit f574b8
    return (result);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Returns a quoted or escaped form of the given parameter, suitable for use in
Packit f574b8
 * a command string.
Packit f574b8
 */
Packit f574b8
#if USE_QUOTED_PARAMETER
Packit f574b8
#define S_QUOTE '\''
Packit f574b8
#define D_QUOTE '"'
Packit f574b8
char *HTQuoteParameter(const char *parameter)
Packit f574b8
{
Packit f574b8
    size_t i;
Packit f574b8
    size_t last;
Packit f574b8
    size_t n = 0;
Packit f574b8
    size_t quoted = 0;
Packit f574b8
    char *result;
Packit f574b8
Packit f574b8
    if (parameter == 0)
Packit f574b8
	parameter = "";
Packit f574b8
Packit f574b8
    last = strlen(parameter);
Packit f574b8
    for (i = 0; i < last; ++i)
Packit f574b8
	if (StrChr("\\&#$^*?(){}<>\"';`|", parameter[i]) != 0
Packit f574b8
	    || isspace(UCH(parameter[i])))
Packit f574b8
	    ++quoted;
Packit f574b8
Packit f574b8
    result = (char *) malloc(last + 5 * quoted + 3);
Packit f574b8
    if (result == NULL)
Packit f574b8
	outofmem(__FILE__, "HTQuoteParameter");
Packit f574b8
Packit f574b8
    n = 0;
Packit f574b8
#if (USE_QUOTED_PARAMETER == 1)
Packit f574b8
    /*
Packit f574b8
     * Only double-quotes are used in Win32/DOS -TD
Packit f574b8
     */
Packit f574b8
    if (quoted)
Packit f574b8
	result[n++] = D_QUOTE;
Packit f574b8
    for (i = 0; i < last; i++) {
Packit f574b8
	result[n++] = parameter[i];
Packit f574b8
    }
Packit f574b8
    if (quoted)
Packit f574b8
	result[n++] = D_QUOTE;
Packit f574b8
#else
Packit f574b8
    if (quoted)
Packit f574b8
	result[n++] = S_QUOTE;
Packit f574b8
    for (i = 0; i < last; i++) {
Packit f574b8
	if (parameter[i] == S_QUOTE) {
Packit f574b8
	    result[n++] = S_QUOTE;
Packit f574b8
	    result[n++] = D_QUOTE;
Packit f574b8
	    result[n++] = parameter[i];
Packit f574b8
	    result[n++] = D_QUOTE;
Packit f574b8
	    result[n++] = S_QUOTE;
Packit f574b8
	} else {
Packit f574b8
	    /* Note:  No special handling of other characters, including
Packit f574b8
	       backslash, since we are constructing a single-quoted string!
Packit f574b8
	       Backslash has no special escape meaning within those for sh
Packit f574b8
	       and compatible shells, so trying to escape a backslash by
Packit f574b8
	       doubling it is unnecessary and would be interpreted by the
Packit f574b8
	       shell as an additional data character. - kw 2000-05-02
Packit f574b8
	     */
Packit f574b8
	    result[n++] = parameter[i];
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    if (quoted)
Packit f574b8
	result[n++] = S_QUOTE;
Packit f574b8
#endif
Packit f574b8
    result[n] = '\0';
Packit f574b8
    return result;
Packit f574b8
}
Packit f574b8
#endif
Packit f574b8
Packit f574b8
#define HTIsParam(string) ((string[0] == '%' && string[1] == 's'))
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Returns the number of "%s" tokens in a system command-template.
Packit f574b8
 */
Packit f574b8
int HTCountCommandArgs(const char *command)
Packit f574b8
{
Packit f574b8
    int number = 0;
Packit f574b8
Packit f574b8
    while (command[0] != 0) {
Packit f574b8
	if (HTIsParam(command))
Packit f574b8
	    number++;
Packit f574b8
	command++;
Packit f574b8
    }
Packit f574b8
    return number;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Returns a pointer into the given string after the given parameter number
Packit f574b8
 */
Packit f574b8
static const char *HTAfterCommandArg(const char *command,
Packit f574b8
				     int number)
Packit f574b8
{
Packit f574b8
    while (number > 0) {
Packit f574b8
	if (command[0] != 0) {
Packit f574b8
	    if (HTIsParam(command)) {
Packit f574b8
		number--;
Packit f574b8
		command++;
Packit f574b8
	    }
Packit f574b8
	    command++;
Packit f574b8
	} else {
Packit f574b8
	    break;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
    return command;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Like HTAddParam, but the parameter may be an environment variable, which we
Packit f574b8
 * will expand and append.  Do this only for things like the command-verb,
Packit f574b8
 * where we obtain the parameter from the user's configuration.  Any quoting
Packit f574b8
 * required for the environment variable has to be done within its value, e.g.,
Packit f574b8
 *
Packit f574b8
 *	setenv EDITOR 'xvile -name "No such class"'
Packit f574b8
 *
Packit f574b8
 * This is useful only when we quote parameters, of course.
Packit f574b8
 */
Packit f574b8
#if USE_QUOTED_PARAMETER
Packit f574b8
void HTAddXpand(char **result,
Packit f574b8
		const char *command,
Packit f574b8
		int number,
Packit f574b8
		const char *parameter)
Packit f574b8
{
Packit f574b8
    if (number > 0) {
Packit f574b8
	const char *last = HTAfterCommandArg(command, number - 1);
Packit f574b8
	const char *next = last;
Packit f574b8
Packit f574b8
	if (number <= 1) {
Packit f574b8
	    FREE(*result);
Packit f574b8
	}
Packit f574b8
Packit f574b8
	while (next[0] != 0) {
Packit f574b8
	    if (HTIsParam(next)) {
Packit f574b8
		if (next != last) {
Packit f574b8
		    size_t len = ((size_t) (next - last)
Packit f574b8
				  + ((*result != 0)
Packit f574b8
				     ? strlen(*result)
Packit f574b8
				     : 0));
Packit f574b8
Packit f574b8
		    HTSACat(result, last);
Packit f574b8
		    (*result)[len] = 0;
Packit f574b8
		}
Packit f574b8
		HTSACat(result, parameter);
Packit f574b8
		CTRACE((tfp, "PARAM-EXP:%s\n", *result));
Packit f574b8
		return;
Packit f574b8
	    }
Packit f574b8
	    next++;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
#endif /* USE_QUOTED_PARAMETER */
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Append string to a system command that we are constructing, without quoting. 
Packit f574b8
 * We're given the index of the newest parameter we're processing.  Zero
Packit f574b8
 * indicates none, so a value of '1' indicates that we copy from the beginning
Packit f574b8
 * of the command string up to the first parameter, substitute the quoted
Packit f574b8
 * parameter and return the result.
Packit f574b8
 *
Packit f574b8
 * Parameters are substituted at "%s" tokens, like printf.  Other printf-style
Packit f574b8
 * tokens are not substituted; they are passed through without change.
Packit f574b8
 */
Packit f574b8
void HTAddToCmd(char **result,
Packit f574b8
		const char *command,
Packit f574b8
		int number,
Packit f574b8
		const char *string)
Packit f574b8
{
Packit f574b8
    if (number > 0) {
Packit f574b8
	const char *last = HTAfterCommandArg(command, number - 1);
Packit f574b8
	const char *next = last;
Packit f574b8
Packit f574b8
	if (number <= 1) {
Packit f574b8
	    FREE(*result);
Packit f574b8
	}
Packit f574b8
	if (string == 0)
Packit f574b8
	    string = "";
Packit f574b8
	while (next[0] != 0) {
Packit f574b8
	    if (HTIsParam(next)) {
Packit f574b8
		if (next != last) {
Packit f574b8
		    size_t len = ((size_t) (next - last)
Packit f574b8
				  + ((*result != 0)
Packit f574b8
				     ? strlen(*result)
Packit f574b8
				     : 0));
Packit f574b8
Packit f574b8
		    HTSACat(result, last);
Packit f574b8
		    (*result)[len] = 0;
Packit f574b8
		}
Packit f574b8
		HTSACat(result, string);
Packit f574b8
		CTRACE((tfp, "PARAM-ADD:%s\n", *result));
Packit f574b8
		return;
Packit f574b8
	    }
Packit f574b8
	    next++;
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Append string-parameter to a system command that we are constructing.  The
Packit f574b8
 * string is a complete parameter (which is a necessary assumption so we can
Packit f574b8
 * quote it properly).
Packit f574b8
 */
Packit f574b8
void HTAddParam(char **result,
Packit f574b8
		const char *command,
Packit f574b8
		int number,
Packit f574b8
		const char *parameter)
Packit f574b8
{
Packit f574b8
    if (number > 0) {
Packit f574b8
#if USE_QUOTED_PARAMETER
Packit f574b8
	char *quoted = HTQuoteParameter(parameter);
Packit f574b8
Packit f574b8
	HTAddToCmd(result, command, number, quoted);
Packit f574b8
	FREE(quoted);
Packit f574b8
#else
Packit f574b8
	HTAddToCmd(result, command, number, parameter);
Packit f574b8
#endif
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Append the remaining command-string to a system command (compare with
Packit f574b8
 * HTAddParam).  Any remaining "%s" tokens are copied as empty strings.
Packit f574b8
 */
Packit f574b8
void HTEndParam(char **result,
Packit f574b8
		const char *command,
Packit f574b8
		int number)
Packit f574b8
{
Packit f574b8
    const char *last;
Packit f574b8
    int count;
Packit f574b8
Packit f574b8
    count = HTCountCommandArgs(command);
Packit f574b8
    if (count < number)
Packit f574b8
	number = count;
Packit f574b8
    last = HTAfterCommandArg(command, number);
Packit f574b8
    if (last[0] != 0) {
Packit f574b8
	HTSACat(result, last);
Packit f574b8
    }
Packit f574b8
    CTRACE((tfp, "PARAM-END:%s\n", *result));
Packit f574b8
}
Packit f574b8
Packit f574b8
/* Binary-strings (may have embedded nulls).  Some modules (HTGopher) assume
Packit f574b8
 * there is a null on the end, anyway.
Packit f574b8
 */
Packit f574b8
Packit f574b8
/* (Re)allocate a bstring, e.g., to increase its buffer size for ad hoc
Packit f574b8
 * operations.
Packit f574b8
 */
Packit f574b8
void HTSABAlloc(bstring **dest, int len)
Packit f574b8
{
Packit f574b8
    if (*dest == 0) {
Packit f574b8
	*dest = typecalloc(bstring);
Packit f574b8
Packit f574b8
	if (*dest == 0)
Packit f574b8
	    outofmem(__FILE__, "HTSABAlloc");
Packit f574b8
    }
Packit f574b8
Packit f574b8
    if ((*dest)->len != len) {
Packit f574b8
	(*dest)->str = typeRealloc(char, (*dest)->str, len);
Packit f574b8
Packit f574b8
	if ((*dest)->str == 0)
Packit f574b8
	    outofmem(__FILE__, "HTSABAlloc");
Packit f574b8
Packit f574b8
	(*dest)->len = len;
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/* Allocate a new bstring, and return it.
Packit f574b8
*/
Packit f574b8
void HTSABCopy(bstring **dest, const char *src,
Packit f574b8
	       int len)
Packit f574b8
{
Packit f574b8
    bstring *t;
Packit f574b8
    unsigned need = (unsigned) (len + 1);
Packit f574b8
Packit f574b8
    CTRACE2(TRACE_BSTRING,
Packit f574b8
	    (tfp, "HTSABCopy(%p, %p, %d)\n",
Packit f574b8
	     (void *) dest, (const void *) src, len));
Packit f574b8
    HTSABFree(dest);
Packit f574b8
    if (src) {
Packit f574b8
	if (TRACE_BSTRING) {
Packit f574b8
	    CTRACE((tfp, "===    %4d:", len));
Packit f574b8
	    trace_bstring2(src, len);
Packit f574b8
	    CTRACE((tfp, "\n"));
Packit f574b8
	}
Packit f574b8
	if ((t = (bstring *) malloc(sizeof(bstring))) == NULL)
Packit f574b8
	      outofmem(__FILE__, "HTSABCopy");
Packit f574b8
Packit f574b8
	if ((t->str = typeMallocn(char, need)) == NULL)
Packit f574b8
	      outofmem(__FILE__, "HTSABCopy");
Packit f574b8
Packit f574b8
	MemCpy(t->str, src, len);
Packit f574b8
	t->len = len;
Packit f574b8
	t->str[t->len] = '\0';
Packit f574b8
	*dest = t;
Packit f574b8
    }
Packit f574b8
    if (TRACE_BSTRING) {
Packit f574b8
	CTRACE((tfp, "=>     %4d:", BStrLen(*dest)));
Packit f574b8
	trace_bstring(*dest);
Packit f574b8
	CTRACE((tfp, "\n"));
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Initialize with a null-terminated string (discards the null).
Packit f574b8
 */
Packit f574b8
void HTSABCopy0(bstring **dest, const char *src)
Packit f574b8
{
Packit f574b8
    HTSABCopy(dest, src, (int) strlen(src));
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Append a block of memory to a bstring.
Packit f574b8
 */
Packit f574b8
void HTSABCat(bstring **dest, const char *src,
Packit f574b8
	      int len)
Packit f574b8
{
Packit f574b8
    bstring *t = *dest;
Packit f574b8
Packit f574b8
    CTRACE2(TRACE_BSTRING,
Packit f574b8
	    (tfp, "HTSABCat(%p, %p, %d)\n",
Packit f574b8
	     (void *) dest, (const void *) src, len));
Packit f574b8
    if (src) {
Packit f574b8
	unsigned need = (unsigned) (len + 1);
Packit f574b8
Packit f574b8
	if (TRACE_BSTRING) {
Packit f574b8
	    CTRACE((tfp, "===    %4d:", len));
Packit f574b8
	    trace_bstring2(src, len);
Packit f574b8
	    CTRACE((tfp, "\n"));
Packit f574b8
	}
Packit f574b8
	if (t) {
Packit f574b8
	    unsigned length = (unsigned) t->len + need;
Packit f574b8
Packit f574b8
	    t->str = typeRealloc(char, t->str, length);
Packit f574b8
	} else {
Packit f574b8
	    if ((t = typecalloc(bstring)) == NULL)
Packit f574b8
		  outofmem(__FILE__, "HTSACat");
Packit f574b8
Packit f574b8
	    t->str = typeMallocn(char, need);
Packit f574b8
	}
Packit f574b8
	if (t->str == NULL)
Packit f574b8
	    outofmem(__FILE__, "HTSACat");
Packit f574b8
Packit f574b8
	MemCpy(t->str + t->len, src, len);
Packit f574b8
	t->len += len;
Packit f574b8
	t->str[t->len] = '\0';
Packit f574b8
	*dest = t;
Packit f574b8
    }
Packit f574b8
    if (TRACE_BSTRING) {
Packit f574b8
	CTRACE((tfp, "=>     %4d:", BStrLen(*dest)));
Packit f574b8
	trace_bstring(*dest);
Packit f574b8
	CTRACE((tfp, "\n"));
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Append a null-terminated string (discards the null).
Packit f574b8
 */
Packit f574b8
void HTSABCat0(bstring **dest, const char *src)
Packit f574b8
{
Packit f574b8
    HTSABCat(dest, src, (int) strlen(src));
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Compare two bstring's for equality
Packit f574b8
 */
Packit f574b8
BOOL HTSABEql(bstring *a, bstring *b)
Packit f574b8
{
Packit f574b8
    unsigned len_a = (unsigned) ((a != 0) ? a->len : 0);
Packit f574b8
    unsigned len_b = (unsigned) ((b != 0) ? b->len : 0);
Packit f574b8
Packit f574b8
    if (len_a == len_b) {
Packit f574b8
	if (len_a == 0
Packit f574b8
	    || MemCmp(a->str, b->str, a->len) == 0)
Packit f574b8
	    return TRUE;
Packit f574b8
    }
Packit f574b8
    return FALSE;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Deallocate a bstring.
Packit f574b8
 */
Packit f574b8
void HTSABFree(bstring **ptr)
Packit f574b8
{
Packit f574b8
    if (*ptr != NULL) {
Packit f574b8
	FREE((*ptr)->str);
Packit f574b8
	FREE(*ptr);
Packit f574b8
	*ptr = NULL;
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Use this function to perform formatted sprintf's onto the end of a bstring.
Packit f574b8
 * The bstring may contain embedded nulls; the formatted portions must not.
Packit f574b8
 */
Packit f574b8
bstring *HTBprintf(bstring **pstr, const char *fmt,...)
Packit f574b8
{
Packit f574b8
    bstring *result = 0;
Packit f574b8
    char *temp = 0;
Packit f574b8
    va_list ap;
Packit f574b8
Packit f574b8
    LYva_start(ap, fmt);
Packit f574b8
    {
Packit f574b8
	temp = StrAllocVsprintf(&temp, (size_t) 0, fmt, &ap);
Packit f574b8
	if (non_empty(temp)) {
Packit f574b8
	    HTSABCat(pstr, temp, (int) strlen(temp));
Packit f574b8
	}
Packit f574b8
	FREE(temp);
Packit f574b8
	result = *pstr;
Packit f574b8
    }
Packit f574b8
    va_end(ap);
Packit f574b8
Packit f574b8
    return (result);
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Write binary-data to the logfile, making it safe for most editors to view.
Packit f574b8
 * That is most, since we do not restrict line-length.  Nulls and other
Packit f574b8
 * non-printing characters are addressed.
Packit f574b8
 */
Packit f574b8
void trace_bstring2(const char *text,
Packit f574b8
		    int size)
Packit f574b8
{
Packit f574b8
    int n;
Packit f574b8
Packit f574b8
    if (text != 0) {
Packit f574b8
	for (n = 0; n < size; ++n) {
Packit f574b8
	    int ch = UCH(text[n]);
Packit f574b8
Packit f574b8
	    switch (ch) {
Packit f574b8
	    case '\\':
Packit f574b8
		fputs("\\\\", tfp);
Packit f574b8
		break;
Packit f574b8
	    case '\r':
Packit f574b8
		fputs("\\r", tfp);
Packit f574b8
		break;
Packit f574b8
	    case '\t':
Packit f574b8
		fputs("\\t", tfp);
Packit f574b8
		break;
Packit f574b8
	    case '\f':
Packit f574b8
		fputs("\\f", tfp);
Packit f574b8
		break;
Packit f574b8
	    default:
Packit f574b8
		if (isprint(ch) || isspace(ch)) {
Packit f574b8
		    fputc(ch, tfp);
Packit f574b8
		} else {
Packit f574b8
		    fprintf(tfp, "\\%03o", ch);
Packit f574b8
		}
Packit f574b8
		break;
Packit f574b8
	    }
Packit f574b8
	}
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
void trace_bstring(bstring *data)
Packit f574b8
{
Packit f574b8
    trace_bstring2(BStrData(data), BStrLen(data));
Packit f574b8
}