]> mj.ucw.cz Git - libucw.git/commitdiff
Conf: Rewritten configuration parser to support multiple contexts (step 1)
authorMartin Mares <mj@ucw.cz>
Sat, 28 Apr 2012 13:17:38 +0000 (15:17 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 29 Apr 2012 11:57:29 +0000 (13:57 +0200)
Some parts remain, most notably the handling of dirty sections
in conf-section.c.

ucw/Makefile
ucw/conf-alloc.c
ucw/conf-context.c [new file with mode: 0644]
ucw/conf-dump.c
ucw/conf-input.c
ucw/conf-internal.h
ucw/conf-intr.c
ucw/conf-journal.c
ucw/conf-section.c
ucw/conf.h
ucw/threads.h

index aa795e76202c9101c6c0d48b738648a9a5bcb598..62373ade03e4200dc60f9e1f4962ae79c7283f72 100644 (file)
@@ -13,7 +13,7 @@ LIBUCW_MODS= \
        partmap hashfunc \
        slists simple-lists bitsig \
        log log-stream log-file log-syslog log-conf tbf \
-       conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section \
+       conf-context conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section \
        ipaccess \
        fastbuf ff-binary ff-string ff-printf ff-unicode ff-stkstring \
        fb-file fb-mem fb-temp tempfile fb-mmap fb-limfd fb-buffer fb-grow fb-pool fb-atomic fb-param fb-socket \
index 937965dd19f3d86dd7213c87a53042958a397e6f..f5f80cc8067f19a9db967396a362e5cef5e81d3a 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: memory allocation
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 
 #include <ucw/lib.h>
 #include <ucw/conf.h>
+#include <ucw/conf-internal.h>
 #include <ucw/mempool.h>
 
-struct mempool *cf_pool;       // current pool for loading new configuration
+inline struct mempool *
+cf_get_pool(void)
+{
+  return cf_get_context()->pool;
+}
 
 void *
 cf_malloc(uns size)
 {
-  return mp_alloc(cf_pool, size);
+  return mp_alloc(cf_get_pool(), size);
 }
 
 void *
 cf_malloc_zero(uns size)
 {
-  return mp_alloc_zero(cf_pool, size);
+  return mp_alloc_zero(cf_get_pool(), size);
 }
 
 char *
 cf_strdup(const char *s)
 {
-  return mp_strdup(cf_pool, s);
+  return mp_strdup(cf_get_pool(), s);
 }
 
 char *
@@ -37,7 +42,7 @@ cf_printf(const char *fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
-  char *res = mp_vprintf(cf_pool, fmt, args);
+  char *res = mp_vprintf(cf_get_pool(), fmt, args);
   va_end(args);
   return res;
 }
diff --git a/ucw/conf-context.c b/ucw/conf-context.c
new file mode 100644 (file)
index 0000000..dc74b66
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *     UCW Library -- Configuration files: Contexts
+ *
+ *     (c) 2012 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include <ucw/lib.h>
+#include <ucw/conf.h>
+#include <ucw/conf-internal.h>
+#include <ucw/threads.h>
+
+#ifndef CONFIG_UCW_DEFAULT_CONFIG
+#define CONFIG_UCW_DEFAULT_CONFIG NULL
+#endif
+
+#ifndef CONFIG_UCW_ENV_VAR_CONFIG
+#define CONFIG_UCW_ENV_VAR_CONFIG NULL
+#endif
+
+struct cf_context *
+cf_new_context(void)
+{
+  struct cf_context *cc = xmalloc_zero(sizeof(*cc));
+  cc->need_journal = 1;
+  clist_init(&cc->conf_entries);
+  return cc;
+}
+
+void
+cf_free_context(struct cf_context *cc)
+{
+  ASSERT(!cc->is_active);
+  xfree(cc->parser);
+  xfree(cc);
+}
+
+struct cf_context *
+cf_switch_context(struct cf_context *cc)
+{
+  struct ucwlib_context *uc = ucwlib_thread_context();
+  struct cf_context *prev = uc->cf_context;
+  if (prev)
+    prev->is_active = 0;
+  if (cc)
+    {
+      ASSERT(!cc->is_active);
+      cc->is_active = 1;
+    }
+  uc->cf_context = cc;
+  return prev;
+}
+
+struct cf_context *
+cf_obtain_context(void)
+{
+  struct ucwlib_context *uc = ucwlib_thread_context();
+  if (unlikely(!uc->cf_context))
+    {
+      struct cf_context *cc = cf_new_context();
+      uc->cf_context = cc;
+      cc->def_file = CONFIG_UCW_DEFAULT_CONFIG;
+      cc->env_file = CONFIG_UCW_ENV_VAR_CONFIG;
+      cc->is_active = 1;
+    }
+  return uc->cf_context;
+}
+
+void
+cf_set_default_file(char *name)
+{
+  struct cf_context *cc = cf_obtain_context();
+  cc->def_file = name;
+}
+
+void
+cf_set_env_override(char *name)
+{
+  struct cf_context *cc = cf_obtain_context();
+  cc->env_file = name;
+}
index 2176f71e90000b14be4385a73d242875d1eaabcb..9d7e31c926b9e7bcdbd735f822adc6e377add00f 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: dumping
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -118,6 +118,7 @@ dump_section(struct fastbuf *fb, struct cf_section *sec, int level, void *ptr)
 void
 cf_dump_sections(struct fastbuf *fb)
 {
-  dump_section(fb, &cf_sections, 0, NULL);
+  struct cf_context *cc = cf_get_context();
+  dump_section(fb, &cc->sections, 0, NULL);
 }
 
index 117c54822ab8a25ce080f480bebb7dfbd0786be3..fff753ce01743606735983ca6ec7bcabef7272c5 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: parsing input streams
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2009 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 
 /* Text file parser */
 
-static const char *name_parse_fb;
-static struct fastbuf *parse_fb;
-static uns line_num;
-
 #define MAX_LINE       4096
-static char line_buf[MAX_LINE];
-static char *line = line_buf;
 
 #include <ucw/bbuf.h>
-static bb_t copy_buf;
-static uns copied;
 
 #define GBUF_TYPE      uns
 #define GBUF_PREFIX(x) split_##x
 #include <ucw/gbuf.h>
-static split_t word_buf;
-static uns words;
-static uns ends_by_brace;              // the line is ended by "{"
+
+struct cf_parser_state {
+  const char *name_parse_fb;
+  struct fastbuf *parse_fb;
+  uns line_num;
+  char *line;
+  split_t word_buf;
+  uns words;
+  uns ends_by_brace;           // the line is ended by "{"
+  bb_t copy_buf;
+  uns copied;
+  char line_buf[];
+};
 
 static int
-get_line(char **msg)
+get_line(struct cf_parser_state *p, char **msg)
 {
-  int err = bgets_nodie(parse_fb, line_buf, MAX_LINE);
-  line_num++;
+  int err = bgets_nodie(p->parse_fb, p->line_buf, MAX_LINE);
+  p->line_num++;
   if (err <= 0) {
     *msg = err < 0 ? "Line too long" : NULL;
     return 0;
   }
-  line = line_buf;
-  while (Cblank(*line))
-    line++;
+  p->line = p->line_buf;
+  while (Cblank(*p->line))
+    p->line++;
   return 1;
 }
 
 static void
-append(char *start, char *end)
+append(struct cf_parser_state *p, char *start, char *end)
 {
   uns len = end - start;
-  bb_grow(&copy_buf, copied + len + 1);
-  memcpy(copy_buf.ptr + copied, start, len);
-  copied += len + 1;
-  copy_buf.ptr[copied-1] = 0;
+  bb_grow(&p->copy_buf, p->copied + len + 1);
+  memcpy(p->copy_buf.ptr + p->copied, start, len);
+  p->copied += len + 1;
+  p->copy_buf.ptr[p->copied-1] = 0;
 }
 
 static char *
-get_word(uns is_command_name)
+get_word(struct cf_parser_state *p, uns is_command_name)
 {
   char *msg;
+  char *line = p->line;
+
   if (*line == '\'') {
     line++;
     while (1) {
       char *start = line;
       while (*line && *line != '\'')
        line++;
-      append(start, line);
+      append(p, start, line);
       if (*line)
        break;
-      copy_buf.ptr[copied-1] = '\n';
-      if (!get_line(&msg))
+      p->copy_buf.ptr[p->copied-1] = '\n';
+      if (!get_line(p, &msg))
        return msg ? : "Unterminated apostrophe word at the end";
+      line = p->line;
     }
     line++;
 
   } else if (*line == '"') {
     line++;
-    uns start_copy = copied;
+    uns start_copy = p->copied;
     while (1) {
       char *start = line;
       uns escape = 0;
@@ -103,23 +108,24 @@ get_word(uns is_command_name)
          escape = 0;
        line++;
       }
-      append(start, line);
+      append(p, start, line);
       if (*line)
        break;
       if (!escape)
-       copy_buf.ptr[copied-1] = '\n';
+       p->copy_buf.ptr[p->copied-1] = '\n';
       else // merge two lines
-       copied -= 2;
-      if (!get_line(&msg))
+       p->copied -= 2;
+      if (!get_line(p, &msg))
        return msg ? : "Unterminated quoted word at the end";
+      line = p->line;
     }
     line++;
 
-    char *tmp = stk_str_unesc(copy_buf.ptr + start_copy);
+    char *tmp = stk_str_unesc(p->copy_buf.ptr + start_copy);
     uns l = strlen(tmp);
-    bb_grow(&copy_buf, start_copy + l + 1);
-    strcpy(copy_buf.ptr + start_copy, tmp);
-    copied = start_copy + l + 1;
+    bb_grow(&p->copy_buf, start_copy + l + 1);
+    strcpy(p->copy_buf.ptr + start_copy, tmp);
+    p->copied = start_copy + l + 1;
 
   } else {
     // promised that *line is non-null and non-blank
@@ -135,59 +141,60 @@ get_word(uns is_command_name)
     }
     if (line == start)                         // already the first char is control
       line++;
-    append(start, line);
+    append(p, start, line);
   }
   while (Cblank(*line))
     line++;
