views:

719

answers:

6

In C, how to configure the initial settings for some program, using key-value pairs, with any or all of: a plain text configuration file, environment variables, and options on the command line. Also, how to decide which method's values overide those from either of the other two. Then if values have been changed, to optionally update the configuration file.

What's the simplest way to do this, and what if any, are the most accepted methods? Is there a, preferably small, open source program that gives a good example of how this can be done?

+2  A: 

There are tons of libraries for dealing with configuration file parsing, for various formats. Look for XML and INI formats, for two popular choices. Writing a custom parser is probably a bad idea, since it can be a lot of work for little or no gain. Here is a random C library for parsing INI files, XML is left as an exercise.

The priority between settings is usually such that command line options override any "environmental" settings. I would suggest priorities like this, in falling order of importance:

  1. Command line options override anything
  2. Settings file is next
    • Sometimes split between user's local, and system global files
  3. Next come environment variables

But the 2 and 3 might well be flipped.

unwind
+2  A: 

The question is not terribly clear. Is the question "what mechanisms exist?", "what are the conventions for arguments and formats?", or "how you should I mix and match?"?

There are several pretty standard ways (at least in the unix world):

  • environment variables
  • configuration files
  • command line arguments
  • as a subset of the above, config files specified on the command line

To choose what methods to use for your own program, examine many programs from the canon of accepted practice before you freeze your own choices, read some blogs, read some books...

Configuration files are probably the most portable across operating systems.

The treatment can get fairly complicated. If the command line arguments might affect the interpretation of config files or environment variable, but you still want the command line to overrule the other mechanisms (a good idea) you may need three passes:

  1. Parse the command line and set any variables which affect further settings (say which config file to read)
  2. Handle config files and environment variable (what order?)
  3. Re-run the command line to override all other settings.


In the unix tradition look at getopt and getopt_long. Also consider tools like gengetopt

You can simplify you config file problem by making them shell scripts that set environment variables (but this locks you into a unix model). Parsing plain text is easy and cross platform, but makes more code to write. Using a standard format and a library puts requirements on your user's build environment, but should save on bugs and confusion.


If your configuration environment is complicated, it is very helpful to encapsulate the configuration state in a structure which can be passed around as needed. This is the approach taken by gengetopt, and I have found it to be useful.

dmckee
It's more "what mechanisms exist?", just using the usual key-value pairs for the format.
Rob Kam
+5  A: 

The basics:

  • To configure your program using environment variables, you can use the getenv function defined in stdlib.h.
  • To configure your program using command line arguments, declare your main function like 'int main(int argc, const char* const* argv)', and use a loop to go over the arguments in the argv array. It's size is given by argc.
  • To configure your program using a configuration file, preferably pick some library doing this for you instead of inventing yet another custom config file format. Note that depending on the platform you target, there are also libraries to parse commandline arguments.

Which settings source should override each other depends on the application, but in my opinion generally commandline argument > environment variable > configuration file makes most sense.

Here is an example of getting configuration from environment and commandline, with commandline overriding environment:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char* const* argv) {
    int i;
    const char* myConfigVar;

    // get default setting from environment
    myConfigVar = getenv("MY_CONFIG_VAR");

    // if the variable wasn't defined, initialize to hardcoded default
    if (!myConfigVar)
        myConfigVar = "default value";

    // parse commandline arguments
    // start at 1, because argv[0] contains the name of the program
    for (i = 1; i < argc; ++i) {
        if (strcmp("--my-config-var", argv[i]) == 0) {
            if (i + 1 < argc)
                myConfigVar = argv[i + 1];
            else
                printf("missing value for my-config-var argument\n");
        }
    }

    printf("myConfigVar = '%s'\n", myConfigVar);
    return 0;
}

You already see it becomes very long and tedious very soon, so better use an existing library if one exists for your desired target platform(s), or at least factor this kind of code into a number of functions.

Another interesting option is to bind a scripting language to your application, then you could make your application only read and "execute" your settings file, and the user could configure the settings file to read some settings from the environment and some from the commandline, for example. It really depends on type and size of the application and your target audience whether this is worth doing though.

Tobi
Ok, deleted that last line :)
Tobi
+4  A: 

Eric Raymond covers a lot of this in Section 10 of The Art of Unix Programming Obviously this is Unix centric, but most of the principles can be applied in any OS.

Steve Fallows
Without a background image, at http://www.faqs.org/docs/artu/ is easier to read.
Rob Kam
Thanks, Rob. Wish I'd found that when I read the whole thing.:) Updated my link.
Steve Fallows
+1  A: 

For Unix-like design patterns in this area, look at Raymond's "The Art of Unix Programming". It discusses the prioritization of command line arguments over environment variables and configuration files, and so on.

Jonathan Leffler
+1  A: 

The Lua language partly got its start motivated by the need to have a well-defined configuration language for a collection of tools. It remains quite easy to integrate Lua as a configuration language. A fairly complete example is in the book Programming in Lua, an older edition of which is available online. Chapter 25 describes using the Lua C API to embed Lua as a configuration language, and reasons why you might want to do this.

RBerteig