changeset 70:a0e1b29be35d

Refactor configuration file handling module rather thoroughly. The API is broken by these changes.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 15 Nov 2012 19:32:00 +0200
parents 28156333ef4c
children ce49160d2599
files th_config.c th_config.h
diffstat 2 files changed, 121 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- a/th_config.c	Thu Nov 15 19:22:42 2012 +0200
+++ b/th_config.c	Thu Nov 15 19:32:00 2012 +0200
@@ -16,36 +16,36 @@
 
 /* Free a given configuration (the values are not free'd)
  */
-void th_cfg_free(cfgitem_t *cfg)
+void th_cfg_free(th_cfgitem_t *cfg)
 {
-    cfgitem_t *curr = cfg;
+    th_cfgitem_t *node = cfg;
 
-    while (curr != NULL)
+    while (node != NULL)
     {
-        cfgitem_t *next = curr->next;
+        th_cfgitem_t *next = node->next;
 
-        if (curr->type == ITEM_SECTION)
-            th_cfg_free((cfgitem_t *) curr->v.data);
+        if (node->type == ITEM_SECTION)
+            th_cfg_free((th_cfgitem_t *) node->v.data);
 
-        th_free(curr->name);
-        th_free(curr);
-        curr = next;
+        th_free(node->name);
+        th_free(node);
+        node = next;
     }
 }
 
 
 /* Allocate and add new item to configuration
  */
-static cfgitem_t *th_cfg_add(cfgitem_t **cfg, const char *name,
+static th_cfgitem_t *th_cfg_add(th_cfgitem_t **cfg, const char *name,
                              const int type, void *data)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     if (cfg == NULL)
         return NULL;
 
     /* Allocate new item */
-    node = (cfgitem_t *) th_calloc(1, sizeof(cfgitem_t));
+    node = (th_cfgitem_t *) th_calloc(1, sizeof(th_cfgitem_t));
     if (node == NULL)
         return NULL;
 
@@ -74,9 +74,9 @@
 
 /* Add integer type setting into give configuration
  */
-int th_cfg_add_int(cfgitem_t **cfg, char *name, int *itemData, int itemDef)
+int th_cfg_add_int(th_cfgitem_t **cfg, const char *name, int *itemData, int itemDef)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_INT, (void *) itemData);
     if (node == NULL)
@@ -88,10 +88,10 @@
 }
 
 
-int th_cfg_add_hexvalue(cfgitem_t **cfg, char *name,
+int th_cfg_add_hexvalue(th_cfgitem_t **cfg, const char *name,
                         int *itemData, int itemDef)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_HEX_TRIPLET, (void *) itemData);
     if (node == NULL)
@@ -105,10 +105,10 @@
 
 /* Add unsigned integer type setting into give configuration
  */
-int th_cfg_add_uint(cfgitem_t **cfg, char *name,
+int th_cfg_add_uint(th_cfgitem_t **cfg, const char *name,
                     unsigned int *itemData, unsigned int itemDef)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_UINT, (void *) itemData);
     if (node == NULL)
@@ -122,10 +122,10 @@
 
 /* Add strint type setting into given configuration
  */
-int th_cfg_add_string(cfgitem_t **cfg, char *name,
+int th_cfg_add_string(th_cfgitem_t **cfg, const char *name,
                       char **itemData, char *itemDef)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_STRING, (void *) itemData);
     if (node == NULL)
@@ -139,10 +139,10 @@
 
 /* Add boolean type setting into given configuration
  */
-int th_cfg_add_bool(cfgitem_t **cfg, char *name,
+int th_cfg_add_bool(th_cfgitem_t **cfg, const char *name,
                     BOOL *itemData, BOOL itemDef)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_BOOL, (void *) itemData);
     if (node == NULL)
@@ -156,9 +156,9 @@
 
 /* Add implicit comment
  */
-int th_cfg_add_comment(cfgitem_t **cfg, char *comment)
+int th_cfg_add_comment(th_cfgitem_t **cfg, const char *comment)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, comment, ITEM_COMMENT, NULL);
     if (node == NULL)
@@ -170,9 +170,9 @@
 
 /* Add new section
  */