+  p->line = line;
   return NULL;
 }
 
 static char *
-get_token(uns is_command_name, char **err)
+get_token(struct cf_parser_state *p, uns is_command_name, char **err)
 {
   *err = NULL;
   while (1) {
-    if (!*line || *line == '#') {
-      if (!is_command_name || !get_line(err))
+    if (!*p->line || *p->line == '#') {
+      if (!is_command_name || !get_line(p, err))
        return NULL;
-    } else if (*line == ';') {
-      *err = get_word(0);
+    } else if (*p->line == ';') {
+      *err = get_word(p, 0);
       if (!is_command_name || *err)
        return NULL;
-    } else if (*line == '\\' && !line[1]) {
-      if (!get_line(err)) {
+    } else if (*p->line == '\\' && !p->line[1]) {
+      if (!get_line(p, err)) {
        if (!*err)
          *err = "Last line ends by a backslash";
        return NULL;
       }
-      if (!*line || *line == '#')
-       msg(L_WARN, "The line %s:%d following a backslash is empty", name_parse_fb ? : "", line_num);
+      if (!*p->line || *p->line == '#')
+       msg(L_WARN, "The line %s:%d following a backslash is empty", p->name_parse_fb ? : "", p->line_num);
     } else {
-      split_grow(&word_buf, words+1);
-      uns start = copied;
-      word_buf.ptr[words++] = copied;
-      *err = get_word(is_command_name);
-      return *err ? NULL : copy_buf.ptr + start;
+      split_grow(&p->word_buf, p->words+1);
+      uns start = p->copied;
+      p->word_buf.ptr[p->words++] = p->copied;
+      *err = get_word(p, is_command_name);
+      return *err ? NULL : p->copy_buf.ptr + start;
     }
   }
 }
 
 static char *
-split_command(void)
+split_command(struct cf_parser_state *p)
 {
-  words = copied = ends_by_brace = 0;
+  p->words = p->copied = p->ends_by_brace = 0;
   char *msg, *start_word;
-  if (!(start_word = get_token(1, &msg)))
+  if (!(start_word = get_token(p, 1, &msg)))
     return msg;
   if (*start_word == '{')                      // only one opening brace
     return "Unexpected opening brace";
-  while (*line != '}')                         // stays for the next time
+  while (*p->line != '}')                      // stays for the next time
   {
-    if (!(start_word = get_token(0, &msg)))
+    if (!(start_word = get_token(p, 0, &msg)))
       return msg;
     if (*start_word == '{') {
-      words--;                                 // discard the brace
-      ends_by_brace = 1;
+      p->words--;                              // discard the brace
+      p->ends_by_brace = 1;
       break;
     }
   }
@@ -197,32 +204,36 @@ split_command(void)
 /* Parsing multiple files */
 
 static char *
-parse_fastbuf(const char *name_fb, struct fastbuf *fb, uns depth)
+parse_fastbuf(struct cf_context *cc, const char *name_fb, struct fastbuf *fb, uns depth)
 {
+  struct cf_parser_state *p = cc->parser;
+  if (!p)
+    p = cc->parser = xmalloc_zero(sizeof(*p) + MAX_LINE);
+  p->name_parse_fb = name_fb;
+  p->parse_fb = fb;
+  p->line_num = 0;
+  p->line = p->line_buf;
+  *p->line = 0;
+
   char *err;
-  name_parse_fb = name_fb;
-  parse_fb = fb;
-  line_num = 0;
-  line = line_buf;
-  *line = 0;
   while (1)
   {
-    err = split_command();
+    err = split_command(p);
     if (err)
       goto error;
-    if (!words)
+    if (!p->words)
       return NULL;
-    char *name = copy_buf.ptr + word_buf.ptr[0];
-    char *pars[words-1];
-    for (uns i=1; i<words; i++)
-      pars[i-1] = copy_buf.ptr + word_buf.ptr[i];
+    char *name = p->copy_buf.ptr + p->word_buf.ptr[0];
+    char *pars[p->words-1];
+    for (uns i=1; i<p->words; i++)
+      pars[i-1] = p->copy_buf.ptr + p->word_buf.ptr[i];
     if (!strcasecmp(name, "include"))
     {
-      if (words != 2)
+      if (p->words != 2)
        err = "Expecting one filename";
       else if (depth > 8)
        err = "Too many nested files";
-      else if (*line && *line != '#')          // because the contents of line_buf is not re-entrant and will be cleared
+      else if (*p->line && *p->line != '#')    // because the contents of line_buf is not re-entrant and will be cleared
        err = "The include command must be the last one on a line";
       if (err)
        goto error;
@@ -231,13 +242,13 @@ parse_fastbuf(const char *name_fb, struct fastbuf *fb, uns depth)
        err = cf_printf("Cannot open file %s: %m", pars[0]);
        goto error;
       }
-      uns ll = line_num;
-      err = parse_fastbuf(stk_strdup(pars[0]), new_fb, depth+1);
-      line_num = ll;
+      uns ll = p->line_num;
+      err = parse_fastbuf(cc, stk_strdup(pars[0]), new_fb, depth+1);
+      p->line_num = ll;
       bclose(new_fb);
       if (err)
        goto error;
-      parse_fb = fb;
+      p->parse_fb = fb;
       continue;
     }
     enum cf_operation op;
@@ -265,70 +276,56 @@ parse_fastbuf(const char *name_fb, struct fastbuf *fb, uns depth)
        goto error;
       }
     }
-    if (ends_by_brace)
+    if (p->ends_by_brace)
       op |= OP_OPEN;
-    err = cf_interpret_line(name, op, words-1, pars);
+    err = cf_interpret_line(cc, name, op, p->words-1, pars);
     if (err)
       goto error;
   }
 error:
   if (name_fb)
-    msg(L_ERROR, "File %s, line %d: %s", name_fb, line_num, err);
-  else if (line_num == 1)
+    msg(L_ERROR, "File %s, line %d: %s", name_fb, p->line_num, err);
+  else if (p->line_num == 1)
     msg(L_ERROR, "Manual setting of configuration: %s", err);
   else
-    msg(L_ERROR, "Manual setting of configuration, line %d: %s", line_num, err);
+    msg(L_ERROR, "Manual setting of configuration, line %d: %s", p->line_num, err);
   return "included from here";
 }
 
