4 * Id: configfile.c,v 1.21 2007/04/15 19:01:18 bkorb Exp
5 * Time-stamp: "2007-04-15 11:22:46 bkorb"
7 * configuration/rc/ini file handling.
11 * Automated Options copyright 1992-2007 Bruce Korb
13 * Automated Options is free software.
14 * You may redistribute it and/or modify it under the terms of the
15 * GNU General Public License, as published by the Free Software
16 * Foundation; either version 2, or (at your option) any later version.
18 * Automated Options is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Automated Options. See the file "COPYING". If not,
25 * write to: The Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
29 * As a special exception, Bruce Korb gives permission for additional
30 * uses of the text contained in his release of AutoOpts.
32 * The exception is that, if you link the AutoOpts library with other
33 * files to produce an executable, this does not by itself cause the
34 * resulting executable to be covered by the GNU General Public License.
35 * Your use of that executable is in no way restricted on account of
36 * linking the AutoOpts library code into it.
38 * This exception does not however invalidate any other reasons why
39 * the executable file might be covered by the GNU General Public License.
41 * This exception applies only to the code released by Bruce Korb under
42 * the name AutoOpts. If you copy code from other sources under the
43 * General Public License into a copy of AutoOpts, as the General Public
44 * License permits, the exception does not apply to the code that you add
45 * in this way. To avoid misleading anyone as to the status of such
46 * modified files, you must delete this exception notice from them.
48 * If you write modifications of your own for AutoOpts, it is your choice
49 * whether to permit this exception to apply to your modifications.
50 * If you do not wish that, delete this exception notice.
53 /* = = = START-STATIC-FORWARD = = = */
54 /* static forward declarations maintained by :mkfwd */
58 char const* pzFileName
,
62 handleComment( char* pzText
);
92 tOptionValue
* pType
);
97 tOptionLoadMode
* pMode
);
103 tOptionValue
* pType
);
108 tOptionValue
* pType
);
111 skipUnknown( char* pzText
);
112 /* = = = END-STATIC-FORWARD = = = */
115 /*=export_func configFileLoad
117 * what: parse a configuration file
118 * arg: + char const* + pzFile + the file to load +
120 * ret_type: const tOptionValue*
121 * ret_desc: An allocated, compound value structure
124 * This routine will load a named configuration file and parse the
125 * text as a hierarchically valued option. The option descriptor
126 * created from an option definition file is not used via this interface.
127 * The returned value is "named" with the input file name and is of
128 * type "@code{OPARG_TYPE_HIERARCHY}". It may be used in calls to
129 * @code{optionGetValue()}, @code{optionNextValue()} and
130 * @code{optionUnloadNested()}.
133 * If the file cannot be loaded or processed, @code{NULL} is returned and
134 * @var{errno} is set. It may be set by a call to either @code{open(2)}
135 * @code{mmap(2)} or other file system calls, or it may be:
138 * @code{ENOENT} - the file was empty.
140 * @code{EINVAL} - the file contents are invalid -- not properly formed.
142 * @code{ENOMEM} - not enough memory to allocate the needed structures.
146 configFileLoad( char const* pzFile
)
149 tOptionValue
* pRes
= NULL
;
150 tOptionLoadMode save_mode
= option_load_mode
;
153 text_mmap( pzFile
, PROT_READ
, MAP_PRIVATE
, &cfgfile
);
155 if (TEXT_MMAP_FAILED_ADDR(pzText
))
156 return NULL
; /* errno is set */
158 option_load_mode
= OPTION_LOAD_COOKED
;
159 pRes
= optionLoadNested(pzText
, pzFile
, strlen(pzFile
));
163 text_munmap( &cfgfile
);
166 text_munmap( &cfgfile
);
168 option_load_mode
= save_mode
;
173 /*=export_func optionFindValue
175 * what: find a hierarcicaly valued option instance
176 * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type +
177 * arg: + char const* + name + name of value to find +
178 * arg: + char const* + value + the matching value +
180 * ret_type: const tOptionValue*
181 * ret_desc: a compound value structure
184 * This routine will find an entry in a nested value option or configurable.
185 * It will search through the list and return a matching entry.
188 * The returned result is NULL and errno is set:
191 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
192 * hierarchical option value.
194 * @code{ENOENT} - no entry matched the given name.
198 optionFindValue( const tOptDesc
* pOptDesc
,
199 char const* pzName
, char const* pzVal
)
201 const tOptionValue
* pRes
= NULL
;
203 if ( (pOptDesc
== NULL
)
204 || (OPTST_GET_ARGTYPE(pOptDesc
->fOptState
) != OPARG_TYPE_HIERARCHY
)) {
208 else if (pOptDesc
->optCookie
== NULL
) {
213 tArgList
* pAL
= pOptDesc
->optCookie
;
215 void** ppOV
= (void**)(pAL
->apzArgs
);
222 if (pzName
== NULL
) {
223 pRes
= (tOptionValue
*)*ppOV
;
228 const tOptionValue
* pOV
= *(ppOV
++);
229 const tOptionValue
* pRV
= optionGetValue( pOV
, pzName
);
247 /*=export_func optionFindNextValue
249 * what: find a hierarcicaly valued option instance
250 * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type +
251 * arg: + const tOptionValue* + pPrevVal + the last entry +
252 * arg: + char const* + name + name of value to find +
253 * arg: + char const* + value + the matching value +
255 * ret_type: const tOptionValue*
256 * ret_desc: a compound value structure
259 * This routine will find the next entry in a nested value option or
260 * configurable. It will search through the list and return the next entry
261 * that matches the criteria.
264 * The returned result is NULL and errno is set:
267 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
268 * hierarchical option value.
270 * @code{ENOENT} - no entry matched the given name.
274 optionFindNextValue( const tOptDesc
* pOptDesc
, const tOptionValue
* pPrevVal
,
275 char const* pzName
, char const* pzVal
)
278 tOptionValue
* pRes
= NULL
;
280 if ( (pOptDesc
== NULL
)
281 || (OPTST_GET_ARGTYPE(pOptDesc
->fOptState
) != OPARG_TYPE_HIERARCHY
)) {
285 else if (pOptDesc
->optCookie
== NULL
) {
290 tArgList
* pAL
= pOptDesc
->optCookie
;
292 void** ppOV
= (void**)pAL
->apzArgs
;
300 tOptionValue
* pOV
= *(ppOV
++);
316 /*=export_func optionGetValue
318 * what: get a specific value from a hierarcical list
319 * arg: + const tOptionValue* + pOptValue + a hierarchcal value +
320 * arg: + char const* + valueName + name of value to get +
322 * ret_type: const tOptionValue*
323 * ret_desc: a compound value structure
326 * This routine will find an entry in a nested value option or configurable.
327 * If "valueName" is NULL, then the first entry is returned. Otherwise,
328 * the first entry with a name that exactly matches the argument will be
332 * The returned result is NULL and errno is set:
335 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
336 * hierarchical option value.
338 * @code{ENOENT} - no entry matched the given name.
342 optionGetValue( const tOptionValue
* pOld
, char const* pzValName
)
345 tOptionValue
* pRes
= NULL
;
347 if ((pOld
== NULL
) || (pOld
->valType
!= OPARG_TYPE_HIERARCHY
)) {
351 pAL
= pOld
->v
.nestVal
;
353 if (pAL
->useCt
> 0) {
355 void** papOV
= (void**)(pAL
->apzArgs
);
357 if (pzValName
== NULL
) {
358 pRes
= (tOptionValue
*)*papOV
;
362 tOptionValue
* pOV
= *(papOV
++);
363 if (strcmp( pOV
->pzName
, pzValName
) == 0) {
375 /*=export_func optionNextValue
377 * what: get the next value from a hierarchical list
378 * arg: + const tOptionValue* + pOptValue + a hierarchcal list value +
379 * arg: + const tOptionValue* + pOldValue + a value from this list +
381 * ret_type: const tOptionValue*
382 * ret_desc: a compound value structure
385 * This routine will return the next entry after the entry passed in. At the
386 * end of the list, NULL will be returned. If the entry is not found on the
387 * list, NULL will be returned and "@var{errno}" will be set to EINVAL.
388 * The "@var{pOldValue}" must have been gotten from a prior call to this
389 * routine or to "@code{opitonGetValue()}".
392 * The returned result is NULL and errno is set:
395 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
396 * hierarchical option value or @code{pOldValue} does not point to a
397 * member of that option value.
399 * @code{ENOENT} - the supplied @code{pOldValue} pointed to the last entry.
403 optionNextValue(tOptionValue
const * pOVList
,tOptionValue
const * pOldOV
)
406 tOptionValue
* pRes
= NULL
;
409 if ((pOVList
== NULL
) || (pOVList
->valType
!= OPARG_TYPE_HIERARCHY
)) {
413 pAL
= pOVList
->v
.nestVal
;
416 void** papNV
= (void**)(pAL
->apzArgs
);
419 tOptionValue
* pNV
= *(papNV
++);
426 pRes
= (tOptionValue
*)*papNV
;
440 * Load a file containing presetting information (a configuration file).
445 char const* pzFileName
,
449 tOptState st
= OPTSTATE_INITIALIZER(PRESET
);
451 text_mmap( pzFileName
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, &cfgfile
);
453 if (TEXT_MMAP_FAILED_ADDR(pzFileText
))
456 if (direction
== DIRECTION_CALLED
) {
457 st
.flags
= OPTST_DEFINED
;
458 direction
= DIRECTION_PROCESS
;
462 * IF this is called via "optionProcess", then we are presetting.
463 * This is the default and the PRESETTING bit will be set.
464 * If this is called via "optionFileLoad", then the bit is not set
465 * and we consider stuff set herein to be "set" by the client program.
467 if ((pOpts
->fOptSet
& OPTPROC_PRESETTING
) == 0)
468 st
.flags
= OPTST_SET
;
471 while (isspace( (int)*pzFileText
)) pzFileText
++;
473 if (isalpha( (int)*pzFileText
)) {
474 pzFileText
= handleConfig( pOpts
, &st
, pzFileText
, direction
);
476 } else switch (*pzFileText
) {
478 if (isalpha( (int)pzFileText
[1] ))
479 pzFileText
= handleStructure(pOpts
, &st
, pzFileText
, direction
);
481 else switch (pzFileText
[1]) {
483 pzFileText
= handleDirective( pOpts
, pzFileText
);
487 pzFileText
= handleComment( pzFileText
);
491 pzFileText
= strchr( pzFileText
+2, '>' );
492 if (pzFileText
++ != NULL
)
501 pzFileText
= handleProgramSection( pOpts
, pzFileText
);
505 pzFileText
= strchr( pzFileText
+1, '\n' );
509 goto all_done
; /* invalid format */
511 } while (pzFileText
!= NULL
);
514 text_munmap( &cfgfile
);
520 * "pzText" points to a "<!" sequence.
521 * Theoretically, we should ensure that it begins with "<!--",
522 * but actually I don't care that much. It ends with "-->".
525 handleComment( char* pzText
)
527 char* pz
= strstr( pzText
, "-->" );
536 * "pzText" points to the start of some value name.
537 * The end of the entry is the end of the line that is not preceded by
538 * a backslash escape character. The string value is always processed
548 char* pzName
= pzText
++;
549 char* pzEnd
= strchr( pzText
, '\n' );
552 return pzText
+ strlen(pzText
);
554 while (ISNAMECHAR( (int)*pzText
)) pzText
++;
555 while (isspace( (int)*pzText
)) pzText
++;
556 if (pzText
> pzEnd
) {
559 loadOptionLine( pOpts
, pOS
, pzName
, direction
, OPTION_LOAD_UNCOOKED
);
564 * Either the first character after the name is a ':' or '=',
565 * or else we must have skipped over white space. Anything else
566 * is an invalid format and we give up parsing the text.
568 if ((*pzText
== '=') || (*pzText
== ':')) {
569 while (isspace( (int)*++pzText
)) ;
572 } else if (! isspace((int)pzText
[-1]))
576 * IF the value is continued, remove the backslash escape and push "pzEnd"
577 * on to a newline *not* preceded by a backslash.
579 if (pzEnd
[-1] == '\\') {
606 * The newline was not preceded by a backslash. NUL it out
612 * "pzName" points to what looks like text for one option/configurable.
613 * It is NUL terminated. Process it.
615 loadOptionLine( pOpts
, pOS
, pzName
, direction
, OPTION_LOAD_UNCOOKED
);
623 * "pzText" points to a "<?" sequence.
624 * For the moment, we only handle "<?program" directives.
631 char ztitle
[32] = "<?";
632 size_t title_len
= strlen( zProg
);
635 if ( (strncmp( pzText
+2, zProg
, title_len
) != 0)
636 || (! isspace( (int)pzText
[title_len
+2] )) ) {
637 pzText
= strchr( pzText
+2, '>' );
643 name_len
= strlen( pOpts
->pzProgName
);
644 strcpy( ztitle
+2, zProg
);
650 if (isspace((int)*pzText
)) {
651 while (isspace((int)*pzText
)) pzText
++;
652 if ( (strneqvcmp( pzText
, pOpts
->pzProgName
, (int)name_len
) == 0)
653 && (pzText
[name_len
] == '>')) {
654 pzText
+= name_len
+ 1;
659 pzText
= strstr( pzText
, ztitle
);
660 } while (pzText
!= NULL
);
666 /* handleProgramSection
668 * "pzText" points to a '[' character.
669 * The "traditional" [PROG_NAME] segmentation of the config file.
670 * Do not ever mix with the "<?program prog-name>" variation.
673 handleProgramSection(
677 size_t len
= strlen( pOpts
->pzPROGNAME
);
678 if ( (strncmp( pzText
+1, pOpts
->pzPROGNAME
, len
) == 0)
679 && (pzText
[len
+1] == ']'))
680 return strchr( pzText
+ len
+ 2, '\n' );
687 sprintf( z
, "[%s]", pOpts
->pzPROGNAME
);
688 pzText
= strstr( pzText
, z
);
692 pzText
= strchr( pzText
, '\n' );
699 * "pzText" points to a '<' character, followed by an alpha.
700 * The end of the entry is either the "/>" following the name, or else a
710 tOptionLoadMode mode
= option_load_mode
;
713 char* pzName
= ++pzText
;
717 while (ISNAMECHAR( *pzText
)) pzText
++;
719 valu
.valType
= OPARG_TYPE_STRING
;
724 pzText
= parseAttributes( pOpts
, pzText
, &mode
, &valu
);
732 if (pzText
[1] != '>')
736 loadOptionLine( pOpts
, pOS
, pzName
, direction
, mode
);
743 pzText
= strchr( pzText
, '>');
750 * If we are here, we have a value. "pzText" points to a closing angle
751 * bracket. Separate the name from the value for a moment.
757 * Find the end of the option text and NUL terminate it
761 size_t len
= strlen(pzName
) + 4;
763 pz
= AGALOC(len
, "scan name");
765 sprintf( pz
, "</%s>", pzName
);
767 pzText
= strstr( pzText
, pz
);
768 if (pz
!= z
) AGFREE(pz
);
779 * Rejoin the name and value for parsing by "loadOptionLine()".
780 * Erase any attributes parsed by "parseAttributes()".
782 memset(pcNulPoint
, ' ', pzData
- pcNulPoint
);
785 * "pzName" points to what looks like text for one option/configurable.
786 * It is NUL terminated. Process it.
788 loadOptionLine( pOpts
, pOS
, pzName
, direction
, mode
);
796 * Load a configuration file. This may be invoked either from
797 * scanning the "homerc" list, or from a specific file request.
798 * (see "optionFileLoad()", the implementation for --load-opts)
801 internalFileLoad( tOptions
* pOpts
)
804 int inc
= DIRECTION_PRESET
;
805 char zFileName
[ AG_PATH_MAX
+1 ];
807 if (pOpts
->papzHomeList
== NULL
)
811 * Find the last RC entry (highest priority entry)
813 for (idx
= 0; pOpts
->papzHomeList
[ idx
+1 ] != NULL
; ++idx
) ;
816 * For every path in the home list, ... *TWICE* We start at the last
817 * (highest priority) entry, work our way down to the lowest priority,
818 * handling the immediate options.
819 * Then we go back up, doing the normal options.
826 * IF we've reached the bottom end, change direction
829 inc
= DIRECTION_PROCESS
;
833 pzPath
= pOpts
->papzHomeList
[ idx
];
836 * IF we've reached the top end, bail out
843 if (! optionMakePath( zFileName
, (int)sizeof(zFileName
),
844 pzPath
, pOpts
->pzProgPath
))
848 * IF the file name we constructed is a directory,
849 * THEN append the Resource Configuration file name
850 * ELSE we must have the complete file name
852 if (stat( zFileName
, &StatBuf
) != 0)
853 continue; /* bogus name - skip the home list entry */
855 if (S_ISDIR( StatBuf
.st_mode
)) {
856 size_t len
= strlen( zFileName
);
859 if (len
+ 1 + strlen( pOpts
->pzRcName
) >= sizeof( zFileName
))
862 pz
= zFileName
+ len
;
865 strcpy( pz
, pOpts
->pzRcName
);
868 filePreset( pOpts
, zFileName
, inc
);
871 * IF we are now to skip config files AND we are presetting,
872 * THEN change direction. We must go the other way.
875 tOptDesc
* pOD
= pOpts
->pOptDesc
+ pOpts
->specOptIdx
.save_opts
+1;
876 if (DISABLED_OPT(pOD
) && PRESETTING(inc
)) {
877 idx
-= inc
; /* go back and reprocess current file */
878 inc
= DIRECTION_PROCESS
;
881 } /* twice for every path in the home list, ... */
885 /*=export_func optionFileLoad
887 * what: Load the locatable config files, in order
889 * arg: + tOptions* + pOpts + program options descriptor +
890 * arg: + char const* + pzProg + program name +
893 * ret_desc: 0 -> SUCCESS, -1 -> FAILURE
897 * This function looks in all the specified directories for a configuration
898 * file ("rc" file or "ini" file) and processes any found twice. The first
899 * time through, they are processed in reverse order (last file first). At
900 * that time, only "immediate action" configurables are processed. For
901 * example, if the last named file specifies not processing any more
902 * configuration files, then no more configuration files will be processed.
903 * Such an option in the @strong{first} named directory will have no effect.
905 * Once the immediate action configurables have been handled, then the
906 * directories are handled in normal, forward order. In that way, later
907 * config files can override the settings of earlier config files.
909 * See the AutoOpts documentation for a thorough discussion of the
910 * config file format.
912 * Configuration files not found or not decipherable are simply ignored.
914 * err: Returns the value, "-1" if the program options descriptor
915 * is out of date or indecipherable. Otherwise, the value "0" will
916 * always be returned.
919 optionFileLoad( tOptions
* pOpts
, char const* pzProgram
)
921 if (! SUCCESSFUL( validateOptionsStruct( pOpts
, pzProgram
)))
924 pOpts
->pzProgName
= pzProgram
;
925 internalFileLoad( pOpts
);
930 /*=export_func optionLoadOpt
933 * what: Load an option rc/ini file
934 * arg: + tOptions* + pOpts + program options descriptor +
935 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg +
938 * Processes the options found in the file named with
939 * pOptDesc->optArg.argString.
942 optionLoadOpt( tOptions
* pOpts
, tOptDesc
* pOptDesc
)
945 * IF the option is not being disabled, THEN load the file. There must
946 * be a file. (If it is being disabled, then the disablement processing
947 * already took place. It must be done to suppress preloading of ini/rc
950 if (! DISABLED_OPT( pOptDesc
)) {
952 if (stat( pOptDesc
->optArg
.argString
, &sb
) != 0) {
953 if ((pOpts
->fOptSet
& OPTPROC_ERRSTOP
) == 0)
956 fprintf( stderr
, zFSErrOptLoad
, errno
, strerror( errno
),
957 pOptDesc
->optArg
.argString
);
962 if (! S_ISREG( sb
.st_mode
)) {
963 if ((pOpts
->fOptSet
& OPTPROC_ERRSTOP
) == 0)
966 fprintf( stderr
, zNotFile
, pOptDesc
->optArg
.argString
);
971 filePreset(pOpts
, pOptDesc
->optArg
.argString
, DIRECTION_CALLED
);
978 * Parse the various attributes of an XML-styled config file entry
984 tOptionLoadMode
* pMode
,
985 tOptionValue
* pType
)
987 size_t lenLoadType
= strlen( zLoadType
);
988 size_t lenKeyWords
= strlen( zKeyWords
);
989 size_t lenSetMem
= strlen( zSetMembers
);
993 case '/': pType
->valType
= OPARG_TYPE_NONE
;
994 case '>': return pzText
;
997 case NUL
: return NULL
;
1008 while (isspace( (int)*++pzText
)) ;
1010 if (strncmp( pzText
, zLoadType
, lenLoadType
) == 0) {
1011 pzText
= parseValueType( pzText
+lenLoadType
, pType
);
1015 if (strncmp( pzText
, zKeyWords
, lenKeyWords
) == 0) {
1016 pzText
= parseKeyWordType( pOpts
, pzText
+lenKeyWords
, pType
);
1020 if (strncmp( pzText
, zSetMembers
, lenSetMem
) == 0) {
1021 pzText
= parseSetMemType( pOpts
, pzText
+lenSetMem
, pType
);
1025 pzText
= parseLoadMode( pzText
, pMode
);
1026 } while (pzText
!= NULL
);
1034 * "pzText" points to the character after "words=".
1035 * What should follow is a name of a keyword (enumeration) list.
1041 tOptionValue
* pType
)
1043 return skipUnknown( pzText
);
1049 * "pzText" points to some name character. We check for "cooked" or
1050 * "uncooked" or "keep". This function should handle any attribute
1051 * that does not have an associated value.
1056 tOptionLoadMode
* pMode
)
1059 size_t len
= strlen(zLoadCooked
);
1060 if (strncmp( pzText
, zLoadCooked
, len
) == 0) {
1061 if ( (pzText
[len
] == '>')
1062 || (pzText
[len
] == '/')
1063 || isspace((int)pzText
[len
])) {
1064 *pMode
= OPTION_LOAD_COOKED
;
1065 return pzText
+ len
;
1072 size_t len
= strlen(zLoadUncooked
);
1073 if (strncmp( pzText
, zLoadUncooked
, len
) == 0) {
1074 if ( (pzText
[len
] == '>')
1075 || (pzText
[len
] == '/')
1076 || isspace((int)pzText
[len
])) {
1077 *pMode
= OPTION_LOAD_UNCOOKED
;
1078 return pzText
+ len
;
1085 size_t len
= strlen(zLoadKeep
);
1086 if (strncmp( pzText
, zLoadKeep
, len
) == 0) {
1087 if ( (pzText
[len
] == '>')
1088 || (pzText
[len
] == '/')
1089 || isspace((int)pzText
[len
])) {
1090 *pMode
= OPTION_LOAD_KEEP
;
1091 return pzText
+ len
;
1098 return skipUnknown( pzText
);
1104 * "pzText" points to the character after "members="
1105 * What should follow is a name of a "set membership".
1106 * A collection of bit flags.
1112 tOptionValue
* pType
)
1114 return skipUnknown( pzText
);
1120 * "pzText" points to the character after "type="
1125 tOptionValue
* pType
)
1128 size_t len
= strlen(zLtypeString
);
1129 if (strncmp( pzText
, zLtypeString
, len
) == 0) {
1130 if ((pzText
[len
] == '>') || isspace((int)pzText
[len
])) {
1131 pType
->valType
= OPARG_TYPE_STRING
;
1132 return pzText
+ len
;
1139 size_t len
= strlen(zLtypeInteger
);
1140 if (strncmp( pzText
, zLtypeInteger
, len
) == 0) {
1141 if ((pzText
[len
] == '>') || isspace((int)pzText
[len
])) {
1142 pType
->valType
= OPARG_TYPE_NUMERIC
;
1143 return pzText
+ len
;
1150 size_t len
= strlen(zLtypeBool
);
1151 if (strncmp( pzText
, zLtypeBool
, len
) == 0) {
1152 if ((pzText
[len
] == '>') || isspace(pzText
[len
])) {
1153 pType
->valType
= OPARG_TYPE_BOOLEAN
;
1154 return pzText
+ len
;
1161 size_t len
= strlen(zLtypeKeyword
);
1162 if (strncmp( pzText
, zLtypeKeyword
, len
) == 0) {
1163 if ((pzText
[len
] == '>') || isspace((int)pzText
[len
])) {
1164 pType
->valType
= OPARG_TYPE_ENUMERATION
;
1165 return pzText
+ len
;
1172 size_t len
= strlen(zLtypeSetMembership
);
1173 if (strncmp( pzText
, zLtypeSetMembership
, len
) == 0) {
1174 if ((pzText
[len
] == '>') || isspace((int)pzText
[len
])) {
1175 pType
->valType
= OPARG_TYPE_MEMBERSHIP
;
1176 return pzText
+ len
;
1183 size_t len
= strlen(zLtypeNest
);
1184 if (strncmp( pzText
, zLtypeNest
, len
) == 0) {
1185 if ((pzText
[len
] == '>') || isspace((int)pzText
[len
])) {
1186 pType
->valType
= OPARG_TYPE_HIERARCHY
;
1187 return pzText
+ len
;
1194 pType
->valType
= OPARG_TYPE_NONE
;
1195 return skipUnknown( pzText
);
1201 * Skip over some unknown attribute
1204 skipUnknown( char* pzText
)
1207 if (isspace( (int)*pzText
)) return pzText
;
1209 case NUL
: return NULL
;
1211 case '>': return pzText
;
1217 /* validateOptionsStruct
1219 * Make sure the option descriptor is there and that we understand it.
1220 * This should be called from any user entry point where one needs to
1221 * worry about validity. (Some entry points are free to assume that
1222 * the call is not the first to the library and, thus, that this has
1223 * already been called.)
1226 validateOptionsStruct( tOptions
* pOpts
, char const* pzProgram
)
1228 if (pOpts
== NULL
) {
1229 fputs( zAO_Bad
, stderr
);
1234 * IF the client has enabled translation and the translation procedure
1235 * is available, then go do it.
1237 if ( ((pOpts
->fOptSet
& OPTPROC_TRANSLATE
) != 0)
1238 && (pOpts
->pTransProc
!= 0) ) {
1239 (*pOpts
->pTransProc
)();
1240 pOpts
->fOptSet
&= ~OPTPROC_TRANSLATE
;
1244 * IF the struct version is not the current, and also
1245 * either too large (?!) or too small,
1246 * THEN emit error message and fail-exit
1248 if ( ( pOpts
->structVersion
!= OPTIONS_STRUCT_VERSION
)
1249 && ( (pOpts
->structVersion
> OPTIONS_STRUCT_VERSION
)
1250 || (pOpts
->structVersion
< OPTIONS_MINIMUM_VERSION
)
1253 fprintf( stderr
, zAO_Err
, pOpts
->origArgVect
[0],
1254 NUM_TO_VER( pOpts
->structVersion
));
1255 if (pOpts
->structVersion
> OPTIONS_STRUCT_VERSION
)
1256 fputs( zAO_Big
, stderr
);
1258 fputs( zAO_Sml
, stderr
);
1264 * If the program name hasn't been set, then set the name and the path
1265 * and the set of equivalent characters.
1267 if (pOpts
->pzProgName
== NULL
) {
1268 char const* pz
= strrchr( pzProgram
, DIRCH
);
1271 pOpts
->pzProgName
= pzProgram
;
1272 else pOpts
->pzProgName
= pz
+1;
1274 pOpts
->pzProgPath
= pzProgram
;
1277 * when comparing long names, these are equivalent
1279 strequate( zSepChars
);
1289 * c-file-style: "stroustrup"
1290 * indent-tabs-mode: nil
1292 * end of autoopts/configfile.c */