4 * Id: f1650b45a91ec95af830ff76041cc4f0048e60f0
5 * Time-stamp: "2009-01-18 10:21:58 bkorb"
7 * configuration/rc/ini file handling.
9 * This file is part of AutoOpts, a companion to AutoGen.
10 * AutoOpts is free software.
11 * AutoOpts is copyright (c) 1992-2009 by Bruce Korb - all rights reserved
13 * AutoOpts is available under any one of two licenses. The license
14 * in use must be one of these two and the choice is under the control
15 * of the user of the license.
17 * The GNU Lesser General Public License, version 3 or later
18 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
20 * The Modified Berkeley Software Distribution License
21 * See the file "COPYING.mbsd"
23 * These files have the following md5sums:
25 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
26 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
27 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
30 /* = = = START-STATIC-FORWARD = = = */
31 /* static forward declarations maintained by mk-fwd */
35 char const* pzFileName
,
39 handleComment( char* pzText
);
69 tOptionValue
* pType
);
75 tOptionValue
* pType
);
80 tOptionValue
* pType
);
83 skipUnknown( char* pzText
);
84 /* = = = END-STATIC-FORWARD = = = */
87 /*=export_func configFileLoad
89 * what: parse a configuration file
90 * arg: + char const* + pzFile + the file to load +
92 * ret_type: const tOptionValue*
93 * ret_desc: An allocated, compound value structure
96 * This routine will load a named configuration file and parse the
97 * text as a hierarchically valued option. The option descriptor
98 * created from an option definition file is not used via this interface.
99 * The returned value is "named" with the input file name and is of
100 * type "@code{OPARG_TYPE_HIERARCHY}". It may be used in calls to
101 * @code{optionGetValue()}, @code{optionNextValue()} and
102 * @code{optionUnloadNested()}.
105 * If the file cannot be loaded or processed, @code{NULL} is returned and
106 * @var{errno} is set. It may be set by a call to either @code{open(2)}
107 * @code{mmap(2)} or other file system calls, or it may be:
110 * @code{ENOENT} - the file was empty.
112 * @code{EINVAL} - the file contents are invalid -- not properly formed.
114 * @code{ENOMEM} - not enough memory to allocate the needed structures.
118 configFileLoad( char const* pzFile
)
121 tOptionValue
* pRes
= NULL
;
122 tOptionLoadMode save_mode
= option_load_mode
;
125 text_mmap( pzFile
, PROT_READ
, MAP_PRIVATE
, &cfgfile
);
127 if (TEXT_MMAP_FAILED_ADDR(pzText
))
128 return NULL
; /* errno is set */
130 option_load_mode
= OPTION_LOAD_COOKED
;
131 pRes
= optionLoadNested(pzText
, pzFile
, strlen(pzFile
));
135 text_munmap( &cfgfile
);
138 text_munmap( &cfgfile
);
140 option_load_mode
= save_mode
;
145 /*=export_func optionFindValue
147 * what: find a hierarcicaly valued option instance
148 * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type +
149 * arg: + char const* + name + name of value to find +
150 * arg: + char const* + value + the matching value +
152 * ret_type: const tOptionValue*
153 * ret_desc: a compound value structure
156 * This routine will find an entry in a nested value option or configurable.
157 * It will search through the list and return a matching entry.
160 * The returned result is NULL and errno is set:
163 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
164 * hierarchical option value.
166 * @code{ENOENT} - no entry matched the given name.
170 optionFindValue( const tOptDesc
* pOptDesc
,
171 char const* pzName
, char const* pzVal
)
173 const tOptionValue
* pRes
= NULL
;
175 if ( (pOptDesc
== NULL
)
176 || (OPTST_GET_ARGTYPE(pOptDesc
->fOptState
) != OPARG_TYPE_HIERARCHY
)) {
180 else if (pOptDesc
->optCookie
== NULL
) {
185 tArgList
* pAL
= pOptDesc
->optCookie
;
187 void** ppOV
= (void**)(pAL
->apzArgs
);
194 if (pzName
== NULL
) {
195 pRes
= (tOptionValue
*)*ppOV
;
200 const tOptionValue
* pOV
= *(ppOV
++);
201 const tOptionValue
* pRV
= optionGetValue( pOV
, pzName
);
219 /*=export_func optionFindNextValue
221 * what: find a hierarcicaly valued option instance
222 * arg: + const tOptDesc* + pOptDesc + an option with a nested arg type +
223 * arg: + const tOptionValue* + pPrevVal + the last entry +
224 * arg: + char const* + name + name of value to find +
225 * arg: + char const* + value + the matching value +
227 * ret_type: const tOptionValue*
228 * ret_desc: a compound value structure
231 * This routine will find the next entry in a nested value option or
232 * configurable. It will search through the list and return the next entry
233 * that matches the criteria.
236 * The returned result is NULL and errno is set:
239 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
240 * hierarchical option value.
242 * @code{ENOENT} - no entry matched the given name.
246 optionFindNextValue( const tOptDesc
* pOptDesc
, const tOptionValue
* pPrevVal
,
247 char const* pzName
, char const* pzVal
)
250 tOptionValue
* pRes
= NULL
;
252 if ( (pOptDesc
== NULL
)
253 || (OPTST_GET_ARGTYPE(pOptDesc
->fOptState
) != OPARG_TYPE_HIERARCHY
)) {
257 else if (pOptDesc
->optCookie
== NULL
) {
262 tArgList
* pAL
= pOptDesc
->optCookie
;
264 void** ppOV
= (void**)pAL
->apzArgs
;
272 tOptionValue
* pOV
= *(ppOV
++);
288 /*=export_func optionGetValue
290 * what: get a specific value from a hierarcical list
291 * arg: + const tOptionValue* + pOptValue + a hierarchcal value +
292 * arg: + char const* + valueName + name of value to get +
294 * ret_type: const tOptionValue*
295 * ret_desc: a compound value structure
298 * This routine will find an entry in a nested value option or configurable.
299 * If "valueName" is NULL, then the first entry is returned. Otherwise,
300 * the first entry with a name that exactly matches the argument will be
304 * The returned result is NULL and errno is set:
307 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
308 * hierarchical option value.
310 * @code{ENOENT} - no entry matched the given name.
314 optionGetValue( const tOptionValue
* pOld
, char const* pzValName
)
317 tOptionValue
* pRes
= NULL
;
319 if ((pOld
== NULL
) || (pOld
->valType
!= OPARG_TYPE_HIERARCHY
)) {
323 pAL
= pOld
->v
.nestVal
;
325 if (pAL
->useCt
> 0) {
327 void** papOV
= (void**)(pAL
->apzArgs
);
329 if (pzValName
== NULL
) {
330 pRes
= (tOptionValue
*)*papOV
;
334 tOptionValue
* pOV
= *(papOV
++);
335 if (strcmp( pOV
->pzName
, pzValName
) == 0) {
347 /*=export_func optionNextValue
349 * what: get the next value from a hierarchical list
350 * arg: + const tOptionValue* + pOptValue + a hierarchcal list value +
351 * arg: + const tOptionValue* + pOldValue + a value from this list +
353 * ret_type: const tOptionValue*
354 * ret_desc: a compound value structure
357 * This routine will return the next entry after the entry passed in. At the
358 * end of the list, NULL will be returned. If the entry is not found on the
359 * list, NULL will be returned and "@var{errno}" will be set to EINVAL.
360 * The "@var{pOldValue}" must have been gotten from a prior call to this
361 * routine or to "@code{opitonGetValue()}".
364 * The returned result is NULL and errno is set:
367 * @code{EINVAL} - the @code{pOptValue} does not point to a valid
368 * hierarchical option value or @code{pOldValue} does not point to a
369 * member of that option value.
371 * @code{ENOENT} - the supplied @code{pOldValue} pointed to the last entry.
375 optionNextValue(tOptionValue
const * pOVList
,tOptionValue
const * pOldOV
)
378 tOptionValue
* pRes
= NULL
;
381 if ((pOVList
== NULL
) || (pOVList
->valType
!= OPARG_TYPE_HIERARCHY
)) {
385 pAL
= pOVList
->v
.nestVal
;
388 void** papNV
= (void**)(pAL
->apzArgs
);
391 tOptionValue
* pNV
= *(papNV
++);
398 pRes
= (tOptionValue
*)*papNV
;
412 * Load a file containing presetting information (a configuration file).
417 char const* pzFileName
,
421 tOptState optst
= OPTSTATE_INITIALIZER(PRESET
);
423 text_mmap( pzFileName
, PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, &cfgfile
);
425 if (TEXT_MMAP_FAILED_ADDR(pzFileText
))
428 if (direction
== DIRECTION_CALLED
) {
429 optst
.flags
= OPTST_DEFINED
;
430 direction
= DIRECTION_PROCESS
;
434 * IF this is called via "optionProcess", then we are presetting.
435 * This is the default and the PRESETTING bit will be set.
436 * If this is called via "optionFileLoad", then the bit is not set
437 * and we consider stuff set herein to be "set" by the client program.
439 if ((pOpts
->fOptSet
& OPTPROC_PRESETTING
) == 0)
440 optst
.flags
= OPTST_SET
;
443 while (IS_WHITESPACE_CHAR(*pzFileText
)) pzFileText
++;
445 if (IS_VAR_FIRST_CHAR(*pzFileText
)) {
446 pzFileText
= handleConfig(pOpts
, &optst
, pzFileText
, direction
);
448 } else switch (*pzFileText
) {
450 if (IS_VAR_FIRST_CHAR(pzFileText
[1]))
452 handleStructure(pOpts
, &optst
, pzFileText
, direction
);
454 else switch (pzFileText
[1]) {
456 pzFileText
= handleDirective( pOpts
, pzFileText
);
460 pzFileText
= handleComment( pzFileText
);
464 pzFileText
= strchr( pzFileText
+2, '>' );
465 if (pzFileText
++ != NULL
)
474 pzFileText
= handleProgramSection( pOpts
, pzFileText
);
478 pzFileText
= strchr( pzFileText
+1, '\n' );
482 goto all_done
; /* invalid format */
484 } while (pzFileText
!= NULL
);
487 text_munmap( &cfgfile
);
493 * "pzText" points to a "<!" sequence.
494 * Theoretically, we should ensure that it begins with "<!--",
495 * but actually I don't care that much. It ends with "-->".
498 handleComment( char* pzText
)
500 char* pz
= strstr( pzText
, "-->" );
509 * "pzText" points to the start of some value name.
510 * The end of the entry is the end of the line that is not preceded by
511 * a backslash escape character. The string value is always processed
521 char* pzName
= pzText
++;
522 char* pzEnd
= strchr( pzText
, '\n' );
525 return pzText
+ strlen(pzText
);
527 while (IS_VALUE_NAME_CHAR(*pzText
)) pzText
++;
528 while (IS_WHITESPACE_CHAR(*pzText
)) pzText
++;
529 if (pzText
> pzEnd
) {
532 loadOptionLine( pOpts
, pOS
, pzName
, direction
, OPTION_LOAD_UNCOOKED
);
537 * Either the first character after the name is a ':' or '=',
538 * or else we must have skipped over white space. Anything else
539 * is an invalid format and we give up parsing the text.
541 if ((*pzText
== '=') || (*pzText
== ':')) {
542 while (IS_WHITESPACE_CHAR(*++pzText
)) ;
545 } else if (! IS_WHITESPACE_CHAR(pzText
[-1]))
549 * IF the value is continued, remove the backslash escape and push "pzEnd"
550 * on to a newline *not* preceded by a backslash.
552 if (pzEnd
[-1] == '\\') {
579 * The newline was not preceded by a backslash. NUL it out
585 * "pzName" points to what looks like text for one option/configurable.
586 * It is NUL terminated. Process it.
588 loadOptionLine( pOpts
, pOS
, pzName
, direction
, OPTION_LOAD_UNCOOKED
);
596 * "pzText" points to a "<?" sequence.
597 * For the moment, we only handle "<?program" directives.
604 char ztitle
[32] = "<?";
605 size_t title_len
= strlen( zProg
);
608 if ( (strncmp( pzText
+2, zProg
, title_len
) != 0)
609 || (! IS_WHITESPACE_CHAR(pzText
[title_len
+2])) ) {
610 pzText
= strchr( pzText
+2, '>' );
616 name_len
= strlen( pOpts
->pzProgName
);
617 strcpy( ztitle
+2, zProg
);
623 if (IS_WHITESPACE_CHAR(*pzText
)) {
624 while (IS_WHITESPACE_CHAR(*++pzText
)) ;
625 if ( (strneqvcmp( pzText
, pOpts
->pzProgName
, (int)name_len
) == 0)
626 && (pzText
[name_len
] == '>')) {
627 pzText
+= name_len
+ 1;
632 pzText
= strstr( pzText
, ztitle
);
633 } while (pzText
!= NULL
);
639 /* handleProgramSection
641 * "pzText" points to a '[' character.
642 * The "traditional" [PROG_NAME] segmentation of the config file.
643 * Do not ever mix with the "<?program prog-name>" variation.
646 handleProgramSection(
650 size_t len
= strlen( pOpts
->pzPROGNAME
);
651 if ( (strncmp( pzText
+1, pOpts
->pzPROGNAME
, len
) == 0)
652 && (pzText
[len
+1] == ']'))
653 return strchr( pzText
+ len
+ 2, '\n' );
660 sprintf( z
, "[%s]", pOpts
->pzPROGNAME
);
661 pzText
= strstr( pzText
, z
);
665 pzText
= strchr( pzText
, '\n' );
672 * "pzText" points to a '<' character, followed by an alpha.
673 * The end of the entry is either the "/>" following the name, or else a
683 tOptionLoadMode mode
= option_load_mode
;
686 char* pzName
= ++pzText
;
690 while (IS_VALUE_NAME_CHAR(*pzText
)) pzText
++;
692 valu
.valType
= OPARG_TYPE_STRING
;
697 pzText
= parseAttributes( pOpts
, pzText
, &mode
, &valu
);
705 if (pzText
[1] != '>')
709 loadOptionLine( pOpts
, pOS
, pzName
, direction
, mode
);
716 pzText
= strchr( pzText
, '>');
723 * If we are here, we have a value. "pzText" points to a closing angle
724 * bracket. Separate the name from the value for a moment.
730 * Find the end of the option text and NUL terminate it
734 size_t len
= strlen(pzName
) + 4;
736 pz
= AGALOC(len
, "scan name");
738 sprintf( pz
, "</%s>", pzName
);
740 pzText
= strstr( pzText
, pz
);
741 if (pz
!= z
) AGFREE(pz
);
752 * Rejoin the name and value for parsing by "loadOptionLine()".
753 * Erase any attributes parsed by "parseAttributes()".
755 memset(pcNulPoint
, ' ', pzData
- pcNulPoint
);
758 * If we are getting a "string" value, the process the XML-ish
759 * %XX hex characters.
761 if (valu
.valType
== OPARG_TYPE_STRING
) {
762 char * pzSrc
= pzData
;
763 char * pzDst
= pzData
;
768 int ch
= ((int)*(pzSrc
++)) & 0xFF;
770 case NUL
: goto string_fixup_done
;
775 if ((bf
[0] == NUL
) || (bf
[1] == NUL
))
776 goto string_fixup_done
;
777 ch
= strtoul(bf
, NULL
, 16);
783 } string_fixup_done
:;
788 * "pzName" points to what looks like text for one option/configurable.
789 * It is NUL terminated. Process it.
791 loadOptionLine( pOpts
, pOS
, pzName
, direction
, mode
);
799 * Load a configuration file. This may be invoked either from
800 * scanning the "homerc" list, or from a specific file request.
801 * (see "optionFileLoad()", the implementation for --load-opts)
804 internalFileLoad( tOptions
* pOpts
)
809 char zFileName
[ AG_PATH_MAX
+1 ];
811 if (pOpts
->papzHomeList
== NULL
)
814 svfl
= pOpts
->fOptSet
;
815 inc
= DIRECTION_PRESET
;
818 * Never stop on errors in config files.
820 pOpts
->fOptSet
&= ~OPTPROC_ERRSTOP
;
823 * Find the last RC entry (highest priority entry)
825 for (idx
= 0; pOpts
->papzHomeList
[ idx
+1 ] != NULL
; ++idx
) ;
828 * For every path in the home list, ... *TWICE* We start at the last
829 * (highest priority) entry, work our way down to the lowest priority,
830 * handling the immediate options.
831 * Then we go back up, doing the normal options.
838 * IF we've reached the bottom end, change direction
841 inc
= DIRECTION_PROCESS
;
845 pzPath
= pOpts
->papzHomeList
[ idx
];
848 * IF we've reached the top end, bail out
855 if (! optionMakePath( zFileName
, (int)sizeof(zFileName
),
856 pzPath
, pOpts
->pzProgPath
))
860 * IF the file name we constructed is a directory,
861 * THEN append the Resource Configuration file name
862 * ELSE we must have the complete file name
864 if (stat( zFileName
, &StatBuf
) != 0)
865 continue; /* bogus name - skip the home list entry */
867 if (S_ISDIR( StatBuf
.st_mode
)) {
868 size_t len
= strlen( zFileName
);
871 if (len
+ 1 + strlen( pOpts
->pzRcName
) >= sizeof( zFileName
))
874 pz
= zFileName
+ len
;
877 strcpy( pz
, pOpts
->pzRcName
);
880 filePreset( pOpts
, zFileName
, inc
);
883 * IF we are now to skip config files AND we are presetting,
884 * THEN change direction. We must go the other way.
887 tOptDesc
* pOD
= pOpts
->pOptDesc
+ pOpts
->specOptIdx
.save_opts
+1;
888 if (DISABLED_OPT(pOD
) && PRESETTING(inc
)) {
889 idx
-= inc
; /* go back and reprocess current file */
890 inc
= DIRECTION_PROCESS
;
893 } /* twice for every path in the home list, ... */
895 pOpts
->fOptSet
= svfl
;
899 /*=export_func optionFileLoad
901 * what: Load the locatable config files, in order
903 * arg: + tOptions* + pOpts + program options descriptor +
904 * arg: + char const* + pzProg + program name +
907 * ret_desc: 0 -> SUCCESS, -1 -> FAILURE
911 * This function looks in all the specified directories for a configuration
912 * file ("rc" file or "ini" file) and processes any found twice. The first
913 * time through, they are processed in reverse order (last file first). At
914 * that time, only "immediate action" configurables are processed. For
915 * example, if the last named file specifies not processing any more
916 * configuration files, then no more configuration files will be processed.
917 * Such an option in the @strong{first} named directory will have no effect.
919 * Once the immediate action configurables have been handled, then the
920 * directories are handled in normal, forward order. In that way, later
921 * config files can override the settings of earlier config files.
923 * See the AutoOpts documentation for a thorough discussion of the
924 * config file format.
926 * Configuration files not found or not decipherable are simply ignored.
928 * err: Returns the value, "-1" if the program options descriptor
929 * is out of date or indecipherable. Otherwise, the value "0" will
930 * always be returned.
933 optionFileLoad( tOptions
* pOpts
, char const* pzProgram
)
935 if (! SUCCESSFUL( validateOptionsStruct( pOpts
, pzProgram
)))
938 pOpts
->pzProgName
= pzProgram
;
939 internalFileLoad( pOpts
);
944 /*=export_func optionLoadOpt
947 * what: Load an option rc/ini file
948 * arg: + tOptions* + pOpts + program options descriptor +
949 * arg: + tOptDesc* + pOptDesc + the descriptor for this arg +
952 * Processes the options found in the file named with
953 * pOptDesc->optArg.argString.
956 optionLoadOpt( tOptions
* pOpts
, tOptDesc
* pOptDesc
)
961 * IF the option is not being disabled, THEN load the file. There must
962 * be a file. (If it is being disabled, then the disablement processing
963 * already took place. It must be done to suppress preloading of ini/rc
966 if ( DISABLED_OPT(pOptDesc
)
967 || ((pOptDesc
->fOptState
& OPTST_RESET
) != 0))
970 if (stat( pOptDesc
->optArg
.argString
, &sb
) != 0) {
971 if ((pOpts
->fOptSet
& OPTPROC_ERRSTOP
) == 0)
974 fprintf( stderr
, zFSErrOptLoad
, errno
, strerror( errno
),
975 pOptDesc
->optArg
.argString
);
980 if (! S_ISREG( sb
.st_mode
)) {
981 if ((pOpts
->fOptSet
& OPTPROC_ERRSTOP
) == 0)
984 fprintf( stderr
, zNotFile
, pOptDesc
->optArg
.argString
);
989 filePreset(pOpts
, pOptDesc
->optArg
.argString
, DIRECTION_CALLED
);
995 * Parse the various attributes of an XML-styled config file entry
1001 tOptionLoadMode
* pMode
,
1002 tOptionValue
* pType
)
1007 if (! IS_WHITESPACE_CHAR(*pzText
))
1009 case '/': pType
->valType
= OPARG_TYPE_NONE
;
1010 case '>': return pzText
;
1013 case NUL
: return NULL
;
1016 while (IS_WHITESPACE_CHAR(*++pzText
)) ;
1018 while (IS_LOWER_CASE_CHAR(pzText
[len
])) len
++;
1020 switch (find_xat_attribute_id(pzText
, len
)) {
1022 pzText
= parseValueType( pzText
+len
, pType
);
1026 pzText
= parseKeyWordType( pOpts
, pzText
+len
, pType
);
1029 case XAT_KWD_MEMBERS
:
1030 pzText
= parseSetMemType( pOpts
, pzText
+len
, pType
);
1033 case XAT_KWD_COOKED
:
1035 if (! IS_END_XML_TOKEN_CHAR(*pzText
))
1038 *pMode
= OPTION_LOAD_COOKED
;
1041 case XAT_KWD_UNCOOKED
:
1043 if (! IS_END_XML_TOKEN_CHAR(*pzText
))
1046 *pMode
= OPTION_LOAD_UNCOOKED
;
1051 if (! IS_END_XML_TOKEN_CHAR(*pzText
))
1054 *pMode
= OPTION_LOAD_KEEP
;
1058 case XAT_KWD_INVALID
:
1060 pType
->valType
= OPARG_TYPE_NONE
;
1061 return skipUnknown( pzText
);
1063 } while (pzText
!= NULL
);
1071 * "pzText" points to the character after "words=".
1072 * What should follow is a name of a keyword (enumeration) list.
1078 tOptionValue
* pType
)
1080 return skipUnknown( pzText
);
1086 * "pzText" points to the character after "members="
1087 * What should follow is a name of a "set membership".
1088 * A collection of bit flags.
1094 tOptionValue
* pType
)
1096 return skipUnknown( pzText
);
1102 * "pzText" points to the character after "type="
1107 tOptionValue
* pType
)
1111 if (*(pzText
++) != '=')
1114 while (IS_OPTION_NAME_CHAR(pzText
[len
])) len
++;
1117 if ((len
== 0) || (! IS_END_XML_TOKEN_CHAR(*pzText
))) {
1119 pType
->valType
= OPARG_TYPE_NONE
;
1120 return skipUnknown( pzText
);
1123 switch (find_value_type_id(pzText
- len
, len
)) {
1125 case VTP_KWD_INVALID
: goto woops
;
1127 case VTP_KWD_STRING
:
1128 pType
->valType
= OPARG_TYPE_STRING
;
1131 case VTP_KWD_INTEGER
:
1132 pType
->valType
= OPARG_TYPE_NUMERIC
;
1136 case VTP_KWD_BOOLEAN
:
1137 pType
->valType
= OPARG_TYPE_BOOLEAN
;
1140 case VTP_KWD_KEYWORD
:
1141 pType
->valType
= OPARG_TYPE_ENUMERATION
;
1145 case VTP_KWD_SET_MEMBERSHIP
:
1146 pType
->valType
= OPARG_TYPE_MEMBERSHIP
;
1149 case VTP_KWD_NESTED
:
1150 case VTP_KWD_HIERARCHY
:
1151 pType
->valType
= OPARG_TYPE_HIERARCHY
;
1160 * Skip over some unknown attribute
1163 skipUnknown( char* pzText
)
1166 if (IS_END_XML_TOKEN_CHAR(*pzText
)) return pzText
;
1167 if (*pzText
== NUL
) return NULL
;
1172 /* validateOptionsStruct
1174 * Make sure the option descriptor is there and that we understand it.
1175 * This should be called from any user entry point where one needs to
1176 * worry about validity. (Some entry points are free to assume that
1177 * the call is not the first to the library and, thus, that this has
1178 * already been called.)
1181 validateOptionsStruct( tOptions
* pOpts
, char const* pzProgram
)
1183 if (pOpts
== NULL
) {
1184 fputs( zAO_Bad
, stderr
);
1189 * IF the client has enabled translation and the translation procedure
1190 * is available, then go do it.
1192 if ( ((pOpts
->fOptSet
& OPTPROC_TRANSLATE
) != 0)
1193 && (pOpts
->pTransProc
!= NULL
) ) {
1195 * If option names are not to be translated at all, then do not do
1196 * it for configuration parsing either. (That is the bit that really
1197 * gets tested anyway.)
1199 if ((pOpts
->fOptSet
& OPTPROC_NO_XLAT_MASK
) == OPTPROC_NXLAT_OPT
)
1200 pOpts
->fOptSet
|= OPTPROC_NXLAT_OPT_CFG
;
1201 (*pOpts
->pTransProc
)();
1202 pOpts
->fOptSet
&= ~OPTPROC_TRANSLATE
;
1206 * IF the struct version is not the current, and also
1207 * either too large (?!) or too small,
1208 * THEN emit error message and fail-exit
1210 if ( ( pOpts
->structVersion
!= OPTIONS_STRUCT_VERSION
)
1211 && ( (pOpts
->structVersion
> OPTIONS_STRUCT_VERSION
)
1212 || (pOpts
->structVersion
< OPTIONS_MINIMUM_VERSION
)
1215 fprintf(stderr
, zAO_Err
, pzProgram
, NUM_TO_VER(pOpts
->structVersion
));
1216 if (pOpts
->structVersion
> OPTIONS_STRUCT_VERSION
)
1217 fputs( zAO_Big
, stderr
);
1219 fputs( zAO_Sml
, stderr
);
1225 * If the program name hasn't been set, then set the name and the path
1226 * and the set of equivalent characters.
1228 if (pOpts
->pzProgName
== NULL
) {
1229 char const* pz
= strrchr( pzProgram
, DIRCH
);
1232 pOpts
->pzProgName
= pzProgram
;
1233 else pOpts
->pzProgName
= pz
+1;
1235 pOpts
->pzProgPath
= pzProgram
;
1238 * when comparing long names, these are equivalent
1240 strequate( zSepChars
);
1250 * c-file-style: "stroustrup"
1251 * indent-tabs-mode: nil
1253 * end of autoopts/configfile.c */