diff -r 740cfd9dd443 -r 28433f06d5ee src/server/util/object.c --- a/src/server/util/object.c Sun Jun 30 15:11:48 2013 +0200 +++ b/src/server/util/object.c Mon Jul 01 18:05:13 2013 +0200 @@ -32,6 +32,7 @@ #include "pool.h" #include "../daemon/func.h" +#include "../ucx/string.h" @@ -107,3 +108,365 @@ context->objset_index = -1; context->last_req_code = REQ_NOACTION; } + + +Condition* condition_from_str(pool_handle_t *pool, char *expr, size_t len) { + Condition *cond = pool_malloc(pool, sizeof(Condition)); + cond->expression = NULL; + cond->parent = NULL; + cond->index = 0; + + printf("Expression: {"); + fwrite(expr, len, 1, stdout); + printf("}\n"); + + cond->expression = expression_from_str(pool, expr, len); + + return cond; +} + +Expression* expression_from_str(pool_handle_t *pool, char *expr, size_t len) { + char str_qc = 0; // 0 or the quote char + char c_brace = 0; + int brace_count = 0; + + Expression *expression = pool_malloc(pool, sizeof(Expression)); + ZERO(expression, sizeof(Expression)); + + Expression *ex = expression; + /* + * 0: first operand + * 1: second operand + * 2: next expression + */ + int optoken = 0; + int token_start = 0; // index of token begin + int i; + for(i=0;i<=len;i++) { + char c = i == len ? ' ' : expr[i]; + + if(brace_count > 0) { + if(c == c_brace) { + char *token = expr + token_start; + int token_len = i - token_start; + printf("Token {"); + fwrite(token, token_len, 1, stdout); + printf("}\n"); + + + + // reset token_start + token_start = -1; + } + } else { + if((c == '(' || c == '[') && !str_qc) { + brace_count++; + if(brace_count == 1) { + if(c == '(') { + c_brace = ')'; + } else { + c_brace = ']'; + } + token_start = i+1; + } + } else if(c == str_qc) { + str_qc = 0; + } else if(c == '\'' || c == '\"') { + if(token_start != -1) { + // error + printf("error: token_start != -1"); + return NULL; + } + token_start = i; + str_qc = c; + } else if(c < 33 && token_start != -1 && !str_qc) { + char *token = expr + token_start; + int token_len = i - token_start; + //printf("Token {"); + //fwrite(token, token_len, 1, stdout); + //printf("}[%u]\n", token_len); + + int token_type = expr_token_type(token, token_len); + switch(optoken) { + case 0: { + // first operand + if(token_type == 1) { + ex->optype[1] = EXPR_OP_NULL; + ex->opdata[1] = NULL; + ex->expr_operator = expr_operator( + token, + token_len); + break; + } else { + expr_set_op(pool, &ex->optype[0], &ex->opdata[0], token, token_len); + } + optoken++; + break; + } + case 1: { + // second operand + if(token_type == 1) { + Operator op = expr_operator( + token, + token_len); + if(op != OP_AND && op != OP_OR && op != OP_XOR) { + ex->expr_operator = op; + break; + } // else: jump to case 2 + } else if(ex->expr_operator != 0) { + expr_set_op(pool, &ex->optype[1], &ex->opdata[1], token, token_len); + optoken++; + break; + } else { + // syntax error + fprintf(stderr, "expr: missing operator(1)\n"); + return NULL; + } + } + case 2: { + // next + if(token_type == 1) { + ex->next_operator = expr_operator( + token, + token_len); + optoken = 0; + Expression *next_expr = pool_malloc( + pool, + sizeof(Expression)); + ZERO(next_expr, sizeof(Expression)); + ex->next = next_expr; + ex = next_expr; + break; + } else { + // syntax error + fprintf(stderr, "expr: missing operator(2)\n"); + return NULL; + } + } + } + + // reset token_start + token_start = -1; + } else if(c > 32 && token_start == -1) { + token_start = i; + } + } + } + + return expression; +} + +Operator expr_operator(char *token, size_t len) { + if(!strncmp(token, "not", len) || !strncmp(token, "!", len)) { + return OP_NOT; + } else if(!strncmp(token, "and", len) || !strncmp(token, "&&", len)) { + return OP_AND; + } else if(!strncmp(token, "or", len) || !strncmp(token, "||", len)) { + return OP_OR; + } else if(!strncmp(token, "xor", len) || !strncmp(token, "^", len)) { + return OP_XOR; + } else if(!strncmp(token, "=", len)) { + return OP_WILDCARD; + } else if(!strncmp(token, "=~", len)) { + return OP_REGEX; + } else if(!strncmp(token, "!~", len)) { + return OP_NREGEX; + } else if(!strncmp(token, "+", len)) { + return OP_ADD; + } else if(!strncmp(token, "-", len)) { + return OP_SUB; + } else if(!strncmp(token, ".", len)) { + return OP_CAT; + } else if(!strncmp(token, "defined", len)) { + return OP_DEF; + } else if(!strncmp(token, "-d", len)) { + return OP_DEXISTS; + } else if(!strncmp(token, "-e", len)) { + return OP_FDEXISTS; + } else if(!strncmp(token, "-f", len)) { + return OP_FEXISTS; + } else if(!strncmp(token, "-l", len)) { + return OP_LEXISTS; + } else if(!strncmp(token, "-r", len)) { + return OP_READABLE; + } else if(!strncmp(token, "-s", len)) { + return OP_FSIZE; + } else if(!strncmp(token, "-U", len)) { + return OP_UMAP; + } else if(!strncmp(token, "<", len)) { + return OP_LESS; + } else if(!strncmp(token, "<=", len)) { + return OP_LESSEQ; + } else if(!strncmp(token, ">", len)) { + return OP_GREATER; + } else if(!strncmp(token, ">=", len)) { + return OP_GREATEREQ; + } else if(!strncmp(token, "lt", len)) { + return OP_STRLESS; + } else if(!strncmp(token, "le", len)) { + return OP_STRLESSEQ; + } else if(!strncmp(token, "gt", len)) { + return OP_GREATER; + } else if(!strncmp(token, "ge", len)) { + return OP_STRGREATEREQ; + } else if(!strncmp(token, "==", len)) { + return OP_EQUAL; + } else if(!strncmp(token, "!=", len)) { + return OP_NOTEQUAL; + } else if(!strncmp(token, "eq", len)) { + return OP_STREQUAL; + } else if(!strncmp(token, "ne", len)) { + return OP_STRNOTEQUAL; + } + return OP_NOOP; +} + +int expr_token_type(char *token, size_t len) { + char c = token[0]; + if(c == '$' || c == '"' || c == '\'') { + return 0; + } else { + if(expr_operator(token, len) == OP_NOOP) { + return 0; + } else { + return 1; + } + } +} + +void expr_set_op(pool_handle_t *pool, OperandType *type, void **val, char *token, size_t len) { + char c = token[0]; + if(c == '$') { + *type = EXPR_OP_VAR; + sstr_t s = sstrn(token+1, len-1); + s = sstrdup_pool(pool, s); + *val = s.ptr; + } else if(c == '"' || c == '\'') { + *type = EXPR_OP_STRING; + sstr_t s = sstrn(token+1, len-2); + s = sstrdup_pool(pool, s); + *val = s.ptr; + } +} + + +int condition_evaluate(Condition *condition, Session *sn, Request *rq) { + return expression_evaluate(condition->expression, sn, rq); +} + +int expression_evaluate(Expression *ex, Session *sn, Request *rq) { + int ret = 0; + + int last_eval = 0; + Operator expr_lconn = OP_NOOP; // logical connective between 2 expressions + while(ex) { + int eval = 0; + + if(!ex->opdata[1]) { + /* + * Only one operand. Can be: + * boolean with or without not operator + * defined operator + * file/directory/link exists operator + */ + int not_op = 0; + switch(ex->expr_operator) { + case OP_NOT: { + not_op = 1; + } + case OP_NOOP: { + // must be boolean + // TODO + } + } + + } else { + void *ops[2]; + VarType types[2]; + for(int i=0;i<2;i++) { + switch(ex->optype[i]) { + case EXPR_OP_STRING: { + ops[i] = ex->opdata[i]; + types[i] = VAR_STRING; + break; + } + case EXPR_OP_VAR: { + if(!expr_get_var(ex->opdata[i], sn, rq, &ops[i], &types[i])); + break; + } + } + } + + if(types[0] != types[1]) { + fprintf(stderr, "Condition: incompatible types\n"); + return 0; + } + + if(types[0] == VAR_STRING) { + switch(ex->expr_operator) { + case OP_WILDCARD: { + eval = !shexp_match(ops[0], ops[1]); + break; + } + case OP_STREQUAL: { + eval = !strcmp(ops[0], ops[1]); + break; + } + } + } + } + + + // evaluate logical connective between last 2 expressions + switch(expr_lconn) { + case OP_AND: { + if(!last_eval || !eval) { + return 0; + } + break; + } + case OP_OR: { + if(!last_eval && !eval) { + return 0; + } + } + case OP_XOR: { + if(last_eval == eval) { + return 0; + } + } + } + + last_eval = eval; + // switch to next expression + if(ex->next) { + expr_lconn = ex->next_operator; + } + ex = ex->next; + } + + return last_eval; +} + +int expr_get_var(char *var, Session *sn, Request *rq, void **val, VarType *t) { + if(!strcmp(var, "path")) { + char *ppath = pblock_findval("ppath", rq->vars); + if(ppath) { + *t = VAR_STRING; + *val = ppath; + return 1; + } + } else if(!strcmp(var, "uri")) { + char *uri = pblock_findval("uri", rq->reqpb); + if(uri) { + *t = VAR_STRING; + *val = uri; + return 1; + } + } + + *val = NULL; + *t = 0; + return 0; +} +