-#ifndef CONFIG_UCW_DEFAULT_CONFIG
-#define CONFIG_UCW_DEFAULT_CONFIG NULL
-#endif
-char *cf_def_file = CONFIG_UCW_DEFAULT_CONFIG;
-static int cf_def_loaded;
-
-#ifndef CONFIG_UCW_ENV_VAR_CONFIG
-#define CONFIG_UCW_ENV_VAR_CONFIG NULL
-#endif
-char *cf_env_file = CONFIG_UCW_ENV_VAR_CONFIG;
-
-static uns postpone_commit;                    // only for cf_getopt()
-static uns everything_committed;               // after the 1st load, this flag is set on
-
 static int
-done_stack(void)
+done_stack(struct cf_context *cc)
 {
-  if (cf_check_stack())
+  if (cf_check_stack(cc))
     return 1;
-  if (cf_commit_all(postpone_commit ? CF_NO_COMMIT : everything_committed ? CF_COMMIT : CF_COMMIT_ALL))
+  if (cf_commit_all(cc->postpone_commit ? CF_NO_COMMIT : cc->everything_committed ? CF_COMMIT : CF_COMMIT_ALL))
     return 1;
-  if (!postpone_commit)
-    everything_committed = 1;
+  if (!cc->postpone_commit)
+    cc->everything_committed = 1;
   return 0;
 }
 
 static int
