The CONF library. The CONF library is a simple set of routines that can be used to configure programs. It is a superset of the genenv() function with some extra structure. The library consists of 5 functions. LHASH *CONF_load(LHASH *config,char *file); This function is called to load in a configuration file. Multiple configuration files can be loaded, with each subsequent 'load' overwriting any already defined 'variables'. If there is an error, NULL is returned. If config is NULL, a new LHASH structure is created and returned, otherwise the new data in the 'file' is loaded into the 'config' structure. void CONF_free(LHASH *config); This function free()s the data in config. char *CONF_get_string(LHASH *config,char *section,char *name); This function returns the string found in 'config' that corresponds to the 'section' and 'name' specified. Classes and the naming system used will be discussed later in this document. If the variable is not defined, an NULL is returned. long CONF_get_long(LHASH *config,char *section, char *name); This function is the same as CONF_get_string() except that it converts the string to an long and returns it. If variable is not a number or the variable does not exist, 0 is returned. This is a little problematic but I don't know of a simple way around it. STACK *CONF_get_section(LHASH *config, char *section); This function returns a 'stack' of CONF_VALUE items that are all the items defined in a particular section. DO NOT free() any of the variable returned. They will disappear when CONF_free() is called. The 'lookup' model. The configuration file is divided into 'sections'. Each section is started by a line of the form '[ section ]'. All subsequent variable definitions are of this section. A variable definition is a simple alpha-numeric name followed by an '=' and then the data. A section or variable name can be described by a regular expression of the following form '[A-Za-z0-9_]+'. The value of the variable is the text after the '=' until the end of the line, stripped of leading and trailing white space. At this point I should mention that a '#' is a comment character, \ is the escape character, and all three types of quote can be used to stop any special interpretation of the data. Now when the data is being loaded, variable expansion can occur. This is done by expanding any $NAME sequences into the value represented by the variable NAME. If the variable is not in the current section, the different section can be specified by using the $SECTION::NAME form. The ${NAME} form also works and is very useful for expanding variables inside strings. When a variable is looked up, there are 2 special section. 'default', which is the initial section, and 'ENV' which is the processes environment variables (accessed via getenv()). When a variable is looked up, it is first 'matched' with it's section (if one was specified), if this fails, the 'default' section is matched. If the 'lhash' variable passed was NULL, the environment is searched. Now why do we bother with sections? So we can have multiple programs using the same configuration file, or multiple instances of the same program using different variables. It also provides a nice mechanism to override the processes environment variables (eg ENV::HOME=/tmp). If there is a program specific variable missing, we can have default values. Multiple configuration files can be loaded, with each new value clearing any predefined values. A system config file can provide 'default' values, and application/usr specific files can provide overriding values. Examples # This is a simple example SSLEAY_HOME = /usr/local/ssl ENV::PATH = $SSLEAY_HOME/bin:$PATH # override my path [X509] cert_dir = $SSLEAY_HOME/certs # /usr/local/ssl/certs [SSL] CIPHER = DES-EDE-MD5:RC4-MD5 USER_CERT = $HOME/${USER}di'r 5' # /home/eay/eaydir 5 USER_CERT = $HOME/\${USER}di\'r # /home/eay/${USER}di'r USER_CERT = "$HOME/${US"ER}di\'r # $HOME/${USER}di'r TEST = 1234\ 5678\ 9ab # TEST=123456789ab TTT = 1234\n\n # TTT=1234