diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2011-07-07 08:22:40 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2011-07-07 08:22:40 +0200 |
commit | 5710b413963d2fde9d062127ed72672b8a58a07e (patch) | |
tree | 35cd364e62273da3a239f1c72f1d50d4e69ce21b /grammar/rainerscript.c | |
parent | 30f2b5b094d282af6f601aa4e8fa88c1baf187f4 (diff) | |
download | rsyslog-5710b413963d2fde9d062127ed72672b8a58a07e.tar.gz rsyslog-5710b413963d2fde9d062127ed72672b8a58a07e.tar.xz rsyslog-5710b413963d2fde9d062127ed72672b8a58a07e.zip |
milestone/[PARTWORK]: integrted script filter, but var access is missing
Diffstat (limited to 'grammar/rainerscript.c')
-rw-r--r-- | grammar/rainerscript.c | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c new file mode 100644 index 00000000..801a52b2 --- /dev/null +++ b/grammar/rainerscript.c @@ -0,0 +1,658 @@ +/* rainerscript.c - routines to support RainerScript config language + * + * Module begun 2011-07-01 by Rainer Gerhards + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <libestr.h> +#include "rainerscript.h" +#include "parserif.h" +#include "grammar.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; + int len, i; + int start; /* start index of to be submitted text */ + int bContLine = 0; + int lineno = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + } + if(!bContLine) + es_addChar(str, '\n'); + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + dbgprintf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + dbgprintf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} + + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + if(lst == NULL) + return NULL; + prev = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = NULL; + while(actlst != NULL) { + //dbgprintf("reversing: %s\n", actlst->data.legActLine); + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + dbgprintf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + dbgprintf("action:cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } +} + +struct cnfexpr* +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } +done: + return expr; +} + +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + dbgprintf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&r); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + dbgprintf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +/* Evaluate an expression as a bool. This is added because expressions are + * mostly used inside filters, and so this function is quite common and + * important. + */ +int +cnfexprEvalBool(struct cnfexpr *expr) +{ + struct exprret ret; + cnfexprEval(expr, &ret); + return exprret2Number(&ret); +} + +inline static void +doIndent(int indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + dbgprintf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + struct cnffparamlst *param; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + dbgprintf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + dbgprintf("'\n"); + break; + case 'N': + doIndent(indent); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case 'V': + doIndent(indent); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'F': + doIndent(indent); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); + dbgprintf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + dbgprintf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + dbgprintf("------ end rule %p\n", rule); +} + +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} |