libidav/davql.c

changeset 135
664aeaec8d25
parent 134
4bccc18820e8
child 136
59058927b885
--- a/libidav/davql.c	Tue Jul 07 20:47:02 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,770 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2015 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "davql.h"
-#include "methods.h"
-#include "utils.h"
-
-DavQuery dav_ql_parse(char *query, va_list ap) {
-    DavQuery davquery;
-    davquery.command = DAV_QUERY_ERROR;
-    davquery.command_data = NULL;
-    sstr_t q = sstr(query);
-    q = sstrtrim(q);
-    
-    // get query command
-    sstr_t cmd;
-    cmd.ptr = NULL;
-    int i;
-    for(i=0;i<q.length;i++) {
-        if(q.ptr[i] == ' ') {
-            cmd = sstrsubsl(q, 0, i);
-            break;
-        }
-    }
-    if(!cmd.ptr) {
-        fprintf(stderr, "DQL syntax error\n");
-        return davquery;
-    }
-    
-    cmd = sstrtrim(cmd);
-    q = sstrtrim(sstrsubs(q, i));
-    if(!sstrcmp(cmd, S("get"))) {
-        davquery.command = DAV_QUERY_GET;
-        davquery.command_data = dav_ql_parse_get(q, ap);
-    }
-    
-    return davquery;
-}
-
-DavGetQuery* dav_ql_parse_get(sstr_t q, va_list ap) {  
-    sstr_t property_query = q;
-    q = util_getsubstr_until_token(q, S("from"), &property_query);
-    
-    sstr_t from_query = q;
-    sstr_t cond = util_getsubstr_until_token(q, S("where"), &from_query);
-    sstr_t with = util_getsubstr_until_token(cond, S("with"), &cond);
-    int depth = 1;
-       
-    // insert variable values
-    UcxBuffer *fbuf = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
-    int var = 0;
-    for(int i=0;i<from_query.length;i++) {
-        char c = from_query.ptr[i];
-        if(c == '%') {
-            if(var) {
-                ucx_buffer_putc(fbuf, '%'); // previous '%'
-            } else {
-                var = 1;
-            }
-        } else if(var) {
-            switch(c) {
-                case 's': {
-                    char *arg = va_arg(ap, char*);
-                    ucx_buffer_puts(fbuf, arg);
-                    break;
-                }
-                default: {
-                    ucx_buffer_putc(fbuf, '%');
-                    ucx_buffer_putc(fbuf, c);
-                }
-            }
-            var = 0;
-        } else {
-            ucx_buffer_putc(fbuf, c);
-        }
-    }
-    
-    // condition
-    DavQOp *condition = NULL;
-    size_t oplen = 0;
-    if(cond.ptr) {
-        //printf("cond: {%.*s}\n", cond.length, cond.ptr);
-        UcxList *ops = NULL;
-        if(dav_parse_condition(&ops, cond, ap)) {
-            // TODO: error
-            printf("parse error\n");
-            return NULL;
-        }
-        oplen = ucx_list_size(ops);
-        condition = calloc(sizeof(DavQOp), oplen);
-        int l = 0;
-        UCX_FOREACH(elm, ops) {
-            condition[l] = *(DavQOp*)elm->data;
-            free(elm->data);
-            l++;
-        }
-        ucx_list_free(ops);
-    }
-    
-    // with
-    if(with.ptr) {
-        if(dav_parse_with(with, &depth, ap)) {
-            // TODO: error
-            printf("parse error\n");
-            return NULL;
-        }
-    }
-    
-    DavGetQuery *getquery = malloc(sizeof(DavGetQuery));
-    getquery->properties = sstrdup(property_query);
-    getquery->from = sstrdup(sstrn(fbuf->space, fbuf->pos));
-    getquery->depth = depth;
-    if(condition) {
-        getquery->condition = condition;
-        getquery->condlen = oplen;
-    } else {
-        getquery->condition = NULL;
-        getquery->condlen = 0;
-    }
-    
-    ucx_buffer_free(fbuf);
-    return getquery;
-}
-
-void free_get_query(DavGetQuery *q) {
-    free(q->from.ptr);
-    free(q->properties.ptr);
-    if(q->condition) {
-        free(q->condition);
-    }
-    free(q);
-}
-
-int parse_path_query(sstr_t query, char **path, int *depth) {
-    if(query.length == 1) {
-        if(query.ptr[0] == '/') {
-            *path = sstrdup(query).ptr;
-            *depth = 1;
-            return 0;
-        } else {
-            *path = NULL;
-            return 1;
-        }
-    }
-    
-    if(query.ptr[query.length-1] == '*') {
-        *depth = -1;
-        *path = sstrdup(sstrsubsl(query, 0, query.length-1)).ptr;
-    } else {
-        *path = sstrdup(query).ptr;
-        *depth = 1;
-    }
-    
-    return 0;
-}
-
-static int dav_str2depth(sstr_t str, int *depth) {
-    if(!sstrcmp(str, S("infinity"))) {
-        *depth = -1;
-    } else {
-        sstr_t cp = sstrdup(str); // terminate
-        *depth = atoi(cp.ptr);
-        free(cp.ptr);
-    }
-    return 0;
-}
-
-int dav_parse_with(sstr_t with, int *depth, va_list ap) {
-    int i;
-    for(i=0;i<with.length;i++) {
-        if(with.ptr[i] == ' ') {
-            break;
-        }
-    }
-    
-    sstr_t name = sstrsubsl(with, 0, i);
-    sstr_t value = sstrtrim(sstrsubs(with, i));
-    //printf("with {%.*s} {%.*s}\n", name.length, name.ptr, value.length, value.ptr);
-    
-    if(!sstrcmp(name, S("depth"))) {
-        if(value.length == 0) {
-            return 1;
-        } else if(value.ptr[0] == '%') {
-            switch(value.ptr[1]) {
-                default: return 1;
-                case 's': {
-                    sstr_t v = sstr(va_arg(ap, char*));
-                    if(dav_str2depth(value, depth)) {
-                        return 1;
-                    }
-                    break;
-                }
-                case 'd': {
-                    *depth = va_arg(ap, int);
-                    break;
-                }
-            }
-        } else {
-            if(dav_str2depth(value, depth)) {
-                return 1;
-            }
-        }
-    }
-    
-    return 0;
-}
-
-int dav_parse_condition(UcxList **ops, sstr_t cond, va_list ap) {
-    sstr_t token;
-    DavQOp *op1 = NULL; // level 1 operator
-    DavQOp *op2 = NULL; // level 2 operator
-    DavQOp *op3 = NULL; // level 3 operator
-    while((token = condition_parser_next_token(&cond)).length > 0) {
-        //printf("token: {%.*s}[%d]\n", token.length, token.ptr, token.length);
-        int64_t type = 0;
-        int tkop = condition_operator_type(token, &type);
-        DavQOp *operation = malloc(sizeof(DavQOp));
-        if(tkop > 0) {
-            // operator token
-            operation->type = DAVQOP_OPERATOR;
-            operation->val = NULL;
-            operation->intval = type;
-            switch(tkop) {
-                case 1: {
-                    // operators: + - / * not
-                    // add operation after next non operator token
-                    op1 = operation;
-                    break;
-                }
-                case 2: {
-                    // operators: < > == != <= >=
-                    if(op2) {
-                        *ops = ucx_list_append(*ops, op2);
-                    }
-                    op2 = operation;
-                    break;
-                }
-                case 3: {
-                    // operators: and or xor
-                    if(op2) {
-                        *ops = ucx_list_append(*ops, op2);
-                        op2 = NULL;
-                    }
-                    if(op3) {
-                        *ops = ucx_list_append(*ops, op3);
-                    }
-                    op3 = operation;
-                    break;
-                }
-            }
-        } else {
-            if(token.ptr[0] == '"' || token.ptr[0] == '\'') {
-                operation->type = DAVQOP_STRING;
-                operation->val = token.ptr+1;
-                operation->intval = token.length-2;
-            } else if(!sstrcmp(token, S("true")) ||
-                    !sstrcmp(token, S("false")))
-            {
-                operation->type = DAVQOP_INTEGER;
-                operation->val = NULL;
-                operation->intval = util_getboolean(token.ptr);
-            } else if(token.length == 2 && token.ptr[0] == '%') {
-                switch(token.ptr[1]) {
-                    case 's': {
-                        char *arg = va_arg(ap, char*);
-                        operation->type = DAVQOP_STRING;
-                        operation->val = arg;
-                        operation->intval = strlen(arg);
-                        break;
-                    }
-                    case 'd': {
-                        operation->type = DAVQOP_INTEGER;
-                        operation->val = NULL;
-                        operation->intval = va_arg(ap, int);
-                        break;
-                    }
-                    case 't': {
-                        operation->type = DAVQOP_INTEGER;
-                        operation->val = NULL;
-                        operation->intval = va_arg(ap, time_t);
-                        break;
-                    }
-                    default: {
-                        operation->type = DAVQOP_STRING;
-                        operation->val = token.ptr;
-                        operation->intval = token.length;
-                    }
-                }
-            } else {
-                sstr_t d = sstrdup(token);
-                int64_t val = 0;
-                int intval = util_strtoint(d.ptr, &val);
-                free(d.ptr);
-                if(intval) {
-                    operation->type = DAVQOP_INTEGER;
-                    operation->val = NULL;
-                    operation->intval = val;
-                } else {
-                    if(!sstrcmp(token, S("contentlength"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else if(!sstrcmp(token, S("lastmodified"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else if(!sstrcmp(token, S("creationdate"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else if(!sstrcmp(token, S("name"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else if(!sstrcmp(token, S("path"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else if(!sstrcmp(token, S("iscollection"))) {
-                        operation->type = DAVQOP_RESPROP;
-                    } else {
-                        operation->type = DAVQOP_PROPERTY;
-                    }
-                    operation->val = token.ptr;
-                    operation->intval = token.length;
-                }
-            }
-            
-            // add operation
-            *ops = ucx_list_append(*ops, operation);
-            if(op1) {
-                // add level 1 operator
-                *ops = ucx_list_append(*ops, op1);
-                op1 = NULL;
-            }
-        }
-    }
-    if(op1) {
-        *ops = ucx_list_append(*ops, op1);
-    }
-    if(op2) {
-        *ops = ucx_list_append(*ops, op2);
-    }
-    if(op3) {
-        *ops = ucx_list_append(*ops, op3);
-    }
-    return 0;
-}
-
-sstr_t condition_parser_next_token(sstr_t *str) {
-    sstr_t s = *str;
-    sstr_t t;
-    t.ptr = NULL;
-    t.length = 0;
-    // remove leading space
-    int i;
-    for(i=0;i<s.length;i++) {
-        if(s.ptr[i] > 32) {
-            break;
-        }
-    }
-    s.length -= i;
-    s.ptr += i;
-    
-    if(s.length == 0) {
-        *str = s;
-        return t;
-    }
-    
-    // check for single char operators
-    switch(s.ptr[0]) {
-        case '<':
-        case '>':
-        case '+':
-        case '-':
-        case '*':
-        case '/': {
-            t.ptr = s.ptr;
-            t.length = 1;
-            str->ptr = s.ptr + 1;
-            str->length = s.length - 1;
-            return t;
-        }
-    }
-    
-    if(s.length > 1) {
-        // check for double char operators
-        int16_t op = *(int16_t*)s.ptr;
-        if(op == '==' || op == '!=' || op == '>=' || op == '=<') {
-            t.ptr = s.ptr;
-            t.length = 2;
-            str->ptr = s.ptr + 2;
-            str->length = s.length - 2;
-            return t;
-        }
-    } else {
-        t.ptr = s.ptr;
-        t.length = 1;
-        str->ptr = s.ptr + 1;
-        str->length = s.length - 1;
-        return t;
-    }
-    
-    // TODO: brackets
-    
-    // check for string literal
-    if(s.ptr[0] == '\'' || s.ptr[0] == '"') {
-        for(i=1;i<s.length;i++) {
-            if(s.ptr[0] == s.ptr[i]) {
-                i++;
-                break;
-            }
-        }
-        t.ptr = s.ptr;
-        t.length = i;
-        str->ptr = s.ptr + i;
-        str->length = s.length - i;
-        return t;
-    }
-    
-    for(i=0;i<s.length;i++) {
-        char c = s.ptr[i];
-        if((c < 33) || (c > 41 && c < 48) || (c > 59 && c < 63)) {
-            break;
-        }
-    }
-    t.ptr = s.ptr;
-    t.length = i;
-    str->ptr = s.ptr + i;
-    str->length = s.length - i;
-    return t;
-}
-
-int condition_operator_type(sstr_t token, int64_t *type) {
-    // returns the operator level and sets the type
-    
-    if(token.ptr[0] == '"' || token.ptr[0] == '\'' || token.ptr[0] == '(') {
-        return 0;
-    }
-    
-    if(token.length == 1) {
-        switch(token.ptr[0]) {
-            case '+': *type = 1; return 1;
-            case '-': *type = 2; return 1;
-            case '*': *type = 3; return 1;
-            case '/': *type = 4; return 1;
-            case '<': *type = 5; return 2;
-            case '>': *type = 6; return 2;
-        }
-    }
-    if(!sstrcmp(token, S("not"))) {
-        *type = 0;
-        return 1;
-    }
-    
-    if(!sstrcmp(token, S("=="))) {
-        *type = 7;
-        return 2;
-    }
-    if(!sstrcmp(token, S("!="))) {
-        *type = 8;
-        return 2;
-    }
-    if(!sstrcmp(token, S("<="))) {
-        *type = 9;
-        return 2;
-    }
-    if(!sstrcmp(token, S(">="))) {
-        *type = 10;
-        return 2;
-    }
-    
-    if(!sstrcmp(token, S("and"))) {
-        *type = 11;
-        return 3;
-    }
-    if(!sstrcmp(token, S("or"))) {
-        *type = 12;
-        return 3;
-    }
-    if(!sstrcmp(token, S("xor"))) {
-        *type = 13;
-        return 3;
-    }
-    
-    return 0;
-}
-
-int condition_eval(DavResource *res, DavQOp *cond, size_t len) {
-    DavQOp stack[128];
-    int stackpos = 0;
-    for(int i=0;i<len;i++) {
-        DavQOp op = cond[i];
-        switch(op.type) {
-            case DAVQOP_OPERATOR: {
-                if(op.intval == 0) {
-                    // not operator
-                    if(stackpos < 1) {
-                        // error
-                        printf("no data on stack\n");
-                        return 0;
-                    }
-                    int pos = stackpos-1;
-                    if(stack[pos].type == DAVQOP_INTEGER) {
-                        //printf("not %" PRId64 "\n", stack[pos].intval);
-                        stack[pos].intval = !stack[pos].intval;
-                    } else {
-                        // error
-                        printf("wrong value for 'not' operator\n");
-                        return 0;
-                    }
-                } else {
-                    DavQOp val1 = stack[stackpos-2];
-                    DavQOp val2 = stack[stackpos-1];
-                    DavQOp result;
-                    if(val1.type == DAVQOP_INTEGER) {
-                        if(val2.type == DAVQOP_INTEGER) {
-                            result = compare_intint(
-                                    op.intval,
-                                    val1.intval,
-                                    val2.intval);
-                        } else {
-                            result = compare_intstr(op.intval, val1, val2);
-                        }
-                    } else {
-                        if(val2.type == DAVQOP_INTEGER) {
-                            result = compare_strint(op.intval, val1, val2);
-                        } else {
-                            result = compare_strstr(op.intval, val1, val2);
-                        }
-                    } 
-                    stack[stackpos-2] = result;
-                    stackpos--;
-                }
-                break;
-            }
-            case DAVQOP_STRING:
-            case DAVQOP_INTEGER:
-            case DAVQOP_TIME: {
-                if(op.type == DAVQOP_STRING) {
-                    //printf("put on stack: '%s'\n", op.val);
-                } else {
-                    //printf("put on stack[%d]: %" PRId64 "\n", stackpos, op.intval);
-                }
-                stack[stackpos++] = op;
-                break;
-            }
-            case DAVQOP_PROPERTY: {
-                sstr_t pname = sstrn(op.val, op.intval);
-                pname = sstrdup(pname);
-                char *property_value = dav_get_property(res, pname.ptr);
-                free(pname.ptr);
-                DavQOp value;
-                value.type = DAVQOP_STRING;
-                if(property_value) {
-                    //printf("put on stack: \"%s\"\n", property_value);
-                    value.val = property_value;
-                    value.intval = strlen(property_value);
-                } else {
-                    //printf("put on stack: null string\n");
-                    value.val = NULL;
-                    value.intval = 0;
-                }
-                stack[stackpos++] = value;
-                break;
-            }
-            case DAVQOP_RESPROP: {
-                sstr_t name = sstrn(op.val, op.intval);
-                DavQOp value;
-                value.type = DAVQOP_INTEGER;
-                value.val = NULL;
-                if(!sstrcmp(name, S("contentlength"))) {
-                    //printf("put contentlength\n");
-                    value.intval = res->contentlength;
-                } else if(!sstrcmp(name, S("lastmodified"))) {
-                    //printf("put getlastmodified\n");
-                    value.intval = res->lastmodified;
-                } else if(!sstrcmp(name, S("creationdate"))) {
-                    value.intval = res->creationdate;
-                } else if(!sstrcmp(name, S("name"))) {
-                    value.type = DAVQOP_STRING;
-                    value.val = res->name;
-                    value.intval = strlen(res->name);
-                } else if(!sstrcmp(name, S("path"))) {
-                    value.type = DAVQOP_STRING;
-                    value.val = res->path;
-                    value.intval = strlen(res->path);
-                } else if(!sstrcmp(name, S("iscollection"))) {
-                    value.type = DAVQOP_INTEGER;
-                    value.val = NULL;
-                    value.intval = res->iscollection;
-                }
-                stack[stackpos++] = value;
-                break;
-            }
-        }
-    }
-    if(stackpos != 1) {
-        return 0;
-    }
-    DavQOp result = stack[0];
-    //printf("result: %" PRId64 "\n", result.intval);
-    return (int)result.intval;
-}
-
-DavQOp compare_intint(int op, int64_t v1, int64_t v2) {
-    DavQOp res;
-    res.type = DAVQOP_INTEGER;
-    res.val = NULL;
-    res.intval = 0;
-    switch(op) {
-        case 5: {
-            // <
-            //printf("compare: %" PRId64 " < %" PRId64 "\n", v1, v2);
-            res.intval = v1 < v2;
-            break;
-        }
-        case 6: {
-            // >
-            //printf("compare: %" PRId64 " > %" PRId64 "\n", v1, v2);
-            res.intval = v1 > v2;
-            break;
-        }
-        case 7: {
-            // ==
-            //printf("compare: %" PRId64 " == %" PRId64 "\n", v1, v2);
-            res.intval = v1 == v2;
-            break;
-        }
-        case 8: {
-            // !=
-            //printf("compare: %" PRId64 " != %" PRId64 "\n", v1, v2);
-            res.intval = v1 != v2;
-            break;
-        }
-        case 9: {
-            // <=
-            //printf("compare: %" PRId64 " <= %" PRId64 "\n", v1, v2);
-            res.intval = v1 <= v2;
-            break;
-        }
-        case 10: {
-            // >=
-            //printf("compare: %" PRId64 " >= %" PRId64 "\n", v1, v2);
-            res.intval = v1 >= v2;
-            break;
-        }
-        case 11: {
-            // and
-            //printf("compare: %" PRId64 " and %" PRId64 "\n", v1, v2);
-            res.intval = v1 && v2;
-            break;
-        }
-        case 12: {
-            // or
-            //printf("compare: %" PRId64 " or %" PRId64 "\n", v1, v2);
-            res.intval = v1 || v2;
-            break;
-        }
-        case 13: {
-            // xor
-            //printf("compare: %" PRId64 " xor %" PRId64 "\n", v1, v2);
-            res.intval = v1 ^ v2;
-            break;
-        }
-    }
-    return res;
-}
-
-DavQOp compare_strint(int op, DavQOp v1, DavQOp v2) {
-    int64_t v1int;
-    sstr_t s1 = sstrn(v1.val, v1.intval);
-    s1 = sstrdup(s1);
-    if(util_strtoint(s1.ptr, &v1int)) {
-        free(s1.ptr);
-        return compare_intint(op, v1int, v2.intval);
-    } else {
-        free(s1.ptr);
-        // TODO
-    }
-}
-
-DavQOp compare_intstr(int op, DavQOp v1, DavQOp v2) {
-    // TODO
-}
-
-DavQOp compare_strstr(int op, DavQOp v1, DavQOp v2) {
-    DavQOp res;
-    res.type = DAVQOP_INTEGER;
-    res.val = NULL;
-    res.intval = 0;
-    sstr_t s1 = sstrn(v1.val, v1.intval);
-    sstr_t s2 = sstrn(v2.val, v2.intval);
-    switch(op) {
-        case 5: {
-            // <
-            //printf("str compare: %.*s < %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.length < s2.length;
-            break;
-        }
-        case 6: {
-            // >
-            //printf("str compare: %.*s > %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.length > s2.length;
-            break;
-        }
-        case 7: {
-            // ==
-            //printf("str compare: %.*s == %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = sstrcmp(s1, s2) == 0;
-            break;
-        }
-        case 8: {
-            // !=
-            //printf("str compare: %.*s != %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = sstrcmp(s1, s2) != 0;
-            break;
-        }
-        case 9: {
-            // <=
-            //printf("str compare: %.*s <= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.length <= s2.length;
-            break;
-        }
-        case 10: {
-            // >=
-            //printf("str compare: %.*s >= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.length >= s2.length;
-            break;
-        }
-        case 11: {
-            // and
-            //printf("str compare: %.*s and %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.ptr && s2.ptr;
-            break;
-        }
-        case 12: {
-            // or
-            //printf("str compare: %.*s or %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = s1.ptr || s2.ptr;
-            break;
-        }
-        case 13: {
-            // xor
-            //printf("str compare: %.*s xor %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
-            res.intval = (intptr_t)s1.ptr ^ (intptr_t)s2.ptr;
-            break;
-        }
-    }
-    return res;
-}

mercurial