src/server/config/objconf.c

changeset 16
a9bbd82d2dce
child 17
d2a97bbeb57d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/objconf.c	Sun Jan 15 17:00:16 2012 +0100
@@ -0,0 +1,399 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "objconf.h"
+
+#include <string.h>
+
+/* dev notes:
+ *
+ * to free ObjectConfig, free:
+ *    line dlist
+ *    mempool
+ *    object
+ */
+
+ObjectConfig *load_object_config(char *file) {
+    FILE *in = fopen(file, "r");
+    if(in == NULL) {
+        return NULL;
+    }
+
+    ObjectConfig *conf = malloc(sizeof(ObjectConfig));
+    conf->parser.parse = objconf_parse;
+    conf->file = file;
+
+    int r = cfg_parse_basic_file((ConfigParser*)conf, in);
+    if(r != 0) {
+        // TODO: free
+        return NULL;
+    }
+
+    return conf;
+}
+
+
+
+int objconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
+    ObjectConfig *conf = p;
+
+    begin->type = objconf_get_line_type(line);
+    switch(begin->type) {
+        case LINE_BEGIN_TAG: {
+            ConfigTag *tag = objconf_parse_begin_tag(line, conf->parser.mp);
+            if(tag == NULL) {
+                fprintf(stderr, "Parse error!\n");
+                exit(-1); // TODO: better error handling
+            }
+            tag->begin = begin;
+            tag->end = end;
+            tag->type_num = objconf_get_tag_type(tag->name);
+            //printf("line {%s}\n", sstrdub(ll).ptr);
+            if(objconf_on_begin_tag(conf, tag) != 0) {
+                fprintf(stderr, "1error!\n");
+                exit(-1);
+            }
+            break;
+        }
+        case LINE_END_TAG: {
+            sstr_t tag = objconf_get_end_tag_name(line);
+            if(objconf_on_end_tag(conf, tag) != 0) {
+                fprintf(stderr, "2error!\n");
+                exit(-1);
+            }
+
+            break;
+        }
+        case LINE_DIRECTIVE: {
+            ConfigDirective *dir = objconf_parse_directive(
+                    line,
+                    conf->parser.mp);
+            dir->begin = begin;
+            dir->end = end;
+            if(objconf_on_directive(conf, dir) != 0) {
+                fprintf(stderr, "3error!\n");
+                exit(-1);
+            }
+        }
+    }
+    return 0;
+}
+
+int objconf_on_begin_tag(ObjectConfig *conf, ConfigTag *tag) {
+    if(tag->type_num != TAG_OBJECT) {
+        ConfigParserLevel *l = conf->levels->data;
+        if(l->tag->type_num != TAG_OBJECT) {
+            tag->parent = l->tag;
+        }
+    }
+    
+
+    switch(tag->type_num) {
+        case TAG_OBJECT: {
+            ConfigObject *obj = OBJ_NEW_N(conf->parser.mp, ConfigObject);
+            obj->begin = tag->begin;
+            obj->end = tag->end;
+
+            obj->name = cfg_param_get(tag->param, sstr("name"));
+            obj->ppath = cfg_param_get(tag->param, sstr("ppath"));
+
+            conf->obj = obj;
+            conf->objects = ucx_dlist_append(conf->objects, obj);
+
+            // create tree level object
+            ConfigParserLevel *lvl = OBJ_NEW(conf->parser.mp, ConfigParserLevel);
+            lvl->iftag = NULL;
+            lvl->levelnum = 1;
+            lvl->tag = tag;
+            conf->levels = ucx_list_prepend(conf->levels, lvl);
+
+            break;
+        }
+        case TAG_IF: {
+            // create tree level object
+            ConfigParserLevel *last_lvl = conf->levels->data;
+
+            ConfigParserLevel *lvl = OBJ_NEW(conf->parser.mp, ConfigParserLevel);
+            lvl->iftag = NULL;
+            lvl->levelnum = last_lvl->levelnum + 1;
+            lvl->tag = tag;
+            conf->levels = ucx_list_prepend(conf->levels, lvl);
+            last_lvl->iftag = tag;
+
+            break;
+        }
+        case TAG_ELSEIF: {
+        }
+        case TAG_ELSE: {
+            // create tree level object
+            ConfigParserLevel *last_lvl = conf->levels->data;
+            tag->iftag = last_lvl->iftag;
+
+            ConfigParserLevel *lvl = OBJ_NEW(
+                    conf->parser.mp,
+                    ConfigParserLevel);
+            
+            lvl->iftag = last_lvl->tag;
+            lvl->levelnum = last_lvl->levelnum + 1;
+            lvl->tag = tag;
+            conf->levels = ucx_list_prepend(conf->levels, lvl);
+
+            break;
+        }
+        case TAG_CLIENT: {
+            // create tree level object
+            
+            // TODO
+            
+            break;
+        }
+        default: {
+            printf("unknown tag\n");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+int objconf_on_end_tag(ObjectConfig *conf, sstr_t tagname) {
+    int type = objconf_get_tag_type(tagname);
+    if(type == -1) {
+        fprintf(stderr, "unknown tag\n");
+        return 1;
+    } else {
+        if(type == TAG_OBJECT) {
+            conf->obj = NULL;
+        }
+
+        // remove level
+        conf->levels = ucx_list_remove(conf->levels, conf->levels);
+    }
+    
+    return 0;
+}
+
+int objconf_on_directive(ObjectConfig *conf, ConfigDirective *dir) {
+    ConfigParserLevel *lvl = conf->levels->data;
+
+    // check if we have a condition for the directive
+    // if the level tag is not an object tag, use it as condition
+    if(lvl->tag->type_num != TAG_OBJECT) {
+        dir->condition = lvl->tag;
+    }
+
+    // add directive to current object
+    conf->obj->directives[dir->type_num] = ucx_dlist_append(
+            conf->obj->directives[dir->type_num],
+            dir);
+
+    return 0;
+}
+
+/*
+ * checks if the line contains a begin/end tag or a directive
+ */
+int objconf_get_line_type(sstr_t line) {
+    if(line.length < 3) {
+        // this line is to short to be correct
+        return LINE_ERROR;
+    }
+    
+    if(line.ptr[0] == '<') {
+        // start or end tag
+        // TODO: check for space between '<' and '/'
+        if(line.ptr[1] == '/') {
+            return LINE_END_TAG;
+        } else {
+            return LINE_BEGIN_TAG;
+        }
+    } else {
+        return LINE_DIRECTIVE;
+    }
+}
+
+ConfigTag* objconf_parse_begin_tag(sstr_t line, UcxMempool *mp) {
+    if(line.length < 4) {
+        return NULL; // this line can't contain a valid tag
+    }
+
+    if(line.ptr[0] != '<' || line.ptr[line.length - 1] != '>') {
+        return NULL; // syntax error
+    }
+
+    sstr_t name;
+    name.ptr = line.ptr + 1;
+    int i;
+    for(i=1;i<line.length - 1;i++) {
+        if(line.ptr[i] < 33) { // char is space
+            name.length = i - 1;
+            break;
+        }
+    }
+    if(name.length < 1) {
+        return NULL; // syntax error
+    }
+
+    // create tag object
+    ConfigTag *tag = OBJ_NEW(mp, ConfigTag);
+    tag->name = sstrdub_mp(mp, name);
+    tag->param = NULL;
+
+    // parse parameters
+    sstr_t param_str;
+    param_str.ptr = line.ptr + i;
+    param_str.length = line.length - name.length - 2;
+    param_str = sstrtrim(param_str);
+    if(param_str.length <= 0) {
+        return tag; // no parameters
+    }
+
+    sstr_t pname;
+    sstr_t pvalue;
+    for(;;) {
+        param_str = cfg_param(param_str, &pname, &pvalue);
+        if(pname.length <= 0) {
+            break;
+        }
+
+        // create param object
+        ConfigParam *param = OBJ_NEW(mp, ConfigParam);
+        param->name = sstrdub_mp(mp, pname);
+        if(pvalue.length > 0) {
+            param->value = sstrdub_mp(mp, pvalue);
+        } else {
+            param->value.ptr = NULL;
+            param->value.length = 0;
+        }
+
+        // add param to list
+        tag->param = ucx_list_append(tag->param, param);
+    }
+
+    return tag;
+}
+
+/*
+ * returns the name of the ending tag
+ * on error, this functions returns a zero length string
+ */
+sstr_t objconf_get_end_tag_name(sstr_t line) {
+    sstr_t ns;
+    ns.ptr = NULL;
+    ns.length = 0;
+
+    if(line.length < 4) {
+        // minimum of 4 chars: </a>
+        return ns;
+    }
+
+    sstr_t name;
+    name.ptr = line.ptr + 2;
+    name.length = line.length - 3;
+
+    // check for </ > frame
+    if(line.ptr[0] != '<'
+            || line.ptr[1] != '/'
+            || line.ptr[line.length - 1] != '>')
+    {
+        return ns;
+    }
+
+    return sstrtrim(name);
+}
+
+/*
+ * parses a line containing a directive and returns a ConfigDirective object
+ * or NULL if an error occurs
+ */
+ConfigDirective* objconf_parse_directive(sstr_t line, UcxMempool *mp) {
+    if(line.length < 6) {
+        return NULL; // line too short
+    }
+
+    sstr_t name;
+
+    int i;
+    for(i=0;i<line.length;i++) {
+        if(line.ptr[i] < 33) {
+            break;
+        }
+    }
+    name.ptr = line.ptr;
+    name.length = i;
+
+    // create directive object
+    ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective);
+    directive->directive_type = sstrdub_mp(mp, name);
+    directive->type_num = cfg_get_directive_type_num(name);
+    directive->condition = NULL; // set later by main parsing function
+    directive->param = NULL;
+
+    sstr_t param_str;
+    param_str.ptr = name.ptr + i;
+    param_str.length = line.length - i;
+    param_str = sstrtrim(param_str);
+    sstr_t pname;
+    sstr_t pvalue;
+    for(;;) {
+        param_str = cfg_param(param_str, &pname, &pvalue);
+        if(pname.length <= 0) {
+            break;
+        }
+
+        // create param object
+        ConfigParam *param = OBJ_NEW(mp, ConfigParam);
+        param->name = sstrdub_mp(mp, pname);
+        if(pvalue.length > 0) {
+            param->value = sstrdub_mp(mp, pvalue);
+        } else {
+            param->value.ptr = NULL;
+            param->value.length = 0;
+        }
+
+        // add param to list
+        directive->param = ucx_list_append(directive->param, param);
+    }
+
+    return directive;
+}
+
+int objconf_get_tag_type(sstr_t tag) {
+    if(!sstrcmp(tag, sstr("Object"))) {
+        return TAG_OBJECT;
+    } else if(!sstrcmp(tag, sstr("If"))) {
+        return TAG_IF;
+    } else if(!sstrcmp(tag, sstr("ElseIf"))) {
+        return TAG_ELSEIF;
+    } else if(!sstrcmp(tag, sstr("Else"))) {
+        return TAG_ELSE;
+    } else if(!sstrcmp(tag, sstr("Client"))) {
+        return TAG_CLIENT;
+    }
+    return -1;
+}

mercurial