Sat, 12 Nov 2022 11:01:11 +0100
add obj.conf expression parser
--- a/src/server/config/serverconfig.c Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/config/serverconfig.c Sat Nov 12 11:01:11 2022 +0100 @@ -96,6 +96,15 @@ return root; } +static int scfg_char_is_delim(char c) { + static const char *scfg_tokenizer_delim = "()+-/*%"; + for(int i=0;i<sizeof(scfg_tokenizer_delim)-1;i++) { + if(c == scfg_tokenizer_delim[i]) { + return 1; + } + } + return 0; +} static CFGToken get_next_token(cxstring content, int *pos) { CFGToken token = { {NULL, 0}, CFG_NO_TOKEN }; @@ -155,7 +164,7 @@ if(token_begin < 0) { token_begin = i; } - } else if(c == '(' || c == ')') { + } else if(scfg_char_is_delim(c)) { if(token_begin >= 0) { token_end = i; i--;
--- a/src/server/daemon/config.c Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/daemon/config.c Sat Nov 12 11:01:11 2022 +0100 @@ -844,18 +844,40 @@ return 0; } -static int set_if_condition(pool_handle_t *pool, ConfigNode *node, Condition *condition) { - printf("\n"); +static int set_if_condition(pool_handle_t *pool, ConfigNode *node, Condition *condition) { + // convert to parameters to a list of tokens + // usually, one parameter is one token, however the config parser + // converts name=value pairs to one ConfigParam - ConfigParam *token = node->args; - while(token) { - printf("token: %s %s\n", token->name.ptr, token->value.ptr); - token = token->next; + // list of cxmutstr, however the expression parser will use this + // as list of cxstring, but that is totally fine + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxmutstr)); + ConfigParam *arg = node->args; + while(arg) { + if(arg->name.length > 0) { + // arg text is name=value, therefore we add 3 tokens + // name, "=", value + cxListAdd(tokens, &arg->name); + cxmutstr op = (cxmutstr){ "=", 1 }; + cxListAdd(tokens, &op); + } + if(cxListAdd(tokens, &arg->value)) { + cxListDestroy(tokens); + return 1; // OOM + } + arg = arg->next; } - printf("\n"); - fflush(stdout); - return 0; + int ret = 0; + condition->expression = condition_create(pool, tokens); + if(!condition->expression) { + ret = 1; + } + + // don't need the token list anymore + cxListDestroy(tokens); + + return ret; } // convert a condition
--- a/src/server/test/main.c Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/test/main.c Sat Nov 12 11:01:11 2022 +0100 @@ -47,6 +47,7 @@ #include "xml.h" #include "webdav.h" #include "uri.h" +#include "object.h" void register_pg_tests(int argc, char **argv, UcxTestSuite *suite); @@ -77,6 +78,18 @@ ucx_test_register(suite, test_util_uri_escape_latin); ucx_test_register(suite, test_util_uri_escape_kanji); + // object tests + //ucx_test_register(suite, test_expr_parse_expr_value); + //ucx_test_register(suite, test_expr_parse_expr_value_str); + //ucx_test_register(suite, test_expr_parse_expr_value_bool); + //ucx_test_register(suite, test_expr_parse_expr_value_var); + //ucx_test_register(suite, test_expr_parse_expr_not_value); + //ucx_test_register(suite, test_expr_parse_expr_sign_value); + //ucx_test_register(suite, test_expr_parse_expr_compare2values); + //ucx_test_register(suite, test_expr_parse_expr_compare2value_expr); + //ucx_test_register(suite, test_expr_parse_expr_compare2expr_value); + ucx_test_register(suite, test_expr_parse_expr_bracket); + // vfs tests ucx_test_register(suite, test_vfs_open); ucx_test_register(suite, test_vfs_mkdir);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/object.c Sat Nov 12 11:01:11 2022 +0100 @@ -0,0 +1,346 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2022 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 "object.h" + +#include "../util/object.h" + +#include <cx/linked_list.h> +#include <cx/compare.h> + +#include "object.h" + + +UCX_TEST(test_expr_parse_expr_value) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("123"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 1, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_INT, "wrong type"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_value_str) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("\"hello world\""); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 1, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_STRING, "wrong type"); + UCX_TEST_ASSERT(!cx_strcmp(expr->value.str, cx_str("hello world")), "wrong value"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_value_bool) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("true"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 1, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BOOL, "wrong type"); + UCX_TEST_ASSERT(expr->value.b == 1, "wrong value"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_value_var) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("$test"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 1, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_VARIABLE, "wrong type"); + UCX_TEST_ASSERT(!cx_strcmp(expr->value.var, cx_str("test")), "wrong var name"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_not_value) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("not"); + cxListAdd(tokens, &token); + token = cx_str("true"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 2, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_UNARY, "wrong root expression type"); + UCX_TEST_ASSERT(expr->left, "missing left expression"); + UCX_TEST_ASSERT(!expr->right, "right expression should be null"); + UCX_TEST_ASSERT(expr->left->type == NSAPI_EXPRESSION_BOOL, "left expression has wrong type"); + UCX_TEST_ASSERT(expr->left->value.b == 1, "left expression has wrong value"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_sign_value) { + pool_handle_t *pool = pool_create(); + + CxList *tokens1 = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("+"); + cxListAdd(tokens1, &token); + token = cx_str("123"); + cxListAdd(tokens1, &token); + + CxList *tokens2 = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + token = cx_str("-"); + cxListAdd(tokens2, &token); + token = cx_str("123"); + cxListAdd(tokens2, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens1, &pos); + + UCX_TEST_ASSERT(pos == 2, "test1: wrong token pos"); + UCX_TEST_ASSERT(expr, "test1: expression is null"); + + pos = 0; + expr = expr_parse_logical_expr(pool, tokens2, &pos); + + UCX_TEST_ASSERT(pos == 2, "test2: wrong token pos"); + UCX_TEST_ASSERT(expr, "test2: expression is null"); + + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_UNARY, "wrong expression type"); + UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_SUB, "wrong expression operator"); + UCX_TEST_ASSERT(expr->left, "missing left expresion"); + UCX_TEST_ASSERT(expr->left->type == NSAPI_EXPRESSION_INT, "left expression has wrong type"); + UCX_TEST_ASSERT(expr->left->value.i == 123, "left expression has wrong value"); + + UCX_TEST_END; + + pool_destroy(pool); +} + + + +UCX_TEST(test_expr_parse_expr_compare2values) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("2"); + cxListAdd(tokens, &token); + token = cx_str("=="); + cxListAdd(tokens, &token); + token = cx_str("2"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 3, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BINARY, "wrong expression type"); + UCX_TEST_ASSERT(expr->left, "left expression is null"); + UCX_TEST_ASSERT(expr->right, "right expression is null"); + + UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_NOOP, "left should be a literal with no operator"); + UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_NOOP, "right should be a literal with no operator"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_compare2value_expr) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("2"); + cxListAdd(tokens, &token); + token = cx_str("=="); + cxListAdd(tokens, &token); + token = cx_str("1"); + cxListAdd(tokens, &token); + token = cx_str("+"); + cxListAdd(tokens, &token); + token = cx_str("1"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 5, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BINARY, "wrong expression type"); + UCX_TEST_ASSERT(expr->left, "left expression is null"); + UCX_TEST_ASSERT(expr->right, "right expression is null"); + + UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_NOOP, "left should be a literal with no operator"); + UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_ADD, "right should be a binary expression"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_compare2expr_value) { + pool_handle_t *pool = pool_create(); + + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("1"); + cxListAdd(tokens, &token); + token = cx_str("+"); + cxListAdd(tokens, &token); + token = cx_str("1"); + cxListAdd(tokens, &token); + token = cx_str("=="); + cxListAdd(tokens, &token); + token = cx_str("2"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 5, "wrong token pos"); + UCX_TEST_ASSERT(expr, "expression is null"); + + UCX_TEST_ASSERT(expr->type == NSAPI_EXPRESSION_BINARY, "wrong expression type"); + UCX_TEST_ASSERT(expr->left, "left expression is null"); + UCX_TEST_ASSERT(expr->right, "right expression is null"); + UCX_TEST_ASSERT(expr->right->value.i == 2, "right wrong value"); + + UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_ADD, "left should be a binary operation"); + UCX_TEST_ASSERT(expr->right->operator == NSAPI_EXPRESSION_NOOP, "right should be NOOP"); + UCX_TEST_ASSERT(expr->left->left, "ADD-op missing left"); + UCX_TEST_ASSERT(expr->left->right, "ADD-op missing right"); + UCX_TEST_ASSERT(expr->left->left->value.i == 1, "ADD-op: wrong left value"); + UCX_TEST_ASSERT(expr->left->right->value.i == 1, "ADD-op: wrong right value"); + + UCX_TEST_END; + + pool_destroy(pool); +} + +UCX_TEST(test_expr_parse_expr_bracket) { + pool_handle_t *pool = pool_create(); + + // expression: 2 * (1 + 2) == 6 + CxList *tokens = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(cxstring)); + cxstring token = cx_str("2"); + cxListAdd(tokens, &token); + token = cx_str("*"); + cxListAdd(tokens, &token); + token = cx_str("("); + cxListAdd(tokens, &token); + token = cx_str("1"); + cxListAdd(tokens, &token); + token = cx_str("+"); + cxListAdd(tokens, &token); + token = cx_str("2"); + cxListAdd(tokens, &token); + token = cx_str(")"); + cxListAdd(tokens, &token); + token = cx_str("=="); + cxListAdd(tokens, &token); + token = cx_str("6"); + cxListAdd(tokens, &token); + + UCX_TEST_BEGIN; + + size_t pos = 0; + NSAPIExpression *expr = expr_parse_logical_expr(pool, tokens, &pos); + + UCX_TEST_ASSERT(pos == 9, "wrong token pos"); + UCX_TEST_ASSERT(expr->operator == NSAPI_EXPRESSION_EQ, "root: wrong operator"); + UCX_TEST_ASSERT(expr->left, "missing left expression"); + UCX_TEST_ASSERT(expr->right, "missing right expression"); + UCX_TEST_ASSERT(expr->right->type == NSAPI_EXPRESSION_INT, "right expression has wrong type"); + UCX_TEST_ASSERT(expr->left->operator == NSAPI_EXPRESSION_MUL, "left expression has wrong operator"); + UCX_TEST_ASSERT(expr->left->left, "mul: missing left"); + UCX_TEST_ASSERT(expr->left->right, "mul: missing right"); + UCX_TEST_ASSERT(expr->left->right->operator == NSAPI_EXPRESSION_ADD, "missing add operator"); + UCX_TEST_ASSERT(expr->left->right->left, "add: missing left"); + UCX_TEST_ASSERT(expr->left->right->left, "add: missing right"); + + UCX_TEST_END; + + pool_destroy(pool); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/object.h Sat Nov 12 11:01:11 2022 +0100 @@ -0,0 +1,59 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2022 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. + */ + +#ifndef TEST_OBJECT_H +#define TEST_OBJECT_H + +#include "../public/nsapi.h" + +#include "test.h" + +#ifdef __cplusplus +extern "C" { +#endif + +UCX_TEST(test_expr_parse_expr_value); +UCX_TEST(test_expr_parse_expr_value_str); +UCX_TEST(test_expr_parse_expr_value_bool); +UCX_TEST(test_expr_parse_expr_value_var); +UCX_TEST(test_expr_parse_expr_not_value); +UCX_TEST(test_expr_parse_expr_sign_value); + +UCX_TEST(test_expr_parse_expr_compare2values); +UCX_TEST(test_expr_parse_expr_compare2value_expr); +UCX_TEST(test_expr_parse_expr_compare2expr_value); + +UCX_TEST(test_expr_parse_expr_bracket); + + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_OBJECT_H */ +
--- a/src/server/test/objs.mk Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/test/objs.mk Sat Nov 12 11:01:11 2022 +0100 @@ -38,6 +38,7 @@ TESTOBJ += xml.o TESTOBJ += writer.o TESTOBJ += uri.o +TESTOBJ += object.o TESTOBJS = $(TESTOBJ:%=$(TEST_OBJPRE)%) TESTSOURCE = $(TESTOBJ:%.o=test/%.c)
--- a/src/server/util/object.c Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/util/object.c Sat Nov 12 11:01:11 2022 +0100 @@ -27,11 +27,13 @@ */ #include <cx/string.h> +#include <cx/linked_list.h> +#include <cx/compare.h> #include "../public/nsapi.h" #include "object.h" - +#include "util.h" #include "pool.h" #include "../daemon/func.h" @@ -106,6 +108,281 @@ context->last_req_code = REQ_NOACTION; } + +/* ------------------------------ Expression ------------------------------ */ + +Expression* condition_create(pool_handle_t *pool, CxList *tokens) { + + + + return NULL; +} + + +typedef struct { + pool_handle_t *pool; + CxList *op_stack; + CxList *ex_stack; + CxList *tokens; + size_t *pos; + int expect_value; +} ExprParser; + +typedef struct { + NSAPIExpressionOperator operator; + int expect_value; + int open_parenthesis; +} ExprOpStackItem; + +static void expr_free(pool_handle_t *pool, NSAPIExpression *expr) { + if(expr->left) { + expr_free(pool, expr->left); + } + if(expr->right) { + expr_free(pool, expr->right); + } + if(expr->type == NSAPI_EXPRESSION_STRING && expr->value.str.ptr) { + pool_free(pool, (char*)expr->value.str.ptr); + } else if(expr->type == NSAPI_EXPRESSION_VARIABLE && expr->value.var.ptr) { + pool_free(pool, (char*)expr->value.var.ptr); + } + pool_free(pool, expr); +} + +static NSAPIExpressionOperator expr_operator(cxstring token) { + if(!cx_strcmp(token, cx_str("+"))) { + return NSAPI_EXPRESSION_ADD; + } else if(!cx_strcmp(token, cx_str("-"))) { + return NSAPI_EXPRESSION_SUB; + } else if(!cx_strcmp(token, cx_str("*"))) { + return NSAPI_EXPRESSION_MUL; + } else if(!cx_strcmp(token, cx_str("/"))) { + return NSAPI_EXPRESSION_DIV; + } else if(!cx_strcmp(token, cx_str("%"))) { + return NSAPI_EXPRESSION_MOD; + } else if(!cx_strcmp(token, cx_str("not"))) { + return NSAPI_EXPRESSION_NOT; + } else if(!cx_strcmp(token, cx_str("and"))) { + return NSAPI_EXPRESSION_AND; + } else if(!cx_strcmp(token, cx_str("or"))) { + return NSAPI_EXPRESSION_OR; + } else if(!cx_strcmp(token, cx_str("xor"))) { + return NSAPI_EXPRESSION_XOR; + } else if(!cx_strcmp(token, cx_str("=="))) { + return NSAPI_EXPRESSION_EQ; + } else if(!cx_strcmp(token, cx_str("!="))) { + return NSAPI_EXPRESSION_NEQ; + } else if(!cx_strcmp(token, cx_str(">"))) { + return NSAPI_EXPRESSION_GT; + } else if(!cx_strcmp(token, cx_str("<"))) { + return NSAPI_EXPRESSION_LT; + } else if(!cx_strcmp(token, cx_str(">="))) { + return NSAPI_EXPRESSION_GE; + } else if(!cx_strcmp(token, cx_str("<="))) { + return NSAPI_EXPRESSION_LE; + } + return NSAPI_EXPRESSION_NOOP; +} + +static int token_is_int(cxstring token) { + for(size_t i=0;i<token.length;i++) { + if(!isdigit(token.ptr[i])) { + return 0; + } + } + return 1; +} + +static int expr_set_value(pool_handle_t *pool, NSAPIExpression *expr, cxstring token) { + if(token.length >= 2 && token.ptr[0] == '\"' && token.ptr[token.length-1] == '\"') { + expr->value.str = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubsl(token, 1, token.length-2))); + expr->type = NSAPI_EXPRESSION_STRING; + } else if(token.length >= 2 && token.ptr[0] == '$' && isalpha(token.ptr[1])) { + expr->value.var = cx_strcast(cx_strdup_a(pool_allocator(pool), cx_strsubs(token, 1))); + expr->type = NSAPI_EXPRESSION_VARIABLE; + } else if(token_is_int(token)) { + if(!util_strtoint(token.ptr, &expr->value.i)) { + return 1; + } + expr->type = NSAPI_EXPRESSION_INT; + } else if(!strcmp(token.ptr, "true")) { + expr->type = NSAPI_EXPRESSION_BOOL; + expr->value.b = 1; + } else if(!strcmp(token.ptr, "false")) { + expr->type = NSAPI_EXPRESSION_BOOL; + expr->value.b = 0; + } else { + return 1; + } + // TODO: double + return 0; +} + +cxstring expr_next_token(CxList *tokens, size_t *pos) { + cxstring *token = cxListAt(tokens, *pos); + if(token) { + (*pos)++; + return *token; + } + return (cxstring){NULL, 0}; +} + +NSAPIExpression* expr_parser_pop(ExprParser *parser) { + CxList *stack = parser->ex_stack; + if(stack->size == 0) { + return NULL; + } + NSAPIExpression *ret = cxListAt(stack, stack->size-1); + cxListRemove(stack, stack->size-1); + return ret; +} + +// takes items from ex_stack and adds a new operator expression to ex_stack +static int expr_add_operator(ExprParser *parser, ExprOpStackItem *op) { + NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression)); + exp->operator = op->operator; + // op->expect_value == TRUE means, that the operator was found in a case + // a value was expected. + // For example: 1 + - 2 + // After + a value is expected, but there is the - operator + // in that case, the - operator is a unary expression + if(op->expect_value) { + // We expected a value but got an operator? This must be an unary operator + exp->type = NSAPI_EXPRESSION_UNARY; + exp->left = expr_parser_pop(parser); + exp->right = NULL; + } else { + // binary operator + exp->type = NSAPI_EXPRESSION_BINARY; + exp->right = expr_parser_pop(parser); + exp->left = expr_parser_pop(parser); + } + + if(!exp->left && !exp->right) { + return 1; // error + } + + cxListAdd(parser->ex_stack, exp); + + parser->expect_value = TRUE; + return 0; +} + +// converts the token to a value expression (int, bool, str, ...) +// and adds it to parser->ex_stack +// sets parser->expect_value to false +static int expr_add_value(ExprParser *parser, cxstring token) { + NSAPIExpression *exp = pool_malloc(parser->pool, sizeof(NSAPIExpression)); + ZERO(exp, sizeof(NSAPIExpression)); + if(expr_set_value(parser->pool, exp, token)) { + return 1; + } + cxListAdd(parser->ex_stack, exp); + parser->expect_value = FALSE; + return 0; +} + + +static NSAPIExpression* expr_parse_expr(ExprParser *parser) { + CxList *op_stack = parser->op_stack; + CxList *ex_stack = parser->ex_stack; + + // Shunting yard algorithm + cxstring token = expr_next_token(parser->tokens, parser->pos); + for(;token.ptr;token=expr_next_token(parser->tokens, parser->pos)) { + NSAPIExpressionOperator op = expr_operator(token); + if(op != NSAPI_EXPRESSION_NOOP) { + ExprOpStackItem new_op; + new_op.operator = op; + new_op.expect_value = parser->expect_value; + new_op.open_parenthesis = FALSE; + while(op_stack->size > 0) { + ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1); + if(stack_item->operator == NSAPI_EXPRESSION_NOOP) { + break; + } + // check presedence + if(op >= stack_item->operator) { + break; + } + if(expr_add_operator(parser, stack_item)) { + return NULL; + } + cxListRemove(op_stack, op_stack->size-1); + } + cxListAdd(op_stack, &new_op); + parser->expect_value = TRUE; + } else if(token.length == 1 && token.ptr[0] == '(') { + ExprOpStackItem new_op; + new_op.operator = NSAPI_EXPRESSION_NOOP; + new_op.expect_value = 0; + new_op.open_parenthesis = 1; + cxListAdd(op_stack, &new_op); + parser->expect_value = TRUE; + } else if(token.length == 1 && token.ptr[0] == ')') { + int found_open_bracket = FALSE; + while(op_stack->size > 0) { + ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1); + cxListRemove(op_stack, op_stack->size-1); + if(stack_item->open_parenthesis) { + found_open_bracket = TRUE; + break; + } else { + if(expr_add_operator(parser, stack_item)) { + return NULL; + } + } + } + if(!found_open_bracket) { + return NULL; + } + parser->expect_value = FALSE; + } else { + if(expr_add_value(parser, token)) { + return NULL; + } + } + } + + while(op_stack->size > 0) { + ExprOpStackItem *stack_item = cxListAt(op_stack, op_stack->size-1); + if(stack_item->open_parenthesis) { + return NULL; + } + if(expr_add_operator(parser, stack_item)) { + return NULL; + } + cxListRemove(op_stack, op_stack->size-1); + } + + if(ex_stack->size != 1) { + return NULL; + } + + return cxListAt(ex_stack, 0); +} + +NSAPIExpression* expr_parse_logical_expr(pool_handle_t *pool, CxList *tokens, size_t *pos) { + CxList *op_stack = cxLinkedListCreate(pool_allocator(pool), cx_cmp_ptr, sizeof(ExprOpStackItem)); + CxList *ex_stack = cxPointerLinkedListCreate(pool_allocator(pool), cx_cmp_ptr); + + ExprParser parser; + parser.pool = pool; + parser.op_stack = op_stack; + parser.ex_stack = ex_stack; + parser.tokens = tokens; + parser.pos = pos; + parser.expect_value = TRUE; + + NSAPIExpression *ret = expr_parse_expr(&parser); + cxListDestroy(op_stack); + cxListDestroy(ex_stack); + + return ret; +} + + + int condition_evaluate(Condition *condition, Session *sn, Request *rq) { return 1; }
--- a/src/server/util/object.h Wed Nov 09 11:51:19 2022 +0100 +++ b/src/server/util/object.h Sat Nov 12 11:01:11 2022 +0100 @@ -32,6 +32,9 @@ #include "../public/nsapi.h" #include "pool.h" +#include <inttypes.h> +#include <cx/list.h> + #ifdef __cplusplus extern "C" { #endif @@ -120,6 +123,73 @@ uint32_t ref; // reference counter }; + + +typedef struct NSAPIExpression NSAPIExpression; +typedef enum NSAPIExpressionType NSAPIExpressionType; +typedef enum NSAPIExpressionOperator NSAPIExpressionOperator; + +enum NSAPIExpressionType { + NSAPI_EXPRESSION_BOOL = 0, + NSAPI_EXPRESSION_INT, + NSAPI_EXPRESSION_DOUBLE, + NSAPI_EXPRESSION_STRING, + NSAPI_EXPRESSION_VARIABLE, + NSAPI_EXPRESSION_LOGICAL, + NSAPI_EXPRESSION_UNARY, + NSAPI_EXPRESSION_BINARY +}; + +enum NSAPIExpressionOperator { + NSAPI_EXPRESSION_NOOP = 0, + NSAPI_EXPRESSION_NOT, + NSAPI_EXPRESSION_AND, + NSAPI_EXPRESSION_OR, + NSAPI_EXPRESSION_XOR, + NSAPI_EXPRESSION_EQ, + NSAPI_EXPRESSION_NEQ, + NSAPI_EXPRESSION_GT, + NSAPI_EXPRESSION_LT, + NSAPI_EXPRESSION_GE, + NSAPI_EXPRESSION_LE, + NSAPI_EXPRESSION_ADD, + NSAPI_EXPRESSION_SUB, + NSAPI_EXPRESSION_MUL, + NSAPI_EXPRESSION_DIV, + NSAPI_EXPRESSION_MOD +}; + +union NSAPIExpressionValue { + cxstring str; + cxstring var; + int64_t i; + double f; + int b; +}; + +struct NSAPIExpression { + // value.ptr is not null if + // type is one of (bool, int, string): literal text + // type is variable: variable name + union NSAPIExpressionValue value; + + NSAPIExpressionType type; + + NSAPIExpressionOperator operator; + + /* + * left/single operand + */ + NSAPIExpression *left; + + /* + * right operand or NULL + */ + NSAPIExpression *right; +}; + + + /* * creates a new httpd_object */ @@ -171,6 +241,16 @@ void nsapi_context_next_stage(NSAPIContext *context); +/* + * parses an expression from a list of cxstring tokens and compiles the + * expression into an Expression object + * + * tokens: CxList that contains cxstring + */ +Expression* condition_create(pool_handle_t *pool, CxList *tokens); + +NSAPIExpression* expr_parse_logical_expr(pool_handle_t *pool, CxList *tokens, size_t *pos); + int condition_evaluate(Condition *condition, Session *sn, Request *rq);