Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF library
0003  *   UBF expression functions
0004  *
0005  * @file expr_funcs.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 /* needed for asprintf */
0038 #ifndef _GNU_SOURCE
0039 #define _GNU_SOURCE
0040 #endif
0041 
0042 #include <stdio.h>
0043 #include <stdlib.h>
0044 #include <stdarg.h>
0045 #include <string.h>
0046 #include <math.h>
0047 #include "expr.h"
0048 #include "ndebug.h"
0049 #include "ferror.h"
0050 #include <ubf.h>
0051 #include <ubf_int.h>
0052 #include <errno.h>
0053 #include <sys/types.h>
0054 #include <regex.h>
0055 #include <expr.tab.h>
0056 #include <exhash.h>
0057 /*---------------------------Externs------------------------------------*/
0058 /* make llvm silent.. */
0059 extern void yy_scan_string (char *yy_str  );
0060 extern void _free_parser(void);
0061 extern int yyparse (void);
0062 /*---------------------------Macros-------------------------------------*/
0063 #define FREE_UP_UB_BUF(v) \
0064 if (v->dyn_alloc && NULL!=v->strval)\
0065 {\
0066 free(v->strval);\
0067 v->strval=NULL;\
0068 v->dyn_alloc=0;\
0069 }
0070 
0071 #ifdef UBF_DEBUG
0072 #define DUMP_VALUE_BLOCK(TEXT, V) if (EXSUCCEED==ret) dump_val(TEXT, V)
0073 #else
0074 #define DUMP_VALUE_BLOCK(TEXT, V) {}
0075 #endif
0076 
0077 /** Compare the the float to test against is it 0 or not */
0078 #define IS_FLOAT_0(X) (X < 0.000000001 && X > -0.000000001)
0079 
0080 /*---------------------------Enums--------------------------------------*/
0081 /*---------------------------Typedefs-----------------------------------*/
0082 /*---------------------------Globals------------------------------------*/
0083 
0084 /* Compile time stuff only: */
0085 __thread struct ast *G_p_root_node=NULL;
0086 __thread int G_node_count=0;
0087 __thread int G_error;
0088 static __thread struct list_node *M_cur_mem;
0089 static __thread struct list_node *M_first_mem;
0090 /* Compile time stuff only, end */
0091 
0092 func_hash_t *M_func_hash = NULL;    /* Hash of customer functions regi */
0093 /*---------------------------Statics------------------------------------*/
0094 
0095 /*
0096  * Listing of types
0097  */
0098 char *M_nodetypes[] =
0099 {
0100     "[OR    (0) ]",
0101     "[AND   (1) ]",
0102     "[XOR   (2) ]",
0103     "[EQOP  (3) ]",
0104     "[RELOP (4) ]",
0105     "[ADDOP (5) ]",
0106     "[MULTOP(6) ]",
0107     "[UNARY (7) ]",
0108     "[FLD   (8) ]",
0109     "[STR   (9) ]",
0110     "[FLOAT (10)]",
0111     "[LONG  (11)]",
0112     "[FUNC  (12)]"
0113 };
0114 
0115 /*
0116  * Listing of sub-types
0117  */
0118 char *M_subtypes[] =
0119 {
0120     "[DF(0) ]",
0121     "[==(1) ]",
0122     "[!=(2) ]",
0123     "[%%(3) ]",
0124     "[!%(4) ]",
0125     "[< (5) ]",
0126     "[<=(6) ]",
0127     "[> (7) ]",
0128     "[>=(8) ]",
0129     "[+ (9) ]",
0130     "[- (10)]",
0131     "[~ (11)]",
0132     "[! (12)]",
0133     "[* (13)]",
0134     "[/ (14)]",
0135     "[% (15)]",
0136     "[||(16)]",
0137     "[&&(17)]",
0138     "[^ (18)]"
0139 };
0140 
0141 /*
0142  * Listing of sub-types ( only operation sign for tree printing.)
0143  */
0144 char *M_subtypes_sign_only[] =
0145 {
0146     " ",
0147     " == ",
0148     " != ",
0149     " %% ",
0150     " !% ",
0151     " < ",
0152     " <= ",
0153     " > ",
0154     " >= ",
0155     "+",
0156     "-",
0157     "~",
0158     "!",
0159     "*",
0160     "/",
0161     "%",
0162     " || ",
0163     " && ",
0164     " ^ "
0165 };
0166 
0167 /*---------------------------Prototypes---------------------------------*/
0168 expublic void _Btreefree_no_recurse (char *tree);
0169 int is_float_val(value_block_t *v);
0170 /*
0171  * ERROR RECOVERY AND ALLOCATED RESOUCES.
0172  * Not sure is there any other better way (using bison's destructor maybe?)
0173  * but I tried and it does not work out. So I have created simple linked list
0174  * that will track allocated nodes. If parse finds out to be OK, then only list
0175  * it self is removed by remove_resouce_list(). If parse fails, then by using the list
0176  * all allocated ASTs are removed and then list by it self by function remove_resouces().
0177  */
0178 
0179 /**
0180  * Put error here!
0181  * @param s
0182  * @param ...
0183  */
0184 void yyerror(char *s, ...)
0185 {
0186     /* Log only first error! */
0187     if (EXFAIL!=G_error)
0188     {
0189         va_list ap;
0190         char errbuf[2048];
0191         int len;
0192 
0193         va_start(ap, s);
0194         snprintf(errbuf, sizeof(errbuf), ". Near of %d-%d: ", 
0195                 yylloc.first_column, yylloc.last_column);
0196         len=strlen(errbuf);
0197         vsnprintf(errbuf+len, sizeof(errbuf)-len, s, ap);
0198         va_end(ap);
0199 
0200         if (ndrx_Bis_error())
0201         {
0202           /* append message */
0203           ndrx_Bappend_error_msg(errbuf);
0204         }
0205         else
0206         {
0207           /* Set the error from fresh! (+2 for remvoing [. ]) */
0208           ndrx_Bset_error_msg(BSYNTAX, errbuf+2);
0209         }
0210 
0211         G_error = EXFAIL;
0212     }
0213 }
0214 
0215 /**
0216  * Not sure are there any better way to clean up the AST... somehow does not
0217  * work for me!
0218  * @param p
0219  * @return
0220  */
0221 int add_resource(char *p)
0222 {
0223 
0224     struct list_node *tmp = M_cur_mem;
0225     M_cur_mem = malloc (sizeof(struct list_node));
0226 
0227     if (NULL==M_cur_mem)
0228             return EXFAIL; /* <<< RETURN FAIL! */
0229 
0230     if (NULL!=tmp)
0231         tmp->next = M_cur_mem;
0232     
0233     M_cur_mem->mem = p;
0234     M_cur_mem->next = NULL;
0235 
0236     if (NULL==M_first_mem)
0237     {
0238         M_first_mem=M_cur_mem;
0239     }
0240 
0241     return EXSUCCEED;
0242 }
0243 
0244 /**
0245  * In normal case just destroy the resource list!
0246  * @return
0247  */
0248 void remove_resouce_list(void)
0249 {
0250     struct list_node *p = M_first_mem;
0251     while (p)
0252     {
0253         struct list_node *tmp = p;
0254         p = p->next;
0255         NDRX_FREE(tmp); /* Delete current */
0256         UBF_LOG(6, "List node free-up!");
0257     }
0258 }
0259 
0260 /**
0261  * Destroy the AST and then remove resouce list
0262  * @return
0263  */
0264 void remove_resouces(void)
0265 {
0266     struct list_node *p = M_first_mem;
0267     while (p)
0268     {
0269         /* Free up AST */
0270         _Btreefree_no_recurse(p->mem);
0271         p = p->next;
0272     }
0273     /* Remove list by it self */
0274     remove_resouce_list();
0275 }
0276 
0277 /**
0278  * Same as Btreefree, but no recusion!
0279  * This is for error recovery.
0280  * This must be maintained to gether with Btreefree()!
0281  * @param tree
0282  */
0283 expublic void _Btreefree_no_recurse (char *tree)
0284 {
0285     struct ast *a = (struct ast *)tree;
0286     struct ast_string *a_string = (struct ast_string *)tree;
0287     struct ast_fld *a_fld;
0288     struct ast_func *a_func;
0289     
0290     if (NULL==tree)
0291         return; /* <<<< RETURN! Nothing to do! */
0292 
0293     UBF_LOG(6, "Free up nodeid=%d nodetype=%d", a->nodeid, a->nodetype);
0294     switch (a->nodetype)
0295     {
0296         case NODE_TYPE_FLD:
0297             a_fld = (struct ast_fld *)tree;
0298             ndrx_ubf_rfldid_free(&(a_fld->fld));
0299             break;
0300         case NODE_TYPE_STR:
0301             /* Free up internal resources (if have such)? */
0302             if (NULL!=a_string->str)
0303             {
0304                 NDRX_FREE(a_string->str);
0305                 a_string->str_bufsz=0;
0306             }
0307 
0308             /* check regexp, maybe needs to clean up? */
0309             if (a_string->regex.compiled)
0310                 regfree(&(a_string->regex.re));
0311             break;
0312         case NODE_TYPE_FLOAT:
0313             /* nothing to do */
0314             break;
0315         case NODE_TYPE_LONG:
0316             /* nothing to do */
0317             break;
0318         case NODE_TYPE_FUNC:
0319             a_func = (struct ast_func *)tree;
0320             
0321             if (NULL!=a_func->funcall)
0322             {
0323                 NDRX_FPFREE(a_func->funcall);
0324                 
0325             }
0326             break;
0327         default:
0328             /* nothing to do */
0329             break;
0330     }
0331     /* delete self */
0332     NDRX_FREE(tree);
0333 }
0334 
0335 /**
0336  * Standard AST node type W/O data. (i.e. by it self it is +/-, etc...)
0337  * @param nodetype - node type
0338  * @param sub_type - sub type
0339  * @param l - left node
0340  * @param r - right node
0341  * @return ptr to AST node.
0342  */
0343 struct ast * newast(int nodetype, int sub_type, struct ast *l, struct ast *r)
0344 {
0345     struct ast *a = NDRX_MALLOC(sizeof(struct ast));
0346     memset(a, 0, sizeof(struct ast));
0347 
0348     if(!a)
0349     {
0350         yyerror("out of space");
0351         ndrx_Bset_error_msg(BMALLOC, "out of memory for new ast");
0352         return NULL;
0353     }
0354     else
0355     {
0356         if (EXSUCCEED!=add_resource((char *)a))
0357         {
0358             yyerror("out of space");
0359             ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0360             return NULL;
0361         }
0362     }
0363 
0364     a->nodetype = nodetype;
0365     a->sub_type = sub_type;
0366     a->nodeid = G_node_count;
0367     a->l = l;
0368     a->r = r;
0369 
0370     G_node_count++;
0371 
0372     UBF_LOG(log_debug, "adding newast: nodeid: %d, nodetype: %d, type: %s, sub-type:%s "
0373                               "value: [N/A] l=%p r=%p",
0374                           a->nodeid, a->nodetype,
0375                           M_nodetypes[a->nodetype],
0376                           M_subtypes[a->sub_type],
0377                           l, r);
0378 
0379     return a;
0380 }
0381 
0382 struct ast * newfld(ndrx_ubf_rfldid_t f)
0383 {
0384     struct ast_fld *a;
0385     int typ = Bfldtype(f.bfldid);
0386     
0387     if ((BFLD_UBF==typ) || (BFLD_VIEW==typ && NULL==f.cname))
0388     {
0389         /* free up the rfield.. */
0390         ndrx_Bset_error_msg(BEBADOP, "Field types: BFLD_UBF and BFLD_VIEW "
0391                 "not supported in expression");
0392         
0393         yyerror("Field types: BFLD_UBF and BFLD_VIEW not supported in expression");
0394         
0395         
0396         ndrx_ubf_rfldid_free(&f);
0397         
0398         return NULL;
0399     }
0400     
0401     a = NDRX_MALLOC(sizeof(struct ast_fld));
0402     if(!a) 
0403     {
0404         yyerror("out of space");
0405         ndrx_Bset_error_msg(BMALLOC, "out of memory for new ast_fld");
0406         return NULL;
0407     }
0408     else
0409     {
0410         if (EXSUCCEED!=add_resource((char *)a))
0411         {
0412             yyerror("out of space");
0413             ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0414             return NULL;
0415         }
0416     }
0417     
0418     memset(a, 0, sizeof(struct ast_fld));
0419 
0420     a->nodetype = NODE_TYPE_FLD;
0421     a->sub_type = NODE_SUB_TYPE_DEF;
0422     a->nodeid = G_node_count;
0423     /*
0424     a->fld = f;
0425     a->fld.bfldid = BBADFLDID;
0426     */
0427     G_node_count++;
0428 
0429     /* Resolve field id */
0430     memcpy(&(a->fld), &f, sizeof(ndrx_ubf_rfldid_t));
0431     
0432     UBF_LOG(log_debug, "adding newfld: id: %02d, type: %s, sub-type:%s "
0433                               "value: [fld: [%s] occ: [%d] bfldid: [%d]]",
0434                           a->nodeid,
0435                           M_nodetypes[a->nodetype],
0436                           M_subtypes[a->sub_type],
0437                           a->fld.fldnm, a->fld.occ,
0438                           a->fld.bfldid);
0439 out:
0440     return (struct ast *)a;
0441 
0442 }
0443 
0444 /*
0445  * Get Function name
0446  */
0447 func_hash_t * get_func(char *funcname)
0448 {
0449     func_hash_t *r = NULL;
0450     EXHASH_FIND_STR( M_func_hash, funcname, r);
0451     if (NULL!=r)
0452         return r;
0453     else
0454         return NULL;
0455 }
0456 
0457 /*
0458  * Set function pointer by user.
0459  * This is API function. If function ptr is NULL, func is removed from hash.
0460  */
0461 int set_func(char *funcname, void* functionPtr, int functype)
0462 {
0463     int ret=EXSUCCEED;
0464     func_hash_t *tmp;
0465     
0466     UBF_LOG(log_warn, "registering callback: [%s]:%p", 
0467                         funcname, functionPtr);
0468     
0469     if (NULL==functionPtr)
0470     {
0471         func_hash_t *r = NULL;
0472         EXHASH_FIND_STR( M_func_hash, funcname, r);
0473         if (NULL!=r)
0474         {
0475             EXHASH_DEL(M_func_hash, r);
0476             NDRX_FREE(r);
0477         }
0478     }
0479     else
0480     {
0481         tmp = NDRX_MALLOC(sizeof(func_hash_t));
0482 
0483         if (NULL==tmp)
0484         {
0485             yyerror("out of space");
0486             ndrx_Bset_error_msg(BMALLOC, "out of memory for new func_hash_t");
0487             ret=EXFAIL;
0488             goto out;
0489         }
0490 
0491         NDRX_STRCPY_SAFE(tmp->name, funcname);
0492         tmp->fptr = functionPtr;
0493         tmp->functype = functype;
0494         EXHASH_ADD_STR( M_func_hash, name, tmp );
0495     }
0496     
0497 out:
0498     return ret;
0499 }
0500 
0501 /* Function call-back */
0502 struct ast *newfunc(ndrx_symbfunc_t *funccall)
0503 {
0504     int len;
0505     int ret = EXSUCCEED;
0506     struct ast_func *a = NDRX_MALLOC(sizeof(struct ast_func));
0507     memset(a, 0, sizeof(struct ast_func));
0508 
0509     if(!a)
0510     {
0511         yyerror("out of space");
0512         ndrx_Bset_error_msg(BMALLOC, "out of memory for new ast_func");
0513         return NULL;
0514     }
0515     else
0516     {
0517         if (EXSUCCEED!=add_resource((char *)a))
0518         {
0519             yyerror("out of space");
0520             ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0521             return NULL;
0522         }
0523     }
0524 
0525     a->nodetype = NODE_TYPE_FUNC;
0526     a->sub_type = NODE_SUB_TYPE_DEF;
0527     a->nodeid = G_node_count;
0528 
0529     len = strlen(funccall->funcname);
0530 
0531     /* Resolve field function */
0532     if (len<1)
0533     {
0534         yyerror("Function name too short!");
0535         ndrx_Bset_error_fmt(BBADNAME, "Full function name too short [%s]", funccall->funcname);
0536         /* Not sure is this good? If we do free get stack coruption/double free */
0537         EXFAIL_OUT(ret);
0538     }
0539 
0540     a->funcall = funccall;
0541 
0542     /* Resolve field function */
0543     if (NULL==(a->f=get_func(a->funcall->funcname)))
0544     {
0545         yyerror("Bad function name");
0546         
0547         ndrx_Bset_error_fmt(BBADNAME, "Bad function name for [%s]", a->funcall);
0548         /* Not sure is this good? If we do free get stack coruption/double free */
0549         EXFAIL_OUT(ret);
0550     }
0551 
0552     UBF_LOG(log_debug, "ast_func id: %02d, type: %s, sub-type:%s "
0553                               "value: [func: [%s]]",
0554                           a->nodeid,
0555                           M_nodetypes[a->nodetype],
0556                           M_subtypes[a->sub_type],
0557                           a->funcall);
0558     G_node_count++;
0559 out:
0560             
0561     if (EXSUCCEED!=ret)
0562     {
0563         a->funcall=NULL;
0564         NDRX_FPFREE(funccall);
0565     }
0566     
0567     return (struct ast *)a;
0568 }
0569 
0570 struct ast * newstring(char *str)
0571 {
0572     struct ast_string *a = NDRX_MALLOC(sizeof(struct ast_string));
0573     memset(a, 0, sizeof(struct ast_string));
0574 
0575     a->str_bufsz = strlen(str)+1;
0576 
0577     a->str = NDRX_MALLOC (a->str_bufsz);
0578 
0579     if(!a || !a->str) {
0580         yyerror("out of space");
0581         ndrx_Bset_error_msg(BMALLOC, "out of memory for new ast_string or a->str");
0582         return NULL;
0583     }
0584     else
0585     {
0586       if (EXSUCCEED!=add_resource((char *)a))
0587       {
0588           yyerror("out of space");
0589           ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0590           return NULL;
0591       }
0592     }
0593 
0594     a->nodetype = NODE_TYPE_STR;
0595     a->sub_type = NODE_SUB_TYPE_DEF;
0596     a->nodeid = G_node_count;
0597     strcpy(a->str, str);
0598     G_node_count++;
0599 
0600     UBF_LOG(log_debug, "adding newstr: id: %02d, type: %s, sub-type:%s "
0601                     "value: [%s]",
0602                     a->nodeid,
0603                     M_nodetypes[a->nodetype],
0604                     M_subtypes[a->sub_type],
0605                     a->str);
0606 
0607     return (struct ast *)a;
0608 }
0609 
0610 struct ast * newfloat(double d)
0611 {
0612     struct ast_float *a = NDRX_MALLOC(sizeof(struct ast_float));
0613     memset(a, 0, sizeof(struct ast_float));
0614     
0615     if(!a) 
0616     {
0617         yyerror("out of space");
0618         ndrx_Bset_error_msg(BMALLOC, "out of memory for new newfloat");
0619         return NULL;
0620     }
0621     else
0622     {
0623         if (EXSUCCEED!=add_resource((char *)a))
0624         {
0625             yyerror("out of space");
0626             ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0627             return NULL;
0628         }
0629     }
0630     
0631     a->nodetype = NODE_TYPE_FLOAT;
0632     a->sub_type = NODE_SUB_TYPE_DEF;
0633     a->nodeid = G_node_count;
0634     a->d = d;
0635     G_node_count++;
0636     
0637     UBF_LOG(log_debug, "adding newflt: id: %02d, type: %s, sub-type:%s "
0638             "value: [%0.13lf]",
0639             a->nodeid,
0640             M_nodetypes[a->nodetype],
0641             M_subtypes[a->sub_type],
0642             a->d);
0643 
0644     return (struct ast *)a;
0645 }
0646 
0647 struct ast * newlong(long l)
0648 {
0649     struct ast_long *a = NDRX_MALLOC(sizeof(struct ast_long));
0650     memset(a, 0, sizeof(struct ast_long));
0651 
0652     if(!a) {
0653         yyerror("out of space");
0654         ndrx_Bset_error_msg(BMALLOC, "out of memory for new newfloat");
0655         return NULL;
0656     }
0657     else
0658     {
0659         if (EXSUCCEED!=add_resource((char *)a))
0660         {
0661             yyerror("out of space");
0662             ndrx_Bset_error_msg(BMALLOC, "out of memory for resource list");
0663             return NULL;
0664         }
0665     }
0666     
0667     a->nodetype = NODE_TYPE_LONG;
0668     a->sub_type = NODE_SUB_TYPE_DEF;
0669     a->nodeid = G_node_count;
0670     a->l = l;
0671     G_node_count++;
0672 
0673     UBF_LOG(log_debug, "adding newlng: id: %02d, type: %s, sub-type:%s "
0674                 "value: [%ld]",
0675                 a->nodeid,
0676                 M_nodetypes[a->nodetype],
0677                 M_subtypes[a->sub_type],
0678                 a->l);
0679 
0680     return (struct ast *)a;
0681 }
0682 /*
0683  * Convert value block to the string
0684  * Or hmm... maybe we need to convert string to float and then do check?
0685  * That would cause better effect in case of trailing zeros...
0686  */
0687 int get_float(value_block_t *v)
0688 {
0689     int ret=EXSUCCEED;
0690     if (VALUE_TYPE_FLOAT==v->value_type)
0691     {
0692         /* do nothing. */
0693     }
0694     else if (VALUE_TYPE_LONG==v->value_type)
0695     {
0696         v->value_type = VALUE_TYPE_FLOAT;
0697         v->floatval= (double) v->longval;
0698     }
0699     else if (VALUE_TYPE_STRING==v->value_type || VALUE_TYPE_FLD_STR==v->value_type)
0700     {
0701         v->value_type = VALUE_TYPE_FLOAT;
0702         v->floatval = atof(v->strval);
0703     }
0704     else
0705     {
0706         UBF_LOG(log_error, "get_float: Unknown value type %d\n",
0707                                     v->value_type);
0708         ndrx_Bset_error_fmt(BSYNTAX, "get_float: Unknown value type %d\n",
0709                                     v->value_type);
0710         ret=EXFAIL;
0711     }
0712     
0713     return ret;
0714 }
0715 /**
0716  * Dump value block
0717  * @param v - ptr to initialized value block
0718  */
0719 void dump_val(char *text, value_block_t *v)
0720 {
0721     switch(v->value_type)
0722     {
0723         case VALUE_TYPE_LONG:
0724             UBF_LOG(log_info, "%s:ret long          : %ld", text, v->longval);
0725             break;
0726         case VALUE_TYPE_FLOAT:
0727             UBF_LOG(log_info, "%s:ret float         : %.13lf", text, v->floatval);
0728             break;
0729         case VALUE_TYPE_STRING:
0730             UBF_LOG(log_info, "%s:ret const string  : [%s]", text, v->strval);
0731             break;
0732         case VALUE_TYPE_FLD_STR:
0733             UBF_LOG(log_info, "%s:ret fld string    : [%s]", text, v->strval);
0734             break;
0735         default:
0736             UBF_LOG(log_error,   "%s:Error: unknown type value block", text, v->strval);
0737             break;
0738     }
0739     UBF_LOG(log_debug,       "%s:ret bool          : %d", text, v->boolval);
0740 }
0741 /**
0742  * Convert value block to string.
0743  * @param buf - pointer to buffer space where to put string value.
0744  * @param bufsz - buffer size of the buf
0745  * @param v
0746  * @return SUCCEED
0747  */
0748 exprivate int conv_to_string(char *buf, size_t bufsz, value_block_t *v)
0749 {
0750     int ret=EXSUCCEED;
0751 
0752     v->strval = buf;
0753     
0754     if (VALUE_TYPE_LONG==v->value_type)
0755     {
0756         v->value_type = VALUE_TYPE_STRING;
0757         snprintf(v->strval, bufsz, "%ld", v->longval);
0758     }
0759     else if (VALUE_TYPE_FLOAT==v->value_type)
0760     {
0761         v->value_type = VALUE_TYPE_STRING;
0762         snprintf(v->strval, bufsz, "%.13lf", v->floatval);
0763     }
0764     else
0765     {
0766         UBF_LOG(log_error, "conv_to_string: Unknown value type %d\n",
0767                                 v->value_type);
0768         ndrx_Bset_error_fmt(BSYNTAX, "conv_to_string: Unknown value type %d\n",
0769                                 v->value_type);
0770         ret=EXFAIL;
0771     }
0772 
0773     return ret;
0774 }
0775 
0776 /**
0777  * Convert value block to long.
0778  * @param v
0779  * @return SUCCEED
0780  */
0781 int conv_to_long(value_block_t *v)
0782 {
0783     int ret=EXSUCCEED;
0784 
0785     if (VALUE_TYPE_STRING==v->value_type || VALUE_TYPE_FLD_STR==v->value_type)
0786     {
0787         v->longval=atof(v->strval);
0788     }
0789     else if (VALUE_TYPE_FLOAT==v->value_type)
0790     {
0791         v->longval=(long)v->floatval;
0792     }
0793     else
0794     {
0795         UBF_LOG(log_error,"conv_to_long: Unknown value type %d\n",
0796                                 v->value_type);
0797         ndrx_Bset_error_fmt(BSYNTAX, "conv_to_long: Unknown value type %d\n",
0798                                 v->value_type);
0799         ret=EXFAIL;
0800     }
0801 
0802     return ret;
0803 }
0804 
0805 /**
0806  * Compare (and do other math ops) on two value blocks
0807  * @param type
0808  * @param sub_type
0809  * @param lval
0810  * @param rval
0811  * @param v - returned value block
0812  * @return SUCCEED/FAIL
0813  */
0814 int op_equal_float_cmp(int type, int sub_type, value_block_t *lval, 
0815         value_block_t *rval, value_block_t *v)
0816 {
0817     int ret=EXSUCCEED;
0818 
0819     v->value_type = VALUE_TYPE_LONG;
0820 
0821     if (VALUE_TYPE_FLOAT!=lval->value_type && EXSUCCEED!=get_float(lval))
0822     {
0823         ret=EXFAIL;
0824     }
0825 
0826     if (EXSUCCEED==ret && VALUE_TYPE_FLOAT!=rval->value_type &&
0827                             EXSUCCEED!=get_float(rval))
0828     {
0829         ret=EXFAIL;
0830     }
0831 
0832     if (EXSUCCEED==ret)
0833     {
0834         UBF_LOG(log_debug, "flt CMP (%s/%s): [%lf] vs [%lf]",
0835                         M_nodetypes[type], M_subtypes[sub_type], lval->floatval, rval->floatval);
0836 
0837         if (NODE_TYPE_EQOP==type)
0838         {
0839             v->longval = v->boolval = (fabs(lval->floatval-rval->floatval)<DOUBLE_EQUAL);
0840         }
0841         else if (NODE_TYPE_RELOP==type && RELOP_LESS==sub_type) /* RELOP_LESS -> [x < y]*/
0842         {
0843             v->longval = v->boolval = (lval->floatval<rval->floatval?EXTRUE:EXFALSE);
0844         }
0845         else if (NODE_TYPE_RELOP==type && RELOP_LESS_EQUAL==sub_type) /* RELOP_LESS_EQUAL -> [x <= y]*/
0846         {
0847             v->longval = v->boolval = (lval->floatval<=rval->floatval?EXTRUE:EXFALSE);
0848         }
0849         else if (NODE_TYPE_RELOP==type && RELOP_GREATER==sub_type) /* RELOP_GREATER -> [x > y]*/
0850         {
0851             v->longval = v->boolval = (lval->floatval>rval->floatval?EXTRUE:EXFALSE);
0852         }
0853         else if (NODE_TYPE_RELOP==type && RELOP_GREATER_EQUAL==sub_type) /* RELOP_GREATER_EQUAL -> [x >= y]*/
0854         {
0855             v->longval = v->boolval = (lval->floatval>=rval->floatval?EXTRUE:EXFALSE);
0856         }
0857         else if (NODE_TYPE_ADDOP==type || NODE_TYPE_MULTOP==type)
0858         {
0859             v->value_type = VALUE_TYPE_FLOAT;
0860 
0861             if (NODE_TYPE_ADDOP==type && ADDOP_PLUS==sub_type)
0862             {
0863                 v->floatval=lval->floatval+rval->floatval;
0864             }
0865             else if (NODE_TYPE_ADDOP==type && ADDOP_MINUS==sub_type)
0866             {
0867                 v->floatval=lval->floatval-rval->floatval;
0868             }
0869             else if (NODE_TYPE_MULTOP==type && MULOP_DOT==sub_type)
0870             {
0871                 v->floatval=lval->floatval*rval->floatval;
0872             }
0873             else if (NODE_TYPE_MULTOP==type && MULOP_DIV==sub_type)
0874             {
0875                 if (IS_FLOAT_0(rval->floatval)) /* Original system specifics... */
0876                     rval->floatval = 0;
0877                 else
0878                     v->floatval=lval->floatval/rval->floatval;
0879             }
0880             else if (NODE_TYPE_MULTOP==type && MULOP_MOD==sub_type)
0881             {
0882                 /* Make these cases as false - original system do this such */
0883                 v->value_type = VALUE_TYPE_LONG;
0884                 UBF_LOG(log_warn, "ERROR! No mod support for floats!");
0885                 v->longval = v->boolval = EXFALSE;
0886             }
0887             
0888             /* Set TRUE/FALSE flag */
0889             if (!IS_FLOAT_0(v->floatval))
0890                 v->boolval=EXTRUE;
0891             else
0892                 v->boolval=EXFALSE;
0893         }
0894     } /*if (SUCCEED==ret)*/
0895     
0896     /* Dump out the final value */
0897     DUMP_VALUE_BLOCK("op_equal_float_cmp", v);
0898 
0899     return ret;
0900 }
0901 
0902 /**
0903  * Do compare and math op's on left/rigt and put result back in v
0904  * @param type
0905  * @param sub_type
0906  * @param lval
0907  * @param rval
0908  * @param v
0909  * @return SUCCEED/FAIL
0910  */
0911 int op_equal_long_cmp(int type, int sub_type, value_block_t *lval, 
0912         value_block_t *rval, value_block_t *v)
0913 {
0914     int ret=EXSUCCEED;
0915     v->value_type = VALUE_TYPE_LONG;
0916 
0917     if ((VALUE_TYPE_LONG!=lval->value_type) && EXSUCCEED!=conv_to_long(lval))
0918     {
0919         ret=EXFAIL;
0920     }
0921 
0922     if (EXSUCCEED==ret && (VALUE_TYPE_LONG!=rval->value_type) &&
0923             EXSUCCEED!=conv_to_long(rval))
0924     {
0925         ret=EXFAIL;
0926     }
0927 
0928     if (EXSUCCEED==ret)
0929     {
0930         UBF_LOG(log_debug, "lng CMP (%s/%s): [%ld] vs [%ld]",
0931                         M_nodetypes[type], M_subtypes[sub_type], lval->longval, rval->longval);
0932 
0933         if (NODE_TYPE_EQOP==type)
0934         {
0935             v->longval = v->boolval = (lval->longval==rval->longval);
0936         }
0937         else if (NODE_TYPE_RELOP==type && RELOP_LESS==sub_type) /* RELOP_LESS -> [x < y]*/
0938         {
0939             v->longval = v->boolval = (lval->longval<rval->longval?EXTRUE:EXFALSE);
0940         }
0941         else if (NODE_TYPE_RELOP==type && RELOP_LESS_EQUAL==sub_type) /* RELOP_LESS_EQUAL -> [x <= y]*/
0942         {
0943             v->longval = v->boolval = (lval->longval<=rval->longval?EXTRUE:EXFALSE);
0944         }
0945         else if (NODE_TYPE_RELOP==type && RELOP_GREATER==sub_type) /* RELOP_GREATER -> [x > y]*/
0946         {
0947             v->longval = v->boolval = (lval->longval>rval->longval?EXTRUE:EXFALSE);
0948         }
0949         else if (NODE_TYPE_RELOP==type && RELOP_GREATER_EQUAL==sub_type) /* RELOP_GREATER_EQUAL -> [x >= y]*/
0950         {
0951             v->longval = v->boolval = (lval->longval>=rval->longval?EXTRUE:EXFALSE);
0952         }
0953         else if (NODE_TYPE_ADDOP==type || NODE_TYPE_MULTOP==type)
0954         {
0955             v->value_type = VALUE_TYPE_LONG;
0956 
0957             if (NODE_TYPE_ADDOP==type && ADDOP_PLUS==sub_type)
0958             {
0959                 v->longval=lval->longval+rval->longval;
0960             }
0961             if (NODE_TYPE_ADDOP==type && ADDOP_MINUS==sub_type)
0962             {
0963                 v->longval=lval->longval-rval->longval;
0964             }
0965             else if (NODE_TYPE_MULTOP==type && MULOP_DOT==sub_type)
0966             {
0967                 v->longval=lval->longval*rval->longval;
0968             }
0969             else if (NODE_TYPE_MULTOP==type && MULOP_DIV==sub_type)
0970             {
0971                 /* Original system specifics... */
0972                 if (0==rval->longval)
0973                     v->longval=0;
0974                 else
0975                     v->longval=lval->longval/rval->longval;
0976             }
0977             else if (NODE_TYPE_MULTOP==type && MULOP_MOD==sub_type)
0978             {
0979                 if (0==rval->longval)
0980                     v->longval=lval->longval;
0981                 else
0982                     v->longval=lval->longval%rval->longval;
0983             }
0984             /* Set TRUE/FALSE flag */
0985             if (v->longval)
0986                 v->boolval=EXTRUE;
0987             else
0988                 v->boolval=EXFALSE;
0989         }
0990     }
0991 
0992     /* Dump out the final value */
0993     DUMP_VALUE_BLOCK("op_equal_long_cmp", v);
0994 
0995     return ret;
0996 }
0997 
0998 int op_equal_str_cmp(int type, int sub_type, value_block_t *lval, 
0999         value_block_t *rval, value_block_t *v)
1000 {
1001     int ret=EXSUCCEED;
1002     int result;
1003     char lval_buf[CF_TEMP_BUF_MAX]; /* should be enough for all data types */
1004     char rval_buf[CF_TEMP_BUF_MAX]; /* should be enough for all data types */
1005     v->value_type = VALUE_TYPE_LONG;
1006 
1007     if (VALUE_TYPE_FLD_STR!=lval->value_type &&
1008             VALUE_TYPE_STRING!=lval->value_type &&
1009             EXSUCCEED!=conv_to_string(lval_buf, CF_TEMP_BUF_MAX, lval))
1010     {
1011         ret=EXFAIL;
1012     }
1013 
1014     if (EXSUCCEED==ret && VALUE_TYPE_FLD_STR!=rval->value_type &&
1015             VALUE_TYPE_STRING!=rval->value_type &&
1016             EXSUCCEED!=conv_to_string(rval_buf, CF_TEMP_BUF_MAX, rval))
1017     {
1018         ret=EXFAIL;
1019     }
1020 
1021     if (EXSUCCEED==ret)
1022     {
1023         result=strcmp(lval->strval, rval->strval);
1024 
1025         UBF_LOG(log_debug, "str CMP (%s/%s): [%s] vs [%s]",
1026                 M_nodetypes[type], M_subtypes[sub_type], 
1027                 lval->strval, rval->strval);
1028 
1029         if (NODE_TYPE_EQOP==type)
1030         {
1031             v->longval = v->boolval = result==0?EXTRUE:EXFALSE;
1032         }
1033         else if (NODE_TYPE_RELOP==type && RELOP_LESS==sub_type) /* RELOP_LESS -> [x < y]*/
1034         {
1035             v->longval = v->boolval = (result<0?EXTRUE:EXFALSE);
1036         }
1037         else if (NODE_TYPE_RELOP==type && RELOP_LESS_EQUAL==sub_type) /* RELOP_LESS_EQUAL -> [x <= y]*/
1038         {
1039             v->longval = v->boolval = (result<=0?EXTRUE:EXFALSE);
1040         }
1041         else if (NODE_TYPE_RELOP==type && RELOP_GREATER==sub_type) /* RELOP_GREATER -> [x > y]*/
1042         {
1043             v->longval = v->boolval = (result>0?EXTRUE:EXFALSE);
1044         }
1045         else if (NODE_TYPE_RELOP==type && RELOP_GREATER_EQUAL==sub_type) /* RELOP_GREATER_EQUAL -> [x >= y]*/
1046         {
1047             v->longval = v->boolval = (result>=0?EXTRUE:EXFALSE);
1048         }
1049         else if (NODE_TYPE_ADDOP==type || NODE_TYPE_MULTOP==type)
1050         {
1051             /* Make these cases as false - original system do this such */
1052             UBF_LOG(log_warn, "ERROR! No math support for strings!");
1053             v->longval = v->boolval = EXFALSE;
1054         }
1055 
1056         UBF_LOG(log_debug, "Result bool: %d long:%ld", v->boolval, rval->longval);
1057     }
1058 
1059     /* Dump out the final value */
1060     DUMP_VALUE_BLOCK("op_equal_str_cmp", v);
1061     
1062     return ret;
1063 }
1064 
1065 /**
1066  * As by specification ' ' VS NUM, we convert NUM to str
1067  * if FLD(STR) VS NUM, we convert FDL to NUM
1068  */
1069 int op_equal(UBFH *p_ub, int type, int sub_type, struct ast *l, struct ast *r, value_block_t *v)
1070 {
1071     int ret=EXSUCCEED;
1072     value_block_t lval, rval;
1073     memset(&lval, 0, sizeof(lval));
1074     memset(&rval, 0, sizeof(rval));
1075     /* Get the values out of the child stuff */
1076     if (EXSUCCEED!=eval(p_ub, l, &lval))
1077     {
1078         ret=EXFAIL;
1079     }
1080 
1081     if (EXSUCCEED==ret && EXSUCCEED!=eval(p_ub, r, &rval))
1082     {
1083         ret=EXFAIL;
1084     }
1085 
1086     if (EXSUCCEED==ret)
1087     {
1088         if (lval.is_null || rval.is_null)
1089         {
1090             /* Not equal... */
1091             UBF_LOG(log_debug, "LVAR or LVAL is NULL => False");
1092             v->longval = v->boolval = EXFALSE;
1093             goto out;
1094         }
1095     
1096         if (( (VALUE_TYPE_STRING==lval.value_type &&
1097             VALUE_TYPE_STRING==rval.value_type)
1098             ||
1099             (VALUE_TYPE_FLD_STR==lval.value_type &&
1100             VALUE_TYPE_FLD_STR==rval.value_type)
1101             ||
1102             (VALUE_TYPE_STRING==lval.value_type &&
1103             VALUE_TYPE_FLD_STR==rval.value_type)
1104             ||
1105             (VALUE_TYPE_FLD_STR==lval.value_type &&
1106             VALUE_TYPE_STRING==rval.value_type)) &&
1107                 !(type==NODE_TYPE_ADDOP || type==NODE_TYPE_MULTOP) /* do not run math ops */
1108                 )
1109         {
1110             ret=op_equal_str_cmp(type, sub_type, &lval, &rval, v);
1111 
1112         }
1113         else if ((VALUE_TYPE_STRING==lval.value_type ||
1114             VALUE_TYPE_STRING==rval.value_type) && !(type==NODE_TYPE_ADDOP || 
1115                 type==NODE_TYPE_MULTOP))
1116         {
1117             ret=op_equal_str_cmp(type, sub_type, &lval, &rval, v);
1118         }
1119         /* if both are longs, then compare them */
1120         else if (VALUE_TYPE_LONG==lval.value_type && VALUE_TYPE_LONG==rval.value_type)
1121         {
1122             ret=op_equal_long_cmp(type, sub_type, &lval, &rval, v);
1123         }
1124         else /* limit the scope for is_float_val call */
1125         {
1126             int is_lval_float = is_float_val(&lval);
1127             int is_rval_float = is_float_val(&rval);
1128 #if 0
1129             /* If any is long and other is not containing float symbols - convert longs & cmp*/
1130             if (VALUE_TYPE_LONG==lval.value_type && !is_rval_float ||
1131                      VALUE_TYPE_LONG==rval.value_type && !is_lval_float)
1132             {
1133                 ret=op_equal_long_cmp(type, sub_type, &lval, &rval, v);
1134             }
1135             /* If both strings are not floats, then do the long cmp */
1136             else
1137 #endif      /* mode (%) we will process as long. */
1138             if ((!is_lval_float && !is_rval_float) || 
1139                     (NODE_TYPE_MULTOP==type && MULOP_MOD==sub_type))
1140             {
1141                 ret=op_equal_long_cmp(type, sub_type, &lval, &rval, v);
1142             }
1143             else /* Nothing to do:- downgrade to float compare */
1144             {
1145                 ret=op_equal_float_cmp(type, sub_type, &lval, &rval, v);
1146             } /* else */
1147         }
1148 
1149     } /* main SUCCEED==ret */
1150 
1151 out:
1152     /* Ensure that we clean up dynamically allocated FB resources! */
1153     FREE_UP_UB_BUF((&lval));
1154     FREE_UP_UB_BUF((&rval));
1155 
1156     return ret;
1157 }
1158 
1159 
1160 /**
1161  * Retrieve value in unified/recursive way.
1162  * Also read the value from view buffer
1163  * @param p_ub
1164  * @param rbfldid
1165  * @param buf allocated buffer where to unload the data for strings...
1166  *  in case if string type is read, it is cast to double ptr
1167  * @param len
1168  * @param usrtype
1169  * @return 
1170  */
1171 exprivate int CBget_unified(UBFH *p_ub, ndrx_ubf_rfldid_t *rbfldid, 
1172         char *buf, BFLDLEN *len, int usrtype)
1173 {
1174     int ret = EXSUCCEED;
1175     char **dptr = (char **)buf;
1176     if (rbfldid->nrflds==1)
1177     {
1178         if (BFLD_STRING==usrtype)
1179         {
1180             *dptr=CBgetalloc(p_ub, rbfldid->bfldid, rbfldid->occ, usrtype, NULL);
1181             if (NULL==*dptr)
1182             {
1183                 ret=EXFAIL;
1184             }
1185             
1186         }
1187         else
1188         {
1189             ret=CBget(p_ub, rbfldid->bfldid, rbfldid->occ, buf, len, usrtype);
1190         }
1191     }
1192     else if (NULL!=rbfldid->cname)
1193     {
1194         /* recursive view lookup 
1195          * return data even if it is NULL, so that buffer can tested agains
1196          * NULL values.
1197          */
1198         if (BFLD_STRING==usrtype)
1199         {
1200             *dptr = CBvgetallocr(p_ub, (BFLDID *)rbfldid->fldidocc.mem, rbfldid->cname, 
1201                     rbfldid->cname_occ, usrtype, BVACCESS_NOTNULL, NULL);
1202             if (NULL==*dptr)
1203             {
1204                 ret=EXFAIL;
1205             }
1206         }
1207         else
1208         {
1209             ret = CBvgetr(p_ub, (BFLDID *)rbfldid->fldidocc.mem, rbfldid->cname, 
1210                     rbfldid->cname_occ, buf, len, usrtype, BVACCESS_NOTNULL);
1211         }
1212     }
1213     else
1214     {
1215         if (BFLD_STRING==usrtype)
1216         {
1217             *dptr = CBgetallocr (p_ub, (BFLDID *)rbfldid->fldidocc.mem, usrtype, NULL);
1218             
1219             if (NULL==*dptr)
1220             {
1221                 ret=EXFAIL;
1222             }
1223         }
1224         else
1225         {
1226             ret = CBgetr (p_ub, (BFLDID *)rbfldid->fldidocc.mem,
1227                                 buf, len, usrtype);
1228         }
1229     }
1230     
1231     return ret;
1232 }
1233 
1234 /**
1235  * Unified field presence tester, works for sub-views too and recursive buffers
1236  * @param p_ub UBF buffer
1237  * @param rbfldid recursive field id
1238  * @return EXFAIL/EXFALSE/EXTRUE
1239  */
1240 exprivate int Bpres_unified(UBFH *p_ub, ndrx_ubf_rfldid_t *rbfldid)
1241 {
1242     int ret = EXSUCCEED;
1243     
1244     if (rbfldid->nrflds==1)
1245     {
1246         ret=Bpres(p_ub, rbfldid->bfldid, rbfldid->occ);
1247     }
1248     else if (NULL!=rbfldid->cname)
1249     {
1250         /* recursive view lookup */
1251         ret=Bvnullr(p_ub, (BFLDID *)rbfldid->fldidocc.mem, rbfldid->cname, 
1252                 rbfldid->cname_occ);
1253         
1254         if (EXFALSE==ret)
1255         {
1256             ret=EXTRUE;
1257         }
1258         else if (EXTRUE==ret)
1259         {
1260             ret=EXFALSE;
1261         }
1262         /*else it is failure*/
1263     }
1264     else
1265     {
1266         /* recursive buffer lookup */
1267         ret=Bpresr (p_ub, (BFLDID *)rbfldid->fldidocc.mem);
1268     }
1269     
1270     return ret;
1271 }
1272 
1273 /* This will not use recursion on eval. We will take data out of AST by selves! */
1274 int regexp_eval(UBFH *p_ub, struct ast *l, struct ast *r, value_block_t *v)
1275 {
1276     int ret=EXSUCCEED;
1277     char *l_buf=NULL;
1278     char *p_l=NULL;
1279     char *p_r=NULL;
1280     regex_t *re;
1281     int err;
1282     struct ast_string *ls = (struct ast_string *)l;
1283     struct ast_fld *lf = (struct ast_fld *)l;
1284     struct ast_string *rs = (struct ast_string *)r;
1285 
1286     if (NODE_TYPE_FLD==l->nodetype)
1287     {
1288         /* Get the value of field */
1289         if (EXSUCCEED!=(ret=CBget_unified(p_ub, &(lf->fld),
1290                                     (char *)&l_buf, NULL, BFLD_STRING)))
1291         {
1292             if (BNOTPRES==Berror)
1293             {
1294                 ndrx_Bunset_error(); /* Clear error, because this is not error case! */
1295                 /* This is OK */
1296                 UBF_LOG(log_warn, "Field not present [%s]", lf->fld.fldnm);
1297                 v->value_type=VALUE_TYPE_LONG;
1298                 v->longval=v->boolval=EXFALSE;
1299                 v->is_null=EXTRUE; /* Cannot do compare! */
1300 
1301                 return EXSUCCEED; /* <<< RETURN!!! Nothing to do. */
1302             }
1303             else
1304             {
1305                 UBF_LOG(log_warn, "Failed to get [%s] - %s",
1306                                         lf->fld.fldnm, Bstrerror(Berror));
1307                 EXFAIL_OUT(ret);
1308             }
1309 
1310         }
1311         else
1312         {
1313             p_l = l_buf;
1314         }
1315     }
1316     else if (NODE_TYPE_STR==l->nodetype)
1317     {
1318         /* Set the pointer to AST node */
1319         p_l = ls->str;
1320     }
1321     else
1322     {
1323         /* cannot handle other items, but should be already handled by parser! */
1324         ndrx_Bset_error_msg(BSYNTAX, "Left side of regex must be const string or FB field");
1325         ret=EXFAIL;
1326     }
1327 
1328     /* Right string must be quoted const string! */
1329     if (NODE_TYPE_STR==r->nodetype)
1330     {
1331         p_r = rs->str;
1332     } /* We do not have correct right side - FAIL */
1333     else
1334     {
1335     /* We must handle this by parser */
1336         UBF_LOG(log_error, "Right side of regexp must be const string! "
1337                                 "But got node type [%d]\n", r->nodetype);
1338          ndrx_Bset_error_msg(BSYNTAX, "Right side of regex must be const string");
1339          EXFAIL_OUT(ret);
1340     }
1341 
1342 
1343     re = &(rs->regex.re);
1344     UBF_LOG(log_debug, "Regex left  [%s]", p_l);
1345     UBF_LOG(log_debug, "Regex right [%s]", p_r);
1346 
1347     /* Now see do we need to compile  */
1348     if (!rs->regex.compiled)
1349     {
1350         UBF_LOG(log_debug, "Compiling regex");
1351         if (EXSUCCEED!=(err=regcomp(re, p_r, REG_EXTENDED | REG_NOSUB)))
1352         {
1353             ndrx_report_regexp_error("regcomp", err, re);
1354             EXFAIL_OUT(ret);
1355         }
1356         else
1357         {
1358             UBF_LOG(log_debug, "REGEX: Compiled OK");
1359             rs->regex.compiled = 1;
1360         }
1361     }
1362 
1363     if (EXSUCCEED==regexec(re, p_l, (size_t) 0, NULL, 0))
1364     {
1365         v->value_type=VALUE_TYPE_LONG;
1366         v->longval=v->boolval=EXTRUE;
1367         UBF_LOG(log_debug, "REGEX: matched!");
1368     }
1369     else if (EXSUCCEED==ret)
1370     {
1371         v->value_type=VALUE_TYPE_LONG;
1372         v->longval=v->boolval=EXFALSE;
1373         UBF_LOG(log_debug, "REGEX: NOT matched!");
1374     }
1375 
1376 out:
1377     /* Dump out the final value */
1378     DUMP_VALUE_BLOCK("regexp_eval", v);
1379 
1380     if (NULL!=l_buf)
1381     {
1382         NDRX_FREE(l_buf);
1383     }
1384 
1385     return ret;
1386 }
1387 
1388 /**
1389  * This reads FB. But takes out no string value.
1390  */
1391 int read_unary_func(UBFH *p_ub, struct ast *a, value_block_t * v)
1392 {
1393     int ret=EXSUCCEED;
1394     struct ast_func *func = (struct ast_func *)a;
1395     char *fn = "read_unary_func";
1396 
1397     UBF_LOG(log_debug, "Entering %s func: [%s]",
1398                                     fn, func->funcall);
1399     
1400     /* Call the function... */
1401     v->value_type=VALUE_TYPE_LONG;
1402     
1403     if (NDRX_CBFUNTYPE_ARG1==func->f->functype)
1404     {
1405         functionPtr2_t fcall = (functionPtr2_t)func->f->fptr;
1406         UBF_LOG(log_debug, "Arg1 func call");
1407         
1408         v->longval = fcall(p_ub, func->funcall->funcname, func->funcall->arg1);
1409         
1410     }
1411     else
1412     {
1413         functionPtr_t fcall = (functionPtr_t)func->f->fptr;
1414         UBF_LOG(log_debug, "No args call %d", func->f->functype);
1415         
1416         v->longval = fcall(p_ub, func->funcall->funcname);
1417     }
1418 
1419     if (v->longval)
1420         v->boolval=EXTRUE;
1421     else
1422         v->boolval=EXFALSE;
1423     
1424     /* Dump out the final value */
1425     DUMP_VALUE_BLOCK("read_unary_fb", v);
1426 
1427     UBF_LOG(log_debug, "return %s %d", fn, ret);
1428     
1429     return ret;
1430 }
1431 /**
1432  * This reads FB. But takes out no string value.
1433  * This reads long, float/double.
1434  * All others are assumed as 
1435  */
1436 /**
1437  * This reads FB. But takes out no string value.
1438  * This reads long, float/double.
1439  * All others are assumed as 
1440  */
1441 int read_unary_fb(UBFH *p_ub, struct ast *a, value_block_t * v)
1442 {
1443     int ret=EXSUCCEED;
1444     struct ast_fld *fld = (struct ast_fld *)a;
1445     BFLDID bfldid;
1446     BFLDOCC occ;
1447     int fld_type;
1448     char fn[] = "read_unary_fb()";
1449     /* Must be already found! */
1450     bfldid = fld->fld.bfldid;
1451     occ = fld->fld.occ;
1452 
1453     UBF_LOG(log_debug, "Entering %s fldnm [%s] bfldid=%d occ=%d",
1454                                     fn, fld->fld.fldnm, bfldid, occ);
1455     /*
1456      * Now read field type.
1457      * If string or char, then it becomes as long/bool.
1458      * float/double->float (double)
1459      * short/long -> long
1460      * all true if field present.
1461      */
1462 
1463     fld_type=Bfldtype(bfldid);
1464 
1465     if (!Bpres_unified(p_ub, &(fld->fld)))
1466     {
1467         UBF_LOG(log_debug, "Field [%s] not present in fb",
1468                                             fld->fld.fldnm);
1469         v->value_type = VALUE_TYPE_LONG;
1470         v->longval=v->boolval=EXFALSE;
1471         v->is_null=EXTRUE;
1472     }
1473     /* In this case it is just a TRUE. */
1474     else if (BFLD_STRING==fld_type || BFLD_CARRAY==fld_type || BFLD_CHAR==fld_type ||
1475             NULL!=fld->fld.cname)
1476     {
1477         if (EXSUCCEED!=CBget_unified(p_ub, &(fld->fld),
1478                         (char *)&v->strval, NULL, BFLD_STRING))
1479         {
1480             if (BNOTPRES==Berror)
1481             {
1482                 ndrx_Bunset_error(); /* clear error */
1483                 UBF_LOG(log_warn, "Failed to get [%s] as str"
1484                                              " - downgrade to FALSE!",
1485                                              fld->fld.fldnm);
1486                 v->value_type = VALUE_TYPE_FLD_STR;
1487                 v->longval=v->boolval=EXFALSE;
1488                 v->is_null=EXTRUE;
1489             }
1490             else /* on all other errors we are going to FAIL! */
1491             {
1492                 UBF_LOG(log_warn, "Failed to get [%s] - %s",
1493                     fld->fld.fldnm, Bstrerror(Berror));
1494                 ret=EXFAIL;
1495             }
1496             /* Lets free memory right right here, why not? */
1497 
1498             NDRX_FREE(v->strval);
1499             v->dyn_alloc = EXFALSE;
1500             v->strval = NULL;
1501         }
1502         else
1503         {
1504             v->value_type = VALUE_TYPE_FLD_STR;
1505             v->boolval=EXTRUE;
1506             v->dyn_alloc = EXTRUE;
1507         }
1508 
1509     }
1510     else if (BFLD_SHORT==fld_type || BFLD_LONG==fld_type)
1511     {
1512         if (EXSUCCEED!=CBget_unified(p_ub, &(fld->fld), 
1513                         (char *)&v->longval, NULL, BFLD_LONG))
1514         {
1515             if (BNOTPRES==Berror)
1516             {
1517                 ndrx_Bunset_error(); /* clear error */
1518                 UBF_LOG(log_warn, "Failed to get [%s] as long"
1519                         " - downgrade to FALSE!",
1520                         fld->fld.fldnm);
1521                 v->value_type = VALUE_TYPE_LONG;
1522                 v->longval=v->boolval=EXFALSE;
1523                 v->is_null=EXTRUE;
1524             }
1525             else /* on all other errors we are going to FAIL! */
1526             {
1527                 UBF_LOG(log_warn, "Failed to get [%s] - %s",
1528                     fld->fld.fldnm, Bstrerror(Berror));
1529                 ret=EXFAIL;
1530             }
1531         }
1532         else
1533         {
1534                 v->value_type = VALUE_TYPE_LONG;
1535                 v->boolval=EXTRUE;
1536         }
1537     }
1538     else if (BFLD_FLOAT==fld_type || BFLD_DOUBLE==fld_type)
1539     {
1540         if (EXSUCCEED!=CBget_unified(p_ub, &(fld->fld), 
1541                         (char *)&v->floatval, NULL, BFLD_DOUBLE))
1542         {
1543             if (BNOTPRES==Berror)
1544             {
1545                 ndrx_Bunset_error(); /* clear error */
1546                 UBF_LOG(log_warn, "Failed to get [%s] as double"
1547                         " - downgrade to FALSE!",
1548                         fld->fld.fldnm);
1549                 v->value_type = VALUE_TYPE_LONG;
1550                 v->longval=v->boolval=EXFALSE;
1551                 v->is_null=EXTRUE;
1552             }
1553             else /* on all other errors we are going to FAIL! */
1554             {
1555                 UBF_LOG(log_warn, "Failed to get [%s] - %s",
1556                     fld->fld.fldnm, Bstrerror(Berror));
1557                 ret=EXFAIL;
1558             }
1559         }
1560         else
1561         {
1562             v->value_type = VALUE_TYPE_FLOAT;
1563             v->boolval=EXTRUE;
1564         }
1565     }
1566 
1567     /* Dump out the final value */
1568     DUMP_VALUE_BLOCK("read_unary_fb", v);
1569 
1570     UBF_LOG(log_debug, "return %s %d", fn, ret);
1571 
1572     return ret;
1573 }
1574 
1575 /**
1576  * Detect is string looking like float?
1577  * @param s
1578  * @return
1579  */
1580 int is_float(char *s)
1581 {
1582     if (strpbrk(s, ".,eE")) /* this will work faster than multiple strchrs */
1583     {
1584         return EXTRUE;
1585     }
1586     return EXFALSE;
1587 }
1588 /**
1589  * Detect is float value type block.
1590  * @param v
1591  * @return
1592  */
1593 int is_float_val(value_block_t *v)
1594 {
1595     if ( VALUE_TYPE_FLOAT==v->value_type )
1596         return EXTRUE;
1597 
1598     if ( VALUE_TYPE_FLD_STR==v->value_type || VALUE_TYPE_STRING==v->value_type)
1599         return is_float(v->strval);
1600     
1601     return EXFALSE;
1602 }
1603 
1604 /**
1605  * Process unary operation.
1606  * This may have some differences from orginal system when operating
1607  * with FB fields.
1608  * @param p_ub - pointer to FB
1609  * @param op - unary operation (ADDOP_PLUS, ADDOP_MINUS, UNARY_CMPL, UNARY_INV)
1610  * @param a - tree node containing unary operation (left side node contains the value of)
1611  * @param v - return value block
1612  * @return SUCCEED/FAIL
1613  */
1614 int process_unary(UBFH *p_ub, int op, struct ast *a, value_block_t *v)
1615 {
1616     int ret=EXSUCCEED;
1617     value_block_t pri;
1618     /* Data keepers */
1619     double f;
1620     long  l;
1621     int is_long=EXTRUE;
1622     char fn[] = "process_unary()";
1623 
1624     memset(&pri, 0, sizeof(pri));
1625     
1626     UBF_LOG(log_debug, "Entering %s", fn);
1627 
1628     if (EXSUCCEED==eval(p_ub, a->r, &pri))
1629     {
1630 
1631         if (VALUE_TYPE_FLD_STR==pri.value_type || 
1632                 VALUE_TYPE_STRING==pri.value_type)
1633         {
1634             if (is_float(pri.strval))
1635             {
1636                 f = atof(pri.strval);
1637                 is_long = EXFALSE;
1638                 UBF_LOG(log_warn, "Treating unary field as "
1639                                     "float [%f]!", f);
1640             }
1641             else
1642             {
1643                 l = atol(pri.strval);
1644                 is_long = EXTRUE;
1645                 UBF_LOG(log_warn, "Treating unary "
1646                         "field as long [%ld]", l);
1647             }
1648         }
1649         else if (VALUE_TYPE_FLOAT==pri.value_type)
1650         {
1651             is_long=EXFALSE;
1652             f = pri.floatval;
1653         }
1654         else if (VALUE_TYPE_LONG==pri.value_type)
1655         {
1656             /* it must be long */
1657             is_long=EXTRUE;
1658             l = pri.longval;
1659         } /* Bug #325 */
1660         else if (VALUE_TYPE_BOOL!=pri.value_type)
1661         {
1662             UBF_LOG(log_warn, "Unknown value type %d op: %d", 
1663                                 pri.value_type, op);
1664             return EXFAIL;
1665         }
1666         
1667 #if 0
1668         - Bug #325
1669         if (((op==UNARY_CMPL || op==UNARY_INV) && !is_long) 
1670                 && VALUE_TYPE_BOOL!=pri.value_type)
1671         {
1672             /* Convert to long */
1673             UBF_LOG(log_warn, "! or ~ converting double to long!");
1674             l = (long) f;
1675         }
1676 #endif
1677         
1678         v->boolval = pri.boolval;
1679 
1680         switch (op)
1681         {
1682             case ADDOP_PLUS:
1683                 /* actually do nothing here! */
1684                 if (is_long)
1685                 {
1686                     v->value_type=VALUE_TYPE_LONG;
1687                     v->longval = l;
1688                     
1689                     if (v->longval)
1690                         v->boolval=EXTRUE;
1691                     else
1692                         v->boolval=EXFALSE;
1693                     
1694                 }
1695                 else /* float */
1696                 {
1697                     v->value_type=VALUE_TYPE_FLOAT;
1698                     v->floatval = f;
1699                     if (!IS_FLOAT_0(v->floatval))
1700                         v->boolval=EXTRUE;
1701                     else
1702                         v->boolval=EXFALSE;
1703                 }
1704                 break;
1705             case ADDOP_MINUS:
1706                 /* actually do nothing here! */
1707                 if (is_long)
1708                 {
1709                     v->value_type=VALUE_TYPE_LONG;
1710                     v->longval = -l;
1711                     
1712                     if (v->longval)
1713                         v->boolval=EXTRUE;
1714                     else
1715                         v->boolval=EXFALSE;
1716                     
1717                 }
1718                 else /* float */
1719                 {
1720                     v->value_type=VALUE_TYPE_FLOAT;
1721                     v->floatval = -f;
1722                     
1723                     if (!IS_FLOAT_0(v->floatval))
1724                         v->boolval=EXTRUE;
1725                     else
1726                         v->boolval=EXFALSE;
1727                 }
1728                 break;
1729             case UNARY_CMPL:
1730                 /* Works only on longs! */
1731                 v->value_type=VALUE_TYPE_LONG;
1732                 v->boolval = ~pri.boolval;
1733                 /* Assuming long as final bool*/
1734                 v->longval = v->boolval;
1735                 break;
1736             case UNARY_INV:
1737                 v->value_type=VALUE_TYPE_LONG;
1738                 v->boolval = !pri.boolval;
1739                 v->longval = v->boolval;
1740                 break;
1741         }
1742     }
1743     else
1744     {
1745         ret=EXFAIL;
1746     }
1747     /* Ensure that we clean up dynamically allocated FB resources! */
1748     FREE_UP_UB_BUF((&pri));
1749     /* Dump out the final value */
1750     DUMP_VALUE_BLOCK("process_unary", v);
1751     UBF_LOG(log_debug, "Return %s %d", fn, ret);
1752     return ret;
1753 }
1754 
1755 /**
1756  * Doing evaluation recursively.
1757  * There is specific strategy for FB string buffer hadling.
1758  * FB strings are put in dynamically allocated buffers. Meaning that these buffers
1759  * needs to be freed after field wents out of the stack (i.e. on function return)
1760  *
1761  * @param p_ub - pointer to FB
1762  * @param a - root of the AST
1763  * @param v - value to return.
1764  * @return SUCCEED/FAIL
1765  */
1766 int eval(UBFH *p_ub, struct ast *a, value_block_t *v)
1767 {
1768     int ret=EXSUCCEED;
1769     value_block_t l, r;
1770     char fn[] = "eval";
1771     memset(v, 0, sizeof(*v));
1772     memset(&l, 0, sizeof(l));
1773     memset(&r, 0, sizeof(r));
1774 
1775     if (!v)
1776     {
1777         ndrx_Bset_error_msg(BNOTFLD, "internal error, null ret value");
1778             return EXFAIL; /* <<< RETURN HERE! */
1779     }
1780 
1781     if(!a)
1782     {
1783         ndrx_Bset_error_msg(BNOTFLD, "internal error, null eval");
1784         return EXFAIL; /* <<< RETURN HERE! */
1785     }
1786     
1787     UBF_LOG(log_debug, "%s: id: %02d type: %s sub-type %s", fn,
1788                     a->nodeid, M_nodetypes[a->nodetype], M_subtypes[a->sub_type]);
1789     /* Reset that we are successful. */
1790     
1791     switch (a->nodetype)
1792     {
1793         case NODE_TYPE_OR:
1794             ret=eval(p_ub, a->l, &l);
1795             /* So that do we really need to evaluate other side 
1796              * to keep c style working!
1797              */
1798             if (EXSUCCEED==ret && !l.boolval)
1799                     ret=eval(p_ub, a->r, &r);
1800 
1801             if (EXSUCCEED==ret)
1802             {
1803                 v->value_type=VALUE_TYPE_LONG;
1804                 v->longval = v->boolval = (l.boolval || r.boolval)?EXTRUE:EXFALSE;
1805             }
1806             DUMP_VALUE_BLOCK("NODE_TYPE_OR", v);
1807             break;
1808         case NODE_TYPE_AND:
1809             ret=eval(p_ub, a->l, &l);
1810             /* Right side needs only if left is true
1811              * keeping c style
1812              */
1813             if (EXSUCCEED==ret && l.boolval)
1814             {
1815                 ret=eval( p_ub, a->r, &r);
1816             }
1817 
1818             if (EXSUCCEED==ret)
1819             {
1820                 v->value_type=VALUE_TYPE_LONG;
1821 
1822                 v->longval = v->boolval = (l.boolval && r.boolval)?EXTRUE:EXFALSE;
1823             }
1824             DUMP_VALUE_BLOCK("NODE_TYPE_AND", v);
1825             break;
1826         case NODE_TYPE_XOR:
1827             ret = eval( p_ub, a->l, &l);
1828 
1829             if (EXSUCCEED==ret)
1830             {
1831                 ret = eval( p_ub, a->r, &r);
1832             }
1833 
1834             if (EXSUCCEED==ret)
1835             {
1836                 v->value_type=VALUE_TYPE_LONG;
1837 
1838                 if ((l.boolval && !r.boolval) || (!l.boolval && r.boolval))
1839                     v->boolval=EXTRUE;
1840                 else
1841                     v->boolval=EXFALSE;
1842             }
1843             DUMP_VALUE_BLOCK("NODE_TYPE_XOR", v);
1844             break;
1845         case NODE_TYPE_EQOP:
1846             switch (a->sub_type)
1847             {
1848                 case EQOP_EQUAL:
1849                     ret = op_equal(p_ub, NODE_TYPE_EQOP, NODE_SUB_TYPE_DEF, a->l, a->r, v);
1850                     break;
1851                 case EQOP_NOT_EQUAL:
1852                     ret = op_equal(p_ub, NODE_TYPE_EQOP, NODE_SUB_TYPE_DEF, a->l, a->r, v);
1853                     if (EXSUCCEED==ret)
1854                     {
1855                         /* Inverse the result. */
1856                         v->boolval = !v->boolval;
1857                         v->longval = !v->longval;
1858                     }
1859                     DUMP_VALUE_BLOCK("EQOP_NOT_EQUAL", v);
1860                     break;
1861                 case EQOP_REGEX_EQUAL:
1862                     ret=regexp_eval(p_ub, a->l, a->r, v);
1863                     break;
1864                 case EQOP_REGEX_NOT_EQUAL:
1865                     ret=regexp_eval(p_ub, a->l, a->r, v);
1866                     if (EXSUCCEED==ret)
1867                     {
1868                         /* Inverse the result. */
1869                         v->boolval = !v->boolval;
1870                         v->longval = !v->longval;
1871                     }
1872                     DUMP_VALUE_BLOCK("EQOP_REGEX_NOT_EQUAL", v);
1873                     break;
1874             }
1875             break;
1876         case NODE_TYPE_RELOP:
1877             ret = op_equal(p_ub, NODE_TYPE_RELOP, a->sub_type, a->l, a->r, v);
1878             break;
1879         case NODE_TYPE_ADDOP:
1880             ret = op_equal(p_ub, NODE_TYPE_ADDOP, a->sub_type, a->l, a->r, v);
1881             break;
1882         case NODE_TYPE_MULTOP:
1883             ret = op_equal(p_ub, NODE_TYPE_MULTOP, a->sub_type, a->l, a->r, v);
1884             break;
1885         case NODE_TYPE_UNARY:
1886             ret = process_unary(p_ub, a->sub_type, a, v);
1887             break;
1888         case NODE_TYPE_FLD:
1889             /* read the field */
1890             ret=read_unary_fb(p_ub, a, v);
1891             break;
1892         case NODE_TYPE_FUNC:
1893             /* Get func unary... */
1894             ret=read_unary_func(p_ub, a, v);
1895             break;
1896         case NODE_TYPE_STR:
1897             /* In this case we assume it is TRUE 
1898              * We do not use string value block so that we do not get
1899              * stack full of those.
1900              */
1901             v->value_type = VALUE_TYPE_STRING;
1902             v->boolval = EXTRUE; 
1903             {
1904                 struct ast_string *s = (struct ast_string *)a;
1905                 /* Make pointer to point to the AST str value. */
1906                 /* strcpy(v->strval, s->str); */
1907                 v->strval = s->str;
1908             }
1909             /* dump the final value */
1910             DUMP_VALUE_BLOCK("NODE_TYPE_STR", v);
1911             break;
1912         case NODE_TYPE_FLOAT:
1913             v->value_type = VALUE_TYPE_FLOAT;
1914             /* Copy off the string value */
1915             {
1916                 struct ast_float * a_f = (struct ast_float*)a;
1917                 v->floatval = a_f->d;
1918                 /* Set the boolean value of this stuff */
1919                 if (!IS_FLOAT_0(v->floatval))
1920                     v->boolval = EXTRUE;
1921                 else
1922                     v->boolval = EXFALSE;
1923             }
1924             /* dump the final value */
1925              DUMP_VALUE_BLOCK("VALUE_TYPE_FLOAT", v);
1926             break;
1927         case NODE_TYPE_LONG:
1928             v->value_type = VALUE_TYPE_LONG;
1929             /* Copy off the string value */
1930             {
1931                 struct ast_long * a_long = (struct ast_long*)a;
1932                 v->longval = a_long->l;
1933                 /* Set the boolean value of this stuff */
1934                 if (v->longval)
1935                     v->boolval = EXTRUE;
1936                 else
1937                     v->boolval = EXFALSE;
1938             }
1939             /* dump the final value */
1940             DUMP_VALUE_BLOCK("VALUE_TYPE_LONG", v);
1941             break;
1942     }
1943     /* Free up resources that may be allocated! */
1944     FREE_UP_UB_BUF((&l));
1945     FREE_UP_UB_BUF((&r));
1946     return ret;
1947 }
1948 /* ===========================================================================*/
1949 /* =========================API FUNCTIONS=====================================*/
1950 /* ===========================================================================*/
1951 
1952 expublic char * ndrx_Bboolco (char * expr)
1953 {
1954 
1955     char *ret=NULL;
1956     char *fn = "Bboolco";
1957     extern  int yycolumn;
1958     char *expr_int;
1959     int buf_len = strlen(expr)+2;
1960     UBF_LOG(log_debug, "%s: Compiling expression [%s]", fn, expr);
1961 
1962     /* We have some trouble with flex! For marking the end of the line
1963      * So we will put there newline... not the best practice, but it will work. */
1964     expr_int = NDRX_MALLOC(buf_len);
1965 
1966     if (NULL==expr_int)
1967     {
1968         ndrx_Bset_error_fmt(BMALLOC, "cannot allocate %d bytes for expression copy",
1969                                     buf_len);
1970     }
1971     else
1972     {
1973         /* All OK */
1974         NDRX_STRCPY_SAFE_DST(expr_int, expr, buf_len);
1975         strcat(expr_int, "\n");
1976 
1977         yy_scan_string(expr_int);
1978         G_p_root_node = NULL;
1979         G_node_count = 0;
1980         G_error = 0;
1981         yycolumn = 1;
1982 
1983         M_first_mem=NULL;
1984         M_cur_mem=NULL;
1985 
1986         if (EXSUCCEED==yyparse() && NULL!=G_p_root_node && EXFAIL!=G_error)
1987         {
1988             ret=(char *)G_p_root_node;
1989             remove_resouce_list();
1990         }
1991         else
1992         {
1993             remove_resouces();
1994         }
1995 
1996     /* wrapper call to yylex_destroy */
1997         _free_parser();
1998 
1999         NDRX_FREE(expr_int);
2000     }
2001     UBF_LOG(log_debug, "%s: return %p", fn, ret);
2002     return ret;
2003 }
2004 
2005 expublic int ndrx_Bboolev (UBFH * p_ub, char *tree)
2006 {
2007     int ret=EXSUCCEED;
2008     value_block_t v;
2009     struct ast *a = (struct ast *)tree;
2010     memset(&v, 0, sizeof(v));
2011 
2012     if (NULL==tree)
2013     {
2014         ndrx_Bset_error_msg(BEINVAL, "NULL tree passed for eval!");
2015         return EXFAIL; /* <<< RETURN */
2016     }
2017     /*
2018      * Evaluate the parse tree
2019      */
2020     if (EXSUCCEED==eval(p_ub, a, &v))
2021     {
2022         if (v.boolval)
2023         {
2024             ret=EXTRUE;
2025         }
2026         else
2027         {
2028             ret=EXFALSE;
2029         }
2030     }
2031     else
2032     {
2033         ret=EXFAIL;
2034     }
2035 
2036     FREE_UP_UB_BUF((&v));
2037 
2038     return ret;
2039 }
2040 
2041 /**
2042  * This function is not tested very hardly but it shows up that it should work fine
2043  * @param p_ub
2044  * @param tree
2045  * @return
2046  */
2047 expublic double ndrx_Bfloatev (UBFH * p_ub, char *tree)
2048 {
2049     double ret=0.0;
2050     value_block_t v;
2051     struct ast *a = (struct ast *)tree;
2052     memset(&v, 0, sizeof(v));
2053 
2054     if (NULL==tree)
2055     {
2056         ndrx_Bset_error_msg(BEINVAL, "NULL tree passed for eval!");
2057         return EXFAIL; /* <<< RETURN */
2058     }
2059     /*
2060      * Evaluate the parse tree
2061      */
2062     if (EXSUCCEED==eval(p_ub, a, &v))
2063     {
2064         if (VALUE_TYPE_FLOAT!=v.value_type)
2065             get_float(&v);
2066         ret=v.floatval;
2067     }
2068     else
2069     {
2070         ret=EXFAIL;
2071     }
2072 
2073     FREE_UP_UB_BUF((&v));
2074 
2075     return ret;
2076 }
2077 /**
2078  * Free up used tree.
2079  * This recursively frees up resources. Should be called once compiled tree
2080  * is not needed.
2081  * @param tree
2082  */
2083 expublic void ndrx_Btreefree (char *tree)
2084 {
2085     struct ast *a = (struct ast *)tree;
2086     struct ast_string *a_string = (struct ast_string *)tree;
2087     struct ast_fld *a_fld;
2088     struct ast_func *a_func;    
2089 
2090     if (NULL==tree)
2091         return; /* <<<< RETURN! Nothing to do! */
2092 
2093     UBF_LOG(6, "Free up buffer %p nodeid=%d nodetype=%d", tree, a->nodeid, a->nodetype);
2094     switch (a->nodetype)
2095     {
2096         case NODE_TYPE_FLD:
2097             a_fld = (struct ast_fld *)tree;
2098             ndrx_ubf_rfldid_free(&(a_fld->fld));
2099             break;
2100         case NODE_TYPE_STR:
2101             /* Free up internal resources (if have such)? */
2102             if (NULL!=a_string->str)
2103             {
2104                 NDRX_FREE(a_string->str);
2105                 a_string->str_bufsz=0;
2106             }
2107 
2108             /* check regexp, maybe needs to clean up? */
2109             if (a_string->regex.compiled)
2110                 regfree(&(a_string->regex.re));
2111             break;
2112         case NODE_TYPE_FLOAT:
2113             /* nothing to do */
2114             break;
2115         case NODE_TYPE_FUNC:
2116             a_func = (struct ast_func *)tree;
2117             if (NULL!=a_func->funcall)
2118             {
2119                 NDRX_FPFREE(a_func->funcall);
2120             }
2121             break;
2122         case NODE_TYPE_LONG:
2123             /* nothing to do */
2124             break;
2125         default:
2126             if (a->l)
2127             {
2128                 ndrx_Btreefree ((char *)a->l);
2129             }
2130             if (a->r)
2131             {
2132                 ndrx_Btreefree ((char *)a->r);
2133             }
2134             break;
2135     }
2136     /* delete self */
2137     NDRX_FREE(tree);
2138 
2139 }
2140 
2141 /**
2142  * Print expression tree to file
2143  * @param tree - evaluation tree
2144  * @param outf - file to print to 
2145  * @param[in] p_writef callback to data writer function. Either outf must be
2146  *  present or this parameter
2147  * @param[in] dataptr1 optional data parameter forwarded to p_wirtef if invoked.
2148  */
2149 expublic void ndrx_Bboolpr (char * tree, FILE *outf, 
2150         int (*p_writef)(char *buffer, long datalen, void *dataptr1), void *dataptr1)
2151 {
2152     struct ast *a = (struct ast *)tree;
2153     struct ast_string *a_string = (struct ast_string *)tree;
2154     char *tmp;
2155     long tmp_len;
2156 
2157     if (NULL==tree)
2158         return; /* <<<< RETURN! Nothing to do! */
2159 
2160     if (NULL!=outf && ferror(outf))
2161     {
2162         return;
2163     }
2164     
2165 #define NDRX_BBOOLPR_FMT(...) \
2166     if (NULL!=p_writef)\
2167     {\
2168         NDRX_ASPRINTF(&tmp, &tmp_len, ##__VA_ARGS__);\
2169         if (NULL==tmp)\
2170         {\
2171             int err = errno;\
2172             UBF_LOG(log_error, "Failed to asprintf: %s", strerror(err));\
2173             userlog("Failed to asprintf: %s", strerror(err));\
2174         }\
2175         tmp_len++;\
2176         if (EXSUCCEED!=p_writef(tmp, tmp_len, dataptr1))\
2177         {\
2178             return;\
2179         }\
2180     }\
2181     else\
2182     {\
2183         fprintf(outf, ##__VA_ARGS__);\
2184     }
2185 
2186     switch (a->nodetype)
2187     {
2188         case NODE_TYPE_FUNC:
2189             {
2190                 /* print func */
2191                 struct ast_func *a_func = (struct ast_func *)tree;
2192                 
2193                 NDRX_BBOOLPR_FMT("%s(%s)", a_func->funcall->funcname, a_func->funcall->arg1);
2194                 
2195             }
2196             break;
2197         case NODE_TYPE_FLD:
2198             {
2199                 /* print field */
2200                 struct ast_fld *a_fld = (struct ast_fld *)tree;
2201                 NDRX_BBOOLPR_FMT("%s", a_fld->fld.fldnm);
2202             }
2203             break;
2204         case NODE_TYPE_STR:
2205             
2206             /* print string value */
2207             if (NULL!=a_string->str)
2208             {
2209                 NDRX_BBOOLPR_FMT("'%s'", a_string->str);
2210             }
2211             else
2212             {
2213                 NDRX_BBOOLPR_FMT("<null>");
2214             }
2215             
2216             break;
2217         case NODE_TYPE_FLOAT:
2218             {
2219                 /* Print float value */
2220                 struct ast_float *a_float = (struct ast_float *)tree;
2221                 /* print field */
2222                 NDRX_BBOOLPR_FMT("%.*lf", DOUBLE_RESOLUTION, a_float->d);
2223             }
2224             break;
2225         case NODE_TYPE_LONG:
2226             {
2227                 /* Print long value */
2228                 struct ast_long *a_long = (struct ast_long *)tree;
2229                 NDRX_BBOOLPR_FMT("%ld", a_long->l);
2230             }
2231             break;
2232         default:
2233             NDRX_BBOOLPR_FMT("(");
2234             if (a->l)
2235             {
2236                 ndrx_Bboolpr ((char *)a->l, outf, p_writef, dataptr1);
2237             }
2238             NDRX_BBOOLPR_FMT("%s", M_subtypes_sign_only[a->sub_type]);
2239             if (a->r)
2240             {
2241                 ndrx_Bboolpr ((char *)a->r, outf, p_writef, dataptr1);
2242             }
2243             NDRX_BBOOLPR_FMT(")");
2244             break;
2245     }
2246 }
2247 
2248 /**
2249  * Set callback function
2250  * With additional argument
2251  * @param funcptr pointer to callback, either functionPtr_t or functionPtr2_t
2252  * @param functype NDRX_CBFUNTYPE_NOARGS or NDRX_CBFUNTYPE_ARG1
2253  * @return EXSUCCEED/EXFAIL
2254  */
2255 expublic int ndrx_Bboolsetcbf2 (char *funcname, void *funcptr, int functype)
2256 {
2257 
2258     int ret=EXSUCCEED;
2259     char *fn = "_Bsetcbfunc";
2260     int len;
2261     
2262     UBF_LOG(log_debug, "%s: setting callback function [%s]:%p", fn, 
2263             funcname, funcptr);
2264 
2265     if (NULL==funcname || (len=strlen(funcname)) < 1 || len > MAX_FUNC_NAME-1)
2266     {
2267         ndrx_Bset_error_fmt(BBADNAME, "Bad function name passed [%s]", funcname);
2268         ret=EXFAIL;
2269         goto out;
2270     }
2271     
2272     ret = set_func(funcname, funcptr, functype);
2273     
2274 out:
2275     UBF_LOG(log_debug, "%s: return %p", fn, ret);
2276     return ret;
2277 }
2278 
2279 /* vim: set ts=4 sw=4 et smartindent: */