load.c revision 1.10 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