make sure WIN32 sections do NOT kick in for cygwin compiles
[rrdtool.git] / src / rrd_rpncalc.c
index 8e64d8b..73bef2f 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.0.28  Copyright Tobias Oetiker, 1997 - 2002
+ * RRDtool 1.2rc3  Copyright by Tobi Oetiker, 1997-2005
  ****************************************************************************
  * rrd_rpncalc.c  RPN calculator functions
  ****************************************************************************/
@@ -97,7 +97,7 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **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);
@@ -153,7 +153,11 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str)
          add_op(OP_NOW,NOW)
          add_op(OP_LTIME,LTIME)
          add_op(OP_TIME,TIME)
-
+         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)
 #undef add_op
               }
     (*str)[offset] = '\0';
@@ -196,10 +200,10 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx)
      * 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;
         }
@@ -222,7 +226,7 @@ void parseCDEF_DS(char *def,rrd_t *rrd, int ds_idx)
  */
 long lookup_DS(void *rrd_vptr,char *ds_name)
 {
-    int i;
+    unsigned int i;
     rrd_t *rrd; 
     
     rrd = (rrd_t *) rrd_vptr;
@@ -299,6 +303,7 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        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)
@@ -313,14 +318,18 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        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_ATAN,ATAN)
+       match_op(OP_SQRT,SQRT)
+       match_op(OP_SORT,SORT)
+       match_op(OP_REV,REV)
+       match_op(OP_TREND,TREND)
 #undef match_op
 
 
@@ -364,6 +373,14 @@ rpnstack_free(rpnstack_t *rpnstack)
    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:
@@ -428,15 +445,18 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                    }
                }
                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) {
+         if ((output_idx) <= 0) {
                rpnstack -> s[++stptr] = DNAN;
          } else {
                rpnstack -> s[++stptr] = rpnp[rpnp[rpi].ptr].data[output_idx-1];
@@ -497,6 +517,10 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                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_COS:
                stackunderflow(0);
                rpnstack -> s[stptr] = cos(rpnstack -> s[stptr]);
@@ -650,6 +674,61 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                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_END:
                break;
        }
@@ -670,20 +749,20 @@ int
 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;