1181834Sroberto
2181834Sroberto/*
3181834Sroberto *  $Id: load.c,v 4.20 2007/02/04 22:17:39 bkorb Exp $
4181834Sroberto *  Time-stamp:      "2007-02-04 11:54:57 bkorb"
5181834Sroberto *
6181834Sroberto *  This file contains the routines that deal with processing text strings
7181834Sroberto *  for options, either from a NUL-terminated string passed in or from an
8181834Sroberto *  rc/ini file.
9181834Sroberto */
10181834Sroberto
11181834Sroberto/*
12181834Sroberto *  Automated Options copyright 1992-2007 Bruce Korb
13181834Sroberto *
14181834Sroberto *  Automated Options is free software.
15181834Sroberto *  You may redistribute it and/or modify it under the terms of the
16181834Sroberto *  GNU General Public License, as published by the Free Software
17181834Sroberto *  Foundation; either version 2, or (at your option) any later version.
18181834Sroberto *
19181834Sroberto *  Automated Options is distributed in the hope that it will be useful,
20181834Sroberto *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21181834Sroberto *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22181834Sroberto *  GNU General Public License for more details.
23181834Sroberto *
24181834Sroberto *  You should have received a copy of the GNU General Public License
25181834Sroberto *  along with Automated Options.  See the file "COPYING".  If not,
26181834Sroberto *  write to:  The Free Software Foundation, Inc.,
27181834Sroberto *             51 Franklin Street, Fifth Floor,
28181834Sroberto *             Boston, MA  02110-1301, USA.
29181834Sroberto *
30181834Sroberto * As a special exception, Bruce Korb gives permission for additional
31181834Sroberto * uses of the text contained in his release of AutoOpts.
32181834Sroberto *
33181834Sroberto * The exception is that, if you link the AutoOpts library with other
34181834Sroberto * files to produce an executable, this does not by itself cause the
35181834Sroberto * resulting executable to be covered by the GNU General Public License.
36181834Sroberto * Your use of that executable is in no way restricted on account of
37181834Sroberto * linking the AutoOpts library code into it.
38181834Sroberto *
39181834Sroberto * This exception does not however invalidate any other reasons why
40181834Sroberto * the executable file might be covered by the GNU General Public License.
41181834Sroberto *
42181834Sroberto * This exception applies only to the code released by Bruce Korb under
43181834Sroberto * the name AutoOpts.  If you copy code from other sources under the
44181834Sroberto * General Public License into a copy of AutoOpts, as the General Public
45181834Sroberto * License permits, the exception does not apply to the code that you add
46181834Sroberto * in this way.  To avoid misleading anyone as to the status of such
47181834Sroberto * modified files, you must delete this exception notice from them.
48181834Sroberto *
49181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice
50181834Sroberto * whether to permit this exception to apply to your modifications.
51181834Sroberto * If you do not wish that, delete this exception notice.
52181834Sroberto */
53181834Sroberto
54181834SrobertotOptionLoadMode option_load_mode = OPTION_LOAD_UNCOOKED;
55181834Sroberto
56181834Sroberto/* = = = START-STATIC-FORWARD = = = */
57181834Sroberto/* static forward declarations maintained by :mkfwd */
58181834Srobertostatic ag_bool
59181834SrobertoinsertProgramPath(
60181834Sroberto    char*   pzBuf,
61181834Sroberto    int     bufSize,
62181834Sroberto    tCC*    pzName,
63181834Sroberto    tCC*    pzProgPath );
64181834Sroberto
65181834Srobertostatic ag_bool
66181834SrobertoinsertEnvVal(
67181834Sroberto    char*   pzBuf,
68181834Sroberto    int     bufSize,
69181834Sroberto    tCC*    pzName,
70181834Sroberto    tCC*    pzProgPath );
71181834Sroberto
72181834Srobertostatic char*
73181834SrobertoassembleArgValue( char* pzTxt, tOptionLoadMode mode );
74181834Sroberto/* = = = END-STATIC-FORWARD = = = */
75181834Sroberto
76181834Sroberto/*=export_func  optionMakePath
77181834Sroberto * private:
78181834Sroberto *
79181834Sroberto * what:  translate and construct a path
80181834Sroberto * arg:   + char*       + pzBuf      + The result buffer +
81181834Sroberto * arg:   + int         + bufSize    + The size of this buffer +
82181834Sroberto * arg:   + char const* + pzName     + The input name +
83181834Sroberto * arg:   + char const* + pzProgPath + The full path of the current program +
84181834Sroberto *
85181834Sroberto * ret-type: ag_bool
86181834Sroberto * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE.
87181834Sroberto *           If the name does not start with ``$'', then it is handled
88181834Sroberto *           simply by copying the input name to the output buffer and
89181834Sroberto *           resolving the name with either @code{canonicalize_file_name(3GLIBC)}
90181834Sroberto *           or @code{realpath(3C)}.
91181834Sroberto *
92181834Sroberto * doc:
93181834Sroberto *
94181834Sroberto *  This routine will copy the @code{pzName} input name into the @code{pzBuf}
95181834Sroberto *  output buffer, carefully not exceeding @code{bufSize} bytes.  If the
96181834Sroberto *  first character of the input name is a @code{'$'} character, then there
97181834Sroberto *  is special handling:
98181834Sroberto *  @*
99181834Sroberto *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
100181834Sroberto *  searching @code{$PATH} if necessary.
101181834Sroberto *  @*
102181834Sroberto *  @code{$@} is replaced with the AutoGen package data installation directory
103181834Sroberto *  (aka @code{pkgdatadir}).
104181834Sroberto *  @*
105181834Sroberto *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
106181834Sroberto *  variable.  If not found, the search fails.
107181834Sroberto *
108181834Sroberto *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
109181834Sroberto *     @code{pzName} string and must either be the entire string or be followed
110181834Sroberto *     by the @code{'/'} (backslash on windows) character.
111181834Sroberto *
112181834Sroberto * err:  @code{AG_FALSE} is returned if:
113181834Sroberto *       @*
114181834Sroberto *       @bullet{} The input name exceeds @code{bufSize} bytes.
115181834Sroberto *       @*
116181834Sroberto *       @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
117181834Sroberto *                 and the next character is not '/'.
118181834Sroberto *       @*
119181834Sroberto *       @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
120181834Sroberto *                 was specified.
121181834Sroberto *       @*
122181834Sroberto *       @bullet{} @code{NAME} is not a known environment variable
123181834Sroberto *       @*
124181834Sroberto *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
125181834Sroberto *                 errors (cannot resolve the resulting path).
126181834Sroberto=*/
127181834Srobertoag_bool
128181834SrobertooptionMakePath(
129181834Sroberto    char*   pzBuf,
130181834Sroberto    int     bufSize,
131181834Sroberto    tCC*    pzName,
132181834Sroberto    tCC*    pzProgPath )
133181834Sroberto{
134181834Sroberto    size_t  name_len = strlen( pzName );
135181834Sroberto
136181834Sroberto#   ifndef PKGDATADIR
137181834Sroberto#     define PKGDATADIR ""
138181834Sroberto#   endif
139181834Sroberto
140181834Sroberto    tSCC    pkgdatadir[] = PKGDATADIR;
141181834Sroberto
142181834Sroberto    ag_bool res = AG_TRUE;
143181834Sroberto
144181834Sroberto    if (bufSize <= name_len)
145181834Sroberto        return AG_FALSE;
146181834Sroberto
147181834Sroberto    /*
148181834Sroberto     *  IF not an environment variable, just copy the data
149181834Sroberto     */
150181834Sroberto    if (*pzName != '$') {
151181834Sroberto        tCC*  pzS = pzName;
152181834Sroberto        char* pzD = pzBuf;
153181834Sroberto        int   ct  = bufSize;
154181834Sroberto
155181834Sroberto        for (;;) {
156181834Sroberto            if ( (*(pzD++) = *(pzS++)) == NUL)
157181834Sroberto                break;
158181834Sroberto            if (--ct <= 0)
159181834Sroberto                return AG_FALSE;
160181834Sroberto        }
161181834Sroberto    }
162181834Sroberto
163181834Sroberto    /*
164181834Sroberto     *  IF the name starts with "$$", then it must be "$$" or
165181834Sroberto     *  it must start with "$$/".  In either event, replace the "$$"
166181834Sroberto     *  with the path to the executable and append a "/" character.
167181834Sroberto     */
168181834Sroberto    else switch (pzName[1]) {
169181834Sroberto    case NUL:
170181834Sroberto        return AG_FALSE;
171181834Sroberto
172181834Sroberto    case '$':
173181834Sroberto        res = insertProgramPath( pzBuf, bufSize, pzName, pzProgPath );
174181834Sroberto        break;
175181834Sroberto
176181834Sroberto    case '@':
177181834Sroberto        if (pkgdatadir[0] == NUL)
178181834Sroberto            return AG_FALSE;
179181834Sroberto
180181834Sroberto        if (name_len + sizeof (pkgdatadir) > bufSize)
181181834Sroberto            return AG_FALSE;
182181834Sroberto
183181834Sroberto        strcpy(pzBuf, pkgdatadir);
184181834Sroberto        strcpy(pzBuf + sizeof(pkgdatadir) - 1, pzName + 2);
185181834Sroberto        break;
186181834Sroberto
187181834Sroberto    default:
188181834Sroberto        res = insertEnvVal( pzBuf, bufSize, pzName, pzProgPath );
189181834Sroberto    }
190181834Sroberto
191181834Sroberto    if (! res)
192181834Sroberto        return AG_FALSE;
193181834Sroberto
194181834Sroberto#if defined(HAVE_CANONICALIZE_FILE_NAME)
195181834Sroberto    {
196181834Sroberto        char* pz = canonicalize_file_name(pzBuf);
197181834Sroberto        if (pz == NULL)
198181834Sroberto            return AG_FALSE;
199181834Sroberto        if (strlen(pz) < bufSize)
200181834Sroberto            strcpy(pzBuf, pz);
201181834Sroberto        free(pz);
202181834Sroberto    }
203181834Sroberto
204181834Sroberto#elif defined(HAVE_REALPATH)
205181834Sroberto    {
206181834Sroberto        char z[ PATH_MAX+1 ];
207181834Sroberto
208181834Sroberto        if (realpath( pzBuf, z ) == NULL)
209181834Sroberto            return AG_FALSE;
210181834Sroberto
211181834Sroberto        if (strlen(z) < bufSize)
212181834Sroberto            strcpy( pzBuf, z );
213181834Sroberto    }
214181834Sroberto#endif
215181834Sroberto
216181834Sroberto    return AG_TRUE;
217181834Sroberto}
218181834Sroberto
219181834Sroberto
220181834Srobertostatic ag_bool
221181834SrobertoinsertProgramPath(
222181834Sroberto    char*   pzBuf,
223181834Sroberto    int     bufSize,
224181834Sroberto    tCC*    pzName,
225181834Sroberto    tCC*    pzProgPath )
226181834Sroberto{
227181834Sroberto    tCC*    pzPath;
228181834Sroberto    tCC*    pz;
229181834Sroberto    int     skip = 2;
230181834Sroberto
231181834Sroberto    switch (pzName[2]) {
232181834Sroberto    case DIRCH:
233181834Sroberto        skip = 3;
234181834Sroberto    case NUL:
235181834Sroberto        break;
236181834Sroberto    default:
237181834Sroberto        return AG_FALSE;
238181834Sroberto    }
239181834Sroberto
240181834Sroberto    /*
241181834Sroberto     *  See if the path is included in the program name.
242181834Sroberto     *  If it is, we're done.  Otherwise, we have to hunt
243181834Sroberto     *  for the program using "pathfind".
244181834Sroberto     */
245181834Sroberto    if (strchr( pzProgPath, DIRCH ) != NULL)
246181834Sroberto        pzPath = pzProgPath;
247181834Sroberto    else {
248181834Sroberto        pzPath = pathfind( getenv( "PATH" ), (char*)pzProgPath, "rx" );
249181834Sroberto
250181834Sroberto        if (pzPath == NULL)
251181834Sroberto            return AG_FALSE;
252181834Sroberto    }
253181834Sroberto
254181834Sroberto    pz = strrchr( pzPath, DIRCH );
255181834Sroberto
256181834Sroberto    /*
257181834Sroberto     *  IF we cannot find a directory name separator,
258181834Sroberto     *  THEN we do not have a path name to our executable file.
259181834Sroberto     */
260181834Sroberto    if (pz == NULL)
261181834Sroberto        return AG_FALSE;
262181834Sroberto
263181834Sroberto    pzName += skip;
264181834Sroberto
265181834Sroberto    /*
266181834Sroberto     *  Concatenate the file name to the end of the executable path.
267181834Sroberto     *  The result may be either a file or a directory.
268181834Sroberto     */
269181834Sroberto    if ((pz - pzPath)+1 + strlen(pzName) >= bufSize)
270181834Sroberto        return AG_FALSE;
271181834Sroberto
272181834Sroberto    memcpy( pzBuf, pzPath, (size_t)((pz - pzPath)+1) );
273181834Sroberto    strcpy( pzBuf + (pz - pzPath) + 1, pzName );
274181834Sroberto
275181834Sroberto    /*
276181834Sroberto     *  If the "pzPath" path was gotten from "pathfind()", then it was
277181834Sroberto     *  allocated and we need to deallocate it.
278181834Sroberto     */
279181834Sroberto    if (pzPath != pzProgPath)
280181834Sroberto        free( (void*)pzPath );
281181834Sroberto    return AG_TRUE;
282181834Sroberto}
283181834Sroberto
284181834Sroberto
285181834Srobertostatic ag_bool
286181834SrobertoinsertEnvVal(
287181834Sroberto    char*   pzBuf,
288181834Sroberto    int     bufSize,
289181834Sroberto    tCC*    pzName,
290181834Sroberto    tCC*    pzProgPath )
291181834Sroberto{
292181834Sroberto    char* pzDir = pzBuf;
293181834Sroberto
294181834Sroberto    for (;;) {
295181834Sroberto        int ch = (int)*++pzName;
296181834Sroberto        if (! ISNAMECHAR( ch ))
297181834Sroberto            break;
298181834Sroberto        *(pzDir++) = (char)ch;
299181834Sroberto    }
300181834Sroberto
301181834Sroberto    if (pzDir == pzBuf)
302181834Sroberto        return AG_FALSE;
303181834Sroberto
304181834Sroberto    *pzDir = NUL;
305181834Sroberto
306181834Sroberto    pzDir = getenv( pzBuf );
307181834Sroberto
308181834Sroberto    /*
309181834Sroberto     *  Environment value not found -- skip the home list entry
310181834Sroberto     */
311181834Sroberto    if (pzDir == NULL)
312181834Sroberto        return AG_FALSE;
313181834Sroberto
314181834Sroberto    if (strlen( pzDir ) + 1 + strlen( pzName ) >= bufSize)
315181834Sroberto        return AG_FALSE;
316181834Sroberto
317181834Sroberto    sprintf( pzBuf, "%s%s", pzDir, pzName );
318181834Sroberto    return AG_TRUE;
319181834Sroberto}
320181834Sroberto
321181834Sroberto
322181834SrobertoLOCAL void
323181834SrobertomungeString( char* pzTxt, tOptionLoadMode mode )
324181834Sroberto{
325181834Sroberto    char* pzE;
326181834Sroberto
327181834Sroberto    if (mode == OPTION_LOAD_KEEP)
328181834Sroberto        return;
329181834Sroberto
330181834Sroberto    if (isspace( (int)*pzTxt )) {
331181834Sroberto        char* pzS = pzTxt;
332181834Sroberto        char* pzD = pzTxt;
333181834Sroberto        while (isspace( (int)*++pzS ))  ;
334181834Sroberto        while ((*(pzD++) = *(pzS++)) != NUL)   ;
335181834Sroberto        pzE = pzD-1;
336181834Sroberto    } else
337181834Sroberto        pzE = pzTxt + strlen( pzTxt );
338181834Sroberto
339181834Sroberto    while ((pzE > pzTxt) && isspace( (int)pzE[-1] ))  pzE--;
340181834Sroberto    *pzE = NUL;
341181834Sroberto
342181834Sroberto    if (mode == OPTION_LOAD_UNCOOKED)
343181834Sroberto        return;
344181834Sroberto
345181834Sroberto    switch (*pzTxt) {
346181834Sroberto    default: return;
347181834Sroberto    case '"':
348181834Sroberto    case '\'': break;
349181834Sroberto    }
350181834Sroberto
351181834Sroberto    switch (pzE[-1]) {
352181834Sroberto    default: return;
353181834Sroberto    case '"':
354181834Sroberto    case '\'': break;
355181834Sroberto    }
356181834Sroberto
357181834Sroberto    (void)ao_string_cook( pzTxt, NULL );
358181834Sroberto}
359181834Sroberto
360181834Sroberto
361181834Srobertostatic char*
362181834SrobertoassembleArgValue( char* pzTxt, tOptionLoadMode mode )
363181834Sroberto{
364181834Sroberto    tSCC zBrk[] = " \t:=";
365181834Sroberto    char* pzEnd = strpbrk( pzTxt, zBrk );
366181834Sroberto    int   space_break;
367181834Sroberto
368181834Sroberto    /*
369181834Sroberto     *  Not having an argument to a configurable name is okay.
370181834Sroberto     */
371181834Sroberto    if (pzEnd == NULL)
372181834Sroberto        return pzTxt + strlen(pzTxt);
373181834Sroberto
374181834Sroberto    /*
375181834Sroberto     *  If we are keeping all whitespace, then the  modevalue starts with the
376181834Sroberto     *  character that follows the end of the configurable name, regardless
377181834Sroberto     *  of which character caused it.
378181834Sroberto     */
379181834Sroberto    if (mode == OPTION_LOAD_KEEP) {
380181834Sroberto        *(pzEnd++) = NUL;
381181834Sroberto        return pzEnd;
382181834Sroberto    }
383181834Sroberto
384181834Sroberto    /*
385181834Sroberto     *  If the name ended on a white space character, remember that
386181834Sroberto     *  because we'll have to skip over an immediately following ':' or '='
387181834Sroberto     *  (and the white space following *that*).
388181834Sroberto     */
389181834Sroberto    space_break = isspace((int)*pzEnd);
390181834Sroberto    *(pzEnd++) = NUL;
391181834Sroberto    while (isspace((int)*pzEnd))  pzEnd++;
392181834Sroberto    if (space_break && ((*pzEnd == ':') || (*pzEnd == '=')))
393181834Sroberto        while (isspace((int)*++pzEnd))  ;
394181834Sroberto
395181834Sroberto    return pzEnd;
396181834Sroberto}
397181834Sroberto
398181834Sroberto
399181834Sroberto/*
400181834Sroberto *  Load an option from a block of text.  The text must start with the
401181834Sroberto *  configurable/option name and be followed by its associated value.
402181834Sroberto *  That value may be processed in any of several ways.  See "tOptionLoadMode"
403181834Sroberto *  in autoopts.h.
404181834Sroberto */
405181834SrobertoLOCAL void
406181834SrobertoloadOptionLine(
407181834Sroberto    tOptions*   pOpts,
408181834Sroberto    tOptState*  pOS,
409181834Sroberto    char*       pzLine,
410181834Sroberto    tDirection  direction,
411181834Sroberto    tOptionLoadMode   load_mode )
412181834Sroberto{
413181834Sroberto    while (isspace( (int)*pzLine ))  pzLine++;
414181834Sroberto
415181834Sroberto    {
416181834Sroberto        char* pzArg = assembleArgValue( pzLine, load_mode );
417181834Sroberto
418181834Sroberto        if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS )))
419181834Sroberto            return;
420181834Sroberto        if (pOS->flags & OPTST_NO_INIT)
421181834Sroberto            return;
422181834Sroberto        pOS->pzOptArg = pzArg;
423181834Sroberto    }
424181834Sroberto
425181834Sroberto    switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
426181834Sroberto    case 0:
427181834Sroberto        /*
428181834Sroberto         *  The selected option has no immediate action.
429181834Sroberto         *  THEREFORE, if the direction is PRESETTING
430181834Sroberto         *  THEN we skip this option.
431181834Sroberto         */
432181834Sroberto        if (PRESETTING(direction))
433181834Sroberto            return;
434181834Sroberto        break;
435181834Sroberto
436181834Sroberto    case OPTST_IMM:
437181834Sroberto        if (PRESETTING(direction)) {
438181834Sroberto            /*
439181834Sroberto             *  We are in the presetting direction with an option we handle
440181834Sroberto             *  immediately for enablement, but normally for disablement.
441181834Sroberto             *  Therefore, skip if disabled.
442181834Sroberto             */
443181834Sroberto            if ((pOS->flags & OPTST_DISABLED) == 0)
444181834Sroberto                return;
445181834Sroberto        } else {
446181834Sroberto            /*
447181834Sroberto             *  We are in the processing direction with an option we handle
448181834Sroberto             *  immediately for enablement, but normally for disablement.
449181834Sroberto             *  Therefore, skip if NOT disabled.
450181834Sroberto             */
451181834Sroberto            if ((pOS->flags & OPTST_DISABLED) != 0)
452181834Sroberto                return;
453181834Sroberto        }
454181834Sroberto        break;
455181834Sroberto
456181834Sroberto    case OPTST_DISABLE_IMM:
457181834Sroberto        if (PRESETTING(direction)) {
458181834Sroberto            /*
459181834Sroberto             *  We are in the presetting direction with an option we handle
460181834Sroberto             *  immediately for disablement, but normally for disablement.
461181834Sroberto             *  Therefore, skip if NOT disabled.
462181834Sroberto             */
463181834Sroberto            if ((pOS->flags & OPTST_DISABLED) != 0)
464181834Sroberto                return;
465181834Sroberto        } else {
466181834Sroberto            /*
467181834Sroberto             *  We are in the processing direction with an option we handle
468181834Sroberto             *  immediately for disablement, but normally for disablement.
469181834Sroberto             *  Therefore, skip if disabled.
470181834Sroberto             */
471181834Sroberto            if ((pOS->flags & OPTST_DISABLED) == 0)
472181834Sroberto                return;
473181834Sroberto        }
474181834Sroberto        break;
475181834Sroberto
476181834Sroberto    case OPTST_IMM|OPTST_DISABLE_IMM:
477181834Sroberto        /*
478181834Sroberto         *  The selected option is always for immediate action.
479181834Sroberto         *  THEREFORE, if the direction is PROCESSING
480181834Sroberto         *  THEN we skip this option.
481181834Sroberto         */
482181834Sroberto        if (PROCESSING(direction))
483181834Sroberto            return;
484181834Sroberto        break;
485181834Sroberto    }
486181834Sroberto
487181834Sroberto    /*
488181834Sroberto     *  Fix up the args.
489181834Sroberto     */
490181834Sroberto    if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
491181834Sroberto        if (*pOS->pzOptArg != NUL)
492181834Sroberto            return;
493181834Sroberto        pOS->pzOptArg = NULL;
494181834Sroberto
495181834Sroberto    } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
496181834Sroberto        if (*pOS->pzOptArg == NUL)
497181834Sroberto             pOS->pzOptArg = NULL;
498181834Sroberto        else {
499181834Sroberto            AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
500181834Sroberto            pOS->flags |= OPTST_ALLOC_ARG;
501181834Sroberto        }
502181834Sroberto
503181834Sroberto    } else {
504181834Sroberto        if (*pOS->pzOptArg == NUL)
505181834Sroberto             pOS->pzOptArg = zNil;
506181834Sroberto        else {
507181834Sroberto            AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
508181834Sroberto            pOS->flags |= OPTST_ALLOC_ARG;
509181834Sroberto        }
510181834Sroberto    }
511181834Sroberto
512181834Sroberto    {
513181834Sroberto        tOptionLoadMode sv = option_load_mode;
514181834Sroberto        option_load_mode = load_mode;
515181834Sroberto        handleOption( pOpts, pOS );
516181834Sroberto        option_load_mode = sv;
517181834Sroberto    }
518181834Sroberto}
519181834Sroberto
520181834Sroberto
521181834Sroberto/*=export_func  optionLoadLine
522181834Sroberto *
523181834Sroberto * what:  process a string for an option name and value
524181834Sroberto *
525181834Sroberto * arg:   tOptions*,   pOpts,  program options descriptor
526181834Sroberto * arg:   char const*, pzLine, NUL-terminated text
527181834Sroberto *
528181834Sroberto * doc:
529181834Sroberto *
530181834Sroberto *  This is a client program callable routine for setting options from, for
531181834Sroberto *  example, the contents of a file that they read in.  Only one option may
532181834Sroberto *  appear in the text.  It will be treated as a normal (non-preset) option.
533181834Sroberto *
534181834Sroberto *  When passed a pointer to the option struct and a string, it will find
535181834Sroberto *  the option named by the first token on the string and set the option
536181834Sroberto *  argument to the remainder of the string.  The caller must NUL terminate
537181834Sroberto *  the string.  Any embedded new lines will be included in the option
538181834Sroberto *  argument.  If the input looks like one or more quoted strings, then the
539181834Sroberto *  input will be "cooked".  The "cooking" is identical to the string
540181834Sroberto *  formation used in AutoGen definition files (@pxref{basic expression}),
541181834Sroberto *  except that you may not use backquotes.
542181834Sroberto *
543181834Sroberto * err:   Invalid options are silently ignored.  Invalid option arguments
544181834Sroberto *        will cause a warning to print, but the function should return.
545181834Sroberto=*/
546181834Srobertovoid
547181834SrobertooptionLoadLine(
548181834Sroberto    tOptions*  pOpts,
549181834Sroberto    tCC*       pzLine )
550181834Sroberto{
551181834Sroberto    tOptState st = OPTSTATE_INITIALIZER(SET);
552181834Sroberto    char* pz;
553181834Sroberto    AGDUPSTR( pz, pzLine, "user option line" );
554181834Sroberto    loadOptionLine( pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED );
555181834Sroberto    AGFREE( pz );
556181834Sroberto}
557181834Sroberto/*
558181834Sroberto * Local Variables:
559181834Sroberto * mode: C
560181834Sroberto * c-file-style: "stroustrup"
561181834Sroberto * indent-tabs-mode: nil
562181834Sroberto * End:
563181834Sroberto * end of autoopts/load.c */
564