| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 | 
							
- /*
 
-  *  $Id: load.c,v 4.20 2007/02/04 22:17:39 bkorb Exp $
 
-  *  Time-stamp:      "2007-02-04 11:54:57 bkorb"
 
-  *
 
-  *  This file contains the routines that deal with processing text strings
 
-  *  for options, either from a NUL-terminated string passed in or from an
 
-  *  rc/ini file.
 
-  */
 
- /*
 
-  *  Automated Options copyright 1992-2007 Bruce Korb
 
-  *
 
-  *  Automated Options is free software.
 
-  *  You may redistribute it and/or modify it under the terms of the
 
-  *  GNU General Public License, as published by the Free Software
 
-  *  Foundation; either version 2, or (at your option) any later version.
 
-  *
 
-  *  Automated Options is distributed in the hope that it will be useful,
 
-  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
-  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
-  *  GNU General Public License for more details.
 
-  *
 
-  *  You should have received a copy of the GNU General Public License
 
-  *  along with Automated Options.  See the file "COPYING".  If not,
 
-  *  write to:  The Free Software Foundation, Inc.,
 
-  *             51 Franklin Street, Fifth Floor,
 
-  *             Boston, MA  02110-1301, USA.
 
-  *
 
-  * As a special exception, Bruce Korb gives permission for additional
 
-  * uses of the text contained in his release of AutoOpts.
 
-  *
 
-  * The exception is that, if you link the AutoOpts library with other
 
-  * files to produce an executable, this does not by itself cause the
 
-  * resulting executable to be covered by the GNU General Public License.
 
-  * Your use of that executable is in no way restricted on account of
 
-  * linking the AutoOpts library code into it.
 
-  *
 
-  * This exception does not however invalidate any other reasons why
 
-  * the executable file might be covered by the GNU General Public License.
 
-  *
 
-  * This exception applies only to the code released by Bruce Korb under
 
-  * the name AutoOpts.  If you copy code from other sources under the
 
-  * General Public License into a copy of AutoOpts, as the General Public
 
-  * License permits, the exception does not apply to the code that you add
 
-  * in this way.  To avoid misleading anyone as to the status of such
 
-  * modified files, you must delete this exception notice from them.
 
-  *
 
-  * If you write modifications of your own for AutoOpts, it is your choice
 
-  * whether to permit this exception to apply to your modifications.
 
-  * If you do not wish that, delete this exception notice.
 
-  */
 
- tOptionLoadMode option_load_mode = OPTION_LOAD_UNCOOKED;
 
- /* = = = START-STATIC-FORWARD = = = */
 
- /* static forward declarations maintained by :mkfwd */
 
- static ag_bool
 
- insertProgramPath(
 
-     char*   pzBuf,
 
-     int     bufSize,
 
-     tCC*    pzName,
 
-     tCC*    pzProgPath );
 
- static ag_bool
 
- insertEnvVal(
 
-     char*   pzBuf,
 
-     int     bufSize,
 
-     tCC*    pzName,
 
-     tCC*    pzProgPath );
 
- static char*
 
- assembleArgValue( char* pzTxt, tOptionLoadMode mode );
 
- /* = = = END-STATIC-FORWARD = = = */
 
