1ea906c41SOllivier Robert
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert * \file load.c
4ea906c41SOllivier Robert *
5ea906c41SOllivier Robert * This file contains the routines that deal with processing text strings
6ea906c41SOllivier Robert * for options, either from a NUL-terminated string passed in or from an
7ea906c41SOllivier Robert * rc/ini file.
82b15cb3dSCy Schubert *
92b15cb3dSCy Schubert * @addtogroup autoopts
102b15cb3dSCy Schubert * @{
11ea906c41SOllivier Robert */
12ea906c41SOllivier Robert /*
132b15cb3dSCy Schubert * This file is part of AutoOpts, a companion to AutoGen.
142b15cb3dSCy Schubert * AutoOpts is free software.
15*a466cc55SCy Schubert * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
16ea906c41SOllivier Robert *
172b15cb3dSCy Schubert * AutoOpts is available under any one of two licenses. The license
182b15cb3dSCy Schubert * in use must be one of these two and the choice is under the control
192b15cb3dSCy Schubert * of the user of the license.
20ea906c41SOllivier Robert *
212b15cb3dSCy Schubert * The GNU Lesser General Public License, version 3 or later
222b15cb3dSCy Schubert * See the files "COPYING.lgplv3" and "COPYING.gplv3"
23ea906c41SOllivier Robert *
242b15cb3dSCy Schubert * The Modified Berkeley Software Distribution License
252b15cb3dSCy Schubert * See the file "COPYING.mbsd"
26ea906c41SOllivier Robert *
272b15cb3dSCy Schubert * These files have the following sha256 sums:
28ea906c41SOllivier Robert *
292b15cb3dSCy Schubert * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
302b15cb3dSCy Schubert * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
312b15cb3dSCy Schubert * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
32ea906c41SOllivier Robert */
33ea906c41SOllivier Robert
342b15cb3dSCy Schubert static bool
get_realpath(char * buf,size_t b_sz)352b15cb3dSCy Schubert get_realpath(char * buf, size_t b_sz)
362b15cb3dSCy Schubert {
372b15cb3dSCy Schubert #if defined(HAVE_CANONICALIZE_FILE_NAME)
382b15cb3dSCy Schubert {
392b15cb3dSCy Schubert size_t name_len;
402b15cb3dSCy Schubert
412b15cb3dSCy Schubert char * pz = canonicalize_file_name(buf);
422b15cb3dSCy Schubert if (pz == NULL)
432b15cb3dSCy Schubert return false;
442b15cb3dSCy Schubert
452b15cb3dSCy Schubert name_len = strlen(pz);
462b15cb3dSCy Schubert if (name_len >= (size_t)b_sz) {
472b15cb3dSCy Schubert free(pz);
482b15cb3dSCy Schubert return false;
492b15cb3dSCy Schubert }
502b15cb3dSCy Schubert
512b15cb3dSCy Schubert memcpy(buf, pz, name_len + 1);
522b15cb3dSCy Schubert free(pz);
532b15cb3dSCy Schubert }
542b15cb3dSCy Schubert
552b15cb3dSCy Schubert #elif defined(HAVE_REALPATH)
562b15cb3dSCy Schubert {
572b15cb3dSCy Schubert size_t name_len;
582b15cb3dSCy Schubert char z[PATH_MAX+1];
592b15cb3dSCy Schubert
602b15cb3dSCy Schubert if (realpath(buf, z) == NULL)
612b15cb3dSCy Schubert return false;
622b15cb3dSCy Schubert
632b15cb3dSCy Schubert name_len = strlen(z);
642b15cb3dSCy Schubert if (name_len >= b_sz)
652b15cb3dSCy Schubert return false;
662b15cb3dSCy Schubert
672b15cb3dSCy Schubert memcpy(buf, z, name_len + 1);
682b15cb3dSCy Schubert }
692b15cb3dSCy Schubert #endif
702b15cb3dSCy Schubert return true;
712b15cb3dSCy Schubert }
722b15cb3dSCy Schubert
73ea906c41SOllivier Robert /*=export_func optionMakePath
74ea906c41SOllivier Robert * private:
75ea906c41SOllivier Robert *
76ea906c41SOllivier Robert * what: translate and construct a path
772b15cb3dSCy Schubert * arg: + char * + p_buf + The result buffer +
782b15cb3dSCy Schubert * arg: + int + b_sz + The size of this buffer +
792b15cb3dSCy Schubert * arg: + char const * + fname + The input name +
802b15cb3dSCy Schubert * arg: + char const * + prg_path + The full path of the current program +
81ea906c41SOllivier Robert *
822b15cb3dSCy Schubert * ret-type: bool
832b15cb3dSCy Schubert * ret-desc: true if the name was handled, otherwise false.
84ea906c41SOllivier Robert * If the name does not start with ``$'', then it is handled
85ea906c41SOllivier Robert * simply by copying the input name to the output buffer and
862b15cb3dSCy Schubert * resolving the name with either
872b15cb3dSCy Schubert * @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}.
88ea906c41SOllivier Robert *
89ea906c41SOllivier Robert * doc:
90ea906c41SOllivier Robert *
912b15cb3dSCy Schubert * This routine will copy the @code{pzName} input name into the
922b15cb3dSCy Schubert * @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes. If the
93ea906c41SOllivier Robert * first character of the input name is a @code{'$'} character, then there
94ea906c41SOllivier Robert * is special handling:
95ea906c41SOllivier Robert * @*
96ea906c41SOllivier Robert * @code{$$} is replaced with the directory name of the @code{pzProgPath},
97ea906c41SOllivier Robert * searching @code{$PATH} if necessary.
98ea906c41SOllivier Robert * @*
99ea906c41SOllivier Robert * @code{$@} is replaced with the AutoGen package data installation directory
100ea906c41SOllivier Robert * (aka @code{pkgdatadir}).
101ea906c41SOllivier Robert * @*
102ea906c41SOllivier Robert * @code{$NAME} is replaced by the contents of the @code{NAME} environment
103ea906c41SOllivier Robert * variable. If not found, the search fails.
104ea906c41SOllivier Robert *
105ea906c41SOllivier Robert * Please note: both @code{$$} and @code{$NAME} must be at the start of the
106ea906c41SOllivier Robert * @code{pzName} string and must either be the entire string or be followed
107ea906c41SOllivier Robert * by the @code{'/'} (backslash on windows) character.
108ea906c41SOllivier Robert *
1092b15cb3dSCy Schubert * err: @code{false} is returned if:
110ea906c41SOllivier Robert * @*
111ea906c41SOllivier Robert * @bullet{} The input name exceeds @code{bufSize} bytes.
112ea906c41SOllivier Robert * @*
113ea906c41SOllivier Robert * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
114ea906c41SOllivier Robert * and the next character is not '/'.
115ea906c41SOllivier Robert * @*
116ea906c41SOllivier Robert * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
117ea906c41SOllivier Robert * was specified.
118ea906c41SOllivier Robert * @*
119ea906c41SOllivier Robert * @bullet{} @code{NAME} is not a known environment variable
120ea906c41SOllivier Robert * @*
121ea906c41SOllivier Robert * @bullet{} @code{canonicalize_file_name} or @code{realpath} return
122ea906c41SOllivier Robert * errors (cannot resolve the resulting path).
123ea906c41SOllivier Robert =*/
1242b15cb3dSCy Schubert bool
optionMakePath(char * p_buf,int b_sz,char const * fname,char const * prg_path)1252b15cb3dSCy Schubert optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path)
126ea906c41SOllivier Robert {
1272b15cb3dSCy Schubert {
1282b15cb3dSCy Schubert size_t len = strlen(fname);
129ea906c41SOllivier Robert
1302b15cb3dSCy Schubert if (((size_t)b_sz <= len) || (len == 0))
1312b15cb3dSCy Schubert return false;
1322b15cb3dSCy Schubert }
133ea906c41SOllivier Robert
134ea906c41SOllivier Robert /*
135ea906c41SOllivier Robert * IF not an environment variable, just copy the data
136ea906c41SOllivier Robert */
1372b15cb3dSCy Schubert if (*fname != '$') {
1382b15cb3dSCy Schubert char const * src = fname;
1392b15cb3dSCy Schubert char * dst = p_buf;
1402b15cb3dSCy Schubert int ct = b_sz;
141ea906c41SOllivier Robert
142ea906c41SOllivier Robert for (;;) {
1432b15cb3dSCy Schubert if ( (*(dst++) = *(src++)) == NUL)
144ea906c41SOllivier Robert break;
145ea906c41SOllivier Robert if (--ct <= 0)
1462b15cb3dSCy Schubert return false;
147ea906c41SOllivier Robert }
148ea906c41SOllivier Robert }
149ea906c41SOllivier Robert
150ea906c41SOllivier Robert /*
151ea906c41SOllivier Robert * IF the name starts with "$$", then it must be "$$" or
152ea906c41SOllivier Robert * it must start with "$$/". In either event, replace the "$$"
153ea906c41SOllivier Robert * with the path to the executable and append a "/" character.
154ea906c41SOllivier Robert */
1552b15cb3dSCy Schubert else switch (fname[1]) {
156ea906c41SOllivier Robert case NUL:
1572b15cb3dSCy Schubert return false;
158ea906c41SOllivier Robert
159ea906c41SOllivier Robert case '$':
1602b15cb3dSCy Schubert if (! add_prog_path(p_buf, b_sz, fname, prg_path))
1612b15cb3dSCy Schubert return false;
162ea906c41SOllivier Robert break;
163ea906c41SOllivier Robert
164ea906c41SOllivier Robert case '@':
1652b15cb3dSCy Schubert if (program_pkgdatadir[0] == NUL)
1662b15cb3dSCy Schubert return false;
167ea906c41SOllivier Robert
1682b15cb3dSCy Schubert if (snprintf(p_buf, (size_t)b_sz, "%s%s",
1692b15cb3dSCy Schubert program_pkgdatadir, fname + 2) >= b_sz)
1702b15cb3dSCy Schubert return false;
171ea906c41SOllivier Robert break;
172ea906c41SOllivier Robert
173ea906c41SOllivier Robert default:
1742b15cb3dSCy Schubert if (! add_env_val(p_buf, b_sz, fname))
1752b15cb3dSCy Schubert return false;
176ea906c41SOllivier Robert }
177ea906c41SOllivier Robert
1782b15cb3dSCy Schubert return get_realpath(p_buf, b_sz);
1792b15cb3dSCy Schubert }
180ea906c41SOllivier Robert
1812b15cb3dSCy Schubert /**
1822b15cb3dSCy Schubert * convert a leading "$$" into a path to the executable.
1832b15cb3dSCy Schubert */
1842b15cb3dSCy Schubert static bool
add_prog_path(char * buf,int b_sz,char const * fname,char const * prg_path)1852b15cb3dSCy Schubert add_prog_path(char * buf, int b_sz, char const * fname, char const * prg_path)
186ea906c41SOllivier Robert {
1872b15cb3dSCy Schubert char const * path;
1882b15cb3dSCy Schubert char const * pz;
189ea906c41SOllivier Robert int skip = 2;
190*a466cc55SCy Schubert size_t fname_len;
191*a466cc55SCy Schubert size_t dir_len; //!< length of the directory portion of the path to the exe
192ea906c41SOllivier Robert
1932b15cb3dSCy Schubert switch (fname[2]) {
194ea906c41SOllivier Robert case DIRCH:
195ea906c41SOllivier Robert skip = 3;
196ea906c41SOllivier Robert case NUL:
197ea906c41SOllivier Robert break;
198ea906c41SOllivier Robert default:
1992b15cb3dSCy Schubert return false;
200ea906c41SOllivier Robert }
201ea906c41SOllivier Robert
202ea906c41SOllivier Robert /*
203ea906c41SOllivier Robert * See if the path is included in the program name.
204ea906c41SOllivier Robert * If it is, we're done. Otherwise, we have to hunt
205ea906c41SOllivier Robert * for the program using "pathfind".
206ea906c41SOllivier Robert */
2072b15cb3dSCy Schubert if (strchr(prg_path, DIRCH) != NULL)
2082b15cb3dSCy Schubert path = prg_path;
209ea906c41SOllivier Robert else {
210*a466cc55SCy Schubert path = pathfind(getenv("PATH"), (char *)prg_path, "rx");
211ea906c41SOllivier Robert
2122b15cb3dSCy Schubert if (path == NULL)
2132b15cb3dSCy Schubert return false;
214ea906c41SOllivier Robert }
215ea906c41SOllivier Robert
2162b15cb3dSCy Schubert pz = strrchr(path, DIRCH);
217ea906c41SOllivier Robert
218ea906c41SOllivier Robert /*
219ea906c41SOllivier Robert * IF we cannot find a directory name separator,
220ea906c41SOllivier Robert * THEN we do not have a path name to our executable file.
221ea906c41SOllivier Robert */
222ea906c41SOllivier Robert if (pz == NULL)
2232b15cb3dSCy Schubert return false;
224ea906c41SOllivier Robert
2252b15cb3dSCy Schubert fname += skip;
226*a466cc55SCy Schubert fname_len = strlen(fname) + 1; // + NUL byte
227*a466cc55SCy Schubert dir_len = (pz - path) + 1; // + dir sep character
228ea906c41SOllivier Robert
229ea906c41SOllivier Robert /*
230ea906c41SOllivier Robert * Concatenate the file name to the end of the executable path.
231ea906c41SOllivier Robert * The result may be either a file or a directory.
232ea906c41SOllivier Robert */
233*a466cc55SCy Schubert if (dir_len + fname_len > (unsigned)b_sz)
2342b15cb3dSCy Schubert return false;
235ea906c41SOllivier Robert
236*a466cc55SCy Schubert memcpy(buf, path, dir_len);
237*a466cc55SCy Schubert memcpy(buf + dir_len, fname, fname_len);
238ea906c41SOllivier Robert
239ea906c41SOllivier Robert /*
2402b15cb3dSCy Schubert * If the "path" path was gotten from "pathfind()", then it was
241ea906c41SOllivier Robert * allocated and we need to deallocate it.
242ea906c41SOllivier Robert */
2432b15cb3dSCy Schubert if (path != prg_path)
2442b15cb3dSCy Schubert AGFREE(path);
2452b15cb3dSCy Schubert return true;
246ea906c41SOllivier Robert }
247ea906c41SOllivier Robert
2482b15cb3dSCy Schubert /**
2492b15cb3dSCy Schubert * Add an environment variable value.
2502b15cb3dSCy Schubert */
2512b15cb3dSCy Schubert static bool
add_env_val(char * buf,int buf_sz,char const * name)2522b15cb3dSCy Schubert add_env_val(char * buf, int buf_sz, char const * name)
253ea906c41SOllivier Robert {
2542b15cb3dSCy Schubert char * dir_part = buf;
255ea906c41SOllivier Robert
256ea906c41SOllivier Robert for (;;) {
2572b15cb3dSCy Schubert int ch = (int)*++name;
2582b15cb3dSCy Schubert if (! IS_VALUE_NAME_CHAR(ch))
259ea906c41SOllivier Robert break;
2602b15cb3dSCy Schubert *(dir_part++) = (char)ch;
261ea906c41SOllivier Robert }
262ea906c41SOllivier Robert
2632b15cb3dSCy Schubert if (dir_part == buf)
2642b15cb3dSCy Schubert return false;
265ea906c41SOllivier Robert
2662b15cb3dSCy Schubert *dir_part = NUL;
267ea906c41SOllivier Robert
2682b15cb3dSCy Schubert dir_part = getenv(buf);
269ea906c41SOllivier Robert
270ea906c41SOllivier Robert /*
271ea906c41SOllivier Robert * Environment value not found -- skip the home list entry
272ea906c41SOllivier Robert */
2732b15cb3dSCy Schubert if (dir_part == NULL)
2742b15cb3dSCy Schubert return false;
275ea906c41SOllivier Robert
276*a466cc55SCy Schubert {
277*a466cc55SCy Schubert size_t dir_len = strlen(dir_part);
278*a466cc55SCy Schubert size_t nm_len = strlen(name) + 1;
279ea906c41SOllivier Robert
280*a466cc55SCy Schubert if (dir_len + nm_len >= (unsigned)buf_sz)
281*a466cc55SCy Schubert return false;
282*a466cc55SCy Schubert memcpy(buf, dir_part, dir_len);
283*a466cc55SCy Schubert memcpy(buf + dir_len, name, nm_len);
284*a466cc55SCy Schubert }
285*a466cc55SCy Schubert
2862b15cb3dSCy Schubert return true;
287ea906c41SOllivier Robert }
288ea906c41SOllivier Robert
2892b15cb3dSCy Schubert /**
2902b15cb3dSCy Schubert * Trim leading and trailing white space.
2912b15cb3dSCy Schubert * If we are cooking the text and the text is quoted, then "cook"
2922b15cb3dSCy Schubert * the string. To cook, the string must be quoted.
2932b15cb3dSCy Schubert *
2942b15cb3dSCy Schubert * @param[in,out] txt the input and output string
2952b15cb3dSCy Schubert * @param[in] mode the handling mode (cooking method)
2962b15cb3dSCy Schubert */
297*a466cc55SCy Schubert static void
munge_str(char * txt,tOptionLoadMode mode)2982b15cb3dSCy Schubert munge_str(char * txt, tOptionLoadMode mode)
299ea906c41SOllivier Robert {
300*a466cc55SCy Schubert char * end;
301ea906c41SOllivier Robert
302ea906c41SOllivier Robert if (mode == OPTION_LOAD_KEEP)
303ea906c41SOllivier Robert return;
304ea906c41SOllivier Robert
3052b15cb3dSCy Schubert if (IS_WHITESPACE_CHAR(*txt)) {
3062b15cb3dSCy Schubert char * src = SPN_WHITESPACE_CHARS(txt+1);
3072b15cb3dSCy Schubert size_t l = strlen(src) + 1;
3082b15cb3dSCy Schubert memmove(txt, src, l);
309*a466cc55SCy Schubert end = txt + l - 1;
310ea906c41SOllivier Robert
3112b15cb3dSCy Schubert } else
312*a466cc55SCy Schubert end = txt + strlen(txt);
3132b15cb3dSCy Schubert
314*a466cc55SCy Schubert end = SPN_WHITESPACE_BACK(txt, end);
315*a466cc55SCy Schubert *end = NUL;
316ea906c41SOllivier Robert
317ea906c41SOllivier Robert if (mode == OPTION_LOAD_UNCOOKED)
318ea906c41SOllivier Robert return;
319ea906c41SOllivier Robert
3202b15cb3dSCy Schubert switch (*txt) {
321ea906c41SOllivier Robert default: return;
322ea906c41SOllivier Robert case '"':
323ea906c41SOllivier Robert case '\'': break;
324ea906c41SOllivier Robert }
325ea906c41SOllivier Robert
326*a466cc55SCy Schubert switch (end[-1]) {
327ea906c41SOllivier Robert default: return;
328ea906c41SOllivier Robert case '"':
329ea906c41SOllivier Robert case '\'': break;
330ea906c41SOllivier Robert }
331ea906c41SOllivier Robert
3322b15cb3dSCy Schubert (void)ao_string_cook(txt, NULL);
333ea906c41SOllivier Robert }
334ea906c41SOllivier Robert
335ea906c41SOllivier Robert static char *
assemble_arg_val(char * txt,tOptionLoadMode mode)3362b15cb3dSCy Schubert assemble_arg_val(char * txt, tOptionLoadMode mode)
337ea906c41SOllivier Robert {
3382b15cb3dSCy Schubert char * end = strpbrk(txt, ARG_BREAK_STR);
339ea906c41SOllivier Robert int space_break;
340ea906c41SOllivier Robert
341ea906c41SOllivier Robert /*
342ea906c41SOllivier Robert * Not having an argument to a configurable name is okay.
343ea906c41SOllivier Robert */
3442b15cb3dSCy Schubert if (end == NULL)
3452b15cb3dSCy Schubert return txt + strlen(txt);
346ea906c41SOllivier Robert
347ea906c41SOllivier Robert /*
348ea906c41SOllivier Robert * If we are keeping all whitespace, then the modevalue starts with the
349ea906c41SOllivier Robert * character that follows the end of the configurable name, regardless
350ea906c41SOllivier Robert * of which character caused it.
351ea906c41SOllivier Robert */
352ea906c41SOllivier Robert if (mode == OPTION_LOAD_KEEP) {
3532b15cb3dSCy Schubert *(end++) = NUL;
3542b15cb3dSCy Schubert return end;
355ea906c41SOllivier Robert }
356ea906c41SOllivier Robert
357ea906c41SOllivier Robert /*
358ea906c41SOllivier Robert * If the name ended on a white space character, remember that
359ea906c41SOllivier Robert * because we'll have to skip over an immediately following ':' or '='
360ea906c41SOllivier Robert * (and the white space following *that*).
361ea906c41SOllivier Robert */
3622b15cb3dSCy Schubert space_break = IS_WHITESPACE_CHAR(*end);
3632b15cb3dSCy Schubert *(end++) = NUL;
364ea906c41SOllivier Robert
3652b15cb3dSCy Schubert end = SPN_WHITESPACE_CHARS(end);
3662b15cb3dSCy Schubert if (space_break && ((*end == ':') || (*end == '=')))
3672b15cb3dSCy Schubert end = SPN_WHITESPACE_CHARS(end+1);
3682b15cb3dSCy Schubert
3692b15cb3dSCy Schubert return end;
370ea906c41SOllivier Robert }
371ea906c41SOllivier Robert
3722b15cb3dSCy Schubert static char *
trim_quotes(char * arg)3732b15cb3dSCy Schubert trim_quotes(char * arg)
3742b15cb3dSCy Schubert {
3752b15cb3dSCy Schubert switch (*arg) {
3762b15cb3dSCy Schubert case '"':
3772b15cb3dSCy Schubert case '\'':
3782b15cb3dSCy Schubert ao_string_cook(arg, NULL);
3792b15cb3dSCy Schubert }
3802b15cb3dSCy Schubert return arg;
3812b15cb3dSCy Schubert }
382ea906c41SOllivier Robert
3832b15cb3dSCy Schubert /**
3842b15cb3dSCy Schubert * See if the option is to be processed in the current scan direction
3852b15cb3dSCy Schubert * (-1 or +1).
386ea906c41SOllivier Robert */
3872b15cb3dSCy Schubert static bool
direction_ok(opt_state_mask_t f,int dir)3882b15cb3dSCy Schubert direction_ok(opt_state_mask_t f, int dir)
389ea906c41SOllivier Robert {
3902b15cb3dSCy Schubert if (dir == 0)
3912b15cb3dSCy Schubert return true;
392ea906c41SOllivier Robert
3932b15cb3dSCy Schubert switch (f & (OPTST_IMM|OPTST_DISABLE_IMM)) {
394ea906c41SOllivier Robert case 0:
395ea906c41SOllivier Robert /*
396ea906c41SOllivier Robert * The selected option has no immediate action.
397ea906c41SOllivier Robert * THEREFORE, if the direction is PRESETTING
398ea906c41SOllivier Robert * THEN we skip this option.
399ea906c41SOllivier Robert */
4002b15cb3dSCy Schubert if (PRESETTING(dir))
4012b15cb3dSCy Schubert return false;
402ea906c41SOllivier Robert break;
403ea906c41SOllivier Robert
404ea906c41SOllivier Robert case OPTST_IMM:
4052b15cb3dSCy Schubert if (PRESETTING(dir)) {
406ea906c41SOllivier Robert /*
407ea906c41SOllivier Robert * We are in the presetting direction with an option we handle
408ea906c41SOllivier Robert * immediately for enablement, but normally for disablement.
409ea906c41SOllivier Robert * Therefore, skip if disabled.
410ea906c41SOllivier Robert */
4112b15cb3dSCy Schubert if ((f & OPTST_DISABLED) == 0)
4122b15cb3dSCy Schubert return false;
413ea906c41SOllivier Robert } else {
414ea906c41SOllivier Robert /*
415ea906c41SOllivier Robert * We are in the processing direction with an option we handle
416ea906c41SOllivier Robert * immediately for enablement, but normally for disablement.
417ea906c41SOllivier Robert * Therefore, skip if NOT disabled.
418ea906c41SOllivier Robert */
4192b15cb3dSCy Schubert if ((f & OPTST_DISABLED) != 0)
4202b15cb3dSCy Schubert return false;
421ea906c41SOllivier Robert }
422ea906c41SOllivier Robert break;
423ea906c41SOllivier Robert
424ea906c41SOllivier Robert case OPTST_DISABLE_IMM:
4252b15cb3dSCy Schubert if (PRESETTING(dir)) {
426ea906c41SOllivier Robert /*
427ea906c41SOllivier Robert * We are in the presetting direction with an option we handle
428*a466cc55SCy Schubert * immediately for disablement, but normally for handling.
429ea906c41SOllivier Robert * Therefore, skip if NOT disabled.
430ea906c41SOllivier Robert */
4312b15cb3dSCy Schubert if ((f & OPTST_DISABLED) != 0)
4322b15cb3dSCy Schubert return false;
433ea906c41SOllivier Robert } else {
434ea906c41SOllivier Robert /*
435ea906c41SOllivier Robert * We are in the processing direction with an option we handle
436*a466cc55SCy Schubert * immediately for disablement, but normally for handling.
437ea906c41SOllivier Robert * Therefore, skip if disabled.
438ea906c41SOllivier Robert */
4392b15cb3dSCy Schubert if ((f & OPTST_DISABLED) == 0)
4402b15cb3dSCy Schubert return false;
441ea906c41SOllivier Robert }
442ea906c41SOllivier Robert break;
443ea906c41SOllivier Robert
444ea906c41SOllivier Robert case OPTST_IMM|OPTST_DISABLE_IMM:
445ea906c41SOllivier Robert /*
446ea906c41SOllivier Robert * The selected option is always for immediate action.
447ea906c41SOllivier Robert * THEREFORE, if the direction is PROCESSING
448ea906c41SOllivier Robert * THEN we skip this option.
449ea906c41SOllivier Robert */
4502b15cb3dSCy Schubert if (PROCESSING(dir))
4512b15cb3dSCy Schubert return false;
452ea906c41SOllivier Robert break;
453ea906c41SOllivier Robert }
4542b15cb3dSCy Schubert return true;
4552b15cb3dSCy Schubert }
4562b15cb3dSCy Schubert
4572b15cb3dSCy Schubert /**
4582b15cb3dSCy Schubert * Load an option from a block of text. The text must start with the
4592b15cb3dSCy Schubert * configurable/option name and be followed by its associated value.
4602b15cb3dSCy Schubert * That value may be processed in any of several ways. See "tOptionLoadMode"
4612b15cb3dSCy Schubert * in autoopts.h.
4622b15cb3dSCy Schubert *
4632b15cb3dSCy Schubert * @param[in,out] opts program options descriptor
4642b15cb3dSCy Schubert * @param[in,out] opt_state option processing state
4652b15cb3dSCy Schubert * @param[in,out] line source line with long option name in it
4662b15cb3dSCy Schubert * @param[in] direction current processing direction (preset or not)
4672b15cb3dSCy Schubert * @param[in] load_mode option loading mode (OPTION_LOAD_*)
4682b15cb3dSCy Schubert */
469*a466cc55SCy Schubert static void
load_opt_line(tOptions * opts,tOptState * opt_state,char * line,tDirection direction,tOptionLoadMode load_mode)4702b15cb3dSCy Schubert load_opt_line(tOptions * opts, tOptState * opt_state, char * line,
4712b15cb3dSCy Schubert tDirection direction, tOptionLoadMode load_mode )
4722b15cb3dSCy Schubert {
4732b15cb3dSCy Schubert /*
4742b15cb3dSCy Schubert * When parsing a stored line, we only look at the characters after
4752b15cb3dSCy Schubert * a hyphen. Long names must always be at least two characters and
4762b15cb3dSCy Schubert * short options are always exactly one character long.
4772b15cb3dSCy Schubert */
4782b15cb3dSCy Schubert line = SPN_LOAD_LINE_SKIP_CHARS(line);
4792b15cb3dSCy Schubert
4802b15cb3dSCy Schubert {
4812b15cb3dSCy Schubert char * arg = assemble_arg_val(line, load_mode);
4822b15cb3dSCy Schubert
4832b15cb3dSCy Schubert if (IS_OPTION_NAME_CHAR(line[1])) {
4842b15cb3dSCy Schubert
4852b15cb3dSCy Schubert if (! SUCCESSFUL(opt_find_long(opts, line, opt_state)))
4862b15cb3dSCy Schubert return;
4872b15cb3dSCy Schubert
4882b15cb3dSCy Schubert } else if (! SUCCESSFUL(opt_find_short(opts, *line, opt_state)))
4892b15cb3dSCy Schubert return;
4902b15cb3dSCy Schubert
4912b15cb3dSCy Schubert if ((! CALLED(direction)) && (opt_state->flags & OPTST_NO_INIT))
4922b15cb3dSCy Schubert return;
4932b15cb3dSCy Schubert
4942b15cb3dSCy Schubert opt_state->pzOptArg = trim_quotes(arg);
4952b15cb3dSCy Schubert }
4962b15cb3dSCy Schubert
4972b15cb3dSCy Schubert if (! direction_ok(opt_state->flags, direction))
4982b15cb3dSCy Schubert return;
499ea906c41SOllivier Robert
500ea906c41SOllivier Robert /*
501ea906c41SOllivier Robert * Fix up the args.
502ea906c41SOllivier Robert */
5032b15cb3dSCy Schubert if (OPTST_GET_ARGTYPE(opt_state->pOD->fOptState) == OPARG_TYPE_NONE) {
5042b15cb3dSCy Schubert if (*opt_state->pzOptArg != NUL)
505ea906c41SOllivier Robert return;
5062b15cb3dSCy Schubert opt_state->pzOptArg = NULL;
507ea906c41SOllivier Robert
5082b15cb3dSCy Schubert } else if (opt_state->pOD->fOptState & OPTST_ARG_OPTIONAL) {
5092b15cb3dSCy Schubert if (*opt_state->pzOptArg == NUL)
5102b15cb3dSCy Schubert opt_state->pzOptArg = NULL;
511ea906c41SOllivier Robert else {
5122b15cb3dSCy Schubert AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg");
5132b15cb3dSCy Schubert opt_state->flags |= OPTST_ALLOC_ARG;
514ea906c41SOllivier Robert }
515ea906c41SOllivier Robert
516ea906c41SOllivier Robert } else {
5172b15cb3dSCy Schubert if (*opt_state->pzOptArg == NUL)
5182b15cb3dSCy Schubert opt_state->pzOptArg = zNil;
519ea906c41SOllivier Robert else {
5202b15cb3dSCy Schubert AGDUPSTR(opt_state->pzOptArg, opt_state->pzOptArg, "opt arg");
5212b15cb3dSCy Schubert opt_state->flags |= OPTST_ALLOC_ARG;
522ea906c41SOllivier Robert }
523ea906c41SOllivier Robert }
524ea906c41SOllivier Robert
525ea906c41SOllivier Robert {
526ea906c41SOllivier Robert tOptionLoadMode sv = option_load_mode;
527ea906c41SOllivier Robert option_load_mode = load_mode;
5282b15cb3dSCy Schubert handle_opt(opts, opt_state);
529ea906c41SOllivier Robert option_load_mode = sv;
530ea906c41SOllivier Robert }
531ea906c41SOllivier Robert }
532ea906c41SOllivier Robert
533ea906c41SOllivier Robert /*=export_func optionLoadLine
534ea906c41SOllivier Robert *
535ea906c41SOllivier Robert * what: process a string for an option name and value
536ea906c41SOllivier Robert *
5372b15cb3dSCy Schubert * arg: tOptions *, opts, program options descriptor
5382b15cb3dSCy Schubert * arg: char const *, line, NUL-terminated text
539ea906c41SOllivier Robert *
540ea906c41SOllivier Robert * doc:
541ea906c41SOllivier Robert *
542ea906c41SOllivier Robert * This is a client program callable routine for setting options from, for
543ea906c41SOllivier Robert * example, the contents of a file that they read in. Only one option may
544ea906c41SOllivier Robert * appear in the text. It will be treated as a normal (non-preset) option.
545ea906c41SOllivier Robert *
546ea906c41SOllivier Robert * When passed a pointer to the option struct and a string, it will find
547ea906c41SOllivier Robert * the option named by the first token on the string and set the option
548ea906c41SOllivier Robert * argument to the remainder of the string. The caller must NUL terminate
5492b15cb3dSCy Schubert * the string. The caller need not skip over any introductory hyphens.
5502b15cb3dSCy Schubert * Any embedded new lines will be included in the option
551ea906c41SOllivier Robert * argument. If the input looks like one or more quoted strings, then the
552ea906c41SOllivier Robert * input will be "cooked". The "cooking" is identical to the string
553ea906c41SOllivier Robert * formation used in AutoGen definition files (@pxref{basic expression}),
554ea906c41SOllivier Robert * except that you may not use backquotes.
555ea906c41SOllivier Robert *
556ea906c41SOllivier Robert * err: Invalid options are silently ignored. Invalid option arguments
557ea906c41SOllivier Robert * will cause a warning to print, but the function should return.
558ea906c41SOllivier Robert =*/
559ea906c41SOllivier Robert void
optionLoadLine(tOptions * opts,char const * line)5602b15cb3dSCy Schubert optionLoadLine(tOptions * opts, char const * line)
561ea906c41SOllivier Robert {
562ea906c41SOllivier Robert tOptState st = OPTSTATE_INITIALIZER(SET);
563ea906c41SOllivier Robert char * pz;
5642b15cb3dSCy Schubert proc_state_mask_t sv_flags = opts->fOptSet;
5652b15cb3dSCy Schubert opts->fOptSet &= ~OPTPROC_ERRSTOP;
5662b15cb3dSCy Schubert AGDUPSTR(pz, line, "opt line");
5672b15cb3dSCy Schubert load_opt_line(opts, &st, pz, DIRECTION_CALLED, OPTION_LOAD_COOKED);
568ea906c41SOllivier Robert AGFREE(pz);
5692b15cb3dSCy Schubert opts->fOptSet = sv_flags;
570ea906c41SOllivier Robert }
5712b15cb3dSCy Schubert /** @}
5722b15cb3dSCy Schubert *
573ea906c41SOllivier Robert * Local Variables:
574ea906c41SOllivier Robert * mode: C
575ea906c41SOllivier Robert * c-file-style: "stroustrup"
576ea906c41SOllivier Robert * indent-tabs-mode: nil
577ea906c41SOllivier Robert * End:
578ea906c41SOllivier Robert * end of autoopts/load.c */
579