diff th_config.c @ 16:0cea9c0cfce7

Sync.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 02 Nov 2010 23:22:44 +0200
parents 4adf7093060c
children 05a44cbd1150
line wrap: on
line diff
--- a/th_config.c	Sat Oct 30 17:48:40 2010 +0300
+++ b/th_config.c	Tue Nov 02 23:22:44 2010 +0200
@@ -1,7 +1,7 @@
 /*
  * Very simple configuration handling functions
  * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2004-2008 Tecnic Software productions (TNSP)
+ * (C) Copyright 2004-2010 Tecnic Software productions (TNSP)
  *
  * Please read file 'COPYING' for information on license and distribution.
  */
@@ -19,15 +19,15 @@
 
 /* Free a given configuration (the values are not free'd)
  */
-void th_config_free(cfgitem_t *cfg)
+void th_cfg_free(cfgitem_t *cfg)
 {
     cfgitem_t *curr = cfg;
 
     while (curr != NULL) {
         cfgitem_t *next = curr->next;
         
-        if (curr->type == ITEM_BLOCK)
-            th_config_free((cfgitem_t *) curr->data);
+        if (curr->type == ITEM_SECTION)
+            th_cfg_free((cfgitem_t *) curr->data);
         
         th_free(curr->name);
         th_free(curr);
@@ -38,8 +38,7 @@
 
 /* Allocate and add new item to configuration
  */
-static cfgitem_t *th_config_add(cfgitem_t **cfg, char *name, int type,
-                 BOOL (*validate)(cfgitem_t *), void *data)
+static cfgitem_t *th_cfg_add(cfgitem_t **cfg, const char *name, const int type, void *data)
 {
     cfgitem_t *node;
 
@@ -54,7 +53,6 @@
     /* Set values */
     node->type = type;
     node->data = data;
-    node->validate = validate;
     node->name = th_strdup(name);
     
     /* Insert into linked list */
@@ -74,12 +72,12 @@
 
 /* Add integer type setting into give configuration
  */
-int th_config_add_int(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *),
+int th_cfg_add_int(cfgitem_t ** cfg, char * name,
               int *itemData, int itemDef)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, name, ITEM_INT, itemValidate, (void *) itemData);
+    node = th_cfg_add(cfg, name, ITEM_INT, (void *) itemData);
     if (node == NULL)
         return -1;
 
@@ -89,12 +87,12 @@
 }
 
 
-int th_config_add_hexvalue(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *),
+int th_cfg_add_hexvalue(cfgitem_t ** cfg, char * name,
               int *itemData, int itemDef)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, name, ITEM_HEX_TRIPLET, itemValidate, (void *) itemData);
+    node = th_cfg_add(cfg, name, ITEM_HEX_TRIPLET, (void *) itemData);
     if (node == NULL)
         return -1;
 
@@ -106,12 +104,12 @@
 
 /* Add unsigned integer type setting into give configuration
  */
-int th_config_add_uint(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *),
+int th_cfg_add_uint(cfgitem_t ** cfg, char * name,
                unsigned int * itemData, unsigned int itemDef)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, name, ITEM_UINT, itemValidate, (void *) itemData);
+    node = th_cfg_add(cfg, name, ITEM_UINT, (void *) itemData);
     if (node == NULL)
         return -1;
 
@@ -123,12 +121,12 @@
 
 /* Add strint type setting into given configuration
  */
-int th_config_add_string(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *),
+int th_cfg_add_string(cfgitem_t ** cfg, char * name,
               char ** itemData, char * itemDef)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, name, ITEM_STRING, itemValidate, (void *) itemData);
+    node = th_cfg_add(cfg, name, ITEM_STRING, (void *) itemData);
     if (node == NULL)
         return -1;
 
@@ -140,12 +138,12 @@
 
 /* Add boolean type setting into given configuration
  */
-int th_config_add_bool(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *),
+int th_cfg_add_bool(cfgitem_t ** cfg, char * name,
                BOOL * itemData, BOOL itemDef)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, name, ITEM_BOOL, itemValidate, (void *) itemData);
+    node = th_cfg_add(cfg, name, ITEM_BOOL, (void *) itemData);
     if (node == NULL)
         return -1;
 
@@ -157,11 +155,11 @@
 
 /* Add implicit comment
  */
-int th_config_add_comment(cfgitem_t ** cfg, char * comment)
+int th_cfg_add_comment(cfgitem_t ** cfg, char * comment)
 {
     cfgitem_t *node;
 
-    node = th_config_add(cfg, comment, ITEM_COMMENT, NULL, NULL);
+    node = th_cfg_add(cfg, comment, ITEM_COMMENT, NULL);
     if (node == NULL)
         return -1;
 
@@ -169,13 +167,28 @@
 }
 
 
