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