index d83c0f4a7d920aabd62f6daacff1d910c7b8061b..ab01c8ad12aed2687e1b2325fe6a0f504709e488 100644 (file)
/****************************************************************************
- * 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 <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+
#include "rrd_tool.h"
#include "rrd_rpncalc.h"
// #include "rrd_graph.h"
-#include <limits.h>
-#include <locale.h>
short addop2str(
enum op_en op,
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;
}
/* 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) {
(*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)
}
#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, -)
* 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;
}
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;
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)) !=
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) {
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;
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;
}