diff options
Diffstat (limited to 'sntp/libopts/nested.c')
-rw-r--r-- | sntp/libopts/nested.c | 538 |
1 files changed, 314 insertions, 224 deletions
diff --git a/sntp/libopts/nested.c b/sntp/libopts/nested.c index b39f8d1faddb..f9f7e7ae7b80 100644 --- a/sntp/libopts/nested.c +++ b/sntp/libopts/nested.c @@ -1,122 +1,123 @@ -/* - * $Id: nested.c,v 4.14 2007/02/04 17:44:12 bkorb Exp $ - * Time-stamp: "2007-01-26 11:04:35 bkorb" +/** + * \file nested.c * - * Automated Options Nested Values module. - */ - -/* - * Automated Options copyright 1992-2007 Bruce Korb - * - * Automated Options is free software. - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2, or (at your option) any later version. + * Time-stamp: "2010-08-22 11:17:56 bkorb" * - * Automated Options is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Automated Options Nested Values module. * - * You should have received a copy of the GNU General Public License - * along with Automated Options. See the file "COPYING". If not, - * write to: The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. + * This file is part of AutoOpts, a companion to AutoGen. + * AutoOpts is free software. + * AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved * - * As a special exception, Bruce Korb gives permission for additional - * uses of the text contained in his release of AutoOpts. + * 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 + * of the user of the license. * - * The exception is that, if you link the AutoOpts library with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the AutoOpts library code into it. + * The GNU Lesser General Public License, version 3 or later + * See the files "COPYING.lgplv3" and "COPYING.gplv3" * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. + * The Modified Berkeley Software Distribution License + * See the file "COPYING.mbsd" * - * This exception applies only to the code released by Bruce Korb under - * the name AutoOpts. If you copy code from other sources under the - * General Public License into a copy of AutoOpts, as the General Public - * License permits, the exception does not apply to the code that you add - * in this way. To avoid misleading anyone as to the status of such - * modified files, you must delete this exception notice from them. + * These files have the following md5sums: * - * If you write modifications of your own for AutoOpts, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. + * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3 + * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3 + * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd */ + +typedef struct { + int xml_ch; + int xml_len; + char xml_txt[8]; +} xml_xlate_t; + +static xml_xlate_t const xml_xlate[] = { + { '&', 4, "amp;" }, + { '<', 3, "lt;" }, + { '>', 3, "gt;" }, + { '"', 5, "quot;" }, + { '\'',5, "apos;" } +}; + /* = = = START-STATIC-FORWARD = = = */ -/* static forward declarations maintained by :mkfwd */ static void -removeBackslashes( char* pzSrc ); +remove_continuation(char* pzSrc); static char const* -scanQuotedString( char const* pzTxt ); +scan_q_str(char const* pzTxt); static tOptionValue* -addStringValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ); +add_string(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen); static tOptionValue* -addBoolValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ); +add_bool(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen); static tOptionValue* -addNumberValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ); +add_number(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen); static tOptionValue* -addNestedValue( void** pp, char const* pzName, size_t nameLen, - char* pzValue, size_t dataLen ); +add_nested(void** pp, char const* pzName, size_t nameLen, + char* pzValue, size_t dataLen); -static char const* -scanNameEntry(char const* pzName, tOptionValue* pRes); +static char const * +scan_name(char const* pzName, tOptionValue* pRes); static char const* -scanXmlEntry( char const* pzName, tOptionValue* pRes ); - -static void -unloadNestedArglist( tArgList* pAL ); +scan_xml(char const* pzName, tOptionValue* pRes); static void -sortNestedList( tArgList* pAL ); +sort_list(tArgList* pAL); /* = = = END-STATIC-FORWARD = = = */ -/* removeBackslashes - * - * This function assumes that all newline characters were preceeded by - * backslashes that need removal. +/** + * Backslashes are used for line continuations. We keep the newline + * characters, but trim out the backslash: */ static void -removeBackslashes( char* pzSrc ) +remove_continuation(char* pzSrc) { - char* pzD = strchr(pzSrc, '\n'); + char* pzD; - if (pzD == NULL) - return; - *--pzD = '\n'; + do { + while (*pzSrc == '\n') pzSrc++; + pzD = strchr(pzSrc, '\n'); + if (pzD == NULL) + return; + /* + * pzD has skipped at least one non-newline character and now + * points to a newline character. It now becomes the source and + * pzD goes to the previous character. + */ + pzSrc = pzD--; + if (*pzD != '\\') + pzD++; + } while (pzD == pzSrc); + + /* + * Start shifting text. + */ for (;;) { char ch = ((*pzD++) = *(pzSrc++)); switch (ch) { - case '\n': *--pzD = ch; break; case NUL: return; - default: - ; + case '\\': + if (*pzSrc == '\n') + --pzD; /* rewrite on next iteration */ } } } - -/* scanQuotedString - * +/** * Find the end of a quoted string, skipping escaped quote characters. */ static char const* -scanQuotedString( char const* pzTxt ) +scan_q_str(char const* pzTxt) { char q = *(pzTxt++); /* remember the type of quote */ @@ -149,18 +150,17 @@ scanQuotedString( char const* pzTxt ) } -/* addStringValue - * +/** * Associate a name with either a string or no value. */ static tOptionValue* -addStringValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ) +add_string(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen) { tOptionValue* pNV; size_t sz = nameLen + dataLen + sizeof(*pNV); - pNV = AGALOC( sz, "option name/str value pair" ); + pNV = AGALOC(sz, "option name/str value pair"); if (pNV == NULL) return NULL; @@ -170,178 +170,173 @@ addStringValue( void** pp, char const* pzName, size_t nameLen, } else { pNV->valType = OPARG_TYPE_STRING; - if (dataLen > 0) - memcpy( pNV->v.strVal, pzValue, dataLen ); - pNV->v.strVal[dataLen] = NUL; + if (dataLen > 0) { + char const * pzSrc = pzValue; + char * pzDst = pNV->v.strVal; + int ct = dataLen; + do { + int ch = *(pzSrc++) & 0xFF; + if (ch == NUL) goto data_copy_done; + if (ch == '&') + ch = get_special_char(&pzSrc, &ct); + *(pzDst++) = ch; + } while (--ct > 0); + data_copy_done: + *pzDst = NUL; + + } else { + pNV->v.strVal[0] = NUL; + } + pNV->pzName = pNV->v.strVal + dataLen + 1; } - memcpy( pNV->pzName, pzName, nameLen ); + memcpy(pNV->pzName, pzName, nameLen); pNV->pzName[ nameLen ] = NUL; - addArgListEntry( pp, pNV ); + addArgListEntry(pp, pNV); return pNV; } - -/* addBoolValue - * +/** * Associate a name with either a string or no value. */ static tOptionValue* -addBoolValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ) +add_bool(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen) { tOptionValue* pNV; size_t sz = nameLen + sizeof(*pNV) + 1; - pNV = AGALOC( sz, "option name/bool value pair" ); + pNV = AGALOC(sz, "option name/bool value pair"); if (pNV == NULL) return NULL; - while (isspace( (int)*pzValue ) && (dataLen > 0)) { + while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) { dataLen--; pzValue++; } if (dataLen == 0) pNV->v.boolVal = 0; - else if (isdigit( (int)*pzValue )) - pNV->v.boolVal = atoi( pzValue ); - else switch (*pzValue) { - case 'f': - case 'F': - case 'n': - case 'N': - pNV->v.boolVal = 0; break; - default: - pNV->v.boolVal = 1; - } + + else if (IS_DEC_DIGIT_CHAR(*pzValue)) + pNV->v.boolVal = atoi(pzValue); + + else pNV->v.boolVal = ! IS_FALSE_TYPE_CHAR(*pzValue); pNV->valType = OPARG_TYPE_BOOLEAN; pNV->pzName = (char*)(pNV + 1); - memcpy( pNV->pzName, pzName, nameLen ); + memcpy(pNV->pzName, pzName, nameLen); pNV->pzName[ nameLen ] = NUL; - addArgListEntry( pp, pNV ); + addArgListEntry(pp, pNV); return pNV; } - -/* addNumberValue - * +/** * Associate a name with either a string or no value. */ static tOptionValue* -addNumberValue( void** pp, char const* pzName, size_t nameLen, - char const* pzValue, size_t dataLen ) +add_number(void** pp, char const* pzName, size_t nameLen, + char const* pzValue, size_t dataLen) { tOptionValue* pNV; size_t sz = nameLen + sizeof(*pNV) + 1; - pNV = AGALOC( sz, "option name/bool value pair" ); + pNV = AGALOC(sz, "option name/bool value pair"); if (pNV == NULL) return NULL; - while (isspace( (int)*pzValue ) && (dataLen > 0)) { + while (IS_WHITESPACE_CHAR(*pzValue) && (dataLen > 0)) { dataLen--; pzValue++; } if (dataLen == 0) - pNV->v.boolVal = 0; + pNV->v.longVal = 0; else - pNV->v.boolVal = atoi( pzValue ); + pNV->v.longVal = strtol(pzValue, 0, 0); pNV->valType = OPARG_TYPE_NUMERIC; - pNV->pzName = (char*)(pNV + 1); - memcpy( pNV->pzName, pzName, nameLen ); + pNV->pzName = (char*)(pNV + 1); + memcpy(pNV->pzName, pzName, nameLen); pNV->pzName[ nameLen ] = NUL; - addArgListEntry( pp, pNV ); + addArgListEntry(pp, pNV); return pNV; } - -/* addNestedValue - * +/** * Associate a name with either a string or no value. */ static tOptionValue* -addNestedValue( void** pp, char const* pzName, size_t nameLen, - char* pzValue, size_t dataLen ) +add_nested(void** pp, char const* pzName, size_t nameLen, + char* pzValue, size_t dataLen) { tOptionValue* pNV; if (dataLen == 0) { size_t sz = nameLen + sizeof(*pNV) + 1; - pNV = AGALOC( sz, "empty nested value pair" ); + pNV = AGALOC(sz, "empty nested value pair"); if (pNV == NULL) return NULL; pNV->v.nestVal = NULL; pNV->valType = OPARG_TYPE_HIERARCHY; pNV->pzName = (char*)(pNV + 1); - memcpy( pNV->pzName, pzName, nameLen ); + memcpy(pNV->pzName, pzName, nameLen); pNV->pzName[ nameLen ] = NUL; } else { - pNV = optionLoadNested( pzValue, pzName, nameLen ); + pNV = optionLoadNested(pzValue, pzName, nameLen); } if (pNV != NULL) - addArgListEntry( pp, pNV ); + addArgListEntry(pp, pNV); return pNV; } - -/* scanNameEntry - * +/** * We have an entry that starts with a name. Find the end of it, cook it * (if called for) and create the name/value association. */ -static char const* -scanNameEntry(char const* pzName, tOptionValue* pRes) +static char const * +scan_name(char const* pzName, tOptionValue* pRes) { tOptionValue* pNV; - char const * pzScan = pzName+1; + char const * pzScan = pzName+1; /* we know first char is a name char */ char const * pzVal; size_t nameLen = 1; size_t dataLen = 0; - while (ISNAMECHAR( (int)*pzScan )) { pzScan++; nameLen++; } + /* + * Scan over characters that name a value. These names may not end + * with a colon, but they may contain colons. + */ + while (IS_VALUE_NAME_CHAR(*pzScan)) { pzScan++; nameLen++; } + if (pzScan[-1] == ':') { pzScan--; nameLen--; } + while (IS_HORIZ_WHITE_CHAR(*pzScan)) pzScan++; - while (isspace( (int)*pzScan )) { - char ch = *(pzScan++); - if ((ch == '\n') || (ch == ',')) { - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL,(size_t)0); - return pzScan - 1; - } - } + re_switch: switch (*pzScan) { case '=': case ':': - while (isspace( (int)*++pzScan )) ; - switch (*pzScan) { - case ',': goto comma_char; - case '"': - case '\'': goto quote_char; - case NUL: goto nul_byte; - default: goto default_char; - } + while (IS_HORIZ_WHITE_CHAR((int)*++pzScan)) ; + if ((*pzScan == '=') || (*pzScan == ':')) + goto default_char; + goto re_switch; + case '\n': case ',': - comma_char: pzScan++; /* FALLTHROUGH */ case NUL: - nul_byte: - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); + add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); break; case '"': case '\'': - quote_char: pzVal = pzScan; - pzScan = scanQuotedString( pzScan ); + pzScan = scan_q_str(pzScan); dataLen = pzScan - pzVal; - pNV = addStringValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, - dataLen ); + 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 ); + ao_string_cook(pNV->v.strVal, NULL); break; default: @@ -370,10 +365,10 @@ scanNameEntry(char const* pzName, tOptionValue* pRes) case ',': dataLen = (pzScan - pzVal) - 1; string_done: - pNV = addStringValue( &(pRes->v.nestVal), pzName, nameLen, - pzVal, dataLen ); + pNV = add_string(&(pRes->v.nestVal), pzName, nameLen, + pzVal, dataLen); if (pNV != NULL) - removeBackslashes( pNV->v.strVal ); + remove_continuation(pNV->v.strVal); goto leave_scan_name; } } @@ -383,15 +378,13 @@ scanNameEntry(char const* pzName, tOptionValue* pRes) return pzScan; } - -/* scanXmlEntry - * +/** * 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. */ static char const* -scanXmlEntry( char const* pzName, tOptionValue* pRes ) +scan_xml(char const* pzName, tOptionValue* pRes) { size_t nameLen = 1, valLen = 0; char const* pzScan = ++pzName; @@ -400,20 +393,20 @@ scanXmlEntry( char const* pzName, tOptionValue* pRes ) tOptionValue* pNewVal; tOptionLoadMode save_mode = option_load_mode; - if (! isalpha((int)*pzName)) { + if (! IS_VAR_FIRST_CHAR(*pzName)) { switch (*pzName) { default: pzName = NULL; break; case '!': - pzName = strstr( pzName, "-->" ); + pzName = strstr(pzName, "-->"); if (pzName != NULL) pzName += 3; break; case '?': - pzName = strchr( pzName, '>' ); + pzName = strchr(pzName, '>'); if (pzName != NULL) pzName++; break; @@ -421,7 +414,8 @@ scanXmlEntry( char const* pzName, tOptionValue* pRes ) return pzName; } - while (isalpha( (int)*++pzScan )) nameLen++; + pzScan++; + while (IS_VALUE_NAME_CHAR((int)*pzScan)) { pzScan++; nameLen++; } if (nameLen > 64) return NULL; valu.valType = OPARG_TYPE_STRING; @@ -447,9 +441,9 @@ scanXmlEntry( char const* pzName, tOptionValue* pRes ) option_load_mode = save_mode; return NULL; } - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); + add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); option_load_mode = save_mode; - return pzScan+2; + return pzScan+1; default: option_load_mode = save_mode; @@ -477,46 +471,46 @@ scanXmlEntry( char const* pzName, tOptionValue* pRes ) *(pzD++) = '>'; *pzD = NUL; - pzScan = strstr( pzScan, z ); + pzScan = strstr(pzScan, z); if (pzScan == NULL) { option_load_mode = save_mode; return NULL; } valLen = (pzScan - pzVal); pzScan += nameLen + 3; - while (isspace( (int)*pzScan )) pzScan++; + while (IS_WHITESPACE_CHAR(*pzScan)) pzScan++; } switch (valu.valType) { case OPARG_TYPE_NONE: - addStringValue( &(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); + add_string(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); break; case OPARG_TYPE_STRING: - pNewVal = addStringValue( + pNewVal = add_string( &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen); if (option_load_mode == OPTION_LOAD_KEEP) break; - mungeString( pNewVal->v.strVal, option_load_mode ); + mungeString(pNewVal->v.strVal, option_load_mode); break; case OPARG_TYPE_BOOLEAN: - addBoolValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen ); + add_bool(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen); break; case OPARG_TYPE_NUMERIC: - addNumberValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen ); + add_number(&(pRes->v.nestVal), pzName, nameLen, pzVal, valLen); break; case OPARG_TYPE_HIERARCHY: { - char* pz = AGALOC( valLen+1, "hierarchical scan" ); + char* pz = AGALOC(valLen+1, "hierarchical scan"); if (pz == NULL) break; - memcpy( pz, pzVal, valLen ); + memcpy(pz, pzVal, valLen); pz[valLen] = NUL; - addNestedValue( &(pRes->v.nestVal), pzName, nameLen, pz, valLen ); + add_nested(&(pRes->v.nestVal), pzName, nameLen, pz, valLen); AGFREE(pz); break; } @@ -532,15 +526,14 @@ scanXmlEntry( char const* pzName, tOptionValue* pRes ) } -/* unloadNestedArglist - * +/** * Deallocate a list of option arguments. This must have been gotten from * a hierarchical option argument, not a stacked list of strings. It is * an internal call, so it is not validated. The caller is responsible for * knowing what they are doing. */ -static void -unloadNestedArglist( tArgList* pAL ) +LOCAL void +unload_arg_list(tArgList* pAL) { int ct = pAL->useCt; tCC** ppNV = pAL->apzArgs; @@ -548,14 +541,13 @@ unloadNestedArglist( tArgList* pAL ) while (ct-- > 0) { tOptionValue* pNV = (tOptionValue*)(void*)*(ppNV++); if (pNV->valType == OPARG_TYPE_HIERARCHY) - unloadNestedArglist( pNV->v.nestVal ); - AGFREE( pNV ); + unload_arg_list(pNV->v.nestVal); + AGFREE(pNV); } - AGFREE( (void*)pAL ); + AGFREE((void*)pAL); } - /*=export_func optionUnloadNested * * what: Deallocate the memory for a nested value @@ -567,7 +559,7 @@ unloadNestedArglist( tArgList* pAL ) * @pxref{libopts-configFileLoad}). =*/ void -optionUnloadNested( tOptionValue const * pOV ) +optionUnloadNested(tOptionValue const * pOV) { if (pOV == NULL) return; if (pOV->valType != OPARG_TYPE_HIERARCHY) { @@ -575,20 +567,18 @@ optionUnloadNested( tOptionValue const * pOV ) return; } - unloadNestedArglist( pOV->v.nestVal ); + unload_arg_list(pOV->v.nestVal); - AGFREE( (void*)pOV ); + AGFREE((void*)pOV); } - -/* sortNestedList - * +/** * This is a _stable_ sort. The entries are sorted alphabetically, * but within entries of the same name the ordering is unchanged. * Typically, we also hope the input is sorted. */ static void -sortNestedList( tArgList* pAL ) +sort_list(tArgList* pAL) { int ix; int lm = pAL->useCt; @@ -606,7 +596,7 @@ sortNestedList( tArgList* pAL ) * move the old pointer. Stop before trying to extract the * "-1" entry. */ - while (strcmp( pOldNV->pzName, pNewNV->pzName ) > 0) { + while (strcmp(pOldNV->pzName, pNewNV->pzName) > 0) { pAL->apzArgs[iy+1] = (void*)pOldNV; pOldNV = (tOptionValue*)(void*)(pAL->apzArgs[--iy]); if (iy < 0) @@ -621,7 +611,6 @@ sortNestedList( tArgList* pAL ) } } - /* optionLoadNested * private: * @@ -642,7 +631,6 @@ LOCAL tOptionValue* optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen) { tOptionValue* pRes; - tArgList* pAL; /* * Make sure we have some data and we have space to put what we find. @@ -651,60 +639,65 @@ optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen) errno = EINVAL; return NULL; } - while (isspace( (int)*pzTxt )) pzTxt++; + while (IS_WHITESPACE_CHAR(*pzTxt)) pzTxt++; if (*pzTxt == NUL) { errno = ENOENT; return NULL; } - pRes = AGALOC( sizeof(*pRes) + nameLen + 1, "nested args" ); + 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; + memcpy(pRes->pzName, pzName, nameLen); + pRes->pzName[nameLen] = NUL; - pAL = AGALOC( sizeof(*pAL), "nested arg list" ); - if (pAL == NULL) { - AGFREE( pRes ); - return NULL; + { + tArgList * pAL = AGALOC(sizeof(*pAL), "nested arg list"); + if (pAL == NULL) { + AGFREE(pRes); + return NULL; + } + + pRes->v.nestVal = pAL; + pAL->useCt = 0; + pAL->allocCt = MIN_ARG_ALLOC_CT; } - pRes->v.nestVal = pAL; - pAL->useCt = 0; - pAL->allocCt = MIN_ARG_ALLOC_CT; /* * Scan until we hit a NUL. */ do { - while (isspace( (int)*pzTxt )) pzTxt++; - if (isalpha( (int)*pzTxt )) { - pzTxt = scanNameEntry( pzTxt, pRes ); + while (IS_WHITESPACE_CHAR((int)*pzTxt)) pzTxt++; + if (IS_VAR_FIRST_CHAR((int)*pzTxt)) { + pzTxt = scan_name(pzTxt, pRes); } else switch (*pzTxt) { case NUL: goto scan_done; - case '<': pzTxt = scanXmlEntry( pzTxt, pRes ); + case '<': pzTxt = scan_xml(pzTxt, pRes); + if (pzTxt == NULL) goto woops; if (*pzTxt == ',') pzTxt++; break; - case '#': pzTxt = strchr( pzTxt, '\n' ); break; + case '#': pzTxt = strchr(pzTxt, '\n'); break; default: goto woops; } } while (pzTxt != NULL); scan_done:; - pAL = pRes->v.nestVal; - if (pAL->useCt != 0) { - sortNestedList( pAL ); - return pRes; + { + tArgList * al = pRes->v.nestVal; + if (al->useCt != 0) + sort_list(al); } + return pRes; + woops: - AGFREE( pRes->v.nestVal ); - AGFREE( pRes ); + AGFREE(pRes->v.nestVal); + AGFREE(pRes); return NULL; } - /*=export_func optionNestedVal * private: * @@ -716,14 +709,111 @@ optionLoadNested(char const* pzTxt, char const* pzName, size_t nameLen) * Nested value was found on the command line =*/ void -optionNestedVal( tOptions* pOpts, tOptDesc* pOD ) +optionNestedVal(tOptions* pOpts, tOptDesc* pOD) { - tOptionValue* pOV = optionLoadNested( - pOD->optArg.argString, pOD->pz_Name, strlen(pOD->pz_Name)); + if (pOpts < OPTPROC_EMIT_LIMIT) + return; - if (pOV != NULL) - addArgListEntry( &(pOD->optCookie), (void*)pOV ); + if (pOD->fOptState & OPTST_RESET) { + tArgList* pAL = pOD->optCookie; + int ct; + tCC ** av; + + if (pAL == NULL) + return; + ct = pAL->useCt; + av = pAL->apzArgs; + + while (--ct >= 0) { + void * p = (void *)*(av++); + optionUnloadNested((tOptionValue const *)p); + } + + AGFREE(pOD->optCookie); + + } else { + tOptionValue* pOV = optionLoadNested( + pOD->optArg.argString, pOD->pz_Name, strlen(pOD->pz_Name)); + + if (pOV != NULL) + addArgListEntry(&(pOD->optCookie), (void*)pOV); + } } + +/* + * get_special_char + */ +LOCAL int +get_special_char(char const ** ppz, int * ct) +{ + char const * pz = *ppz; + + if (*ct < 3) + return '&'; + + if (*pz == '#') { + int base = 10; + int retch; + + pz++; + if (*pz == 'x') { + base = 16; + pz++; + } + retch = (int)strtoul(pz, (char **)&pz, base); + if (*pz != ';') + return '&'; + base = ++pz - *ppz; + if (base > *ct) + return '&'; + + *ct -= base; + *ppz = pz; + return retch; + } + + { + int ctr = sizeof(xml_xlate) / sizeof(xml_xlate[0]); + xml_xlate_t const * xlatp = xml_xlate; + + for (;;) { + if ( (*ct >= xlatp->xml_len) + && (strncmp(pz, xlatp->xml_txt, xlatp->xml_len) == 0)) { + *ppz += xlatp->xml_len; + *ct -= xlatp->xml_len; + return xlatp->xml_ch; + } + + if (--ctr <= 0) + break; + xlatp++; + } + } + return '&'; +} + +/* + * emit_special_char + */ +LOCAL void +emit_special_char(FILE * fp, int ch) +{ + int ctr = sizeof(xml_xlate) / sizeof(xml_xlate[0]); + xml_xlate_t const * xlatp = xml_xlate; + + putc('&', fp); + for (;;) { + if (ch == xlatp->xml_ch) { + fputs(xlatp->xml_txt, fp); + return; + } + if (--ctr <= 0) + break; + xlatp++; + } + fprintf(fp, "#x%02X;", (ch & 0xFF)); +} + /* * Local Variables: * mode: C |