/** * 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; }
/** * Skip over some unknown attribute */ static char * skip_unkn(char* pzText) { for (;; pzText++) { if (IS_END_XML_TOKEN_CHAR(*pzText)) return pzText; if (*pzText == NUL) return NULL; } }
/** * parse the type. The keyword "type" was found, now figure out * the type that follows the type. * * @param[in] txt points to the '=' character after the "type" keyword. * @param[out] typ where to store the type found * @returns the next byte after the type name */ static char const * parse_value(char const * txt, tOptionValue * typ) { size_t len = 0; if (*(txt++) != '=') goto woops; len = (size_t)(SPN_OPTION_NAME_CHARS(txt) - txt); if ((len == 0) || (! IS_END_XML_TOKEN_CHAR(txt[len]))) { woops: typ->valType = OPARG_TYPE_NONE; return skip_unkn(txt + len); } /* * The enumeration used in this switch is derived from this switch * statement itself. The "find_option_value_type_cmd" function * will return VTP_CMD_INTEGER for the "txt" string value * "integer", etc. */ switch (find_option_value_type_cmd(txt, len)) { default: case VTP_INVALID_CMD: goto woops; case VTP_CMD_STRING: typ->valType = OPARG_TYPE_STRING; break; case VTP_CMD_INTEGER: typ->valType = OPARG_TYPE_NUMERIC; break; case VTP_CMD_BOOL: case VTP_CMD_BOOLEAN: typ->valType = OPARG_TYPE_BOOLEAN; break; case VTP_CMD_KEYWORD: typ->valType = OPARG_TYPE_ENUMERATION; break; case VTP_CMD_SET: case VTP_CMD_SET_MEMBERSHIP: typ->valType = OPARG_TYPE_MEMBERSHIP; break; case VTP_CMD_NESTED: case VTP_CMD_HIERARCHY: typ->valType = OPARG_TYPE_HIERARCHY; } return txt + len; }
/* parseValueType * * "pzText" points to the character after "type=" */ static char* parseValueType( char* pzText, tOptionValue* pType ) { size_t len = 0; if (*(pzText++) != '=') goto woops; while (IS_OPTION_NAME_CHAR(pzText[len])) len++; pzText += len; if ((len == 0) || (! IS_END_XML_TOKEN_CHAR(*pzText))) { woops: pType->valType = OPARG_TYPE_NONE; return skipUnknown( pzText ); } switch (find_value_type_id(pzText - len, len)) { default: case VTP_KWD_INVALID: goto woops; case VTP_KWD_STRING: pType->valType = OPARG_TYPE_STRING; break; case VTP_KWD_INTEGER: pType->valType = OPARG_TYPE_NUMERIC; break; case VTP_KWD_BOOL: case VTP_KWD_BOOLEAN: pType->valType = OPARG_TYPE_BOOLEAN; break; case VTP_KWD_KEYWORD: pType->valType = OPARG_TYPE_ENUMERATION; break; case VTP_KWD_SET: case VTP_KWD_SET_MEMBERSHIP: pType->valType = OPARG_TYPE_MEMBERSHIP; break; case VTP_KWD_NESTED: case VTP_KWD_HIERARCHY: pType->valType = OPARG_TYPE_HIERARCHY; } return pzText; }
/** * handle program segmentation of config file. * * @param[in,out] opts program option descriptor * @param[in] txt scanning pointer * @returns the next character to look at */ static char * program_directive(tOptions * opts, char * txt) { static char const ttlfmt[] = "<?"; size_t ttl_len = sizeof(ttlfmt) + strlen(zCfgProg); char * ttl = AGALOC(ttl_len, "prog title"); size_t name_len = strlen(opts->pzProgName); memcpy(ttl, ttlfmt, sizeof(ttlfmt) - 1); memcpy(ttl + sizeof(ttlfmt) - 1, zCfgProg, ttl_len - (sizeof(ttlfmt) - 1)); do { txt = SPN_WHITESPACE_CHARS(txt+1); if ( (strneqvcmp(txt, opts->pzProgName, (int)name_len) == 0) && (IS_END_XML_TOKEN_CHAR(txt[name_len])) ) { txt += name_len; break; } txt = strstr(txt, ttl); } while (txt != NULL); AGFREE(ttl); if (txt != NULL) for (;;) { if (*txt == NUL) { txt = NULL; break; } if (*(txt++) == '>') break; } return txt; }
/** * Parse the various attributes of an XML-styled config file entry * * @returns NULL on failure, otherwise the scan point */ LOCAL char const * parse_attrs(tOptions * opts, char const * txt, tOptionLoadMode * pMode, tOptionValue * pType) { size_t len = 0; for (;;) { len = (size_t)(SPN_LOWER_CASE_CHARS(txt) - txt); /* * The enumeration used in this switch is derived from this switch * statement itself. The "find_option_xat_attribute_cmd" function * will return XAT_CMD_MEMBERS for the "txt" string value * "members", etc. */ switch (find_option_xat_attribute_cmd(txt, len)) { case XAT_CMD_TYPE: txt = parse_value(txt+len, pType); break; case XAT_CMD_WORDS: txt = parse_keyword(opts, txt+len, pType); break; case XAT_CMD_MEMBERS: txt = parse_set_mem(opts, txt+len, pType); break; case XAT_CMD_COOKED: txt += len; if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_COOKED; break; case XAT_CMD_UNCOOKED: txt += len; if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_UNCOOKED; break; case XAT_CMD_KEEP: txt += len; if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_KEEP; break; default: case XAT_INVALID_CMD: invalid_kwd: pType->valType = OPARG_TYPE_NONE; return skip_unkn(txt); } if (txt == NULL) return NULL; txt = SPN_WHITESPACE_CHARS(txt); switch (*txt) { case '/': pType->valType = OPARG_TYPE_NONE; /* FALLTHROUGH */ case '>': return txt; } if (! IS_LOWER_CASE_CHAR(*txt)) return NULL; } }
/** * Parse the various attributes of an XML-styled config file entry */ LOCAL char* parseAttributes( tOptions* pOpts, char* pzText, tOptionLoadMode* pMode, tOptionValue* pType ) { size_t len; do { if (! IS_WHITESPACE_CHAR(*pzText)) switch (*pzText) { case '/': pType->valType = OPARG_TYPE_NONE; case '>': return pzText; default: case NUL: return NULL; } while (IS_WHITESPACE_CHAR(*++pzText)) ; len = 0; while (IS_LOWER_CASE_CHAR(pzText[len])) len++; switch (find_xat_attribute_id(pzText, len)) { case XAT_KWD_TYPE: pzText = parse_value(pzText+len, pType); break; case XAT_KWD_WORDS: pzText = parse_keyword(pOpts, pzText+len, pType); break; case XAT_KWD_MEMBERS: pzText = parse_set_mem(pOpts, pzText+len, pType); break; case XAT_KWD_COOKED: pzText += len; if (! IS_END_XML_TOKEN_CHAR(*pzText)) goto invalid_kwd; *pMode = OPTION_LOAD_COOKED; break; case XAT_KWD_UNCOOKED: pzText += len; if (! IS_END_XML_TOKEN_CHAR(*pzText)) goto invalid_kwd; *pMode = OPTION_LOAD_UNCOOKED; break; case XAT_KWD_KEEP: pzText += len; if (! IS_END_XML_TOKEN_CHAR(*pzText)) goto invalid_kwd; *pMode = OPTION_LOAD_KEEP; break; default: case XAT_KWD_INVALID: invalid_kwd: pType->valType = OPARG_TYPE_NONE; return skip_unkn(pzText); } } while (pzText != NULL); return pzText; }