📄 nested.c
字号:
/* 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 voidunloadNestedArglist( 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}).=*/voidoptionUnloadNested( 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 voidsortNestedList( 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=*/voidoptionNestedVal( 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -