load.c revision 294569
1163953Srrs 2169382Srrs/** 3235828Stuexen * \file load.c 4235828Stuexen * 5163953Srrs * This file contains the routines that deal with processing text strings 6163953Srrs * for options, either from a NUL-terminated string passed in or from an 7163953Srrs * rc/ini file. 8163953Srrs * 9163953Srrs * @addtogroup autoopts 10228653Stuexen * @{ 11163953Srrs */ 12163953Srrs/* 13163953Srrs * This file is part of AutoOpts, a companion to AutoGen. 14228653Stuexen * AutoOpts is free software. 15163953Srrs * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 16163953Srrs * 17163953Srrs * AutoOpts is available under any one of two licenses. The license 18163953Srrs * in use must be one of these two and the choice is under the control 19163953Srrs * of the user of the license. 20163953Srrs * 21163953Srrs * The GNU Lesser General Public License, version 3 or later 22163953Srrs * See the files "COPYING.lgplv3" and "COPYING.gplv3" 23163953Srrs * 24163953Srrs * The Modified Berkeley Software Distribution License 25163953Srrs * See the file "COPYING.mbsd" 26163953Srrs * 27163953Srrs * These files have the following sha256 sums: 28163953Srrs * 29163953Srrs * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 30163953Srrs * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 31163953Srrs * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 32163953Srrs */ 33163953Srrs 34163953Srrs/* = = = START-STATIC-FORWARD = = = */ 35163953Srrsstatic bool 36163953Srrsget_realpath(char * buf, size_t b_sz); 37163953Srrs 38167598Srrsstatic bool 39163953Srrsadd_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path); 40163953Srrs 41163953Srrsstatic bool 42163953Srrsadd_env_val(char * buf, int buf_sz, char const * name); 43163953Srrs 44163953Srrsstatic char * 45163953Srrsassemble_arg_val(char * txt, tOptionLoadMode mode); 46163953Srrs 47163953Srrsstatic char * 48163953Srrstrim_quotes(char * arg); 49163953Srrs 50163953Srrsstatic bool 51163953Srrsdirection_ok(opt_state_mask_t f, int dir); 52163953Srrs/* = = = END-STATIC-FORWARD = = = */ 53163953Srrs 54163953Srrsstatic bool 55163953Srrsget_realpath(char * buf, size_t b_sz) 56163953Srrs{ 57163953Srrs#if defined(HAVE_CANONICALIZE_FILE_NAME) 58163953Srrs { 59170806Srrs size_t name_len; 60163953Srrs 61163953Srrs char * pz = canonicalize_file_name(buf); 62179783Srrs if (pz == NULL) 63163953Srrs return false; 64163953Srrs 65163953Srrs name_len = strlen(pz); 66170806Srrs if (name_len >= (size_t)b_sz) { 67163953Srrs free(pz); 68163953Srrs return false; 69179783Srrs } 70163953Srrs 71163953Srrs memcpy(buf, pz, name_len + 1); 72163953Srrs free(pz); 73163953Srrs } 74163953Srrs 75163953Srrs#elif defined(HAVE_REALPATH) 76163953Srrs { 77163953Srrs size_t name_len; 78163953Srrs char z[PATH_MAX+1]; 79163953Srrs 80163953Srrs if (realpath(buf, z) == NULL) 81163953Srrs return false; 82163953Srrs 83163953Srrs name_len = strlen(z); 84179783Srrs if (name_len >= b_sz) 85163953Srrs return false; 86163953Srrs 87163953Srrs memcpy(buf, z, name_len + 1); 88163953Srrs } 89163953Srrs#endif 90163953Srrs return true; 91163953Srrs} 92163953Srrs 93163953Srrs/*=export_func optionMakePath 94210599Srrs * private: 95210599Srrs * 96210599Srrs * what: translate and construct a path 97210599Srrs * arg: + char * + p_buf + The result buffer + 98163953Srrs * arg: + int + b_sz + The size of this buffer + 99163953Srrs * arg: + char const * + fname + The input name + 100163953Srrs * arg: + char const * + prg_path + The full path of the current program + 101163953Srrs * 102163953Srrs * ret-type: bool 103163953Srrs * ret-desc: true if the name was handled, otherwise false. 104171990Srrs * If the name does not start with ``$'', then it is handled 105179783Srrs * simply by copying the input name to the output buffer and 106179783Srrs * resolving the name with either 107179783Srrs * @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}. 108179783Srrs * 109179783Srrs * doc: 110179783Srrs * 111163953Srrs * This routine will copy the @code{pzName} input name into the 112179783Srrs * @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes. If the 113163953Srrs * first character of the input name is a @code{'$'} character, then there 114163953Srrs * is special handling: 115163953Srrs * @* 116163953Srrs * @code{$$} is replaced with the directory name of the @code{pzProgPath}, 117163953Srrs * searching @code{$PATH} if necessary. 118163953Srrs * @* 119163953Srrs * @code{$@} is replaced with the AutoGen package data installation directory 120163953Srrs * (aka @code{pkgdatadir}). 121163953Srrs * @* 122163953Srrs * @code{$NAME} is replaced by the contents of the @code{NAME} environment 123163953Srrs * variable. If not found, the search fails. 124163953Srrs * 125163953Srrs * Please note: both @code{$$} and @code{$NAME} must be at the start of the 126163953Srrs * @code{pzName} string and must either be the entire string or be followed 127163953Srrs * by the @code{'/'} (backslash on windows) character. 128163953Srrs * 129163953Srrs * err: @code{false} is returned if: 130163953Srrs * @* 131163953Srrs * @bullet{} The input name exceeds @code{bufSize} bytes. 132163953Srrs * @* 133163953Srrs * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string 134163953Srrs * and the next character is not '/'. 135163953Srrs * @* 136163953Srrs * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@} 137163953Srrs * was specified. 138228653Stuexen * @* 139163953Srrs * @bullet{} @code{NAME} is not a known environment variable 140163953Srrs * @* 141163953Srrs * @bullet{} @code{canonicalize_file_name} or @code{realpath} return 142163953Srrs * errors (cannot resolve the resulting path). 143163953Srrs=*/ 144163953Srrsbool 145163953SrrsoptionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path) 146163953Srrs{ 147165647Srrs { 148163953Srrs size_t len = strlen(fname); 149169352Srrs 150163953Srrs if (((size_t)b_sz <= len) || (len == 0)) 151163953Srrs return false; 152163953Srrs } 153163953Srrs 154168943Srrs /* 155164085Srrs * IF not an environment variable, just copy the data 156163953Srrs */ 157163953Srrs if (*fname != '$') { 158163953Srrs char const * src = fname; 159163953Srrs char * dst = p_buf; 160163953Srrs int ct = b_sz; 161163953Srrs 162163953Srrs for (;;) { 163163953Srrs if ( (*(dst++) = *(src++)) == NUL) 164163953Srrs break; 165163953Srrs if (--ct <= 0) 166163953Srrs return false; 167163953Srrs } 168163953Srrs } 169163953Srrs 170163953Srrs /* 171163953Srrs * IF the name starts with "$$", then it must be "$$" or 172163953Srrs * it must start with "$$/". In either event, replace the "$$" 173163953Srrs * with the path to the executable and append a "/" character. 174163953Srrs */ 175163953Srrs else switch (fname[1]) { 176163953Srrs case NUL: 177163953Srrs return false; 178163953Srrs 179163953Srrs case '$': 180163953Srrs if (! add_prog_path(p_buf, b_sz, fname, prg_path)) 181163953Srrs return false; 182163953Srrs break; 183163953Srrs 184169352Srrs case '@': 185163953Srrs if (program_pkgdatadir[0] == NUL) 186163953Srrs return false; 187163953Srrs 188163953Srrs if (snprintf(p_buf, (size_t)b_sz, "%s%s", 189163953Srrs program_pkgdatadir, fname + 2) >= b_sz) 190163953Srrs return false; 191165647Srrs break; 192163953Srrs 193163953Srrs default: 194168943Srrs if (! add_env_val(p_buf, b_sz, fname)) 195164085Srrs return false; 196163953Srrs } 197163953Srrs 198163953Srrs return get_realpath(p_buf, b_sz); 199163953Srrs} 200163953Srrs 201163953Srrs/** 202223132Stuexen * convert a leading "$$" into a path to the executable. 203163953Srrs */ 204223132Stuexenstatic bool 205163953Srrsadd_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path) 206223132Stuexen{ 207223132Stuexen char const * path; 208163953Srrs char const * pz; 209163953Srrs int skip = 2; 210163953Srrs 211223132Stuexen switch (fname[2]) { 212223132Stuexen case DIRCH: 213163953Srrs skip = 3; 214223132Stuexen case NUL: 215223132Stuexen break; 216223132Stuexen default: 217223132Stuexen return false; 218163953Srrs } 219163953Srrs 220223132Stuexen /* 221223132Stuexen * See if the path is included in the program name. 222223132Stuexen * If it is, we're done. Otherwise, we have to hunt 223223132Stuexen * for the program using "pathfind". 224223132Stuexen */ 225223132Stuexen if (strchr(prg_path, DIRCH) != NULL) 226294178Stuexen path = prg_path; 227223132Stuexen else { 228294181Stuexen path = pathfind(getenv("PATH"), prg_path, "rx"); 229163953Srrs 230223132Stuexen if (path == NULL) 231163953Srrs return false; 232223132Stuexen } 233223132Stuexen 234223132Stuexen pz = strrchr(path, DIRCH); 235223132Stuexen 236223132Stuexen /* 237223132Stuexen * IF we cannot find a directory name separator, 238223132Stuexen * THEN we do not have a path name to our executable file. 239223132Stuexen */ 240223132Stuexen if (pz == NULL) 241223132Stuexen return false; 242223132Stuexen 243163953Srrs fname += skip; 244243882Sglebius 245163953Srrs /* 246163953Srrs * Concatenate the file name to the end of the executable path. 247163953Srrs * The result may be either a file or a directory. 248163953Srrs */ 249223132Stuexen if ((unsigned)(pz - path) + 1 + strlen(fname) >= (unsigned)b_sz) 250223132Stuexen return false; 251223132Stuexen 252163953Srrs memcpy(buf, path, (size_t)((pz - path)+1)); 253268432Sdelphij strcpy(buf + (pz - path) + 1, fname); 254268432Sdelphij 255268432Sdelphij /* 256268432Sdelphij * If the "path" path was gotten from "pathfind()", then it was 257268432Sdelphij * allocated and we need to deallocate it. 258223132Stuexen */ 259223132Stuexen if (path != prg_path) 260223132Stuexen AGFREE(path); 261223132Stuexen return true; 262223132Stuexen} 263223132Stuexen 264223132Stuexen/** 265223132Stuexen * Add an environment variable value. 266223132Stuexen */ 267223132Stuexenstatic bool 268223132Stuexenadd_env_val(char * buf, int buf_sz, char const * name) 269223132Stuexen{ 270223132Stuexen char * dir_part = buf; 271223132Stuexen 272223132Stuexen for (;;) { 273163953Srrs int ch = (int)*++name; 274223132Stuexen if (! IS_VALUE_NAME_CHAR(ch)) 275223132Stuexen break; 276223132Stuexen *(dir_part++) = (char)ch; 277223132Stuexen } 278223132Stuexen 279294178Stuexen if (dir_part == buf) 280223132Stuexen return false; 281294178Stuexen 282223132Stuexen *dir_part = NUL; 283223132Stuexen 284294178Stuexen dir_part = getenv(buf); 285223132Stuexen 286223132Stuexen /* 287294178Stuexen * Environment value not found -- skip the home list entry 288223132Stuexen */ 289223132Stuexen if (dir_part == NULL) 290294178Stuexen return false; 291294178Stuexen 292294178Stuexen if (strlen(dir_part) + 1 + strlen(name) >= (unsigned)buf_sz) 293223132Stuexen return false; 294223132Stuexen 295223132Stuexen sprintf(buf, "%s%s", dir_part, name); 296223132Stuexen return true; 297223132Stuexen} 298223132Stuexen 299223132Stuexen/** 300223132Stuexen * Trim leading and trailing white space. 301223132Stuexen * If we are cooking the text and the text is quoted, then "cook" 302223132Stuexen * the string. To cook, the string must be quoted. 303223132Stuexen * 304223132Stuexen * @param[in,out] txt the input and output string 305223132Stuexen * @param[in] mode the handling mode (cooking method) 306223132Stuexen */ 307223132StuexenLOCAL void 308223132Stuexenmunge_str(char * txt, tOptionLoadMode mode) 309223132Stuexen{ 310223132Stuexen char * pzE; 311163953Srrs 312163953Srrs if (mode == OPTION_LOAD_KEEP) 313163953Srrs return; 314165647Srrs 315205627Srrs if (IS_WHITESPACE_CHAR(*txt)) { 316205627Srrs char * src = SPN_WHITESPACE_CHARS(txt+1); 317205627Srrs size_t l = strlen(src) + 1; 318208902Srrs memmove(txt, src, l); 319205627Srrs pzE = txt + l - 1; 320169352Srrs 321205627Srrs } else 322205627Srrs pzE = txt + strlen(txt); 323205627Srrs 324208902Srrs pzE = SPN_WHITESPACE_BACK(txt, pzE); 325216825Stuexen *pzE = NUL; 326208902Srrs 327208902Srrs if (mode == OPTION_LOAD_UNCOOKED) 328208902Srrs return; 329208902Srrs 330208902Srrs switch (*txt) { 331208902Srrs default: return; 332205627Srrs case '"': 333205627Srrs case '\'': break; 334234995Stuexen } 335205627Srrs 336206137Stuexen switch (pzE[-1]) { 337205627Srrs default: return; 338206137Stuexen case '"': 339205627Srrs case '\'': break; 340205627Srrs } 341205627Srrs 342216825Stuexen (void)ao_string_cook(txt, NULL); 343205627Srrs} 344205627Srrs 345205627Srrsstatic char * 346205627Srrsassemble_arg_val(char * txt, tOptionLoadMode mode) 347216825Stuexen{ 348205627Srrs char * end = strpbrk(txt, ARG_BREAK_STR); 349205627Srrs int space_break; 350205627Srrs 351205627Srrs /* 352205627Srrs * Not having an argument to a configurable name is okay. 353205627Srrs */ 354205627Srrs if (end == NULL) 355205627Srrs return txt + strlen(txt); 356205627Srrs 357205627Srrs /* 358205627Srrs * If we are keeping all whitespace, then the modevalue starts with the 359205627Srrs * character that follows the end of the configurable name, regardless 360205627Srrs * of which character caused it. 361205627Srrs */ 362163953Srrs if (mode == OPTION_LOAD_KEEP) { 363163953Srrs *(end++) = NUL; 364163953Srrs return end; 365163953Srrs } 366163953Srrs 367163953Srrs /* 368163953Srrs * If the name ended on a white space character, remember that 369163953Srrs * because we'll have to skip over an immediately following ':' or '=' 370216822Stuexen * (and the white space following *that*). 371163953Srrs */ 372163953Srrs space_break = IS_WHITESPACE_CHAR(*end); 373163953Srrs *(end++) = NUL; 374163953Srrs 375216822Stuexen end = SPN_WHITESPACE_CHARS(end); 376185694Srrs if (space_break && ((*end == ':') || (*end == '='))) 377169420Srrs end = SPN_WHITESPACE_CHARS(end+1); 378169420Srrs 379169420Srrs return end; 380163953Srrs} 381169420Srrs 382172091Srrsstatic char * 383169420Srrstrim_quotes(char * arg) 384172091Srrs{ 385172091Srrs switch (*arg) { 386163953Srrs case '"': 387216822Stuexen case '\'': 388163953Srrs ao_string_cook(arg, NULL); 389163953Srrs } 390163953Srrs return arg; 391163953Srrs} 392163953Srrs 393163953Srrs/** 394163953Srrs * See if the option is to be processed in the current scan direction 395163953Srrs * (-1 or +1). 396163953Srrs */ 397163953Srrsstatic bool 398163953Srrsdirection_ok(opt_state_mask_t f, int dir) 399163953Srrs{ 400221627Stuexen if (dir == 0) 401169655Srrs return true; 402163953Srrs 403163953Srrs switch (f & (OPTST_IMM|OPTST_DISABLE_IMM)) { 404163953Srrs case 0: 405163953Srrs /* 406216822Stuexen * The selected option has no immediate action. 407163953Srrs * THEREFORE, if the direction is PRESETTING 408163953Srrs * THEN we skip this option. 409163953Srrs */ 410163953Srrs if (PRESETTING(dir)) 411163953Srrs return false; 412163953Srrs break; 413163953Srrs 414163953Srrs case OPTST_IMM: 415163953Srrs if (PRESETTING(dir)) { 416163953Srrs /* 417163953Srrs * We are in the presetting direction with an option we handle 418163953Srrs * immediately for enablement, but normally for disablement. 419163953Srrs * Therefore, skip if disabled. 420163953Srrs */ 421163953Srrs if ((f & OPTST_DISABLED) == 0) 422163953Srrs return false; 423163953Srrs } else { 424163953Srrs /* 425163953Srrs * We are in the processing direction with an option we handle 426163953Srrs * immediately for enablement, but normally for disablement. 427163953Srrs * Therefore, skip if NOT disabled. 428163953Srrs */ 429163953Srrs if ((f & OPTST_DISABLED) != 0) 430163953Srrs return false; 431163953Srrs } 432163953Srrs break; 433163953Srrs 434206137Stuexen case OPTST_DISABLE_IMM: 435163953Srrs if (PRESETTING(dir)) { 436195918Srrs /* 437195918Srrs * We are in the presetting direction with an option we handle 438163953Srrs * immediately for disablement, but normally for disablement. 439163953Srrs * Therefore, skip if NOT disabled. 440163953Srrs */ 441163953Srrs if ((f & OPTST_DISABLED) != 0) 442163953Srrs return false; 443163953Srrs } else { 444206137Stuexen /* 445163953Srrs * We are in the processing direction with an option we handle 446163953Srrs * immediately for disablement, but normally for disablement. 447163953Srrs * Therefore, skip if disabled. 448163953Srrs */ 449163953Srrs if ((f & OPTST_DISABLED) == 0) 450163953Srrs return false; 451163953Srrs } 452163953Srrs break; 453163953Srrs 454163953Srrs case OPTST_IMM|OPTST_DISABLE_IMM: 455172091Srrs /* 456172091Srrs * The selected option is always for immediate action. 457172091Srrs * THEREFORE, if the direction is PROCESSING 458182367Srrs * THEN we skip this option. 459172091Srrs */ 460172091Srrs if (PROCESSING(dir)) 461172091Srrs return false; 462172091Srrs break; 463172091Srrs } 464182367Srrs return true; 465182367Srrs} 466182367Srrs 467182367Srrs/** 468182367Srrs * Load an option from a block of text. The text must start with the 469182367Srrs * configurable/option name and be followed by its associated value. 470182367Srrs * That value may be processed in any of several ways. See "tOptionLoadMode" 471182367Srrs * in autoopts.h. 472182367Srrs * 473163953Srrs * @param[in,out] opts program options descriptor 474163953Srrs * @param[in,out] opt_state option processing state 475163953Srrs * @param[in,out] line source line with long option name in it 476163953Srrs * @param[in] direction current processing direction (preset or not) 477163953Srrs * @param[in] load_mode option loading mode (OPTION_LOAD_*) 478163953Srrs */ 479163953SrrsLOCAL void 480163953Srrsload_opt_line(tOptions * opts, tOptState * opt_state, char * line, 481163953Srrs tDirection direction, tOptionLoadMode load_mode ) 482163953Srrs{ 483163953Srrs /* 484163953Srrs * When parsing a stored line, we only look at the characters after 485163953Srrs * a hyphen. Long names must always be at least two characters and 486163953Srrs * short options are always exactly one character long. 487163953Srrs */ 488163953Srrs line = SPN_LOAD_LINE_SKIP_CHARS(line); 489163953Srrs 490163953Srrs { 491163953Srrs char * arg = assemble_arg_val(line, load_mode); 492163953Srrs 493163953Srrs if (IS_OPTION_NAME_CHAR(line[1])) { 494163953Srrs 495163953Srrs if (! SUCCESSFUL(opt_find_long(opts, line, opt_state))) 496163953Srrs return; 497163953Srrs 498163953Srrs } else if (! SUCCESSFUL(opt_find_short(opts, *line, opt_state))) 499163953Srrs return; 500163953Srrs 501163953Srrs if ((! CALLED(direction)) && (opt_state->flags & OPTST_NO_INIT)) 502163953Srrs return; 503163953Srrs 504221627Stuexen opt_state->pzOptArg = trim_quotes(arg); 505163953Srrs } 506163953Srrs 507163953Srrs if (! direction_ok(opt_state->flags, direction)) 508163953Srrs return; 509163953Srrs 510163953Srrs /* 511163953Srrs * Fix up the args. 512163953Srrs */ 513163953Srrs if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) { 514163953Srrs if (*opt_state->pzOptArg != NUL) 515216822Stuexen return; 516216822Stuexen opt_state->pzOptArg = NULL; 517216822Stuexen 518216822Stuexen } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) { 519216822Stuexen if (*opt_state->pzOptArg == NUL) 520216822Stuexen opt_state->pzOptArg = NULL; 521216822Stuexen else { 522216822Stuexen AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 523216822Stuexen opt_state->flags |= OPTST_ALLOC_ARG; 524216822Stuexen } 525216822Stuexen 526216822Stuexen } else { 527216822Stuexen if (*opt_state->pzOptArg == NUL) 528216822Stuexen opt_state->pzOptArg = zNil; 529163953Srrs else { 530216822Stuexen AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 531163953Srrs opt_state->flags |= OPTST_ALLOC_ARG; 532165647Srrs } 533163953Srrs } 534216822Stuexen 535163953Srrs { 536163953Srrs tOptionLoadMode sv = option_load_mode; 537163953Srrs option_load_mode = load_mode; 538163953Srrs handle_opt(opts, opt_state); 539163953Srrs option_load_mode = sv; 540163953Srrs } 541163953Srrs} 542163953Srrs 543163953Srrs/*=export_func optionLoadLine 544163953Srrs * 545163953Srrs * what: process a string for an option name and value 546163953Srrs * 547163953Srrs * arg: tOptions *, opts, program options descriptor 548163953Srrs * arg: char const *, line, NUL-terminated text 549163953Srrs * 550163953Srrs * doc: 551163953Srrs * 552163953Srrs * This is a client program callable routine for setting options from, for 553163953Srrs * example, the contents of a file that they read in. Only one option may 554163953Srrs * appear in the text. It will be treated as a normal (non-preset) option. 555163953Srrs * 556163953Srrs * When passed a pointer to the option struct and a string, it will find 557163953Srrs * the option named by the first token on the string and set the option 558163953Srrs * argument to the remainder of the string. The caller must NUL terminate 559163953Srrs * the string. The caller need not skip over any introductory hyphens. 560163953Srrs * Any embedded new lines will be included in the option 561163953Srrs * argument. If the input looks like one or more quoted strings, then the 562163953Srrs * input will be "cooked". The "cooking" is identical to the string 563163953Srrs * formation used in AutoGen definition files (@pxref{basic expression}), 564163953Srrs * except that you may not use backquotes. 565163953Srrs * 566163953Srrs * err: Invalid options are silently ignored. Invalid option arguments 567163953Srrs * will cause a warning to print, but the function should return. 568163953Srrs=*/ 569267723Stuexenvoid 570267723StuexenoptionLoadLine(tOptions * opts, char const * line) 571163953Srrs{ 572163953Srrs tOptState st = OPTSTATE_INITIALIZER(SET); 573163953Srrs char * pz; 574163953Srrs proc_state_mask_t sv_flags = opts->fOptSet; 575163953Srrs opts->fOptSet &= ~OPTPROC_ERRSTOP; 576163953Srrs AGDUPSTR(pz, line, "opt line"); 577179783Srrs load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED); 578170744Srrs AGFREE(pz); 579170744Srrs opts->fOptSet = sv_flags; 580169420Srrs} 581294143Stuexen/** @} 582294143Stuexen * 583294143Stuexen * Local Variables: 584294143Stuexen * mode: C 585216825Stuexen * c-file-style: "stroustrup" 586163953Srrs * indent-tabs-mode: nil 587267723Stuexen * End: 588169420Srrs * end of autoopts/load.c */ 589178198Srrs