- /*=export_func  optionMakePath
 
-  * private:
 
-  *
 
-  * what:  translate and construct a path
 
-  * arg:   + char*       + pzBuf      + The result buffer +
 
-  * arg:   + int         + bufSize    + The size of this buffer +
 
-  * arg:   + char const* + pzName     + The input name +
 
-  * arg:   + char const* + pzProgPath + The full path of the current program +
 
-  *
 
-  * ret-type: ag_bool
 
-  * ret-desc: AG_TRUE if the name was handled, otherwise AG_FALSE.
 
-  *           If the name does not start with ``$'', then it is handled
 
-  *           simply by copying the input name to the output buffer and
 
-  *           resolving the name with either @code{canonicalize_file_name(3GLIBC)}
 
-  *           or @code{realpath(3C)}.
 
-  *
 
-  * doc:
 
-  *
 
-  *  This routine will copy the @code{pzName} input name into the @code{pzBuf}
 
-  *  output buffer, carefully not exceeding @code{bufSize} bytes.  If the
 
-  *  first character of the input name is a @code{'$'} character, then there
 
-  *  is special handling:
 
-  *  @*
 
-  *  @code{$$} is replaced with the directory name of the @code{pzProgPath},
 
-  *  searching @code{$PATH} if necessary.
 
-  *  @*
 
-  *  @code{$@} is replaced with the AutoGen package data installation directory
 
-  *  (aka @code{pkgdatadir}).
 
-  *  @*
 
-  *  @code{$NAME} is replaced by the contents of the @code{NAME} environment
 
-  *  variable.  If not found, the search fails.
 
-  *
 
-  *  Please note: both @code{$$} and @code{$NAME} must be at the start of the
 
-  *     @code{pzName} string and must either be the entire string or be followed
 
-  *     by the @code{'/'} (backslash on windows) character.
 
-  *
 
-  * err:  @code{AG_FALSE} is returned if:
 
-  *       @*
 
-  *       @bullet{} The input name exceeds @code{bufSize} bytes.
 
-  *       @*
 
-  *       @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string
 
-  *                 and the next character is not '/'.
 
-  *       @*
 
-  *       @bullet{} libopts was built without PKGDATADIR defined and @code{$@@}
 
-  *                 was specified.
 
-  *       @*
 
-  *       @bullet{} @code{NAME} is not a known environment variable
 
-  *       @*
 
-  *       @bullet{} @code{canonicalize_file_name} or @code{realpath} return
 
-  *                 errors (cannot resolve the resulting path).
 
- =*/
 
- ag_bool
 
- optionMakePath(
 
-     char*   pzBuf,
 
-     int     bufSize,
 
-     tCC*    pzName,
 
-     tCC*    pzProgPath )
 
- {
 
-     size_t  name_len = strlen( pzName );
 
- #   ifndef PKGDATADIR
 
- #     define PKGDATADIR ""
 
- #   endif
 
-     tSCC    pkgdatadir[] = PKGDATADIR;
 
-     ag_bool res = AG_TRUE;
 
-     if (bufSize <= name_len)
 
-         return AG_FALSE;
 
-     /*
 
-      *  IF not an environment variable, just copy the data
 
-      */
 
-     if (*pzName != '$') {
 
-         tCC*  pzS = pzName;
 
-         char* pzD = pzBuf;
 
-         int   ct  = bufSize;
 
-         for (;;) {
 
-             if ( (*(pzD++) = *(pzS++)) == NUL)
 
-                 break;
 
-             if (--ct <= 0)
 
-                 return AG_FALSE;
 
-         }
 
-     }
 
-     /*
 
-      *  IF the name starts with "$$", then it must be "$$" or
 
-      *  it must start with "$$/".  In either event, replace the "$$"
 
-      *  with the path to the executable and append a "/" character.
 
-      */
 
-     else switch (pzName[1]) {
 
-     case NUL:
 
-         return AG_FALSE;
 
-     case '$':
 
-         res = insertProgramPath( pzBuf, bufSize, pzName, pzProgPath );
 
-         break;
 
-     case '@':
 
-         if (pkgdatadir[0] == NUL)
 
-             return AG_FALSE;
 
-         if (name_len + sizeof (pkgdatadir) > bufSize)
 
-             return AG_FALSE;
 
-         strcpy(pzBuf, pkgdatadir);
 
-         strcpy(pzBuf + sizeof(pkgdatadir) - 1, pzName + 2);
 
-         break;
 
-     default:
 
-         res = insertEnvVal( pzBuf, bufSize, pzName, pzProgPath );
 
-     }
 
-     if (! res)
 
-         return AG_FALSE;
 
- #if defined(HAVE_CANONICALIZE_FILE_NAME)
 
-     {
 
-         char* pz = canonicalize_file_name(pzBuf);
 
-         if (pz == NULL)
 
-             return AG_FALSE;
 
-         if (strlen(pz) < bufSize)
 
-             strcpy(pzBuf, pz);
 
-         free(pz);
 
-     }
 
- #elif defined(HAVE_REALPATH)
 
-     {
 
-         char z[ PATH_MAX+1 ];
 
-         if (realpath( pzBuf, z ) == NULL)
 
-             return AG_FALSE;
 
-         if (strlen(z) < bufSize)
 
-             strcpy( pzBuf, z );
 
-     }
 
- #endif
 
-     return AG_TRUE;
 
- }
 
