1 1.9 christos /* $NetBSD: load.c,v 1.10 2024/08/18 20:47:24 christos Exp $ */ 2 1.1 kardel 3 1.1 kardel 4 1.2 christos /** 5 1.2 christos * \file load.c 6 1.1 kardel * 7 1.1 kardel * This file contains the routines that deal with processing text strings 8 1.1 kardel * for options, either from a NUL-terminated string passed in or from an 9 1.1 kardel * rc/ini file. 10 1.1 kardel * 11 1.3 christos * @addtogroup autoopts 12 1.3 christos * @{ 13 1.3 christos */ 14 1.3 christos /* 15 1.1 kardel * This file is part of AutoOpts, a companion to AutoGen. 16 1.1 kardel * AutoOpts is free software. 17 1.10 christos * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 18 1.1 kardel * 19 1.1 kardel * AutoOpts is available under any one of two licenses. The license 20 1.1 kardel * in use must be one of these two and the choice is under the control 21 1.1 kardel * of the user of the license. 22 1.1 kardel * 23 1.1 kardel * The GNU Lesser General Public License, version 3 or later 24 1.1 kardel * See the files "COPYING.lgplv3" and "COPYING.gplv3" 25 1.1 kardel * 26 1.1 kardel * The Modified Berkeley Software Distribution License 27 1.1 kardel * See the file "COPYING.mbsd" 28 1.1 kardel * 29 1.3 christos * These files have the following sha256 sums: 30 1.1 kardel * 31 1.3 christos * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 32 1.3 christos * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 33 1.3 christos * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 34 1.1 kardel */ 35 1.1 kardel 36 1.3 christos static bool 37 1.3 christos get_realpath(char * buf, size_t b_sz) 38 1.3 christos { 39 1.3 christos #if defined(HAVE_CANONICALIZE_FILE_NAME) 40 1.3 christos { 41 1.3 christos size_t name_len; 42 1.3 christos 43 1.3 christos char * pz = canonicalize_file_name(buf); 44 1.3 christos if (pz == NULL) 45 1.3 christos return false; 46 1.3 christos 47 1.3 christos name_len = strlen(pz); 48 1.3 christos if (name_len >= (size_t)b_sz) { 49 1.3 christos free(pz); 50 1.3 christos return false; 51 1.3 christos } 52 1.3 christos 53 1.3 christos memcpy(buf, pz, name_len + 1); 54 1.3 christos free(pz); 55 1.3 christos } 56 1.3 christos 57 1.3 christos #elif defined(HAVE_REALPATH) 58 1.3 christos { 59 1.3 christos size_t name_len; 60 1.3 christos char z[PATH_MAX+1]; 61 1.3 christos 62 1.3 christos if (realpath(buf, z) == NULL) 63 1.3 christos return false; 64 1.3 christos 65 1.3 christos name_len = strlen(z); 66 1.3 christos if (name_len >= b_sz) 67 1.3 christos return false; 68 1.3 christos 69 1.3 christos memcpy(buf, z, name_len + 1); 70 1.3 christos } 71 1.3 christos #endif 72 1.3 christos return true; 73 1.3 christos } 74 1.3 christos 75 1.1 kardel /*=export_func optionMakePath 76 1.1 kardel * private: 77 1.1 kardel * 78 1.1 kardel * what: translate and construct a path 79 1.6 christos * arg: + char * + p_buf + The result buffer + 80 1.6 christos * arg: + int + b_sz + The size of this buffer + 81 1.6 christos * arg: + char const * + fname + The input name + 82 1.6 christos * arg: + char const * + prg_path + The full path of the current program + 83 1.1 kardel * 84 1.3 christos * ret-type: bool 85 1.3 christos * ret-desc: true if the name was handled, otherwise false. 86 1.1 kardel * If the name does not start with ``$'', then it is handled 87 1.1 kardel * simply by copying the input name to the output buffer and 88 1.1 kardel * resolving the name with either 89 1.1 kardel * @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}. 90 1.1 kardel * 91 1.1 kardel * doc: 92 1.1 kardel * 93 1.2 christos * This routine will copy the @code{pzName} input name into the 94 1.2 christos * @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes. If the 95 1.1 kardel * first character of the input name is a @code{'$'} character, then there 96 1.1 kardel * is special handling: 97 1.1 kardel * @* 98 1.1 kardel * @code{$$} is replaced with the directory name of the @code{pzProgPath}, 99 1.1 kardel * searching @code{$PATH} if necessary. 100 1.1 kardel * @* 101 1.1 kardel * @code{$@} is replaced with the AutoGen package data installation directory 102 1.1 kardel * (aka @code{pkgdatadir}). 103 1.1 kardel * @* 104 1.1 kardel * @code{$NAME} is replaced by the contents of the @code{NAME} environment 105 1.1 kardel * variable. If not found, the search fails. 106 1.1 kardel * 107 1.1 kardel * Please note: both @code{$$} and @code{$NAME} must be at the start of the 108 1.1 kardel * @code{pzName} string and must either be the entire string or be followed 109 1.1 kardel * by the @code{'/'} (backslash on windows) character. 110 1.1 kardel * 111 1.3 christos * err: @code{false} is returned if: 112 1.1 kardel * @* 113 1.1 kardel * @bullet{} The input name exceeds @code{bufSize} bytes. 114 1.1 kardel * @* 115 1.1 kardel * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string 116 1.1 kardel * and the next character is not '/'. 117 1.1 kardel * @* 118 1.1 kardel * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@} 119 1.1 kardel * was specified. 120 1.1 kardel * @* 121 1.1 kardel * @bullet{} @code{NAME} is not a known environment variable 122 1.1 kardel * @* 123 1.1 kardel * @bullet{} @code{canonicalize_file_name} or @code{realpath} return 124 1.1 kardel * errors (cannot resolve the resulting path). 125 1.1 kardel =*/ 126 1.3 christos bool 127 1.3 christos optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path) 128 1.1 kardel { 129 1.3 christos { 130 1.3 christos size_t len = strlen(fname); 131 1.1 kardel 132 1.3 christos if (((size_t)b_sz <= len) || (len == 0)) 133 1.3 christos return false; 134 1.3 christos } 135 1.1 kardel 136 1.1 kardel /* 137 1.1 kardel * IF not an environment variable, just copy the data 138 1.1 kardel */ 139 1.3 christos if (*fname != '$') { 140 1.3 christos char const * src = fname; 141 1.3 christos char * dst = p_buf; 142 1.3 christos int ct = b_sz; 143 1.1 kardel 144 1.1 kardel for (;;) { 145 1.3 christos if ( (*(dst++) = *(src++)) == NUL) 146 1.1 kardel break; 147 1.1 kardel if (--ct <= 0) 148 1.3 christos return false; 149 1.1 kardel } 150 1.1 kardel } 151 1.1 kardel 152 1.1 kardel /* 153 1.1 kardel * IF the name starts with "$$", then it must be "$$" or 154 1.1 kardel * it must start with "$$/". In either event, replace the "$$" 155 1.1 kardel * with the path to the executable and append a "/" character. 156 1.1 kardel */ 157 1.3 christos else switch (fname[1]) { 158 1.1 kardel case NUL: 159 1.3 christos return false; 160 1.1 kardel 161 1.1 kardel case '$': 162 1.3 christos if (! add_prog_path(p_buf, b_sz, fname, prg_path)) 163 1.3 christos return false; 164 1.1 kardel break; 165 1.1 kardel 166 1.1 kardel case '@': 167 1.2 christos if (program_pkgdatadir[0] == NUL) 168 1.3 christos return false; 169 1.1 kardel 170 1.3 christos if (snprintf(p_buf, (size_t)b_sz, "%s%s", 171 1.3 christos program_pkgdatadir, fname + 2) >= b_sz) 172 1.3 christos return false; 173 1.1 kardel break; 174 1.1 kardel 175 1.1 kardel default: 176 1.3 christos if (! add_env_val(p_buf, b_sz, fname)) 177 1.3 christos return false; 178 1.1 kardel } 179 1.1 kardel 180 1.3 christos return get_realpath(p_buf, b_sz); 181 1.1 kardel } 182 1.1 kardel 183 1.3 christos /** 184 1.3 christos * convert a leading "$$" into a path to the executable. 185 1.3 christos */ 186 1.3 christos static bool 187 1.3 christos add_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path) 188 1.1 kardel { 189 1.3 christos char const * path; 190 1.3 christos char const * pz; 191 1.1 kardel int skip = 2; 192 1.10 christos size_t fname_len; 193 1.10 christos size_t dir_len; //!< length of the directory portion of the path to the exe 194 1.1 kardel 195 1.3 christos switch (fname[2]) { 196 1.1 kardel case DIRCH: 197 1.1 kardel skip = 3; 198 1.1 kardel case NUL: 199 1.1 kardel break; 200 1.1 kardel default: 201 1.3 christos return false; 202 1.1 kardel } 203 1.1 kardel 204 1.1 kardel /* 205 1.1 kardel * See if the path is included in the program name. 206 1.1 kardel * If it is, we're done. Otherwise, we have to hunt 207 1.1 kardel * for the program using "pathfind". 208 1.1 kardel */ 209 1.3 christos if (strchr(prg_path, DIRCH) != NULL) 210 1.3 christos path = prg_path; 211 1.1 kardel else { 212 1.6 christos path = pathfind(getenv("PATH"), prg_path, "rx"); 213 1.1 kardel 214 1.3 christos if (path == NULL) 215 1.3 christos return false; 216 1.1 kardel } 217 1.1 kardel 218 1.3 christos pz = strrchr(path, DIRCH); 219 1.1 kardel 220 1.1 kardel /* 221 1.1 kardel * IF we cannot find a directory name separator, 222 1.1 kardel * THEN we do not have a path name to our executable file. 223 1.1 kardel */ 224 1.1 kardel if (pz == NULL) 225 1.3 christos return false; 226 1.1 kardel 227 1.10 christos fname += skip; 228 1.10 christos fname_len = strlen(fname) + 1; // + NUL byte 229 1.10 christos dir_len = (pz - path) + 1; // + dir sep character 230 1.1 kardel 231 1.1 kardel /* 232 1.1 kardel * Concatenate the file name to the end of the executable path. 233 1.1 kardel * The result may be either a file or a directory. 234 1.1 kardel */ 235 1.10 christos if (dir_len + fname_len > (unsigned)b_sz) 236 1.3 christos return false; 237 1.1 kardel 238 1.10 christos memcpy(buf, path, dir_len); 239 1.10 christos memcpy(buf + dir_len, fname, fname_len); 240 1.1 kardel 241 1.1 kardel /* 242 1.3 christos * If the "path" path was gotten from "pathfind()", then it was 243 1.1 kardel * allocated and we need to deallocate it. 244 1.1 kardel */ 245 1.3 christos if (path != prg_path) 246 1.3 christos AGFREE(path); 247 1.3 christos return true; 248 1.1 kardel } 249 1.1 kardel 250 1.3 christos /** 251 1.3 christos * Add an environment variable value. 252 1.3 christos */ 253 1.3 christos static bool 254 1.3 christos add_env_val(char * buf, int buf_sz, char const * name) 255 1.1 kardel { 256 1.3 christos char * dir_part = buf; 257 1.1 kardel 258 1.1 kardel for (;;) { 259 1.3 christos int ch = (int)*++name; 260 1.1 kardel if (! IS_VALUE_NAME_CHAR(ch)) 261 1.1 kardel break; 262 1.3 christos *(dir_part++) = (char)ch; 263 1.1 kardel } 264 1.1 kardel 265 1.3 christos if (dir_part == buf) 266 1.3 christos return false; 267 1.1 kardel 268 1.3 christos *dir_part = NUL; 269 1.1 kardel 270 1.3 christos dir_part = getenv(buf); 271 1.1 kardel 272 1.1 kardel /* 273 1.1 kardel * Environment value not found -- skip the home list entry 274 1.1 kardel */ 275 1.3 christos if (dir_part == NULL) 276 1.3 christos return false; 277 1.1 kardel 278 1.10 christos { 279 1.10 christos size_t dir_len = strlen(dir_part); 280 1.10 christos size_t nm_len = strlen(name) + 1; 281 1.10 christos 282 1.10 christos if (dir_len + nm_len >= (unsigned)buf_sz) 283 1.10 christos return false; 284 1.10 christos memcpy(buf, dir_part, dir_len); 285 1.10 christos memcpy(buf + dir_len, name, nm_len); 286 1.10 christos } 287 1.1 kardel 288 1.3 christos return true; 289 1.1 kardel } 290 1.1 kardel 291 1.3 christos /** 292 1.3 christos * Trim leading and trailing white space. 293 1.3 christos * If we are cooking the text and the text is quoted, then "cook" 294 1.3 christos * the string. To cook, the string must be quoted. 295 1.3 christos * 296 1.3 christos * @param[in,out] txt the input and output string 297 1.3 christos * @param[in] mode the handling mode (cooking method) 298 1.3 christos */ 299 1.10 christos static void 300 1.3 christos munge_str(char * txt, tOptionLoadMode mode) 301 1.1 kardel { 302 1.10 christos char * end; 303 1.1 kardel 304 1.1 kardel if (mode == OPTION_LOAD_KEEP) 305 1.1 kardel return; 306 1.1 kardel 307 1.3 christos if (IS_WHITESPACE_CHAR(*txt)) { 308 1.3 christos char * src = SPN_WHITESPACE_CHARS(txt+1); 309 1.3 christos size_t l = strlen(src) + 1; 310 1.3 christos memmove(txt, src, l); 311 1.10 christos end = txt + l - 1; 312 1.3 christos 313 1.1 kardel } else 314 1.10 christos end = txt + strlen(txt); 315 1.1 kardel 316 1.10 christos end = SPN_WHITESPACE_BACK(txt, end); 317 1.10 christos *end = NUL; 318 1.1 kardel 319 1.1 kardel if (mode == OPTION_LOAD_UNCOOKED) 320 1.1 kardel return; 321 1.1 kardel 322 1.3 christos switch (*txt) { 323 1.1 kardel default: return; 324 1.1 kardel case '"': 325 1.1 kardel case '\'': break; 326 1.1 kardel } 327 1.1 kardel 328 1.10 christos switch (end[-1]) { 329 1.1 kardel default: return; 330 1.1 kardel case '"': 331 1.1 kardel case '\'': break; 332 1.1 kardel } 333 1.1 kardel 334 1.3 christos (void)ao_string_cook(txt, NULL); 335 1.1 kardel } 336 1.1 kardel 337 1.3 christos static char * 338 1.3 christos assemble_arg_val(char * txt, tOptionLoadMode mode) 339 1.1 kardel { 340 1.3 christos char * end = strpbrk(txt, ARG_BREAK_STR); 341 1.3 christos int space_break; 342 1.1 kardel 343 1.1 kardel /* 344 1.1 kardel * Not having an argument to a configurable name is okay. 345 1.1 kardel */ 346 1.3 christos if (end == NULL) 347 1.3 christos return txt + strlen(txt); 348 1.1 kardel 349 1.1 kardel /* 350 1.1 kardel * If we are keeping all whitespace, then the modevalue starts with the 351 1.1 kardel * character that follows the end of the configurable name, regardless 352 1.1 kardel * of which character caused it. 353 1.1 kardel */ 354 1.1 kardel if (mode == OPTION_LOAD_KEEP) { 355 1.3 christos *(end++) = NUL; 356 1.3 christos return end; 357 1.1 kardel } 358 1.1 kardel 359 1.1 kardel /* 360 1.1 kardel * If the name ended on a white space character, remember that 361 1.1 kardel * because we'll have to skip over an immediately following ':' or '=' 362 1.1 kardel * (and the white space following *that*). 363 1.1 kardel */ 364 1.3 christos space_break = IS_WHITESPACE_CHAR(*end); 365 1.3 christos *(end++) = NUL; 366 1.1 kardel 367 1.3 christos end = SPN_WHITESPACE_CHARS(end); 368 1.3 christos if (space_break && ((*end == ':') || (*end == '='))) 369 1.3 christos end = SPN_WHITESPACE_CHARS(end+1); 370 1.3 christos 371 1.3 christos return end; 372 1.1 kardel } 373 1.1 kardel 374 1.3 christos static char * 375 1.3 christos trim_quotes(char * arg) 376 1.3 christos { 377 1.3 christos switch (*arg) { 378 1.3 christos case '"': 379 1.3 christos case '\'': 380 1.3 christos ao_string_cook(arg, NULL); 381 1.3 christos } 382 1.3 christos return arg; 383 1.3 christos } 384 1.1 kardel 385 1.3 christos /** 386 1.3 christos * See if the option is to be processed in the current scan direction 387 1.3 christos * (-1 or +1). 388 1.1 kardel */ 389 1.3 christos static bool 390 1.3 christos direction_ok(opt_state_mask_t f, int dir) 391 1.1 kardel { 392 1.3 christos if (dir == 0) 393 1.3 christos return true; 394 1.1 kardel 395 1.3 christos switch (f & (OPTST_IMM|OPTST_DISABLE_IMM)) { 396 1.1 kardel case 0: 397 1.1 kardel /* 398 1.1 kardel * The selected option has no immediate action. 399 1.1 kardel * THEREFORE, if the direction is PRESETTING 400 1.1 kardel * THEN we skip this option. 401 1.1 kardel */ 402 1.3 christos if (PRESETTING(dir)) 403 1.3 christos return false; 404 1.1 kardel break; 405 1.1 kardel 406 1.1 kardel case OPTST_IMM: 407 1.3 christos if (PRESETTING(dir)) { 408 1.1 kardel /* 409 1.1 kardel * We are in the presetting direction with an option we handle 410 1.1 kardel * immediately for enablement, but normally for disablement. 411 1.1 kardel * Therefore, skip if disabled. 412 1.1 kardel */ 413 1.3 christos if ((f & OPTST_DISABLED) == 0) 414 1.3 christos return false; 415 1.1 kardel } else { 416 1.1 kardel /* 417 1.1 kardel * We are in the processing direction with an option we handle 418 1.1 kardel * immediately for enablement, but normally for disablement. 419 1.1 kardel * Therefore, skip if NOT disabled. 420 1.1 kardel */ 421 1.3 christos if ((f & OPTST_DISABLED) != 0) 422 1.3 christos return false; 423 1.1 kardel } 424 1.1 kardel break; 425 1.1 kardel 426 1.1 kardel case OPTST_DISABLE_IMM: 427 1.3 christos if (PRESETTING(dir)) { 428 1.1 kardel /* 429 1.1 kardel * We are in the presetting direction with an option we handle 430 1.10 christos * immediately for disablement, but normally for handling. 431 1.1 kardel * Therefore, skip if NOT disabled. 432 1.1 kardel */ 433 1.3 christos if ((f & OPTST_DISABLED) != 0) 434 1.3 christos return false; 435 1.1 kardel } else { 436 1.1 kardel /* 437 1.1 kardel * We are in the processing direction with an option we handle 438 1.10 christos * immediately for disablement, but normally for handling. 439 1.1 kardel * Therefore, skip if disabled. 440 1.1 kardel */ 441 1.3 christos if ((f & OPTST_DISABLED) == 0) 442 1.3 christos return false; 443 1.1 kardel } 444 1.1 kardel break; 445 1.1 kardel 446 1.1 kardel case OPTST_IMM|OPTST_DISABLE_IMM: 447 1.1 kardel /* 448 1.1 kardel * The selected option is always for immediate action. 449 1.1 kardel * THEREFORE, if the direction is PROCESSING 450 1.1 kardel * THEN we skip this option. 451 1.1 kardel */ 452 1.3 christos if (PROCESSING(dir)) 453 1.3 christos return false; 454 1.3 christos break; 455 1.3 christos } 456 1.3 christos return true; 457 1.3 christos } 458 1.3 christos 459 1.3 christos /** 460 1.3 christos * Load an option from a block of text. The text must start with the 461 1.3 christos * configurable/option name and be followed by its associated value. 462 1.3 christos * That value may be processed in any of several ways. See "tOptionLoadMode" 463 1.3 christos * in autoopts.h. 464 1.3 christos * 465 1.3 christos * @param[in,out] opts program options descriptor 466 1.3 christos * @param[in,out] opt_state option processing state 467 1.3 christos * @param[in,out] line source line with long option name in it 468 1.3 christos * @param[in] direction current processing direction (preset or not) 469 1.3 christos * @param[in] load_mode option loading mode (OPTION_LOAD_*) 470 1.3 christos */ 471 1.10 christos static void 472 1.3 christos load_opt_line(tOptions * opts, tOptState * opt_state, char * line, 473 1.3 christos tDirection direction, tOptionLoadMode load_mode ) 474 1.3 christos { 475 1.3 christos /* 476 1.3 christos * When parsing a stored line, we only look at the characters after 477 1.3 christos * a hyphen. Long names must always be at least two characters and 478 1.3 christos * short options are always exactly one character long. 479 1.3 christos */ 480 1.3 christos line = SPN_LOAD_LINE_SKIP_CHARS(line); 481 1.3 christos 482 1.3 christos { 483 1.3 christos char * arg = assemble_arg_val(line, load_mode); 484 1.3 christos 485 1.3 christos if (IS_OPTION_NAME_CHAR(line[1])) { 486 1.3 christos 487 1.3 christos if (! SUCCESSFUL(opt_find_long(opts, line, opt_state))) 488 1.3 christos return; 489 1.3 christos 490 1.3 christos } else if (! SUCCESSFUL(opt_find_short(opts, *line, opt_state))) 491 1.3 christos return; 492 1.3 christos 493 1.3 christos if ((! CALLED(direction)) && (opt_state->flags & OPTST_NO_INIT)) 494 1.1 kardel return; 495 1.3 christos 496 1.3 christos opt_state->pzOptArg = trim_quotes(arg); 497 1.1 kardel } 498 1.1 kardel 499 1.3 christos if (! direction_ok(opt_state->flags, direction)) 500 1.3 christos return; 501 1.3 christos 502 1.1 kardel /* 503 1.1 kardel * Fix up the args. 504 1.1 kardel */ 505 1.3 christos if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) { 506 1.3 christos if (*opt_state->pzOptArg != NUL) 507 1.1 kardel return; 508 1.3 christos opt_state->pzOptArg = NULL; 509 1.1 kardel 510 1.3 christos } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) { 511 1.3 christos if (*opt_state->pzOptArg == NUL) 512 1.3 christos opt_state->pzOptArg = NULL; 513 1.1 kardel else { 514 1.3 christos AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 515 1.3 christos opt_state->flags |= OPTST_ALLOC_ARG; 516 1.1 kardel } 517 1.1 kardel 518 1.1 kardel } else { 519 1.3 christos if (*opt_state->pzOptArg == NUL) 520 1.3 christos opt_state->pzOptArg = zNil; 521 1.1 kardel else { 522 1.3 christos AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg"); 523 1.3 christos opt_state->flags |= OPTST_ALLOC_ARG; 524 1.1 kardel } 525 1.1 kardel } 526 1.1 kardel 527 1.1 kardel { 528 1.1 kardel tOptionLoadMode sv = option_load_mode; 529 1.1 kardel option_load_mode = load_mode; 530 1.3 christos handle_opt(opts, opt_state); 531 1.1 kardel option_load_mode = sv; 532 1.1 kardel } 533 1.1 kardel } 534 1.1 kardel 535 1.1 kardel /*=export_func optionLoadLine 536 1.1 kardel * 537 1.1 kardel * what: process a string for an option name and value 538 1.1 kardel * 539 1.6 christos * arg: tOptions *, opts, program options descriptor 540 1.6 christos * arg: char const *, line, NUL-terminated text 541 1.1 kardel * 542 1.1 kardel * doc: 543 1.1 kardel * 544 1.1 kardel * This is a client program callable routine for setting options from, for 545 1.1 kardel * example, the contents of a file that they read in. Only one option may 546 1.1 kardel * appear in the text. It will be treated as a normal (non-preset) option. 547 1.1 kardel * 548 1.1 kardel * When passed a pointer to the option struct and a string, it will find 549 1.1 kardel * the option named by the first token on the string and set the option 550 1.1 kardel * argument to the remainder of the string. The caller must NUL terminate 551 1.3 christos * the string. The caller need not skip over any introductory hyphens. 552 1.3 christos * Any embedded new lines will be included in the option 553 1.1 kardel * argument. If the input looks like one or more quoted strings, then the 554 1.1 kardel * input will be "cooked". The "cooking" is identical to the string 555 1.1 kardel * formation used in AutoGen definition files (@pxref{basic expression}), 556 1.1 kardel * except that you may not use backquotes. 557 1.1 kardel * 558 1.1 kardel * err: Invalid options are silently ignored. Invalid option arguments 559 1.1 kardel * will cause a warning to print, but the function should return. 560 1.1 kardel =*/ 561 1.1 kardel void 562 1.3 christos optionLoadLine(tOptions * opts, char const * line) 563 1.1 kardel { 564 1.1 kardel tOptState st = OPTSTATE_INITIALIZER(SET); 565 1.3 christos char * pz; 566 1.3 christos proc_state_mask_t sv_flags = opts->fOptSet; 567 1.3 christos opts->fOptSet &= ~OPTPROC_ERRSTOP; 568 1.3 christos AGDUPSTR(pz, line, "opt line"); 569 1.3 christos load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED); 570 1.2 christos AGFREE(pz); 571 1.3 christos opts->fOptSet = sv_flags; 572 1.1 kardel } 573 1.3 christos /** @} 574 1.3 christos * 575 1.1 kardel * Local Variables: 576 1.1 kardel * mode: C 577 1.1 kardel * c-file-style: "stroustrup" 578 1.1 kardel * indent-tabs-mode: nil 579 1.1 kardel * End: 580 1.1 kardel * end of autoopts/load.c */ 581