-
Notifications
You must be signed in to change notification settings - Fork 95
The basic idea behind the u_env module is to load configuration values (i.e. values that a program needs at run-time) from a shell script which exports some variables in a given namespace. We let the shell act in the background - using just some env(1) and pipe(2) tricks to redirect and capture the variables - which in turn gives us a great deal of power and flexibility in just a couple of C lines.
Let’s start with a very simple configuration file in which three variables are set and exported to the environment.
export PFX_VAR1="tip"
export PFX_VAR2="tap"
export PFX_VAR3=$((10 * 100 * 1000))
Here we have two alternate configurations (i.e. two different set of values for the same three variables in the PFX_ namespace) which can be selected by just setting the top level USE_DEFAULT_CONF variable value.
USE_DEFAULT_CONF="true"
default_conf ()
{
export PFX_VAR1="tip"
export PFX_VAR2="tap"
export PFX_VAR3=$((10 * 100 * 1000))
alternate_conf ()
{
local X=`jot -r -c 1 a z`
export PFX_VAR1=$X"ic"
export PFX_VAR2=$X"ac"
export PFX_VAR3=$X"oe"
}
if [ $USE_DEFAULT_CONF = "true" ]
then
default_conf
else
alternate_conf
fi
Things worth noting are:
- the conditional behaviour;
- bash does the math (!) and spawns external utilities (e.g. jot(1));
- it is possible to do complex substitutions;
- every information one can get through the shell is available (e.g. cat /proc/something);
- aggregation of other configuration modules is trivial via the source shell built-in.
Now let’s take a look at the C code that uses the u_env API. Basically we have two function calls: the first one u_env_init() asks the shell to parse and evaluate the supplied configuration/script file. This function shall be called just once, i.e. when we need to load all the variables in the supplied namespace.
#include <stdlib.h>
#include <u/libu.h>
int main (int ac, char *av[])
{
int i;
const char *v, *vp[] = { "PFX_VAR1", "PFX_VAR2", "PFX_VAR3" };
con_err_if (ac != 2);
==> con_err_if (u_env_init("PFX_", av[1])); <==
Then for each needed variable we load its value using the u_env_var() function:
for (i = 0; i < 3; i++)
{
==> if ((v = u_env_var(vp[i])) == NULL) <==
con("%s not set", vp[i]);
else
con("%s set to %s", vp[i], v);
}
return EXIT_SUCCESS;
err:
return EXIT_FAILURE;
}
Note that when the USE_DEFAULT_CONF variable is set to true, running the test program on the two different configuration files produces the same output:
PFX_VAR1 set to tip
PFX_VAR2 set to tap
PFX_VAR3 set to 1000000
That's all.