- static ag_bool
 
- insertProgramPath(
 
-     char*   pzBuf,
 
-     int     bufSize,
 
-     tCC*    pzName,
 
-     tCC*    pzProgPath )
 
- {
 
-     tCC*    pzPath;
 
-     tCC*    pz;
 
-     int     skip = 2;
 
-     switch (pzName[2]) {
 
-     case DIRCH:
 
-         skip = 3;
 
-     case NUL:
 
-         break;
 
-     default:
 
-         return AG_FALSE;
 
-     }
 
-     /*
 
-      *  See if the path is included in the program name.
 
-      *  If it is, we're done.  Otherwise, we have to hunt
 
-      *  for the program using "pathfind".
 
-      */
 
-     if (strchr( pzProgPath, DIRCH ) != NULL)
 
-         pzPath = pzProgPath;
 
-     else {
 
-         pzPath = pathfind( getenv( "PATH" ), (char*)pzProgPath, "rx" );
 
-         if (pzPath == NULL)
 
-             return AG_FALSE;
 
-     }
 
-     pz = strrchr( pzPath, DIRCH );
 
-     /*
 
-      *  IF we cannot find a directory name separator,
 
-      *  THEN we do not have a path name to our executable file.
 
-      */
 
-     if (pz == NULL)
 
-         return AG_FALSE;
 
-     pzName += skip;
 
-     /*
 
-      *  Concatenate the file name to the end of the executable path.
 
-      *  The result may be either a file or a directory.
 
-      */
 
-     if ((pz - pzPath)+1 + strlen(pzName) >= bufSize)
 
-         return AG_FALSE;
 
-     memcpy( pzBuf, pzPath, (size_t)((pz - pzPath)+1) );
 
-     strcpy( pzBuf + (pz - pzPath) + 1, pzName );
 
-     /*
 
-      *  If the "pzPath" path was gotten from "pathfind()", then it was
 
-      *  allocated and we need to deallocate it.
 
-      */
 
-     if (pzPath != pzProgPath)
 
-         free( (void*)pzPath );
 
-     return AG_TRUE;
 
- }
 
- static ag_bool
 
- insertEnvVal(
 
-     char*   pzBuf,
 
-     int     bufSize,
 
-     tCC*    pzName,
 
-     tCC*    pzProgPath )
 
- {
 
-     char* pzDir = pzBuf;
 
-     for (;;) {
 
-         int ch = (int)*++pzName;
 
-         if (! ISNAMECHAR( ch ))
 
-             break;
 
-         *(pzDir++) = (char)ch;
 
-     }
 
-     if (pzDir == pzBuf)
 
-         return AG_FALSE;
 
-     *pzDir = NUL;
 
-     pzDir = getenv( pzBuf );
 
-     /*
 
-      *  Environment value not found -- skip the home list entry
 
-      */
 
-     if (pzDir == NULL)
 
-         return AG_FALSE;
 
-     if (strlen( pzDir ) + 1 + strlen( pzName ) >= bufSize)
 
-         return AG_FALSE;
 
-     sprintf( pzBuf, "%s%s", pzDir, pzName );
 
-     return AG_TRUE;
 
- }
 
- LOCAL void
 
- mungeString( char* pzTxt, tOptionLoadMode mode )
 
- {
 
-     char* pzE;
 
-     if (mode == OPTION_LOAD_KEEP)
 
-         return;
 
-     if (isspace( (int)*pzTxt )) {
 
-         char* pzS = pzTxt;
 
-         char* pzD = pzTxt;
 
-         while (isspace( (int)*++pzS ))  ;
 
-         while ((*(pzD++) = *(pzS++)) != NUL)   ;
 
-         pzE = pzD-1;
 
-     } else
 
-         pzE = pzTxt + strlen( pzTxt );
 
-     while ((pzE > pzTxt) && isspace( (int)pzE[-1] ))  pzE--;
 
-     *pzE = NUL;
 
-     if (mode == OPTION_LOAD_UNCOOKED)
 
-         return;
 
-     switch (*pzTxt) {
 
-     default: return;
 
-     case '"':
 
-     case '\'': break;
 
-     }
 
-     switch (pzE[-1]) {
 
-     default: return;
 
-     case '"':
 
-     case '\'': break;
 
-     }
 
-     (void)ao_string_cook( pzTxt, NULL );
 
- }
 
