misc fixed and TREND and reduce functionality by
[rrdtool.git] / src / rrd_graph.c
index 18be573..d22c853 100644 (file)
 /* some constant definitions */
 
 
-#ifndef RRD_DEFAULT_FONT
 #ifdef WIN32
-#define RRD_DEFAULT_FONT "c:/winnt/fonts/COUR.TTF"
-#else
-#define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/openoffice/ariosor.ttf" 
+char rrd_win_default_font[80];
+#endif
+
+#ifndef RRD_DEFAULT_FONT
+#ifndef WIN32
+#define RRD_DEFAULT_FONT "VeraMono.ttf"
+/* #define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/openoffice/ariosor.ttf" */
 /* #define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/Arial.ttf" */
 #endif
 #endif
 
-
 text_prop_t text_prop[] = {   
      { 10.0, RRD_DEFAULT_FONT }, /* default */
-     { 12.0, RRD_DEFAULT_FONT }, /* title */
+     { 10.0, RRD_DEFAULT_FONT }, /* title */
      { 8.0,  RRD_DEFAULT_FONT },  /* axis */
      { 10.0, RRD_DEFAULT_FONT },  /* unit */
      { 10.0, RRD_DEFAULT_FONT }  /* legend */
@@ -186,6 +188,7 @@ enum gf_en gf_conv(char *string){
     conv_if(VDEF,GF_VDEF)
     conv_if(PART,GF_PART)
     conv_if(XPORT,GF_XPORT)
+    conv_if(SHIFT,GF_SHIFT)
     
     return (-1);
 }
@@ -599,7 +602,7 @@ printf("row_cnt after:   %lu\n",row_cnt);
     ** into one interval for the destination.
     */
 
-    for (dst_row=0;row_cnt>=reduce_factor;dst_row++) {
+    for (dst_row=0;(long int)row_cnt>=reduce_factor;dst_row++) {
        for (col=0;col<(*ds_cnt);col++) {
            rrd_value_t newval=DNAN;
            unsigned long validval=0;
@@ -677,13 +680,13 @@ for (col=0;col<row_cnt;col++) {
    relevant rrds ... */
 
 int
-data_fetch( image_desc_t *im )
+data_fetch(image_desc_t *im )
 {
-    int                i,ii;
+    int i,ii;
     int                skip;
 
     /* pull the data from the log files ... */
-    for (i=0;i<im->gdes_c;i++){
+    for (i=0;i< (int)im->gdes_c;i++){
        /* only GF_DEF elements fetch data */
        if (im->gdes[i].gf != GF_DEF) 
            continue;
@@ -695,6 +698,7 @@ data_fetch( image_desc_t *im )
                continue;
            if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
                        && (im->gdes[i].cf    == im->gdes[ii].cf)
+                       && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
                        && (im->gdes[i].start == im->gdes[ii].start)
                        && (im->gdes[i].end   == im->gdes[ii].end)
                        && (im->gdes[i].step  == im->gdes[ii].step)) {
@@ -727,9 +731,10 @@ data_fetch( image_desc_t *im )
                return -1;
            }
            im->gdes[i].data_first = 1;     
+           im->gdes[i].step = im->step;
        
            if (ft_step < im->gdes[i].step) {
-               reduce_data(im->gdes[i].cf,
+               reduce_data(im->gdes[i].cf_reduce,
                            ft_step,
                            &im->gdes[i].start,
                            &im->gdes[i].end,
@@ -741,8 +746,8 @@ data_fetch( image_desc_t *im )
            }
        }
        
-        /* lets see if the required data source is realy there */
-       for(ii=0;ii<im->gdes[i].ds_cnt;ii++){
+        /* lets see if the required data source is really there */
+       for(ii=0;ii<(int)im->gdes[i].ds_cnt;ii++){
            if(strcmp(im->gdes[i].ds_namv[ii],im->gdes[i].ds_nam) == 0){
                im->gdes[i].ds=ii; }
        }
@@ -820,6 +825,28 @@ data_calc( image_desc_t *im){
        switch (im->gdes[gdi].gf) {
            case GF_XPORT:
              break;
+           case GF_SHIFT: {
+               graph_desc_t    *vdp = &im->gdes[im->gdes[gdi].vidx];
+               
+               /* remove current shift */
+               vdp->start -= vdp->shift;
+               vdp->end -= vdp->shift;
+               
+               /* vdef */
+               if (im->gdes[gdi].shidx >= 0) 
+                       vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val;
+               /* constant */
+               else
+                       vdp->shift = im->gdes[gdi].shval;
+
+               /* normalize shift to multiple of consolidated step */
+               vdp->shift = (vdp->shift / (long)vdp->step) * (long)vdp->step;
+
+               /* apply shift */
+               vdp->start += vdp->shift;
+               vdp->end += vdp->shift;
+               break;
+           }
            case GF_VDEF:
                /* A VDEF has no DS.  This also signals other parts
                 * of rrdtool that this is a VDEF value, not a CDEF.
@@ -910,12 +937,12 @@ data_calc( image_desc_t *im){
                if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
                   im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
                         long ptr = im->gdes[gdi].rpnp[rpi].ptr;
-                        if(im->gdes[gdi].start > im->gdes[ptr].start) {
-                            im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt;
-                        }
+                       long diff = im->gdes[gdi].start - im->gdes[ptr].start;
+
+                        if(diff > 0)
+                           im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt;
                      }
                 }
-        
 
                if(steparray == NULL){
                    rrd_set_error("rpn expressions without DEF"
@@ -1008,13 +1035,15 @@ data_proc( image_desc_t *im ){
                        paintval = 0.0;
                case GF_STACK:
                    value = im->gdes[ii].yrule;
-                   if (isnan(value)) { /* not a number or VDEF */
+                   if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) {
                        /* The time of the data doesn't necessarily match
                        ** the time of the graph. Beware.
                        */
                        vidx = im->gdes[ii].vidx;
-                       if (    (gr_time >= im->gdes[vidx].start) &&
-                               (gr_time <= im->gdes[vidx].end) ) {
+                       if (im->gdes[vidx].gf == GF_VDEF) {
+                           value = im->gdes[vidx].vf.val;
+                       } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) &&
+                                  ((long int)gr_time <= (long int)im->gdes[vidx].end) ) {
                            value = im->gdes[vidx].data[
                                (unsigned long) floor(
                                    (double)(gr_time - im->gdes[vidx].start)
@@ -1070,6 +1099,11 @@ data_proc( image_desc_t *im ){
        else
            im->maxval = maxval;
     }
+    /* make sure min is smaller than max */
+    if (im->minval > im->maxval) {
+            im->minval = 0.99 * im->maxval;
+    }
+                      
     /* make sure min and max are not equal */
     if (im->minval == im->maxval) {
        im->maxval *= 1.01; 
@@ -1096,7 +1130,7 @@ find_first_time(
     )
 {
     struct tm tm;
-    tm = *localtime(&start);
+    localtime_r(&start, &tm);
     switch(baseint){
     case TMT_SECOND:
        tm.tm_sec -= tm.tm_sec % basestep; break;
@@ -1149,7 +1183,7 @@ find_next_time(
 {
     struct tm tm;
     time_t madetime;
-    tm = *localtime(&current);
+    localtime_r(&current, &tm);
     do {
        switch(baseint){
        case TMT_SECOND:
@@ -1254,14 +1288,15 @@ print_calc(image_desc_t *im, char ***prdata)
            } /* prepare printval */
 
            if (!strcmp(im->gdes[i].format,"%c")) { /* VDEF time print */
+               char ctime_buf[128]; /* PS: for ctime_r, must be >= 26 chars */
                if (im->gdes[i].gf == GF_PRINT){
                    (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
                    sprintf((*prdata)[prlines-2],"%s (%lu)",
-                                       ctime(&printtime),printtime);
+                                       ctime_r(&printtime,ctime_buf),printtime);
                    (*prdata)[prlines-1] = NULL;
                } else {
                    sprintf(im->gdes[i].legend,"%s (%lu)",
-                                       ctime(&printtime),printtime);
+                                       ctime_r(&printtime,ctime_buf),printtime);
                    graphelement = 1;
                }
            } else {
@@ -1285,6 +1320,7 @@ print_calc(image_desc_t *im, char ***prdata)
 
            if (im->gdes[i].gf == GF_PRINT){
                (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char));
+               (*prdata)[prlines-1] = NULL;
                if (bad_format(im->gdes[i].format)) {
                        rrd_set_error("bad format for [G]PRINT in '%s'", im->gdes[i].format);
                        return -1;
@@ -1294,7 +1330,6 @@ print_calc(image_desc_t *im, char ***prdata)
 #else
                sprintf((*prdata)[prlines-2],im->gdes[i].format,printval,si_symb);
 #endif
-               (*prdata)[prlines-1] = NULL;
            } else {
                /* GF_GPRINT */
 
@@ -1324,6 +1359,7 @@ print_calc(image_desc_t *im, char ***prdata)
        case GF_CDEF:       
        case GF_VDEF:       
        case GF_PART:
+       case GF_SHIFT:
        case GF_XPORT:
            break;
        }
@@ -1349,7 +1385,7 @@ leg_place(image_desc_t *im)
     char  prt_fctn; /*special printfunctions */
     int  *legspace;
 
-  if( !(im->extra_flags & NOLEGEND) ) {
+  if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) {
     if ((legspace = malloc(im->gdes_c*sizeof(int)))==NULL){
        rrd_set_error("malloc for legspace");
        return -1;
@@ -1357,6 +1393,16 @@ leg_place(image_desc_t *im)
 
     for(i=0;i<im->gdes_c;i++){
        fill_last = fill;
+        
+        /* hid legends for rules which are not displayed */
+        
+       if (im->gdes[i].gf == GF_HRULE &&
+           (im->gdes[i].yrule < im->minval || im->gdes[i].yrule > im->maxval))
+           im->gdes[i].legend[0] = '\0';
+
+       if (im->gdes[i].gf == GF_VRULE &&
+           (im->gdes[i].xrule < im->start || im->gdes[i].xrule > im->end))
+           im->gdes[i].legend[0] = '\0';
 
        leg_cc = strlen(im->gdes[i].legend);
        
@@ -1390,7 +1436,7 @@ leg_place(image_desc_t *im)
                                      im->text_prop[TEXT_PROP_LEGEND].font,
                                      im->text_prop[TEXT_PROP_LEGEND].size,
                                      im->tabwidth,
-                                     im->gdes[i].legend);
+                                     im->gdes[i].legend, 0);
            leg_c++;
        } else {
           legspace[i]=0;
@@ -1438,7 +1484,7 @@ leg_place(image_desc_t *im)
                                      im->text_prop[TEXT_PROP_LEGEND].font,
                                      im->text_prop[TEXT_PROP_LEGEND].size,
                                      im->tabwidth,
-                                     im->gdes[ii].legend) 
+                                     im->gdes[ii].legend, 0
                   + legspace[ii]
                   + glue;
                if (im->gdes[ii].gf != GF_GPRINT && 
@@ -1591,7 +1637,7 @@ int draw_horizontal_grid(image_desc_t *im)
                              MGRIDWIDTH, im->graph_col[GRC_MGRID],
                              im->grid_dash_on, im->grid_dash_off);            
               
-           } else {            
+           } else if (!(im->extra_flags & NOMINOR)) {          
               gfx_new_dashed_line ( im->canvas,
                              X0-1,Y0,
                              X1+1,Y0,
@@ -1694,7 +1740,7 @@ vertical_grid(
     long factor;
     char graph_label[100];
     double X0,Y0,Y1; /* points for filled graph and more*/
-   
+    struct tm tm;
 
     /* the type of time grid is determined by finding
        the number of seconds per pixel in the graph */
@@ -1721,27 +1767,30 @@ vertical_grid(
    
 
     /* paint the minor grid */
-    for(ti = find_first_time(im->start,
-                           im->xlab_user.gridtm,
-                           im->xlab_user.gridst),
-        timajor = find_first_time(im->start,
-                           im->xlab_user.mgridtm,
-                           im->xlab_user.mgridst);
-       ti < im->end; 
-       ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst)
-       ){
-       /* are we inside the graph ? */
-       if (ti < im->start || ti > im->end) continue;
-       while (timajor < ti) {
-           timajor = find_next_time(timajor,
-                   im->xlab_user.mgridtm, im->xlab_user.mgridst);
-       }
-       if (ti == timajor) continue; /* skip as falls on major grid line */
-       X0 = xtr(im,ti);       
-       gfx_new_dashed_line(im->canvas,X0,Y0+1, X0,Y1-1,GRIDWIDTH,
-          im->graph_col[GRC_GRID],
-          im->grid_dash_on, im->grid_dash_off);
-       
+    if (!(im->extra_flags & NOMINOR))
+    {
+        for(ti = find_first_time(im->start,
+                                im->xlab_user.gridtm,
+                                im->xlab_user.gridst),
+            timajor = find_first_time(im->start,
+                                im->xlab_user.mgridtm,
+                                im->xlab_user.mgridst);
+            ti < im->end; 
+            ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst)
+            ){
+            /* are we inside the graph ? */
+            if (ti < im->start || ti > im->end) continue;
+            while (timajor < ti) {
+                timajor = find_next_time(timajor,
+                        im->xlab_user.mgridtm, im->xlab_user.mgridst);
+            }
+            if (ti == timajor) continue; /* skip as falls on major grid line */
+           X0 = xtr(im,ti);       
+           gfx_new_dashed_line(im->canvas,X0,Y0+1, X0,Y1-1,GRIDWIDTH,
+               im->graph_col[GRC_GRID],
+               im->grid_dash_on, im->grid_dash_off);
+           
+        }
     }
 
     /* paint the major grid */
@@ -1771,7 +1820,8 @@ vertical_grid(
        if (ti < im->start || ti > im->end) continue;
 
 #if HAVE_STRFTIME
-       strftime(graph_label,99,im->xlab_user.stst,localtime(&tilab));
+       localtime_r(&tilab, &tm);
+       strftime(graph_label,99,im->xlab_user.stst, &tm);
 #else
 # error "your libc has no strftime I guess we'll abort the exercise here."
 #endif
@@ -1872,24 +1922,25 @@ grid_paint(image_desc_t   *im)
     }
 
     /* yaxis description */
-       if (im->canvas->imgformat != IF_PNG) {
+/*     if (im->canvas->imgformat != IF_PNG) {*/
+       if (1) {
            gfx_new_text( im->canvas,
                          7, (im->yorigin - im->ysize/2),
                          im->graph_col[GRC_FONT],
                          im->text_prop[TEXT_PROP_AXIS].font,
-                         im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 270.0,
-                         GFX_H_CENTER, GFX_V_CENTER,
+                         im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 
+                         RRDGRAPH_YLEGEND_ANGLE,
+                         GFX_H_LEFT, GFX_V_CENTER,
                          im->ylegend);
        } else {
            /* horrible hack until we can actually print vertically */
            {
                int n;
-               int l=strlen(im->ylegend);
                char s[2];
-               for (n=0;n<strlen(im->ylegend);n++) {
+               for (n=0;n< (int)strlen(im->ylegend);n++) {
                    s[0]=im->ylegend[n];
                    s[1]='\0';
-                   gfx_new_text(im->canvas,7,im->text_prop[TEXT_PROP_AXIS].size*(l-n),
+                   gfx_new_text(im->canvas,7,im->text_prop[TEXT_PROP_AXIS].size*(n+1),
                        im->graph_col[GRC_FONT],
                        im->text_prop[TEXT_PROP_AXIS].font,
                        im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 270.0,
@@ -1909,7 +1960,7 @@ grid_paint(image_desc_t   *im)
                  im->title);
 
     /* graph labels */
-    if( !(im->extra_flags & NOLEGEND) ) {
+    if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) {
       for(i=0;i<im->gdes_c;i++){
        if(im->gdes[i].legend[0] =='\0')
            continue;
@@ -1925,7 +1976,7 @@ grid_paint(image_desc_t   *im)
                    boxH = gfx_get_text_width(im->canvas, 0,
                                im->text_prop[TEXT_PROP_AXIS].font,
                                im->text_prop[TEXT_PROP_AXIS].size,
-                               im->tabwidth,"M") * 1.25;
+                               im->tabwidth,"M", 0) * 1.25;
                    boxV = boxH;
 
                    node = gfx_new_area(im->canvas,
@@ -2061,11 +2112,20 @@ graph_size_location(image_desc_t *im, int elements, int piechart )
 #if 0
        Xlegend  =0,    Ylegend  =0,
 #endif
-       Xspacing =10,   Yspacing =10;
+        Xspacing =10,  Yspacing =10;
 
-    if (im->ylegend[0] != '\0') {
-       Xvertical = im->text_prop[TEXT_PROP_LEGEND].size *2;
-       Yvertical = im->text_prop[TEXT_PROP_LEGEND].size * (strlen(im->ylegend)+1);
+    if (im->extra_flags & ONLY_GRAPH) {
+        if ( im->ysize > 32 ) {
+           rrd_set_error("height > 32 is not possible with --only-graph option");
+           return -1;
+        }
+       Xspacing =0;
+        Yspacing =0;
+    } else {
+        if (im->ylegend[0] != '\0') {
+           Xvertical = im->text_prop[TEXT_PROP_LEGEND].size *2;
+           Yvertical = im->text_prop[TEXT_PROP_LEGEND].size * (strlen(im->ylegend)+1);
+        }
     }
 
     if (im->title[0] != '\0') {
@@ -2077,7 +2137,7 @@ graph_size_location(image_desc_t *im, int elements, int piechart )
                im->text_prop[TEXT_PROP_TITLE].font,
                im->text_prop[TEXT_PROP_TITLE].size,
                im->tabwidth,
-               im->title) + 2*Xspacing;
+               im->title, 0) + 2*Xspacing;
        Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2;
     }
 
@@ -2111,10 +2171,21 @@ graph_size_location(image_desc_t *im, int elements, int piechart )
     ** forget about it at all; the legend will have to fit in the
     ** size already allocated.
     */
-    im->ximg = Xylabel + Xmain + Xpie + Xspacing;
+    im->ximg = Xmain;
+
+    if ( !(im->extra_flags & ONLY_GRAPH) ) {
+        im->ximg = Xylabel + Xmain + Xpie + Xspacing;
+    }
+
     if (Xmain) im->ximg += Xspacing;
     if (Xpie) im->ximg += Xspacing;
-    im->xorigin = Xspacing + Xylabel;
+
+    if (im->extra_flags & ONLY_GRAPH) {
+       im->xorigin = 0;
+    } else {
+       im->xorigin = Xspacing + Xylabel;
+    }
+
     if (Xtitle > im->ximg) im->ximg = Xtitle;
     if (Xvertical) {
        im->ximg += Xvertical;
@@ -2132,9 +2203,21 @@ graph_size_location(image_desc_t *im, int elements, int piechart )
     */
 
     /* reserve space for main and/or pie */
-    im->yimg = Ymain + Yxlabel;
+
+    if (im->extra_flags & ONLY_GRAPH) {
+        im->yimg = Ymain;
+    } else {
+        im->yimg = Ymain + Yxlabel;
+    }
+
     if (im->yimg < Ypie) im->yimg = Ypie;
-    im->yorigin = im->yimg - Yxlabel;
+
+    if (im->extra_flags & ONLY_GRAPH) {
+        im->yorigin = im->yimg;
+    } else {
+        im->yorigin = im->yimg - Yxlabel;
+    }
+
     /* reserve space for the title *or* some padding above the graph */
     if (Ytitle) {
        im->yimg += Ytitle;
@@ -2192,15 +2275,15 @@ graph_paint(image_desc_t *im, char ***calcpr)
   double areazero = 0.0;
   enum gf_en stack_gf = GF_PRINT;
   graph_desc_t *lastgdes = NULL;    
-  
+
   /* if we are lazy and there is nothing to PRINT ... quit now */
   if (lazy && im->prt_c==0) return 0;
-  
+
   /* pull the data from the rrd files ... */
   
   if(data_fetch(im)==-1)
     return -1;
-  
+
   /* evaluate VDEF and CDEF operations ... */
   if(data_calc(im)==-1)
     return -1;
@@ -2237,9 +2320,11 @@ graph_paint(image_desc_t *im, char ***calcpr)
 
   if (!calc_horizontal_grid(im))
     return -1;
+
   if (im->gridfit)
     apply_gridfit(im);
 
+
 /**************************************************************
  *** Calculating sizes and locations became a bit confusing ***
  *** so I moved this into a separate function.              ***
@@ -2271,8 +2356,8 @@ graph_paint(image_desc_t *im, char ***calcpr)
       areazero = im->minval;
     if (im->maxval < 0.0)
       areazero = im->maxval;
-  
-    axis_paint(im);
+    if( !(im->extra_flags & ONLY_GRAPH) )  
+      axis_paint(im);
   }
 
   if (piechart) {
@@ -2290,6 +2375,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
     case GF_HRULE:
     case GF_VRULE:
     case GF_XPORT:
+    case GF_SHIFT:
       break;
     case GF_TICK:
       for (ii = 0; ii < im->xsize; ii++)
@@ -2396,14 +2482,11 @@ graph_paint(image_desc_t *im, char ***calcpr)
       /* 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])) {
-          double ybase = 0.0;
-          if (lastgdes) {
-            ybase = ytr(im,lastgdes->p_data[ii-1]);
-          };
-          if (isnan(ybase) || !lastgdes ){
-            ybase =  ytr(im,areazero);
+          if (lastgdes && (im->gdes[i].gf == GF_STACK)) {
+            im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
+          } else {
+            im->gdes[i].p_data[ii] =  ytr(im,areazero);
           }
-          im->gdes[i].p_data[ii] = ybase;
         }
       } 
       lastgdes = &(im->gdes[i]);                         
@@ -2427,7 +2510,8 @@ graph_paint(image_desc_t *im, char ***calcpr)
     im->draw_y_grid=0;
   }
   /* grid_paint also does the text */
-  grid_paint(im);
+  if( !(im->extra_flags & ONLY_GRAPH) )  
+    grid_paint(im);
   
   /* the RULES are the last thing to paint ... */
   for(i=0;i<im->gdes_c;i++){    
@@ -2462,15 +2546,15 @@ graph_paint(image_desc_t *im, char ***calcpr)
 
   
   if (strcmp(im->graphfile,"-")==0) {
+    fo = im->graphhandle ? im->graphhandle : stdout;
 #ifdef WIN32
     /* Change translation mode for stdout to BINARY */
-    _setmode( _fileno( stdout ), O_BINARY );
+    _setmode( _fileno( fo ), O_BINARY );
 #endif
-    fo = stdout;
   } else {
     if ((fo = fopen(im->graphfile,"wb")) == NULL) {
       rrd_set_error("Opening '%s' for write: %s",im->graphfile,
-                    strerror(errno));
+                    rrd_strerror(errno));
       return (-1);
     }
   }
@@ -2488,13 +2572,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
 int
 gdes_alloc(image_desc_t *im){
 
-    long def_step = (im->end-im->start)/im->xsize;
-    
-    if (im->step > def_step) /* step can be increassed ... no decreassed */
-      def_step = im->step;
-
     im->gdes_c++;
-    
     if ((im->gdes = (graph_desc_t *) rrd_realloc(im->gdes, (im->gdes_c)
                                           * sizeof(graph_desc_t)))==NULL){
        rrd_set_error("realloc graph_descs");
@@ -2502,7 +2580,7 @@ gdes_alloc(image_desc_t *im){
     }
 
 
-    im->gdes[im->gdes_c-1].step=def_step; 
+    im->gdes[im->gdes_c-1].step=im->step;
     im->gdes[im->gdes_c-1].stack=0;
     im->gdes[im->gdes_c-1].debug=0;
     im->gdes[im->gdes_c-1].start=im->start; 
@@ -2513,6 +2591,7 @@ gdes_alloc(image_desc_t *im){
     im->gdes[im->gdes_c-1].data_first=0;
     im->gdes[im->gdes_c-1].p_data=NULL;
     im->gdes[im->gdes_c-1].rpnp=NULL;
+    im->gdes[im->gdes_c-1].shift=0;
     im->gdes[im->gdes_c-1].col = 0x0;
     im->gdes[im->gdes_c-1].legend[0]='\0';
     im->gdes[im->gdes_c-1].rrd[0]='\0';
@@ -2554,12 +2633,13 @@ scan_for_col(char *input, int len, char *output)
 ** - script parsing   now in rrd_graph_script()
 */
 int 
-rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
+rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *stream)
 {
     image_desc_t   im;
             
     rrd_graph_init(&im);
-
+    im.graphhandle = stream;
+    
     rrd_graph_options(argc,argv,&im);
     if (rrd_test_error()) {
        im_free(&im);
@@ -2574,7 +2654,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
     strncpy(im.graphfile,argv[optind],MAXPATH-1);
     im.graphfile[MAXPATH-1]='\0';
 
-    rrd_graph_script(argc,argv,&im);
+    rrd_graph_script(argc,argv,&im,1);
     if (rrd_test_error()) {
        im_free(&im);
        return -1;
@@ -2623,7 +2703,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
 void
 rrd_graph_init(image_desc_t *im)
 {
-    int i;
+    unsigned int i;
 
 #ifdef HAVE_TZSET
     tzset();
@@ -2662,7 +2742,19 @@ rrd_graph_init(image_desc_t *im)
 
     for(i=0;i<DIM(graph_col);i++)
         im->graph_col[i]=graph_col[i];
-
+#ifdef WIN32
+    {
+    char *windir; 
+    windir = getenv("windir");
+    /* %windir% is something like D:\windows or C:\winnt */
+    if (windir != NULL) {
+        strcpy(rrd_win_default_font,windir);
+        strcat(rrd_win_default_font,"\\fonts\\cour.ttf");
+        for(i=0;i<DIM(text_prop);i++)
+           text_prop[i].font = rrd_win_default_font;
+    }
+    }
+#endif
     for(i=0;i<DIM(text_prop);i++){        
       im->text_prop[i].size = text_prop[i].size;
       im->text_prop[i].font = text_prop[i].font;
@@ -2677,7 +2769,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
     char               scan_gtm[12],scan_mtm[12],scan_ltm[12],col_nam[12];
     time_t             start_tmp=0,end_tmp=0;
     long               long_tmp;
-    struct time_value  start_tv, end_tv;
+    struct rrd_time_value      start_tv, end_tv;
     gfx_color_t         color;
 
     parsetime("end-24h", &start_tv);
@@ -2707,41 +2799,49 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            {"lazy",       no_argument,       0,  'z'},
             {"zoom",       required_argument, 0,  'm'},
            {"no-legend",  no_argument,       0,  'g'},
-           {"alt-y-grid", no_argument,       0,   257 },
-           {"alt-autoscale", no_argument,    0,   258 },
-           {"alt-autoscale-max", no_argument,    0,   259 },
-           {"units-exponent",required_argument, 0,  260},
-           {"step",       required_argument, 0,   261},
-           {"no-gridfit", no_argument,       0,   262},
+            {"only-graph", no_argument,       0,  'j'},
+           {"alt-y-grid", no_argument,       0,  'Y'},
+            {"no-minor",   no_argument,       0,  'I'},
+           {"alt-autoscale", no_argument,    0,  'A'},
+           {"alt-autoscale-max", no_argument, 0, 'M'},
+           {"units-exponent",required_argument, 0, 'X'},
+           {"step",       required_argument, 0,    'S'},
+           {"no-gridfit", no_argument,       0,   'N'},
            {0,0,0,0}};
        int option_index = 0;
        int opt;
 
 
        opt = getopt_long(argc, argv, 
-                         "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:z:g",
+                         "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjYAMX:S:N",
                          long_options, &option_index);
 
        if (opt == EOF)
            break;
        
        switch(opt) {
-       case 257:
+        case 'I':
+            im->extra_flags |= NOMINOR;
+            break;
+       case 'Y':
            im->extra_flags |= ALTYGRID;
            break;
-       case 258:
+       case 'A':
            im->extra_flags |= ALTAUTOSCALE;
            break;
-       case 259:
+       case 'M':
            im->extra_flags |= ALTAUTOSCALE_MAX;
            break;
+       case 'j':
+           im->extra_flags |= ONLY_GRAPH;
+           break;
        case 'g':
            im->extra_flags |= NOLEGEND;
            break;
-       case 260:
+       case 'X':
            im->unitsexponent = atoi(optarg);
            break;
-       case 261:
+       case 'S':
            im->step =  atoi(optarg);
            break;
        case 262:
@@ -2776,13 +2876,13 @@ 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);
-               if((im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
+               if((int)(im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1){
                    rrd_set_error("unknown keyword %s",scan_gtm);
                    return;
-               } else if ((im->xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1){
+               } else if ((int)(im->xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1){
                    rrd_set_error("unknown keyword %s",scan_mtm);
                    return;
-               } else if ((im->xlab_user.labtm = tmt_conv(scan_ltm)) == -1){
+               } else if ((int)(im->xlab_user.labtm = tmt_conv(scan_ltm)) == -1){
                    rrd_set_error("unknown keyword %s",scan_ltm);
                    return;
                } 
@@ -2859,7 +2959,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            im->imginfo = optarg;
            break;
        case 'a':
-           if((im->canvas->imgformat = if_conv(optarg)) == -1) {
+           if((int)(im->canvas->imgformat = if_conv(optarg)) == -1) {
                rrd_set_error("unsupported graphics format '%s'",optarg);
                return;
            }
@@ -2977,6 +3077,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
     
     im->start = start_tmp;
     im->end = end_tmp;
+    im->step = max((long)im->step, (im->end-im->start)/im->xsize);
 }
 
 int
@@ -3064,9 +3165,9 @@ int bad_format(char *fmt) {
                  if (*ptr == '.') ptr++;
                  while (*ptr >= '0' && *ptr <= '9') ptr++;
   
-                 /* Either 'le' or 'lf' must follow here */
+                 /* Either 'le', 'lf' or 'lg' must follow here */
                  if (*ptr++ != 'l') return 1;
-                 if (*ptr == 'e' || *ptr == 'f') ptr++;
+                 if (*ptr == 'e' || *ptr == 'f' || *ptr == 'g') ptr++;
                  else return 1;
                  n++;
             }
@@ -3090,12 +3191,12 @@ char *str;
     
     n=0;
     sscanf(str,"%le,%29[A-Z]%n",&param,func,&n);
-    if (n==strlen(str)) { /* matched */
+    if (n== (int)strlen(str)) { /* matched */
        ;
     } else {
        n=0;
        sscanf(str,"%29[A-Z]%n",func,&n);
-       if (n==strlen(str)) { /* matched */
+       if (n== (int)strlen(str)) { /* matched */
            param=DNAN;
        } else {
            rrd_set_error("Unknown function string '%s' in VDEF '%s'"
@@ -3204,6 +3305,7 @@ printf("DEBUG: start == %lu, end == %lu, %lu steps\n"
                field = (steps-1)*dst->vf.param/100;
                dst->vf.val  = array[field];
                dst->vf.when = 0;       /* no time component */
+               free(array);
 #if 0
 for(step=0;step<steps;step++)
 printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' ');