|
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 |
}
|