Annotation of embedaddon/ntp/sntp/libopts/load.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>