-/* Add new block
+/* Add new section
  */
-int th_config_add_section(cfgitem_t ** cfg, char * name, cfgitem_t *data)
+int th_cfg_add_section(cfgitem_t ** cfg, char * name, cfgitem_t *data)
 {
     cfgitem_t *node;
     
-    node = th_config_add(cfg, name, ITEM_BLOCK, NULL, (void *) data);
+    node = th_cfg_add(cfg, name, ITEM_SECTION, (void *) data);
+    if (node == NULL)
+        return -1;
+
+    return 0;
+}
+
+
+int th_cfg_add_string_list(cfgitem_t ** cfg, char * name, qlist_t **data)
+{
+    cfgitem_t *node;
+    
+    if (data == NULL)
+        return -5;
+    
+    node = th_cfg_add(cfg, name, ITEM_STRING_LIST, (void *) data);
     if (node == NULL)
         return -1;
 
@@ -196,7 +209,8 @@
     PM_STRING,
     PM_INT,
     PM_BOOL,
-    PM_BLOCK
+    PM_SECTION,
+    PM_ARRAY
 };
 
 #define VADDCH(ch) if (strPos < SET_MAX_BUF) { tmpStr[strPos++] = ch; }
@@ -209,7 +223,7 @@
 } conffile_t;
 
 
-static void th_config_error(conffile_t *f, const char *fmt, ...)
+static void th_cfg_error(conffile_t *f, const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
@@ -219,7 +233,7 @@
 }
 
 
