Sun, 06 Nov 2022 17:41:39 +0100
prepare serverconfig parser to be also used for obj.conf and init.conf
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 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 "conf.h" #include <string.h> int cfg_parse_basic_file(ConfigParser *parser, FILE *in) { parser->lines_begin = NULL; parser->lines_end = NULL; CxMempool *mp = cxBasicMempoolCreate(512); CxAllocator *a = (CxAllocator*)mp->allocator; parser->mp = a; // one logical line over many lines cxmutstr mline; mline.ptr = NULL; mline.length = 0; ConfigLine *start_line = NULL; ConfigLine *end_line = NULL; // read file cxmutstr l; while((l = cfg_readln(in)).ptr != NULL) { void *org_ptr = l.ptr; // put the line to the list ConfigLine *line = OBJ_NEW(parser->mp, ConfigLine); line->line = cx_strdup_a(parser->mp, cx_strcast(l)); // TODO: check for 0-len str line->object = NULL; line->type = LINE_OTHER; CFG_LINE_ADD(&parser->lines_begin, &parser->lines_end, line); // check if the line contains something l = cfg_trim_comment(l); line->type = cfg_get_basic_type(l); if(line->type == LINE_OTHER) { // check for multi line if(mline.ptr != NULL) { // concate lines char *ptr = cxMalloc(a, mline.length + l.length + 1); // TODO: maybe we can use cx_strcat memcpy(ptr, mline.ptr, mline.length); memcpy(ptr + mline.length - 1, l.ptr, l.length); mline.length += l.length; free(mline.ptr); mline.ptr = ptr; mline.ptr[mline.length] = 0; end_line = line; line->type = LINE_MULTI; } if(l.ptr[l.length - 1] == '\\') { if(mline.ptr == NULL) { mline = cx_strdup_a(parser->mp, cx_strcast(l)); start_line = line; } } else { // this line is complete so we can parse it cxmutstr ll; // we parse this line if(mline.ptr == NULL) { // single line ll = l; start_line = line; end_line = line; } else { ll = mline; } // parse int r = parser->parse(parser, start_line, end_line, ll); // clean up if(mline.ptr != NULL) { free(mline.ptr); mline.ptr = NULL; mline.length = 0; start_line = NULL; end_line = NULL; } if(r != 0) { free(org_ptr); return -1; } } } free(org_ptr); } return 0; } cxmutstr cfg_readln(FILE *file) { cxmutstr ns; ns.ptr = NULL; ns.length = 0; if(!feof(file)) { char buf[512]; buf[0] = 0; int len = 512; if(fgets(buf, len, file) == NULL) { return ns; } if(*buf == 0) { printf("???\n"); return ns; } char *ptr; if((ptr = strrchr(buf, '\n'))) { ptr[0] = 0; } cxmutstr line = cx_mutstr(buf); return cx_strdup(cx_strcast(line)); } cxmutstr s; s.ptr = NULL; s.length = 0; return s; } /* * removes a comment from the line */ cxmutstr cfg_trim_comment(cxmutstr line) { cxmutstr nl = line; for(int i=0;i<line.length;i++) { if(line.ptr[i] == '#') { if(i > 0) { nl.ptr = line.ptr + i - 1; nl.length = i; break; } else { nl.ptr = line.ptr; nl.length = 0; break; } } } return cx_strtrim_m(nl); } /* * gets the first parameter in the params string and returns a new string * containing the other parameters or an empty string, if there are no more * parameters */ cxmutstr cfg_param(cxmutstr params, cxmutstr *name, cxmutstr *value) { name->ptr = NULL; name->length = 0; value->ptr = NULL; value->length = 0; // get name int i; for(i=0;i<params.length;i++) { char c = params.ptr[i]; if(c == '=') { break; } else if(c < 33) { // no '=' means there is only a name, no value name->ptr = params.ptr; name->length = i; params.ptr = params.ptr + i; params.length -= i; return cx_strtrim_m(params); } } name->ptr = params.ptr; name->length = i; i++; // get value if(i>=params.length) { cxmutstr ns; ns.ptr = NULL; ns.length = 0; return ns; } int quote = 0; value->ptr = params.ptr + i; for(;i<params.length;i++) { char c = params.ptr[i]; if(c == '"') { if(quote) { break; // end of quoted value } else { quote = 1; value->ptr++; } } else if(!quote && c < 33) { break; // end of value } } if(quote) { // if the value is quoted, i points to the last quote char value->length = i - name->length - 2; // subtract the quotes i++; // set i behind the last quote } else { // i points to a white space char, which must be subtraced value->length = i - name->length - 1; } if(value->length <= 0) { value->length = 0; value->ptr = NULL; } // create new params string params.ptr += i; params.length -= i; return cx_strtrim_m(params); } /* * gets a value from a parameter */ cxmutstr cfg_param_get(ConfigParam *param, cxstring name) { while(param != NULL) { if(!cx_strcmp((cxstring){param->name.ptr, param->name.length}, name)) { return param->value; } param = param->next; } return (cxmutstr){ NULL, 0 }; } /* * parses a line containing a directive and returns a ConfigDirective object * or NULL if an error occurs */ ConfigDirective* cfg_parse_directive(cxmutstr line, CxAllocator *mp) { if(line.length < 6) { log_ereport(LOG_FAILURE, "cfg_parse_directive: line too short"); return NULL; // line too short } cxstring 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 = cx_strdup_a(mp, name); directive->type_num = cfg_get_directive_type_num(name); directive->condition = NULL; // set later by main parsing function //directive->param = NULL; cxstring param_str; param_str.ptr = name.ptr + i; param_str.length = line.length - i; param_str = cx_strtrim(param_str); directive->value = cx_strdup_a(mp, param_str); /* cxmutstr pname; cxmutstr 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 = cx_strdup_mp(mp, pname); if(pvalue.length > 0) { param->value = cx_strdup_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; } ConfigParam* cfg_param_list(cxmutstr param_str, CxAllocator *mp) { cxmutstr pname; cxmutstr pvalue; ConfigParam *plist_begin = NULL; ConfigParam *plist_end = NULL; 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 = cx_strdup_a(mp, cx_strcast(pname)); param->next = NULL; if(pvalue.length > 0) { param->value = cx_strdup_a(mp, cx_strcast(pvalue)); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list CFG_PARAM_ADD(&plist_begin, &plist_end, param); } return plist_begin; } /* * gets the directive type number from a type string * valid types are: * AuthTrans 0 * NameTrans 1 * PathCheck 2 * ObjectType 3 * Service 4 * AddLog 5 * Init 6 */ int cfg_get_directive_type_num(cxstring type) { /* get nsapi function type */ // TODO: replace hard coded numbers int dt = -1; if(cx_strcmp(type, cx_str("AuthTrans")) == 0) { dt = NSAPIAuthTrans; } else if(cx_strcmp(type, cx_str("NameTrans")) == 0) { dt = NSAPINameTrans; } else if(cx_strcmp(type, cx_str("PathCheck")) == 0) { dt = NSAPIPathCheck; } else if(cx_strcmp(type, cx_str("ObjectType")) == 0) { dt = NSAPIObjectType; } else if(cx_strcmp(type, cx_str("Service")) == 0) { dt = NSAPIService; } else if(cx_strcmp(type, cx_str("Error")) == 0) { dt = NSAPIError; } else if(cx_strcmp(type, cx_str("AddLog")) == 0) { dt = NSAPIAddLog; } else if(cx_strcmp(type, cx_str("Init")) == 0) { dt = INIT_DIRECTIVE; } return dt; } /* * checks if the line contains only a comment or space */ int cfg_get_basic_type(cxmutstr line) { if(line.length == 0) { return LINE_NOCONTENT; } else if(line.ptr[0] == '#') { return LINE_NOCONTENT; } return LINE_OTHER; } /* * checks if the line contains a begin/end tag or a directive */ int cfg_get_line_type(cxmutstr 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; } } int cfg_get_tag_type(cxstring tag) { if(!cx_strcmp(tag, cx_str("Object"))) { return TAG_OBJECT; } else if(!cx_strcmp(tag, cx_str("If"))) { return TAG_IF; } else if(!cx_strcmp(tag, cx_str("ElseIf"))) { return TAG_ELSEIF; } else if(!cx_strcmp(tag, cx_str("Else"))) { return TAG_ELSE; } else if(!cx_strcmp(tag, cx_str("Client"))) { return TAG_CLIENT; } return -1; } /* * returns the name of the ending tag * on error, this functions returns a zero length string */ cxmutstr cfg_get_end_tag_name(cxmutstr line) { cxmutstr ns; ns.ptr = NULL; ns.length = 0; if(line.length < 4) { // minimum of 4 chars: </a> return ns; } cxmutstr 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 cx_strtrim_m(name); } ConfigTag* cfg_parse_begin_tag(cxmutstr line, CxAllocator *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 } cxmutstr name; name.ptr = line.ptr + 1; int i; for(i=1;i<line.length - 1;i++) { if(line.ptr[i] < 33) { // char is space break; } } name.length = i - 1; if(name.length < 1) { return NULL; // syntax error } // create tag object ConfigTag *tag = OBJ_NEW(mp, ConfigTag); tag->name = cx_strdup_a(mp, cx_strcast(name)); tag->param = NULL; // parse parameters cxmutstr param_str; param_str.ptr = line.ptr + i; param_str.length = line.length - name.length - 2; param_str = cx_strtrim_m(param_str); if(param_str.length == 0) { return tag; // no parameters } tag->param_str = cx_strdup_a(mp, cx_strcast(param_str)); cxmutstr pname; cxmutstr 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->next = NULL; param->name = cx_strdup_a(mp, cx_strcast(pname)); if(pvalue.length > 0) { param->value = cx_strdup_a(mp, cx_strcast(pvalue)); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list CFG_PARAM_ADD(&tag->param, NULL, param); } return tag; } /* directive functions */ /* * gets a ConfigDirective with a specific name from a List of directives * returns a directive or NULL, if the directive cannot be found */ // TODO: remove /* ConfigDirective* cfg_directivelist_get(UcxList *dirs, cxmutstr name) { while(dirs != NULL) { ConfigDirective *d = dirs->data; if(d != NULL) { if(!cx_strcmp(d->directive_type, name)) { return d; } } dirs = dirs->next; } return NULL; } cxmutstr cfg_directivelist_get_str(UcxList *dirs, cxmutstr name) { ConfigDirective *d = cfg_directivelist_get(dirs, name); if(d == NULL) { cxmutstr n; n.ptr = NULL; n.length = 0; return n; } //return cfg_directive_pstr1(d); return d->value; } */ /* * returns the name of the first parameter of the directive * useful for 'name value' directives */ /* cxmutstr cfg_directive_pstr1(ConfigDirective *dir) { if(dir->param == NULL) { fprintf(stderr, "%s", "Error: cfg_directive_pstr1: param is NULL\n"); cxmutstr n; n.ptr = NULL; n.length = 0; return n; } ConfigParam *p = dir->param->data; return p->name; } static void cfg_list_free(void *list) { ucx_list_free(list); } static void cfg_map_free(void *map) { ucx_map_free(map); } */