- static char*
 
- assembleArgValue( char* pzTxt, tOptionLoadMode mode )
 
- {
 
-     tSCC zBrk[] = " \t:=";
 
-     char* pzEnd = strpbrk( pzTxt, zBrk );
 
-     int   space_break;
 
-     /*
 
-      *  Not having an argument to a configurable name is okay.
 
-      */
 
-     if (pzEnd == NULL)
 
-         return pzTxt + strlen(pzTxt);
 
-     /*
 
-      *  If we are keeping all whitespace, then the  modevalue starts with the
 
-      *  character that follows the end of the configurable name, regardless
 
-      *  of which character caused it.
 
-      */
 
-     if (mode == OPTION_LOAD_KEEP) {
 
-         *(pzEnd++) = NUL;
 
-         return pzEnd;
 
-     }
 
-     /*
 
-      *  If the name ended on a white space character, remember that
 
-      *  because we'll have to skip over an immediately following ':' or '='
 
-      *  (and the white space following *that*).
 
-      */
 
-     space_break = isspace((int)*pzEnd);
 
-     *(pzEnd++) = NUL;
 
-     while (isspace((int)*pzEnd))  pzEnd++;
 
-     if (space_break && ((*pzEnd == ':') || (*pzEnd == '=')))
 
-         while (isspace((int)*++pzEnd))  ;
 
-     return pzEnd;
 
- }
 
- /*
 
-  *  Load an option from a block of text.  The text must start with the
 
-  *  configurable/option name and be followed by its associated value.
 
-  *  That value may be processed in any of several ways.  See "tOptionLoadMode"
 
-  *  in autoopts.h.
 
-  */
 
- LOCAL void
 
- loadOptionLine(
 
-     tOptions*   pOpts,
 
-     tOptState*  pOS,
 
-     char*       pzLine,
 
-     tDirection  direction,
 
-     tOptionLoadMode   load_mode )
 