-int th_cfg_add_section(cfgitem_t **cfg, char *name, cfgitem_t *data)
+int th_cfg_add_section(th_cfgitem_t **cfg, const char *name, th_cfgitem_t *data)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     node = th_cfg_add(cfg, name, ITEM_SECTION, (void *) data);
     if (node == NULL)
@@ -182,9 +182,9 @@
 }
 
 
-int th_cfg_add_string_list(cfgitem_t **cfg, char *name, qlist_t **data)
+int th_cfg_add_string_list(th_cfgitem_t **cfg, const char *name, qlist_t **data)
 {
-    cfgitem_t *node;
+    th_cfgitem_t *node;
 
     if (data == NULL)
         return -5;
@@ -218,28 +218,9 @@
 #define VADDCH(ch) if (strPos < SET_MAX_BUF) { tmpStr[strPos++] = ch; }
 #define VISEND(ch) (ch == '\r' || ch == '\n' || ch == ';' || th_isspace(c) || ch == '#')
 
-typedef struct
-{
-    FILE *file;
-    char *filename;
-    size_t line;
-} conffile_t;
-
-
-static void th_cfg_error(conffile_t *f, const char *fmt, ...)
+static int th_cfg_read_sect(th_ioctx_t *ctx, th_cfgitem_t *cfg, int nesting)
 {
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "%s: '%s', line #%d: ", th_prog_name, f->filename,
-            (unsigned int) f->line);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-}
-
-
-static int th_cfg_read_sect(conffile_t *f, cfgitem_t *cfg, int nesting)
-{
-    cfgitem_t *item = NULL;
+    th_cfgitem_t *item = NULL;
     char tmpStr[SET_MAX_BUF + 1];
     size_t strPos;
     int c, parseMode, prevMode, nextMode, tmpCh;
@@ -258,12 +239,12 @@
         if (c == -1)
         {
             /* Get next character */
-            switch (c = fgetc(f->file))
+            switch (c = fgetc(ctx->fp))
             {
             case EOF:
                 if (parseMode != PM_NORMAL)
                 {
-                    th_cfg_error(f, "Unexpected end of file.\n");
+                    th_ioctx_error(ctx, -1, "Unexpected end of file.\n");
                     parseMode = PM_ERROR;
                 }
                 else
@@ -271,7 +252,7 @@
                 break;
 
             case '\n':
-                f->line++;
+                ctx->line++;
             }
         }
 
@@ -309,8 +290,8 @@
                 }
                 else
                 {
-                    th_cfg_error(f,
-                                 "Invalid nesting sequence encountered.\n");
+                    th_ioctx_error(ctx, -1,
+                        "Invalid nesting sequence encountered.\n");
                     parseMode = PM_ERROR;
                 }
             }
@@ -324,7 +305,7 @@
             else
             {
                 /* Error! Invalid character found */
-                th_cfg_error(f, "Unexpected character '%c'.\n", c);
+                th_ioctx_error(ctx, -1, "Unexpected character '%c'.\n", c);
                 parseMode = PM_ERROR;
             }
             break;
@@ -352,7 +333,7 @@
                 else
                 {
                     /* Error! Key name string too long! */
-                    th_cfg_error(f, "Config key name too long!");
+                    th_ioctx_error(ctx, -1, "Config key name too long!");
                     parseMode = PM_ERROR;
                 }
                 c = -1;
@@ -361,9 +342,9 @@
             {
                 /* Error! Invalid character found */
                 tmpStr[strPos] = 0;
-                th_cfg_error(f,
-                             "Unexpected character '%c' in key name '%s'.\n",
-                             c, tmpStr);
+                th_ioctx_error(ctx, -1,
+                    "Unexpected character '%c' in key name '%s'.\n",
+                    c, tmpStr);
                 parseMode = PM_ERROR;
             }
             break;
@@ -420,9 +401,9 @@
                 else
                 {
                     /* Error! No configuration key by this name found */
-                    th_cfg_error(f,
-                                 "No such configuration setting ('%s')\n",
-                                 tmpStr);
+                    th_ioctx_error(ctx, -1,
+                        "No such configuration setting ('%s')\n",
+                        tmpStr);
                     parseMode = PM_ERROR;
                 }
 
