Code

complete segfault fix for second axis %s format begun in r2123 (thanks Martin Pelikan...
[rrdtool.git] / src / rrd_rpncalc.c
index 7953320f084820349345a38e55b0fba2d8cfdb8d..e4b224de0a7b4fd342a7f107bf77a7dc65acc969 100644 (file)
@@ -1,13 +1,18 @@
 /****************************************************************************
- * RRDtool 1.2.23  Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.3.9  Copyright by Tobi Oetiker, 1997-2009
  ****************************************************************************
  * rrd_rpncalc.c  RPN calculator functions
  ****************************************************************************/
 
 #include "rrd_tool.h"
 #include "rrd_rpncalc.h"
-#include "rrd_graph.h"
+// #include "rrd_graph.h"
 #include <limits.h>
+#include <locale.h>
+
+#ifdef WIN32
+#include <stdlib.h>
+#endif
 
 short     addop2str(
     enum op_en op,
@@ -69,10 +74,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) {
@@ -105,7 +112,7 @@ 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 */
@@ -131,7 +138,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, -)
@@ -177,6 +184,7 @@ void rpn_compact2str(
             add_op(OP_DEG2RAD, DEG2RAD)
             add_op(OP_AVG, AVG)
             add_op(OP_ABS, ABS)
+            add_op(OP_ADDNAN, ADDNAN)
 #undef add_op
     }
     (*str)[offset] = '\0';
@@ -287,6 +295,10 @@ rpnp_t   *rpn_parse(
     long      steps = -1;
     rpnp_t   *rpnp;
     char      vname[MAX_VNAME_LEN + 10];
+    char     *old_locale;
+
+    old_locale = setlocale(LC_NUMERIC, NULL);
+    setlocale(LC_NUMERIC, "C");
 
     rpnp = NULL;
     expr = (char *) expr_const;
@@ -294,6 +306,7 @@ rpnp_t   *rpn_parse(
     while (*expr) {
         if ((rpnp = (rpnp_t *) rrd_realloc(rpnp, (++steps + 2) *
                                            sizeof(rpnp_t))) == NULL) {
+            setlocale(LC_NUMERIC, old_locale);
             return NULL;
         }
 
@@ -306,8 +319,7 @@ rpnp_t   *rpn_parse(
         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) { \
@@ -370,6 +382,7 @@ rpnp_t   *rpn_parse(
             match_op(OP_DEG2RAD, DEG2RAD)
             match_op(OP_AVG, AVG)
             match_op(OP_ABS, ABS)
+            match_op(OP_ADDNAN, ADDNAN)
 #undef match_op
             else if ((sscanf(expr, DEF_NAM_FMT "%n", vname, &pos) == 1)
                      && ((rpnp[steps].ptr = (*lookup) (key_hash, vname)) !=
@@ -379,19 +392,23 @@ rpnp_t   *rpn_parse(
         }
 
         else {
+            setlocale(LC_NUMERIC, old_locale);
             free(rpnp);
             return NULL;
         }
+
         if (*expr == 0)
             break;
         if (*expr == ',')
             expr++;
         else {
+            setlocale(LC_NUMERIC, old_locale);
             free(rpnp);
             return NULL;
         }
     }
     rpnp[steps + 1].op = OP_END;
+    setlocale(LC_NUMERIC, old_locale);
     return rpnp;
 }
 
@@ -451,9 +468,9 @@ 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)));
+                                                            sizeof(*(rpnstack->s))));
             if (rpnstack->s == NULL) {
                 rrd_set_error("RPN stack overflow");
                 return -1;
@@ -535,6 +552,20 @@ short rpn_calc(
                 + rpnstack->s[stptr];
             stptr--;
             break;
+        case OP_ADDNAN:
+            stackunderflow(1);
+            if (isnan(rpnstack->s[stptr - 1])) {
+                rpnstack->s[stptr - 1] = rpnstack->s[stptr];
+            } else if (isnan(rpnstack->s[stptr])) {
+                /* NOOP */
+                /* rpnstack->s[stptr - 1] = rpnstack->s[stptr - 1]; */
+            } else {
+                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]
@@ -682,8 +713,10 @@ short rpn_calc(
             break;
         case OP_IF:
             stackunderflow(2);
-            rpnstack->s[stptr - 2] = rpnstack->s[stptr - 2] != 0.0 ?
-                rpnstack->s[stptr - 1] : rpnstack->s[stptr];
+            rpnstack->s[stptr - 2] = (isnan(rpnstack->s[stptr - 2])
+                                      || rpnstack->s[stptr - 2] ==
+                                      0.0) ? rpnstack->s[stptr] : rpnstack->
+                s[stptr - 1];
             stptr--;
             stptr--;
             break;