X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_rpncalc.c;h=ab01c8ad12aed2687e1b2325fe6a0f504709e488;hb=23a7a9744b3f840f358e1c8e8483f93bd2bdf97f;hp=d83c0f4a7d920aabd62f6daacff1d910c7b8061b;hpb=f9e62abf5664d61987e111e4f1f9388e506a10ff;p=rrdtool.git diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c index d83c0f4..ab01c8a 100644 --- a/src/rrd_rpncalc.c +++ b/src/rrd_rpncalc.c @@ -1,14 +1,16 @@ /**************************************************************************** - * RRDtool 1.3.2 Copyright by Tobi Oetiker, 1997-2008 + * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010 **************************************************************************** * rrd_rpncalc.c RPN calculator functions ****************************************************************************/ +#include +#include +#include + #include "rrd_tool.h" #include "rrd_rpncalc.h" // #include "rrd_graph.h" -#include -#include short addop2str( enum op_en op, @@ -31,8 +33,8 @@ short rpn_compact( while (rpnp[*count].op != OP_END) (*count)++; if (++(*count) > DS_CDEF_MAX_RPN_NODES) { - rrd_set_error("Maximum %d RPN nodes permitted", - DS_CDEF_MAX_RPN_NODES); + rrd_set_error("Maximum %d RPN nodes permitted. Got %d RPN nodes at present.", + DS_CDEF_MAX_RPN_NODES-1,(*count)-1); return -1; } @@ -70,10 +72,12 @@ rpnp_t *rpn_expand( /* DS_CDEF_MAX_RPN_NODES is small, so at the expense of some wasted * memory we avoid any reallocs */ rpnp = (rpnp_t *) calloc(DS_CDEF_MAX_RPN_NODES, sizeof(rpnp_t)); - if (rpnp == NULL) + if (rpnp == NULL) { + rrd_set_error("failed allocating rpnp array"); return NULL; + } for (i = 0; rpnc[i].op != OP_END; ++i) { - rpnp[i].op = (long) rpnc[i].op; + rpnp[i].op = (enum op_en)rpnc[i].op; if (rpnp[i].op == OP_NUMBER) { rpnp[i].val = (double) rpnc[i].val; } else if (rpnp[i].op == OP_VARIABLE || rpnp[i].op == OP_PREV_OTHER) { @@ -106,14 +110,14 @@ void rpn_compact2str( (*str)[offset++] = ','; #define add_op(VV,VVV) \ - if (addop2str(rpnc[i].op, VV, VVV, str, &offset) == 1) continue; + if (addop2str((enum op_en)(rpnc[i].op), VV, VVV, str, &offset) == 1) continue; if (rpnc[i].op == OP_NUMBER) { /* convert a short into a string */ #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) _itoa(rpnc[i].val, buffer, 10); #else - sprintf(buffer, "%d", rpnc[i].val); + snprintf(buffer, sizeof buffer, "%d", rpnc[i].val); #endif add_op(OP_NUMBER, buffer) } @@ -132,7 +136,7 @@ void rpn_compact2str( #undef add_op #define add_op(VV,VVV) \ - if (addop2str(rpnc[i].op, VV, #VVV, str, &offset) == 1) continue; + if (addop2str((enum op_en)rpnc[i].op, VV, #VVV, str, &offset) == 1) continue; add_op(OP_ADD, +) add_op(OP_SUB, -) @@ -232,9 +236,11 @@ void parseCDEF_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_COUNT) { + rpnp[i].op == OP_PREV || rpnp[i].op == OP_COUNT || + rpnp[i].op == OP_TREND || rpnp[i].op == OP_TRENDNAN || + rpnp[i].op == OP_PREDICT || rpnp[i].op == OP_PREDICTSIGMA ) { rrd_set_error - ("operators time, ltime, prev and count not supported with DS COMPUTE"); + ("operators TIME, LTIME, PREV COUNT TREND TRENDNAN PREDICT PREDICTSIGMA are not supported with DS COMPUTE"); free(rpnp); return; } @@ -293,7 +299,8 @@ rpnp_t *rpn_parse( char vname[MAX_VNAME_LEN + 10]; char *old_locale; - old_locale = setlocale(LC_NUMERIC, "C"); + old_locale = setlocale(LC_NUMERIC, NULL); + setlocale(LC_NUMERIC, "C"); rpnp = NULL; expr = (char *) expr_const; @@ -380,6 +387,7 @@ rpnp_t *rpn_parse( match_op(OP_AVG, AVG) match_op(OP_ABS, ABS) match_op(OP_ADDNAN, ADDNAN) + match_op(OP_MEDIAN, MEDIAN) #undef match_op else if ((sscanf(expr, DEF_NAM_FMT "%n", vname, &pos) == 1) && ((rpnp[steps].ptr = (*lookup) (key_hash, vname)) != @@ -465,7 +473,7 @@ short rpn_calc( if (stptr + 5 > rpnstack->dc_stacksize) { /* could move this to a separate function */ rpnstack->dc_stacksize += rpnstack->dc_stackblock; - rpnstack->s = rrd_realloc(rpnstack->s, + rpnstack->s = (double*)rrd_realloc(rpnstack->s, (rpnstack->dc_stacksize) * sizeof(*(rpnstack->s))); if (rpnstack->s == NULL) { @@ -876,7 +884,7 @@ short rpn_calc( 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)) { + if (output_idx + 1 >= (int) ceil((float) dur / (float) step)) { int ignorenan = (rpnp[rpi].op == OP_TREND); double accum = 0.0; int i = 0; @@ -929,6 +937,51 @@ short rpn_calc( stackunderflow(0); rpnstack->s[stptr] = fabs(rpnstack->s[stptr]); break; + case OP_MEDIAN: + stackunderflow(0); + { + int elements = (int) rpnstack->s[stptr--]; + int final_elements = elements; + double *element_ptr = rpnstack->s + stptr - elements + 1; + double *goodvals = element_ptr; + double *badvals = element_ptr + elements - 1; + + stackunderflow(elements - 1); + + /* move values to consolidate the non-NANs for sorting, keeping + * track of how many NANs we encounter. */ + while (goodvals < badvals) { + if (isnan(*goodvals)) { + *goodvals = *badvals--; + --final_elements; + } else { + ++goodvals; + } + } + + stptr -= elements; + if (!final_elements) { + /* no non-NAN elements; push NAN */ + rpnstack->s[++stptr] = DNAN; + } else { + /* when goodvals and badvals meet, they might have met on a + * NAN, which wouldn't decrease final_elements. so, check + * that now. */ + if (isnan(*goodvals)) --final_elements; + /* and finally, take the median of the remaining non-NAN + * elements. */ + qsort(element_ptr, final_elements, sizeof(double), + rpn_compare_double); + if (final_elements % 2 == 1){ + rpnstack->s[++stptr] = element_ptr[ final_elements / 2 ]; + } + else { + rpnstack->s[++stptr] = 0.5 * ( element_ptr[ final_elements / 2 ] + element_ptr[ final_elements / 2 - 1 ] ); + } + } + } + break; + case OP_END: break; }