[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10 Configuring your program

AutoOpts supports the notion of presetting the value or state of an option. The values may be obtained either from environment variables or from configuration files (‘rc’ or ‘ini’ files). In order to take advantage of this, the AutoOpts client program must specify these features in the option descriptor file (see section Program Description Attributes) with the rcfile or environrc attributes.

It is also possible to configure your program without using the command line option parsing code. This is done by using only the following four functions from the ‘libopts’ library:

configFileLoad

(see section configFileLoad) will parse the contents of a config file and return a pointer to a structure representing the hierarchical value. The values are sorted alphabetically by the value name and all entries with the same name will retain their original order. Insertion sort is used.

optionGetValue

(see section optionGetValue) will find the first value within the hierarchy with a name that matches the name passed in.

optionNextValue

(see section optionNextValue) will return the next value that follows the value passed in as an argument. If you wish to get all the values for a particular name, you must take note when the name changes.

optionUnloadNested

(see section optionUnloadNested). The pointer passed in must be of type, OPARG_TYPE_HIERARCHY (see the autoopts/options.h header file). configFileLoad will return a tOptionValue pointer of that type. This function will release all the associated memory. AutoOpts generated code uses this function for its own needs. Client code should only call this function with pointers gotten from configFileLoad.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10.1 configuration file presets

Configuration files are enabled by specifying the program attribute homerc (see section Program Description Attributes). Any option not marked with the no-preset attribute may appear in a configuration file. The files loaded are selected both by the homerc entries and, optionally, via a command line option. The first component of the homerc entry may be an environment variable such as $HOME, or it may also be ‘$$’ (two dollar sign characters) to specify the directory of the executable. For example:

 
homerc = "$$/../share/autogen";

will cause the AutoOpts library to look in the normal autogen datadir relative to the current installation directory for autogen.

The configuration files are processed in the order they are specified by the homerc attribute, so that each new file will normally override the settings of the previous files. This may be overridden by marking some options for immediate action (see section Immediate Action Attributes). Any such options are acted upon in reverse order. The disabled load-opts (‘--no-load-opts’) option, for example, is an immediate action option. Its presence in the last homerc file will prevent the processing of any prior homerc files because its effect is immediate.

Configuration file processing can be completely suppressed by specifying ‘--no-load-opts’ on the command line, or PROGRAM_LOAD_OPTS=no in the environment (if environrc has been specified).

See the Configuration File Format section (see section Configuration File Format) for details on the format of the file.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10.2 Saving the presets into a configuration file

When configuration files are enabled for an application, the user is also provided with an automatically supplied ‘--save-opts’ option. All of the known option state will be written to either the specified output file or, if it is not specified, then to the last specified homerc file.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10.3 Creating a sample configuration file

AutoOpts is shipped with a template named, ‘rc-sample.tpl’. If your option definition file specifies the homerc attribute, then you may invoke ‘autogen’ thus:

 
autogen -Trc-sample <your-option-def-file>

This will, by default, produce a sample file named, ‘sample-<prog-name>rc’. It will be named differently if you specify your configuration (rc) file name with the rcfile attribute. In that case, the output file will be named, ‘sample-<rcfile-name>’. It will contain all of the program options not marked as no-preset. It will also include the text from the doc attribute.

Doing so with getdefs’ option definitions yields this sample-getdefsrc file. I tend to be wordy in my doc attributes:

 
# getdefs sample configuration file
## This source file is copyrighted and licensed under the following terms:
#
#  Copyright (C) 1999-2014 Bruce Korb, all rights reserved.
#  This is free software. It is licensed for use, modification and
#  redistribution under the terms of the GNU General Public License,
#  version 3 or later <http://gnu.org/licenses/gpl.html>
#
#  getdefs is free software: you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  getdefs 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 this program.  If not, see <http://www.gnu.org/licenses/>.

# defs_to_get -- Regexp to look for after the "/*="
#
# 
#
#
# If you want definitions only from a particular category, or even
# with names matching particular patterns, then specify this regular
# expression for the text that must follow the @code{/*=}.
# Example:
#
#defs_to_get	reg-ex

# subblock -- subblock definition names
#
# 
#
#
# This option is used to create shorthand entries for nested definitions.
# For example, with:
# @table @r
# @item using subblock thus
# @code{--subblock=arg=argname,type,null}
# @item and defining an @code{arg} thus
# @code{arg: this, char *}
# @item will then expand to:
# @code{arg = @{ argname = this; type = "char *"; @};}
# @end table
# The "this, char *" string is separated at the commas, with the
# white space removed.  You may use characters other than commas by
# starting the value string with a punctuation character other than
# a single or double quote character.  You may also omit intermediate
# values by placing the commas next to each other with no intervening
# white space.  For example, "+mumble++yes+" will expand to:
# @*
# @code{arg = @{ argname = mumble; null = "yes"; @};}.
# Example:
#
#subblock	sub-def

# listattr -- attribute with list of values
#
# 
#
#
# This option is used to create shorthand entries for definitions
# that generally appear several times.  That is, they tend to be
# a list of values.  For example, with:
# @*
# @code{listattr=foo} defined, the text:
# @*
# @code{foo: this, is, a, multi-list} will then expand to:
# @*
# @code{foo = 'this', 'is', 'a', 'multi-list';}
# @*
# The texts are separated by the commas, with the
# white space removed.  You may use characters other than commas by
# starting the value string with a punctuation character other than
# a single or double quote character.
# Example:
#
#listattr	def

# ordering -- Alphabetize or use named file
#
# 
#
#
# By default, ordering is alphabetical by the entry name.  Use,
# @code{no-ordering} if order is unimportant.  Use @code{ordering}
# with no argument to order without case sensitivity.  Use
# @code{ordering=<file-name>} if chronological order is important.
# getdefs will maintain the text content of @code{file-name}.
# @code{file-name} need not exist.
# Example:
#
#ordering	file-name

# first_index -- The first index to apply to groups
#
# This configuration value takes an integer number as its argument.
#
#
# By default, the first occurrence of a named definition will have an
# index of zero.  Sometimes, that needs to be a reserved value.  Provide
# this option to specify a different starting point.
# Example:
#
#first_index	0

# filelist -- Insert source file names into defs
#
# 
#
#
# Inserts the name of each input file into the output definitions.
# If no argument is supplied, the format will be:
# @example
# infile = '%s';
# @end example
# If an argument is supplied, that string will be used for the entry
# name instead of @var{infile}.
# Example:
#
#filelist	file

# assign -- Global assignments
#
# 
#
#
# The argument to each copy of this option will be inserted into
# the output definitions, with only a semicolon attached.
# Example:
#
#assign	ag-def

# common_assign -- Assignments common to all blocks
#
# 
#
#
# The argument to each copy of this option will be inserted into
# each output definition, with only a semicolon attached.
# Example:
#
#common_assign	ag-def

# copy -- File(s) to copy into definitions
#
# 
#
#
# The content of each file named by these options will be inserted into
# the output definitions.
# Example:
#
#copy	file

# srcfile -- Insert source file name into each def
#
# 
#
#
# Inserts the name of the input file where a definition was found
# into the output definition.
# If no argument is supplied, the format will be:
# @example
# srcfile = '%s';
# @end example
# If an argument is supplied, that string will be used for the entry
# name instead of @var{srcfile}.
# Example:
#
#srcfile	file

# linenum -- Insert source line number into each def
#
# 
#
#
# Inserts the line number in the input file where a definition
# was found into the output definition.
# If no argument is supplied, the format will be:
# @example
# linenum = '%s';
# @end example
# If an argument is supplied, that string will be used for the entry
# name instead of @var{linenum}.
# Example:
#
#linenum	def-name

# input -- Input file to search for defs
#
# 
#
#
# All files that are to be searched for definitions must be named on
# the command line or read from @code{stdin}.  If there is only one
# @code{input} option and it is the string, "-", then the input file
# list is read from @code{stdin}.  If a command line argument is not
# an option name and does not contain an assignment operator
# (@code{=}), then it defaults to being an input file name.
# At least one input file must be specified.
# Example:
#
#input	src-file

# output -- Output file to open
#
# 
#
#
# If you are not sending the output to an AutoGen process,
# you may name an output file instead.
# Example:
#
#output	file

# autogen -- Invoke AutoGen with defs
#
# 
#
#
# This is the default output mode.  Specifying @code{no-autogen} is
# equivalent to @code{output=-}.  If you supply an argument to this
# option, that program will be started as if it were AutoGen and
# its standard in will be set to the output definitions of this program.
# Example:
#
#autogen	ag-cmd

# template -- Template Name
#
# 
#
#
# Specifies the template name to be used for generating the final output.
# Example:
#
#template	file

# agarg -- AutoGen Argument
#
# 
#
#
# This is a pass-through argument.  It allows you to specify any
# arbitrary argument to be passed to AutoGen.
# Example:
#
#agarg	ag-opt

# base_name -- Base name for output file(s)
#
# 
#
#
# When output is going to AutoGen, a base name must either be supplied
# or derived.  If this option is not supplied, then it is taken from
# the @code{template} option.  If that is not provided either, then
# it is set to the base name of the current directory.
# Example:
#
#base_name	name

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10.4 environment variable presets

If the AutoOpts client program specifies environrc in its option descriptor file, then environment variables will be used for presetting option state. Variables will be looked for that are named, PROGRAM_OPTNAME and PROGRAM. PROGRAM is the upper cased C-name of the program, and OPTNAME is the upper cased C-name of a specific option. (The C-names are the regular names with all special characters converted to underscores (_).)

Option specific environment variables are processed after (and thus take precedence over) the contents of the PROGRAM environment variable. The option argument string for these options takes on the string value gotten from the environment. Consequently, you can only have one instance of the OPTNAME.

If a particular option may be disabled, then its disabled state is indicated by setting the PROGRAM_OPTNAME value to the disablement prefix. So, for example, if the disablement prefix were dont, then you can disable the optname option by setting the PROGRAM_OPTNAME’ environment variable to dont. See section Common Option Attributes.

The PROGRAM environment string is tokenized and parsed much like a command line. Doubly quoted strings have backslash escapes processed the same way they are processed in C program constant strings. Singly quoted strings are pretty raw in that backslashes are honored before other backslashes, apostrophes, newlines and cr/newline pairs. The options must be introduced with hyphens in the same way as the command line.

Note that not all options may be preset. Options that are specified with the no-preset attribute and the ‘--help’, ‘--more-help’, and ‘--save-opts’ auto-supported options may not be preset.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.10.5 Config file only example

If for some reason it is difficult or unworkable to integrate configuration file processing with command line option parsing, the libopts (see section libopts External Procedures) library can still be used to process configuration files. Below is a Hello, World! greeting program that tries to load a configuration file ‘hello.conf’ to see if it should use an alternate greeting or to personalize the salutation.

 
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <string.h>
#ifdef   HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <autoopts/options.h>
int main(int argc, char ** argv) {
  char const * greeting = "Hello";
  char const * greeted  = "World";
  tOptionValue const * pOV = configFileLoad("hello.conf");

  if (pOV != NULL) {
    const tOptionValue* pGetV = optionGetValue(pOV, "greeting");

    if (  (pGetV != NULL)
       && (pGetV->valType == OPARG_TYPE_STRING))
      greeting = strdup(pGetV->v.strVal);

    pGetV = optionGetValue(pOV, "personalize");
    if (pGetV != NULL) {
      struct passwd * pwe = getpwuid(getuid());
      if (pwe != NULL)
        greeted = strdup(pwe->pw_gecos);
    }

    optionUnloadNested(pOV); /* deallocate config data */
  }
  printf("%s, %s!\n", greeting, greeted);
  return 0;
}

With that text in a file named “hello.c”, this short script:

 
cc -o hello hello.c `autoopts-config cflags ldflags`
./hello
echo 'greeting Buzz off' > hello.conf
./hello
echo personalize > hello.conf
./hello

will produce the following output:

 
Hello, World!
Buzz off, World!
Hello, Bruce Korb!

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Bruce Korb on August 21, 2015 using texi2html 1.82.