The main question is: do you want your configuration file to be in some Turing complete language (like Python is)? If you do want that, you might also consider embedding some other (Turing complete) scripting language like Guile or Lua (because there could be perceived as "simpler" to use, or to embed, than Python is; read the chapter on Extending & Embedding Python). I won't discuss that further (but notice that embedding a scripting language in your application is a major architectural choice, that you should consider very early; I really don't recommend making that choice later!), because other answers (e.g. by Amon) discussed that in depth.
However (at least on POSIX systems), you might consider convenient to enable the configuration to be dynamically computed at initialization time (of course, leaving the burden of a sane configuration to your system admin or user). For that, you could simply adopt the convention (and document it) that a configuration file path starting with e.g. a !
or a |
is actually a shell command that you would read as a pipeline. This leaves your user with the choice of using whatever "preprocessor" or "scripting language" he is the most familiar with.
So in your initialization code, your main
would (for example) accept some --config
argument confarg
and get some FILE*configf;
from it. If that argument starts with !
(i.e. if (confarg[0]=='!')
....), you would use configf = popen(confarg+1, "r");
and close that file with pclose(configf);
. Otherwise you would use configf=fopen(confarg, "r");
and close it with fclose(configf);
(don't forget the error checking). See pipe(7), popen(3), fopen(3).