ggLoadConfig(3) Configuration helpers

Other Alias

ggFreeConfig, ggConfigIterTarget, ggConfigIterLocation

SYNOPSIS


int ggLoadConfig(const char *file, gg_config *config);
void ggFreeConfig(gg_config config);
struct gg_location_iter {
struct gg_iter iter;
const void * config;
const char * name;
char * location;
const char * symbol;
void * _state;
};
int ggConfigIterLocation(struct gg_location_iter * iter);

struct gg_target_iter {
struct gg_iter iter;
void * config;
const char * input;
char * target;
char * options;
void * nested;
};
int ggConfigIterTarget(struct gg_target_iter *iter);

DESCRIPTION

These functions provides a simple way of handling configuration files.

ggLoadConfig tries to load the configuration file given as parameter. It adds the content to the config handle found at *config. If the handle is NULL, a new one is created.

ggFreeConfig deletes the internal structure for the configuration handle config. This handle becomes invalid and should not be used anymore.

ggConfigIterLocation allows to retreive the location and symbol associated to canonical names. This function is mainly used together with the scope abstraction to query application modules at runtime. This function will prepare the iter structure to be used as an iterator that will generate correct matches. iter is a pointer to a gg_location_iter structure owned by the caller. This user part of the structure must be set by the caller before calling ggConfigIterLocation. The config field must be filled with the config handle which contains target information; the name field must be filled with the canonical name that is being looked for. location and symbol are placeholders in which the results will be found along the iteration. The resulting strings *do* belong to libgg and *must not* be freed or altered, and they may be invalidated if not used during the iteration process. They must be copied if needed later. _state is an internal opaque pointer that keeps track of the iterator state. Its value must never be touched by the caller.

ggConfigIterTarget allows to iterate over canonical target names and options strings found in a target spec string. This function also work as a generator. iter is a pointer to a gg_target_iter structure owned by the caller. This user part of the structure must be set by the caller before calling ggConfigIterTarget. The config field must be filled with the config handle which contains target information; the input field must be filled with the initial input spec string. target and options are placeholders in which the results will be found along the iteration. Here again, the resulting strings *do* belong to libgg and *must not* be freed or altered, and they may be invalidated if not used during the iteration process. They must be copied if needed later. nested is an internal opaque pointer that keeps track of the iterator state. Its value must never be touched by the caller.

RETURN VALUE

ggLoadConfig returns GGI_OK on success, or:
  • GGI_ENOMEM if it can not allocate a new configuration handle. Note that if subsequent memory allocations fail (when feeding the handle), those will not be reported as an error. The handle will be incomplete with regard to the config file contents;
  • GGI_ENOTFOUND if the file does not exists. Note that missing files in include directives will not be reported an error. Also, other parse error in the file will simply cause the incriminated lines to be ignored.

ggConfigIterLocation returns GGI_OK on success or GGI_ENOMEM.

ggConfigIterTarget always return GGI_OK and will never fail.

CONFIG FILE FORMAT

The configuration file is line oriented. Each line may define a mapping between a canonical name and a location. The generic format is:

<pattern>  <location>[:<symbol>]
alias <name> <expansion>

On the first line pattern is a canonical name that may contain one * as a wildcard, location is a string that corresponds to a scope location, and symbol is an optional string that gives the name of the symbol to retreive from the scope. If not given, NULL will be reported. The second line defines an alias. When a target called name is found while iterating over target spec strings, the iterator parse expansion as a sub-input spec, and aggregate all option strings that where found on upstream aliases.

In addition, the configuration file loader knowns the following directives:

  .root <path>
  .include <file>

When locations following the .root directive are given as relative path, path will be prepended. .include will parse the given file recursively, before continuing with the current one.

EXAMPLE

This code demonstrates how to get the first module init function accessible from a scope for a given name. It also shows how to use the libgg iterator scheme:

int openModule(gg_config cfg, const char * moduleName,
                              const char * defaultSymbol) {
  struct gg_location_iter match;
  gg_scope scope;
  module_init_func *init;
  
  /* prepare the iterator */
  
  match.name = name;
  match.config = cfg;
  ggConfigMatchIter(&match);
  
  /* iterate over the matches */
  
  GG_ITER_FOREACH(&match) {
     /* try to retreive the collection at suggested location */
     if((scope = ggGetScope(match.location)) == NULL)
               continue;
     /* use default symbol if none suggested */
     if (match.symbol == NULL) match.symbol = defaultSymbol;
     
     /* try to retreive the symbol from that scope */
     if((init = ggFromScope(scope, match.symbol)) == NULL) {
              ggDelScope(scope);
              continue;
     }
     /* try to initialize the module */
     if(init() != GGI_OK) {
              ggDelScope(scope);
              continue;
     }
     /* the module is up, abort iteration and return */
     GG_ITER_DONE(&match);
     return GGI_OK;
  }
  
  /* module not found */
  GG_ITER_DONE(&match);
  return GGI_ENOTFOUND;

Note that this code is not completely correct, because the scope cannot be deleted later if it is not remembered somewhere. This next example shows how to list all targets and options specified by a string:

static void showAllTargets(void * cfg, const char * input)
{
      struct gg_target_iter match;
      
      match.config = cfg;
      match.input = input;
      ggConfigIterTarget(&match);
      GG_ITER_FOREACH(&match) {
              printf("Target \"%s\" with options \"%s\".\n",
                     match.target, match.options);
      }
      GG_ITER_DONE(&match);
}