@@ -431,9 +412,9 @@
             else
             {
                 /* Error! '=' expected! */
-                th_cfg_error(f,
-                             "Unexpected character '%c', assignation '=' was expected.\n",
-                             c);
+                th_ioctx_error(ctx, -1,
+                    "Unexpected character '%c', assignation '=' was expected.\n",
+                    c);
                 parseMode = PM_ERROR;
             }
             break;
@@ -495,14 +476,14 @@
             if (c != '{')
             {
                 /* Error! Section start '{' expected! */
-                th_cfg_error(f,
-                             "Unexpected character '%c', section start '{' was expected.\n",
-                             c);
+                th_ioctx_error(ctx, -1,
+                    "Unexpected character '%c', section start '{' was expected.\n",
+                    c);
                 parseMode = PM_ERROR;
             }
             else
             {
-                int res = th_cfg_read_sect(f, item->v.section, nesting + 1);
+                int res = th_cfg_read_sect(ctx, item->v.section, nesting + 1);
                 c = -1;
                 if (res > 0)
                     validError = TRUE;
@@ -558,9 +539,9 @@
                 else
                 {
                     /* Error! String too long! */
-                    th_cfg_error(f,
-                                 "String too long! Maximum is %d characters.",
-                                 SET_MAX_BUF);
+                    th_ioctx_error(ctx, -1,
+                        "String too long! Maximum is %d characters.",
+                        SET_MAX_BUF);
                     parseMode = PM_ERROR;
                 }
             }
@@ -573,9 +554,9 @@
             if (isStart && item->type == ITEM_UINT && c == '-')
             {
                 /* Error! Negative values not allowed for unsigned ints */
-                th_cfg_error(f,
-                             "Negative value specified for %s, unsigned value expected.",
-                             item->name);
+                th_ioctx_error(ctx, -1,
+                    "Negative value specified for %s, unsigned value expected.",
+                    item->name);
                 parseMode = PM_ERROR;
             }
             else if (isStart && (c == '-' || c == '+'))
@@ -611,17 +592,18 @@
             else
             {
                 /* Error! Unexpected character. */
-                th_cfg_error(f,
-                             "Unexpected character '%c' for integer setting '%s'.",
-                             c, item->name);
+                th_ioctx_error(ctx, -1,
+                    "Unexpected character '%c' for integer setting '%s'.",
+                    c, item->name);
                 parseMode = PM_ERROR;
             }
 
             if (isError)
             {
                 /* Error! String too long! */
-                th_cfg_error(f, "String too long! Maximum is %d characters.",
-                             SET_MAX_BUF);
+                th_ioctx_error(ctx, -1,
+                    "String too long! Maximum is %d characters.",
+                    SET_MAX_BUF);
                 parseMode = PM_ERROR;
             }
 
@@ -665,8 +647,9 @@
 
                 if (isError)
                 {
-                    th_cfg_error(f, "Invalid boolean value for '%s'.\n",
-                                 item->name);
+                    th_ioctx_error(ctx, -1,
+                        "Invalid boolean value for '%s'.\n",
+                        item->name);
                     parseMode = PM_ERROR;
                 }
                 else
@@ -694,56 +677,53 @@
 }
 
 
-int th_cfg_read(FILE *inFile, char *filename, cfgitem_t *cfg)
+int th_cfg_read(th_ioctx_t *ctx, th_cfgitem_t *cfg)
 {
-    conffile_t f;
+    if (ctx == NULL || cfg == NULL)
+        return -1;
 
-    f.file = inFile;
-    f.filename = filename;
-    f.line = 1;
-
-    return th_cfg_read_sect(&f, cfg, 0);
+    return th_cfg_read_sect(ctx, cfg, 0);
 }
 
 
 /* Write a configuration into file
  */
-static void th_print_indent(conffile_t *f, int nesting)
+static void th_print_indent(th_ioctx_t *ctx, int nesting)
 {
     int i;
     for (i = 0; i < nesting * 2; i++)
-        fputc(' ', f->file);
+        fputc(' ', ctx->fp);
 }
 
 
