revamped drawing routines to be less complex and more stable. be kind to libart
[rrdtool.git] / src / rrd_graph.c
index 0279d49..67fce90 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.2rc2  Copyright by Tobi Oetiker, 1997-2005
+ * RRDtool 1.2rc5  Copyright by Tobi Oetiker, 1997-2005
  ****************************************************************************
  * rrd__graph.c  produce graphs from data in rrdfiles
  ****************************************************************************/
@@ -9,7 +9,7 @@
 
 #include "rrd_tool.h"
 
-#ifdef WIN32
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #include <fcntl.h>
 #endif
@@ -27,9 +27,6 @@
 /* some constant definitions */
 
 
-#ifdef WIN32
-char rrd_win_default_font[80];
-#endif
 
 #ifndef RRD_DEFAULT_FONT
 /* there is special code later to pick Cour.ttf when running on windows */
@@ -2100,7 +2097,9 @@ graph_size_location(image_desc_t *im, int elements
        Xtitle   =0,    Ytitle   =0,
        Xylabel  =0,    Yylabel  =0,
        Xmain    =0,    Ymain    =0,
+#ifdef WITH_PIECHART
        Xpie     =0,    Ypie     =0,
+#endif
        Xxlabel  =0,    Yxlabel  =0,
 #if 0
        Xlegend  =0,    Ylegend  =0,
@@ -2108,18 +2107,22 @@ graph_size_location(image_desc_t *im, int elements
         Xspacing =10,  Yspacing =10;
 
     if (im->extra_flags & ONLY_GRAPH) {
-       Xspacing =0;
-       Yspacing =0;
-    } else {
-        if (im->ylegend[0] != '\0') {
+       im->xorigin =0;
+       im->ximg = im->xsize;
+        im->yimg = im->ysize;
+        im->yorigin = im->ysize;
+       return 0;
+    }
+
+    if (im->ylegend[0] != '\0' ) {
            Xvertical = im->text_prop[TEXT_PROP_UNIT].size *2;
            Yvertical = gfx_get_text_width(im->canvas, 0,
                                           im->text_prop[TEXT_PROP_UNIT].font,
                                           im->text_prop[TEXT_PROP_UNIT].size,
                                           im->tabwidth,im->ylegend, 0);
-        }
     }
 
+
     if (im->title[0] != '\0') {
        /* The title is placed "inbetween" two text lines so it
        ** automatically has some vertical spacing.  The horizontal
@@ -2165,23 +2168,22 @@ graph_size_location(image_desc_t *im, int elements
     ** forget about it at all; the legend will have to fit in the
     ** size already allocated.
     */
-    im->ximg = Xmain;
+    im->ximg = Xylabel + Xmain + 2 * Xspacing;
 
-    if ( !(im->extra_flags & ONLY_GRAPH) ) {
-        im->ximg = Xylabel + Xmain + Xpie + 2 * Xspacing;
-    }
+#ifdef WITH_PIECHART
+    im->ximg  += Xpie;
+#endif
 
     if (Xmain) im->ximg += Xspacing;
+#ifdef WITH_PIECHART
     if (Xpie) im->ximg += Xspacing;
+#endif
 
-    if (im->extra_flags & ONLY_GRAPH) {
-       im->xorigin = 0;
-    } else {
-       im->xorigin = Xspacing + Xylabel;
-    }
+    im->xorigin = Xspacing + Xylabel;
 
     if (Xtitle > im->ximg) im->ximg = Xtitle;
-    if (Xvertical) {
+
+    if (Xvertical) { /* unit description */
        im->ximg += Xvertical;
        im->xorigin += Xvertical;
     }
@@ -2198,19 +2200,13 @@ graph_size_location(image_desc_t *im, int elements
 
     /* reserve space for main and/or pie */
 
-    if (im->extra_flags & ONLY_GRAPH) {
-        im->yimg = Ymain;
-    } else {
-        im->yimg = Ymain + Yxlabel;
-    }
+    im->yimg = Ymain + Yxlabel;
 
+#ifdef WITH_PIECHART
     if (im->yimg < Ypie) im->yimg = Ypie;
+#endif
 
-    if (im->extra_flags & ONLY_GRAPH) {
-        im->yorigin = im->yimg;
-    } else {
-        im->yorigin = im->yimg - Yxlabel;
-    }
+    im->yorigin = im->yimg - Yxlabel;
 
     /* reserve space for the title *or* some padding above the graph */
     if (Ytitle) {
@@ -2422,81 +2418,69 @@ graph_paint(image_desc_t *im, char ***calcpr)
           
         }
       } /* for */
-      
-      if (im->gdes[i].col != 0x0){               
+
+      /* *******************************************************
+                   ___ 
+                 |   |    ___
+              ____|   |   |   |
+              |       |___|
+       -------|---------------------------------------      
+                      
+      if we know the value of y at time t was a then 
+      we draw a square from t-1 to t with the value a.
+
+      ********************************************************* */
+      if (im->gdes[i].col != 0x0){   
         /* GF_LINE and friend */
         if(stack_gf == GF_LINE ){
           node = NULL;
           for(ii=1;ii<im->xsize;ii++){
-            if ( ! isnan(im->gdes[i].p_data[ii-1])
-                 && ! isnan(im->gdes[i].p_data[ii])){
-              if (node == NULL){
-                node = gfx_new_line(im->canvas,
-                                    ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
+           if (isnan(im->gdes[i].p_data[ii])){
+               node = NULL;
+               continue;
+           }
+            if ( node == NULL ) {
+                 node = gfx_new_line(im->canvas,
+                                    ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
                                     ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
                                     im->gdes[i].linewidth,
                                     im->gdes[i].col);
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
-              }
-            } else {
-              node = NULL;
-            }
+             } else {
+               gfx_add_point(node,ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+               gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+             };
+
           }
         } else {
-          int area_start=-1;
-          node = NULL;
           for(ii=1;ii<im->xsize;ii++){
-            /* open an area */
-            if ( ! isnan(im->gdes[i].p_data[ii-1])
-                 && ! isnan(im->gdes[i].p_data[ii])){
-              if (node == NULL){
-                float ybase = 0.0;
-/*
-                if (im->gdes[i].gf == GF_STACK) {
-*/
-               if ( (im->gdes[i].gf == GF_STACK)
-                 || (im->gdes[i].stack) ) {
-
-                  ybase = ytr(im,lastgdes->p_data[ii-1]);
-                } else {
-                  ybase =  ytr(im,areazero);
-                }
-                area_start = ii-1;
-                node = gfx_new_area(im->canvas,
-                                    ii-1+im->xorigin,ybase,
-                                    ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
-                                    ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
-                                    im->gdes[i].col
-                                    );
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
-              }
+           /* keep things simple for now, just draw these bars
+              do not try to build a big and complex area */
+           float ybase;
+           if ( isnan(im->gdes[i].p_data[ii]) ) {
+               continue;
+           }
+           if ( im->gdes[i].stack ) {
+                  ybase = ytr(im,lastgdes->p_data[ii]);
+            } else {
+                  ybase = ytr(im,areazero);
             }
-
-            if ( node != NULL && (ii+1==im->xsize || isnan(im->gdes[i].p_data[ii]) )){
-              /* GF_AREA STACK type*/
-/*
-              if (im->gdes[i].gf == GF_STACK ) {
-*/
-             if ( (im->gdes[i].gf == GF_STACK)
-               || (im->gdes[i].stack) ) {
-                int iii;
-                for (iii=ii-1;iii>area_start;iii--){
-                  gfx_add_point(node,iii+im->xorigin,ytr(im,lastgdes->p_data[iii]));
-                }
-              } else {
-                gfx_add_point(node,ii+im->xorigin,ytr(im,areazero));
-              };
-              node=NULL;
-            };
+            if ( ybase == im->gdes[i].p_data[ii] ){
+               continue;
+           }
+            node = gfx_new_area(im->canvas,
+                                ii-1+im->xorigin,ybase,
+                                ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+                                ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),                         
+                                im->gdes[i].col
+                               );
+            gfx_add_point(node,ii+im->xorigin,ybase);
           }             
         } /* else GF_LINE */
       } /* if color != 0x0 */
       /* make sure we do not run into trouble when stacking on NaN */
       for(ii=0;ii<im->xsize;ii++){
         if (isnan(im->gdes[i].p_data[ii])) {
-          if (lastgdes && (im->gdes[i].gf == GF_STACK)) {
+          if (lastgdes && (im->gdes[i].stack)) {
             im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
           } else {
             im->gdes[i].p_data[ii] =  ytr(im,areazero);
@@ -2570,7 +2554,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
   
   if (strcmp(im->graphfile,"-")==0) {
     fo = im->graphhandle ? im->graphhandle : stdout;
-#ifdef WIN32
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
     /* Change translation mode for stdout to BINARY */
     _setmode( _fileno( fo ), O_BINARY );
 #endif
@@ -2769,19 +2753,34 @@ rrd_graph_init(image_desc_t *im)
     
     for(i=0;i<DIM(graph_col);i++)
         im->graph_col[i]=graph_col[i];
-#ifdef WIN32
+
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
     {
             char *windir; 
+           char rrd_win_default_font[1000];
             windir = getenv("windir");
             /* %windir% is something like D:\windows or C:\winnt */
             if (windir != NULL) {
-                    strcpy(rrd_win_default_font,windir);
+                    strncpy(rrd_win_default_font,windir,999);
+                    rrd_win_default_font[999] = '\0';
                     strcat(rrd_win_default_font,"\\fonts\\cour.ttf");
-                    for(i=0;i<DIM(text_prop);i++)
-                            strcpy(text_prop[i].font,rrd_win_default_font);
-            }
+                    for(i=0;i<DIM(text_prop);i++){
+                            strncpy(text_prop[i].font,rrd_win_default_font,sizeof(text_prop[i].font)-1);
+                            text_prop[i].font[sizeof(text_prop[i].font)-1] = '\0';
+                     }
     }
 #endif
+    {
+            char *deffont; 
+            deffont = getenv("RRD_DEFAULT_FONT");
+            /* %windir% is something like D:\windows or C:\winnt */
+            if (deffont != NULL) {
+                 for(i=0;i<DIM(text_prop);i++){
+                       strncpy(text_prop[i].font,deffont,sizeof(text_prop[i].font)-1);
+                       text_prop[i].font[sizeof(text_prop[i].font)-1] = '\0';
+                }
+            }
+    }
     for(i=0;i<DIM(text_prop);i++){        
       im->text_prop[i].size = text_prop[i].size;
       strcpy(im->text_prop[i].font,text_prop[i].font);
@@ -2839,7 +2838,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            {0,0,0,0}};
        int option_index = 0;
        int opt;
-
+        int col_start,col_end;
 
        opt = getopt_long(argc, argv, 
                         "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMX:S:NT:",
@@ -2911,6 +2910,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
                      &im->xlab_user.precis,
                      &stroff) == 7 && stroff != 0){
                 strncpy(im->xlab_form, optarg+stroff, sizeof(im->xlab_form) - 1);
+               im->xlab_form[sizeof(im->xlab_form)-1] = '\0'; 
                if((int)(im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
                    rrd_set_error("unknown keyword %s",scan_gtm);
                    return;
@@ -3009,13 +3009,25 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            break;
         case 'c':
             if(sscanf(optarg,
-                      "%10[A-Z]#%8lx",
-                      col_nam,&color) == 2){
+                      "%10[A-Z]#%n%8lx%n",
+                      col_nam,&col_start,&color,&col_end) == 2){
                 int ci;
+               int col_len = col_end - col_start;
+               switch (col_len){
+                       case 6:
+                               color = (color << 8) + 0xff /* shift left by 8 */;
+                               break;
+                       case 8:
+                               break;
+                       default:
+                               rrd_set_error("the color format is #RRGGBB[AA]");
+                               return;
+               }
                 if((ci=grc_conv(col_nam)) != -1){
                     im->graph_col[ci]=color;
                 }  else {
                   rrd_set_error("invalid color name '%s'",col_nam);
+                 return;
                 }
             } else {
                 rrd_set_error("invalid color def format");