diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c
index 41d1ce3e4778690be5cddb57a7c32bbbf9f32aa4..eb7c94b2e5be67d8dd74afd2e7d060ee01bbc824 100644 (file)
--- a/src/rrd_rpncalc.c
+++ b/src/rrd_rpncalc.c
/****************************************************************************
- * RRDtool 1.0.28 Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2.23 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 <limits.h>
short addop2str(enum op_en op, enum op_en op_type, char *op_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);
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)
+ add_op(OP_ABS,ABS)
#undef add_op
}
(*str)[offset] = '\0';
return 0;
}
-void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx)
+void parseCDEF_DS(const char *def,rrd_t *rrd, int ds_idx)
{
rpnp_t *rpnp = NULL;
rpn_cdefds_t *rpnc = NULL;
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.
* 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;
}
*/
long lookup_DS(void *rrd_vptr,char *ds_name)
{
- int i;
+ unsigned int i;
rrd_t *rrd;
rrd = (rrd_t *) rrd_vptr;
* 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)*
}
#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); \
}
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)
match_op(OP_UN,UN)
match_op(OP_NEGINF,NEGINF)
match_op(OP_NE,NE)
- match_op_param(OP_PREV_OTHER,PREV)
+ 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)
+ match_op(OP_ABS,ABS)
#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;
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:
rpnstack -> 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;
* row in the rra (skip over non-relevant
* data sources)
*/
- rpnstack -> s[++stptr] = *(rpnp[rpi].data);
+ 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;
}
}
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_PREV_OTHER:
- if ((output_idx-1) <= 0) {
- rpnstack -> s[++stptr] = DNAN;
- } else {
- rpnstack -> s[++stptr] = rpnp[rpnp[rpi].ptr].data[output_idx-1];
- }
- break;
- case OP_UNKN:
+ break;
+ case OP_UNKN:
rpnstack -> s[++stptr] = DNAN;
break;
case OP_INF:
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]);
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 back on stack */
+ if (count>0) {
+ rpnstack -> s[++stptr]=sum/count;
+ } else {
+ rpnstack -> s[++stptr]=DNAN;
+ }
+ }
+ break;
+ case OP_ABS:
+ stackunderflow(0);
+ rpnstack -> s[stptr] = fabs(rpnstack -> s[stptr]);
+ break;
case OP_END:
break;
}
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;