]> mj.ucw.cz Git - libucw.git/commitdiff
implemented journal and safe (re)loading of cf/files and setting variables
authorRobert Spalek <robert@ucw.cz>
Thu, 20 Apr 2006 13:32:53 +0000 (15:32 +0200)
committerRobert Spalek <robert@ucw.cz>
Thu, 20 Apr 2006 13:32:53 +0000 (15:32 +0200)
lib/conf2.c
lib/conf2.h

index c37e2b6da66586592e8c0a1d3e3de59a9040a692..bdba4456409385ab68b5009f69bcbe6c8bca0226 100644 (file)
 #include "lib/mempool.h"
 
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 
 /* Memory allocation */
 
-static struct mempool *cf_pool;
+static struct old_pools {
+  struct old_pools *prev;
+  struct mempool *pool;
+} *pools;
 
 void *
 cf_malloc(uns size)
 {
-  return mp_alloc(cf_pool, size);
+  return mp_alloc(pools->pool, size);
 }
 
 void *
 cf_malloc_zero(uns size)
 {
-  return mp_alloc_zero(cf_pool, size);
+  return mp_alloc_zero(pools->pool, size);
 }
 
 byte *
 cf_strdup(byte *s)
 {
-  return mp_strdup(cf_pool, s);
+  return mp_strdup(pools->pool, s);
 }
 
 byte *
@@ -42,16 +46,141 @@ cf_printf(char *fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
-  byte *res = mp_vprintf(cf_pool, fmt, args);
+  byte *res = mp_vprintf(pools->pool, fmt, args);
   va_end(args);
   return res;
 }
 
 /* Undo journal */
 
+static struct journal_item {
+  struct journal_item *prev;
+  void *ptr;
+  uns len;
+  byte copy[0];
+} *journal;
+
 void
-cf_journal_block(void *ptr UNUSED, uns len UNUSED)
+cf_journal_block(void *ptr, uns len)
+{
+  struct journal_item *ji = cf_malloc(sizeof(struct journal_item) + len);
+  ji->prev = journal;
+  ji->ptr = ptr;
+  ji->len = len;
+  memcpy(ji->copy, ptr, len);
+  journal = ji;
+}
+
+static void
+journal_swap(void)
+  // swaps the contents of the memory and the journal, and reverses the list
+{
+  struct journal_item *curr, *prev, *next;
+  uns max_len = 0;
+  for (curr=journal; curr; curr=curr->prev)
+    max_len = MAX(max_len, curr->len);
+  byte *buf = xmalloc(max_len);
+  for (next=NULL, curr=journal; curr; next=curr, curr=prev)
+  {
+    prev = curr->prev;
+    curr->prev = next;
+    memcpy(buf, curr->copy, curr->len);
+    memcpy(curr->copy, curr->ptr, curr->len);
+    memcpy(curr->ptr, buf, curr->len);
+  }
+  journal = next;
+  xfree(buf);
+}
+
+static struct journal_item *
+journal_new_section(uns new_pool)
+{
+  if (new_pool)
+  {
+    struct old_pools *oldp = pools;
+    struct mempool *mp = mp_new(1<<14);
+    pools = mp_alloc(mp, sizeof(struct old_pools));
+    pools->prev = oldp;
+    pools->pool = mp;
+  }
+  struct journal_item *oldj = journal;
+  journal = NULL;
+  return oldj;
+}
+
+static void
+journal_commit_section(struct journal_item *oldj)
+{
+  struct journal_item **j = &journal;
+  while (*j)
+    j = &(*j)->prev;
+  *j = oldj;
+}
+
+static void
+journal_rollback_section(uns new_pool, struct journal_item *oldj)
+{
+  journal_swap();
+  journal = oldj;
+  if (new_pool)
+  {
+    struct old_pools *oldp = pools;
+    pools = pools->prev;
+    mp_delete(oldp->pool);
+  }
+}
+
+/* Safe loading and reloading */
+
+static byte *load_file(byte *file);
+static byte *load_string(byte *string);
+
+byte *
+cf_reload(byte *file)
+{
+  journal_swap();
+  struct old_pools *oldp = pools;
+  pools = NULL;
+
+  struct journal_item *oldj = journal_new_section(1);
+  byte *msg = load_file(file);
+  if (msg)
+  {
+    journal_rollback_section(1, oldj);
+    pools = oldp;
+    journal_swap();
+  }
+  else
+    for (struct old_pools *p=oldp; p; p=oldp)
+    {
+      oldp = p->prev;
+      mp_delete(p->pool);
+    }
+  return msg;
+}
+
+byte *
+cf_load(byte *file)
+{
+  struct journal_item *oldj = journal_new_section(1);
+  byte *msg = load_file(file);
+  if (!msg)
+    journal_commit_section(oldj);
+  else
+    journal_rollback_section(1, oldj);
+  return msg;
+}
+
+byte *
+cf_set(byte *string)
 {
+  struct journal_item *oldj = journal_new_section(0);
+  byte *msg = load_string(string);
+  if (!msg)
+    journal_commit_section(oldj);
+  else
+    journal_rollback_section(0, oldj);
+  return msg;
 }
 
 /* Parsers for standard types */
@@ -210,6 +339,6 @@ cf_parse_dyn(uns number, byte **pars, void **ptr, enum cf_type type)
 {
   cf_journal_block(ptr, sizeof(void*));
   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
-  * (uns*) (ptr - parsers[type].size) = number;
+  * (uns*) (*ptr - parsers[type].size) = number;
   return ((cf_parser*) parsers[type].parser) (number, pars, *ptr);
 }
index c7a53e0648692803144330a9b37f24dcd32e5755..eb4230df6cf15805173f2f32766bdd896b6922c8 100644 (file)
@@ -44,7 +44,7 @@ struct cf_section;
 struct cf_item {
   enum cf_class cls;
   byte *name;
-  int number;                          // length of an array or #parameters of a parser
+  int number;                          // length of an array or #parameters of a parser (negative means at most)
   void *ptr;                           // pointer to a global variable or an offset in a section
   union {
     enum cf_type type;                 // type of a static or dynamic attribute
@@ -101,6 +101,11 @@ byte *cf_printf(char *fmt, ...);
 /* Undo journal for error recovery */
 void cf_journal_block(void *ptr, uns len);
 
+/* Safe reloading and loading of configuration files */
+byte *cf_reload(byte *file);
+byte *cf_load(byte *file);
+byte *cf_set(byte *string);
+
 /* Parsers for basic types */
 byte *cf_parse_int(uns number, byte **pars, int *ptr);
 byte *cf_parse_u64(uns number, byte **pars, u64 *ptr);