Annotation of embedaddon/ntp/sntp/libopts/load.c, revision 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>