diff options
Diffstat (limited to 'src/libopts/configfile.c')
-rw-r--r-- | src/libopts/configfile.c | 816 |
1 files changed, 381 insertions, 435 deletions
diff --git a/src/libopts/configfile.c b/src/libopts/configfile.c index 56e22b5db7..8c71111c5b 100644 --- a/src/libopts/configfile.c +++ b/src/libopts/configfile.c @@ -1,13 +1,15 @@ /** * \file configfile.c * - * Time-stamp: "2012-03-31 13:56:11 bkorb" - * * configuration/rc/ini file handling. * + * @addtogroup autoopts + * @{ + */ +/* * This file is part of AutoOpts, a companion to AutoGen. * AutoOpts is free software. - * AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved + * AutoOpts is Copyright (C) 1992-2013 by Bruce Korb - all rights reserved * * 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 @@ -19,34 +21,34 @@ * The Modified Berkeley Software Distribution License * See the file "COPYING.mbsd" * - * These files have the following md5sums: + * These files have the following sha256 sums: * - * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3 - * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3 - * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd + * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 + * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 + * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd */ /* = = = START-STATIC-FORWARD = = = */ static void file_preset(tOptions * opts, char const * fname, int dir); -static char* -handle_comment(char* pzText); +static char * +handle_comment(char* txt); static char * -handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir); +handle_cfg(tOptions * opts, tOptState * ost, char * txt, int dir); static char * -handle_directive(tOptions * pOpts, char * pzText); +handle_directive(tOptions * opts, char * txt); static char * -aoflags_directive(tOptions * pOpts, char * pzText); +aoflags_directive(tOptions * opts, char * txt); static char * -program_directive(tOptions * pOpts, char * pzText); +program_directive(tOptions * opts, char * txt); static char * -handle_section(tOptions * pOpts, char * pzText); +handle_section(tOptions * opts, char * txt); static int parse_xml_encoding(char ** ppz); @@ -58,26 +60,34 @@ static void cook_xml_text(char * pzData); static char * -handle_struct(tOptions * pOpts, tOptState * pOS, char * pzText, int dir); +handle_struct(tOptions * opts, tOptState * ost, char * txt, int dir); -static char* -parse_keyword(tOptions * pOpts, char * pzText, tOptionValue * pType); +static char const * +parse_keyword(tOptions * opts, char const * txt, tOptionValue * typ); -static char* -parse_set_mem(tOptions * pOpts, char * pzText, tOptionValue * pType); +static char const * +parse_set_mem(tOptions * opts, char const * txt, tOptionValue * typ); -static char * -parse_value(char * pzText, tOptionValue * pType); - -static char * -skip_unkn(char* pzText); +static char const * +parse_value(char const * txt, tOptionValue * typ); /* = = = END-STATIC-FORWARD = = = */ +/** + * Skip over some unknown attribute + * @param[in] txt start of skpped text + * @returns character after skipped text + */ +inline static char const * +skip_unkn(char const * txt) +{ + txt = BRK_END_XML_TOKEN_CHARS(txt); + return (*txt == NUL) ? NULL : txt; +} /*=export_func configFileLoad * * what: parse a configuration file - * arg: + char const* + pzFile + the file to load + + * arg: + char const* + fname + the file to load + * * ret_type: const tOptionValue* * ret_desc: An allocated, compound value structure @@ -106,23 +116,22 @@ skip_unkn(char* pzText); * @code{ENOMEM} - not enough memory to allocate the needed structures. * @end itemize =*/ -const tOptionValue* -configFileLoad(char const* pzFile) +const tOptionValue * +configFileLoad(char const * fname) { - tmap_info_t cfgfile; - tOptionValue* pRes = NULL; + tmap_info_t cfgfile; + tOptionValue * res = NULL; tOptionLoadMode save_mode = option_load_mode; - char* pzText = - text_mmap(pzFile, PROT_READ, MAP_PRIVATE, &cfgfile); + char * txt = text_mmap(fname, PROT_READ, MAP_PRIVATE, &cfgfile); - if (TEXT_MMAP_FAILED_ADDR(pzText)) + if (TEXT_MMAP_FAILED_ADDR(txt)) return NULL; /* errno is set */ option_load_mode = OPTION_LOAD_COOKED; - pRes = optionLoadNested(pzText, pzFile, strlen(pzFile)); + res = optionLoadNested(txt, fname, strlen(fname)); - if (pRes == NULL) { + if (res == NULL) { int err = errno; text_munmap(&cfgfile); errno = err; @@ -130,16 +139,16 @@ configFileLoad(char const* pzFile) text_munmap(&cfgfile); option_load_mode = save_mode; - return pRes; + return res; } /*=export_func optionFindValue * * what: find a hierarcicaly valued option instance - * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type + - * arg: + char const* + name + name of value to find + - * arg: + char const* + value + the matching value + + * arg: + const tOptDesc* + odesc + an option with a nested arg type + + * arg: + char const* + name + name of value to find + + * arg: + char const* + val + the matching value + * * ret_type: const tOptionValue* * ret_desc: a compound value structure @@ -158,53 +167,52 @@ configFileLoad(char const* pzFile) * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ -const tOptionValue* -optionFindValue(const tOptDesc* pOptDesc, char const* pzName, - char const* pzVal) +const tOptionValue * +optionFindValue(const tOptDesc * odesc, char const * name, char const * val) { - const tOptionValue* pRes = NULL; + const tOptionValue * res = NULL; - if ( (pOptDesc == NULL) - || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY)) { + if ( (odesc == NULL) + || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } - else if (pOptDesc->optCookie == NULL) { + else if (odesc->optCookie == NULL) { errno = ENOENT; } else do { - tArgList* pAL = pOptDesc->optCookie; - int ct = pAL->useCt; - void** ppOV = (void**)(pAL->apzArgs); + tArgList* argl = odesc->optCookie; + int argct = argl->useCt; + void ** poptv = (void**)(argl->apzArgs); - if (ct == 0) { + if (argct == 0) { errno = ENOENT; break; } - if (pzName == NULL) { - pRes = (tOptionValue*)*ppOV; + if (name == NULL) { + res = (tOptionValue*)*poptv; break; } - while (--ct >= 0) { - const tOptionValue* pOV = *(ppOV++); - const tOptionValue* pRV = optionGetValue(pOV, pzName); + while (--argct >= 0) { + const tOptionValue * ov = *(poptv++); + const tOptionValue * rv = optionGetValue(ov, name); - if (pRV == NULL) + if (rv == NULL) continue; - if (pzVal == NULL) { - pRes = pOV; + if (val == NULL) { + res = ov; break; } } - if (pRes == NULL) + if (res == NULL) errno = ENOENT; } while (false); - return pRes; + return res; } @@ -213,7 +221,7 @@ optionFindValue(const tOptDesc* pOptDesc, char const* pzName, * FIXME: the handling of 'pzName' and 'pzVal' is just wrong. * * what: find a hierarcicaly valued option instance - * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type + + * arg: + const tOptDesc* + odesc + an option with a nested arg type + * arg: + const tOptionValue* + pPrevVal + the last entry + * arg: + char const* + name + name of value to find + * arg: + char const* + value + the matching value + @@ -237,43 +245,43 @@ optionFindValue(const tOptDesc* pOptDesc, char const* pzName, * @end itemize =*/ tOptionValue const * -optionFindNextValue(const tOptDesc * pOptDesc, const tOptionValue * pPrevVal, +optionFindNextValue(const tOptDesc * odesc, const tOptionValue * pPrevVal, char const * pzName, char const * pzVal) { bool old_found = false; - tOptionValue* pRes = NULL; + tOptionValue* res = NULL; (void)pzName; (void)pzVal; - if ( (pOptDesc == NULL) - || (OPTST_GET_ARGTYPE(pOptDesc->fOptState) != OPARG_TYPE_HIERARCHY)) { + if ( (odesc == NULL) + || (OPTST_GET_ARGTYPE(odesc->fOptState) != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; } - else if (pOptDesc->optCookie == NULL) { + else if (odesc->optCookie == NULL) { errno = ENOENT; } else do { - tArgList* pAL = pOptDesc->optCookie; - int ct = pAL->useCt; - void** ppOV = (void**)pAL->apzArgs; + tArgList* argl = odesc->optCookie; + int ct = argl->useCt; + void** poptv = (void**)argl->apzArgs; while (--ct >= 0) { - tOptionValue* pOV = *(ppOV++); + tOptionValue* pOV = *(poptv++); if (old_found) { - pRes = pOV; + res = pOV; break; } if (pOV == pPrevVal) old_found = true; } - if (pRes == NULL) + if (res == NULL) errno = ENOENT; } while (false); - return pRes; + return res; } @@ -304,39 +312,38 @@ optionFindNextValue(const tOptDesc * pOptDesc, const tOptionValue * pPrevVal, * @code{ENOENT} - no entry matched the given name. * @end itemize =*/ -const tOptionValue* -optionGetValue(tOptionValue const * pOld, char const * pzValName) +tOptionValue const * +optionGetValue(tOptionValue const * oov, char const * vname) { - tArgList * pAL; - tOptionValue * pRes = NULL; + tArgList * arg_list; + tOptionValue * res = NULL; - if ((pOld == NULL) || (pOld->valType != OPARG_TYPE_HIERARCHY)) { + if ((oov == NULL) || (oov->valType != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; - return pRes; + return res; } - pAL = pOld->v.nestVal; + arg_list = oov->v.nestVal; - if (pAL->useCt > 0) { - int ct = pAL->useCt; - void ** papOV = (void**)(pAL->apzArgs); + if (arg_list->useCt > 0) { + int ct = arg_list->useCt; + void ** ovlist = (void**)(arg_list->apzArgs); - if (pzValName == NULL) { - pRes = (tOptionValue*)*papOV; + if (vname == NULL) { + res = (tOptionValue*)*ovlist; } else do { - tOptionValue * pOV = *(papOV++); - if (strcmp(pOV->pzName, pzValName) == 0) { - pRes = pOV; + tOptionValue * opt_val = *(ovlist++); + if (strcmp(opt_val->pzName, vname) == 0) { + res = opt_val; break; } } while (--ct > 0); } - if (pRes == NULL) + if (res == NULL) errno = ENOENT; - return pRes; + return res; } - /*=export_func optionNextValue * * what: get the next value from a hierarchical list @@ -365,30 +372,30 @@ optionGetValue(tOptionValue const * pOld, char const * pzValName) * @end itemize =*/ tOptionValue const * -optionNextValue(tOptionValue const * pOVList,tOptionValue const * pOldOV ) +optionNextValue(tOptionValue const * ov_list,tOptionValue const * oov ) { - tArgList* pAL; - tOptionValue* pRes = NULL; - int err = EINVAL; + tArgList * arg_list; + tOptionValue * res = NULL; + int err = EINVAL; - if ((pOVList == NULL) || (pOVList->valType != OPARG_TYPE_HIERARCHY)) { + if ((ov_list == NULL) || (ov_list->valType != OPARG_TYPE_HIERARCHY)) { errno = EINVAL; return NULL; } - pAL = pOVList->v.nestVal; + arg_list = ov_list->v.nestVal; { - int ct = pAL->useCt; - void** papNV = (void**)(pAL->apzArgs); + int ct = arg_list->useCt; + void ** o_list = (void**)(arg_list->apzArgs); while (ct-- > 0) { - tOptionValue* pNV = *(papNV++); - if (pNV == pOldOV) { + tOptionValue * nov = *(o_list++); + if (nov == oov) { if (ct == 0) { err = ENOENT; } else { - err = 0; - pRes = (tOptionValue*)*papNV; + err = 0; + res = (tOptionValue*)*o_list; } break; } @@ -396,20 +403,19 @@ optionNextValue(tOptionValue const * pOVList,tOptionValue const * pOldOV ) } if (err != 0) errno = err; - return pRes; + return res; } - /** * Load a file containing presetting information (a configuration file). */ static void file_preset(tOptions * opts, char const * fname, int dir) { - tmap_info_t cfgfile; - tOptState optst = OPTSTATE_INITIALIZER(PRESET); - unsigned long st_flags = optst.flags; - char * ftext = + tmap_info_t cfgfile; + tOptState optst = OPTSTATE_INITIALIZER(PRESET); + opt_state_mask_t st_flags = optst.flags; + char * ftext = text_mmap(fname, PROT_READ|PROT_WRITE, MAP_PRIVATE, &cfgfile); if (TEXT_MMAP_FAILED_ADDR(ftext)) @@ -456,8 +462,10 @@ file_preset(tOptions * opts, char const * fname, int dir) break; default: - goto all_done; + ftext = NULL; } + if (ftext == NULL) + goto all_done; break; case '[': @@ -473,47 +481,45 @@ file_preset(tOptions * opts, char const * fname, int dir) } } while (ftext != NULL); -all_done: + all_done: text_munmap(&cfgfile); } - /** - * "pzText" points to a "<!" sequence. + * "txt" points to a "<!" sequence. * Theoretically, we should ensure that it begins with "<!--", * but actually I don't care that much. It ends with "-->". */ -static char* -handle_comment(char* pzText) +static char * +handle_comment(char* txt) { - char* pz = strstr(pzText, "-->"); + char* pz = strstr(txt, "-->"); if (pz != NULL) pz += 3; return pz; } - /** - * "pzText" points to the start of some value name. + * "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 * pOpts, tOptState * pOS, char * pzText, int dir) +handle_cfg(tOptions * opts, tOptState * ost, char * txt, int dir) { - char* pzName = pzText++; - char* pzEnd = strchr(pzText, NL); + char* pzName = txt++; + char* pzEnd = strchr(txt, NL); if (pzEnd == NULL) - return pzText + strlen(pzText); + return txt + strlen(txt); - pzText = SPN_VALUE_NAME_CHARS(pzText); - pzText = SPN_WHITESPACE_CHARS(pzText); - if (pzText > pzEnd) { + txt = SPN_VALUE_NAME_CHARS(txt); + txt = SPN_WHITESPACE_CHARS(txt); + if (txt > pzEnd) { name_only: *pzEnd++ = NUL; - loadOptionLine(pOpts, pOS, pzName, dir, OPTION_LOAD_UNCOOKED); + loadOptionLine(opts, ost, pzName, dir, OPTION_LOAD_UNCOOKED); return pzEnd; } @@ -522,11 +528,11 @@ handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir) * or else we must have skipped over white space. Anything else * is an invalid format and we give up parsing the text. */ - if ((*pzText == '=') || (*pzText == ':')) { - pzText = SPN_WHITESPACE_CHARS(pzText+1); - if (pzText > pzEnd) + if ((*txt == '=') || (*txt == ':')) { + txt = SPN_WHITESPACE_CHARS(txt+1); + if (txt > pzEnd) goto name_only; - } else if (! IS_WHITESPACE_CHAR(pzText[-1])) + } else if (! IS_WHITESPACE_CHAR(txt[-1])) return NULL; /* @@ -542,6 +548,7 @@ handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir) switch (ch) { case NUL: pcS = NULL; + /* FALLTHROUGH */ case NL: *pcD = NUL; @@ -549,9 +556,8 @@ handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir) goto copy_done; case '\\': - if (*pcS == NL) { + if (*pcS == NL) ch = *(pcS++); - } /* FALLTHROUGH */ default: *(pcD++) = ch; @@ -569,19 +575,22 @@ handle_cfg(tOptions * pOpts, tOptState * pOS, char * pzText, int dir) * "pzName" points to what looks like text for one option/configurable. * It is NUL terminated. Process it. */ - loadOptionLine(pOpts, pOS, pzName, dir, OPTION_LOAD_UNCOOKED); + loadOptionLine(opts, ost, pzName, dir, OPTION_LOAD_UNCOOKED); return pzEnd; } - /** - * "pzText" points to a "<?" sequence. + * "txt" points to a "<?" sequence. * We handle "<?program" and "<?auto-options" directives. * All others are treated as comments. + * + * @param[in,out] opts program option descriptor + * @param[in] txt scanning pointer + * @returns the next character to look at */ static char * -handle_directive(tOptions * pOpts, char * pzText) +handle_directive(tOptions * opts, char * txt) { # define DIRECTIVE_TABLE \ _dt_(zCfgProg, program_directive) \ @@ -610,112 +619,124 @@ handle_directive(tOptions * pOpts, char * pzText) for (ix = 0; ix < dir_ct; ix++) { size_t len = strlen(dir_names[ix]); - if ( (strncmp(pzText + 2, dir_names[ix], len) == 0) - && (! IS_VALUE_NAME_CHAR(pzText[len+2])) ) - return dir_disp[ix](pOpts, pzText + len + 2); + if ( (strncmp(txt + 2, dir_names[ix], len) == 0) + && (! IS_VALUE_NAME_CHAR(txt[len+2])) ) + return dir_disp[ix](opts, txt + len + 2); } /* * We don't know what this is. Skip it. */ - pzText = strchr(pzText+2, '>'); - if (pzText != NULL) - pzText++; - return pzText; + txt = strchr(txt+2, '>'); + if (txt != NULL) + txt++; + return txt; +# undef DIRECTIVE_TABLE } /** - * handle AutoOpts mode flags + * handle AutoOpts mode flags. + * + * @param[in,out] opts program option descriptor + * @param[in] txt scanning pointer + * @returns the next character to look at */ static char * -aoflags_directive(tOptions * pOpts, char * pzText) +aoflags_directive(tOptions * opts, char * txt) { char * pz; - pz = SPN_WHITESPACE_CHARS(pzText+1); - pzText = strchr(pz, '>'); - if (pzText != NULL) { + pz = SPN_WHITESPACE_CHARS(txt+1); + txt = strchr(pz, '>'); + if (txt != NULL) { - size_t len = pzText - pz; + size_t len = (unsigned)(txt - pz); char * ftxt = AGALOC(len + 1, "aoflags"); memcpy(ftxt, pz, len); ftxt[len] = NUL; - set_usage_flags(pOpts, ftxt); + set_usage_flags(opts, ftxt); AGFREE(ftxt); - pzText++; + txt++; } - return pzText; + return txt; } /** * 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 * pOpts, char * pzText) +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(pOpts->pzProgName); + 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 { - pzText = SPN_WHITESPACE_CHARS(pzText+1); + txt = SPN_WHITESPACE_CHARS(txt+1); - if ( (strneqvcmp(pzText, pOpts->pzProgName, (int)name_len) == 0) - && (IS_END_XML_TOKEN_CHAR(pzText[name_len])) ) { - pzText += name_len; + if ( (strneqvcmp(txt, opts->pzProgName, (int)name_len) == 0) + && (IS_END_XML_TOKEN_CHAR(txt[name_len])) ) { + txt += name_len; break; } - pzText = strstr(pzText, ttl); - } while (pzText != NULL); + txt = strstr(txt, ttl); + } while (txt != NULL); AGFREE(ttl); - if (pzText != NULL) + if (txt != NULL) for (;;) { - if (*pzText == NUL) { - pzText = NULL; + if (*txt == NUL) { + txt = NULL; break; } - if (*(pzText++) == '>') + if (*(txt++) == '>') break; } - return pzText; + return txt; } - /** - * "pzText" points to a '[' character. + * "txt" points to a '[' character. * The "traditional" [PROG_NAME] segmentation of the config file. * Do not ever mix with the "<?program prog-name>" variation. + * + * @param[in,out] opts program option descriptor + * @param[in] txt scanning pointer + * @returns the next character to look at */ static char * -handle_section(tOptions * pOpts, char * pzText) +handle_section(tOptions * opts, char * txt) { - size_t len = strlen(pOpts->pzPROGNAME); - if ( (strncmp(pzText+1, pOpts->pzPROGNAME, len) == 0) - && (pzText[len+1] == ']')) - return strchr(pzText + len + 2, NL); + size_t len = strlen(opts->pzPROGNAME); + if ( (strncmp(txt+1, opts->pzPROGNAME, len) == 0) + && (txt[len+1] == ']')) + return strchr(txt + len + 2, NL); if (len > 16) return NULL; { char z[24]; - sprintf(z, "[%s]", pOpts->pzPROGNAME); - pzText = strstr(pzText, z); + sprintf(z, "[%s]", opts->pzPROGNAME); + txt = strstr(txt, z); } - if (pzText != NULL) - pzText = strchr(pzText, NL); - return pzText; + if (txt != NULL) + txt = strchr(txt, NL); + return txt; } /** @@ -820,7 +841,7 @@ trim_xml_text(char * intxt, char const * pznm, tOptionLoadMode mode) if (len >= sizeof(z)) pz = AGALOC(len, "scan name"); - len = sprintf(pz, fmt, pznm); + len = (size_t)sprintf(pz, fmt, pznm); *intxt = ' '; etext = strstr(intxt, pz); if (pz != z) AGFREE(pz); @@ -872,7 +893,7 @@ cook_xml_text(char * pzData) return; } - ch = strtoul(bf, NULL, 16); + ch = (int)strtoul(bf, NULL, 16); /* FALLTHROUGH */ default: @@ -882,67 +903,70 @@ cook_xml_text(char * pzData) } /** - * "pzText" points to a '<' character, followed by an alpha. + * "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 * pOpts, tOptState * pOS, char * pzText, int dir) +handle_struct(tOptions * opts, tOptState * ost, char * txt, int dir) { tOptionLoadMode mode = option_load_mode; tOptionValue valu; - char* pzName = ++pzText; + char* pzName = ++txt; char* pzData; char* pcNulPoint; - pzText = SPN_VALUE_NAME_CHARS(pzText); - pcNulPoint = pzText; + txt = SPN_VALUE_NAME_CHARS(txt); + pcNulPoint = txt; valu.valType = OPARG_TYPE_STRING; - switch (*pzText) { + switch (*txt) { case ' ': case '\t': - pzText = parse_attrs(pOpts, pzText, &mode, &valu); - if (*pzText == '>') + txt = (void *)parse_attrs( + opts, SPN_WHITESPACE_CHARS(txt), &mode, &valu); + if (txt == NULL) + return txt; + if (*txt == '>') break; - if (*pzText != '/') + if (*txt != '/') return NULL; /* FALLTHROUGH */ case '/': - if (pzText[1] != '>') + if (txt[1] != '>') return NULL; - *pzText = NUL; - pzText += 2; - loadOptionLine(pOpts, pOS, pzName, dir, mode); - return pzText; + *txt = NUL; + txt += 2; + loadOptionLine(opts, ost, pzName, dir, mode); + return txt; case '>': break; default: - pzText = strchr(pzText, '>'); - if (pzText != NULL) - pzText++; - return pzText; + txt = strchr(txt, '>'); + if (txt != NULL) + txt++; + return txt; } /* - * If we are here, we have a value. "pzText" points to a closing angle + * 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 = ++pzText; - pzText = trim_xml_text(pzText, pzName, mode); - if (pzText == NULL) - return pzText; + 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, ' ', pzData - pcNulPoint); + memset(pcNulPoint, ' ', (size_t)(pzData - pcNulPoint)); /* * If we are getting a "string" value that is to be cooked, @@ -956,40 +980,39 @@ handle_struct(tOptions * pOpts, tOptState * pOS, char * pzText, int dir) * "pzName" points to what looks like text for one option/configurable. * It is NUL terminated. Process it. */ - loadOptionLine(pOpts, pOS, pzName, dir, mode); + loadOptionLine(opts, ost, pzName, dir, mode); - return pzText; + return txt; } - /** * Load a configuration file. This may be invoked either from * scanning the "homerc" list, or from a specific file request. * (see "optionFileLoad()", the implementation for --load-opts) */ LOCAL void -intern_file_load(tOptions* pOpts) +intern_file_load(tOptions * opts) { uint32_t svfl; int idx; int inc; - char zFileName[ AG_PATH_MAX+1 ]; + char f_name[ AG_PATH_MAX+1 ]; - if (pOpts->papzHomeList == NULL) + if (opts->papzHomeList == NULL) return; - svfl = pOpts->fOptSet; + svfl = opts->fOptSet; inc = DIRECTION_PRESET; /* * Never stop on errors in config files. */ - pOpts->fOptSet &= ~OPTPROC_ERRSTOP; + opts->fOptSet &= ~OPTPROC_ERRSTOP; /* * Find the last RC entry (highest priority entry) */ - for (idx = 0; pOpts->papzHomeList[ idx+1 ] != NULL; ++idx) ; + for (idx = 0; opts->papzHomeList[ idx+1 ] != NULL; ++idx) ; /* * For every path in the home list, ... *TWICE* We start at the last @@ -998,8 +1021,8 @@ intern_file_load(tOptions* pOpts) * Then we go back up, doing the normal options. */ for (;;) { - struct stat StatBuf; - cch_t* pzPath; + struct stat sb; + cch_t * path; /* * IF we've reached the bottom end, change direction @@ -1009,18 +1032,18 @@ intern_file_load(tOptions* pOpts) idx = 0; } - pzPath = pOpts->papzHomeList[ idx ]; + path = opts->papzHomeList[ idx ]; /* * IF we've reached the top end, bail out */ - if (pzPath == NULL) + if (path == NULL) break; idx += inc; - if (! optionMakePath(zFileName, (int)sizeof(zFileName), - pzPath, pOpts->pzProgPath)) + if (! optionMakePath(f_name, (int)sizeof(f_name), + path, opts->pzProgPath)) continue; /* @@ -1028,47 +1051,46 @@ intern_file_load(tOptions* pOpts) * THEN append the Resource Configuration file name * ELSE we must have the complete file name */ - if (stat(zFileName, &StatBuf) != 0) + if (stat(f_name, &sb) != 0) continue; /* bogus name - skip the home list entry */ - if (S_ISDIR(StatBuf.st_mode)) { - size_t len = strlen(zFileName); - size_t nln = strlen(pOpts->pzRcName) + 1; - char * pz = zFileName + len; + if (S_ISDIR(sb.st_mode)) { + size_t len = strlen(f_name); + size_t nln = strlen(opts->pzRcName) + 1; + char * pz = f_name + len; - if (len + 1 + nln >= sizeof(zFileName)) + if (len + 1 + nln >= sizeof(f_name)) continue; if (pz[-1] != DIRCH) *(pz++) = DIRCH; - memcpy(pz, pOpts->pzRcName, nln); + memcpy(pz, opts->pzRcName, nln); } - file_preset(pOpts, zFileName, inc); + file_preset(opts, f_name, inc); /* * IF we are now to skip config files AND we are presetting, * THEN change direction. We must go the other way. */ { - tOptDesc * pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts+1; - if (DISABLED_OPT(pOD) && PRESETTING(inc)) { + tOptDesc * od = opts->pOptDesc + opts->specOptIdx.save_opts + 1; + if (DISABLED_OPT(od) && PRESETTING(inc)) { idx -= inc; /* go back and reprocess current file */ inc = DIRECTION_PROCESS; } } } /* twice for every path in the home list, ... */ - pOpts->fOptSet = svfl; + opts->fOptSet = svfl; } - /*=export_func optionFileLoad * * what: Load the locatable config files, in order * - * arg: + tOptions* + pOpts + program options descriptor + - * arg: + char const* + pzProg + program name + + * arg: + tOptions* + opts + program options descriptor + + * arg: + char const* + prog + program name + * * ret_type: int * ret_desc: 0 -> SUCCESS, -1 -> FAILURE @@ -1097,330 +1119,254 @@ intern_file_load(tOptions* pOpts) * always be returned. =*/ int -optionFileLoad(tOptions * pOpts, char const * pzProgram) +optionFileLoad(tOptions * opts, char const * prog) { - if (! SUCCESSFUL(validate_struct(pOpts, pzProgram))) + if (! SUCCESSFUL(validate_struct(opts, prog))) return -1; + /* + * The pointer to the program name is "const". However, the + * structure is in writable memory, so we coerce the address + * of this pointer to point to writable memory. + */ { char const ** pp = - (char const **)(void *)&(pOpts->pzProgName); - *pp = pzProgram; + (char const **)(void *)&(opts->pzProgName); + *pp = prog; } - intern_file_load(pOpts); + intern_file_load(opts); return 0; } - /*=export_func optionLoadOpt * private: * * what: Load an option rc/ini file - * arg: + tOptions* + pOpts + program options descriptor + - * arg: + tOptDesc* + pOptDesc + the descriptor for this arg + + * arg: + tOptions* + opts + program options descriptor + + * arg: + tOptDesc* + odesc + the descriptor for this arg + * * doc: * Processes the options found in the file named with - * pOptDesc->optArg.argString. + * odesc->optArg.argString. =*/ void -optionLoadOpt(tOptions * pOpts, tOptDesc * pOptDesc) +optionLoadOpt(tOptions * opts, tOptDesc * odesc) { struct stat sb; + if (opts <= OPTPROC_EMIT_LIMIT) + return; + /* * IF the option is not being disabled, THEN load the file. There must * be a file. (If it is being disabled, then the disablement processing * already took place. It must be done to suppress preloading of ini/rc * files.) */ - if ( DISABLED_OPT(pOptDesc) - || ((pOptDesc->fOptState & OPTST_RESET) != 0)) + if ( DISABLED_OPT(odesc) + || ((odesc->fOptState & OPTST_RESET) != 0)) return; - if (stat(pOptDesc->optArg.argString, &sb) != 0) { - if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) + if (stat(odesc->optArg.argString, &sb) != 0) { + if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) return; - fprintf(stderr, zFSErrOptLoad, errno, strerror(errno), - pOptDesc->optArg.argString); - exit(EX_NOINPUT); + fserr_exit(opts->pzProgName, "stat", odesc->optArg.argString); /* NOT REACHED */ } if (! S_ISREG(sb.st_mode)) { - if ((pOpts->fOptSet & OPTPROC_ERRSTOP) == 0) + if ((opts->fOptSet & OPTPROC_ERRSTOP) == 0) return; - - fprintf(stderr, zNotFile, pOptDesc->optArg.argString); - exit(EX_NOINPUT); + errno = EINVAL; + fserr_exit(opts->pzProgName, "stat", odesc->optArg.argString); /* NOT REACHED */ } - file_preset(pOpts, pOptDesc->optArg.argString, DIRECTION_CALLED); + file_preset(opts, odesc->optArg.argString, DIRECTION_CALLED); } - /** * Parse the various attributes of an XML-styled config file entry + * + * @returns NULL on failure, otherwise the scan point */ -LOCAL char* -parse_attrs(tOptions * pOpts, char * pzText, tOptionLoadMode * pMode, +LOCAL char const * +parse_attrs(tOptions * opts, char const * txt, 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; - } + size_t len = 0; - pzText = SPN_WHITESPACE_CHARS(pzText+1); - len = SPN_LOWER_CASE_CHARS(pzText) - pzText; + for (;;) { + len = (size_t)(SPN_LOWER_CASE_CHARS(txt) - txt); - switch (find_xat_attribute_id(pzText, len)) { - case XAT_KWD_TYPE: - pzText = parse_value(pzText+len, pType); + /* + * 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_KWD_WORDS: - pzText = parse_keyword(pOpts, pzText+len, pType); + case XAT_CMD_WORDS: + txt = parse_keyword(opts, txt+len, pType); break; - case XAT_KWD_MEMBERS: - pzText = parse_set_mem(pOpts, pzText+len, pType); + case XAT_CMD_MEMBERS: + txt = parse_set_mem(opts, txt+len, pType); break; - case XAT_KWD_COOKED: - pzText += len; - if (! IS_END_XML_TOKEN_CHAR(*pzText)) + case XAT_CMD_COOKED: + txt += len; + if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_COOKED; break; - case XAT_KWD_UNCOOKED: - pzText += len; - if (! IS_END_XML_TOKEN_CHAR(*pzText)) + case XAT_CMD_UNCOOKED: + txt += len; + if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_UNCOOKED; break; - case XAT_KWD_KEEP: - pzText += len; - if (! IS_END_XML_TOKEN_CHAR(*pzText)) + case XAT_CMD_KEEP: + txt += len; + if (! IS_END_XML_TOKEN_CHAR(*txt)) goto invalid_kwd; *pMode = OPTION_LOAD_KEEP; break; default: - case XAT_KWD_INVALID: + case XAT_INVALID_CMD: invalid_kwd: pType->valType = OPARG_TYPE_NONE; - return skip_unkn(pzText); + return skip_unkn(txt); } - } while (pzText != NULL); - return pzText; + 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; + } } - /** - * "pzText" points to the character after "words=". + * "txt" points to the character after "words=". * What should follow is a name of a keyword (enumeration) list. + * + * @param opts unused + * @param[in] txt keyword to skip over + * @param type unused value type + * @returns pointer after skipped text */ -static char* -parse_keyword(tOptions * pOpts, char * pzText, tOptionValue * pType) +static char const * +parse_keyword(tOptions * opts, char const * txt, tOptionValue * typ) { - (void)pOpts; - (void)pType; + (void)opts; + (void)typ; - return skip_unkn(pzText); + return skip_unkn(txt); } - /** - * "pzText" points to the character after "members=" + * "txt" points to the character after "members=" * What should follow is a name of a "set membership". * A collection of bit flags. + * + * @param opts unused + * @param[in] txt keyword to skip over + * @param type unused value type + * @returns pointer after skipped text */ -static char* -parse_set_mem(tOptions * pOpts, char * pzText, tOptionValue * pType) +static char const * +parse_set_mem(tOptions * opts, char const * txt, tOptionValue * typ) { - (void)pOpts; - (void)pType; + (void)opts; + (void)typ; - return skip_unkn(pzText); + return skip_unkn(txt); } - /** - * "pzText" points to the character after "type=" + * 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 * -parse_value(char * pzText, tOptionValue * pType) +static char const * +parse_value(char const * txt, tOptionValue * typ) { size_t len = 0; - if (*(pzText++) != '=') + if (*(txt++) != '=') goto woops; - len = SPN_OPTION_NAME_CHARS(pzText) - pzText; + len = (size_t)(SPN_OPTION_NAME_CHARS(txt) - txt); - if ((len == 0) || (! IS_END_XML_TOKEN_CHAR(pzText[len]))) { + if ((len == 0) || (! IS_END_XML_TOKEN_CHAR(txt[len]))) { woops: - pType->valType = OPARG_TYPE_NONE; - return skip_unkn(pzText + len); + typ->valType = OPARG_TYPE_NONE; + return skip_unkn(txt + len); } - switch (find_value_type_id(pzText, 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_KWD_INVALID: goto woops; + case VTP_INVALID_CMD: goto woops; - case VTP_KWD_STRING: - pType->valType = OPARG_TYPE_STRING; + case VTP_CMD_STRING: + typ->valType = OPARG_TYPE_STRING; break; - case VTP_KWD_INTEGER: - pType->valType = OPARG_TYPE_NUMERIC; + case VTP_CMD_INTEGER: + typ->valType = OPARG_TYPE_NUMERIC; break; - case VTP_KWD_BOOL: - case VTP_KWD_BOOLEAN: - pType->valType = OPARG_TYPE_BOOLEAN; + case VTP_CMD_BOOL: + case VTP_CMD_BOOLEAN: + typ->valType = OPARG_TYPE_BOOLEAN; break; - case VTP_KWD_KEYWORD: - pType->valType = OPARG_TYPE_ENUMERATION; + case VTP_CMD_KEYWORD: + typ->valType = OPARG_TYPE_ENUMERATION; break; - case VTP_KWD_SET: - case VTP_KWD_SET_MEMBERSHIP: - pType->valType = OPARG_TYPE_MEMBERSHIP; + case VTP_CMD_SET: + case VTP_CMD_SET_MEMBERSHIP: + typ->valType = OPARG_TYPE_MEMBERSHIP; break; - case VTP_KWD_NESTED: - case VTP_KWD_HIERARCHY: - pType->valType = OPARG_TYPE_HIERARCHY; + case VTP_CMD_NESTED: + case VTP_CMD_HIERARCHY: + typ->valType = OPARG_TYPE_HIERARCHY; } - return pzText + len; -} - - -/** - * 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; - } + return txt + len; } - -/** - * Make sure the option descriptor is there and that we understand it. - * This should be called from any user entry point where one needs to - * worry about validity. (Some entry points are free to assume that - * the call is not the first to the library and, thus, that this has - * already been called.) +/** @} * - * Upon successful completion, pzProgName and pzProgPath are set. - * - * @param pOpts program options descriptor - * @param pzProgram name of program, from argv[] - * @returns SUCCESS or FAILURE - */ -LOCAL tSuccess -validate_struct(tOptions * pOpts, char const * pzProgram) -{ - if (pOpts == NULL) { - fputs(zAO_Bad, stderr); - return FAILURE; - } - - /* - * IF the client has enabled translation and the translation procedure - * is available, then go do it. - */ - if ( ((pOpts->fOptSet & OPTPROC_TRANSLATE) != 0) - && (pOpts->pTransProc != NULL) ) { - /* - * If option names are not to be translated at all, then do not do - * it for configuration parsing either. (That is the bit that really - * gets tested anyway.) - */ - if ((pOpts->fOptSet & OPTPROC_NO_XLAT_MASK) == OPTPROC_NXLAT_OPT) - pOpts->fOptSet |= OPTPROC_NXLAT_OPT_CFG; - (*pOpts->pTransProc)(); - pOpts->fOptSet &= ~OPTPROC_TRANSLATE; - } - - /* - * IF the struct version is not the current, and also - * either too large (?!) or too small, - * THEN emit error message and fail-exit - */ - if ( ( pOpts->structVersion != OPTIONS_STRUCT_VERSION ) - && ( (pOpts->structVersion > OPTIONS_STRUCT_VERSION ) - || (pOpts->structVersion < OPTIONS_MINIMUM_VERSION ) - ) ) { - static char const aover[] = - STR(AO_CURRENT)":"STR(AO_REVISION)":"STR(AO_AGE)"\n"; - - fprintf(stderr, zAO_Err, pzProgram, NUM_TO_VER(pOpts->structVersion)); - if (pOpts->structVersion > OPTIONS_STRUCT_VERSION ) - fputs(zAO_Big, stderr); - else - fputs(zAO_Sml, stderr); - - fwrite(aover, sizeof(aover) - 1, 1, stderr); - return FAILURE; - } - - /* - * If the program name hasn't been set, then set the name and the path - * and the set of equivalent characters. - */ - if (pOpts->pzProgName == NULL) { - char const * pz = strrchr(pzProgram, DIRCH); - char const ** pp = - (char const **)(void **)&(pOpts->pzProgName); - - if (pz != NULL) { - *pp = pz+1; - } else { - *pp = pzProgram; - pz = pathfind(getenv("PATH"), (char *)pzProgram, "rx"); - if (pz != NULL) - pzProgram = (void *)pz; - } - - pp = (char const **)(void **)&(pOpts->pzProgPath); - *pp = pzProgram; - - /* - * when comparing long names, these are equivalent - */ - strequate(zSepChars); - } - - return SUCCESS; -} - - -/** * Local Variables: * mode: C * c-file-style: "stroustrup" |