From b7f58acb515b102547976cc02bc3fcfcef18dd0c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Feb 2008 08:14:12 +0000 Subject: implemented data type conversion --- srUtils.c | 10 ++-------- var.c | 40 ++++++++++++++++++++++++++++++++------- var.h | 3 +++ vm.c | 64 ++++++++++++++++++++++++++++++++++----------------------------- vmstk.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vmstk.h | 3 +++ 6 files changed, 131 insertions(+), 44 deletions(-) diff --git a/srUtils.c b/srUtils.c index 652ae5c8..d20f1174 100755 --- a/srUtils.c +++ b/srUtils.c @@ -28,7 +28,7 @@ */ #include "config.h" -#include "rsyslog.h" /* THIS IS A MODIFICATION FOR RSYSLOG! 2004-11-18 rgerards */ +#include "rsyslog.h" #include #include #include @@ -39,7 +39,7 @@ #include #include #include -#include "liblogging-stub.h" /* THIS IS A MODIFICATION FOR RSYSLOG! 2004-11-18 rgerards */ +#include "liblogging-stub.h" #define TRUE 1 #define FALSE 0 #include "srUtils.h" @@ -392,14 +392,8 @@ timeoutVal(struct timespec *pt) assert(pt != NULL); /* compute timeout */ clock_gettime(CLOCK_REALTIME, &t); -//RUNLOG_VAR("%ld", pt->tv_sec); -//RUNLOG_VAR("%ld", t.tv_sec); -//RUNLOG_VAR("%ld", pt->tv_nsec); -//RUNLOG_VAR("%ld", t.tv_nsec); iTimeout = (pt->tv_nsec - t.tv_nsec) / 1000000; -//RUNLOG_VAR("%ld", iTimeout); iTimeout += (pt->tv_sec - t.tv_sec) * 1000; -//RUNLOG_VAR("%ld", iTimeout); if(iTimeout < 0) iTimeout = 0; diff --git a/var.c b/var.c index 6910986e..8b5a8dd0 100644 --- a/var.c +++ b/var.c @@ -33,6 +33,7 @@ #include "rsyslog.h" #include "obj.h" +#include "srUtils.h" #include "var.h" /* static data */ @@ -176,13 +177,13 @@ rsRetVal ConvToString(var_t *pThis) { DEFiRet; + uchar szNumBuf[64]; if(pThis->varType == VARTYPE_STR) { FINALIZE; } else if(pThis->varType == VARTYPE_NUMBER) { - //CHKiRet(rsCStrConvertToNumber(pThis->val.pStr, &n)); - //pThis->val.num = n; - // TODO: ADD CODE!!!! + CHKiRet(srUtilItoA((char*)szNumBuf, sizeof(szNumBuf)/sizeof(uchar), pThis->val.num)); + CHKiRet(rsCStrConstructFromszStr(&pThis->val.pStr, szNumBuf)); pThis->varType = VARTYPE_STR; } @@ -191,9 +192,32 @@ finalize_it: } +/* convert (if necessary) the value to a boolean. In essence, this means the + * value must be a number, but in case of a string special logic is used as + * some string-values may represent a boolean (e.g. "true"). + * rgerhards, 2008-02-25 + */ +rsRetVal +ConvToBool(var_t *pThis) +{ + DEFiRet; + number_t n; + + if(pThis->varType == VARTYPE_NUMBER) { + FINALIZE; + } else if(pThis->varType == VARTYPE_STR) { + CHKiRet(rsCStrConvertToBool(pThis->val.pStr, &n)); + pThis->val.num = n; + pThis->varType = VARTYPE_NUMBER; + } + +finalize_it: + RETiRet; +} + /* This function is used to prepare two var_t objects for a common operation, - * e.g before they are added, multiplied or compared. The function looks at + * e.g before they are added, compared. The function looks at * the data types of both operands and finds the best data type suitable for * the operation (in respect to current types). Then, it converts those * operands that need conversion. Please note that the passed-in var objects @@ -229,7 +253,6 @@ static rsRetVal ConvForOperation(var_t *pThis, var_t *pOther) { DEFiRet; - varType_t commonType; if(pThis->varType == VARTYPE_NONE || pOther->varType == VARTYPE_NONE) ABORT_FINALIZE(RS_RET_INVALID_VAR); @@ -244,7 +267,7 @@ ConvForOperation(var_t *pThis, var_t *pOther) ABORT_FINALIZE(RS_RET_INVALID_VAR); break; case VARTYPE_STR: - /* two strings, we are all set */ + FINALIZE; /* two strings, we are all set */ break; case VARTYPE_NUMBER: /* check if we can convert pThis to a number, if so use number format. */ @@ -274,7 +297,7 @@ ConvForOperation(var_t *pThis, var_t *pOther) } break; case VARTYPE_NUMBER: - commonType = VARTYPE_NUMBER; + FINALIZE; /* two numbers, so we are all set */ break; case VARTYPE_SYSLOGTIME: ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); @@ -314,6 +337,9 @@ CODESTARTobjQueryInterface(var) pIf->SetNumber = varSetNumber; pIf->SetString = varSetString; pIf->ConvForOperation = ConvForOperation; + pIf->ConvToNumber = ConvToNumber; + pIf->ConvToBool = ConvToBool; + pIf->ConvToString = ConvToString; finalize_it: ENDobjQueryInterface(var) diff --git a/var.h b/var.h index 77ccb8c6..3ebc1021 100644 --- a/var.h +++ b/var.h @@ -55,6 +55,9 @@ BEGINinterface(var) /* name must also be changed in ENDinterface macro! */ rsRetVal (*SetNumber)(var_t *pThis, number_t iVal); rsRetVal (*SetString)(var_t *pThis, cstr_t *pCStr); rsRetVal (*ConvForOperation)(var_t *pThis, var_t *pOther); + rsRetVal (*ConvToNumber)(var_t *pThis); + rsRetVal (*ConvToBool)(var_t *pThis); + rsRetVal (*ConvToString)(var_t *pThis); ENDinterface(var) #define varCURR_IF_VERSION 1 /* increment whenever you change the interface above! */ diff --git a/vm.c b/vm.c index 93c0d5f6..fe6d9b59 100644 --- a/vm.c +++ b/vm.c @@ -33,56 +33,60 @@ /* static data */ DEFobjStaticHelpers DEFobjCurrIf(vmstk) +DEFobjCurrIf(var) /* ------------------------------ instruction set implementation ------------------------------ * * The following functions implement the VM's instruction set. */ #define BEGINop(instruction) \ - static rsRetVal op##instruction(vm_t *pThis, vmop_t *pOp) \ + static rsRetVal op##instruction(vm_t *pThis, __attribute__((unused)) vmop_t *pOp) \ { \ DEFiRet; #define CODESTARTop(instruction) \ - ISOBJ_TYPE_assert(pThis, vm); \ - ISOBJ_TYPE_assert(pOp, vmop); + ISOBJ_TYPE_assert(pThis, vm); #define ENDop(instruction) \ RETiRet; \ } +/* code generator for boolean operations */ +#define BOOLOP(name, OPERATION) \ +BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ + var_t *operand1; \ + var_t *operand2; \ + vmstk.PopBool(pThis->pStk, &operand1); \ + vmstk.PopBool(pThis->pStk, &operand2); \ + if(operand1->val.num OPERATION operand2->val.num) { \ + CHKiRet(var.SetNumber(operand1, 1)); \ + } else { \ + CHKiRet(var.SetNumber(operand1, 0)); \ + } \ + vmstk.Push(pThis->pStk, operand1); /* result */ \ + var.Destruct(&operand2); /* no longer needed */ \ +finalize_it: \ +ENDop(name) + +BOOLOP(OR, ||) +BOOLOP(AND, &&) + +#undef BOOLOP +#if 0 BEGINop(OR) /* remember to set the instruction also in the ENDop macro! */ // var_t *pVar[2]; var_t *operand1; var_t *operand2; CODESTARTop(OR) - // Pop(2, &pVar); --> should also do the conversion outlined below - vmstk.Pop(pThis->pStk, &operand1); - vmstk.Pop(pThis->pStk, &operand2); - // TODO: implement - /* We must check data types and find out on which data type the - * operation needs to be performed. This may result in some data types - * being converted. - * - * Current school of thought: - * op1 op2 operation data type - * string string string - * string number number if op1 can be converted to number, string else - * date string date if op1 can be converted to date, string else - * number number number - * date number string (maybe we can do better?) - * date date date - * - * If a boolean value is required, we need to have a number inside the - * operand. If it is not, conversion rules to number apply. Once we - * have a number, things get easy: 0 is false, anything else is true. - * Please note that due to this conversion rules, "0" becomes false - * while "-4712" becomes true. Using a date as boolen is not a good - * idea. Depending on the ultimate conversion rules, it may always - * become true or false. As such, using dates as booleans is - * prohibited and the result defined to be undefined. - */ + vmstk.PopBool(pThis->pStk, &operand1); + vmstk.PopBool(pThis->pStk, &operand2); + if(operand1->val.num || operand2->val.num) { + CHKiRet(var.SetNumber(operand1, 1)); + } else { + CHKiRet(var.SetNumber(operand1, 0)); + } vmstk.Push(pThis->pStk, operand1); /* result */ + var.Destruct(operand2); /* no longer needed */ ENDop(OR) BEGINop(AND) /* remember to set the instruction also in the ENDop macro! */ @@ -94,6 +98,7 @@ CODESTARTop(AND) // TODO: implement vmstk.Push(pThis->pStk, operand1); /* result */ ENDop(AND) +#endif BEGINop(POP) /* remember to set the instruction also in the ENDop macro! */ CODESTARTop(POP) @@ -211,6 +216,7 @@ ENDobjQueryInterface(vm) BEGINObjClassInit(vm, 1) /* class, version */ /* request objects we use */ CHKiRet(objUse(vmstk)); + CHKiRet(objUse(var)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint); diff --git a/vmstk.c b/vmstk.c index 6944b6f9..0e035543 100644 --- a/vmstk.c +++ b/vmstk.c @@ -109,6 +109,57 @@ finalize_it: } +/* pop a boolean value from the stack + * The user is responsible for destructing the ppVar returned. + */ +static rsRetVal +popBool(vmstk_t *pThis, var_t **ppVar) +{ + DEFiRet; + + /* assertions are done in pop(), we do not duplicate here */ + CHKiRet(pop(pThis, ppVar)); + CHKiRet(var.ConvToBool(*ppVar)); + +finalize_it: + RETiRet; +} + + +/* pop a number value from the stack + * The user is responsible for destructing the ppVar returned. + */ +static rsRetVal +popNumber(vmstk_t *pThis, var_t **ppVar) +{ + DEFiRet; + + /* assertions are done in pop(), we do not duplicate here */ + CHKiRet(pop(pThis, ppVar)); + CHKiRet(var.ConvToNumber(*ppVar)); + +finalize_it: + RETiRet; +} + + +/* pop a number value from the stack + * The user is responsible for destructing the ppVar returned. + */ +static rsRetVal +popString(vmstk_t *pThis, var_t **ppVar) +{ + DEFiRet; + + /* assertions are done in pop(), we do not duplicate here */ + CHKiRet(pop(pThis, ppVar)); + CHKiRet(var.ConvToString(*ppVar)); + +finalize_it: + RETiRet; +} + + /* queryInterface function * rgerhards, 2008-02-21 */ @@ -131,6 +182,10 @@ CODESTARTobjQueryInterface(vmstk) pIf->DebugPrint = vmstkDebugPrint; pIf->Push = push; pIf->Pop = pop; + pIf->PopBool = popBool; + pIf->PopNumber = popNumber; + pIf->PopString = popString; + finalize_it: ENDobjQueryInterface(vmstk) diff --git a/vmstk.h b/vmstk.h index 30bb9009..206c7070 100644 --- a/vmstk.h +++ b/vmstk.h @@ -41,6 +41,9 @@ BEGINinterface(vmstk) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Destruct)(vmstk_t **ppThis); rsRetVal (*Push)(vmstk_t *pThis, var_t *pVar); rsRetVal (*Pop)(vmstk_t *pThis, var_t **ppVar); + rsRetVal (*PopBool)(vmstk_t *pThis, var_t **ppVar); + rsRetVal (*PopNumber)(vmstk_t *pThis, var_t **ppVar); + rsRetVal (*PopString)(vmstk_t *pThis, var_t **ppVar); ENDinterface(vmstk) #define vmstkCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ -- cgit