-static int th_cfg_write_sect(conffile_t *f, cfgitem_t *item, int nesting)
+static int th_cfg_write_sect(th_ioctx_t *ctx, const th_cfgitem_t *item, int nesting)
 {
     while (item != NULL)
     {
         if (item->type == ITEM_COMMENT)
         {
-            th_print_indent(f, nesting);
-            if (fprintf
-                (f->file, "# %s\n",
-                 (item->name != NULL) ? item->name : "") < 0)
+            th_print_indent(ctx, nesting);
+            if (fprintf(ctx->fp, "# %s\n",
+                (item->name != NULL) ? item->name : "") < 0)
                 return -1;
         }
         else if (item->name != NULL)
         {
-            th_print_indent(f, nesting);
+            th_print_indent(ctx, nesting);
 
             switch (item->type)
             {
             case ITEM_STRING:
                 if (*(item->v.val_str) == NULL)
                 {
-                    if (fprintf(f->file, "#%s = \"\"\n", item->name) < 0)
+                    if (fprintf(ctx->fp, "#%s = \"\"\n",
+                        item->name) < 0)
                         return -3;
                 }
                 else
                 {
-                    if (fprintf(f->file, "%s = \"%s\"\n",
-                                item->name, *(item->v.val_str)) < 0)
+                    if (fprintf(ctx->fp, "%s = \"%s\"\n",
+                        item->name, *(item->v.val_str)) < 0)
                         return -3;
                 }
                 break;
@@ -751,70 +731,69 @@
             case ITEM_STRING_LIST:
                 if (*(item->v.list) == NULL)
                 {
-                    if (fprintf(f->file, "#%s = \"\", \"\"\n", item->name) <
-                        0)
+                    if (fprintf(ctx->fp,
+                        "#%s = \"\", \"\"\n", item->name) < 0)
                         return -3;
                 }
                 else
                 {
                     qlist_t *node = *(item->v.list);
                     size_t n = th_llist_length(node);
-                    if (fprintf(f->file, "%s = ", item->name) < 0)
+                    if (fprintf(ctx->fp, "%s = ", item->name) < 0)
                         return -3;
 
                     while (node != NULL)
                     {
                         if (node->data != NULL)
-                            fprintf(f->file, "\"%s\"", (char *) node->data);
+                            fprintf(ctx->fp, "\"%s\"", (char *) node->data);
 
                         if (--n > 0)
                         {
-                            fprintf(f->file, ",\n");
-                            th_print_indent(f, nesting);
+                            fprintf(ctx->fp, ",\n");
+                            th_print_indent(ctx, nesting);
                         }
                         node = node->next;
                     }
 
-                    if (fprintf(f->file, "\n") < 0)
+                    if (fprintf(ctx->fp, "\n") < 0)
                         return -3;
                 }
                 break;
 
             case ITEM_INT:
-                if (fprintf(f->file, "%s = %i\n",
-                            item->name, *(item->v.val_int)) < 0)
+                if (fprintf(ctx->fp, "%s = %i\n",
+                    item->name, *(item->v.val_int)) < 0)
                     return -4;
                 break;
 
             case ITEM_UINT:
-                if (fprintf(f->file, "%s = %d\n",
-                            item->name, *(item->v.val_uint)) < 0)
+                if (fprintf(ctx->fp, "%s = %d\n",
+                    item->name, *(item->v.val_uint)) < 0)
                     return -5;
                 break;
 
             case ITEM_BOOL:
-                if (fprintf(f->file, "%s = %s\n",
-                            item->name,
-                            *(item->v.val_bool) ? "yes" : "no") < 0)
+                if (fprintf(ctx->fp, "%s = %s\n", item->name,
+                    *(item->v.val_bool) ? "yes" : "no") < 0)
                     return -6;
                 break;
 
             case ITEM_SECTION:
                 {
                     int res;
-                    if (fprintf(f->file, "%s = {\n", item->name) < 0)
+                    if (fprintf(ctx->fp, "%s = {\n", item->name) < 0)
                         return -7;
-                    res = th_cfg_write_sect(f, item->v.section, nesting + 1);
+                    res = th_cfg_write_sect(ctx, item->v.section, nesting + 1);
                     if (res != 0)
                         return res;
-                    if (fprintf(f->file, "}\n\n") < 0)
+                    if (fprintf(ctx->fp, "}\n\n") < 0)
                         return -8;
                 }
                 break;
 
             case ITEM_HEX_TRIPLET:
-                if (fprintf(f->file, "%s = \"%06x\"\n",
-                            item->name, *(item->v.val_int)) < 0)
+                if (fprintf(ctx->fp, "%s = \"%06x\"\n",
+                    item->name, *(item->v.val_int)) < 0)
                     return -6;
                 break;
             }
@@ -826,19 +805,13 @@
 }
 
 
-int th_cfg_write(FILE *outFile, char *filename, cfgitem_t *cfg)
+int th_cfg_write(th_ioctx_t *ctx, const th_cfgitem_t *cfg)
 {
-    conffile_t f;
-
-    if (cfg == NULL)
+    if (ctx == NULL || cfg == NULL)
         return -1;
 
-    f.file = outFile;
-    f.filename = filename;
-    f.line = 1;
-
-    fprintf(outFile, "# Configuration written by %s %s\n\n",
+    fprintf(ctx->fp, "# Configuration written by %s %s\n\n",
             th_prog_desc, th_prog_version);
 
-    return th_cfg_write_sect(&f, cfg, 0);
+    return th_cfg_write_sect(ctx, cfg, 0);
 }
--- a/th_config.h	Thu Nov 15 19:22:42 2012 +0200
+++ b/th_config.h	Thu Nov 15 19:32:00 2012 +0200
@@ -12,8 +12,7 @@
 extern "C" {
 #endif
 
-#include "th_util.h"
-#include <stdio.h>
+#include "th_ioctx.h"
 
 
 /* Definitions
@@ -34,7 +33,8 @@
 };
 
 
-typedef struct _cfgitem_t {
+typedef struct _th_cfgitem_t
+{
     int  type;
     char *name;
     union {
@@ -45,29 +45,30 @@
 
         void *data;
         qlist_t **list;
-        struct _cfgitem_t *section;
+        struct _th_cfgitem_t *section;
     } v;
     
-    struct _cfgitem_t *next, *prev;
-} cfgitem_t;
+    struct _th_cfgitem_t *next, *prev;
+} th_cfgitem_t;
 
 
 /* Functions
  */
-int     th_cfg_read(FILE *, char *, cfgitem_t *);
-void    th_cfg_free(cfgitem_t *);
-int     th_cfg_write(FILE *, char *, cfgitem_t *);
+int     th_cfg_read(th_ioctx_t *, th_cfgitem_t *);
+void    th_cfg_free(th_cfgitem_t *);
+int     th_cfg_write(th_ioctx_t *, const th_cfgitem_t *);
+
+int     th_cfg_add_section(th_cfgitem_t **cfg, const char *name, th_cfgitem_t *data);
+int     th_cfg_add_comment(th_cfgitem_t **cfg, const char *comment);
 
-int     th_cfg_add_section(cfgitem_t **cfg, char *name, cfgitem_t *data);
-int     th_cfg_add_comment(cfgitem_t **cfg, char *comment);
-int     th_cfg_add_int(cfgitem_t **cfg, char *name, int *data, int itemDef);
-int     th_cfg_add_uint(cfgitem_t **cfg, char *name, unsigned int *data, unsigned int itemDef);
-int     th_cfg_add_string(cfgitem_t **cfg, char *name, char **data, char *itemDef);
-int     th_cfg_add_bool(cfgitem_t **cfg, char *name, BOOL *data, BOOL itemDef);
-int     th_cfg_add_float(cfgitem_t **cfg, char *name, float *data, float itemDef);
-int     th_cfg_add_hexvalue(cfgitem_t **cfg, char *name, int *data, int itemDef);
+int     th_cfg_add_int(th_cfgitem_t **cfg, const char *name, int *data, int itemDef);
+int     th_cfg_add_uint(th_cfgitem_t **cfg, const char *name, unsigned int *data, unsigned int itemDef);
+int     th_cfg_add_string(th_cfgitem_t **cfg, const char *name, char **data, char *itemDef);
+int     th_cfg_add_bool(th_cfgitem_t **cfg, const char *name, BOOL *data, BOOL itemDef);
+int     th_cfg_add_float(th_cfgitem_t **cfg, const char *name, float *data, float itemDef);
+int     th_cfg_add_hexvalue(th_cfgitem_t **cfg, const char *name, int *data, int itemDef);
+int     th_cfg_add_string_list(th_cfgitem_t **cfg, const char *name, qlist_t **list);
 
-int     th_cfg_add_string_list(cfgitem_t **cfg, char *name, qlist_t **list);
 
 #ifdef __cplusplus
 }