prevent potential segfaults on boxes where time_t is not long
[rrdtool.git] / src / rrd_rpncalc.c
index d1ab0de..7953320 100644 (file)
@@ -19,8 +19,8 @@ int       tzoffset(
     time_t);            /* used to implement LTIME */
 
 short rpn_compact(
-    rpnp_t * rpnp,
-    rpn_cdefds_t ** rpnc,
+    rpnp_t *rpnp,
+    rpn_cdefds_t **rpnc,
     short *count)
 {
     short     i;
@@ -61,7 +61,7 @@ short rpn_compact(
 }
 
 rpnp_t   *rpn_expand(
-    rpn_cdefds_t * rpnc)
+    rpn_cdefds_t *rpnc)
 {
     short     i;
     rpnp_t   *rpnp;
@@ -93,8 +93,8 @@ rpnp_t   *rpn_expand(
  *  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,
+    rpn_cdefds_t *rpnc,
+    ds_def_t *ds_def,
     char **str)
 {
     unsigned short i, offset = 0;
@@ -172,6 +172,7 @@ void rpn_compact2str(
             add_op(OP_SORT, SORT)
             add_op(OP_REV, REV)
             add_op(OP_TREND, TREND)
+            add_op(OP_TRENDNAN, TRENDNAN)
             add_op(OP_RAD2DEG, RAD2DEG)
             add_op(OP_DEG2RAD, DEG2RAD)
             add_op(OP_AVG, AVG)
@@ -278,8 +279,8 @@ long lookup_DS(
 rpnp_t   *rpn_parse(
     void *key_hash,
     const char *const expr_const,
-    long (*lookup) (void *,
-                    char *))
+    long      (*lookup) (void *,
+                         char *))
 {
     int       pos = 0;
     char     *expr;
@@ -364,6 +365,7 @@ rpnp_t   *rpn_parse(
             match_op(OP_SORT, SORT)
             match_op(OP_REV, REV)
             match_op(OP_TREND, TREND)
+            match_op(OP_TRENDNAN, TRENDNAN)
             match_op(OP_RAD2DEG, RAD2DEG)
             match_op(OP_DEG2RAD, DEG2RAD)
             match_op(OP_AVG, AVG)
@@ -394,7 +396,7 @@ rpnp_t   *rpn_parse(
 }
 
 void rpnstack_init(
-    rpnstack_t * rpnstack)
+    rpnstack_t *rpnstack)
 {
     rpnstack->s = NULL;
     rpnstack->dc_stacksize = 0;
@@ -402,7 +404,7 @@ void rpnstack_init(
 }
 
 void rpnstack_free(
-    rpnstack_t * rpnstack)
+    rpnstack_t *rpnstack)
 {
     if (rpnstack->s != NULL)
         free(rpnstack->s);
@@ -434,10 +436,10 @@ static int rpn_compare_double(
  *           0 on success
  */
 short rpn_calc(
-    rpnp_t * rpnp,
-    rpnstack_t * rpnstack,
+    rpnp_t *rpnp,
+    rpnstack_t *rpnstack,
     long data_idx,
-    rrd_value_t * output,
+    rrd_value_t *output,
     int output_idx)
 {
     int       rpi;
@@ -757,6 +759,7 @@ short rpn_calc(
             }
             break;
         case OP_TREND:
+        case OP_TRENDNAN:
             stackunderflow(1);
             if ((rpi < 2) || (rpnp[rpi - 2].op != OP_VARIABLE)) {
                 rrd_set_error("malformed trend arguments");
@@ -766,16 +769,24 @@ short rpn_calc(
                 time_t    step = (time_t) rpnp[rpi - 2].step;
 
                 if (output_idx > (int) ceil((float) dur / (float) step)) {
+                    int       ignorenan = (rpnp[rpi].op == OP_TREND);
                     double    accum = 0.0;
                     int       i = 0;
+                    int       count = 0;
 
                     do {
-                        accum +=
+                        double    val =
                             rpnp[rpi - 2].data[rpnp[rpi - 2].ds_cnt * i--];
+                        if (ignorenan || !isnan(val)) {
+                            accum += val;
+                            ++count;
+                        }
+
                         dur -= step;
                     } while (dur > 0);
 
-                    rpnstack->s[--stptr] = (accum / -i);
+                    rpnstack->s[--stptr] =
+                        (count == 0) ? DNAN : (accum / count);
                 } else
                     rpnstack->s[--stptr] = DNAN;
             }