src/server/config/objconf.c

changeset 419
f1d29785ad2d
parent 415
d938228c382e
child 425
6440171c257f
--- a/src/server/config/objconf.c	Mon Nov 07 17:59:44 2022 +0100
+++ b/src/server/config/objconf.c	Mon Nov 07 22:30:12 2022 +0100
@@ -65,6 +65,152 @@
     return conf;
 }
 
+ObjectConfig2* objectconf_load(const char *file) {
+    CxMempool *mp = cxBasicMempoolCreate(512);
+    if(!mp) {
+        return NULL;
+    }
+    
+    // setup parser
+    ConfigParser2 parser;
+    memset(&parser, 0, sizeof(ConfigParser2));
+    parser.mp = mp;
+    parser.validateDirective = objectconf_validate_directive;
+    parser.validateObjBegin = objectconf_validate_objbegin;
+    parser.validateObjEnd = objectconf_validate_objend;
+    parser.allow_hierarchy = 1;
+    
+    ConfigNode *obj_config = serverconfig_load_file(&parser, file);
+    if(!obj_config) {
+        cxMempoolDestroy(mp);
+        return NULL;
+    }
+    
+    ObjectConfig2 *conf = cxMalloc(mp->allocator, sizeof(ObjectConfig2));
+    if(!conf) {
+        cxMempoolDestroy(mp);
+        return NULL;
+    }
+    
+    conf->mp = mp;
+    conf->root = obj_config;
+
+    return conf;
+}
+
+void objectconf_free(ObjectConfig2 *objconf) {
+    cxMempoolDestroy(objconf->mp);
+}
+
+int objectconf_validate_directive(ConfigParser2 *parser, ConfigNode *node) {
+    // It is possible that this function is called for Objects
+    // if { is on the next line
+    // It may be possible to fix the parser to not do that, but it is fine
+    // to just deal with that here
+    
+    // ignore if node->name is an Object name like
+    // Object, Client, If, Else IfElse
+    const char *objnames[] = { "Object", "Client", "If", "ElseIf", "Else" };
+    size_t typeindex;
+    if(!serverconfig_validate_directive_name(node, objnames, 5, &typeindex)) {
+        return 0;
+    }
+    
+    // now check directive type
+    const char *dirtypes[] = { "AuthTrans", "NameTrans", "PathCheck", "ObjectType", "Service", "AddLog", "Error" };
+    if(serverconfig_validate_directive_name(node, dirtypes, 7, &typeindex)) {
+        return 1;
+    }
+    
+    // directives must have parameter names
+    ConfigParam *param_err;
+    if(serverconfig_check_param_names(node, &param_err)) {
+        return 1;
+    }
+    
+    // check if the fn parameter exists
+    cxstring fn = serverconfig_directive_get_arg(node, cx_str("fn"));
+    if(fn.length == 0) {
+        return 1;
+    }
+    
+    return 0;
+}
+
+static int validate_else_node(ConfigNode *node) {
+    // previous node must be "If" or "ElseIf"
+    ConfigNode *prev = serverconfig_previous_dir_or_obj(node);
+    const char *allowed_prev_types[] = { "If", "ElseIf" };
+    size_t typeindex;
+    if(serverconfig_validate_directive_name(prev, allowed_prev_types, 2, &typeindex)) {
+        return 1; // prevous node (not counting space, comments) is not "If" or "Else"
+    }
+    
+    // "Else" must have no args
+    return node->args ? 1 : 0;
+}
+
+static int validate_elseif_node(ConfigNode *node) {
+    // the previous node must be "If" or "IfElse"
+    // in case if "IfElse", we also have to check all previous nodes, until
+    // we find the starting "If" node
+    const char *allowed_prev_types[] = { "If", "ElseIf" };
+    size_t typeindex;
+    ConfigNode *prev = serverconfig_previous_dir_or_obj(node);
+    while(prev) {
+        if(serverconfig_validate_directive_name(prev, allowed_prev_types, 2, &typeindex)) {
+            return 1; // previous node was not "If" or "ElseIf"
+        }
+        // we found a valid "If" node, the whole construct is valid
+        if(typeindex == 0) {
+            return 0;
+        }
+        
+        prev = serverconfig_previous_dir_or_obj(node);
+    }
+    // at this point we found only "IfElse" nodes, but no "If" node
+    return 1;
+}
+
+int objectconf_validate_objbegin(ConfigParser2 *parser, ConfigNode *node) {
+    // get object type
+    const char *objnames[] = { "Object", "Client", "If", "ElseIf", "Else" };
+    size_t typeindex;
+    if(serverconfig_validate_directive_name(node, objnames, 5, &typeindex)) {
+        return 1; // unknown object type
+    }
+    
+    // some special requirements for "Else" node
+    if(typeindex == 4) {
+        // type is "Else"
+        return validate_else_node(node);
+    }
+    
+    // check "ElseIf" was used after "If" or "IfElse"
+    if(typeindex == 3 && validate_elseif_node(node)) {
+        return 1;
+    }
+    
+    // only Object must have a name/value arg, other types can have more
+    // complex parameters
+    if(typeindex == 0) {
+        // type is "Object"
+        ConfigParam *err;
+        if(serverconfig_check_param_names(node, &err)) {
+            return 1;
+        }
+        return 0;
+    }
+
+    // all remaining object types must have arguments, but don't check more
+    return node->args ? 0 : 1;
+}
+
+int objectconf_validate_objend(ConfigParser2 *parser, ConfigNode *node) {
+    return 0;
+}
+
+
 void free_object_config(ObjectConfig *conf) {
     // free other lists
     if(conf->levels) {

mercurial