1*eabc0478Schristos /* $NetBSD: load.c,v 1.10 2024/08/18 20:47:24 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel 4f003fb54Skardel /** 5f003fb54Skardel * \file load.c 6abb0f93cSkardel * 7abb0f93cSkardel * This file contains the routines that deal with processing text strings 8abb0f93cSkardel * for options, either from a NUL-terminated string passed in or from an 9abb0f93cSkardel * rc/ini file. 10abb0f93cSkardel * 112950cc38Schristos * @addtogroup autoopts 122950cc38Schristos * @{ 132950cc38Schristos */ 142950cc38Schristos /* 15abb0f93cSkardel * This file is part of AutoOpts, a companion to AutoGen. 16abb0f93cSkardel * AutoOpts is free software. 17*eabc0478Schristos * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 18abb0f93cSkardel * 19abb0f93cSkardel * AutoOpts is available under any one of two licenses. The license 20abb0f93cSkardel * in use must be one of these two and the choice is under the control 21abb0f93cSkardel * of the user of the license. 22abb0f93cSkardel * 23abb0f93cSkardel * The GNU Lesser General Public License, version 3 or later 24abb0f93cSkardel * See the files "COPYING.lgplv3" and "COPYING.gplv3" 25abb0f93cSkardel * 26abb0f93cSkardel * The Modified Berkeley Software Distribution License 27abb0f93cSkardel * See the file "COPYING.mbsd" 28abb0f93cSkardel * 292950cc38Schristos * These files have the following sha256 sums: 30abb0f93cSkardel * 312950cc38Schristos * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 322950cc38Schristos * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 332950cc38Schristos * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 34abb0f93cSkardel */ 35abb0f93cSkardel 362950cc38Schristos static bool 372950cc38Schristos get_realpath(char * buf, size_t b_sz) 382950cc38Schristos { 392950cc38Schristos #if defined(HAVE_CANONICALIZE_FILE_NAME) 402950cc38Schristos { 412950cc38Schristos size_t name_len; 422950cc38Schristos 432950cc38Schristos char * pz = canonicalize_file_name(buf); 442950cc38Schristos if (pz == NULL) 452950cc38Schristos return false; 462950cc38Schristos 472950cc38Schristos name_len = strlen(pz); 482950cc38Schristos if (name_len >= (size_t)b_sz) { 492950cc38Schristos free(pz); 502950cc38Schristos return false; 512950cc38Schristos } 522950cc38Schristos 532950cc38Schristos memcpy(buf, pz, name_len + 1); 542950cc38Schristos free(pz); 552950cc38Schristos } 562950cc38Schristos 572950cc38Schristos #elif defined(HAVE_REALPATH) 582950cc38Schristos { 592950cc38Schristos size_t name_len; 602950cc38Schristos char z[PATH_MAX+1]; 612950cc38Schristos 622950cc38Schristos if (realpath(buf, z) == NULL) 632950cc38Schristos return false; 642950cc38Schristos 652950cc38Schristos name_len = strlen(z); 662950cc38Schristos if (name_len >= b_sz) 672950cc38Schristos return false; 682950cc38Schristos 692950cc38Schristos memcpy(buf, z, name_len + 1); 702950cc38Schristos } 712950cc38Schristos #endif 722950cc38Schristos return true; 732950cc38Schristos } 742950cc38Schristos 75abb0f93cSkardel /*=export_func optionMakePath 76abb0f93cSkardel * private: 77abb0f93cSkardel * 78abb0f93cSkardel * what: translate and construct a path 792950cc38Schristos * arg: + char * + p_buf + The result buffer + 802950cc38Schristos * arg: + int + b_sz + The size of this buffer + 812950cc38Schristos * arg: + char const * + fname + The input name + 822950cc38Schristos * arg: + char const * + prg_path + The full path of the current program + 83abb0f93cSkardel * 842950cc38Schristos * ret-type: bool 852950cc38Schristos * ret-desc: true if the name was handled, otherwise false. 86abb0f93cSkardel * If the name does not start with ``$'', then it is handled 87abb0f93cSkardel * simply by copying the input name to the output buffer and 88abb0f93cSkardel * resolving the name with either 89abb0f93cSkardel * @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}. 90abb0f93cSkardel * 91abb0f93cSkardel * doc: 92abb0f93cSkardel * 93f003fb54Skardel * This routine will copy the @code{pzName} input name into the 94f003fb54Skardel * @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes. If the 95abb0f93cSkardel * first character of the input name is a @code{'$'} character, then there 96abb0f93cSkardel * is special handling: 97abb0f93cSkardel * @* 98abb0f93cSkardel * @code{$$} is replaced with the directory name of the @code{pzProgPath}, 99abb0f93cSkardel * searching @code{$PATH} if necessary. 100abb0f93cSkardel * @* 101abb0f93cSkardel * @code{$@} is replaced with the AutoGen package data installation directory 102abb0f93cSkardel * (aka @code{pkgdatadir}). 103abb0f93cSkardel * @* 104abb0f93cSkardel * @code{$NAME} is replaced by the contents of the @code{NAME} environment 105abb0f93cSkardel * variable. If not found, the search fails. 106abb0f93cSkardel * 107abb0f93cSkardel * Please note: both @code{$$} and @code{$NAME} must be at the start of the 108abb0f93cSkardel * @code{pzName} string and must either be the entire string or be followed 109abb0f93cSkardel * by the @code{'/'} (backslash on windows) character. 110abb0f93cSkardel * 1112950cc38Schristos * err: @code{false} is returned if: 112abb0f93cSkardel * @* 113abb0f93cSkardel * @bullet{} The input name exceeds @code{bufSize} bytes. 114abb0f93cSkardel * @* 115abb0f93cSkardel * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string 116abb0f93cSkardel * and the next character is not '/'. 117abb0f93cSkardel * @* 118abb0f93cSkardel * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@} 119abb0f93cSkardel * was specified. 120abb0f93cSkardel * @* 121abb0f93cSkardel * @bullet{} @code{NAME} is not a known environment variable 122abb0f93cSkardel * @* 123abb0f93cSkardel * @bullet{} @code{canonicalize_file_name} or @code{realpath} return 124abb0f93cSkardel * errors (cannot resolve the resulting path). 125abb0f93cSkardel =*/ 1262950cc38Schristos bool 1272950cc38Schristos optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path) 128abb0f93cSkardel { 1292950cc38Schristos { 1302950cc38Schristos size_t len = strlen(fname); 131abb0f93cSkardel 1322950cc38Schristos if (((size_t)b_sz <= len) || (len == 0)) 1332950cc38Schristos return false; 1342950cc38Schristos } 135abb0f93cSkardel 136abb0f93cSkardel /* 137abb0f93cSkardel * IF not an environment variable, just copy the data 138abb0f93cSkardel */ 1392950cc38Schristos if (*fname != '$') { 1402950cc38Schristos char const * src = fname; 1412950cc38Schristos char * dst = p_buf; 1422950cc38Schristos int ct = b_sz; 143abb0f93cSkardel 144abb0f93cSkardel for (;;) { 1452950cc38Schristos if ( (*(dst++) = *(src++)) == NUL) 146abb0f93cSkardel break; 147abb0f93cSkardel if (--ct <= 0) 1482950cc38Schristos return false; 149abb0f93cSkardel } 150abb0f93cSkardel } 151abb0f93cSkardel 152abb0f93cSkardel /* 153abb0f93cSkardel * IF the name starts with "$$", then it must be "$$" or 154abb0f93cSkardel * it must start with "$$/". In either event, replace the "$$" 155abb0f93cSkardel * with the path to the executable and append a "/" character. 156abb0f93cSkardel */ 1572950cc38Schristos else switch (fname[1]) { 158abb0f93cSkardel case NUL: 1592950cc38Schristos return false; 160abb0f93cSkardel 161abb0f93cSkardel case '$': 1622950cc38Schristos if (! add_prog_path(p_buf, b_sz, fname, prg_path)) 1632950cc38Schristos return false; 164abb0f93cSkardel break; 165abb0f93cSkardel 166abb0f93cSkardel case '@': 167f003fb54Skardel if (program_pkgdatadir[0] == NUL) 1682950cc38Schristos return false; 169abb0f93cSkardel 1702950cc38Schristos if (snprintf(p_buf, (size_t)b_sz, "%s%s", 1712950cc38Schristos program_pkgdatadir, fname + 2) >= b_sz) 1722950cc38Schristos return false; 173abb0f93cSkardel break; 174abb0f93cSkardel 175abb0f93cSkardel default: 1762950cc38Schristos if (! add_env_val(p_buf, b_sz, fname)) 1772950cc38Schristos return false; 178f003fb54Skardel } 179abb0f93cSkardel 1802950cc38Schristos return get_realpath(p_buf, b_sz); 1812950cc38Schristos } 1822950cc38Schristos 1832950cc38Schristos /** 1842950cc38Schristos * convert a leading "$$" into a path to the executable. 1852950cc38Schristos */ 1862950cc38Schristos static bool 1872950cc38Schristos add_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path) 188abb0f93cSkardel { 1892950cc38Schristos char const * path; 190f003fb54Skardel char const * pz; 191abb0f93cSkardel int skip = 2; 192*eabc0478Schristos size_t fname_len; 193*eabc0478Schristos size_t dir_len; //!< length of the directory portion of the path to the exe 194abb0f93cSkardel 1952950cc38Schristos switch (fname[2]) { 196abb0f93cSkardel case DIRCH: 197abb0f93cSkardel skip = 3; 198abb0f93cSkardel case NUL: 199abb0f93cSkardel break; 200abb0f93cSkardel default: 2012950cc38Schristos return false; 202abb0f93cSkardel } 203abb0f93cSkardel 204abb0f93cSkardel /* 205abb0f93cSkardel * See if the path is included in the program name. 206abb0f93cSkardel * If it is, we're done. Otherwise, we have to hunt 207abb0f93cSkardel * for the program using "pathfind". 208abb0f93cSkardel */ 2092950cc38Schristos if (strchr(prg_path, DIRCH) != NULL) 2102950cc38Schristos path = prg_path; 211abb0f93cSkardel else { 2125d681e99Schristos path = pathfind(getenv("PATH"), prg_path, "rx"); 213abb0f93cSkardel 2142950cc38Schristos if (path == NULL) 2152950cc38Schristos return false; 216abb0f93cSkardel } 217abb0f93cSkardel 2182950cc38Schristos pz = strrchr(path, DIRCH); 219abb0f93cSkardel 220abb0f93cSkardel /* 221abb0f93cSkardel * IF we cannot find a directory name separator, 222abb0f93cSkardel * THEN we do not have a path name to our executable file. 223abb0f93cSkardel */ 224abb0f93cSkardel if (pz == NULL) 2252950cc38Schristos return false; 226abb0f93cSkardel 2272950cc38Schristos fname += skip; 228*eabc0478Schristos fname_len = strlen(fname) + 1; // + NUL byte 229*eabc0478Schristos dir_len = (pz - path) + 1; // + dir sep character 230abb0f93cSkardel 231abb0f93cSkardel /* 232abb0f93cSkardel * Concatenate the file name to the end of the executable path. 233abb0f93cSkardel * The result may be either a file or a directory. 234abb0f93cSkardel */ 235*eabc0478Schristos if (dir_len + fname_len > (unsigned)b_sz) 2362950cc38Schristos return false; 237abb0f93cSkardel 238*eabc0478Schristos memcpy(buf, path, dir_len); 239*eabc0478Schristos memcpy(buf + dir_len, fname, fname_len); 240abb0f93cSkardel 241abb0f93cSkardel /* 2422950cc38Schristos * If the "path" path was gotten from "pathfind()", then it was 243abb0f93cSkardel * allocated and we need to deallocate it. 244abb0f93cSkardel */ 2452950cc38Schristos if (path != prg_path) 2462950cc38Schristos AGFREE(path); 2472950cc38Schristos return true; 248abb0f93cSkardel } 249abb0f93cSkardel 2502950cc38Schristos /** 2512950cc38Schristos * Add an environment variable value. 2522950cc38Schristos */ 2532950cc38Schristos static bool 2542950cc38Schristos add_env_val(char * buf, int buf_sz, char const * name) 255abb0f93cSkardel { 2562950cc38Schristos char * dir_part = buf; 257abb0f93cSkardel 258abb0f93cSkardel for (;;) { 2592950cc38Schristos int ch = (int)*++name; 260abb0f93cSkardel if (! IS_VALUE_NAME_CHAR(ch)) 261abb0f93cSkardel break; 2622950cc38Schristos *(dir_part++) = (char)ch; 263abb0f93cSkardel } 264abb0f93cSkardel 2652950cc38Schristos if (dir_part == buf) 2662950cc38Schristos return false; 267abb0f93cSkardel 2682950cc38Schristos *dir_part = NUL; 269abb0f93cSkardel 2702950cc38Schristos dir_part = getenv(buf); 271abb0f93cSkardel 272abb0f93cSkardel /* 273abb0f93cSkardel * Environment value not found -- skip the home list entry 274abb0f93cSkardel */ 2752950cc38Schristos if (dir_part == NULL) 2762950cc38Schristos return false; 277abb0f93cSkardel 278*eabc0478Schristos { 279*eabc0478Schristos size_t dir_len = strlen(dir_part); 280*eabc0478Schristos size_t nm_len = strlen(name) + 1; 281abb0f93cSkardel 282*eabc0478Schristos if (dir_len + nm_len >= (unsigned)buf_sz) 283*eabc0478Schristos return false; 284*eabc0478Schristos memcpy(buf, dir_part, dir_len); 285*eabc0478Schristos memcpy(buf + dir_len, name, nm_len); 286*eabc0478Schristos } 287*eabc0478Schristos 2882950cc38Schristos return true; 289abb0f93cSkardel } 290abb0f93cSkardel 2912950cc38Schristos /** 2922950cc38Schristos * Trim leading and trailing white space. 2932950cc38Schristos * If we are cooking the text and the text is quoted, then "cook" 2942950cc38Schristos * the string. To cook, the string must be quoted. 2952950cc38Schristos * 2962950cc38Schristos * @param[in,out] txt the input and output string 2972950cc38Schristos * @param[in] mode the handling mode (cooking method) 2982950cc38Schristos */ 299*eabc0478Schristos static void 3002950cc38Schristos munge_str(char * txt, tOptionLoadMode mode) 301abb0f93cSkardel { 302*eabc0478Schristos char * end; 303abb0f93cSkardel 304abb0f93cSkardel if (mode == OPTION_LOAD_KEEP) 305abb0f93cSkardel return; 306abb0f93cSkardel 3072950cc38Schristos if (IS_WHITESPACE_CHAR(*txt)) { 3082950cc38Schristos char * src = SPN_WHITESPACE_CHARS(txt+1); 3092950cc38Schristos size_t l = strlen(src) + 1; 3102950cc38Schristos memmove(txt, src, l); 311*eabc0478Schristos end = txt + l - 1; 312abb0f93cSkardel 3132950cc38Schristos } else 314*eabc0478Schristos end = txt + strlen(txt); 3152950cc38Schristos 316*eabc0478Schristos end = SPN_WHITESPACE_BACK(txt, end); 317*eabc0478Schristos *end = NUL; 318abb0f93cSkardel 319abb0f93cSkardel if (mode == OPTION_LOAD_UNCOOKED) 320abb0f93cSkardel return; 321abb0f93cSkardel 3222950cc38Schristos switch (*txt) { 323abb0f93cSkardel default: return; 324abb0f93cSkardel case '"': 325abb0f93cSkardel case '\'': break; 326abb0f93cSkardel } 327abb0f93cSkardel 328*eabc0478Schristos switch (end[-1]) { 329abb0f93cSkardel default: return; 330abb0f93cSkardel case '"': 331abb0f93cSkardel case '\'': break; 332abb0f93cSkardel } 333abb0f93cSkardel 3342950cc38Schristos (void)ao_string_cook(txt, NULL); 335abb0f93cSkardel } 336abb0f93cSkardel 337abb0f93cSkardel static char * 3382950cc38Schristos assemble_arg_val(char * txt, tOptionLoadMode mode) 339abb0f93cSkardel { 3402950cc38Schristos char * end = strpbrk(txt, ARG_BREAK_STR); 341abb0f93cSkardel int space_break; 342abb0f93cSkardel 343abb0f93cSkardel /* 344abb0f93cSkardel * Not having an argument to a configurable name is okay. 345abb0f93cSkardel */ 3462950cc38Schristos if (end == NULL) 3472950cc38Schristos return txt + strlen(txt); 348abb0f93cSkardel 349abb0f93cSkardel /* 350abb0f93cSkardel * If we are keeping all whitespace, then the modevalue starts with the 351abb0f93cSkardel * character that follows the end of the configurable name, regardless 352abb0f93cSkardel * of which character caused it. 353abb0f93cSkardel */ 354abb0f93cSkardel if (mode == OPTION_LOAD_KEEP) { 3552950cc38Schristos *(end++) = NUL; 3562950cc38Schristos return end; 357abb0f93cSkardel } 358abb0f93cSkardel 359abb0f93cSkardel /* 360abb0f93cSkardel * If the name ended on a white space character, remember that 361abb0f93cSkardel * because we'll have to skip over an immediately following ':' or '=' 362abb0f93cSkardel * (and the white space following *that*). 363abb0f93cSkardel */ 3642950cc38Schristos space_break = IS_WHITESPACE_CHAR(*end); 3652950cc38Schristos *(end++) = NUL; 366abb0f93cSkardel 3672950cc38Schristos end = SPN_WHITESPACE_CHARS(end); 3682950cc38Schristos if (space_break && ((*end == ':') || (*end == '='))) 3692950cc38Schristos end = SPN_WHITESPACE_CHARS(end+1); 3702950cc38Schristos 3712950cc38Schristos return end; 372abb0f93cSkardel } 373abb0f93cSkardel 3742950cc38Schristos static char * 3752950cc38Schristos trim_quotes(char * arg) 3762950cc38Schristos { 3772950cc38Schristos switch (*arg) { 3782950cc38Schristos case '"': 3792950cc38Schristos case '\'': 3802950cc38Schristos ao_string_cook(arg, NULL); 3812950cc38Schristos } 3822950cc38Schristos return arg; 3832950cc38Schristos } 384abb0f93cSkardel 3852950cc38Schristos /** 3862950cc38Schristos * See if the option is to be processed in the current scan direction 3872950cc38Schristos * (-1 or +1). 388abb0f93cSkardel */ 3892950cc38Schristos static bool 3902950cc38Schristos direction_ok(opt_state_mask_t f, int dir) 391abb0f93cSkardel { 3922950cc38Schristos if (dir == 0) 3932950cc38Schristos return true; 394abb0f93cSkardel 3952950cc38Schristos switch (f & (OPTST_IMM|OPTST_DISABLE_IMM)) { 396abb0f93cSkardel case 0: 397abb0f93cSkardel /* 398abb0f93cSkardel * The selected option has no immediate action. 399abb0f93cSkardel * THEREFORE, if the direction is PRESETTING 400abb0f93cSkardel * THEN we skip this option. 401abb0f93cSkardel */ 4022950cc38Schristos if (PRESETTING(dir)) 4032950cc38Schristos return false; 404abb0f93cSkardel break; 405abb0f93cSkardel 406abb0f93cSkardel case OPTST_IMM: 4072950cc38Schristos if (PRESETTING(dir)) { 408abb0f93cSkardel /* 409abb0f93cSkardel * We are in the presetting direction with an option we handle 410abb0f93cSkardel * immediately for enablement, but normally for disablement. 411abb0f93cSkardel * Therefore, skip if disabled. 412abb0f93cSkardel */ 4132950cc38Schristos if ((f & OPTST_DISABLED) == 0) 4142950cc38Schristos return false; 415abb0f93cSkardel } else { 416abb0f93cSkardel /* 417abb0f93cSkardel * We are in the processing direction with an option we handle 418abb0f93cSkardel * immediately for enablement, but normally for disablement. 419abb0f93cSkardel * Therefore, skip if NOT disabled. 420abb0f93cSkardel */ 4212950cc38Schristos if ((f & OPTST_DISABLED) != 0) 4222950cc38Schristos return false; 423abb0f93cSkardel } 424abb0f93cSkardel break; 425abb0f93cSkardel 426abb0f93cSkardel case OPTST_DISABLE_IMM: 4272950cc38Schristos if (PRESETTING(dir)) { 428abb0f93cSkardel /* 429abb0f93cSkardel * We are in the presetting direction with an option we handle 430*eabc0478Schristos * immediately for disablement, but normally for handling. 431abb0f93cSkardel * Therefore, skip if NOT disabled. 432abb0f93cSkardel */ 4332950cc38Schristos if ((f & OPTST_DISABLED) != 0) 4342950cc38Schristos return false; 435abb0f93cSkardel } else { 436abb0f93cSkardel /* 437abb0f93cSkardel * We are in the processing direction with an option we handle 438*eabc0478Schristos * immediately for disablement, but normally for handling. 439abb0f93cSkardel * Therefore, skip if disabled. 440abb0f93cSkardel */ 4412950cc38Schristos if ((f & OPTST_DISABLED) == 0) 4422950cc38Schristos return false; 443abb0f93cSkardel } 444abb0f93cSkardel break; 445abb0f93cSkardel 446abb0f93cSkardel case OPTST_IMM|OPTST_DISABLE_IMM: 447abb0f93cSkardel /* 448abb0f93cSkardel * The selected option is always for immediate action. 449abb0f93cSkardel * THEREFORE, if the direction is PROCESSING 450abb0f93cSkardel * THEN we skip this option. 451abb0f93cSkardel */ 4522950cc38Schristos if (PROCESSING(dir)) 4532950cc38Schristos return false; 454abb0f93cSkardel break; 455abb0f93cSkardel } 4562950cc38Schristos return true; 4572950cc38Schristos } 4582950cc38Schristos 4592950cc38Schristos /** 4602950cc38Schristos * Load an option from a block of text. The text must start with the 4612950cc38Schristos * configurable/option name and be followed by its associated value. 4622950cc38Schristos * That value may be processed in any of several ways. See "tOptionLoadMode" 4632950cc38Schristos * in autoopts.h. 4642950cc38Schristos * 4652950cc38Schristos * @param[in,out] opts program options descriptor 4662950cc38Schristos * @param[in,out] opt_state option processing state 4672950cc38Schristos * @param[in,out] line source line with long option name in it 4682950cc38Schristos * @param[in] direction current processing direction (preset or not) 4692950cc38Schristos * @param[in] load_mode option loading mode (OPTION_LOAD_*) 4702950cc38Schristos */ 471*eabc0478Schristos static void 4722950cc38Schristos load_opt_line(tOptions * opts, tOptState * opt_state, char * line, 4732950cc38Schristos tDirection direction, tOptionLoadMode load_mode ) 4742950cc38Schristos { 4752950cc38Schristos /* 4762950cc38Schristos * When parsing a stored line, we only look at the characters after 4772950cc38Schristos * a hyphen. Long names must always be at least two characters and 4782950cc38Schristos * short options are always exactly one character long. 4792950cc38Schristos */ 4802950cc38Schristos line = SPN_LOAD_LINE_SKIP_CHARS(line); 4812950cc38Schristos 4822950cc38Schristos { 4832950cc38Schristos char * arg = assemble_arg_val(line, load_mode); 4842950cc38Schristos 4852950cc38Schristos if (IS_OPTION_NAME_CHAR(line[1])) { 4862950cc38Schristos 4872950cc38Schristos if (! SUCCESSFUL(opt_find_long(opts, line, opt_state))) 4882950cc38Schristos return; 4892950cc38Schristos 4902950cc38Schristos } else if (! SUCCESSFUL(opt_find_short(opts, *line, opt_state))) 4912950cc38Schristos return; 4922950cc38Schristos 4932950cc38Schristos if ((! CALLED(direction)) && (opt_state->flags & OPTST_NO_INIT)) 4942950cc38Schristos return; 4952950cc38Schristos 4962950cc38Schristos opt_state->pzOptArg = trim_quotes(arg); 4972950cc38Schristos } 4982950cc38Schristos 4992950cc38Schristos if (! direction_ok(opt_state->flags, direction)) 5002950cc38Schristos return; 501abb0f93cSkardel 502abb0f93cSkardel /* 503abb0f93cSkardel * Fix up the args. 504abb0f93cSkardel */ 5052950cc38Schristos if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) { 5062950cc38Schristos if (*opt_state->pzOptArg != NUL) 507abb0f93cSkardel return; 5082950cc38Schristos opt_state->pzOptArg = NULL; 509abb0f93cSkardel 5102950cc38Schristos } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) { 5112950cc38Schristos if (*opt_state->pzOptArg == NUL) 5122950cc38Schristos opt_state->pzOptArg = NULL; 513abb0f93cSkardel else { 5142950cc38Schristos AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 5152950cc38Schristos opt_state->flags |= OPTST_ALLOC_ARG; 516abb0f93cSkardel } 517abb0f93cSkardel 518abb0f93cSkardel } else { 5192950cc38Schristos if (*opt_state->pzOptArg == NUL) 5202950cc38Schristos opt_state->pzOptArg = zNil; 521abb0f93cSkardel else { 5222950cc38Schristos AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 5232950cc38Schristos opt_state->flags |= OPTST_ALLOC_ARG; 524abb0f93cSkardel } 525abb0f93cSkardel } 526abb0f93cSkardel 527abb0f93cSkardel { 528abb0f93cSkardel tOptionLoadMode sv = option_load_mode; 529abb0f93cSkardel option_load_mode = load_mode; 5302950cc38Schristos handle_opt(opts, opt_state); 531abb0f93cSkardel option_load_mode = sv; 532abb0f93cSkardel } 533abb0f93cSkardel } 534abb0f93cSkardel 535abb0f93cSkardel /*=export_func optionLoadLine 536abb0f93cSkardel * 537abb0f93cSkardel * what: process a string for an option name and value 538abb0f93cSkardel * 5392950cc38Schristos * arg: tOptions *, opts, program options descriptor 5402950cc38Schristos * arg: char const *, line, NUL-terminated text 541abb0f93cSkardel * 542abb0f93cSkardel * doc: 543abb0f93cSkardel * 544abb0f93cSkardel * This is a client program callable routine for setting options from, for 545abb0f93cSkardel * example, the contents of a file that they read in. Only one option may 546abb0f93cSkardel * appear in the text. It will be treated as a normal (non-preset) option. 547abb0f93cSkardel * 548abb0f93cSkardel * When passed a pointer to the option struct and a string, it will find 549abb0f93cSkardel * the option named by the first token on the string and set the option 550abb0f93cSkardel * argument to the remainder of the string. The caller must NUL terminate 5512950cc38Schristos * the string. The caller need not skip over any introductory hyphens. 5522950cc38Schristos * Any embedded new lines will be included in the option 553abb0f93cSkardel * argument. If the input looks like one or more quoted strings, then the 554abb0f93cSkardel * input will be "cooked". The "cooking" is identical to the string 555abb0f93cSkardel * formation used in AutoGen definition files (@pxref{basic expression}), 556abb0f93cSkardel * except that you may not use backquotes. 557abb0f93cSkardel * 558abb0f93cSkardel * err: Invalid options are silently ignored. Invalid option arguments 559abb0f93cSkardel * will cause a warning to print, but the function should return. 560abb0f93cSkardel =*/ 561abb0f93cSkardel void 5622950cc38Schristos optionLoadLine(tOptions * opts, char const * line) 563abb0f93cSkardel { 564abb0f93cSkardel tOptState st = OPTSTATE_INITIALIZER(SET); 565abb0f93cSkardel char * pz; 5662950cc38Schristos proc_state_mask_t sv_flags = opts->fOptSet; 5672950cc38Schristos opts->fOptSet &= ~OPTPROC_ERRSTOP; 5682950cc38Schristos AGDUPSTR(pz, line, "opt line"); 5692950cc38Schristos load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED); 570abb0f93cSkardel AGFREE(pz); 5712950cc38Schristos opts->fOptSet = sv_flags; 572abb0f93cSkardel } 5732950cc38Schristos /** @} 5742950cc38Schristos * 575abb0f93cSkardel * Local Variables: 576abb0f93cSkardel * mode: C 577abb0f93cSkardel * c-file-style: "stroustrup" 578abb0f93cSkardel * indent-tabs-mode: nil 579abb0f93cSkardel * End: 580abb0f93cSkardel * end of autoopts/load.c */ 581