Logo Search packages:      
Sourcecode: fair version File versions  Download package

conf.c

/******************************************************************************

      conf.c -- handle the configuration file
      Copyright (C) 2004  Wessel Dankers <wsl@uvt.nl>

      This program 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 2 of the License, or
      (at your option) any later version.

      This program 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, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

      $Id: conf.c 23144 2007-12-21 15:36:48Z wsl $
      $URL: https://infix.uvt.nl/its-id/trunk/sources/fair-0.5.1/src/conf.c $

******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <regex.h>

#include "fair.h"
#include "chrono.h"
#include "error.h"

#include "conf.h"

#include <avl.h>

static bool set_string(const char **holder, const char *val) {
      unless(val) return FALSE;
      if(holder) {
            if(*holder)
                  free((char *)*holder);
            *holder = xstrdup(val);
      }
      return TRUE;
}

static bool set_bool(bool *holder, const char *val) {
      bool r;
      unless(val) return FALSE;

      if(!strcasecmp(val, "y") || !strcasecmp(val, "yes")
      || !strcasecmp(val, "t") || !strcasecmp(val, "true")
      || !strcasecmp(val, "1") || !strcasecmp(val, "on"))
                  r = TRUE;
      else if(!strcasecmp(val, "n") || !strcasecmp(val, "no")
           || !strcasecmp(val, "f") || !strcasecmp(val, "false")
           || !strcasecmp(val, "0") || !strcasecmp(val, "off"))
                  r = FALSE;
      else
            return syslog(LOG_CRIT, "Unrecognized boolean value: '%s'.", val), FALSE;
      if(holder)
            *holder = r;
      return TRUE;
}

static bool set_stamp(stamp_t *holder, const char *val) {
      char *end;
      double v;

      unless(val) return FALSE;

      errno = 0;
      v = strtod(val, &end);
      if(errno)
            return syslog(LOG_CRIT, "Error parsing number: %m."), FALSE;
      if(end == val || !end || *end)
            return syslog(LOG_CRIT, "Error parsing '%s' as a number.", val), FALSE;
      if(holder)
            *holder = v * (double)STAMP_TICKS;
      return TRUE;
}

static bool set_size(size_t *holder, const char *val) {
      char *end;
      unsigned long long u;
      size_t s;

      unless(val) return FALSE;

      u = strtoull(val, &end, 0);
      s = u;
      if(end == val || !end || *end || s != u)
            return syslog_exit(LOG_CRIT, "Error parsing \"%s\" as a number.", val), FALSE;
      if(holder)
            *holder = s;
      return TRUE;
}

static bool set_regex(regex_t **holder, const char *val) {
      regex_t *re, *re_swap;
      int err;
      size_t len;
      char *msg = NULL;
      bool r = FALSE;

      unless(val) return FALSE;

      re = xalloc(sizeof *re);
      err = regcomp(re, val, REG_EXTENDED|REG_NOSUB);
      if(err) {
            len = regerror(err, re, NULL, 0);
            msg = alloca(len);
            assert(msg);
            regerror(err, re, msg, len);
            syslog(LOG_ERR, "Error compiling regex: %s", msg);
      } else {
            if(holder) {
                  re_swap = *holder;
                  *holder = re;
                  re = re_swap;
            }
            r = TRUE;
      }

      if(re) {
            regfree(re);
            free(re);
      }
      return r;
}

#define _StringConfigVal(s,d) const char *conf_##s = NULL; \
      static bool set_##s(const char *str, bool dryrun) \
            { return set_string(dryrun ? NULL : &conf_##s, str); }
#define _BoolConfigVal(b,d) bool conf_##b = FALSE; \
      static bool set_##b(const char *str, bool dryrun) \
            { return set_bool(dryrun ? NULL : &conf_##b, str); }
#define _StampConfigVal(t,d) stamp_t conf_##t = 0LL; \
      static bool set_##t(const char *str, bool dryrun) \
            { return set_stamp(dryrun ? NULL : &conf_##t, str); }
#define _SizeConfigVal(s,d) size_t conf_##s = 0; \
      static bool set_##s(const char *str, bool dryrun) \
            { return set_size(dryrun ? NULL : &conf_##s, str); }
#define _RegexConfigVal(r,d) regex_t *conf_##r = NULL; \
      static bool set_##r(const char *str, bool dryrun) \
            { return set_regex(dryrun ? NULL : &conf_##r, str); }

#include "options.h"

static int optcmp(const option_t *a, const option_t *b) {
      assert(a && b);
      return strcasecmp(a->name, b->name);
}

static avl_tree_t options = {NULL, NULL, NULL, (avl_compare_t)optcmp, NULL};

static option_t *option_byname(const char *key) {
      avl_node_t *n;
      struct option_t *opt;
      size_t len;

      unless(key) return NULL;

      len = strlen(key);
      opt = alloca(sizeof *opt + len);
      unless(opt) return NULL;
      strcpy(opt->name, key);
      n = avl_search(&options, opt);
      return n ? n->item : NULL;
}

static option_t *option_new(const char *key, bool (*set)(const char *, bool), const char *def) {
      option_t *opt;
      size_t len;
      assert(key && set && def);
      len = strlen(key);
      opt = xalloc(sizeof *opt + len);
      avl_init_node(&opt->node, opt);
      strcpy(opt->name, key);
      opt->set = set;
      set(def, FALSE);
      if(!avl_insert_node(&options, &opt->node))
            syslog_exit(LOG_CRIT, "Internal error: duplicate configuration key %s", key);
      return opt;
}

static void config_init(void) {
      static bool done = FALSE;
      if(done)
            return;

#define _ConfigVal(k,d) option_new(#k, set_##k, d);
#include "options.h"

      done = TRUE;
}

static void conf_reset(void) {
#define _ConfigVal(k,d) set_##k(d, FALSE);
#include "options.h"
}

static char *chop(char *s) {
      char *end;
      unless(s) return NULL;
      while(isspace(*s))
            s++;
      if(!*s)
            return s;
      end = s + strlen(s) - 1;
      while(isspace(*end))
            *end-- = '\0';
      return s;
}

bool conf_load(const char *config, bool dryrun) {
      FILE *f;
      char buf[65536];
      option_t *opt;
      char *key, *value;
      int lineno = 0;
      bool good = TRUE;

      if(!config)
            config = FAIRCONF_PATH;

      config_init();

      /* Read the options but fail if there's no default for it */
      f = fopen(config, "r");
      if(!f) {
            syslog(LOG_ERR, "Can't open configfile %s: %m", config);
            return FALSE;
      }

      while(fgets(buf, sizeof buf, f)) {
            lineno++;
            key = chop(buf);
            if(*key && *key != '#') {
                  value = strchr(key, '=');
                  if(value) {
                        *value++ = '\0';
                        key = chop(key);
                        opt = option_byname(key);
                        if(opt) {
                              assert(opt->set);
                              if(!opt->set(chop(value), dryrun))
                                    good = FALSE;
                        } else {
                              syslog(LOG_ERR, "Unknown option `%s' at %s:%d", key, config, lineno);
                              good = FALSE;
                        }
                  } else {
                        syslog(LOG_ERR, "Syntax error in %s:%d", config, lineno);
                        good = FALSE;
                  }
            }
      }
      fclose(f);

      return good;
}

bool conf_reload(const char *config) {
      if(!conf_load(config, TRUE))
            return FALSE;
      conf_reset();
      return conf_load(config, FALSE);
}

Generated by  Doxygen 1.6.0   Back to index