yes this should not matter, but I think it is the right thing todo ...
[rrdtool.git] / src / rrd_graph.c
index a0e3ddc..323fec6 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * RRDtool 1.3rc4  Copyright by Tobi Oetiker, 1997-2008
+ * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2008
  ****************************************************************************
  * rrd__graph.c  produce graphs from data in rrdfiles
  ****************************************************************************/
 #ifdef WIN32
 #include "strftime.h"
 #endif
+
 #include "rrd_tool.h"
 
+/* for basename */
+#ifdef HAVE_LIBGEN_H
+#  include <libgen.h>
+#else
+#include "plbasename.h"
+#endif
+
 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #include <fcntl.h>
@@ -26,6 +34,7 @@
 #endif
 
 #include "rrd_graph.h"
+#include "rrd_client.h"
 
 /* some constant definitions */
 
 #endif
 
 text_prop_t text_prop[] = {
-    {8.0, RRD_DEFAULT_FONT}
+    {8.0, RRD_DEFAULT_FONT,NULL}
     ,                   /* default */
-    {9.0, RRD_DEFAULT_FONT}
+    {9.0, RRD_DEFAULT_FONT,NULL}
     ,                   /* title */
-    {7.0, RRD_DEFAULT_FONT}
+    {7.0, RRD_DEFAULT_FONT,NULL}
     ,                   /* axis */
-    {8.0, RRD_DEFAULT_FONT}
+    {8.0, RRD_DEFAULT_FONT,NULL}
     ,                   /* unit */
-    {8.0, RRD_DEFAULT_FONT} /* legend */
+    {8.0, RRD_DEFAULT_FONT,NULL} /* legend */
+    ,
+    {5.5, RRD_DEFAULT_FONT,NULL} /* watermark */    
 };
 
 xlab_t    xlab[] = {
@@ -232,7 +243,7 @@ enum gf_en gf_conv(
     conv_if(XPORT, GF_XPORT);
     conv_if(SHIFT, GF_SHIFT);
 
-    return (-1);
+    return (enum gf_en)(-1);
 }
 
 enum gfx_if_en if_conv(
@@ -244,7 +255,7 @@ enum gfx_if_en if_conv(
     conv_if(EPS, IF_EPS);
     conv_if(PDF, IF_PDF);
 
-    return (-1);
+    return (enum gfx_if_en)(-1);
 }
 
 enum tmt_en tmt_conv(
@@ -258,7 +269,7 @@ enum tmt_en tmt_conv(
     conv_if(WEEK, TMT_WEEK);
     conv_if(MONTH, TMT_MONTH);
     conv_if(YEAR, TMT_YEAR);
-    return (-1);
+    return (enum tmt_en)(-1);
 }
 
 enum grc_en grc_conv(
@@ -276,7 +287,7 @@ enum grc_en grc_conv(
     conv_if(AXIS, GRC_AXIS);
     conv_if(FRAME, GRC_FRAME);
 
-    return -1;
+    return (enum grc_en)(-1);
 }
 
 enum text_prop_en text_prop_conv(
@@ -288,7 +299,8 @@ enum text_prop_en text_prop_conv(
     conv_if(AXIS, TEXT_PROP_AXIS);
     conv_if(UNIT, TEXT_PROP_UNIT);
     conv_if(LEGEND, TEXT_PROP_LEGEND);
-    return -1;
+    conv_if(WATERMARK, TEXT_PROP_WATERMARK);
+    return (enum text_prop_en)(-1);
 }
 
 
@@ -298,10 +310,14 @@ int im_free(
     image_desc_t *im)
 {
     unsigned long i, ii;
-    cairo_status_t status = 0;
+    cairo_status_t status = (cairo_status_t) 0;
 
     if (im == NULL)
         return 0;
+
+    if (im->daemon_addr != NULL)
+      free(im->daemon_addr);
+
     for (i = 0; i < (unsigned) im->gdes_c; i++) {
         if (im->gdes[i].data_first) {
             /* careful here, because a single pointer can occur several times */
@@ -330,12 +346,18 @@ int im_free(
     if (im->rendered_image) {
         free(im->rendered_image);
     }
+
+    if (im->layout) {
+        g_object_unref (im->layout);
+    }
+
     if (im->surface)
         cairo_surface_destroy(im->surface);
+
     if (status)
         fprintf(stderr, "OOPS: Cairo has issues it can't even die: %s\n",
                 cairo_status_to_string(status));
-
+        
     return 0;
 }
 
@@ -412,7 +434,7 @@ void si_unit(
 
     if (im->unitsexponent != 9999) {
         /* unitsexponent = 9, 6, 3, 0, -3, -6, -9, etc */
-        viewdigits = floor(im->unitsexponent / 3);
+        viewdigits = floor((double)(im->unitsexponent / 3));
     } else {
         viewdigits = digits;
     }
@@ -824,6 +846,36 @@ int data_fetch(
         if (!skip) {
             unsigned long ft_step = im->gdes[i].step;   /* ft_step will record what we got from fetch */
 
+            /* Flush the file if
+             * - a connection to the daemon has been established
+             * - this is the first occurrence of that RRD file
+             */
+            if (rrdc_is_connected(im->daemon_addr))
+            {
+                int status;
+
+                status = 0;
+                for (ii = 0; ii < i; ii++)
+                {
+                    if (strcmp (im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
+                    {
+                        status = 1;
+                        break;
+                    }
+                }
+
+                if (status == 0)
+                {
+                    status = rrdc_flush (im->gdes[i].rrd);
+                    if (status != 0)
+                    {
+                        rrd_set_error ("rrdc_flush (%s) failed with status %i.",
+                                im->gdes[i].rrd, status);
+                        return (-1);
+                    }
+                }
+            } /* if (rrdc_is_connected()) */
+
             if ((rrd_fetch_fn(im->gdes[i].rrd,
                               im->gdes[i].cf,
                               &im->gdes[i].start,
@@ -894,7 +946,7 @@ long find_var(
     return -1;
 }
 
-/* find the largest common denominator for all the numbers
+/* find the greatest common divisor for all the numbers
    in the 0 terminated num array */
 long lcd(
     long *num)
@@ -1008,7 +1060,7 @@ int data_calc(
                         /* add one entry to the array that keeps track of the step sizes of the
                          * data sources going into the CDEF. */
                         if ((steparray =
-                             rrd_realloc(steparray,
+                             (long*)rrd_realloc(steparray,
                                          (++stepcnt +
                                           1) * sizeof(*steparray))) == NULL) {
                             rrd_set_error("realloc steparray");
@@ -1076,7 +1128,7 @@ int data_calc(
              */
             im->gdes[gdi].step = lcd(steparray);
             free(steparray);
-            if ((im->gdes[gdi].data = malloc(((im->gdes[gdi].end -
+            if ((im->gdes[gdi].data = (rrd_value_t*)malloc(((im->gdes[gdi].end -
                                                im->gdes[gdi].start)
                                               / im->gdes[gdi].step)
                                              * sizeof(double))) == NULL) {
@@ -1166,7 +1218,7 @@ int data_proc(
     for (i = 0; i < im->gdes_c; i++) {
         if ((im->gdes[i].gf == GF_LINE) ||
             (im->gdes[i].gf == GF_AREA) || (im->gdes[i].gf == GF_TICK)) {
-            if ((im->gdes[i].p_data = malloc((im->xsize + 1)
+            if ((im->gdes[i].p_data = (rrd_value_t*)malloc((im->xsize + 1)
                                              * sizeof(rrd_value_t))) == NULL) {
                 rrd_set_error("malloc data_proc");
                 return -1;
@@ -1520,10 +1572,10 @@ int print_calc(
             }
 
             if (im->gdes[i].gf == GF_PRINT) {
-                infoval   prline;
+                rrd_infoval_t prline;
 
                 if (im->gdes[i].strftm) {
-                    prline.u_str = malloc((FMT_LEG_LEN + 2) * sizeof(char));
+                    prline.u_str = (char*)malloc((FMT_LEG_LEN + 2) * sizeof(char));
                     strftime(prline.u_str,
                              FMT_LEG_LEN, im->gdes[i].format, &tmvdef);
                 } else if (bad_format(im->gdes[i].format)) {
@@ -1602,35 +1654,49 @@ int print_calc(
 }
 
 
+
 /* place legends with color spots */
 int leg_place(
     image_desc_t *im,
-    int *gY)
+    int calc_width)
 {
     /* graph labels */
     int       interleg = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
     int       border = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
     int       fill = 0, fill_last;
+    double    legendwidth; // = im->ximg - 2 * border;
     int       leg_c = 0;
-    int       leg_x = border, leg_y = im->yimg;
-    int       leg_y_prev = im->yimg;
+    double    leg_x = border;
+    int       leg_y = 0; //im->yimg;
+    int       leg_y_prev = 0; // im->yimg;
     int       leg_cc;
-    int       glue = 0;
+    double    glue = 0;
     int       i, ii, mark = 0;
-    char      prt_fctn; /*special printfunctions */
     char      default_txtalign = TXA_JUSTIFIED; /*default line orientation */
     int      *legspace;
+    char     *tab;
+    char      saved_legend[FMT_LEG_LEN + 5];
+
+    if(calc_width){
+        legendwidth = 0;
+    }
+    else{
+        legendwidth = im->legendwidth - 2 * border;
+    }
+
 
     if (!(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH)) {
-        if ((legspace = malloc(im->gdes_c * sizeof(int))) == NULL) {
+        if ((legspace = (int*)malloc(im->gdes_c * sizeof(int))) == NULL) {
             rrd_set_error("malloc for legspace");
             return -1;
         }
 
-        if (im->extra_flags & FULL_SIZE_MODE)
-            leg_y = leg_y_prev =
-                leg_y - (int) (im->text_prop[TEXT_PROP_LEGEND].size * 1.8);
         for (i = 0; i < im->gdes_c; i++) {
+            char      prt_fctn; /*special printfunctions */
+            if(calc_width){
+                strcpy(saved_legend, im->gdes[i].legend);
+            }
+
             fill_last = fill;
             /* hide legends for rules which are not displayed */
             if (im->gdes[i].gf == GF_TEXTALIGN) {
@@ -1648,13 +1714,15 @@ int leg_place(
                     im->gdes[i].legend[0] = '\0';
             }
 
+            /* turn \\t into tab */
+            while ((tab = strstr(im->gdes[i].legend, "\\t"))) {
+                memmove(tab, tab + 1, strlen(tab));
+                tab[0] = (char) 9;
+            }
+
             leg_cc = strlen(im->gdes[i].legend);
-            /* is there a controle code ant the end of the legend string ? */
-            /* and it is not a tab \\t */
-            if (leg_cc >= 2
-                && im->gdes[i].legend[leg_cc -
-                                      2] == '\\'
-                && im->gdes[i].legend[leg_cc - 1] != 't') {
+            /* is there a controle code at the end of the legend string ? */
+            if (leg_cc >= 2 && im->gdes[i].legend[leg_cc - 2] == '\\') {
                 prt_fctn = im->gdes[i].legend[leg_cc - 1];
                 leg_cc -= 2;
                 im->gdes[i].legend[leg_cc] = '\0';
@@ -1666,8 +1734,7 @@ int leg_place(
                 prt_fctn != 'r' &&
                 prt_fctn != 'j' &&
                 prt_fctn != 'c' &&
-                prt_fctn != 's' &&
-                prt_fctn != 't' && prt_fctn != '\0' && prt_fctn != 'g') {
+                prt_fctn != 's' && prt_fctn != '\0' && prt_fctn != 'g') {
                 free(legspace);
                 rrd_set_error
                     ("Unknown control code at the end of '%s\\%c'",
@@ -1699,11 +1766,7 @@ int leg_place(
                                        im->
                                        text_prop
                                        [TEXT_PROP_LEGEND].
-                                       font,
-                                       im->
-                                       text_prop
-                                       [TEXT_PROP_LEGEND].
-                                       size,
+                                       font_desc,
                                        im->tabwidth, im->gdes[i].legend);
                 leg_c++;
             } else {
@@ -1715,7 +1778,10 @@ int leg_place(
             }
 
             if (prt_fctn == '\0') {
-                if (i == im->gdes_c - 1 || fill > im->ximg - 2 * border) {
+                if(calc_width && (fill > legendwidth)){
+                    legendwidth = fill;
+                }
+                if (i == im->gdes_c - 1 || fill > legendwidth) {
                     /* just one legend item is left right or center */
                     switch (default_txtalign) {
                     case TXA_RIGHT:
@@ -1733,7 +1799,7 @@ int leg_place(
                     }
                 }
                 /* is it time to place the legends ? */
-                if (fill > im->ximg - 2 * border) {
+                if (fill > legendwidth) {
                     if (leg_c > 1) {
                         /* go back one */
                         i--;
@@ -1746,67 +1812,56 @@ int leg_place(
                 }
             }
 
-
             if (prt_fctn != '\0') {
                 leg_x = border;
                 if (leg_c >= 2 && prt_fctn == 'j') {
-                    glue = (im->ximg - fill - 2 * border) / (leg_c - 1);
+                    glue = (double)(legendwidth - fill) / (double)(leg_c - 1);
                 } else {
                     glue = 0;
                 }
                 if (prt_fctn == 'c')
-                    leg_x = (im->ximg - fill) / 2.0;
+                    leg_x = (double)(legendwidth - fill) / 2.0;
                 if (prt_fctn == 'r')
-                    leg_x = im->ximg - fill - border;
+                    leg_x = legendwidth - fill - border;
                 for (ii = mark; ii <= i; ii++) {
                     if (im->gdes[ii].legend[0] == '\0')
                         continue;   /* skip empty legends */
                     im->gdes[ii].leg_x = leg_x;
-                    im->gdes[ii].leg_y = leg_y;
+                    im->gdes[ii].leg_y = leg_y + border;
                     leg_x +=
-                        gfx_get_text_width(im, leg_x,
-                                           im->
-                                           text_prop
-                                           [TEXT_PROP_LEGEND].
-                                           font,
+                        (double)gfx_get_text_width(im, leg_x,
                                            im->
                                            text_prop
                                            [TEXT_PROP_LEGEND].
-                                           size,
+                                           font_desc,
                                            im->tabwidth, im->gdes[ii].legend)
-                        + legspace[ii]
+                        +(double)legspace[ii]
                         + glue;
                 }
                 leg_y_prev = leg_y;
-                if (im->extra_flags & FULL_SIZE_MODE) {
-                    /* only add y space if there was text on the line */
-                    if (leg_x > border || prt_fctn == 's')
-                        leg_y -= im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
-                    if (prt_fctn == 's')
-                        leg_y += im->text_prop[TEXT_PROP_LEGEND].size;
-                } else {
-                    if (leg_x > border || prt_fctn == 's')
-                        leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
-                    if (prt_fctn == 's')
-                        leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+                if (leg_x > border || prt_fctn == 's')
+                    leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                if (prt_fctn == 's')
+                    leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+
+                if(calc_width && (fill > legendwidth)){
+                    legendwidth = fill;
                 }
                 fill = 0;
                 leg_c = 0;
                 mark = ii;
             }
-        }
 
-        if (im->extra_flags & FULL_SIZE_MODE) {
-            if (leg_y != leg_y_prev) {
-                *gY = leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
-                im->yorigin =
-                    leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+            if(calc_width){
+                strcpy(im->gdes[i].legend, saved_legend);
             }
-        } else {
-            im->yimg = leg_y_prev;
-            /* if we did place some legends we have to add vertical space */
-            if (leg_y != im->yimg)
-                im->yimg += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+        }
+
+        if(calc_width){
+            im->legendwidth = legendwidth + 2 * border;
+        }
+        else{
+            im->legendheight = leg_y + border * 0.6;
         }
         free(legspace);
     }
@@ -1819,8 +1874,6 @@ int leg_place(
 /* the xaxis labels are determined from the number of seconds per pixel
    in the requested graph */
 
-
-
 int calc_horizontal_grid(
     image_desc_t
     *im)
@@ -1858,13 +1911,16 @@ int calc_horizontal_grid(
             if (im->ygrid_scale.gridstep == 0)  /* range is one -> 0.1 is reasonable scale */
                 im->ygrid_scale.gridstep = 0.1;
             /* should have at least 5 lines but no more then 15 */
-            if (range / im->ygrid_scale.gridstep < 5)
+            if (range / im->ygrid_scale.gridstep < 5
+                && im->ygrid_scale.gridstep >= 30)
                 im->ygrid_scale.gridstep /= 10;
             if (range / im->ygrid_scale.gridstep > 15)
                 im->ygrid_scale.gridstep *= 10;
             if (range / im->ygrid_scale.gridstep > 5) {
                 im->ygrid_scale.labfact = 1;
-                if (range / im->ygrid_scale.gridstep > 8)
+                if (range / im->ygrid_scale.gridstep > 8
+                    || im->ygrid_scale.gridstep <
+                    1.8 * im->text_prop[TEXT_PROP_AXIS].size)
                     im->ygrid_scale.labfact = 2;
             } else {
                 im->ygrid_scale.gridstep /= 5;
@@ -1891,17 +1947,17 @@ int calc_horizontal_grid(
                 sprintf(im->ygrid_scale.labfmt,
                         "%%%d.0f%s", len, (im->symbol != ' ' ? " %c" : ""));
             }
-        } else {
+        } else {        /* classic rrd grid */
             for (i = 0; ylab[i].grid > 0; i++) {
                 pixel = im->ysize / (scaledrange / ylab[i].grid);
                 gridind = i;
-                if (pixel > 7)
+                if (pixel >= 5)
                     break;
             }
 
             for (i = 0; i < 4; i++) {
                 if (pixel * ylab[gridind].lfac[i] >=
-                    2.5 * im->text_prop[TEXT_PROP_AXIS].size) {
+                    1.8 * im->text_prop[TEXT_PROP_AXIS].size) {
                     im->ygrid_scale.labfact = ylab[gridind].lfac[i];
                     break;
                 }
@@ -1929,7 +1985,9 @@ int draw_horizontal_grid(
     int       sgrid = (int) (im->minval / im->ygrid_scale.gridstep - 1);
     int       egrid = (int) (im->maxval / im->ygrid_scale.gridstep + 1);
     double    MaxY;
-
+    double second_axis_magfact = 0;
+    char *second_axis_symb = "";
+    
     scaledstep =
         im->ygrid_scale.gridstep /
         (double) im->magfact * (double) im->viewfactor;
@@ -1980,6 +2038,33 @@ int draw_horizontal_grid(
                     }
                 }
                 nlabels++;
+                if (im->second_axis_scale != 0){
+                        char graph_label_right[100];
+                        double sval = im->ygrid_scale.gridstep*(double)i*im->second_axis_scale+im->second_axis_shift;
+                        if (im->second_axis_format[0] == '\0'){
+                            if (!second_axis_magfact){
+                                double dummy = im->ygrid_scale.gridstep*(double)(sgrid+egrid)/2.0*im->second_axis_scale+im->second_axis_shift;
+                                auto_scale(im,&dummy,&second_axis_symb,&second_axis_magfact);
+                            }
+                            sval /= second_axis_magfact;
+                            if(MaxY < 10) { 
+                                sprintf(graph_label_right,"%5.1f %s",sval,second_axis_symb);
+                            } else {
+                                sprintf(graph_label_right,"%5.0f %s",sval,second_axis_symb);
+                            }
+                        }
+                        else {
+                           sprintf(graph_label_right,im->second_axis_format,sval);
+                        }        
+                        gfx_text ( im,
+                               X1+7, Y0,
+                               im->graph_col[GRC_FONT],
+                               im->text_prop[TEXT_PROP_AXIS].font_desc,
+                               im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER,
+                               graph_label_right );
+                }
                 gfx_text(im,
                          X0 -
                          im->
@@ -1988,10 +2073,8 @@ int draw_horizontal_grid(
                          im->graph_col[GRC_FONT],
                          im->
                          text_prop[TEXT_PROP_AXIS].
-                         font,
-                         im->
-                         text_prop[TEXT_PROP_AXIS].
-                         size, im->tabwidth, 0.0,
+                         font_desc,
+                         im->tabwidth, 0.0,
                          GFX_H_RIGHT, GFX_V_CENTER, graph_label);
                 gfx_line(im, X0 - 2, Y0, X0, Y0,
                          MGRIDWIDTH, im->graph_col[GRC_MGRID]);
@@ -2033,7 +2116,7 @@ double frexp10(
     double    mnt;
     int       iexp;
 
-    iexp = floor(log(fabs(x)) / log(10));
+    iexp = floor(log((double)fabs(x)) / log((double)10));
     mnt = x / pow(10.0, iexp);
     if (mnt >= 10.0) {
         iexp++;
@@ -2159,8 +2242,35 @@ int horizontal_log_grid(
             else
                 symbol = '?';
             sprintf(graph_label, "%3.0f %c", pvalue, symbol);
-        } else
+        } else {            
             sprintf(graph_label, "%3.0e", value);
+        }
+        if (im->second_axis_scale != 0){
+                char graph_label_right[100];
+                double sval = value*im->second_axis_scale+im->second_axis_shift;
+                if (im->second_axis_format[0] == '\0'){
+                        if (im->extra_flags & FORCE_UNITS_SI) {
+                                double mfac = 1;
+                                char   *symb = "";
+                                auto_scale(im,&sval,&symb,&mfac);
+                                sprintf(graph_label_right,"%4.0f %s", sval,symb);
+                        }
+                        else {        
+                                sprintf(graph_label_right,"%3.0e", sval);
+                        }
+                }
+                else {
+                      sprintf(graph_label_right,im->second_axis_format,sval);
+                }    
+    
+                gfx_text ( im,
+                               X1+7, Y0,
+                               im->graph_col[GRC_FONT],
+                               im->text_prop[TEXT_PROP_AXIS].font_desc,
+                               im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER,
+                               graph_label_right );
+        }
+      
         gfx_text(im,
                  X0 -
                  im->
@@ -2169,10 +2279,8 @@ int horizontal_log_grid(
                  im->graph_col[GRC_FONT],
                  im->
                  text_prop[TEXT_PROP_AXIS].
-                 font,
-                 im->
-                 text_prop[TEXT_PROP_AXIS].
-                 size, im->tabwidth, 0.0,
+                 font_desc,
+                 im->tabwidth, 0.0,
                  GFX_H_RIGHT, GFX_V_CENTER, graph_label);
         /* minor grid */
         if (mid < 4 && exfrac == 1) {
@@ -2440,10 +2548,8 @@ void vertical_grid(
                  im->graph_col[GRC_FONT],
                  im->
                  text_prop[TEXT_PROP_AXIS].
-                 font,
-                 im->
-                 text_prop[TEXT_PROP_AXIS].
-                 size, im->tabwidth, 0.0,
+                 font_desc,
+                 im->tabwidth, 0.0,
                  GFX_H_CENTER, GFX_V_TOP, graph_label);
     }
 
@@ -2478,6 +2584,18 @@ void axis_paint(
     gfx_new_area(im, im->xorigin - 3, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin, im->yorigin - im->ysize - 7,  /* vertical */
                  im->graph_col[GRC_ARROW]);
     gfx_close_path(im);
+    if (im->second_axis_scale != 0){
+       gfx_line ( im, im->xorigin+im->xsize,im->yorigin+4,
+                         im->xorigin+im->xsize,im->yorigin-im->ysize-4,
+                         MGRIDWIDTH, im->graph_col[GRC_AXIS]);
+       gfx_new_area ( im, 
+                   im->xorigin+im->xsize-2,  im->yorigin-im->ysize-2,
+                   im->xorigin+im->xsize+3,  im->yorigin-im->ysize-2,
+                   im->xorigin+im->xsize,    im->yorigin-im->ysize-7, /* LINEOFFSET */
+                   im->graph_col[GRC_ARROW]);
+       gfx_close_path(im);
+    }
+
 }
 
 void grid_paint(
@@ -2521,54 +2639,67 @@ void grid_paint(
                      im->graph_col[GRC_FONT],
                      im->
                      text_prop[TEXT_PROP_AXIS].
-                     font,
-                     im->
-                     text_prop[TEXT_PROP_AXIS].
-                     size, im->tabwidth, 0.0,
+                     font_desc,
+                     im->tabwidth, 0.0,
                      GFX_H_CENTER, GFX_V_CENTER, nodata);
         }
     }
 
     /* yaxis unit description */
-    gfx_text(im,
-             10,
-             (im->yorigin -
-              im->ysize / 2),
-             im->graph_col[GRC_FONT],
-             im->
-             text_prop[TEXT_PROP_UNIT].
-             font,
-             im->
-             text_prop[TEXT_PROP_UNIT].
-             size, im->tabwidth,
-             RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend);
+    if (im->ylegend[0] != '\0'){
+        gfx_text(im,
+                 im->xOriginLegendY+10,
+                 im->yOriginLegendY,
+                 im->graph_col[GRC_FONT],
+                 im->
+                 text_prop[TEXT_PROP_UNIT].
+                 font_desc,
+                 im->tabwidth,
+                 RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend);
+
+    }
+    if (im->second_axis_legend[0] != '\0'){
+            gfx_text( im,
+                  im->xOriginLegendY2+10, 
+                  im->yOriginLegendY2,
+                  im->graph_col[GRC_FONT],
+                  im->text_prop[TEXT_PROP_UNIT].font_desc,
+                  im->tabwidth, 
+                  RRDGRAPH_YLEGEND_ANGLE,
+                  GFX_H_CENTER, GFX_V_CENTER,
+                  im->second_axis_legend);
+    }        
     /* graph title */
     gfx_text(im,
-             im->ximg / 2, 6,
+             im->xOriginTitle, im->yOriginTitle+6,
              im->graph_col[GRC_FONT],
              im->
              text_prop[TEXT_PROP_TITLE].
-             font,
-             im->
-             text_prop[TEXT_PROP_TITLE].
-             size, im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title);
+             font_desc,
+             im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title);
     /* rrdtool 'logo' */
-    water_color = im->graph_col[GRC_FONT];
-    water_color.alpha = 0.3;
-    gfx_text(im, im->ximg - 4, 5,
-             water_color,
-             im->
-             text_prop[TEXT_PROP_AXIS].
-             font, 5.5, im->tabwidth,
-             -90, GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER");
+    if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+        water_color = im->graph_col[GRC_FONT];
+        water_color.alpha = 0.3;
+        double xpos = im->legendposition == EAST ? im->xOriginLegendY : im->ximg - 4;
+        gfx_text(im, xpos, 5,
+                 water_color,
+                 im->
+                 text_prop[TEXT_PROP_WATERMARK].
+                 font_desc, im->tabwidth,
+                 -90, GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER");
+    }    
     /* graph watermark */
     if (im->watermark[0] != '\0') {
+        water_color = im->graph_col[GRC_FONT];
+        water_color.alpha = 0.3;
         gfx_text(im,
                  im->ximg / 2, im->yimg - 6,
                  water_color,
                  im->
-                 text_prop[TEXT_PROP_AXIS].
-                 font, 5.5, im->tabwidth, 0,
+                 text_prop[TEXT_PROP_WATERMARK].
+                 font_desc, im->tabwidth, 0,
                  GFX_H_CENTER, GFX_V_BOTTOM, im->watermark);
     }
 
@@ -2578,16 +2709,13 @@ void grid_paint(
             if (im->gdes[i].legend[0] == '\0')
                 continue;
             /* im->gdes[i].leg_y is the bottom of the legend */
-            X0 = im->gdes[i].leg_x;
-            Y0 = im->gdes[i].leg_y;
+            X0 = im->xOriginLegend + im->gdes[i].leg_x;
+            Y0 = im->legenddirection == TOP_DOWN ? im->yOriginLegend + im->gdes[i].leg_y : im->yOriginLegend + im->legendheight - im->gdes[i].leg_y;
             gfx_text(im, X0, Y0,
                      im->graph_col[GRC_FONT],
                      im->
                      text_prop
-                     [TEXT_PROP_LEGEND].font,
-                     im->
-                     text_prop
-                     [TEXT_PROP_LEGEND].size,
+                     [TEXT_PROP_LEGEND].font_desc,
                      im->tabwidth, 0.0,
                      GFX_H_LEFT, GFX_V_BOTTOM, im->gdes[i].legend);
             /* The legend for GRAPH items starts with "M " to have
@@ -2601,11 +2729,8 @@ void grid_paint(
                                           im->
                                           text_prop
                                           [TEXT_PROP_LEGEND].
-                                          font,
-                                          im->
-                                          text_prop
-                                          [TEXT_PROP_LEGEND].
-                                          size, im->tabwidth, "o") * 1.2;
+                                          font_desc,
+                                          im->tabwidth, "o") * 1.2;
                 boxV = boxH;
                 /* shift the box up a bit */
                 Y0 -= boxV * 0.4;
@@ -2702,13 +2827,37 @@ int graph_size_location(
     /* The actual size of the image to draw is determined from
      ** several sources.  The size given on the command line is
      ** the graph area but we need more as we have to draw labels
-     ** and other things outside the graph area
+     ** and other things outside the graph area. If the option 
+     ** --full-size-mode is selected the size defines the total 
+     ** image size and the size available for the graph is 
+     ** calculated.
      */
 
-    int       Xvertical = 0, Ytitle =
+    /** +---+-----------------------------------+
+     ** | y |...............graph title.........|
+     ** |   +---+-------------------------------+
+     ** | a | y |                               |
+     ** | x |   |                               |
+     ** | i | a |                               |    
+     ** | s | x |       main graph area         |
+     ** |   | i |                               |
+     ** | t | s |                               |
+     ** | i |   |                               |
+     ** | t | l |                               |
+     ** | l | b +-------------------------------+
+     ** | e | l |       x axis labels           |
+     ** +---+---+-------------------------------+
+     ** |....................legends............|
+     ** +---------------------------------------+
+     ** |                   watermark           |
+     ** +---------------------------------------+
+     */
+
+    int       Xvertical = 0, Xvertical2 = 0, Ytitle =
         0, Xylabel = 0, Xmain = 0, Ymain =
         0, Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4;
 
+    // no legends and no the shall be plotted it's easy
     if (im->extra_flags & ONLY_GRAPH) {
         im->xorigin = 0;
         im->ximg = im->xsize;
@@ -2718,30 +2867,23 @@ int graph_size_location(
         return 0;
     }
 
-    /** +---+--------------------------------------------+
-     ** | y |...............graph title..................|
-     ** |   +---+-------------------------------+--------+
-     ** | a | y |                               |        |
-     ** | x |   |                               |        |
-     ** | i | a |                               |  pie   |
-     ** | s | x |       main graph area         | chart  |
-     ** |   | i |                               |  area  |
-     ** | t | s |                               |        |
-     ** | i |   |                               |        |
-     ** | t | l |                               |        |
-     ** | l | b +-------------------------------+--------+
-     ** | e | l |       x axis labels           |        |
-     ** +---+---+-------------------------------+--------+
-     ** |....................legends.....................|
-     ** +------------------------------------------------+
-     ** |                   watermark                    |
-     ** +------------------------------------------------+
-     */
+    if(im->watermark[0] != '\0') {
+        Ywatermark = im->text_prop[TEXT_PROP_WATERMARK].size * 2;
+    }
 
+    // calculate the width of the left vertical legend
     if (im->ylegend[0] != '\0') {
         Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
     }
 
+    // calculate the width of the right vertical legend
+    if (im->second_axis_legend[0] != '\0') {
+        Xvertical2 = im->text_prop[TEXT_PROP_UNIT].size * 2;
+    }
+    else{
+        Xvertical2 = Xspacing;
+    }
+
     if (im->title[0] != '\0') {
         /* The title is placed "inbetween" two text lines so it
          ** automatically has some vertical spacing.  The horizontal
@@ -2750,86 +2892,112 @@ int graph_size_location(
         /* if necessary, reduce the font size of the title until it fits the image width */
         Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
     }
+    else{
+        // we have no title; get a little clearing from the top
+        Ytitle = 1.5 * Yspacing;
+    }
 
     if (elements) {
         if (im->draw_x_grid) {
+            // calculate the height of the horizontal labelling
             Yxlabel = im->text_prop[TEXT_PROP_AXIS].size * 2.5;
         }
         if (im->draw_y_grid || im->forceleftspace) {
+            // calculate the width of the vertical labelling
             Xylabel =
                 gfx_get_text_width(im, 0,
-                                   im->
-                                   text_prop
-                                   [TEXT_PROP_AXIS].
-                                   font,
-                                   im->
-                                   text_prop
-                                   [TEXT_PROP_AXIS].
-                                   size, im->tabwidth, "0") * im->unitslength;
+                                   im->text_prop[TEXT_PROP_AXIS].font_desc,
+                                   im->tabwidth, "0") * im->unitslength;
+        }
+    }
+
+    // add some space to the labelling
+    Xylabel += Xspacing;
+
+    /* If the legend is printed besides the graph the width has to be
+     ** calculated first. Placing the legend north or south of the 
+     ** graph requires the width calculation first, so the legend is 
+     ** skipped for the moment.
+     */
+    im->legendheight = 0;
+    im->legendwidth = 0;
+    if (!(im->extra_flags & NOLEGEND)) {
+        if(im->legendposition == WEST || im->legendposition == EAST){
+            if (leg_place(im, 1) == -1){
+                return -1;
+            }
         }
     }
 
     if (im->extra_flags & FULL_SIZE_MODE) {
+
         /* The actual size of the image to draw has been determined by the user.
          ** The graph area is the space remaining after accounting for the legend,
-         ** the watermark, the pie chart, the axis labels, and the title.
+         ** the watermark, the axis labels, and the title.
          */
-        im->xorigin = 0;
         im->ximg = im->xsize;
         im->yimg = im->ysize;
-        im->yorigin = im->ysize;
         Xmain = im->ximg;
         Ymain = im->yimg;
-        im->yorigin += Ytitle;
+
         /* Now calculate the total size.  Insert some spacing where
            desired.  im->xorigin and im->yorigin need to correspond
            with the lower left corner of the main graph area or, if
            this one is not set, the imaginary box surrounding the
            pie chart area. */
         /* Initial size calculation for the main graph area */
-        Xmain = im->ximg - (Xylabel + 2 * Xspacing);
-        if (Xmain)
-            Xmain -= Xspacing;  /* put space between main graph area and right edge */
-        im->xorigin = Xspacing + Xylabel;
-        /* the length of the title should not influence with width of the graph
-           if (Xtitle > im->ximg) im->ximg = Xtitle; */
-        if (Xvertical) {    /* unit description */
-            Xmain -= Xvertical;
-            im->xorigin += Xvertical;
+
+        Xmain -= Xylabel;// + Xspacing;
+        if((im->legendposition == WEST || im->legendposition == EAST) && !(im->extra_flags & NOLEGEND) ){
+            Xmain -= im->legendwidth;// + Xspacing;
+        }
+        if (im->second_axis_scale != 0){
+            Xmain -= Xylabel;
+        }
+        if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+            Xmain -= Xspacing;
+        }
+
+        Xmain -= Xvertical + Xvertical2;
+
+        /* limit the remaining space to 0 */
+        if(Xmain < 1){
+            Xmain = 1;
         }
         im->xsize = Xmain;
-        xtr(im, 0);
-        /* The vertical size of the image is known in advance.  The main graph area
-         ** (Ymain) and im->yorigin must be set according to the space requirements
-         ** of the legend and the axis labels.
-         */
-        if (im->extra_flags & NOLEGEND) {
-            /* set dimensions correctly if using full size mode with no legend */
-            im->yorigin =
-                im->yimg -
-                im->text_prop[TEXT_PROP_AXIS].size * 2.5 - Yspacing;
-            Ymain = im->yorigin;
-        } else {
-            /* Determine where to place the legends onto the image.
-             ** Set Ymain and adjust im->yorigin to match the space requirements.
-             */
-            if (leg_place(im, &Ymain) == -1)
-                return -1;
+
+        /* Putting the legend north or south, the height can now be calculated */
+        if (!(im->extra_flags & NOLEGEND)) {
+            if(im->legendposition == NORTH || im->legendposition == SOUTH){
+                im->legendwidth = im->ximg;
+                if (leg_place(im, 0) == -1){
+                    return -1;
+                }
+            }
         }
 
+        if( (im->legendposition == NORTH || im->legendposition == SOUTH)  && !(im->extra_flags & NOLEGEND) ){
+            Ymain -=  Yxlabel + im->legendheight;
+        }
+        else{
+            Ymain -= Yxlabel;
+        }
+        
+        /* reserve space for the title *or* some padding above the graph */
+        Ymain -= Ytitle;
 
-        /* remove title space *or* some padding above the graph from the main graph area */
-        if (Ytitle) {
-            Ymain -= Ytitle;
-        } else {
-            Ymain -= 1.5 * Yspacing;
+            /* reserve space for padding below the graph */
+        if (im->extra_flags & NOLEGEND) {
+            Ymain -= Yspacing;
         }
 
-        /* watermark doesn't seem to effect the vertical size of the main graph area, oh well! */
         if (im->watermark[0] != '\0') {
             Ymain -= Ywatermark;
         }
-
+        /* limit the remaining height to 0 */
+        if(Ymain < 1){
+            Ymain = 1;
+        }
         im->ysize = Ymain;
     } else {            /* dimension options -width and -height refer to the dimensions of the main graph area */
 
@@ -2839,83 +3007,171 @@ int graph_size_location(
          ** and other things outside the graph area.
          */
 
-        if (im->ylegend[0] != '\0') {
-            Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
+        if (elements) {
+            Xmain = im->xsize; // + Xspacing;
+            Ymain = im->ysize;
         }
 
-
-        if (im->title[0] != '\0') {
-            /* The title is placed "inbetween" two text lines so it
-             ** automatically has some vertical spacing.  The horizontal
-             ** spacing is added here, on each side.
-             */
-            /* don't care for the with of the title
-               Xtitle = gfx_get_text_width(im->canvas, 0,
-               im->text_prop[TEXT_PROP_TITLE].font,
-               im->text_prop[TEXT_PROP_TITLE].size,
-               im->tabwidth,
-               im->title, 0) + 2*Xspacing; */
-            Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
+        im->ximg = Xmain + Xylabel;
+        if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+            im->ximg += Xspacing;
         }
 
-        if (elements) {
-            Xmain = im->xsize;
-            Ymain = im->ysize;
+        if( (im->legendposition == WEST || im->legendposition == EAST) && !(im->extra_flags & NOLEGEND) ){
+            im->ximg += im->legendwidth;// + Xspacing;
+        }
+        if (im->second_axis_scale != 0){
+            im->ximg += Xylabel;
         }
-        /* Now calculate the total size.  Insert some spacing where
-           desired.  im->xorigin and im->yorigin need to correspond
-           with the lower left corner of the main graph area or, if
-           this one is not set, the imaginary box surrounding the
-           pie chart area. */
 
-        /* The legend width cannot yet be determined, as a result we
-         ** have problems adjusting the image to it.  For now, we just
-         ** forget about it at all; the legend will have to fit in the
-         ** size already allocated.
-         */
-        im->ximg = Xylabel + Xmain + 2 * Xspacing;
-        if (Xmain)
-            im->ximg += Xspacing;
-        im->xorigin = Xspacing + Xylabel;
-        /* the length of the title should not influence with width of the graph
-           if (Xtitle > im->ximg) im->ximg = Xtitle; */
-        if (Xvertical) {    /* unit description */
-            im->ximg += Xvertical;
-            im->xorigin += Xvertical;
+        im->ximg += Xvertical + Xvertical2;
+
+        if (!(im->extra_flags & NOLEGEND)) {
+            if(im->legendposition == NORTH || im->legendposition == SOUTH){
+                im->legendwidth = im->ximg;
+                if (leg_place(im, 0) == -1){
+                    return -1;
+                }
+            }
         }
-        xtr(im, 0);
-        /* The vertical size is interesting... we need to compare
-         ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with 
-         ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
-         ** in order to start even thinking about Ylegend or Ywatermark.
-         **
-         ** Do it in three portions: First calculate the inner part,
-         ** then do the legend, then adjust the total height of the img,
-         ** adding space for a watermark if one exists;
-         */
-        /* reserve space for main and/or pie */
+      
         im->yimg = Ymain + Yxlabel;
-        im->yorigin = im->yimg - Yxlabel;
+        if( (im->legendposition == NORTH || im->legendposition == SOUTH)  && !(im->extra_flags & NOLEGEND) ){
+             im->yimg += im->legendheight;
+        }
+        
         /* reserve space for the title *or* some padding above the graph */
         if (Ytitle) {
             im->yimg += Ytitle;
-            im->yorigin += Ytitle;
         } else {
             im->yimg += 1.5 * Yspacing;
-            im->yorigin += 1.5 * Yspacing;
         }
         /* reserve space for padding below the graph */
-        im->yimg += Yspacing;
-        /* Determine where to place the legends onto the image.
-         ** Adjust im->yimg to match the space requirements.
-         */
-        if (leg_place(im, 0) == -1)
-            return -1;
+        if (im->extra_flags & NOLEGEND) {
+            im->yimg += Yspacing;
+        }
+
         if (im->watermark[0] != '\0') {
             im->yimg += Ywatermark;
         }
     }
 
+
+    /* In case of putting the legend in west or east position the first 
+     ** legend calculation might lead to wrong positions if some items 
+     ** are not aligned on the left hand side (e.g. centered) as the 
+     ** legendwidth wight have been increased after the item was placed.
+     ** In this case the positions have to be recalculated.
+     */
+    if (!(im->extra_flags & NOLEGEND)) {
+        if(im->legendposition == WEST || im->legendposition == EAST){
+            if (leg_place(im, 0) == -1){
+                return -1;
+            }
+        }
+    }
+
+    /* After calculating all dimensions
+     ** it is now possible to calculate 
+     ** all offsets.
+     */
+    switch(im->legendposition){
+        case NORTH:
+            im->xOriginTitle   = Xvertical + Xylabel + (im->xsize / 2);
+            im->yOriginTitle   = 0;
+
+            im->xOriginLegend  = 0;
+            im->yOriginLegend  = Ytitle;
+
+            im->xOriginLegendY = 0;
+            im->yOriginLegendY = Ytitle + im->legendheight + (Ymain / 2) + Yxlabel;
+
+            im->xorigin        = Xvertical + Xylabel;
+            im->yorigin        = Ytitle + im->legendheight + Ymain;
+
+            im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+            if (im->second_axis_scale != 0){
+                im->xOriginLegendY2 += Xylabel;
+            }
+            im->yOriginLegendY2 = Ytitle + im->legendheight + (Ymain / 2) + Yxlabel;
+
+            break;
+
+        case WEST:
+            im->xOriginTitle   = im->legendwidth + Xvertical + Xylabel + im->xsize / 2;
+            im->yOriginTitle   = 0;
+
+            im->xOriginLegend  = 0;
+            im->yOriginLegend  = Ytitle;
+
+            im->xOriginLegendY = im->legendwidth;
+            im->yOriginLegendY = Ytitle + (Ymain / 2);
+
+            im->xorigin        = im->legendwidth + Xvertical + Xylabel;
+            im->yorigin        = Ytitle + Ymain;
+
+            im->xOriginLegendY2 = im->legendwidth + Xvertical + Xylabel + Xmain;
+            if (im->second_axis_scale != 0){
+                im->xOriginLegendY2 += Xylabel;
+            }
+            im->yOriginLegendY2 = Ytitle + (Ymain / 2);
+
+            break;
+
+        case SOUTH:
+            im->xOriginTitle   = Xvertical + Xylabel + im->xsize / 2;
+            im->yOriginTitle   = 0;
+
+            im->xOriginLegend  = 0;
+            im->yOriginLegend  = Ytitle + Ymain + Yxlabel;
+
+            im->xOriginLegendY = 0;
+            im->yOriginLegendY = Ytitle + (Ymain / 2);
+
+            im->xorigin        = Xvertical + Xylabel;
+            im->yorigin        = Ytitle + Ymain;
+
+            im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+            if (im->second_axis_scale != 0){
+                im->xOriginLegendY2 += Xylabel;
+            }
+            im->yOriginLegendY2 = Ytitle + (Ymain / 2);
+
+            break;
+
+        case EAST:
+            im->xOriginTitle   = Xvertical + Xylabel + im->xsize / 2;
+            im->yOriginTitle   = 0;
+
+            im->xOriginLegend  = Xvertical + Xylabel + Xmain + Xvertical2;
+            if (im->second_axis_scale != 0){
+                im->xOriginLegend += Xylabel;
+            }
+            im->yOriginLegend  = Ytitle;
+
+            im->xOriginLegendY = 0;
+            im->yOriginLegendY = Ytitle + (Ymain / 2);
+
+            im->xorigin        = Xvertical + Xylabel;
+            im->yorigin        = Ytitle + Ymain;
+
+            im->xOriginLegendY2 = Xvertical + Xylabel + Xmain;
+            if (im->second_axis_scale != 0){
+                im->xOriginLegendY2 += Xylabel;
+            }
+            im->yOriginLegendY2 = Ytitle + (Ymain / 2);
+
+            if (!(im->extra_flags & NO_RRDTOOL_TAG)){
+                im->xOriginTitle    += Xspacing;
+                im->xOriginLegend   += Xspacing;
+                im->xOriginLegendY  += Xspacing;
+                im->xorigin         += Xspacing;
+                im->xOriginLegendY2 += Xspacing;
+            }
+            break;
+    }
+
+    xtr(im, 0);
     ytr(im, DNAN);
     return 0;
 }
@@ -2926,10 +3182,10 @@ static cairo_status_t cairo_output(
     *data,
     unsigned int length)
 {
-    image_desc_t *im = closure;
+    image_desc_t *im = (image_desc_t*)closure;
 
     im->rendered_image =
-        realloc(im->rendered_image, im->rendered_image_size + length);
+        (unsigned char*)realloc(im->rendered_image, im->rendered_image_size + length);
     if (im->rendered_image == NULL)
         return CAIRO_STATUS_WRITE_ERROR;
     memcpy(im->rendered_image + im->rendered_image_size, data, length);
@@ -2945,12 +3201,10 @@ int graph_paint(
     int       lazy = lazy_check(im);
     double    areazero = 0.0;
     graph_desc_t *lastgdes = NULL;
-    infoval   info;
-    PangoFontMap *font_map = pango_cairo_font_map_get_default();
+    rrd_infoval_t info;
+
+//    PangoFontMap *font_map = pango_cairo_font_map_get_default();
 
-    /* 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;
@@ -2959,14 +3213,17 @@ int graph_paint(
         return -1;
     /* calculate and PRINT and GPRINT definitions. We have to do it at
      * this point because it will affect the length of the legends
-     * if there are no graph elements we stop here ... 
+     * if there are no graph elements (i==0) we stop here ... 
      * if we are lazy, try to quit ... 
      */
     i = print_calc(im);
     if (i < 0)
         return -1;
-    if ((i == 0) || lazy)
+
+    /* if we want and can be lazy ... quit now */
+    if (i == 0)
         return 0;
+
 /**************************************************************
  *** Calculating sizes and locations became a bit confusing ***
  *** so I moved this into a separate function.              ***
@@ -2986,6 +3243,14 @@ int graph_paint(
     grinfo_push(im, sprintf_alloc("image_width"), RD_I_CNT, info);
     info.u_cnt = im->yimg;
     grinfo_push(im, sprintf_alloc("image_height"), RD_I_CNT, info);
+    info.u_cnt = im->start;
+    grinfo_push(im, sprintf_alloc("graph_start"), RD_I_CNT, info);
+    info.u_cnt = im->end;
+    grinfo_push(im, sprintf_alloc("graph_end"), RD_I_CNT, info);
+
+    /* if we want and can be lazy ... quit now */
+    if (lazy)
+        return 0;
 
     /* get actual drawing data and find min and max values */
     if (data_proc(im) == -1)
@@ -3004,6 +3269,7 @@ int graph_paint(
     info.u_val = im->maxval;
     grinfo_push(im, sprintf_alloc("value_max"), RD_I_VAL, info);
 
+
     if (!calc_horizontal_grid(im))
         return -1;
     /* reset precalc */
@@ -3050,10 +3316,11 @@ int graph_paint(
             (im->surface, CAIRO_SVG_VERSION_1_1);
         break;
     };
+    cairo_destroy(im->cr);
     im->cr = cairo_create(im->surface);
     cairo_set_antialias(im->cr, im->graph_antialias);
     cairo_scale(im->cr, im->zoom, im->zoom);
-    pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
+//    pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
     gfx_new_area(im, 0, 0, 0, im->yimg,
                  im->ximg, im->yimg, im->graph_col[GRC_BACK]);
     gfx_add_point(im, im->ximg, 0);
@@ -3067,6 +3334,9 @@ int graph_paint(
                  im->yorigin - im->ysize, im->graph_col[GRC_CANVAS]);
     gfx_add_point(im, im->xorigin, im->yorigin - im->ysize);
     gfx_close_path(im);
+    cairo_rectangle(im->cr, im->xorigin, im->yorigin - im->ysize - 1.0,
+                    im->xsize, im->ysize + 2.0);
+    cairo_clip(im->cr);
     if (im->minval > 0.0)
         areazero = im->minval;
     if (im->maxval < 0.0)
@@ -3092,7 +3362,7 @@ int graph_paint(
                     if (im->gdes[i].yrule > 0) {
                         gfx_line(im,
                                  im->xorigin + ii,
-                                 im->yorigin,
+                                 im->yorigin + 1.0,
                                  im->xorigin + ii,
                                  im->yorigin -
                                  im->gdes[i].yrule *
@@ -3100,11 +3370,11 @@ int graph_paint(
                     } else if (im->gdes[i].yrule < 0) {
                         gfx_line(im,
                                  im->xorigin + ii,
-                                 im->yorigin - im->ysize,
+                                 im->yorigin - im->ysize - 1.0,
                                  im->xorigin + ii,
-                                 im->yorigin - (1 -
+                                 im->yorigin - im->ysize -
                                                 im->gdes[i].
-                                                yrule) *
+                                                yrule *
                                  im->ysize, 1.0, im->gdes[i].col);
                     }
                 }
@@ -3354,6 +3624,7 @@ int graph_paint(
             break;
         }               /* switch */
     }
+    cairo_reset_clip(im->cr);
 
     /* grid_paint also does the text */
     if (!(im->extra_flags & ONLY_GRAPH))
@@ -3523,8 +3794,8 @@ int rrd_graph(
     double *ymax)
 {
     int       prlines = 0;
-    info_t   *grinfo = NULL;
-    info_t   *walker;
+    rrd_info_t *grinfo = NULL;
+    rrd_info_t *walker;
 
     grinfo = rrd_graph_v(argc, argv);
     if (grinfo == NULL)
@@ -3535,13 +3806,13 @@ int rrd_graph(
         if (strcmp(walker->key, "image_info") == 0) {
             prlines++;
             if (((*prdata) =
-                 rrd_realloc((*prdata),
+                 (char**)rrd_realloc((*prdata),
                              (prlines + 1) * sizeof(char *))) == NULL) {
                 rrd_set_error("realloc prdata");
                 return 0;
             }
             /* imginfo goes to position 0 in the prdata array */
-            (*prdata)[prlines - 1] = malloc((strlen(walker->value.u_str)
+            (*prdata)[prlines - 1] = (char*)malloc((strlen(walker->value.u_str)
                                              + 2) * sizeof(char));
             strcpy((*prdata)[prlines - 1], walker->value.u_str);
             (*prdata)[prlines] = NULL;
@@ -3550,11 +3821,15 @@ int rrd_graph(
         walker = walker->next;
     }
     walker = grinfo;
+    *xsize = 0;
+    *ysize = 0;
+    *ymin = 0;
+    *ymax = 0;
     while (walker) {
         if (strcmp(walker->key, "image_width") == 0) {
-            *xsize = walker->value.u_int;
+            *xsize = walker->value.u_cnt;
         } else if (strcmp(walker->key, "image_height") == 0) {
-            *ysize = walker->value.u_int;
+            *ysize = walker->value.u_cnt;
         } else if (strcmp(walker->key, "value_min") == 0) {
             *ymin = walker->value.u_val;
         } else if (strcmp(walker->key, "value_max") == 0) {
@@ -3562,23 +3837,26 @@ int rrd_graph(
         } else if (strncmp(walker->key, "print", 5) == 0) { /* keys are prdate[0..] */
             prlines++;
             if (((*prdata) =
-                 rrd_realloc((*prdata),
+                 (char**)rrd_realloc((*prdata),
                              (prlines + 1) * sizeof(char *))) == NULL) {
                 rrd_set_error("realloc prdata");
                 return 0;
             }
-            (*prdata)[prlines - 1] = malloc((strlen(walker->value.u_str)
+            (*prdata)[prlines - 1] = (char*)malloc((strlen(walker->value.u_str)
                                              + 2) * sizeof(char));
             (*prdata)[prlines] = NULL;
             strcpy((*prdata)[prlines - 1], walker->value.u_str);
         } else if (strcmp(walker->key, "image") == 0) {
-            fwrite(walker->value.u_blo.ptr, walker->value.u_blo.size, 1,
-                   (stream ? stream : stdout));
+            if ( fwrite(walker->value.u_blo.ptr, walker->value.u_blo.size, 1,
+                   (stream ? stream : stdout)) == 0 && ferror(stream ? stream : stdout)){
+                rrd_set_error("writing image");
+                return 0;
+            }
         }
         /* skip anything else */
         walker = walker->next;
     }
-    info_free(grinfo);
+    rrd_info_free(grinfo);
     return 0;
 }
 
@@ -3589,26 +3867,24 @@ int rrd_graph(
 ** - options parsing  now in rrd_graph_options()
 ** - script parsing   now in rrd_graph_script()
 */
-info_t   *rrd_graph_v(
+rrd_info_t *rrd_graph_v(
     int argc,
     char **argv)
 {
     image_desc_t im;
-    info_t   *grinfo;
-
+    rrd_info_t *grinfo;
     rrd_graph_init(&im);
     /* a dummy surface so that we can measure text sizes for placements */
-    im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
-    im.cr = cairo_create(im.surface);
+    
     rrd_graph_options(argc, argv, &im);
     if (rrd_test_error()) {
-        info_free(im.grinfo);
+        rrd_info_free(im.grinfo);
         im_free(&im);
         return NULL;
     }
 
     if (optind >= argc) {
-        info_free(im.grinfo);
+        rrd_info_free(im.grinfo);
         im_free(&im);
         rrd_set_error("missing filename");
         return NULL;
@@ -3616,7 +3892,7 @@ info_t   *rrd_graph_v(
 
     if (strlen(argv[optind]) >= MAXPATH) {
         rrd_set_error("filename (including path) too long");
-        info_free(im.grinfo);
+        rrd_info_free(im.grinfo);
         im_free(&im);
         return NULL;
     }
@@ -3630,7 +3906,7 @@ info_t   *rrd_graph_v(
 
     rrd_graph_script(argc, argv, &im, 1);
     if (rrd_test_error()) {
-        info_free(im.grinfo);
+        rrd_info_free(im.grinfo);
         im_free(&im);
         return NULL;
     }
@@ -3638,7 +3914,7 @@ info_t   *rrd_graph_v(
     /* Everything is now read and the actual work can start */
 
     if (graph_paint(&im) == -1) {
-        info_free(im.grinfo);
+        rrd_info_free(im.grinfo);
         im_free(&im);
         return NULL;
     }
@@ -3649,18 +3925,23 @@ info_t   *rrd_graph_v(
      */
 
     if (im.imginfo) {
-        infoval   info;
+        rrd_infoval_t info;
+        char     *path;
+        char     *filename;
 
+        path = strdup(im.graphfile);
+        filename = basename(path);
         info.u_str =
             sprintf_alloc(im.imginfo,
-                          im.graphfile,
+                          filename,
                           (long) (im.zoom *
                                   im.ximg), (long) (im.zoom * im.yimg));
         grinfo_push(&im, sprintf_alloc("image_info"), RD_I_STR, info);
         free(info.u_str);
+        free(path);
     }
     if (im.rendered_image) {
-        infoval   img;
+        rrd_infoval_t img;
 
         img.u_blo.size = im.rendered_image_size;
         img.u_blo.ptr = im.rendered_image;
@@ -3671,11 +3952,30 @@ info_t   *rrd_graph_v(
     return grinfo;
 }
 
+static void 
+rrd_set_font_desc (
+    image_desc_t *im,int prop,char *font, double size ){
+    if (font){
+        strncpy(im->text_prop[prop].font, font, sizeof(text_prop[prop].font) - 1);        
+        im->text_prop[prop].font[sizeof(text_prop[prop].font) - 1] = '\0';   
+        im->text_prop[prop].font_desc = pango_font_description_from_string( font );        
+    };
+    if (size > 0){  
+        im->text_prop[prop].size = size;
+    };
+    if (im->text_prop[prop].font_desc && im->text_prop[prop].size ){
+        pango_font_description_set_size(im->text_prop[prop].font_desc, im->text_prop[prop].size * PANGO_SCALE);
+    };
+}
+
 void rrd_graph_init(
     image_desc_t
     *im)
 {
     unsigned int i;
+    char     *deffont = getenv("RRD_DEFAULT_FONT");
+    static PangoFontMap *fontmap = NULL;
+    PangoContext *context;
 
 #ifdef HAVE_TZSET
     tzset();
@@ -3687,7 +3987,7 @@ void rrd_graph_init(
 #endif
 #endif
     im->base = 1000;
-    im->cr = NULL;
+    im->daemon_addr = NULL;
     im->draw_x_grid = 1;
     im->draw_y_grid = 1;
     im->extra_flags = 0;
@@ -3699,11 +3999,15 @@ void rrd_graph_init(
     im->grid_dash_off = 1;
     im->grid_dash_on = 1;
     im->gridfit = 1;
-    im->grinfo = (info_t *) NULL;
-    im->grinfo_current = (info_t *) NULL;
+    im->grinfo = (rrd_info_t *) NULL;
+    im->grinfo_current = (rrd_info_t *) NULL;
     im->imgformat = IF_PNG;
     im->imginfo = NULL;
     im->lazy = 0;
+    im->legenddirection = TOP_DOWN;
+    im->legendheight = 0;
+    im->legendposition = SOUTH;
+    im->legendwidth = 0;
     im->logarithmic = 0;
     im->maxval = DNAN;
     im->minval = 0;
@@ -3714,7 +4018,6 @@ void rrd_graph_init(
     im->rendered_image = NULL;
     im->slopemode = 0;
     im->step = 0;
-    im->surface = NULL;
     im->symbol = ' ';
     im->tabwidth = 40.0;
     im->title[0] = '\0';
@@ -3722,61 +4025,68 @@ void rrd_graph_init(
     im->unitslength = 6;
     im->viewfactor = 1.0;
     im->watermark[0] = '\0';
+    im->with_markup = 0;
     im->ximg = 0;
     im->xlab_user.minsec = -1;
     im->xorigin = 0;
+    im->xOriginLegend = 0;
+    im->xOriginLegendY = 0;
+    im->xOriginLegendY2 = 0;
+    im->xOriginTitle = 0;
     im->xsize = 400;
     im->ygridstep = DNAN;
     im->yimg = 0;
     im->ylegend[0] = '\0';
+    im->second_axis_scale = 0; /* 0 disables it */
+    im->second_axis_shift = 0; /* no shift by default */
+    im->second_axis_legend[0] = '\0';
+    im->second_axis_format[0] = '\0'; 
     im->yorigin = 0;
+    im->yOriginLegend = 0;
+    im->yOriginLegendY = 0;
+    im->yOriginLegendY2 = 0;
+    im->yOriginTitle = 0;
     im->ysize = 100;
     im->zoom = 1;
+
+    im->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);     
+    im->cr = cairo_create(im->surface);
+
+    for (i = 0; i < DIM(text_prop); i++) {
+        im->text_prop[i].size = -1;
+        rrd_set_font_desc(im,i, deffont ? deffont : text_prop[i].font,text_prop[i].size);
+    }
+
+    if (fontmap == NULL){
+        fontmap = pango_cairo_font_map_get_default();
+    }
+
+    context =  pango_cairo_font_map_create_context((PangoCairoFontMap*)fontmap);
+
+    pango_cairo_context_set_resolution(context, 100);
+
+    pango_cairo_update_context(im->cr,context);
+
+    im->layout = pango_layout_new(context);
+
+//  im->layout = pango_cairo_create_layout(im->cr);
+
+
     cairo_font_options_set_hint_style
         (im->font_options, CAIRO_HINT_STYLE_FULL);
     cairo_font_options_set_hint_metrics
         (im->font_options, CAIRO_HINT_METRICS_ON);
     cairo_font_options_set_antialias(im->font_options, CAIRO_ANTIALIAS_GRAY);
+
+
+
     for (i = 0; i < DIM(graph_col); i++)
         im->graph_col[i] = graph_col[i];
-#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) {
-            strncpy(rrd_win_default_font, windir, 500);
-            rrd_win_default_font[500] = '\0';
-            strcat(rrd_win_default_font, "\\fonts\\");
-            strcat(rrd_win_default_font, RRD_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");
-        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);
-    }
+
+
 }
 
+
 void rrd_graph_options(
     int argc,
     char *argv[],
@@ -3788,141 +4098,80 @@ void rrd_graph_options(
     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 rrd_time_value start_tv, end_tv;
+    rrd_time_value_t start_tv, end_tv;
     long unsigned int color;
     char     *old_locale = "";
 
     /* defines for long options without a short equivalent. should be bytes,
        and may not collide with (the ASCII value of) short options */
 #define LONGOPT_UNITS_SI 255
+
+/* *INDENT-OFF* */
     struct option long_options[] = {
-        {
-         "start", required_argument, 0, 's'}, {
-                                               "end", required_argument, 0,
-                                               'e'}, {
-                                                      "x-grid",
-                                                      required_argument, 0,
-                                                      'x'}, {
-                                                             "y-grid",
-                                                             required_argument,
-                                                             0, 'y'}, {
-                                                                       "vertical-label",
-                                                                       required_argument,
-                                                                       0,
-                                                                       'v'}, {
-                                                                              "width",
-                                                                              required_argument,
-                                                                              0,
-                                                                              'w'},
-        {
-         "height", required_argument, 0, 'h'}, {
-                                                "full-size-mode", no_argument,
-                                                0, 'D'}, {
-                                                          "interlaced",
-                                                          no_argument, 0,
-                                                          'i'}, {
-                                                                 "upper-limit",
-                                                                 required_argument,
-                                                                 0,
-                                                                 'u'}, {
-                                                                        "lower-limit",
-                                                                        required_argument,
-                                                                        0,
-                                                                        'l'}, {
-                                                                               "rigid",
-                                                                               no_argument,
-                                                                               0,
-                                                                               'r'},
-        {
-         "base", required_argument, 0, 'b'}, {
-                                              "logarithmic", no_argument, 0,
-                                              'o'}, {
-                                                     "color",
-                                                     required_argument, 0,
-                                                     'c'}, {
-                                                            "font",
-                                                            required_argument,
-                                                            0, 'n'}, {
-                                                                      "title",
-                                                                      required_argument,
-                                                                      0, 't'},
-        {
-         "imginfo", required_argument, 0, 'f'}, {
-                                                 "imgformat",
-                                                 required_argument, 0, 'a'}, {
-                                                                              "lazy",
-                                                                              no_argument,
-                                                                              0,
-                                                                              'z'},
-        {
-         "zoom", required_argument, 0, 'm'}, {
-                                              "no-legend", no_argument, 0,
-                                              'g'}, {
-                                                     "force-rules-legend",
-                                                     no_argument,
-                                                     0, 'F'}, {
-                                                               "only-graph",
-                                                               no_argument, 0,
-                                                               'j'}, {
-                                                                      "alt-y-grid",
-                                                                      no_argument,
-                                                                      0, 'Y'},
-        {
-         "no-minor", no_argument, 0, 'I'}, {
-                                            "slope-mode", no_argument, 0,
-                                            'E'}, {
-                                                   "alt-autoscale",
-                                                   no_argument, 0, 'A'}, {
-                                                                          "alt-autoscale-min",
-                                                                          no_argument,
-                                                                          0,
-                                                                          'J'}, {
-                                                                                 "alt-autoscale-max",
-                                                                                 no_argument,
-                                                                                 0,
-                                                                                 'M'}, {
-                                                                                        "no-gridfit",
-                                                                                        no_argument,
-                                                                                        0,
-                                                                                        'N'},
-        {
-         "units-exponent", required_argument,
-         0, 'X'}, {
-                   "units-length", required_argument,
-                   0, 'L'}, {
-                             "units", required_argument, 0,
-                             LONGOPT_UNITS_SI}, {
-                                                 "step", required_argument, 0,
-                                                 'S'}, {
-                                                        "tabwidth",
-                                                        required_argument, 0,
-                                                        'T'}, {
-                                                               "font-render-mode",
-                                                               required_argument,
-                                                               0, 'R'}, {
-                                                                         "graph-render-mode",
-                                                                         required_argument,
-                                                                         0,
-                                                                         'G'},
-        {
-         "font-smoothing-threshold",
-         required_argument, 0, 'B'}, {
-                                      "watermark", required_argument, 0, 'W'}, {
-                                                                                "alt-y-mrtg", no_argument, 0, 1000},    /* this has no effect it is just here to save old apps from crashing when they use it */
-        {
-         0, 0, 0, 0}
-    };
+        { "start",              required_argument, 0, 's'}, 
+        { "end",                required_argument, 0, 'e'},
+        { "x-grid",             required_argument, 0, 'x'},
+        { "y-grid",             required_argument, 0, 'y'},
+        { "vertical-label",     required_argument, 0, 'v'},
+        { "width",              required_argument, 0, 'w'},
+        { "height",             required_argument, 0, 'h'},
+        { "full-size-mode",     no_argument,       0, 'D'},
+        { "interlaced",         no_argument,       0, 'i'},
+        { "upper-limit",        required_argument, 0, 'u'},
+        { "lower-limit",        required_argument, 0, 'l'},
+        { "rigid",              no_argument,       0, 'r'},
+        { "base",               required_argument, 0, 'b'},
+        { "logarithmic",        no_argument,       0, 'o'},
+        { "color",              required_argument, 0, 'c'},
+        { "font",               required_argument, 0, 'n'},
+        { "title",              required_argument, 0, 't'},
+        { "imginfo",            required_argument, 0, 'f'},
+        { "imgformat",          required_argument, 0, 'a'},
+        { "lazy",               no_argument,       0, 'z'},
+        { "zoom",               required_argument, 0, 'm'},
+        { "no-legend",          no_argument,       0, 'g'},
+        { "legend-position",    required_argument, 0, 1005},
+        { "legend-direction",   required_argument, 0, 1006},
+        { "force-rules-legend", no_argument,       0, 'F'},
+        { "only-graph",         no_argument,       0, 'j'},
+        { "alt-y-grid",         no_argument,       0, 'Y'},
+        {"disable-rrdtool-tag", no_argument,       0,  1001},
+        {"right-axis",          required_argument, 0,  1002},
+        {"right-axis-label",    required_argument, 0,  1003},
+        {"right-axis-format",   required_argument, 0,  1004},     
+        { "no-minor",           no_argument,       0, 'I'}, 
+        { "slope-mode",         no_argument,       0, 'E'},
+        { "alt-autoscale",      no_argument,       0, 'A'},
+        { "alt-autoscale-min",  no_argument,       0, 'J'},
+        { "alt-autoscale-max",  no_argument,       0, 'M'},
+        { "no-gridfit",         no_argument,       0, 'N'},
+        { "units-exponent",     required_argument, 0, 'X'},
+        { "units-length",       required_argument, 0, 'L'},
+        { "units",              required_argument, 0, LONGOPT_UNITS_SI},
+        { "step",               required_argument, 0, 'S'},
+        { "tabwidth",           required_argument, 0, 'T'},
+        { "font-render-mode",   required_argument, 0, 'R'},
+        { "graph-render-mode",  required_argument, 0, 'G'},
+        { "font-smoothing-threshold", required_argument, 0, 'B'},
+        { "watermark",          required_argument, 0, 'W'},
+        { "alt-y-mrtg",         no_argument,       0, 1000},    /* this has no effect it is just here to save old apps from crashing when they use it */
+        { "pango-markup",       no_argument,       0, 'P'},
+        { "daemon",             required_argument, 0, 'd'},
+        {  0, 0, 0, 0}
+};
+/* *INDENT-ON* */
+
     optind = 0;
     opterr = 0;         /* initialize getopt */
-    parsetime("end-24h", &start_tv);
-    parsetime("now", &end_tv);
+    rrd_parsetime("end-24h", &start_tv);
+    rrd_parsetime("now", &end_tv);
     while (1) {
         int       option_index = 0;
         int       opt;
         int       col_start, col_end;
 
         opt = getopt_long(argc, argv,
-                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:k",
+                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:kPd:",
                           long_options, &option_index);
         if (opt == EOF)
             break;
@@ -3948,9 +4197,36 @@ void rrd_graph_options(
         case 'g':
             im->extra_flags |= NOLEGEND;
             break;
+        case 1005:
+            if (strcmp(optarg, "north") == 0) {
+                im->legendposition = NORTH;
+            } else if (strcmp(optarg, "west") == 0) {
+                im->legendposition = WEST;
+            } else if (strcmp(optarg, "south") == 0) {
+                im->legendposition = SOUTH;
+            } else if (strcmp(optarg, "east") == 0) {
+                im->legendposition = EAST;
+            } else {
+                rrd_set_error("unknown legend-position '%s'", optarg);
+                return;
+            }
+            break;
+        case 1006:
+            if (strcmp(optarg, "topdown") == 0) {
+                im->legenddirection = TOP_DOWN;
+            } else if (strcmp(optarg, "bottomup") == 0) {
+                im->legenddirection = BOTTOM_UP;
+            } else {
+                rrd_set_error("unknown legend-position '%s'", optarg);
+                return;
+            }
+            break;
         case 'F':
             im->extra_flags |= FORCE_RULES_LEGEND;
             break;
+        case 1001:
+            im->extra_flags |= NO_RRDTOOL_TAG;
+            break;              
         case LONGOPT_UNITS_SI:
             if (im->extra_flags & FORCE_UNITS) {
                 rrd_set_error("--units can only be used once!");
@@ -3984,14 +4260,17 @@ void rrd_graph_options(
         case 'N':
             im->gridfit = 0;
             break;
+        case 'P':
+            im->with_markup = 1;
+            break;
         case 's':
-            if ((parsetime_error = parsetime(optarg, &start_tv))) {
+            if ((parsetime_error = rrd_parsetime(optarg, &start_tv))) {
                 rrd_set_error("start time: %s", parsetime_error);
                 return;
             }
             break;
         case 'e':
-            if ((parsetime_error = parsetime(optarg, &end_tv))) {
+            if ((parsetime_error = rrd_parsetime(optarg, &end_tv))) {
                 rrd_set_error("end time: %s", parsetime_error);
                 return;
             }
@@ -4056,6 +4335,33 @@ void rrd_graph_options(
                 return;
             }
             break;
+        case 1002: /* right y axis */
+
+            if(sscanf(optarg,
+                      "%lf:%lf",
+                      &im->second_axis_scale,
+                      &im->second_axis_shift) == 2) {
+                if(im->second_axis_scale==0){
+                    rrd_set_error("the second_axis_scale  must not be 0");
+                    return;
+                }
+            } else {
+                rrd_set_error("invalid right-axis format expected scale:shift");
+                return;
+            }
+            break;
+        case 1003:
+            strncpy(im->second_axis_legend,optarg,150);
+            im->second_axis_legend[150]='\0';
+            break;
+        case 1004:
+            if (bad_format(optarg)){
+                rrd_set_error("use either %le or %lf formats");
+                return;
+            }
+            strncpy(im->second_axis_format,optarg,150);
+            im->second_axis_format[150]='\0';
+            break;
         case 'v':
             strncpy(im->ylegend, optarg, 150);
             im->ylegend[150] = '\0';
@@ -4182,20 +4488,20 @@ void rrd_graph_options(
                     for (propidx = sindex;
                          propidx < TEXT_PROP_LAST; propidx++) {
                         if (size > 0) {
-                            im->text_prop[propidx].size = size;
+                            rrd_set_font_desc(im,propidx,NULL,size);   
                         }
-                        if ((int) strlen(prop) > end) {
-                            if (prop[end] == ':') {
-                                strncpy(im->text_prop[propidx].font,
-                                        prop + end + 1, 255);
-                                im->text_prop[propidx].font[255] = '\0';
+                        if ((int) strlen(optarg) > end+2) {
+                            if (optarg[end] == ':') {
+                                rrd_set_font_desc(im,propidx,optarg + end + 1,0);   
                             } else {
                                 rrd_set_error
-                                    ("expected after font size in '%s'",
-                                     prop);
+                                    ("expected after font size in '%s'",
+                                     optarg);
                                 return;
                             }
                         }
+                        /* only run the for loop for DEFAULT (0) for
+                           all others, we break here. woodo programming */
                         if (propidx == sindex && sindex != 0)
                             break;
                     }
@@ -4261,6 +4567,24 @@ void rrd_graph_options(
             strncpy(im->watermark, optarg, 100);
             im->watermark[99] = '\0';
             break;
+        case 'd':
+        {
+            if (im->daemon_addr != NULL)
+            {
+                rrd_set_error ("You cannot specify --daemon "
+                        "more than once.");
+                return;
+            }
+
+            im->daemon_addr = strdup(optarg);
+            if (im->daemon_addr == NULL)
+            {
+              rrd_set_error("strdup failed");
+              return;
+            }
+
+            break;
+        }
         case '?':
             if (optopt != 0)
                 rrd_set_error("unknown option '%c'", optopt);
@@ -4268,7 +4592,17 @@ void rrd_graph_options(
                 rrd_set_error("unknown option '%s'", argv[optind - 1]);
             return;
         }
+    } /* while (1) */
+
+    {   /* try to connect to rrdcached */
+        int status = rrdc_connect(im->daemon_addr);
+        if (status != 0) return;
     }
+    
+    pango_cairo_context_set_font_options(pango_layout_get_context(im->layout), im->font_options);
+    pango_layout_context_changed(im->layout);
+
+
 
     if (im->logarithmic && im->minval <= 0) {
         rrd_set_error
@@ -4276,8 +4610,8 @@ void rrd_graph_options(
         return;
     }
 
-    if (proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
-        /* error string is set in parsetime.c */
+    if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
+        /* error string is set in rrd_parsetime.c */
         return;
     }
 
@@ -4430,6 +4764,8 @@ int vdef_parse(
     }
     if (!strcmp("PERCENT", func))
         gdes->vf.op = VDEF_PERCENT;
+    else if (!strcmp("PERCENTNAN", func))
+        gdes->vf.op = VDEF_PERCENTNAN;
     else if (!strcmp("MAXIMUM", func))
         gdes->vf.op = VDEF_MAXIMUM;
     else if (!strcmp("AVERAGE", func))
@@ -4457,6 +4793,7 @@ int vdef_parse(
     };
     switch (gdes->vf.op) {
     case VDEF_PERCENT:
+    case VDEF_PERCENTNAN:
         if (isnan(param)) { /* no parameter given */
             rrd_set_error
                 ("Function '%s' needs parameter in VDEF '%s'\n",
@@ -4511,6 +4848,7 @@ int vdef_calc(
     dst = &im->gdes[gdi];
     src = &im->gdes[dst->vidx];
     data = src->data + src->ds;
+
     steps = (src->end - src->start) / src->step;
 #if 0
     printf
@@ -4521,7 +4859,7 @@ int vdef_calc(
     case VDEF_PERCENT:{
         rrd_value_t *array;
         int       field;
-        if ((array = malloc(steps * sizeof(double))) == NULL) {
+        if ((array = (rrd_value_t*)malloc(steps * sizeof(double))) == NULL) {
             rrd_set_error("malloc VDEV_PERCENT");
             return -1;
         }
@@ -4529,7 +4867,7 @@ int vdef_calc(
             array[step] = data[step * src->ds_cnt];
         }
         qsort(array, step, sizeof(double), vdef_percent_compar);
-        field = (steps - 1) * dst->vf.param / 100;
+        field = round((dst->vf.param * (double)(steps - 1)) / 100.0);
         dst->vf.val = array[field];
         dst->vf.when = 0;   /* no time component */
         free(array);
@@ -4540,6 +4878,34 @@ int vdef_calc(
 #endif
     }
         break;
+    case VDEF_PERCENTNAN:{
+        rrd_value_t *array;
+        int       field;
+       /* count number of "valid" values */
+       int nancount=0;
+       for (step = 0; step < steps; step++) {
+         if (!isnan(data[step * src->ds_cnt])) { nancount++; }
+       }
+       /* and allocate it */
+        if ((array = (rrd_value_t*)malloc(nancount * sizeof(double))) == NULL) {
+            rrd_set_error("malloc VDEV_PERCENT");
+            return -1;
+        }
+       /* and fill it in */
+       field=0;
+        for (step = 0; step < steps; step++) {
+           if (!isnan(data[step * src->ds_cnt])) {
+                array[field] = data[step * src->ds_cnt];
+               field++;
+            }
+        }
+        qsort(array, nancount, sizeof(double), vdef_percent_compar);
+        field = round( dst->vf.param * (double)(nancount - 1) / 100.0);
+        dst->vf.val = array[field];
+        dst->vf.when = 0;   /* no time component */
+        free(array);
+    }
+        break;
     case VDEF_MAXIMUM:
         step = 0;
         while (step != steps && isnan(data[step * src->ds_cnt]))
@@ -4736,10 +5102,10 @@ int vdef_percent_compar(
 void grinfo_push(
     image_desc_t *im,
     char *key,
-    enum info_type type,
-    infoval value)
+    rrd_info_type_t type,
+    rrd_infoval_t value)
 {
-    im->grinfo_current = info_push(im->grinfo_current, key, type, value);
+    im->grinfo_current = rrd_info_push(im->grinfo_current, key, type, value);
     if (im->grinfo == NULL) {
         im->grinfo = im->grinfo_current;
     }