diff options
Diffstat (limited to 'libopts/nested.c')
-rw-r--r-- | libopts/nested.c | 733 |
1 files changed, 0 insertions, 733 deletions
diff --git a/libopts/nested.c b/libopts/nested.c deleted file mode 100644 index b39f8d1faddb..000000000000 --- a/libopts/nested.c +++ /dev/null @@ -1,733 +0,0 @@ - -/* - * $Id: nested.c,v 4.14 2007/02/04 17:44:12 bkorb Exp $ - * Time-stamp: "2007-01-26 11:04:35 bkorb" - * - * 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. - * - * 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. - * - * 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. - * - * As a special exception, Bruce Korb gives permission for additional - * uses of the text contained in his release of AutoOpts. - * - * 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. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * 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. - * - * 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. - */ -/* = = = START-STATIC-FORWARD = = = */ -/* static forward declarations maintained by :mkfwd */ -static void -removeBackslashes( char* pzSrc ); - -static char const* -scanQuotedString( char const* pzTxt ); - -static tOptionValue* -addStringValue( 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 ); - -static tOptionValue* -addNumberValue( 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 ); - -static char const* -scanNameEntry(char const* pzName, tOptionValue* pRes); - -static char const* -scanXmlEntry( char const* pzName, tOptionValue* pRes ); - -static void -unloadNestedArglist( tArgList* pAL ); - -static void -sortNestedList( tArgList* pAL ); -/* = = = END-STATIC-FORWARD = = = */ - -/* removeBackslashes - * - * This function assumes that all newline characters were preceeded by - * backslashes that need removal. - */ -static void -removeBackslashes( char* pzSrc ) -{ - char* pzD = strchr(pzSrc, '\n'); - - if (pzD == NULL) - return; - *--pzD = '\n'; - - for (;;) { - char ch = ((*pzD++) = *(pzSrc++)); - switch (ch) { - case '\n': *--pzD = ch; break; - case NUL: return; - default: - ; - } - } -} - - -/* scanQuotedString - * - * Find the end of a quoted string, skipping escaped quote characters. - */ -static char const* -scanQuotedString( char const* pzTxt ) -{ - char q = *(pzTxt++); /* remember the type of quote */ - - for (;;) { - char ch = *(pzTxt++); - if (ch == NUL) - return pzTxt-1; - - if (ch == q) - return pzTxt; - - if (ch == '\\') { - ch = *(pzTxt++); - /* - * IF the next character is NUL, drop the backslash, too. - */ - if (ch == NUL) - return pzTxt - 2; - - /* - * IF the quote character or the escape character were escaped, - * then skip both, as long as the string does not end. - */ - if ((ch == q) || (ch == '\\')) { - if (*(pzTxt++) == NUL) - return pzTxt-1; - } - } - } -} - - -/* 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 ) -{ - tOptionValue* pNV; - size_t sz = nameLen + dataLen + sizeof(*pNV); - - pNV = AGALOC( sz, "option name/str value pair" ); - if (pNV == NULL) - return NULL; - - if (pzValue == NULL) { - pNV->valType = OPARG_TYPE_NONE; - pNV->pzName = pNV->v.strVal; - - } else { - pNV->valType = OPARG_TYPE_STRING; - if (dataLen > 0) - memcpy( pNV->v.strVal, pzValue, dataLen ); - pNV->v.strVal[dataLen] = NUL; - pNV->pzName = pNV->v.strVal + dataLen + 1; - } - - memcpy( pNV->pzName, pzName, nameLen ); - pNV->pzName[ nameLen ] = NUL; - 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 ) -{ - tOptionValue* pNV; - size_t sz = nameLen + sizeof(*pNV) + 1; - - pNV = AGALOC( sz, "option name/bool value pair" ); - if (pNV == NULL) - return NULL; - while (isspace( (int)*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; - } - - pNV->valType = OPARG_TYPE_BOOLEAN; - pNV->pzName = (char*)(pNV + 1); - memcpy( pNV->pzName, pzName, nameLen ); - pNV->pzName[ nameLen ] = NUL; - 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 ) -{ - tOptionValue* pNV; - size_t sz = nameLen + sizeof(*pNV) + 1; - - pNV = AGALOC( sz, "option name/bool value pair" ); - if (pNV == NULL) - return NULL; - while (isspace( (int)*pzValue ) && (dataLen > 0)) { - dataLen--; pzValue++; - } - if (dataLen == 0) - pNV->v.boolVal = 0; - else - pNV->v.boolVal = atoi( pzValue ); - - pNV->valType = OPARG_TYPE_NUMERIC; - pNV->pzName = (char*)(pNV + 1); - memcpy( pNV->pzName, pzName, nameLen ); - pNV->pzName[ nameLen ] = NUL; - 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 ) -{ - tOptionValue* pNV; - - if (dataLen == 0) { - size_t sz = nameLen + sizeof(*pNV) + 1; - 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 ); - pNV->pzName[ nameLen ] = NUL; - - } else { - pNV = optionLoadNested( pzValue, pzName, nameLen ); - } - - if (pNV != NULL) - 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) -{ - tOptionValue* pNV; - char const * pzScan = pzName+1; - char const * pzVal; - size_t nameLen = 1; - size_t dataLen = 0; - - while (ISNAMECHAR( (int)*pzScan )) { pzScan++; nameLen++; } - - while (isspace( (int)*pzScan )) { - char ch = *(pzScan++); - if ((ch == '\n') || (ch == ',')) { - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL,(size_t)0); - return pzScan - 1; - } - } - - 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; - } - - case ',': - comma_char: - pzScan++; - /* FALLTHROUGH */ - - case NUL: - nul_byte: - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); - break; - - case '"': - case '\'': - quote_char: - pzVal = pzScan; - pzScan = scanQuotedString( pzScan ); - dataLen = pzScan - pzVal; - pNV = addStringValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, - dataLen ); - if ((pNV != NULL) && (option_load_mode == OPTION_LOAD_COOKED)) - ao_string_cook( pNV->v.strVal, NULL ); - break; - - default: - default_char: - /* - * We have found some strange text value. It ends with a newline - * or a comma. - */ - pzVal = pzScan; - for (;;) { - char ch = *(pzScan++); - switch (ch) { - case NUL: - pzScan--; - dataLen = pzScan - pzVal; - goto string_done; - /* FALLTHROUGH */ - - case '\n': - if ( (pzScan > pzVal + 2) - && (pzScan[-2] == '\\') - && (pzScan[ 0] != NUL)) - continue; - /* FALLTHROUGH */ - - case ',': - dataLen = (pzScan - pzVal) - 1; - string_done: - pNV = addStringValue( &(pRes->v.nestVal), pzName, nameLen, - pzVal, dataLen ); - if (pNV != NULL) - removeBackslashes( pNV->v.strVal ); - goto leave_scan_name; - } - } - break; - } leave_scan_name:; - - 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 ) -{ - size_t nameLen = 1, valLen = 0; - char const* pzScan = ++pzName; - char const* pzVal; - tOptionValue valu; - tOptionValue* pNewVal; - tOptionLoadMode save_mode = option_load_mode; - - if (! isalpha((int)*pzName)) { - switch (*pzName) { - default: - pzName = NULL; - break; - - case '!': - pzName = strstr( pzName, "-->" ); - if (pzName != NULL) - pzName += 3; - break; - - case '?': - pzName = strchr( pzName, '>' ); - if (pzName != NULL) - pzName++; - break; - } - return pzName; - } - - while (isalpha( (int)*++pzScan )) nameLen++; - if (nameLen > 64) - return NULL; - valu.valType = OPARG_TYPE_STRING; - - switch (*pzScan) { - case ' ': - case '\t': - pzScan = parseAttributes( - 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; - } - addStringValue(&(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); - option_load_mode = save_mode; - return pzScan+2; - - 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; - while (isspace( (int)*pzScan )) pzScan++; - } - - switch (valu.valType) { - case OPARG_TYPE_NONE: - addStringValue( &(pRes->v.nestVal), pzName, nameLen, NULL, (size_t)0); - break; - - case OPARG_TYPE_STRING: - pNewVal = addStringValue( - &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen); - - if (option_load_mode == OPTION_LOAD_KEEP) - break; - mungeString( pNewVal->v.strVal, option_load_mode ); - break; - - case OPARG_TYPE_BOOLEAN: - addBoolValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen ); - break; - - case OPARG_TYPE_NUMERIC: - addNumberValue( &(pRes->v.nestVal), pzName, nameLen, pzVal, valLen ); - break; - - case OPARG_TYPE_HIERARCHY: - { - char* pz = AGALOC( valLen+1, "hierarchical scan" ); - if (pz == NULL) - break; - memcpy( pz, pzVal, valLen ); - pz[valLen] = NUL; - addNestedValue( &(pRes->v.nestVal), pzName, nameLen, pz, valLen ); - AGFREE(pz); - break; - } - - case OPARG_TYPE_ENUMERATION: - case OPARG_TYPE_MEMBERSHIP: - default: - break; - } - - option_load_mode = save_mode; - return pzScan; -} - - -/* 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 ) -{ - int ct = pAL->useCt; - tCC** ppNV = pAL->apzArgs; - - while (ct-- > 0) { - tOptionValue* pNV = (tOptionValue*)(void*)*(ppNV++); - if (pNV->valType == OPARG_TYPE_HIERARCHY) - unloadNestedArglist( pNV->v.nestVal ); - AGFREE( pNV ); - } - - AGFREE( (void*)pAL ); -} - - -/*=export_func optionUnloadNested - * - * what: Deallocate the memory for a nested value - * arg: + tOptionValue const * + pOptVal + the hierarchical value + - * - * doc: - * A nested value needs to be deallocated. The pointer passed in should - * have been gotten from a call to @code{configFileLoad()} (See - * @pxref{libopts-configFileLoad}). -=*/ -void -optionUnloadNested( tOptionValue const * pOV ) -{ - if (pOV == NULL) return; - if (pOV->valType != OPARG_TYPE_HIERARCHY) { - errno = EINVAL; - return; - } - - unloadNestedArglist( pOV->v.nestVal ); - - 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 ) -{ - int ix; - int lm = pAL->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]); - - /* - * 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]); - if (iy < 0) - break; - } - - /* - * 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; - } -} - - -/* optionLoadNested - * 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" + - * - * ret_type: tOptionValue* - * ret_desc: An allocated, compound value structure - * - * doc: - * A block of text represents a series of values. It may be an - * entire configuration file, or it may be an argument to an - * option that takes a hierarchical value. - */ -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. - */ - if (pzTxt == NULL) { - errno = EINVAL; - return NULL; - } - while (isspace( (int)*pzTxt )) pzTxt++; - if (*pzTxt == NUL) { - errno = ENOENT; - 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; - - 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; - - /* - * Scan until we hit a NUL. - */ - do { - while (isspace( (int)*pzTxt )) pzTxt++; - if (isalpha( (int)*pzTxt )) { - pzTxt = scanNameEntry( pzTxt, pRes ); - } - else switch (*pzTxt) { - case NUL: goto scan_done; - case '<': pzTxt = scanXmlEntry( pzTxt, pRes ); - if (*pzTxt == ',') pzTxt++; 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; - } - - woops: - AGFREE( pRes->v.nestVal ); - AGFREE( pRes ); - return NULL; -} - - -/*=export_func optionNestedVal - * private: - * - * what: parse a hierarchical option argument - * arg: + tOptions* + pOpts + program options descriptor + - * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + - * - * doc: - * Nested value was found on the command line -=*/ -void -optionNestedVal( tOptions* pOpts, tOptDesc* pOD ) -{ - tOptionValue* pOV = optionLoadNested( - pOD->optArg.argString, pOD->pz_Name, strlen(pOD->pz_Name)); - - if (pOV != NULL) - addArgListEntry( &(pOD->optCookie), (void*)pOV ); -} -/* - * Local Variables: - * mode: C - * c-file-style: "stroustrup" - * indent-tabs-mode: nil - * End: - * end of autoopts/nested.c */ |