diff options
Diffstat (limited to 'sntp/libopts/load.c')
-rw-r--r-- | sntp/libopts/load.c | 480 |
1 files changed, 275 insertions, 205 deletions
diff --git a/sntp/libopts/load.c b/sntp/libopts/load.c index 024dce9301a8..5c29d96ecc9a 100644 --- a/sntp/libopts/load.c +++ b/sntp/libopts/load.c @@ -1,15 +1,18 @@ /** * \file load.c - * Time-stamp: "2010-12-18 11:46:07 bkorb" * * This file contains the routines that deal with processing text strings * for options, either from a NUL-terminated string passed in or from an * rc/ini file. * + * @addtogroup autoopts + * @{ + */ +/* * This file is part of AutoOpts, a companion to AutoGen. * AutoOpts is free software. - * AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved + * AutoOpts is Copyright (C) 1992-2014 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 @@ -21,37 +24,83 @@ * 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 ag_bool -insertProgramPath(char * pzBuf, int bufSize, char const * pzName, - char const * pzProgPath); +static bool +get_realpath(char * buf, size_t b_sz); + +static bool +add_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path); + +static bool +add_env_val(char * buf, int buf_sz, char const * name); -static ag_bool -insertEnvVal(char * pzBuf, int bufSize, char const * pzName, - char const * pzProgPath); +static char * +assemble_arg_val(char * txt, tOptionLoadMode mode); -static char* -assembleArgValue(char* pzTxt, tOptionLoadMode mode); +static char * +trim_quotes(char * arg); + +static bool +direction_ok(opt_state_mask_t f, int dir); /* = = = END-STATIC-FORWARD = = = */ +static bool +get_realpath(char * buf, size_t b_sz) +{ +#if defined(HAVE_CANONICALIZE_FILE_NAME) + { + size_t name_len; + + char * pz = canonicalize_file_name(buf); + if (pz == NULL) + return false; + + name_len = strlen(pz); + if (name_len >= (size_t)b_sz) { + free(pz); + return false; + } + + memcpy(buf, pz, name_len + 1); + free(pz); + } + +#elif defined(HAVE_REALPATH) + { + size_t name_len; + char z[PATH_MAX+1]; + + if (realpath(buf, z) == NULL) + return false; + + name_len = strlen(z); + if (name_len >= b_sz) + return false; + + memcpy(buf, z, name_len + 1); + } +#endif + return true; +} + /*=export_func optionMakePath * private: * * what: translate and construct a path - * arg: + char* + pzBuf + The result buffer + - * arg: + int + bufSize + The size of this buffer + - * arg: + char const* + pzName + The input name + - * arg: + char const* + pzProgPath + The full path of the current program + + * arg: + char* + p_buf + The result buffer + + * arg: + int + b_sz + The size of this buffer + + * arg: + char const* + fname + The input name + + * arg: + char const* + prg_path + The full path of the current program + * - * ret-type: ag_bool - * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE. + * ret-type: bool + * ret-desc: true if the name was handled, otherwise false. * If the name does not start with ``$'', then it is handled * simply by copying the input name to the output buffer and * resolving the name with either @@ -77,7 +126,7 @@ assembleArgValue(char* pzTxt, tOptionLoadMode mode); * @code{pzName} string and must either be the entire string or be followed * by the @code{'/'} (backslash on windows) character. * - * err: @code{AG_FALSE} is returned if: + * err: @code{false} is returned if: * @* * @bullet{} The input name exceeds @code{bufSize} bytes. * @* @@ -92,28 +141,29 @@ assembleArgValue(char* pzTxt, tOptionLoadMode mode); * @bullet{} @code{canonicalize_file_name} or @code{realpath} return * errors (cannot resolve the resulting path). =*/ -ag_bool -optionMakePath(char * pzBuf, int bufSize, char const * pzName, - char const * pzProgPath) +bool +optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path) { - size_t name_len = strlen(pzName); + { + size_t len = strlen(fname); - if ((bufSize <= name_len) || (name_len == 0)) - return AG_FALSE; + if (((size_t)b_sz <= len) || (len == 0)) + return false; + } /* * IF not an environment variable, just copy the data */ - if (*pzName != '$') { - char const* pzS = pzName; - char* pzD = pzBuf; - int ct = bufSize; + if (*fname != '$') { + char const * src = fname; + char * dst = p_buf; + int ct = b_sz; for (;;) { - if ( (*(pzD++) = *(pzS++)) == NUL) + if ( (*(dst++) = *(src++)) == NUL) break; if (--ct <= 0) - return AG_FALSE; + return false; } } @@ -122,79 +172,49 @@ optionMakePath(char * pzBuf, int bufSize, char const * pzName, * it must start with "$$/". In either event, replace the "$$" * with the path to the executable and append a "/" character. */ - else switch (pzName[1]) { + else switch (fname[1]) { case NUL: - return AG_FALSE; + return false; case '$': - if (! insertProgramPath(pzBuf, bufSize, pzName, pzProgPath)) - return AG_FALSE; + if (! add_prog_path(p_buf, b_sz, fname, prg_path)) + return false; break; case '@': if (program_pkgdatadir[0] == NUL) - return AG_FALSE; + return false; - if (snprintf(pzBuf, bufSize, "%s%s", program_pkgdatadir, pzName + 2) - >= bufSize) - return AG_FALSE; + if (snprintf(p_buf, (size_t)b_sz, "%s%s", + program_pkgdatadir, fname + 2) >= b_sz) + return false; break; default: - if (! insertEnvVal(pzBuf, bufSize, pzName, pzProgPath)) - return AG_FALSE; + if (! add_env_val(p_buf, b_sz, fname)) + return false; } -#if defined(HAVE_CANONICALIZE_FILE_NAME) - { - char * pz = canonicalize_file_name(pzBuf); - if (pz == NULL) - return AG_FALSE; - - name_len = strlen(pz); - if (name_len >= bufSize) { - free(pz); - return AG_FALSE; - } - - memcpy(pzBuf, pz, name_len + 1); - free(pz); - } - -#elif defined(HAVE_REALPATH) - { - char z[PATH_MAX+1]; - - if (realpath(pzBuf, z) == NULL) - return AG_FALSE; - - name_len = strlen(z); - if (name_len >= bufSize) - return AG_FALSE; - - memcpy(pzBuf, z, name_len + 1); - } -#endif - - return AG_TRUE; + return get_realpath(p_buf, b_sz); } - -static ag_bool -insertProgramPath(char * pzBuf, int bufSize, char const * pzName, - char const * pzProgPath) +/** + * convert a leading "$$" into a path to the executable. + */ +static bool +add_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path) { - char const* pzPath; - char const* pz; + char const * path; + char const * pz; int skip = 2; - switch (pzName[2]) { + switch (fname[2]) { case DIRCH: skip = 3; case NUL: break; default: - return AG_FALSE; + return false; } /* @@ -202,104 +222,112 @@ insertProgramPath(char * pzBuf, int bufSize, char const * pzName, * If it is, we're done. Otherwise, we have to hunt * for the program using "pathfind". */ - if (strchr(pzProgPath, DIRCH) != NULL) - pzPath = pzProgPath; + if (strchr(prg_path, DIRCH) != NULL) + path = prg_path; else { - pzPath = pathfind(getenv("PATH"), (char*)pzProgPath, "rx"); + path = pathfind(getenv("PATH"), (char*)prg_path, "rx"); - if (pzPath == NULL) - return AG_FALSE; + if (path == NULL) + return false; } - pz = strrchr(pzPath, DIRCH); + pz = strrchr(path, DIRCH); /* * IF we cannot find a directory name separator, * THEN we do not have a path name to our executable file. */ if (pz == NULL) - return AG_FALSE; + return false; - pzName += skip; + fname += skip; /* * Concatenate the file name to the end of the executable path. * The result may be either a file or a directory. */ - if ((pz - pzPath)+1 + strlen(pzName) >= bufSize) - return AG_FALSE; + if ((unsigned)(pz - path) + 1 + strlen(fname) >= (unsigned)b_sz) + return false; - memcpy(pzBuf, pzPath, (size_t)((pz - pzPath)+1)); - strcpy(pzBuf + (pz - pzPath) + 1, pzName); + memcpy(buf, path, (size_t)((pz - path)+1)); + strcpy(buf + (pz - path) + 1, fname); /* - * If the "pzPath" path was gotten from "pathfind()", then it was + * If the "path" path was gotten from "pathfind()", then it was * allocated and we need to deallocate it. */ - if (pzPath != pzProgPath) - AGFREE(pzPath); - return AG_TRUE; + if (path != prg_path) + AGFREE(path); + return true; } - -static ag_bool -insertEnvVal(char * pzBuf, int bufSize, char const * pzName, - char const * pzProgPath) +/** + * Add an environment variable value. + */ +static bool +add_env_val(char * buf, int buf_sz, char const * name) { - char* pzDir = pzBuf; + char * dir_part = buf; for (;;) { - int ch = (int)*++pzName; + int ch = (int)*++name; if (! IS_VALUE_NAME_CHAR(ch)) break; - *(pzDir++) = (char)ch; + *(dir_part++) = (char)ch; } - if (pzDir == pzBuf) - return AG_FALSE; + if (dir_part == buf) + return false; - *pzDir = NUL; + *dir_part = NUL; - pzDir = getenv(pzBuf); + dir_part = getenv(buf); /* * Environment value not found -- skip the home list entry */ - if (pzDir == NULL) - return AG_FALSE; + if (dir_part == NULL) + return false; - if (strlen(pzDir) + 1 + strlen(pzName) >= bufSize) - return AG_FALSE; + if (strlen(dir_part) + 1 + strlen(name) >= (unsigned)buf_sz) + return false; - sprintf(pzBuf, "%s%s", pzDir, pzName); - return AG_TRUE; + sprintf(buf, "%s%s", dir_part, name); + return true; } - +/** + * Trim leading and trailing white space. + * If we are cooking the text and the text is quoted, then "cook" + * the string. To cook, the string must be quoted. + * + * @param[in,out] txt the input and output string + * @param[in] mode the handling mode (cooking method) + */ LOCAL void -mungeString(char* pzTxt, tOptionLoadMode mode) +munge_str(char * txt, tOptionLoadMode mode) { - char* pzE; + char * pzE; if (mode == OPTION_LOAD_KEEP) return; - if (IS_WHITESPACE_CHAR(*pzTxt)) { - char* pzS = pzTxt; - char* pzD = pzTxt; - while (IS_WHITESPACE_CHAR(*++pzS)) ; - while ((*(pzD++) = *(pzS++)) != NUL) ; - pzE = pzD-1; + if (IS_WHITESPACE_CHAR(*txt)) { + char * src = SPN_WHITESPACE_CHARS(txt+1); + size_t l = strlen(src) + 1; + memmove(txt, src, l); + pzE = txt + l - 1; + } else - pzE = pzTxt + strlen(pzTxt); + pzE = txt + strlen(txt); - while ((pzE > pzTxt) && IS_WHITESPACE_CHAR(pzE[-1])) pzE--; + pzE = SPN_WHITESPACE_BACK(txt, pzE); *pzE = NUL; if (mode == OPTION_LOAD_UNCOOKED) return; - switch (*pzTxt) { + switch (*txt) { default: return; case '"': case '\'': break; @@ -311,22 +339,20 @@ mungeString(char* pzTxt, tOptionLoadMode mode) case '\'': break; } - (void)ao_string_cook(pzTxt, NULL); + (void)ao_string_cook(txt, NULL); } - -static char* -assembleArgValue(char* pzTxt, tOptionLoadMode mode) +static char * +assemble_arg_val(char * txt, tOptionLoadMode mode) { - static char const zBrk[] = " \t\n:="; - char* pzEnd = strpbrk(pzTxt, zBrk); - int space_break; + char * end = strpbrk(txt, ARG_BREAK_STR); + int space_break; /* * Not having an argument to a configurable name is okay. */ - if (pzEnd == NULL) - return pzTxt + strlen(pzTxt); + if (end == NULL) + return txt + strlen(txt); /* * If we are keeping all whitespace, then the modevalue starts with the @@ -334,8 +360,8 @@ assembleArgValue(char* pzTxt, tOptionLoadMode mode) * of which character caused it. */ if (mode == OPTION_LOAD_KEEP) { - *(pzEnd++) = NUL; - return pzEnd; + *(end++) = NUL; + return end; } /* @@ -343,90 +369,85 @@ assembleArgValue(char* pzTxt, tOptionLoadMode mode) * because we'll have to skip over an immediately following ':' or '=' * (and the white space following *that*). */ - space_break = IS_WHITESPACE_CHAR(*pzEnd); - *(pzEnd++) = NUL; - while (IS_WHITESPACE_CHAR(*pzEnd)) pzEnd++; - if (space_break && ((*pzEnd == ':') || (*pzEnd == '='))) - while (IS_WHITESPACE_CHAR(*++pzEnd)) ; + space_break = IS_WHITESPACE_CHAR(*end); + *(end++) = NUL; + + end = SPN_WHITESPACE_CHARS(end); + if (space_break && ((*end == ':') || (*end == '='))) + end = SPN_WHITESPACE_CHARS(end+1); - return pzEnd; + return end; } +static char * +trim_quotes(char * arg) +{ + switch (*arg) { + case '"': + case '\'': + ao_string_cook(arg, NULL); + } + return arg; +} -/* - * Load an option from a block of text. The text must start with the - * configurable/option name and be followed by its associated value. - * That value may be processed in any of several ways. See "tOptionLoadMode" - * in autoopts.h. +/** + * See if the option is to be processed in the current scan direction + * (-1 or +1). */ -LOCAL void -loadOptionLine( - tOptions* pOpts, - tOptState* pOS, - char* pzLine, - tDirection direction, - tOptionLoadMode load_mode ) +static bool +direction_ok(opt_state_mask_t f, int dir) { - while (IS_WHITESPACE_CHAR(*pzLine)) pzLine++; - - { - char* pzArg = assembleArgValue(pzLine, load_mode); - - if (! SUCCESSFUL(longOptionFind(pOpts, pzLine, pOS))) - return; - if (pOS->flags & OPTST_NO_INIT) - return; - pOS->pzOptArg = pzArg; - } + if (dir == 0) + return true; - switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) { + switch (f & (OPTST_IMM|OPTST_DISABLE_IMM)) { case 0: /* * The selected option has no immediate action. * THEREFORE, if the direction is PRESETTING * THEN we skip this option. */ - if (PRESETTING(direction)) - return; + if (PRESETTING(dir)) + return false; break; case OPTST_IMM: - if (PRESETTING(direction)) { + if (PRESETTING(dir)) { /* * We are in the presetting direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if disabled. */ - if ((pOS->flags & OPTST_DISABLED) == 0) - return; + if ((f & OPTST_DISABLED) == 0) + return false; } else { /* * We are in the processing direction with an option we handle * immediately for enablement, but normally for disablement. * Therefore, skip if NOT disabled. */ - if ((pOS->flags & OPTST_DISABLED) != 0) - return; + if ((f & OPTST_DISABLED) != 0) + return false; } break; case OPTST_DISABLE_IMM: - if (PRESETTING(direction)) { + if (PRESETTING(dir)) { /* * We are in the presetting direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if NOT disabled. */ - if ((pOS->flags & OPTST_DISABLED) != 0) - return; + if ((f & OPTST_DISABLED) != 0) + return false; } else { /* * We are in the processing direction with an option we handle * immediately for disablement, but normally for disablement. * Therefore, skip if disabled. */ - if ((pOS->flags & OPTST_DISABLED) == 0) - return; + if ((f & OPTST_DISABLED) == 0) + return false; } break; @@ -436,51 +457,95 @@ loadOptionLine( * THEREFORE, if the direction is PROCESSING * THEN we skip this option. */ - if (PROCESSING(direction)) - return; + if (PROCESSING(dir)) + return false; break; } + return true; +} + +/** + * Load an option from a block of text. The text must start with the + * configurable/option name and be followed by its associated value. + * That value may be processed in any of several ways. See "tOptionLoadMode" + * in autoopts.h. + * + * @param[in,out] opts program options descriptor + * @param[in,out] opt_state option processing state + * @param[in,out] line source line with long option name in it + * @param[in] direction current processing direction (preset or not) + * @param[in] load_mode option loading mode (OPTION_LOAD_*) + */ +LOCAL void +load_opt_line(tOptions * opts, tOptState * opt_state, char * line, + tDirection direction, tOptionLoadMode load_mode ) +{ + /* + * When parsing a stored line, we only look at the characters after + * a hyphen. Long names must always be at least two characters and + * short options are always exactly one character long. + */ + line = SPN_LOAD_LINE_SKIP_CHARS(line); + + { + char * arg = assemble_arg_val(line, load_mode); + + if (IS_OPTION_NAME_CHAR(line[1])) { + + if (! SUCCESSFUL(opt_find_long(opts, line, opt_state))) + return; + + } else if (! SUCCESSFUL(opt_find_short(opts, *line, opt_state))) + return; + + if ((! CALLED(direction)) && (opt_state->flags & OPTST_NO_INIT)) + return; + + opt_state->pzOptArg = trim_quotes(arg); + } + + if (! direction_ok(opt_state->flags, direction)) + return; /* * Fix up the args. */ - if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) { - if (*pOS->pzOptArg != NUL) + if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) { + if (*opt_state->pzOptArg != NUL) return; - pOS->pzOptArg = NULL; + opt_state->pzOptArg = NULL; - } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) { - if (*pOS->pzOptArg == NUL) - pOS->pzOptArg = NULL; + } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) { + if (*opt_state->pzOptArg == NUL) + opt_state->pzOptArg = NULL; else { - AGDUPSTR(pOS->pzOptArg, pOS->pzOptArg, "option argument"); - pOS->flags |= OPTST_ALLOC_ARG; + AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); + opt_state->flags |= OPTST_ALLOC_ARG; } } else { - if (*pOS->pzOptArg == NUL) - pOS->pzOptArg = zNil; + if (*opt_state->pzOptArg == NUL) + opt_state->pzOptArg = zNil; else { - AGDUPSTR(pOS->pzOptArg, pOS->pzOptArg, "option argument"); - pOS->flags |= OPTST_ALLOC_ARG; + AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); + opt_state->flags |= OPTST_ALLOC_ARG; } } { tOptionLoadMode sv = option_load_mode; option_load_mode = load_mode; - handle_opt(pOpts, pOS); + handle_opt(opts, opt_state); option_load_mode = sv; } } - /*=export_func optionLoadLine * * what: process a string for an option name and value * - * arg: tOptions*, pOpts, program options descriptor - * arg: char const*, pzLine, NUL-terminated text + * arg: tOptions*, opts, program options descriptor + * arg: char const*, line, NUL-terminated text * * doc: * @@ -491,7 +556,8 @@ loadOptionLine( * When passed a pointer to the option struct and a string, it will find * the option named by the first token on the string and set the option * argument to the remainder of the string. The caller must NUL terminate - * the string. Any embedded new lines will be included in the option + * the string. The caller need not skip over any introductory hyphens. + * Any embedded new lines will be included in the option * argument. If the input looks like one or more quoted strings, then the * input will be "cooked". The "cooking" is identical to the string * formation used in AutoGen definition files (@pxref{basic expression}), @@ -501,15 +567,19 @@ loadOptionLine( * will cause a warning to print, but the function should return. =*/ void -optionLoadLine(tOptions * pOpts, char const * pzLine) +optionLoadLine(tOptions * opts, char const * line) { tOptState st = OPTSTATE_INITIALIZER(SET); - char* pz; - AGDUPSTR(pz, pzLine, "user option line"); - loadOptionLine(pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED); + char * pz; + proc_state_mask_t sv_flags = opts->fOptSet; + opts->fOptSet &= ~OPTPROC_ERRSTOP; + AGDUPSTR(pz, line, "opt line"); + load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED); AGFREE(pz); + opts->fOptSet = sv_flags; } -/* +/** @} + * * Local Variables: * mode: C * c-file-style: "stroustrup" |