-load_file(const char *file)
+load_file(struct cf_context *cc, const char *file)
 {
-  cf_init_stack();
+  cf_init_stack(cc);
   struct fastbuf *fb = bopen_try(file, O_RDONLY, 1<<14);
   if (!fb) {
     msg(L_ERROR, "Cannot open %s: %m", file);
     return 1;
   }
-  char *err_msg = parse_fastbuf(file, fb, 0);
+  char *err_msg = parse_fastbuf(cc, file, fb, 0);
   bclose(fb);
-  return !!err_msg || done_stack();
+  return !!err_msg || done_stack(cc);
 }
 
 static int
-load_string(const char *string)
+load_string(struct cf_context *cc, const char *string)
 {
-  cf_init_stack();
+  cf_init_stack(cc);
   struct fastbuf fb;
   fbbuf_init_read(&fb, (byte *)string, strlen(string), 0);
-  char *msg = parse_fastbuf(NULL, &fb, 0);
-  return !!msg || done_stack();
+  char *msg = parse_fastbuf(cc, NULL, &fb, 0);
+  return !!msg || done_stack(cc);
 }
 
 /* Safe loading and reloading */
@@ -342,61 +339,58 @@ struct conf_entry {       /* We remember a list of actions to apply upon reload */
   char *arg;
 };
 
-static clist conf_entries;
-
 static void
-cf_remember_entry(uns type, const char *arg)
+cf_remember_entry(struct cf_context *cc, uns type, const char *arg)
 {
-  if (!cf_need_journal)
+  if (!cc->need_journal)
     return;
-  if (!postpone_commit)
+  if (!cc->postpone_commit)
     return;
   struct conf_entry *ce = cf_malloc(sizeof(*ce));
   ce->type = type;
   ce->arg = cf_strdup(arg);
-  clist_add_tail(&conf_entries, &ce->n);
+  clist_add_tail(&cc->conf_entries, &ce->n);
 }
 
 int
 cf_reload(const char *file)
 {
+  struct cf_context *cc = cf_get_context();
   cf_journal_swap();
   struct cf_journal_item *oldj = cf_journal_new_transaction(1);
-  uns ec = everything_committed;
-  everything_committed = 0;
+  uns ec = cc->everything_committed;
+  cc->everything_committed = 0;
 
-  if (!conf_entries.head.next)
-    clist_init(&conf_entries);
   clist old_entries;
-  clist_move(&old_entries, &conf_entries);
-  postpone_commit = 1;
+  clist_move(&old_entries, &cc->conf_entries);
+  cc->postpone_commit = 1;
 
   int err = 0;
   if (file)
-    err = load_file(file);
+    err = load_file(cc, file);
   else
     CLIST_FOR_EACH(struct conf_entry *, ce, old_entries) {
       if (ce->type == CE_FILE)
-       err |= load_file(ce->arg);
+       err |= load_file(cc, ce->arg);
       else
-       err |= load_string(ce->arg);
+       err |= load_string(cc, ce->arg);
       if (err)
        break;
-      cf_remember_entry(ce->type, ce->arg);
+      cf_remember_entry(cc, ce->type, ce->arg);
     }
 
-  postpone_commit = 0;
+  cc->postpone_commit = 0;
   if (!err)
-    err |= done_stack();
+    err |= done_stack(cc);
 
   if (!err) {
     cf_journal_delete();
     cf_journal_commit_transaction(1, NULL);
   } else {
-    everything_committed = ec;
+    cc->everything_committed = ec;
     cf_journal_rollback_transaction(1, oldj);
     cf_journal_swap();
-    clist_move(&conf_entries, &old_entries);
+    clist_move(&cc->conf_entries, &old_entries);
   }
   return err;
 }