- {
 
-     while (isspace( (int)*pzLine ))  pzLine++;
 
-     {
 
-         char* pzArg = assembleArgValue( pzLine, load_mode );
 
-         if (! SUCCESSFUL( longOptionFind( pOpts, pzLine, pOS )))
 
-             return;
 
-         if (pOS->flags & OPTST_NO_INIT)
 
-             return;
 
-         pOS->pzOptArg = pzArg;
 
-     }
 
-     switch (pOS->flags & (OPTST_IMM|OPTST_DISABLE_IMM)) {
 
-     case 0:
 
-         /*
 
-          *  The selected option has no immediate action.
 
-          *  THEREFORE, if the direction is PRESETTING
 
-          *  THEN we skip this option.
 
-          */
 
-         if (PRESETTING(direction))
 
-             return;
 
-         break;
 
-     case OPTST_IMM:
 
-         if (PRESETTING(direction)) {
 
-             /*
 
-              *  We are in the presetting direction with an option we handle
 
-              *  immediately for enablement, but normally for disablement.
 
-              *  Therefore, skip if disabled.
 
-              */
 
-             if ((pOS->flags & OPTST_DISABLED) == 0)
 
-                 return;
 
-         } else {
 
-             /*
 
-              *  We are in the processing direction with an option we handle
 
-              *  immediately for enablement, but normally for disablement.
 
-              *  Therefore, skip if NOT disabled.
 
-              */
 
-             if ((pOS->flags & OPTST_DISABLED) != 0)
 
-                 return;
 
-         }
 
-         break;
 
-     case OPTST_DISABLE_IMM:
 
-         if (PRESETTING(direction)) {
 
-             /*
 
-              *  We are in the presetting direction with an option we handle
 
-              *  immediately for disablement, but normally for disablement.
 
-              *  Therefore, skip if NOT disabled.
 
-              */
 
-             if ((pOS->flags & OPTST_DISABLED) != 0)
 
-                 return;
 
-         } else {
 
-             /*
 
-              *  We are in the processing direction with an option we handle
 
-              *  immediately for disablement, but normally for disablement.
 
-              *  Therefore, skip if disabled.
 
-              */
 
-             if ((pOS->flags & OPTST_DISABLED) == 0)
 
-                 return;
 
-         }
 
-         break;
 
-     case OPTST_IMM|OPTST_DISABLE_IMM:
 
-         /*
 
-          *  The selected option is always for immediate action.
 
-          *  THEREFORE, if the direction is PROCESSING
 
-          *  THEN we skip this option.
 
-          */
 
-         if (PROCESSING(direction))
 
-             return;
 
-         break;
 
-     }
 
-     /*
 
-      *  Fix up the args.
 
-      */
 
-     if (OPTST_GET_ARGTYPE(pOS->pOD->fOptState) == OPARG_TYPE_NONE) {
 
-         if (*pOS->pzOptArg != NUL)
 
-             return;
 
-         pOS->pzOptArg = NULL;
 
-     } else if (pOS->pOD->fOptState & OPTST_ARG_OPTIONAL) {
 
-         if (*pOS->pzOptArg == NUL)
 
-              pOS->pzOptArg = NULL;
 
-         else {
 
-             AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
 
-             pOS->flags |= OPTST_ALLOC_ARG;
 
-         }
 
-     } else {
 
-         if (*pOS->pzOptArg == NUL)
 
-              pOS->pzOptArg = zNil;
 
-         else {
 
-             AGDUPSTR( pOS->pzOptArg, pOS->pzOptArg, "option argument" );
 
-             pOS->flags |= OPTST_ALLOC_ARG;
 
-         }
 
-     }
 
-     {
 
-         tOptionLoadMode sv = option_load_mode;
 
-         option_load_mode = load_mode;
 
-         handleOption( pOpts, pOS );
 
-         option_load_mode = sv;
 
-     }
 
- }
 
- /*=export_func  optionLoadLine
 
-  *
 
-  * what:  process a string for an option name and value
 
-  *
 
-  * arg:   tOptions*,   pOpts,  program options descriptor
 
-  * arg:   char const*, pzLine, NUL-terminated text
 
-  *
 
-  * doc:
 
-  *
 
-  *  This is a client program callable routine for setting options from, for
 
-  *  example, the contents of a file that they read in.  Only one option may
 
-  *  appear in the text.  It will be treated as a normal (non-preset) option.
 
-  *
 
-  *  When passed a pointer to the option struct and a string, it will find
 
-  *  the option named by the first token on the string and set the option
 
-  *  argument to the remainder of the string.  The caller must NUL terminate
 
-  *  the string.  Any embedded new lines will be included in the option
 
-  *  argument.  If the input looks like one or more quoted strings, then the
 
-  *  input will be "cooked".  The "cooking" is identical to the string
 
-  *  formation used in AutoGen definition files (@pxref{basic expression}),
 
-  *  except that you may not use backquotes.
 
-  *
 
-  * err:   Invalid options are silently ignored.  Invalid option arguments
 
-  *        will cause a warning to print, but the function should return.
 
- =*/
 
- void
 
- optionLoadLine(
 
-     tOptions*  pOpts,
 
-     tCC*       pzLine )
 
- {
 
-     tOptState st = OPTSTATE_INITIALIZER(SET);
 
-     char* pz;
 
-     AGDUPSTR( pz, pzLine, "user option line" );
 
-     loadOptionLine( pOpts, &st, pz, DIRECTION_PROCESS, OPTION_LOAD_COOKED );
 
-     AGFREE( pz );
 
- }
 
- /*
 
-  * Local Variables:
 
-  * mode: C
 
-  * c-file-style: "stroustrup"
 
-  * indent-tabs-mode: nil
 
-  * End:
 
-  * end of autoopts/load.c */
 
 
  |