xref: /freebsd/contrib/ntp/sntp/libopts/load.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
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