@@ -404,12 +398,13 @@ cf_reload(const char *file)
 int
 cf_load(const char *file)
 {
+  struct cf_context *cc = cf_get_context();
   struct cf_journal_item *oldj = cf_journal_new_transaction(1);
-  int err = load_file(file);
+  int err = load_file(cc, file);
   if (!err) {
     cf_journal_commit_transaction(1, oldj);
-    cf_remember_entry(CE_FILE, file);
-    cf_def_loaded = 1;
+    cf_remember_entry(cc, CE_FILE, file);
+    cc->def_loaded = 1;
   } else
     cf_journal_rollback_transaction(1, oldj);
   return err;
@@ -418,11 +413,12 @@ cf_load(const char *file)
 int
 cf_set(const char *string)
 {
+  struct cf_context *cc = cf_get_context();
   struct cf_journal_item *oldj = cf_journal_new_transaction(0);
-  int err = load_string(string);
+  int err = load_string(cc, string);
   if (!err) {
     cf_journal_commit_transaction(0, oldj);
-    cf_remember_entry(CE_STRING, string);
+    cf_remember_entry(cc, CE_STRING, string);
   } else
     cf_journal_rollback_transaction(0, oldj);
   return err;
@@ -431,37 +427,37 @@ cf_set(const char *string)
 /* Command-line parser */
 
 static void
-load_default(void)
+load_default(struct cf_context *cc)
 {
-  if (cf_def_loaded++)
+  if (cc->def_loaded++)
     return;
-  if (cf_def_file)
+  if (cc->def_file)
     {
       char *env;
-      if (cf_env_file && (env = getenv(cf_env_file)))
+      if (cc->env_file && (env = getenv(cc->env_file)))
         {
          if (cf_load(env))
            die("Cannot load config file %s", env);
        }
-      else if (cf_load(cf_def_file))
-        die("Cannot load default config %s", cf_def_file);
+      else if (cf_load(cc->def_file))
+        die("Cannot load default config %s", cc->def_file);
     }
   else
     {
       // We need to create an empty pool and initialize all configuration items
       struct cf_journal_item *oldj = cf_journal_new_transaction(1);
-      cf_init_stack();
-      done_stack();
+      cf_init_stack(cc);
+      done_stack(cc);
       cf_journal_commit_transaction(1, oldj);
     }
 }
 
 static void
-final_commit(void)
+final_commit(struct cf_context *cc)
 {
-  if (postpone_commit) {
-    postpone_commit = 0;
-    if (done_stack())
+  if (cc->postpone_commit) {
+    cc->postpone_commit = 0;
+    if (done_stack(cc))
       die("Cannot commit after the initialization");
   }
 }
@@ -469,18 +465,17 @@ final_commit(void)
 int
 cf_getopt(int argc, char * const argv[], const char *short_opts, const struct option *long_opts, int *long_index)
 {
-  clist_init(&conf_entries);
-  postpone_commit = 1;
+  struct cf_context *cc = cf_obtain_context();
+  cc->postpone_commit = 1;
 
-  static int other_options = 0;
   while (1) {
     int res = getopt_long (argc, argv, short_opts, long_opts, long_index);
     if (res == 'S' || res == 'C' || res == 0x64436667)
     {
-      if (other_options)
+      if (cc->other_options)
        die("The -S and -C options must precede all other arguments");
       if (res == 'S') {
-       load_default();
+       load_default(cc);
        if (cf_set(optarg))
          die("Cannot set %s", optarg);
       } else if (res == 'C') {
@@ -489,8 +484,8 @@ cf_getopt(int argc, char * const argv[], const char *short_opts, const struct op
       }
 #ifdef CONFIG_UCW_DEBUG
       else {   /* --dumpconfig */
-       load_default();
-       final_commit();
+       load_default(cc);
+       final_commit(cc);
        struct fastbuf *b = bfdopen(1, 4096);
        cf_dump_sections(b);
        bclose(b);
@@ -500,10 +495,10 @@ cf_getopt(int argc, char * const argv[], const char *short_opts, const struct op
     } else {
       /* unhandled option or end of options */
       if (res != ':' && res != '?') {
-       load_default();
-       final_commit();
+       load_default(cc);
+       final_commit(cc);
       }
-      other_options++;
+      cc->other_options++;
       return res;
     }
   }
index 377a9cb235a1ab63e8815a787610a43892fa1f9c..d8c77d622853fec9fa5191c2381d983642a46c64 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: only for internal use of conf-*.c
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 #ifndef        _UCW_CONF_INTERNAL_H
 #define        _UCW_CONF_INTERNAL_H
 
+#include <ucw/threads.h>
+
+#define MAX_STACK_SIZE 16
+
+struct item_stack {            // used by conf-intr.c
+  struct cf_section *sec;      // nested section
+  void *base_ptr;              // because original pointers are often relative
+  int op;                      // it is performed when a closing brace is encountered
+  void *list;                  // list the operations should be done on
+  u32 mask;                    // bit array of selectors searching in a list
+  struct cf_item *item;                // cf_item of the list
+};
+
+struct cf_context {
+  struct mempool *pool;
+  int is_active;
+  int need_journal;
+  char *def_file;
+  char *env_file;
+  int def_loaded;
+  struct cf_parser_state *parser;
+  uns everything_committed;            // after the 1st load, this flag is set on
+  uns postpone_commit;                 // used internally by cf_getopt()
+  uns other_options;
+  clist conf_entries;
+  struct old_pools *pools;
+  struct cf_journal_item *journal;
+  struct item_stack stack[MAX_STACK_SIZE];
+  uns stack_level;
+  uns initialized;
+  struct cf_section sections;          // root section
+};
+
+/* conf-ctxt.c */
+static inline struct cf_context *
+cf_get_context(void)
+{
+  return ucwlib_thread_context()->cf_context;
+}
+
 /* conf-intr.c */
 #define OP_MASK 0xff           // only get the operation
 #define OP_OPEN 0x100          // here we only get an opening brace instead of parameters
@@ -21,9 +61,9 @@ extern char *cf_op_names[];
 extern char *cf_type_names[];
 
 uns cf_type_size(enum cf_type type, struct cf_user_type *utype);
-char *cf_interpret_line(char *name, enum cf_operation op, int number, char **pars);
-void cf_init_stack(void);
-int cf_check_stack(void);
+char *cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars);
+void cf_init_stack(struct cf_context *cc);
+int cf_check_stack(struct cf_context *cc);
 
 /* conf-journal.c */
 void cf_journal_swap(void);
index ba32dd7bec268569415597b69cebb89ecab1488c..57192e9205e1ab58038ffb3fd8d648f709608a89 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: interpreter
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -378,24 +378,13 @@ record_selector(struct cf_item *item, struct cf_section *sec, u32 *mask)
   return NULL;
 }
 
-#define MAX_STACK_SIZE 10
-static struct item_stack {
-  struct cf_section *sec;      // nested section
-  void *base_ptr;              // because original pointers are often relative
-  enum cf_operation op;                // it is performed when a closing brace is encountered
-  void *list;                  // list the operations should be done on
-  u32 mask;                    // bit array of selectors searching in a list
-  struct cf_item *item;                // cf_item of the list
-} stack[MAX_STACK_SIZE];
-static uns level;
-
 static char *
-opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
+opening_brace(struct cf_context *cc, struct cf_item *item, void *ptr, enum cf_operation op)
 {
-  if (level >= MAX_STACK_SIZE-1)
+  if (cc->stack_level >= MAX_STACK_SIZE-1)
     return "Too many nested sections";
   enum cf_operation pure_op = op & OP_MASK;
-  stack[++level] = (struct item_stack) {
+  cc->stack[++cc->stack_level] = (struct item_stack) {
     .sec = NULL,
     .base_ptr = NULL,
     .op = pure_op,
@@ -405,27 +394,27 @@ opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
   };
   if (!item)                   // unknown is ignored; we just need to trace recursion
     return NULL;
-  stack[level].sec = item->u.sec;
+  cc->stack[cc->stack_level].sec = item->u.sec;
   if (item->cls == CC_SECTION)
   {
     if (pure_op != OP_SET)
       return "Only SET operation can be used with a section";
-    stack[level].base_ptr = ptr;
-    stack[level].op = OP_EDIT | OP_2ND;        // this list operation does nothing
+    cc->stack[cc->stack_level].base_ptr = ptr;
+    cc->stack[cc->stack_level].op = OP_EDIT | OP_2ND;  // this list operation does nothing
   }
   else if (item->cls == CC_LIST)
   {
-    stack[level].base_ptr = cf_malloc(item->u.sec->size);
-    cf_init_section(item->name, item->u.sec, stack[level].base_ptr, 1);
-    stack[level].list = ptr;
-    stack[level].item = item;
+    cc->stack[cc->stack_level].base_ptr = cf_malloc(item->u.sec->size);
+    cf_init_section(item->name, item->u.sec, cc->stack[cc->stack_level].base_ptr, 1);
+    cc->stack[cc->stack_level].list = ptr;
+    cc->stack[cc->stack_level].item = item;
     if (pure_op == OP_ALL)
       return "Operation ALL cannot be applied on lists";
     else if (pure_op < OP_REMOVE) {
-      add_to_list(ptr, stack[level].base_ptr, pure_op);
-      stack[level].op |= OP_2ND;
+      add_to_list(ptr, cc->stack[cc->stack_level].base_ptr, pure_op);
+      cc->stack[cc->stack_level].op |= OP_2ND;
     } else
-      stack[level].op |= OP_1ST;
+      cc->stack[cc->stack_level].op |= OP_1ST;
   }
   else
     return "Opening brace can only be used on sections and lists";
@@ -433,13 +422,13 @@ opening_brace(struct cf_item *item, void *ptr, enum cf_operation op)
 }
 
 static char *
-closing_brace(struct item_stack *st, enum cf_operation op, int number, char **pars)
+closing_brace(struct cf_context *cc, struct item_stack *st, enum cf_operation op, int number, char **pars)
 {
   if (st->op == OP_CLOSE)      // top-level
     return "Unmatched } parenthesis";
   if (!st->sec) {              // dummy run on unknown section
     if (!(op & OP_OPEN))
-      level--;
+      cc->stack_level--;
     return NULL;
   }
   enum cf_operation pure_op = st->op & OP_MASK;
@@ -475,7 +464,7 @@ closing_brace(struct item_stack *st, enum cf_operation op, int number, char **pa
     }
     add_to_list(st->list, st->base_ptr, pure_op);
   }
-  level--;
+  cc->stack_level--;
   if (number)
     return "No parameters expected after the }";
   else if (op & OP_OPEN)
@@ -487,14 +476,15 @@ closing_brace(struct item_stack *st, enum cf_operation op, int number, char **pa
 static struct cf_item *
 find_item(struct cf_section *curr_sec, const char *name, char **msg, void **ptr)
 {
+  struct cf_context *cc = cf_get_context();
   *msg = NULL;
   if (name[0] == '^')                          // absolute name instead of relative
-    name++, curr_sec = &cf_sections, *ptr = NULL;
+    name++, curr_sec = &cc->sections, *ptr = NULL;
   if (!curr_sec)                               // don't even search in an unknown section
     return NULL;
   while (1)
   {
-    if (curr_sec != &cf_sections)
+    if (curr_sec != &cc->sections)
       cf_add_dirty(curr_sec, *ptr);
     char *c = strchr(name, '.');
     if (c)
@@ -535,21 +525,21 @@ interpret_add(char *name, struct cf_item *item, int number, char **pars, int *ta
 }
 
 char *
-cf_interpret_line(char *name, enum cf_operation op, int number, char **pars)
+cf_interpret_line(struct cf_context *cc, char *name, enum cf_operation op, int number, char **pars)
 {
   char *msg;
   if ((op & OP_MASK) == OP_CLOSE)
-    return closing_brace(stack+level, op, number, pars);
-  void *ptr = stack[level].base_ptr;
-  struct cf_item *item = find_item(stack[level].sec, name, &msg, &ptr);
+    return closing_brace(cc, cc->stack+cc->stack_level, op, number, pars);
+  void *ptr = cc->stack[cc->stack_level].base_ptr;
+  struct cf_item *item = find_item(cc->stack[cc->stack_level].sec, name, &msg, &ptr);
   if (msg)
     return msg;
-  if (stack[level].op & OP_1ST)
-    TRY( record_selector(item, stack[level].sec, &stack[level].mask) );
+  if (cc->stack[cc->stack_level].op & OP_1ST)
+    TRY( record_selector(item, cc->stack[cc->stack_level].sec, &cc->stack[cc->stack_level].mask) );
   if (op & OP_OPEN) {          // the operation will be performed after the closing brace
     if (number)
       return "Cannot open a block after a parameter has been passed on a line";
-    return opening_brace(item, ptr, op);
+    return opening_brace(cc, item, ptr, op);
   }
   if (!item)                   // ignored item in an unknown section
     return NULL;
@@ -583,9 +573,10 @@ cf_interpret_line(char *name, enum cf_operation op, int number, char **pars)
 char *
 cf_find_item(const char *name, struct cf_item *item)
 {
+  struct cf_context *cc = cf_get_context();
   char *msg;
   void *ptr = NULL;
-  struct cf_item *ci = find_item(&cf_sections, name, &msg, &ptr);
+  struct cf_item *ci = find_item(&cc->sections, name, &msg, &ptr);
   if (msg)
     return msg;
   if (ci) {
@@ -642,17 +633,16 @@ cf_modify_item(struct cf_item *item, enum cf_operation op, int number, char **pa
 }
 
 void
-cf_init_stack(void)
+cf_init_stack(struct cf_context *cc)
 {
-  static uns initialized = 0;
-  if (!initialized++) {
-    cf_sections.flags |= SEC_FLAG_UNKNOWN;
-    cf_sections.size = 0;                      // size of allocated array used to be stored here
-    cf_init_section(NULL, &cf_sections, NULL, 0);
+  if (!cc->initialized++) {
+    cc->sections.flags |= SEC_FLAG_UNKNOWN;
+    cc->sections.size = 0;                     // size of allocated array used to be stored here
+    cf_init_section(NULL, &cc->sections, NULL, 0);
   }
-  level = 0;
-  stack[0] = (struct item_stack) {
-    .sec = &cf_sections,
+  cc->stack_level = 0;
+  cc->stack[0] = (struct item_stack) {
+    .sec = &cc->sections,
     .base_ptr = NULL,
     .op = OP_CLOSE,
     .list = NULL,
@@ -662,12 +652,11 @@ cf_init_stack(void)
 }
 
 int
-cf_check_stack(void)
+cf_check_stack(struct cf_context *cc)
 {
-  if (level > 0) {
+  if (cc->stack_level > 0) {
     msg(L_ERROR, "Unterminated block");
     return 1;
   }
   return 0;
 }
-
index 6134bfd254d535365b3a1af20447934d01637d60..75af51ad69d3021743cf796945901c9663a8e818 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: journaling
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 
 #include <string.h>
 
-static struct old_pools {
+struct old_pools {
   struct old_pools *prev;
   struct mempool *pool;
-} *pools;                      // link-list of older cf_pool's
+};                             // link-list of older cf_pool's
 
-uns cf_need_journal = 1;       // some programs do not need journal
-static struct cf_journal_item {
+struct cf_journal_item {
   struct cf_journal_item *prev;
   byte *ptr;
   uns len;
   byte copy[0];
-} *journal;
+};
 
 void
 cf_journal_block(void *ptr, uns len)
 {
-  if (!cf_need_journal)
+  struct cf_context *cc = cf_get_context();
+  if (!cc->need_journal)
     return;
   struct cf_journal_item *ji = cf_malloc(sizeof(struct cf_journal_item) + len);
-  ji->prev = journal;
+  ji->prev = cc->journal;
   ji->ptr = ptr;
   ji->len = len;
   memcpy(ji->copy, ptr, len);
-  journal = ji;
+  cc->journal = ji;
 }
 
 void
 cf_journal_swap(void)
   // swaps the contents of the memory and the journal, and reverses the list
 {
+  struct cf_context *cc = cf_get_context();
   struct cf_journal_item *curr, *prev, *next;
-  for (next=NULL, curr=journal; curr; next=curr, curr=prev)
+  for (next=NULL, curr=cc->journal; curr; next=curr, curr=prev)
   {
     prev = curr->prev;
     curr->prev = next;
@@ -58,32 +59,34 @@ cf_journal_swap(void)
       curr->ptr[i] = x;
     }
   }
-  journal = next;
+  cc->journal = next;
 }
 
 struct cf_journal_item *
 cf_journal_new_transaction(uns new_pool)
 {
+  struct cf_context *cc = cf_get_context();
   if (new_pool)
-    cf_pool = mp_new(1<<10);
-  struct cf_journal_item *oldj = journal;
-  journal = NULL;
+    cc->pool = mp_new(1<<10);
+  struct cf_journal_item *oldj = cc->journal;
+  cc->journal = NULL;
   return oldj;
 }
 
 void
 cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj)
 {
+  struct cf_context *cc = cf_get_context();
   if (new_pool)
   {
     struct old_pools *p = cf_malloc(sizeof(struct old_pools));
-    p->prev = pools;
-    p->pool = cf_pool;
-    pools = p;
+    p->prev = cc->pools;
+    p->pool = cc->pool;
+    cc->pools = p;
   }
   if (oldj)
   {
-    struct cf_journal_item **j = &journal;
+    struct cf_journal_item **j = &cc->journal;
     while (*j)
       j = &(*j)->prev;
     *j = oldj;
@@ -93,23 +96,25 @@ cf_journal_commit_transaction(uns new_pool, struct cf_journal_item *oldj)
 void
 cf_journal_rollback_transaction(uns new_pool, struct cf_journal_item *oldj)
 {
-  if (!cf_need_journal)
+  struct cf_context *cc = cf_get_context();
+  if (!cc->need_journal)
     die("Cannot rollback the configuration, because the journal is disabled.");
   cf_journal_swap();
-  journal = oldj;
+  cc->journal = oldj;
   if (new_pool)
   {
-    mp_delete(cf_pool);
-    cf_pool = pools ? pools->pool : NULL;
+    mp_delete(cc->pool);
+    cc->pool = cc->pools ? cc->pools->pool : NULL;
   }
 }
 
 void
 cf_journal_delete(void)
 {
-  for (struct old_pools *p=pools; p; p=pools)
+  struct cf_context *cc = cf_get_context();
+  for (struct old_pools *p=cc->pools; p; p=cc->pools)
   {
-    pools = p->prev;
+    cc->pools = p->prev;
     mp_delete(p->pool);
   }
 }
index 9cac24a5d0e334457c08ab518dc2af0c84319e45..d006643b1e360789c570907ea2760abcb6cdf305 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files: sections
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -18,6 +18,8 @@
 
 /* Dirty sections */
 
+// FIXME!!!
+
 struct dirty_section {
   struct cf_section *sec;
   void *ptr;
@@ -67,8 +69,6 @@ sort_dirty(void)
 
 /* Initialization */
 
-struct cf_section cf_sections; // root section
-
 struct cf_item *
 cf_find_subitem(struct cf_section *sec, const char *name)
 {
@@ -106,12 +106,13 @@ inspect_section(struct cf_section *sec)
 void
 cf_declare_section(const char *name, struct cf_section *sec, uns allow_unknown)
 {
-  if (!cf_sections.cfg)
+  struct cf_context *cc = cf_get_context();
+  if (!cc->sections.cfg)
   {
-    cf_sections.size = 50;
-    cf_sections.cfg = xmalloc_zero(cf_sections.size * sizeof(struct cf_item));
+    cc->sections.size = 50;
+    cc->sections.cfg = xmalloc_zero(cc->sections.size * sizeof(struct cf_item));
   }
-  struct cf_item *ci = cf_find_subitem(&cf_sections, name);
+  struct cf_item *ci = cf_find_subitem(&cc->sections, name);
   if (ci->cls)
     die("Cannot register section %s twice", name);
   ci->cls = CC_SECTION;
@@ -123,11 +124,11 @@ cf_declare_section(const char *name, struct cf_section *sec, uns allow_unknown)
   if (allow_unknown)
     sec->flags |= SEC_FLAG_UNKNOWN;
   ci++;
-  if (ci - cf_sections.cfg >= (int) cf_sections.size)
+  if (ci - cc->sections.cfg >= (int) cc->sections.size)
   {
-    cf_sections.cfg = xrealloc(cf_sections.cfg, 2*cf_sections.size * sizeof(struct cf_item));
-    bzero(cf_sections.cfg + cf_sections.size, cf_sections.size * sizeof(struct cf_item));
-    cf_sections.size *= 2;
+    cc->sections.cfg = xrealloc(cc->sections.cfg, 2*cc->sections.size * sizeof(struct cf_item));
+    bzero(cc->sections.cfg + cc->sections.size, cc->sections.size * sizeof(struct cf_item));
+    cc->sections.size *= 2;
   }
 }
 
@@ -193,10 +194,11 @@ commit_section(struct cf_section *sec, void *ptr, uns commit_all)
 int
 cf_commit_all(enum cf_commit_mode cm)
 {
+  struct cf_context *cc = cf_get_context();
   sort_dirty();
   if (cm == CF_NO_COMMIT)
     return 0;
-  if (commit_section(&cf_sections, NULL, cm == CF_COMMIT_ALL))
+  if (commit_section(&cc->sections, NULL, cm == CF_COMMIT_ALL))
     return 1;
   dirties = 0;
   return 0;
index 50dbddc1712ea109b7c9fc24357e91a825d7b0e8..bf106274b2f239ad900041a8a2fd0ee2743da9c3 100644 (file)
@@ -2,7 +2,7 @@
  *     UCW Library -- Configuration files
  *
  *     (c) 2001--2006 Robert Spalek <robert@ucw.cz>
- *     (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *     (c) 2003--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
 #ifndef        _UCW_CONF_H
 #define        _UCW_CONF_H
 
+#include <ucw/clists.h>
+
+struct mempool;
+
+/***
+ * [[conf_ctxt]]
+ * Configuration contexts
+ * ~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The state of the configuration parser is stored within a configuration context.
+ * If you do not create contexts explicitly, the library will create one for you
+ * and you need not care, as long as you use a single configuration file.
+ *
+ * In whole generality, you can define as many context as you wish and switch
+ * between them. Each thread has its own pointer to the current context, which
+ * must not be shared with other threads.
+ ***/
+
+/** Create a new configuration context. **/
+struct cf_context *cf_new_context(void);
+
+/**
+ * Free a configuration context. The context must not be set as current
+ * for any thread.
+ *
+ * All configuration settings made within the context are rolled back
+ * (except when journalling is turned off). All memory allocated on behalf
+ * of the context is freed, which includes memory obtained by calls to
+ * cf_malloc().
+ **/
+void cf_free_context(struct cf_context *cc);
+
+/**
+ * Make the given configuration context current and return the previously
+ * active context. Both the new and the old context may be NULL.
+ **/
+struct cf_context *cf_switch_context(struct cf_context *cc);
+
+/**
+ * Return a pointer to the current context, or create the default context
+ * if there is no context active.
+ **/
+struct cf_context *cf_obtain_context(void);
+
+/**
+ * Set name of default configuration file. May be NULL if there should be
+ * no such default.
+ * FIXME: Explain where it is used
+ **/
+void cf_set_default_file(char *name);
+
+/**
+ * Set name of environment variable used to override the name of the default
+ * configuration file. May be NULL if there should be no such variable.
+ **/
+void cf_set_env_override(char *name);
+
 /*** === Data types [[conf_types]] ***/
 
 enum cf_class {                                /** Class of the configuration item. **/
@@ -306,18 +363,17 @@ struct cf_section {                       /** A section. **/
  * Memory allocation
  * ~~~~~~~~~~~~~~~~~
  *
- * Uses <<mempool:,memory pools>> for efficiency and journal recovery.
- * You should use these routines when implementing custom parsers.
+ * Each configuration context has one or more <<mempool:,memory pools>>, where all
+ * data related to the configuration are stored.
+ *
+ * The following set of functions allocate from these pools. The allocated memory
+ * is valid as long as the current configuration (when the configuration file is
+ * reloaded or rolled back, or the context is deleted, it gets lost).
+ *
+ * Memory allocated from within custom parsers should be allocated from the pools.
  ***/
-struct mempool;
-/**
- * A <<mempool:type_mempool,memory pool>> for configuration parser needs.
- * Memory allocated from here is valid as long as the current config is loaded
- * (if you allocate some memory and rollback the transaction or you load some
- * other configuration, it gets lost).
- **/
-extern struct mempool *cf_pool;
-void *cf_malloc(uns size);     /** Returns @size bytes of memory. Allocates from <<var_cf_pool,`cf_pool`>>. **/
+struct mempool *cf_get_pool(void); /** Return a pointer to the current configuration pool. **/
+void *cf_malloc(uns size);     /** Returns @size bytes of memory allocated from the current configuration pool. **/
 void *cf_malloc_zero(uns size);        /** Like @cf_malloc(), but zeroes the memory. **/
 char *cf_strdup(const char *s);        /** Copy a string into @cf_malloc()ed memory. **/
 char *cf_printf(const char *fmt, ...) FORMAT_CHECK(printf,1,2); /** printf() into @cf_malloc()ed memory. **/
index de1fa3068aa9df862a1351834107c16d06ca22ca..3c1f29b799ccf292e44ae38df900d23e5fe67326 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The UCW Library -- Threading Helpers
  *
- *     (c) 2006--2011 Martin Mares <mj@ucw.cz>
+ *     (c) 2006--2012 Martin Mares <mj@ucw.cz>
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
@@ -20,6 +20,7 @@ struct ucwlib_context {
   struct asio_queue *io_queue;         // Async I/O queue for fb-direct.c
   ucw_sighandler_t *signal_handlers;   // Signal handlers for sighandler.c
   struct main_context *main_context;   // Current context for mainloop.c
+  struct cf_context *cf_context;       // Current context for configuration parser
   // Resources and transactions:
   struct respool *current_respool;     // Current resource pool
   struct mempool *trans_pool;          // Transaction mempool