-static int th_config_read_sect(conffile_t *f, cfgitem_t * cfg, int nesting)
+static int th_cfg_read_sect(conffile_t *f, cfgitem_t * cfg, int nesting)
 {
     cfgitem_t *item = NULL;
     char tmpStr[SET_MAX_BUF + 1];
@@ -241,7 +255,7 @@
             switch (c = fgetc(f->file)) {
             case EOF:
                 if (parseMode != PM_NORMAL) {
-                    th_config_error(f,
+                    th_cfg_error(f,
                     "Unexpected end of file.\n");
                     parseMode = PM_ERROR;
                 } else
@@ -277,8 +291,7 @@
                     /* Check for validation errors */
                     return (validError) ? 1 : 0;
                 } else {
-                    th_config_error(f,
-                    "HMMM!\n");
+                    th_cfg_error(f, "Invalid nesting sequence encountered.\n");
                     parseMode = PM_ERROR;
                 }
             } else if (th_isalpha(c)) {
@@ -288,7 +301,7 @@
                 strPos = 0;
             } else {
                 /* Error! Invalid character found */
-                th_config_error(f,
+                th_cfg_error(f,
                     "Unexpected character '%c'.\n", c);
                 parseMode = PM_ERROR;
             }
@@ -312,7 +325,7 @@
                 else
                 {
                     /* Error! Key name string too long! */
-                    th_config_error(f,
+                    th_cfg_error(f,
                         "Config key name too long!");
                     parseMode = PM_ERROR;
                 }
@@ -320,7 +333,7 @@
             } else {
                 /* Error! Invalid character found */
                 tmpStr[strPos] = 0;
-                th_config_error(f,
+                th_cfg_error(f,
                     "Unexpected character '%c' in key name '%s'.\n", c, tmpStr);
                 parseMode = PM_ERROR;
             }
@@ -348,6 +361,10 @@
                         nextMode = PM_STRING;
                         break;
 
+                    case ITEM_STRING_LIST:
+                        nextMode = PM_ARRAY;
+                        break;
+
                     case ITEM_INT:
                     case ITEM_UINT:
                         nextMode = PM_INT;
@@ -357,8 +374,8 @@
                         nextMode = PM_BOOL;
                         break;
                     
-                    case ITEM_BLOCK:
-                        nextMode = PM_BLOCK;
+                    case ITEM_SECTION:
+                        nextMode = PM_SECTION;
                         break;
                     }
 
@@ -368,7 +385,7 @@
                     strPos = 0;
                 } else {
                     /* Error! No configuration key by this name found */
-                    th_config_error(f,
+                    th_cfg_error(f,
                         "No such configuration setting ('%s')\n", tmpStr);
                     parseMode = PM_ERROR;
                 }
@@ -376,7 +393,7 @@
                 c = -1;
             } else {
                 /* Error! '=' expected! */
-                th_config_error(f,
+                th_cfg_error(f,
                     "Unexpected character '%c', assignation '=' was expected.\n", c);
                 parseMode = PM_ERROR;
             }
@@ -398,15 +415,39 @@
             }
             break;
 
-        case PM_BLOCK:
-            /* Block parsing mode */
+        case PM_ARRAY:
+            if (isStart) {
+                switch (item->type) {
+                    case ITEM_STRING_LIST:
+                        prevMode = parseMode;
+                        parseMode = PM_STRING;
+                        break;
+                }
+            } else if (c == ',') {
+                switch (item->type) {
+                    case ITEM_STRING_LIST:
+                        c = -1;
+                        isStart = TRUE;
+                        prevMode = parseMode;
+                        parseMode = PM_NEXT;
+                        nextMode = PM_STRING;
+                        break;
+                }
+            } else {
+                prevMode = parseMode;
+                parseMode = PM_NORMAL;
+            }
+            break;
+
+        case PM_SECTION:
+            /* Section parsing mode */
             if (c != '{') {
-                /* Error! Block start '{' expected! */
-                th_config_error(f,
-                    "Unexpected character '%c', block start '{' was expected.\n", c);
+                /* Error! Section start '{' expected! */
+                th_cfg_error(f,
+                    "Unexpected character '%c', section start '{' was expected.\n", c);
                 parseMode = PM_ERROR;
             } else {
-                int res = th_config_read_sect(f, (cfgitem_t *) item->data, nesting + 1);
+                int res = th_cfg_read_sect(f, (cfgitem_t *) item->data, nesting + 1);
                 c = -1;
                 if (res > 0)
                     validError = TRUE;
@@ -430,23 +471,32 @@
                 /* End of string, set the value */
                 tmpStr[strPos] = 0;
                 
-                if (item->type == ITEM_HEX_TRIPLET) {
-                } else if (item->type == ITEM_STRING) {
-                    th_pstrcpy((char **) item->data, tmpStr);
+                switch (item->type) {
+                    case ITEM_HEX_TRIPLET:
+                        *(int *) item->data = th_get_hex_triplet(tmpStr);
+                        prevMode = parseMode;
+                        parseMode = PM_NORMAL;
+                        break;
+                    case ITEM_STRING:
+                        th_pstrcpy((char **) item->data, tmpStr);
+                        prevMode = parseMode;
+                        parseMode = PM_NORMAL;
+                        break;
+                    case ITEM_STRING_LIST:
+                        th_llist_append(item->list, th_strdup(tmpStr));
+                        prevMode = parseMode;
+                        parseMode = PM_NEXT;
+                        nextMode = PM_ARRAY;
+                        break;
                 }
                 
-                if (item->validate != NULL && !item->validate(item))
-                    validError = TRUE;
-
-                prevMode = parseMode;
-                parseMode = PM_NORMAL;
             } else {
                 /* Add character to string */
                 VADDCH(c)
                 else
                 {
                     /* Error! String too long! */
-                    th_config_error(f,
+                    th_cfg_error(f,
                         "String too long! Maximum is %d characters.",
                         SET_MAX_BUF);
                     parseMode = PM_ERROR;
@@ -460,7 +510,7 @@
             /* Integer parsing mode */
             if (isStart && item->type == ITEM_UINT && c == '-') {
                 /* Error! Negative values not allowed for unsigned ints */
-                th_config_error(f,
+                th_cfg_error(f,
                         "Negative value specified for %s, unsigned value expected.",
                         item->name);
                 parseMode = PM_ERROR;
@@ -484,14 +534,12 @@
                     *((unsigned int *) item->data) = atol(tmpStr);
                     break;
                 }
-                if (item->validate != NULL && !item->validate(item))
-                    validError = TRUE;
 
                 prevMode = parseMode;
                 parseMode = PM_NORMAL;
             } else {
                 /* Error! Unexpected character. */
-                th_config_error(f,
+                th_cfg_error(f,
                     "Unexpected character '%c' for integer setting '%s'.",
                     c, item->name);
                 parseMode = PM_ERROR;
@@ -499,7 +547,7 @@
 
             if (isError) {
                 /* Error! String too long! */
-                th_config_error(f, "String too long! Maximum is %d characters.",
+                th_cfg_error(f, "String too long! Maximum is %d characters.",
                         SET_MAX_BUF);
                 parseMode = PM_ERROR;
             }
@@ -535,14 +583,11 @@
                 }
                 
                 if (isError) {
-                    th_config_error(f, "Invalid boolean value for '%s'.\n", item->name);
+                    th_cfg_error(f, "Invalid boolean value for '%s'.\n", item->name);
                     parseMode = PM_ERROR;
                 } else {
                     *((BOOL *) item->data) = tmpBool;
 
-                    if (item->validate != NULL && !item->validate(item))
-                        validError = TRUE;
-
                     prevMode = parseMode;
                     parseMode = PM_NORMAL;
                 }
@@ -564,7 +609,7 @@
 }
 
 
-int th_config_read(FILE *inFile, char *filename, cfgitem_t * cfg)
+int th_cfg_read(FILE *inFile, char *filename, cfgitem_t * cfg)
 {
     conffile_t f;
     
@@ -572,7 +617,7 @@
     f.filename = filename;
     f.line = 1;
     
-    return th_config_read_sect(&f, cfg, 0);
+    return th_cfg_read_sect(&f, cfg, 0);
 }
 
 
@@ -586,7 +631,7 @@
 }
 
 
-static int th_config_write_sect(conffile_t *f, cfgitem_t *item, int nesting)
+static int th_cfg_write_sect(conffile_t *f, cfgitem_t *item, int nesting)
 {
     while (item != NULL) {
         if (item->type == ITEM_COMMENT) {
@@ -599,42 +644,67 @@
             
             switch (item->type) {
             case ITEM_STRING:
-                if (*((char **) item->data) == NULL) {
+                if (*(item->val_str) == NULL) {
                     if (fprintf(f->file, "#%s = \"\"\n", item->name) < 0)
                         return -3;
                 } else {
                     if (fprintf(f->file, "%s = \"%s\"\n",
-                        item->name, *((char **) item->data)) < 0)
+                        item->name, *(item->val_str)) < 0)
+                        return -3;
+                }
+                break;
+
+            case ITEM_STRING_LIST:
+                if (*(item->list) == NULL) {
+                    if (fprintf(f->file, "#%s = \"\", \"\"\n", item->name) < 0)
+                        return -3;
+                } else {
+                    qlist_t *node = *(item->list);
+                    size_t n = th_llist_length(node);
+                    if (fprintf(f->file, "%s = ", item->name) < 0)
+                        return -3;
+                    
+                    while (node != NULL) {
+                        if (node->data != NULL)
+                            fprintf(f->file, "\"%s\"", (char *) node->data);
+
+                        if (--n > 0)
+                            fprintf(f->file, ", ");
+                        
+                        node = node->next;
+                    }
+
+                    if (fprintf(f->file, "\n") < 0)
                         return -3;
                 }
                 break;
 
             case ITEM_INT:
                 if (fprintf(f->file, "%s = %i\n",
-                    item->name, *((int *) item->data)) < 0)
+                    item->name, *(item->val_int)) < 0)
                     return -4;
                 break;
 
             case ITEM_UINT:
                 if (fprintf(f->file, "%s = %d\n",
-                    item->name, *((unsigned int *) item->data)) < 0)
+                    item->name, *(item->val_uint)) < 0)
                     return -5;
                 break;
 
             case ITEM_BOOL:
                 if (fprintf(f->file, "%s = %s\n",
-                    item->name, *((BOOL *) item->data) ? "yes" : "no") < 0)
+                    item->name, *(item->val_bool) ? "yes" : "no") < 0)
                     return -6;
                 break;
             
-            case ITEM_BLOCK:
+            case ITEM_SECTION:
                 {
                 int res;
-                if (fprintf(f->file, "\n%s = {\n", item->name) < 0)
+                if (fprintf(f->file, "%s = {\n", item->name) < 0)
                     return -7;
-                res = th_config_write_sect(f, (cfgitem_t *) item->data, nesting + 1);
+                res = th_cfg_write_sect(f, (cfgitem_t *) item->data, nesting + 1);
                 if (res != 0) return res;
-                if (fprintf(f->file, "} # End of '%s'\n\n", item->name) < 0)
+                if (fprintf(f->file, "}\n\n") < 0)
                     return -8;
                 }
                 break;
@@ -653,7 +723,7 @@
 }
 
 
-int th_config_write(FILE *outFile, char *filename, cfgitem_t *cfg)
+int th_cfg_write(FILE *outFile, char *filename, cfgitem_t *cfg)
 {
     conffile_t f;
     
@@ -667,7 +737,7 @@
     fprintf(outFile, "# Configuration written by %s %s\n\n", 
         th_prog_fullname, th_prog_version);
     
-    return th_config_write_sect(&f, cfg, 0);
+    return th_cfg_write_sect(&f, cfg, 0);
 }