/** * 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; }
/** * "txt" points to a '<' character, followed by an alpha. * The end of the entry is either the "/>" following the name, or else a * "</name>" string. */ static char * handle_struct(tOptions * opts, tOptState * ost, char * txt, int dir) { tOptionLoadMode mode = option_load_mode; tOptionValue valu; char* pzName = ++txt; char* pzData; char* pcNulPoint; txt = SPN_VALUE_NAME_CHARS(txt); pcNulPoint = txt; valu.valType = OPARG_TYPE_STRING; switch (*txt) { case ' ': case '\t': txt = (void *)parse_attrs( opts, SPN_WHITESPACE_CHARS(txt), &mode, &valu); if (txt == NULL) return txt; if (*txt == '>') break; if (*txt != '/') return NULL; /* FALLTHROUGH */ case '/': if (txt[1] != '>') return NULL; *txt = NUL; txt += 2; loadOptionLine(opts, ost, pzName, dir, mode); return txt; case '>': break; default: txt = strchr(txt, '>'); if (txt != NULL) txt++; return txt; } /* * If we are here, we have a value. "txt" points to a closing angle * bracket. Separate the name from the value for a moment. */ *pcNulPoint = NUL; pzData = ++txt; txt = trim_xml_text(txt, pzName, mode); if (txt == NULL) return txt; /* * Rejoin the name and value for parsing by "loadOptionLine()". * Erase any attributes parsed by "parse_attrs()". */ memset(pcNulPoint, ' ', (size_t)(pzData - pcNulPoint)); /* * If we are getting a "string" value that is to be cooked, * then process the XML-ish &xx; XML-ish and %XX hex characters. */ if ( (valu.valType == OPARG_TYPE_STRING) && (mode == OPTION_LOAD_COOKED)) cook_xml_text(pzData); /* * "pzName" points to what looks like text for one option/configurable. * It is NUL terminated. Process it. */ loadOptionLine(opts, ost, pzName, dir, mode); return txt; }
/** * "txt" points to the start of some value name. * The end of the entry is the end of the line that is not preceded by * a backslash escape character. The string value is always processed * in "cooked" mode. */ static char * handle_cfg(tOptions * opts, tOptState * ost, char * txt, int dir) { char* pzName = txt++; char* pzEnd = strchr(txt, NL); if (pzEnd == NULL) return txt + strlen(txt); txt = SPN_VALUE_NAME_CHARS(txt); txt = SPN_WHITESPACE_CHARS(txt); if (txt > pzEnd) { name_only: *pzEnd++ = NUL; loadOptionLine(opts, ost, pzName, dir, OPTION_LOAD_UNCOOKED); return pzEnd; } /* * Either the first character after the name is a ':' or '=', * or else we must have skipped over white space. Anything else * is an invalid format and we give up parsing the text. */ if ((*txt == '=') || (*txt == ':')) { txt = SPN_WHITESPACE_CHARS(txt+1); if (txt > pzEnd) goto name_only; } else if (! IS_WHITESPACE_CHAR(txt[-1])) return NULL; /* * IF the value is continued, remove the backslash escape and push "pzEnd" * on to a newline *not* preceded by a backslash. */ if (pzEnd[-1] == '\\') { char* pcD = pzEnd-1; char* pcS = pzEnd; for (;;) { char ch = *(pcS++); switch (ch) { case NUL: pcS = NULL; /* FALLTHROUGH */ case NL: *pcD = NUL; pzEnd = pcS; goto copy_done; case '\\': if (*pcS == NL) ch = *(pcS++); /* FALLTHROUGH */ default: *(pcD++) = ch; } } copy_done:; } else { /* * The newline was not preceded by a backslash. NUL it out */ *(pzEnd++) = NUL; } /* * "pzName" points to what looks like text for one option/configurable. * It is NUL terminated. Process it. */ loadOptionLine(opts, ost, pzName, dir, OPTION_LOAD_UNCOOKED); return pzEnd; }
/** * 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 * scan_name(char const * name, tOptionValue * res) { tOptionValue * new_val; char const * pzScan = name+1; /* we know first char is a name char */ char const * pzVal; size_t nm_len = 1; size_t d_len = 0; /* * Scan over characters that name a value. These names may not end * with a colon, but they may contain colons. */ pzScan = SPN_VALUE_NAME_CHARS(name + 1); if (pzScan[-1] == ':') pzScan--; nm_len = (size_t)(pzScan - name); pzScan = SPN_HORIZ_WHITE_CHARS(pzScan); re_switch: switch (*pzScan) { case '=': case ':': pzScan = SPN_HORIZ_WHITE_CHARS(pzScan + 1); if ((*pzScan == '=') || (*pzScan == ':')) goto default_char; goto re_switch; case NL: case ',': pzScan++; /* FALLTHROUGH */ case NUL: add_string(&(res->v.nestVal), name, nm_len, NULL, (size_t)0); break; case '"': case '\'': pzVal = pzScan; pzScan = scan_q_str(pzScan); d_len = (size_t)(pzScan - pzVal); new_val = add_string(&(res->v.nestVal), name, 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: 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--; d_len = (size_t)(pzScan - pzVal); goto string_done; /* FALLTHROUGH */ case NL: if ( (pzScan > pzVal + 2) && (pzScan[-2] == '\\') && (pzScan[ 0] != NUL)) continue; /* FALLTHROUGH */ case ',': d_len = (size_t)(pzScan - pzVal) - 1; string_done: new_val = add_string(&(res->v.nestVal), name, nm_len, pzVal, d_len); if (new_val != NULL) remove_continuation(new_val->v.strVal); goto leave_scan_name; } } break; } leave_scan_name:; return pzScan; }
static tDefEntry * find_by_index(tDefEntry * pE, char * pzScan) { int idx; /* * '[]' means the first entry of whatever index number */ if (*pzScan == ']') return pE; /* * '[$]' means the last entry of whatever index number */ if (*pzScan == '$') { pzScan = SPN_WHITESPACE_CHARS(pzScan + 1); if (*pzScan != ']') return NULL; if (pE->pEndTwin != NULL) return pE->pEndTwin; return pE; } /* * '[nn]' means the specified index number */ if (IS_DEC_DIGIT_CHAR(*pzScan)) { char* pz; idx = strtol(pzScan, &pz, 0); /* * Skip over any trailing space and make sure we have a closer */ pz = SPN_WHITESPACE_CHARS(pz); if (*pz != ']') return NULL; } else { /* * '[XX]' means get the index from our definitions */ char* pzDef = pzScan; char const* pzVal; if (! IS_VAR_FIRST_CHAR(*pzScan)) return NULL; pzScan = SPN_VALUE_NAME_CHARS(pzScan); /* * Temporarily remove the character under *pzScan and * find the corresponding defined value. */ { char svch = *pzScan; *pzScan = NUL; pzVal = getDefine(pzDef, AG_TRUE); *pzScan = svch; } /* * Skip over any trailing space and make sure we have a closer */ pzScan = SPN_WHITESPACE_CHARS(pzScan); if (*pzScan != ']') return NULL; /* * make sure we found a defined value */ if ((pzVal == NULL) || (*pzVal == NUL)) return NULL; idx = strtol(pzVal, &pzDef, 0); /* * Make sure we got a legal number */ if (*pzDef != NUL) return NULL; } /* * Search for the entry with the specified index. */ do { if (pE->index > idx) return NULL; if (pE->index == idx) break; pE = pE->pTwin; } while (pE != NULL); return pE; }