src/server/util/object.c

Sat, 12 Nov 2022 11:01:11 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 12 Nov 2022 11:01:11 +0100
changeset 423
bb7cff720dd0
parent 421
437562f5681d
child 424
3df9258cd3cc
permissions
-rw-r--r--

add obj.conf expression parser

/*
 * 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 <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"



httpd_object* object_new(pool_handle_t *pool, char *name) {
    httpd_object *obj = pool_malloc(pool, sizeof(httpd_object));
    obj->pool = pool;
    obj->name = name;
    obj->path = NULL;

    // create directive table
    obj->dt = pool_calloc(pool, NUM_NSAPI_TYPES - 1, sizeof(struct dtable));
    obj->nd = NUM_NSAPI_TYPES - 1;

    return obj;
}

void object_free(httpd_object *obj) {
    //free(obj->name);
    //free(obj->dt);
}


int object_add_directive(httpd_object *obj, directive *dir, int dt) {
    dtable *l = object_get_dtable(obj, dt);
    // allocate space for the new directive
    if(l->ndir >= l->alloc) {
        l->alloc += 8;
        directive **drs = pool_realloc(obj->pool, l->dirs, (l->alloc)*sizeof(void*));
        if(!drs) {
            l->alloc -= 8;
            return -1;
        }
        l->dirs = drs;
    }
    
    // add directive
    l->dirs[l->ndir++] = dir;
    return 0;
}


/* objset functions */
httpd_objset* objset_create(pool_handle_t *pool) {
    httpd_objset *os = pool_malloc(pool, sizeof(httpd_objset));

    os->obj = pool_calloc(pool, 2, sizeof(void*));
    os->pos = 0;

    return os;
}

void objset_add_object(pool_handle_t *p, httpd_objset *os, httpd_object *obj) {
    if(os->pos != 0 && os->pos % 2 == 0) {
        os->obj = pool_realloc(p, os->obj, (os->pos + 2) * sizeof(void*));
    }
    os->obj[os->pos] = obj;
    os->pos++;
}

void httpobjconf_add_object(HTTPObjectConfig *conf, httpd_object *obj) {
    conf->nobj++;
    conf->objects = realloc(conf->objects, conf->nobj * sizeof(void*));
    conf->objects[conf->nobj - 1] = obj;
}


void nsapi_context_next_stage(NSAPIContext *context) {
    context->dtable_index  = 0;
    context->objset_index  = -1;
    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;
}

mercurial