updated libopts

This commit is contained in:
Nikos Mavrogiannopoulos
2013-04-28 15:01:17 +03:00
parent fed7861b89
commit 66d9e9404d
59 changed files with 7427 additions and 4770 deletions

View File

@@ -2,13 +2,17 @@
/**
* \file nested.c
*
* Time-stamp: "2012-03-04 13:30:07 bkorb"
* Handle options with arguments that contain nested values.
*
* @addtogroup autoopts
* @{
*/
/*
* Automated Options Nested Values module.
*
* This file is part of AutoOpts, a companion to AutoGen.
* AutoOpts is free software.
* AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved
* AutoOpts is Copyright (C) 1992-2013 by Bruce Korb - all rights reserved
*
* AutoOpts is available under any one of two licenses. The license
* in use must be one of these two and the choice is under the control
@@ -20,11 +24,11 @@
* The Modified Berkeley Software Distribution License
* See the file "COPYING.mbsd"
*
* These files have the following md5sums:
* These files have the following sha256 sums:
*
* 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
* 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
* 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
* 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
* 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
* 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
*/
typedef struct {
@@ -47,35 +51,44 @@ static xml_xlate_t const xml_xlate[] = {
/* = = = START-STATIC-FORWARD = = = */
static void
remove_continuation(char* pzSrc);
remove_continuation(char * src);
static char const*
scan_q_str(char const* pzTxt);
static tOptionValue *
add_string(void ** pp, char const * pzName, size_t nameLen,
add_string(void ** pp, char const * name, size_t nm_len,
char const* pzValue, size_t dataLen);
static tOptionValue *
add_bool(void ** pp, char const * pzName, size_t nameLen,
char const* pzValue, size_t dataLen);
add_bool(void ** pp, char const * name, size_t nm_len,
char const * val, size_t d_len);
static tOptionValue*
add_number(void** pp, char const* pzName, size_t nameLen,
char const* pzValue, size_t dataLen);
add_number(void** pp, char const* pzName, size_t nm_len,
char const* val, size_t d_len);
static tOptionValue*
add_nested(void** pp, char const* pzName, size_t nameLen,
char* pzValue, size_t dataLen);
add_nested(void** pp, char const* pzName, size_t nm_len,
char* val, size_t d_len);
static char const *
scan_name(char const* pzName, tOptionValue* pRes);
static char const*
scan_xml(char const* pzName, tOptionValue* pRes);
static char const *
unnamed_xml(char const * txt);
static char const *
scan_xml_name(char const * name, size_t * nm_len, tOptionValue * val);
static char const *
find_end_xml(char const * src, size_t nm_len, char const * val, size_t * len);
static char const *
scan_xml(char const * xml_name, tOptionValue * res_val);
static void
sort_list(tArgList* pAL);
sort_list(tArgList * arg_list);
/* = = = END-STATIC-FORWARD = = = */
/**
@@ -83,13 +96,13 @@ sort_list(tArgList* pAL);
* characters, but trim out the backslash:
*/
static void
remove_continuation(char* pzSrc)
remove_continuation(char * src)
{
char* pzD;
do {
while (*pzSrc == NL) pzSrc++;
pzD = strchr(pzSrc, NL);
while (*src == NL) src++;
pzD = strchr(src, NL);
if (pzD == NULL)
return;
@@ -98,20 +111,20 @@ remove_continuation(char* pzSrc)
* points to a newline character. It now becomes the source and
* pzD goes to the previous character.
*/
pzSrc = pzD--;
src = pzD--;
if (*pzD != '\\')
pzD++;
} while (pzD == pzSrc);
} while (pzD == src);
/*
* Start shifting text.
*/
for (;;) {
char ch = ((*pzD++) = *(pzSrc++));
char ch = ((*pzD++) = *(src++));
switch (ch) {
case NUL: return;
case '\\':
if (*pzSrc == NL)
if (*src == NL)
--pzD; /* rewrite on next iteration */
}
}
@@ -158,11 +171,11 @@ scan_q_str(char const* pzTxt)
* Associate a name with either a string or no value.
*/
static tOptionValue *
add_string(void ** pp, char const * pzName, size_t nameLen,
add_string(void ** pp, char const * name, size_t nm_len,
char const* pzValue, size_t dataLen)
{
tOptionValue* pNV;
size_t sz = nameLen + dataLen + sizeof(*pNV);
size_t sz = nm_len + dataLen + sizeof(*pNV);
pNV = AGALOC(sz, "option name/str value pair");
if (pNV == NULL)
@@ -175,14 +188,14 @@ add_string(void ** pp, char const * pzName, size_t nameLen,
} else {
pNV->valType = OPARG_TYPE_STRING;
if (dataLen > 0) {
char const * pzSrc = pzValue;
char const * src = pzValue;
char * pzDst = pNV->v.strVal;
int ct = dataLen;
int ct = (int)dataLen;
do {
int ch = *(pzSrc++) & 0xFF;
int ch = *(src++) & 0xFF;
if (ch == NUL) goto data_copy_done;
if (ch == '&')
ch = get_special_char(&pzSrc, &ct);
ch = get_special_char(&src, &ct);
*(pzDst++) = (char)ch;
} while (--ct > 0);
data_copy_done:
@@ -195,8 +208,8 @@ add_string(void ** pp, char const * pzName, size_t nameLen,
pNV->pzName = pNV->v.strVal + dataLen + 1;
}
memcpy(pNV->pzName, pzName, nameLen);
pNV->pzName[ nameLen ] = NUL;
memcpy(pNV->pzName, name, nm_len);
pNV->pzName[ nm_len ] = NUL;
addArgListEntry(pp, pNV);
return pNV;
}
@@ -205,95 +218,95 @@ add_string(void ** pp, char const * pzName, size_t nameLen,
* Associate a name with either a string or no value.
*/
static tOptionValue *
add_bool(void ** pp, char const * pzName, size_t nameLen,
char const* pzValue, size_t dataLen)
add_bool(void ** pp, char const * name, size_t nm_len,
char const * val, size_t d_len)
{
tOptionValue * pNV;
tOptionValue * new_val;
{
size_t sz = nameLen + sizeof(tOptionValue) + 1;
pNV = AGALOC(sz, "name/bool value");
size_t sz = nm_len + sizeof(tOptionValue) + 1;
new_val = AGALOC(sz, "name/bool value");
}
{
char * p = SPN_WHITESPACE_CHARS(pzValue);
dataLen -= p - pzValue;
pzValue = p;
char * p = SPN_WHITESPACE_CHARS(val);
d_len -= (unsigned long)(p - val);
val = p;
}
if (dataLen == 0)
pNV->v.boolVal = 0;
if (d_len == 0)
new_val->v.boolVal = 0;
else if (IS_DEC_DIGIT_CHAR(*pzValue))
pNV->v.boolVal = atoi(pzValue);
else if (IS_DEC_DIGIT_CHAR(*val))
new_val->v.boolVal = (unsigned)atoi(val);
else pNV->v.boolVal = ! IS_FALSE_TYPE_CHAR(*pzValue);
else new_val->v.boolVal = ! IS_FALSE_TYPE_CHAR(*val);
pNV->valType = OPARG_TYPE_BOOLEAN;
pNV->pzName = (char*)(pNV + 1);
memcpy(pNV->pzName, pzName, nameLen);
pNV->pzName[ nameLen ] = NUL;
addArgListEntry(pp, pNV);
return pNV;
new_val->valType = OPARG_TYPE_BOOLEAN;
new_val->pzName = (char*)(new_val + 1);
memcpy(new_val->pzName, name, nm_len);
new_val->pzName[ nm_len ] = NUL;
addArgListEntry(pp, new_val);
return new_val;
}
/**
* Associate a name with either a string or no value.
*/
static tOptionValue*
add_number(void** pp, char const* pzName, size_t nameLen,
char const* pzValue, size_t dataLen)
add_number(void** pp, char const* pzName, size_t nm_len,
char const* val, size_t d_len)
{
tOptionValue* pNV;
size_t sz = nameLen + sizeof(*pNV) + 1;
tOptionValue* new_val;
size_t sz = nm_len + sizeof(*new_val) + 1;
pNV = AGALOC(sz, "option name/bool value pair");
if (pNV == NULL)
new_val = AGALOC(sz, "bool val");
if (new_val == NULL)
return NULL;
while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) {
dataLen--; pzValue++;
while (IS_WHITESPACE_CHAR(*val) && (d_len > 0)) {
d_len--; val++;
}
if (dataLen == 0)
pNV->v.longVal = 0;
if (d_len == 0)
new_val->v.longVal = 0;
else
pNV->v.longVal = strtol(pzValue, 0, 0);
new_val->v.longVal = strtol(val, 0, 0);
pNV->valType = OPARG_TYPE_NUMERIC;
pNV->pzName = (char*)(pNV + 1);
memcpy(pNV->pzName, pzName, nameLen);
pNV->pzName[ nameLen ] = NUL;
addArgListEntry(pp, pNV);
return pNV;
new_val->valType = OPARG_TYPE_NUMERIC;
new_val->pzName = (char*)(new_val + 1);
memcpy(new_val->pzName, pzName, nm_len);
new_val->pzName[ nm_len ] = NUL;
addArgListEntry(pp, new_val);
return new_val;
}
/**
* Associate a name with either a string or no value.
*/
static tOptionValue*
add_nested(void** pp, char const* pzName, size_t nameLen,
char* pzValue, size_t dataLen)
add_nested(void** pp, char const* pzName, size_t nm_len,
char* val, size_t d_len)
{
tOptionValue* pNV;
tOptionValue* new_val;
if (dataLen == 0) {
size_t sz = nameLen + sizeof(*pNV) + 1;
pNV = AGALOC(sz, "empty nested value pair");
if (pNV == NULL)
if (d_len == 0) {
size_t sz = nm_len + sizeof(*new_val) + 1;
new_val = AGALOC(sz, "empty nest");
if (new_val == NULL)
return NULL;
pNV->v.nestVal = NULL;
pNV->valType = OPARG_TYPE_HIERARCHY;
pNV->pzName = (char*)(pNV + 1);
memcpy(pNV->pzName, pzName, nameLen);
pNV->pzName[ nameLen ] = NUL;
new_val->v.nestVal = NULL;
new_val->valType = OPARG_TYPE_HIERARCHY;
new_val->pzName = (char*)(new_val + 1);
memcpy(new_val->pzName, pzName, nm_len);
new_val->pzName[ nm_len ] = NUL;
} else {
pNV = optionLoadNested(pzValue, pzName, nameLen);
new_val = optionLoadNested(val, pzName, nm_len);
}
if (pNV != NULL)
addArgListEntry(pp, pNV);
if (new_val != NULL)
addArgListEntry(pp, new_val);
return pNV;
return new_val;
}
/**
@@ -303,11 +316,11 @@ add_nested(void** pp, char const* pzName, size_t nameLen,
static char const *
scan_name(char const* pzName, tOptionValue* pRes)
{
tOptionValue* pNV;
tOptionValue* new_val;
char const * pzScan = pzName+1; /* we know first char is a name char */
char const * pzVal;
size_t nameLen = 1;
size_t dataLen = 0;
size_t nm_len = 1;
size_t d_len = 0;
/*
* Scan over characters that name a value. These names may not end
@@ -316,7 +329,7 @@ scan_name(char const* pzName, tOptionValue* pRes)
pzScan = SPN_VALUE_NAME_CHARS(pzName + 1);
if (pzScan[-1] == ':')
pzScan--;
nameLen = pzScan - pzName;
nm_len = (size_t)(pzScan - pzName);
pzScan = SPN_HORIZ_WHITE_CHARS(pzScan);
@@ -336,18 +349,18 @@ scan_name(char const* pzName, tOptionValue* pRes)
/* FALLTHROUGH */
case NUL:
add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
add_string(&(pRes->v.nestVal), pzName, nm_len, NULL, (size_t)0);
break;
case '"':
case '\'':
pzVal = pzScan;
pzScan = scan_q_str(pzScan);
dataLen = pzScan - pzVal;
pNV = add_string(&(pRes->v.nestVal), pzName, nameLen, pzVal,
dataLen);
if ((pNV != NULL) && (option_load_mode == OPTION_LOAD_COOKED))
ao_string_cook(pNV->v.strVal, NULL);
d_len = (size_t)(pzScan - pzVal);
new_val = add_string(&(pRes->v.nestVal), pzName, nm_len, pzVal,
d_len);
if ((new_val != NULL) && (option_load_mode == OPTION_LOAD_COOKED))
ao_string_cook(new_val->v.strVal, NULL);
break;
default:
@@ -362,7 +375,7 @@ scan_name(char const* pzName, tOptionValue* pRes)
switch (ch) {
case NUL:
pzScan--;
dataLen = pzScan - pzVal;
d_len = (size_t)(pzScan - pzVal);
goto string_done;
/* FALLTHROUGH */
@@ -374,12 +387,12 @@ scan_name(char const* pzName, tOptionValue* pRes)
/* FALLTHROUGH */
case ',':
dataLen = (pzScan - pzVal) - 1;
d_len = (size_t)(pzScan - pzVal) - 1;
string_done:
pNV = add_string(&(pRes->v.nestVal), pzName, nameLen,
pzVal, dataLen);
if (pNV != NULL)
remove_continuation(pNV->v.strVal);
new_val = add_string(&(pRes->v.nestVal), pzName, nm_len,
pzVal, d_len);
if (new_val != NULL)
remove_continuation(new_val->v.strVal);
goto leave_scan_name;
}
}
@@ -389,140 +402,194 @@ scan_name(char const* pzName, tOptionValue* pRes)
return pzScan;
}
/**
* Some xml element that does not start with a name.
* The next character must be either '!' (introducing a comment),
* or '?' (introducing an XML meta-marker of some sort).
* We ignore these and indicate an error (NULL result) otherwise.
*
* @param[in] txt the text within an xml bracket
* @returns the address of the character after the closing marker, or NULL.
*/
static char const *
unnamed_xml(char const * txt)
{
switch (*txt) {
default:
txt = NULL;
break;
case '!':
txt = strstr(txt, "-->");
if (txt != NULL)
txt += 3;
break;
case '?':
txt = strchr(txt, '>');
if (txt != NULL)
txt++;
break;
}
return txt;
}
/**
* Scan off the xml element name, and the rest of the header, too.
* Set the value type to NONE if it ends with "/>".
*
* @param[in] name the first name character (alphabetic)
* @param[out] nm_len the length of the name
* @param[out] val set valType field to STRING or NONE.
*
* @returns the scan resumption point, or NULL on error
*/
static char const *
scan_xml_name(char const * name, size_t * nm_len, tOptionValue * val)
{
char const * scan = SPN_VALUE_NAME_CHARS(name + 1);
*nm_len = (size_t)(scan - name);
if (*nm_len > 64)
return NULL;
val->valType = OPARG_TYPE_STRING;
if (IS_WHITESPACE_CHAR(*scan)) {
/*
* There are attributes following the name. Parse 'em.
*/
scan = SPN_WHITESPACE_CHARS(scan);
scan = parse_attrs(NULL, scan, &option_load_mode, val);
if (scan == NULL)
return NULL; /* oops */
}
if (! IS_END_XML_TOKEN_CHAR(*scan))
return NULL; /* oops */
if (*scan == '/') {
/*
* Single element XML entries get inserted as an empty string.
*/
if (*++scan != '>')
return NULL;
val->valType = OPARG_TYPE_NONE;
}
return scan+1;
}
/**
* We've found a closing '>' without a preceding '/', thus we must search
* the text for '<name/>' where "name" is the name of the XML element.
*
* @param[in] name the start of the name in the element header
* @param[in] nm_len the length of that name
* @param[out] len the length of the value (string between header and
* the trailer/tail.
* @returns the character after the trailer, or NULL if not found.
*/
static char const *
find_end_xml(char const * src, size_t nm_len, char const * val, size_t * len)
{
char z[72] = "</";
char * dst = z + 2;
do {
*(dst++) = *(src++);
} while (--nm_len > 0); /* nm_len is known to be 64 or less */
*(dst++) = '>';
*dst = NUL;
{
char const * res = strstr(val, z);
if (res != NULL) {
char const * end = (option_load_mode != OPTION_LOAD_KEEP)
? SPN_WHITESPACE_BACK(val, res)
: res;
*len = (size_t)(end - val); /* includes trailing white space */
res = SPN_WHITESPACE_CHARS(res + (dst - z));
}
return res;
}
}
/**
* We've found a '<' character. We ignore this if it is a comment or a
* directive. If it is something else, then whatever it is we are looking
* at is bogus. Returning NULL stops processing.
*
* @param[in] xml_name the name of an xml bracket (usually)
* @param[in,out] res_val the option data derived from the XML element
*
* @returns the place to resume scanning input
*/
static char const*
scan_xml(char const* pzName, tOptionValue* pRes)
static char const *
scan_xml(char const * xml_name, tOptionValue * res_val)
{
size_t nameLen;
size_t valLen;
char const* pzScan = ++pzName;
char const* pzVal;
tOptionValue valu;
tOptionValue* pNewVal;
size_t nm_len, v_len;
char const * scan;
char const * val_str;
tOptionValue valu;
tOptionLoadMode save_mode = option_load_mode;
if (! IS_VAR_FIRST_CHAR(*pzName)) {
switch (*pzName) {
default:
pzName = NULL;
break;
if (! IS_VAR_FIRST_CHAR(*++xml_name))
return unnamed_xml(xml_name);
case '!':
pzName = strstr(pzName, "-->");
if (pzName != NULL)
pzName += 3;
break;
/*
* "scan_xml_name()" may change "option_load_mode".
*/
val_str = scan_xml_name(xml_name, &nm_len, &valu);
if (val_str == NULL)
goto bail_scan_xml;
case '?':
pzName = strchr(pzName, '>');
if (pzName != NULL)
pzName++;
break;
}
return pzName;
if (valu.valType == OPARG_TYPE_NONE)
scan = val_str;
else {
if (option_load_mode != OPTION_LOAD_KEEP)
val_str = SPN_WHITESPACE_CHARS(val_str);
scan = find_end_xml(xml_name, nm_len, val_str, &v_len);
if (scan == NULL)
goto bail_scan_xml;
}
pzScan = SPN_VALUE_NAME_CHARS(pzName+1);
nameLen = pzScan - pzName;
if (nameLen > 64)
return NULL;
valu.valType = OPARG_TYPE_STRING;
switch (*pzScan) {
case ' ':
case '\t':
pzScan = parse_attrs(
NULL, (char*)pzScan, &option_load_mode, &valu );
if (*pzScan == '>') {
pzScan++;
break;
}
if (*pzScan != '/') {
option_load_mode = save_mode;
return NULL;
}
/* FALLTHROUGH */
case '/':
if (*++pzScan != '>') {
option_load_mode = save_mode;
return NULL;
}
add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
option_load_mode = save_mode;
return pzScan+1;
default:
option_load_mode = save_mode;
return NULL;
case '>':
pzScan++;
break;
}
pzVal = pzScan;
{
char z[68];
char* pzD = z;
int ct = nameLen;
char const* pzS = pzName;
*(pzD++) = '<';
*(pzD++) = '/';
do {
*(pzD++) = *(pzS++);
} while (--ct > 0);
*(pzD++) = '>';
*pzD = NUL;
pzScan = strstr(pzScan, z);
if (pzScan == NULL) {
option_load_mode = save_mode;
return NULL;
}
valLen = (pzScan - pzVal);
pzScan += nameLen + 3;
pzScan = SPN_WHITESPACE_CHARS(pzScan);
}
/*
* "scan" now points to where the scan is to resume after returning.
* It either points after "/>" at the end of the XML element header,
* or it points after the "</name>" tail based on the name in the header.
*/
switch (valu.valType) {
case OPARG_TYPE_NONE:
add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0);
add_string(&(res_val->v.nestVal), xml_name, nm_len, NULL, 0);
break;
case OPARG_TYPE_STRING:
pNewVal = add_string(
&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
{
tOptionValue * new_val = add_string(
&(res_val->v.nestVal), xml_name, nm_len, val_str, v_len);
if (option_load_mode != OPTION_LOAD_KEEP)
munge_str(new_val->v.strVal, option_load_mode);
if (option_load_mode == OPTION_LOAD_KEEP)
break;
mungeString(pNewVal->v.strVal, option_load_mode);
break;
}
case OPARG_TYPE_BOOLEAN:
add_bool(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
add_bool(&(res_val->v.nestVal), xml_name, nm_len, val_str, v_len);
break;
case OPARG_TYPE_NUMERIC:
add_number(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen);
add_number(&(res_val->v.nestVal), xml_name, nm_len, val_str, v_len);
break;
case OPARG_TYPE_HIERARCHY:
{
char* pz = AGALOC(valLen+1, "hierarchical scan");
char * pz = AGALOC(v_len+1, "h scan");
if (pz == NULL)
break;
memcpy(pz, pzVal, valLen);
pz[valLen] = NUL;
add_nested(&(pRes->v.nestVal), pzName, nameLen, pz, valLen);
memcpy(pz, val_str, v_len);
pz[v_len] = NUL;
add_nested(&(res_val->v.nestVal), xml_name, nm_len, pz, v_len);
AGFREE(pz);
break;
}
@@ -534,7 +601,11 @@ scan_xml(char const* pzName, tOptionValue* pRes)
}
option_load_mode = save_mode;
return pzScan;
return scan;
bail_scan_xml:
option_load_mode = save_mode;
return NULL;
}
@@ -545,19 +616,19 @@ scan_xml(char const* pzName, tOptionValue* pRes)
* knowing what they are doing.
*/
LOCAL void
unload_arg_list(tArgList* pAL)
unload_arg_list(tArgList * arg_list)
{
int ct = pAL->useCt;
tCC** ppNV = pAL->apzArgs;
int ct = arg_list->useCt;
char const ** pnew_val = arg_list->apzArgs;
while (ct-- > 0) {
tOptionValue* pNV = (tOptionValue*)(void*)*(ppNV++);
if (pNV->valType == OPARG_TYPE_HIERARCHY)
unload_arg_list(pNV->v.nestVal);
AGFREE(pNV);
tOptionValue* new_val = (tOptionValue*)(void*)*(pnew_val++);
if (new_val->valType == OPARG_TYPE_HIERARCHY)
unload_arg_list(new_val->v.nestVal);
AGFREE(new_val);
}
AGFREE((void*)pAL);
AGFREE((void*)arg_list);
}
/*=export_func optionUnloadNested
@@ -571,17 +642,17 @@ unload_arg_list(tArgList* pAL)
* @pxref{libopts-configFileLoad}).
=*/
void
optionUnloadNested(tOptionValue const * pOV)
optionUnloadNested(tOptionValue const * opt_val)
{
if (pOV == NULL) return;
if (pOV->valType != OPARG_TYPE_HIERARCHY) {
if (opt_val == NULL) return;
if (opt_val->valType != OPARG_TYPE_HIERARCHY) {
errno = EINVAL;
return;
}
unload_arg_list(pOV->v.nestVal);
unload_arg_list(opt_val->v.nestVal);
AGFREE((void*)pOV);
AGFREE((void*)opt_val);
}
/**
@@ -590,27 +661,27 @@ optionUnloadNested(tOptionValue const * pOV)
* Typically, we also hope the input is sorted.
*/
static void
sort_list(tArgList* pAL)
sort_list(tArgList * arg_list)
{
int ix;
int lm = pAL->useCt;
int lm = arg_list->useCt;
/*
* This loop iterates "useCt" - 1 times.
*/
for (ix = 0; ++ix < lm;) {
int iy = ix-1;
tOptionValue* pNewNV = (tOptionValue*)(void*)(pAL->apzArgs[ix]);
tOptionValue* pOldNV = (tOptionValue*)(void*)(pAL->apzArgs[iy]);
tOptionValue * new_v = C(tOptionValue *, arg_list->apzArgs[ix]);
tOptionValue * old_v = C(tOptionValue *, arg_list->apzArgs[iy]);
/*
* For as long as the new entry precedes the "old" entry,
* move the old pointer. Stop before trying to extract the
* "-1" entry.
*/
while (strcmp(pOldNV->pzName, pNewNV->pzName) > 0) {
pAL->apzArgs[iy+1] = (void*)pOldNV;
pOldNV = (tOptionValue*)(void*)(pAL->apzArgs[--iy]);
while (strcmp(old_v->pzName, new_v->pzName) > 0) {
arg_list->apzArgs[iy+1] = (void*)old_v;
old_v = (tOptionValue*)(void*)(arg_list->apzArgs[--iy]);
if (iy < 0)
break;
}
@@ -619,7 +690,7 @@ sort_list(tArgList* pAL)
* Always store the pointer. Sometimes it is redundant,
* but the redundancy is cheaper than a test and branch sequence.
*/
pAL->apzArgs[iy+1] = (void*)pNewNV;
arg_list->apzArgs[iy+1] = (void*)new_v;
}
}
@@ -627,9 +698,9 @@ sort_list(tArgList* pAL)
* private:
*
* what: parse a hierarchical option argument
* arg: + char const* + pzTxt + the text to scan +
* arg: + char const* + pzName + the name for the text +
* arg: + size_t + nameLen + the length of "name" +
* arg: + char const * + pzTxt + the text to scan +
* arg: + char const * + pzName + the name for the text +
* arg: + size_t + nm_len + the length of "name" +
*
* ret_type: tOptionValue*
* ret_desc: An allocated, compound value structure
@@ -649,65 +720,57 @@ sort_list(tArgList* pAL)
* @code{ENOMSG} no configuration values were found
* @end itemize
=*/
LOCAL tOptionValue*
optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen)
LOCAL tOptionValue *
optionLoadNested(char const * text, char const * name, size_t nm_len)
{
tOptionValue* pRes;
tOptionValue* res_val;
/*
* Make sure we have some data and we have space to put what we find.
*/
if (pzTxt == NULL) {
if (text == NULL) {
errno = EINVAL;
return NULL;
}
pzTxt = SPN_WHITESPACE_CHARS(pzTxt);
if (*pzTxt == NUL) {
text = SPN_WHITESPACE_CHARS(text);
if (*text == NUL) {
errno = ENOMSG;
return NULL;
}
pRes = AGALOC(sizeof(*pRes) + nameLen + 1, "nested args");
if (pRes == NULL) {
errno = ENOMEM;
return NULL;
}
pRes->valType = OPARG_TYPE_HIERARCHY;
pRes->pzName = (char*)(pRes + 1);
memcpy(pRes->pzName, pzName, nameLen);
pRes->pzName[nameLen] = NUL;
res_val = AGALOC(sizeof(*res_val) + nm_len + 1, "nest args");
res_val->valType = OPARG_TYPE_HIERARCHY;
res_val->pzName = (char*)(res_val + 1);
memcpy(res_val->pzName, name, nm_len);
res_val->pzName[nm_len] = NUL;
{
tArgList * pAL = AGALOC(sizeof(*pAL), "nested arg list");
if (pAL == NULL) {
AGFREE(pRes);
return NULL;
}
tArgList * arg_list = AGALOC(sizeof(*arg_list), "nest arg l");
pRes->v.nestVal = pAL;
pAL->useCt = 0;
pAL->allocCt = MIN_ARG_ALLOC_CT;
res_val->v.nestVal = arg_list;
arg_list->useCt = 0;
arg_list->allocCt = MIN_ARG_ALLOC_CT;
}
/*
* Scan until we hit a NUL.
*/
do {
pzTxt = SPN_WHITESPACE_CHARS(pzTxt);
if (IS_VAR_FIRST_CHAR(*pzTxt))
pzTxt = scan_name(pzTxt, pRes);
text = SPN_WHITESPACE_CHARS(text);
if (IS_VAR_FIRST_CHAR(*text))
text = scan_name(text, res_val);
else switch (*pzTxt) {
else switch (*text) {
case NUL: goto scan_done;
case '<': pzTxt = scan_xml(pzTxt, pRes);
if (pzTxt == NULL) goto woops;
if (*pzTxt == ',') pzTxt++; break;
case '#': pzTxt = strchr(pzTxt, NL); break;
case '<': text = scan_xml(text, res_val);
if (text == NULL) goto woops;
if (*text == ',') text++; break;
case '#': text = strchr(text, NL); break;
default: goto woops;
}
} while (pzTxt != NULL); scan_done:;
} while (text != NULL); scan_done:;
{
tArgList * al = pRes->v.nestVal;
tArgList * al = res_val->v.nestVal;
if (al->useCt == 0) {
errno = ENOMSG;
goto woops;
@@ -716,11 +779,11 @@ optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen)
sort_list(al);
}
return pRes;
return res_val;
woops:
AGFREE(pRes->v.nestVal);
AGFREE(pRes);
AGFREE(res_val->v.nestVal);
AGFREE(res_val);
return NULL;
}
@@ -728,45 +791,45 @@ optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen)
* private:
*
* what: parse a hierarchical option argument
* arg: + tOptions* + pOpts + program options descriptor +
* arg: + tOptDesc* + pOptDesc + the descriptor for this arg +
* arg: + tOptions* + opts + program options descriptor +
* arg: + tOptDesc* + od + the descriptor for this arg +
*
* doc:
* Nested value was found on the command line
=*/
void
optionNestedVal(tOptions* pOpts, tOptDesc* pOD)
optionNestedVal(tOptions * opts, tOptDesc * od)
{
if (pOpts < OPTPROC_EMIT_LIMIT)
if (opts < OPTPROC_EMIT_LIMIT)
return;
if (pOD->fOptState & OPTST_RESET) {
tArgList* pAL = pOD->optCookie;
int ct;
tCC ** av;
if (od->fOptState & OPTST_RESET) {
tArgList * arg_list = od->optCookie;
int ct;
char const ** av;
if (pAL == NULL)
if (arg_list == NULL)
return;
ct = pAL->useCt;
av = pAL->apzArgs;
ct = arg_list->useCt;
av = arg_list->apzArgs;
while (--ct >= 0) {
void * p = (void *)*(av++);
optionUnloadNested((tOptionValue const *)p);
}
AGFREE(pOD->optCookie);
AGFREE(od->optCookie);
} else {
tOptionValue* pOV = optionLoadNested(
pOD->optArg.argString, pOD->pz_Name, strlen(pOD->pz_Name));
tOptionValue * opt_val = optionLoadNested(
od->optArg.argString, od->pz_Name, strlen(od->pz_Name));
if (pOV != NULL)
addArgListEntry(&(pOD->optCookie), (void*)pOV);
if (opt_val != NULL)
addArgListEntry(&(od->optCookie), (void*)opt_val);
}
}
/*
/**
* get_special_char
*/
LOCAL int
@@ -789,7 +852,7 @@ get_special_char(char const ** ppz, int * ct)
retch = (int)strtoul(pz, (char **)&pz, base);
if (*pz != ';')
return '&';
base = ++pz - *ppz;
base = (int)(++pz - *ppz);
if (base > *ct)
return '&';
@@ -804,7 +867,7 @@ get_special_char(char const ** ppz, int * ct)
for (;;) {
if ( (*ct >= xlatp->xml_len)
&& (strncmp(pz, xlatp->xml_txt, xlatp->xml_len) == 0)) {
&& (strncmp(pz, xlatp->xml_txt, (size_t)xlatp->xml_len) == 0)) {
*ppz += xlatp->xml_len;
*ct -= xlatp->xml_len;
return xlatp->xml_ch;
@@ -818,7 +881,7 @@ get_special_char(char const ** ppz, int * ct)
return '&';
}
/*
/**
* emit_special_char
*/
LOCAL void
@@ -840,7 +903,8 @@ emit_special_char(FILE * fp, int ch)
fprintf(fp, XML_HEX_BYTE_FMT, (ch & 0xFF));
}
/*
/** @}
*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"