X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_rpncalc.c;h=f8759f8d67a84c91f3816b770d0f5efd3c068f84;hb=2e6c98e893777e4abf7b05cb4ecf81dde088cdb8;hp=b1f8da6578d01889ef6cf4fc131272588032b573;hpb=0a64cbeafc2ba2f222040d045c68c34a12af20be;p=rrdtool.git diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c index b1f8da6..f8759f8 100644 --- a/src/rrd_rpncalc.c +++ b/src/rrd_rpncalc.c @@ -1,11 +1,12 @@ /**************************************************************************** - * RRDtool 1.0.28 Copyright Tobias Oetiker, 1997 - 2000 + * RRDtool 1.2.19 Copyright by Tobi Oetiker, 1997-2007 **************************************************************************** * rrd_rpncalc.c RPN calculator functions ****************************************************************************/ #include "rrd_tool.h" #include "rrd_rpncalc.h" +#include "rrd_graph.h" #include short addop2str(enum op_en op, enum op_en op_type, char *op_str, @@ -40,7 +41,8 @@ short rpn_compact(rpnp_t *rpnp, rpn_cdefds_t **rpnc, short *count) return -1; } (*rpnc)[i].val = (short) temp; - } else if (rpnp[i].op == OP_VARIABLE) { + } else if (rpnp[i].op == OP_VARIABLE || + rpnp[i].op == OP_PREV_OTHER) { (*rpnc)[i].val = (short) rpnp[i].ptr; } } @@ -63,7 +65,8 @@ rpnp_t * rpn_expand(rpn_cdefds_t *rpnc) rpnp[i].op = (long) rpnc[i].op; if (rpnp[i].op == OP_NUMBER) { rpnp[i].val = (double) rpnc[i].val; - } else if (rpnp[i].op == OP_VARIABLE) { + } else if (rpnp[i].op == OP_VARIABLE || + rpnp[i].op == OP_PREV_OTHER) { rpnp[i].ptr = (long) rpnc[i].val; } } @@ -76,8 +79,8 @@ rpnp_t * rpn_expand(rpn_cdefds_t *rpnc) * into a CDEF string. This function is used by rrd_dump. * arguments: * rpnc: an array of compact RPN operator nodes - * rrd: a pointer an rrd header (only the ds_cnt and ds_def elements need - * to be valid) for lookup of data source names by index + * ds_def: a pointer to the data source definition section of an RRD header + * for lookup of data source names by index * str: out string, memory is allocated by the function, must be freed by the * the caller */ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str) @@ -94,7 +97,7 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str) if (rpnc[i].op == OP_NUMBER) { /* convert a short into a string */ -#ifdef WIN32 +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) _itoa(rpnc[i].val,buffer,10); #else sprintf(buffer,"%d",rpnc[i].val); @@ -106,6 +109,12 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str) char *ds_name = ds_def[rpnc[i].val].ds_nam; add_op(OP_VARIABLE, ds_name) } + + if (rpnc[i].op == OP_PREV_OTHER) { + char *ds_name = ds_def[rpnc[i].val].ds_nam; + add_op(OP_VARIABLE, ds_name) + } + #undef add_op #define add_op(VV,VVV) \ @@ -137,12 +146,22 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str) add_op(OP_UNKN,UNKN) add_op(OP_UN,UN) add_op(OP_NEGINF,NEGINF) + add_op(OP_NE,NE) add_op(OP_PREV,PREV) add_op(OP_INF,INF) + add_op(OP_ISINF,ISINF) add_op(OP_NOW,NOW) add_op(OP_LTIME,LTIME) add_op(OP_TIME,TIME) - + add_op(OP_ATAN2,ATAN2) + add_op(OP_ATAN,ATAN) + add_op(OP_SQRT,SQRT) + add_op(OP_SORT,SORT) + add_op(OP_REV,REV) + add_op(OP_TREND,TREND) + add_op(OP_RAD2DEG,RAD2DEG) + add_op(OP_DEG2RAD,DEG2RAD) + add_op(OP_AVG,AVG) #undef add_op } (*str)[offset] = '\0'; @@ -176,7 +195,7 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx) rpnp = rpn_parse((void*) rrd, def, &lookup_DS); if (rpnp == NULL) { - rrd_set_error("failed to parse computed data source %s", def); + rrd_set_error("failed to parse computed data source"); return; } /* Check for OP nodes not permitted in COMPUTE DS. @@ -185,10 +204,10 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx) * occur too often. */ for (i = 0; rpnp[i].op != OP_END; i++) { if (rpnp[i].op == OP_TIME || rpnp[i].op == OP_LTIME || - rpnp[i].op == OP_PREV) + rpnp[i].op == OP_PREV || rpnp[i].op == OP_COUNT) { rrd_set_error( - "operators time, ltime and prev not supported with DS COMPUTE"); + "operators time, ltime, prev and count not supported with DS COMPUTE"); free(rpnp); return; } @@ -211,7 +230,7 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx) */ long lookup_DS(void *rrd_vptr,char *ds_name) { - int i; + unsigned int i; rrd_t *rrd; rrd = (rrd_t *) rrd_vptr; @@ -234,13 +253,15 @@ long lookup_DS(void *rrd_vptr,char *ds_name) * lookup(): a function that retrieves a numeric key given a variable name */ rpnp_t * -rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){ +rpn_parse(void *key_hash,const char *const expr_const,long (*lookup)(void *,char*)){ int pos=0; + char *expr; long steps=-1; rpnp_t *rpnp; - char vname[30]; + char vname[MAX_VNAME_LEN+10]; rpnp=NULL; + expr=(char *)expr_const; while(*expr){ if ((rpnp = (rpnp_t *) rrd_realloc(rpnp, (++steps + 2)* @@ -254,11 +275,26 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){ } #define match_op(VV,VVV) \ - else if (strncmp(expr, #VVV, strlen(#VVV))==0){ \ - rpnp[steps].op = VV; \ - expr+=strlen(#VVV); \ + else if (strncmp(expr, #VVV, strlen(#VVV))==0 && ( expr[strlen(#VVV)] == ',' || expr[strlen(#VVV)] == '\0' )){ \ + rpnp[steps].op = VV; \ + expr+=strlen(#VVV); \ } + +#define match_op_param(VV,VVV) \ + else if (sscanf(expr, #VVV "(" DEF_NAM_FMT ")",vname) == 1) { \ + int length = 0; \ + if ((length = strlen(#VVV)+strlen(vname)+2, \ + expr[length] == ',' || expr[length] == '\0') ) { \ + rpnp[steps].op = VV; \ + rpnp[steps].ptr = (*lookup)(key_hash,vname); \ + if (rpnp[steps].ptr < 0) { \ + free(rpnp); \ + return NULL; \ + } else expr+=length; \ + } \ + } + match_op(OP_ADD,+) match_op(OP_SUB,-) match_op(OP_MUL,*) @@ -273,6 +309,7 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){ match_op(OP_DUP,DUP) match_op(OP_EXC,EXC) match_op(OP_POP,POP) + match_op(OP_LTIME,LTIME) match_op(OP_LT,LT) match_op(OP_LE,LE) match_op(OP_GT,GT) @@ -286,16 +323,27 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){ match_op(OP_UNKN,UNKN) match_op(OP_UN,UN) match_op(OP_NEGINF,NEGINF) + match_op(OP_NE,NE) + match_op(OP_COUNT,COUNT) + match_op_param(OP_PREV_OTHER,PREV) match_op(OP_PREV,PREV) match_op(OP_INF,INF) + match_op(OP_ISINF,ISINF) match_op(OP_NOW,NOW) - match_op(OP_LTIME,LTIME) match_op(OP_TIME,TIME) - + match_op(OP_ATAN2,ATAN2) + match_op(OP_ATAN,ATAN) + match_op(OP_SQRT,SQRT) + match_op(OP_SORT,SORT) + match_op(OP_REV,REV) + match_op(OP_TREND,TREND) + match_op(OP_RAD2DEG,RAD2DEG) + match_op(OP_DEG2RAD,DEG2RAD) + match_op(OP_AVG,AVG) #undef match_op - else if ((sscanf(expr,"%29[_A-Za-z0-9]%n", + else if ((sscanf(expr, DEF_NAM_FMT "%n", vname,&pos) == 1) && ((rpnp[steps].ptr = (*lookup)(key_hash,vname)) != -1)){ rpnp[steps].op = OP_VARIABLE; @@ -335,6 +383,14 @@ rpnstack_free(rpnstack_t *rpnstack) rpnstack -> dc_stacksize = 0; } +static int +rpn_compare_double(const void *x, const void *y) +{ + double diff = *((const double *)x) - *((const double *)y); + + return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; +} + /* rpn_calc: run the RPN calculator; also performs variable substitution; * moved and modified from data_calc() originally included in rrd_graph.c * arguments: @@ -370,12 +426,20 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx, return -1; } } + +#define stackunderflow(MINSIZE) \ + if(stptr s[++stptr] = rpnp[rpi].val; break; case OP_VARIABLE: - /* Sanity check: VDEFs shouldn't make it here */ + case OP_PREV_OTHER: + /* Sanity check: VDEFs shouldn't make it here */ if (rpnp[rpi].ds_cnt == 0) { rrd_set_error("VDEF made it into rpn_calc... aborting"); return -1; @@ -386,276 +450,339 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx, * row in the rra (skip over non-relevant * data sources) */ + if (rpnp[rpi].op == OP_VARIABLE) { + rpnstack -> s[++stptr] = *(rpnp[rpi].data); + } else { + if ((output_idx) <= 0) { + rpnstack -> s[++stptr] = DNAN; + } else { + rpnstack -> s[++stptr] = *(rpnp[rpi].data-rpnp[rpi].ds_cnt); + } + + } if (data_idx % rpnp[rpi].step == 0){ rpnp[rpi].data += rpnp[rpi].ds_cnt; } - rpnstack -> s[++stptr] = *(rpnp[rpi].data); } break; + case OP_COUNT: + rpnstack -> s[++stptr] = (output_idx+1); /* Note: Counter starts at 1 */ + break; case OP_PREV: - if ((output_idx-1) <= 0) { + if ((output_idx) <= 0) { rpnstack -> s[++stptr] = DNAN; } else { rpnstack -> s[++stptr] = output[output_idx-1]; } + break; + case OP_UNKN: + rpnstack -> s[++stptr] = DNAN; break; - case OP_UNKN: - rpnstack -> s[++stptr] = DNAN; - break; - case OP_INF: - rpnstack -> s[++stptr] = DINF; - break; - case OP_NEGINF: - rpnstack -> s[++stptr] = -DINF; - break; - case OP_NOW: - rpnstack -> s[++stptr] = (double)time(NULL); - break; - case OP_TIME: - /* HACK: this relies on the data_idx being the time, - * which the within-function scope is unaware of */ - rpnstack -> s[++stptr] = (double) data_idx; - break; - case OP_LTIME: - rpnstack -> s[++stptr] = (double) tzoffset(data_idx) + (double)data_idx; - break; - case OP_ADD: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] - + rpnstack -> s[stptr]; - stptr--; - break; - case OP_SUB: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] - rpnstack -> s[stptr]; - stptr--; - break; - case OP_MUL: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr-1] = (rpnstack -> s[stptr-1]) * (rpnstack -> s[stptr]); - stptr--; - break; - case OP_DIV: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] / rpnstack -> s[stptr]; - stptr--; - break; - case OP_MOD: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr-1] = fmod(rpnstack -> s[stptr-1],rpnstack -> s[stptr]); - stptr--; - break; - case OP_SIN: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = sin(rpnstack -> s[stptr]); - break; - case OP_COS: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = cos(rpnstack -> s[stptr]); - break; - case OP_CEIL: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = ceil(rpnstack -> s[stptr]); - break; - case OP_FLOOR: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = floor(rpnstack -> s[stptr]); - break; - case OP_LOG: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = log(rpnstack -> s[stptr]); - break; - case OP_DUP: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr+1] = rpnstack -> s[stptr]; - stptr++; - break; - case OP_POP: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - stptr--; - break; - case OP_EXC: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } else { - double dummy; - dummy = rpnstack -> s[stptr] ; - rpnstack -> s[stptr] = rpnstack -> s[stptr-1]; - rpnstack -> s[stptr-1] = dummy; - } - break; - case OP_EXP: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack -> s[stptr] = exp(rpnstack -> s[stptr]); - break; - case OP_LT: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack -> s[stptr-1])) - ; - else if (isnan(rpnstack -> s[stptr])) - rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; - else - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] < rpnstack -> s[stptr] ? 1.0 : 0.0; - stptr--; - break; - case OP_LE: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack -> s[stptr-1])) - ; - else if (isnan(rpnstack -> s[stptr])) - rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; - else - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] <= rpnstack -> s[stptr] ? 1.0 : 0.0; - stptr--; - break; - case OP_GT: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack -> s[stptr-1])) - ; - else if (isnan(rpnstack -> s[stptr])) - rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; - else - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] > rpnstack -> s[stptr] ? 1.0 : 0.0; - stptr--; - break; - case OP_GE: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack -> s[stptr-1])) - ; - else if (isnan(rpnstack -> s[stptr])) - rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; - else - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] >= rpnstack -> s[stptr] ? 1.0 : 0.0; - stptr--; - break; - case OP_EQ: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack -> s[stptr-1])) - ; - else if (isnan(rpnstack -> s[stptr])) - rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; - else - rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] == rpnstack -> s[stptr] ? 1.0 : 0.0; - stptr--; - break; - case OP_IF: - if(stptr<2){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack->s[stptr-2] = rpnstack->s[stptr-2] != 0.0 ? rpnstack->s[stptr-1] : rpnstack->s[stptr]; - stptr--; - stptr--; - break; - case OP_MIN: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack->s[stptr-1])) - ; - else if (isnan(rpnstack->s[stptr])) - rpnstack->s[stptr-1] = rpnstack->s[stptr]; - else if (rpnstack->s[stptr-1] > rpnstack->s[stptr]) - rpnstack->s[stptr-1] = rpnstack->s[stptr]; - stptr--; - break; - case OP_MAX: - if(stptr<1){ - rrd_set_error("RPN stack underflow"); - return -1; - } - if (isnan(rpnstack->s[stptr-1])) - ; - else if (isnan(rpnstack->s[stptr])) - rpnstack->s[stptr-1] = rpnstack->s[stptr]; - else if (rpnstack->s[stptr-1] < rpnstack->s[stptr]) - rpnstack->s[stptr-1] = rpnstack->s[stptr]; - stptr--; - break; - case OP_LIMIT: - if(stptr<2){ - rrd_set_error("RPN stack underflow"); - free(rpnstack->s); - return -1; - } - if (isnan(rpnstack->s[stptr-2])) + case OP_INF: + rpnstack -> s[++stptr] = DINF; + break; + case OP_NEGINF: + rpnstack -> s[++stptr] = -DINF; + break; + case OP_NOW: + rpnstack -> s[++stptr] = (double)time(NULL); + break; + case OP_TIME: + /* HACK: this relies on the data_idx being the time, + ** which the within-function scope is unaware of */ + rpnstack -> s[++stptr] = (double) data_idx; + break; + case OP_LTIME: + rpnstack -> s[++stptr] = + (double) tzoffset(data_idx) + (double)data_idx; + break; + case OP_ADD: + stackunderflow(1); + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] + + rpnstack -> s[stptr]; + stptr--; + break; + case OP_SUB: + stackunderflow(1); + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] + - rpnstack -> s[stptr]; + stptr--; + break; + case OP_MUL: + stackunderflow(1); + rpnstack -> s[stptr-1] = (rpnstack -> s[stptr-1]) + * (rpnstack -> s[stptr]); + stptr--; + break; + case OP_DIV: + stackunderflow(1); + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] + / rpnstack -> s[stptr]; + stptr--; + break; + case OP_MOD: + stackunderflow(1); + rpnstack -> s[stptr-1]= fmod( rpnstack -> s[stptr-1] + ,rpnstack -> s[stptr]); + stptr--; + break; + case OP_SIN: + stackunderflow(0); + rpnstack -> s[stptr] = sin(rpnstack -> s[stptr]); + break; + case OP_ATAN: + stackunderflow(0); + rpnstack -> s[stptr] = atan(rpnstack -> s[stptr]); + break; + case OP_RAD2DEG: + stackunderflow(0); + rpnstack -> s[stptr] = 57.29577951 * rpnstack -> s[stptr]; + break; + case OP_DEG2RAD: + stackunderflow(0); + rpnstack -> s[stptr] = 0.0174532952 * rpnstack -> s[stptr]; + break; + case OP_ATAN2: + stackunderflow(1); + rpnstack -> s[stptr-1]= atan2( + rpnstack -> s[stptr-1], + rpnstack -> s[stptr]); + stptr--; + break; + case OP_COS: + stackunderflow(0); + rpnstack -> s[stptr] = cos(rpnstack -> s[stptr]); + break; + case OP_CEIL: + stackunderflow(0); + rpnstack -> s[stptr] = ceil(rpnstack -> s[stptr]); + break; + case OP_FLOOR: + stackunderflow(0); + rpnstack -> s[stptr] = floor(rpnstack -> s[stptr]); + break; + case OP_LOG: + stackunderflow(0); + rpnstack -> s[stptr] = log(rpnstack -> s[stptr]); + break; + case OP_DUP: + stackunderflow(0); + rpnstack -> s[stptr+1] = rpnstack -> s[stptr]; + stptr++; + break; + case OP_POP: + stackunderflow(0); + stptr--; + break; + case OP_EXC: + stackunderflow(1); + { + double dummy; + dummy = rpnstack -> s[stptr] ; + rpnstack -> s[stptr] = rpnstack -> s[stptr-1]; + rpnstack -> s[stptr-1] = dummy; + } + break; + case OP_EXP: + stackunderflow(0); + rpnstack -> s[stptr] = exp(rpnstack -> s[stptr]); + break; + case OP_LT: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] < + rpnstack -> s[stptr] ? 1.0 : 0.0; + stptr--; + break; + case OP_LE: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] <= + rpnstack -> s[stptr] ? 1.0 : 0.0; + stptr--; + break; + case OP_GT: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] > + rpnstack -> s[stptr] ? 1.0 : 0.0; + stptr--; + break; + case OP_GE: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] >= + rpnstack -> s[stptr] ? 1.0 : 0.0; + stptr--; + break; + case OP_NE: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] == + rpnstack -> s[stptr] ? 0.0 : 1.0; + stptr--; + break; + case OP_EQ: + stackunderflow(1); + if (isnan(rpnstack -> s[stptr-1])) + ; + else if (isnan(rpnstack -> s[stptr])) + rpnstack -> s[stptr-1] = rpnstack -> s[stptr]; + else + rpnstack -> s[stptr-1] = rpnstack -> s[stptr-1] == + rpnstack -> s[stptr] ? 1.0 : 0.0; + stptr--; + break; + case OP_IF: + stackunderflow(2); + rpnstack->s[stptr-2] = rpnstack->s[stptr-2] != 0.0 ? + rpnstack->s[stptr-1] : rpnstack->s[stptr]; + stptr--; + stptr--; + break; + case OP_MIN: + stackunderflow(1); + if (isnan(rpnstack->s[stptr-1])) + ; + else if (isnan(rpnstack->s[stptr])) + rpnstack->s[stptr-1] = rpnstack->s[stptr]; + else if (rpnstack->s[stptr-1] > rpnstack->s[stptr]) + rpnstack->s[stptr-1] = rpnstack->s[stptr]; + stptr--; + break; + case OP_MAX: + stackunderflow(1); + if (isnan(rpnstack->s[stptr-1])) ; - else if (isnan(rpnstack->s[stptr-1])) - rpnstack->s[stptr-2] = rpnstack->s[stptr-1]; - else if (isnan(rpnstack->s[stptr])) - rpnstack->s[stptr-2] = rpnstack->s[stptr]; - else if (rpnstack->s[stptr-2] < rpnstack->s[stptr-1]) - rpnstack->s[stptr-2] = DNAN; - else if (rpnstack->s[stptr-2] > rpnstack->s[stptr]) - rpnstack->s[stptr-2] = DNAN; - stptr-=2; - break; - case OP_UN: - if(stptr<0){ - rrd_set_error("RPN stack underflow"); - return -1; - } - rpnstack->s[stptr] = isnan(rpnstack->s[stptr]) ? 1.0 : 0.0; - break; - case OP_END: - break; + else if (isnan(rpnstack->s[stptr])) + rpnstack->s[stptr-1] = rpnstack->s[stptr]; + else if (rpnstack->s[stptr-1] < rpnstack->s[stptr]) + rpnstack->s[stptr-1] = rpnstack->s[stptr]; + stptr--; + break; + case OP_LIMIT: + stackunderflow(2); + if (isnan(rpnstack->s[stptr-2])) + ; + else if (isnan(rpnstack->s[stptr-1])) + rpnstack->s[stptr-2] = rpnstack->s[stptr-1]; + else if (isnan(rpnstack->s[stptr])) + rpnstack->s[stptr-2] = rpnstack->s[stptr]; + else if (rpnstack->s[stptr-2] < rpnstack->s[stptr-1]) + rpnstack->s[stptr-2] = DNAN; + else if (rpnstack->s[stptr-2] > rpnstack->s[stptr]) + rpnstack->s[stptr-2] = DNAN; + stptr-=2; + break; + case OP_UN: + stackunderflow(0); + rpnstack->s[stptr] = isnan(rpnstack->s[stptr]) ? 1.0 : 0.0; + break; + case OP_ISINF: + stackunderflow(0); + rpnstack->s[stptr] = isinf(rpnstack->s[stptr]) ? 1.0 : 0.0; + break; + case OP_SQRT: + stackunderflow(0); + rpnstack -> s[stptr] = sqrt(rpnstack -> s[stptr]); + break; + case OP_SORT: + stackunderflow(0); + { + int spn = (int)rpnstack -> s[stptr--]; + + stackunderflow(spn-1); + qsort(rpnstack -> s + stptr-spn+1, spn, sizeof(double), + rpn_compare_double); + } + break; + case OP_REV: + stackunderflow(0); + { + int spn = (int)rpnstack -> s[stptr--]; + double *p, *q; + + stackunderflow(spn-1); + + p = rpnstack -> s + stptr-spn+1; + q = rpnstack -> s + stptr; + while (p < q) { + double x = *q; + + *q-- = *p; + *p++ = x; + } + } + break; + case OP_TREND: + stackunderflow(1); + if ((rpi < 2) || (rpnp[rpi-2].op != OP_VARIABLE)) { + rrd_set_error("malformed trend arguments"); + return -1; + } else { + time_t dur = (time_t)rpnstack -> s[stptr]; + time_t step = (time_t)rpnp[rpi-2].step; + + if (output_idx > (int)ceil((float)dur / (float)step)) { + double accum = 0.0; + int i = 0; + + do { + accum += rpnp[rpi-2].data[rpnp[rpi-2].ds_cnt * i--]; + dur -= step; + } while (dur > 0); + + rpnstack -> s[--stptr] = (accum / -i); + } else + rpnstack -> s[--stptr] = DNAN; + } + break; + case OP_AVG: + stackunderflow(0); + { + int i=(int)rpnstack -> s[stptr--]; + double sum=0; + int count=0; + stackunderflow(i-1); + while(i>0) { + double val=rpnstack -> s[stptr--]; + i--; + if (isnan(val)) { continue; } + count++; + sum+=val; + } + // now push the result bavk on stack + if (count>0) { + rpnstack -> s[++stptr]=sum/count; + } else { + rpnstack -> s[++stptr]=DNAN; + } + } + break; + case OP_END: + break; } +#undef stackunderflow } if(stptr!=0){ rrd_set_error("RPN final stack size != 1"); @@ -672,20 +799,20 @@ int tzoffset( time_t now ){ int gm_sec, gm_min, gm_hour, gm_yday, gm_year, l_sec, l_min, l_hour, l_yday, l_year; - struct tm *t; + struct tm t; int off; - t = gmtime(&now); - gm_sec = t->tm_sec; - gm_min = t->tm_min; - gm_hour = t->tm_hour; - gm_yday = t->tm_yday; - gm_year = t->tm_year; - t = localtime(&now); - l_sec = t->tm_sec; - l_min = t->tm_min; - l_hour = t->tm_hour; - l_yday = t->tm_yday; - l_year = t->tm_year; + gmtime_r(&now, &t); + gm_sec = t.tm_sec; + gm_min = t.tm_min; + gm_hour = t.tm_hour; + gm_yday = t.tm_yday; + gm_year = t.tm_year; + localtime_r(&now, &t); + l_sec = t.tm_sec; + l_min = t.tm_min; + l_hour = t.tm_hour; + l_yday = t.tm_yday; + l_year = t.tm_year; off = (l_sec-gm_sec)+(l_min-gm_min)*60+(l_hour-gm_hour)*3600; if ( l_yday > gm_yday || l_year > gm_year){ off += 24*3600;