use snprintf, strdup, ... where possible to make for safer operation -- Martin Pelikan
[rrdtool.git] / src / rrd_graph.c
index 3c2795a..317becc 100644 (file)
@@ -59,6 +59,8 @@ text_prop_t text_prop[] = {
     {5.5, RRD_DEFAULT_FONT,NULL} /* watermark */
 };
 
+char week_fmt[128] = "Week %V";
+
 xlab_t    xlab[] = {
     {0, 0, TMT_SECOND, 30, TMT_MINUTE, 5, TMT_MINUTE, 5, 0, "%H:%M"}
     ,
@@ -87,10 +89,9 @@ xlab_t    xlab[] = {
     ,
     {2400, 0, TMT_HOUR, 12, TMT_DAY, 1, TMT_DAY, 2, 24 * 3600, "%a"}
     ,
-    {3600, 0, TMT_DAY, 1, TMT_WEEK, 1, TMT_WEEK, 1, 7 * 24 * 3600, "Week %V"}
+    {3600, 0, TMT_DAY, 1, TMT_WEEK, 1, TMT_WEEK, 1, 7 * 24 * 3600, week_fmt}
     ,
-    {3 * 3600, 0, TMT_WEEK, 1, TMT_MONTH, 1, TMT_WEEK, 2, 7 * 24 * 3600,
-     "Week %V"}
+    {3 * 3600, 0, TMT_WEEK, 1, TMT_MONTH, 1, TMT_WEEK, 2, 7 * 24 * 3600, week_fmt}
     ,
     {6 * 3600, 0, TMT_MONTH, 1, TMT_MONTH, 1, TMT_MONTH, 1, 30 * 24 * 3600,
      "%b"}
@@ -255,10 +256,25 @@ enum gfx_if_en if_conv(
     conv_if(SVG, IF_SVG);
     conv_if(EPS, IF_EPS);
     conv_if(PDF, IF_PDF);
+    conv_if(XML, IF_XML);
+    conv_if(XMLENUM, IF_XMLENUM);
+    conv_if(CSV, IF_CSV);
+    conv_if(TSV, IF_TSV);
+    conv_if(SSV, IF_SSV);
+    conv_if(JSON, IF_JSON);
+    conv_if(JSONTIME, IF_JSONTIME);
 
     return (enum gfx_if_en)(-1);
 }
 
+enum gfx_type_en type_conv(
+    char *string)
+{
+    conv_if(TIME , GTYPE_TIME);
+    conv_if(XY, GTYPE_XY);
+    return (enum gfx_type_en)(-1);
+}
+
 enum tmt_en tmt_conv(
     char *string)
 {
@@ -411,8 +427,11 @@ void auto_scale(
     }
 }
 
+/* power prefixes */
 
 static char si_symbol[] = {
+    'y',                /* 10e-24 Yocto */
+    'z',                /* 10e-21 Zepto */
     'a',                /* 10e-18 Atto */
     'f',                /* 10e-15 Femto */
     'p',                /* 10e-12 Pico */
@@ -426,8 +445,10 @@ static char si_symbol[] = {
     'T',                /* 10e12  Tera */
     'P',                /* 10e15  Peta */
     'E',                /* 10e18  Exa */
+    'Z',                /* 10e21  Zeta */
+    'Y'                 /* 10e24  Yotta */
 };
-static const int si_symbcenter = 6;
+static const int si_symbcenter = 8;
 
 /* find SI magnitude symbol for the numbers on the y-axis*/
 void si_unit(
@@ -894,11 +915,15 @@ int data_fetch(
                                 &im->gdes[i].ds_cnt,
                                 &im->gdes[i].ds_namv,
                                 &im->gdes[i].data)) == -1) {
-                    return -1;
-                }
+                    return -1;                      
+                }               
             }
             im->gdes[i].data_first = 1;
 
+            /* must reduce to at least im->step
+               otherwhise we end up with more data than we can handle in the 
+               chart and visibility of data will be random */            
+            im->gdes[i].step = max(im->gdes[i].step,im->step);
             if (ft_step < im->gdes[i].step) {
                 reduce_data(im->gdes[i].cf_reduce,
                             ft_step,
@@ -1401,6 +1426,8 @@ time_t find_first_time(
     struct tm tm;
 
     localtime_r(&start, &tm);
+    /* let mktime figure this dst on its own */
+    tm.tm_isdst = -1;
 
     switch (baseint) {
     case TMT_SECOND:
@@ -1469,7 +1496,16 @@ time_t find_next_time(
     time_t    madetime;
 
     localtime_r(&current, &tm);
+    /* let mktime figure this dst on its own */
+    tm.tm_isdst = -1;
 
+    int limit = 2;
+    switch (baseint) {
+    case TMT_SECOND: limit = 7200; break;
+    case TMT_MINUTE: limit = 120; break;
+    case TMT_HOUR: limit = 2; break;
+    default: limit = 2; break;
+    }
     do {
         switch (baseint) {
         case TMT_SECOND:
@@ -1500,7 +1536,7 @@ time_t find_next_time(
             tm.       tm_year += basestep;
         }
         madetime = mktime(&tm);
-    } while (madetime == -1);   /* this is necessary to skip impssible times
+    } while (madetime == -1 && limit-- >= 0);   /* this is necessary to skip impossible times
                                    like the daylight saving time skips */
     return madetime;
 
@@ -1640,14 +1676,9 @@ int print_calc(
                              im->gdes[i].format);
                         return -1;
                     }
-#ifdef HAVE_SNPRINTF
                     snprintf(im->gdes[i].legend,
                              FMT_LEG_LEN - 2,
                              im->gdes[i].format, printval, si_symb);
-#else
-                    sprintf(im->gdes[i].legend,
-                            im->gdes[i].format, printval, si_symb);
-#endif
                 }
                 graphelement = 1;
             }
@@ -1686,6 +1717,9 @@ int print_calc(
                 ("STACK should already be turned into LINE or AREA here");
             return -1;
             break;
+        case GF_XAXIS:
+        case GF_YAXIS:
+           break;
         }
     }
     return graphelement;
@@ -1732,7 +1766,7 @@ int leg_place(
         for (i = 0; i < im->gdes_c; i++) {
             char      prt_fctn; /*special printfunctions */
             if(calc_width){
-                strcpy(saved_legend, im->gdes[i].legend);
+                strncpy(saved_legend, im->gdes[i].legend, sizeof saved_legend);
             }
 
             fill_last = fill;
@@ -1773,6 +1807,7 @@ int leg_place(
                 prt_fctn != 'j' &&
                 prt_fctn != 'c' &&
                 prt_fctn != 'u' &&
+                prt_fctn != '.' &&
                 prt_fctn != 's' && prt_fctn != '\0' && prt_fctn != 'g') {
                 free(legspace);
                 rrd_set_error
@@ -1784,6 +1819,10 @@ int leg_place(
             if (prt_fctn == 'n') {
                 prt_fctn = 'l';
             }
+            /* \. is a null operation to allow strings ending in \x */
+            if (prt_fctn == '.') {
+                prt_fctn = '\0';
+            }
 
             /* remove exess space from the end of the legend for \g */
             while (prt_fctn == 'g' &&
@@ -1859,7 +1898,7 @@ int leg_place(
                     glue = 0;
                 }
                 if (prt_fctn == 'c')
-                    leg_x = (double)(legendwidth - fill) / 2.0;
+                    leg_x = border + (double)(legendwidth - fill) / 2.0;
                 if (prt_fctn == 'r')
                     leg_x = legendwidth - fill + border;
                 for (ii = mark; ii <= i; ii++) {
@@ -1894,7 +1933,7 @@ int leg_place(
             }
 
             if(calc_width){
-                strcpy(im->gdes[i].legend, saved_legend);
+                strncpy(im->gdes[i].legend, saved_legend, sizeof im->gdes[0].legend);
             }
         }
 
@@ -1977,7 +2016,7 @@ int calc_horizontal_grid(
 
                 if (im->unitslength < len + 2)
                     im->unitslength = len + 2;
-                sprintf(im->ygrid_scale.labfmt,
+                snprintf(im->ygrid_scale.labfmt, sizeof im->ygrid_scale.labfmt, 
                         "%%%d.%df%s", len,
                         -fractionals, (im->symbol != ' ' ? " %c" : ""));
             } else {
@@ -1985,7 +2024,7 @@ int calc_horizontal_grid(
 
                 if (im->unitslength < len + 2)
                     im->unitslength = len + 2;
-                sprintf(im->ygrid_scale.labfmt,
+                snprintf(im->ygrid_scale.labfmt, sizeof im->ygrid_scale.labfmt,
                         "%%%d.0f%s", len, (im->symbol != ' ' ? " %c" : ""));
             }
         } else {        /* classic rrd grid */
@@ -2049,15 +2088,15 @@ int draw_horizontal_grid(
                     && (YN < im->yorigin - im->ysize || YN > im->yorigin))) {
                 if (im->symbol == ' ') {
                     if (im->extra_flags & ALTYGRID) {
-                        sprintf(graph_label,
+                        snprintf(graph_label, sizeof graph_label,
                                 im->ygrid_scale.labfmt,
                                 scaledstep * (double) i);
                     } else {
                         if (MaxY < 10) {
-                            sprintf(graph_label, "%4.1f",
+                            snprintf(graph_label, sizeof graph_label, "%4.1f",
                                     scaledstep * (double) i);
                         } else {
-                            sprintf(graph_label, "%4.0f",
+                            snprintf(graph_label, sizeof graph_label, "%4.0f",
                                     scaledstep * (double) i);
                         }
                     }
@@ -2065,15 +2104,15 @@ int draw_horizontal_grid(
                     char      sisym = (i == 0 ? ' ' : im->symbol);
 
                     if (im->extra_flags & ALTYGRID) {
-                        sprintf(graph_label,
+                        snprintf(graph_label, sizeof graph_label,
                                 im->ygrid_scale.labfmt,
                                 scaledstep * (double) i, sisym);
                     } else {
                         if (MaxY < 10) {
-                            sprintf(graph_label, "%4.1f %c",
+                            snprintf(graph_label, sizeof graph_label, "%4.1f %c",
                                     scaledstep * (double) i, sisym);
                         } else {
-                            sprintf(graph_label, "%4.0f %c",
+                            snprintf(graph_label, sizeof graph_label, "%4.0f %c",
                                     scaledstep * (double) i, sisym);
                         }
                     }
@@ -2090,13 +2129,13 @@ int draw_horizontal_grid(
                             sval /= second_axis_magfact;
 
                             if(MaxY < 10) {
-                                sprintf(graph_label_right,"%5.1f %s",sval,second_axis_symb);
+                                snprintf(graph_label_right, sizeof graph_label_right, "%5.1f %s",sval,second_axis_symb);
                             } else {
-                                sprintf(graph_label_right,"%5.0f %s",sval,second_axis_symb);
+                                snprintf(graph_label_right, sizeof graph_label_right, "%5.0f %s",sval,second_axis_symb);
                             }
                         }
                         else {
-                           sprintf(graph_label_right,im->second_axis_format,sval);
+                           snprintf(graph_label_right, sizeof graph_label_right, im->second_axis_format,sval,"");
                         }
                         gfx_text ( im,
                                X1+7, Y0,
@@ -2282,9 +2321,9 @@ int horizontal_log_grid(
                 symbol = si_symbol[scale + si_symbcenter];
             else
                 symbol = '?';
-            sprintf(graph_label, "%3.0f %c", pvalue, symbol);
+            snprintf(graph_label, sizeof graph_label, "%3.0f %c", pvalue, symbol);
         } else {
-            sprintf(graph_label, "%3.0e", value);
+            snprintf(graph_label, sizeof graph_label, "%3.0e", value);
         }
         if (im->second_axis_scale != 0){
                 char graph_label_right[100];
@@ -2294,14 +2333,14 @@ int horizontal_log_grid(
                                 double mfac = 1;
                                 char   *symb = "";
                                 auto_scale(im,&sval,&symb,&mfac);
-                                sprintf(graph_label_right,"%4.0f %s", sval,symb);
+                                snprintf(graph_label_right, sizeof graph_label_right, "%4.0f %s", sval,symb);
                         }
                         else {
-                                sprintf(graph_label_right,"%3.0e", sval);
+                                snprintf(graph_label_right, sizeof graph_label_right, "%3.0e", sval);
                         }
                 }
                 else {
-                      sprintf(graph_label_right,im->second_axis_format,sval,"");
+                      snprintf(graph_label_right, sizeof graph_label_right, im->second_axis_format,sval,"");
                 }
 
                 gfx_text ( im,
@@ -2506,19 +2545,20 @@ void vertical_grid(
                              mgridtm,
                              im->xlab_user.
                              mgridst);
-             ti < im->end;
+             ti < im->end && ti != -1;
              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) {
+            while (timajor < ti && timajor != -1) {
                 timajor = find_next_time(timajor,
                                          im->
                                          xlab_user.
                                          mgridtm, im->xlab_user.mgridst);
             }
+            if (timajor == -1) break; /* fail in case of problems with time increments */
             if (ti == timajor)
                 continue;   /* skip as falls on major grid line */
             X0 = xtr(im, ti);
@@ -2542,7 +2582,7 @@ void vertical_grid(
                               im->
                               xlab_user.
                               mgridst);
-         ti < im->end;
+         ti < im->end && ti != -1;
          ti = find_next_time(ti, im->xlab_user.mgridtm, im->xlab_user.mgridst)
         ) {
         /* are we inside the graph ? */
@@ -2568,9 +2608,9 @@ void vertical_grid(
                          labtm,
                          im->xlab_user.
                          labst);
-         ti <=
+         (ti <=
          im->end -
-         im->xlab_user.precis / 2;
+         im->xlab_user.precis / 2) && ti != -1;
          ti = find_next_time(ti, im->xlab_user.labtm, im->xlab_user.labst)
         ) {
         tilab = ti + im->xlab_user.precis / 2;  /* correct time for the label */
@@ -2929,6 +2969,7 @@ int graph_size_location(
         im->ximg = im->xsize;
         im->yimg = im->ysize;
         im->yorigin = im->ysize;
+        xtr(im, 0);
         ytr(im, DNAN);
         return 0;
     }
@@ -2960,7 +3001,7 @@ int graph_size_location(
     }
     else{
         // we have no title; get a little clearing from the top
-        Ytitle = 1.5 * Yspacing;
+        Ytitle = Yspacing;
     }
 
     if (elements) {
@@ -3054,7 +3095,7 @@ int graph_size_location(
 
             /* reserve space for padding below the graph */
         if (im->extra_flags & NOLEGEND) {
-            Ymain -= Yspacing;
+            Ymain -= 0.5*Yspacing;
         }
 
         if (im->watermark[0] != '\0') {
@@ -3114,7 +3155,7 @@ int graph_size_location(
         }
         /* reserve space for padding below the graph */
         if (im->extra_flags & NOLEGEND) {
-            im->yimg += Yspacing;
+            im->yimg += 0.5*Yspacing;
         }
 
         if (im->watermark[0] != '\0') {
@@ -3143,7 +3184,7 @@ int graph_size_location(
      */
     switch(im->legendposition){
         case NORTH:
-            im->xOriginTitle   = Xvertical + Xylabel + (im->xsize / 2);
+            im->xOriginTitle   = (im->ximg / 2);
             im->yOriginTitle   = 0;
 
             im->xOriginLegend  = 0;
@@ -3164,7 +3205,7 @@ int graph_size_location(
             break;
 
         case WEST:
-            im->xOriginTitle   = im->legendwidth + Xvertical + Xylabel + im->xsize / 2;
+            im->xOriginTitle   = im->legendwidth + im->xsize / 2;
             im->yOriginTitle   = 0;
 
             im->xOriginLegend  = 0;
@@ -3185,7 +3226,7 @@ int graph_size_location(
             break;
 
         case SOUTH:
-            im->xOriginTitle   = Xvertical + Xylabel + im->xsize / 2;
+            im->xOriginTitle   = im->ximg / 2;
             im->yOriginTitle   = 0;
 
             im->xOriginLegend  = 0;
@@ -3206,7 +3247,7 @@ int graph_size_location(
             break;
 
         case EAST:
-            im->xOriginTitle   = Xvertical + Xylabel + im->xsize / 2;
+            im->xOriginTitle   = im->xsize / 2;
             im->yOriginTitle   = 0;
 
             im->xOriginLegend  = Xvertical + Xylabel + Xmain + Xvertical2;
@@ -3263,13 +3304,15 @@ static cairo_status_t cairo_output(
 int graph_paint(
     image_desc_t *im)
 {
-    int       i, ii;
     int       lazy = lazy_check(im);
-    double    areazero = 0.0;
-    graph_desc_t *lastgdes = NULL;
-    rrd_infoval_t info;
+    int       cnt;      
 
-//    PangoFontMap *font_map = pango_cairo_font_map_get_default();
+    /* imgformat XML or higher dispatch to xport 
+     * output format there is selected via graph_type 
+     */
+    if (im->imgformat >= IF_XML) {
+      return rrd_graph_xport(im);
+    }
 
     /* pull the data from the rrd files ... */
     if (data_fetch(im) == -1)
@@ -3282,19 +3325,41 @@ int graph_paint(
      * 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)
+    cnt = print_calc(im);
+    if (cnt < 0)
         return -1;
 
     /* if we want and can be lazy ... quit now */
-    if (i == 0)
+    if (cnt == 0)
         return 0;
 
+    /* otherwise call graph_paint_timestring */
+    switch (im->graph_type) {
+    case GTYPE_TIME:
+      return graph_paint_timestring(im,lazy,cnt);
+      break;
+    case GTYPE_XY:
+      return graph_paint_xy(im,lazy,cnt);
+      break;      
+    }
+    /* final return with error*/
+    rrd_set_error("Graph type %i is not implemented",im->graph_type);
+    return -1;
+}
+
+int graph_paint_timestring(
+                          image_desc_t *im, int lazy, int cnt)
+{
+    int       i,ii;
+    double    areazero = 0.0;
+    graph_desc_t *lastgdes = NULL;
+    rrd_infoval_t info;
+
 /**************************************************************
  *** Calculating sizes and locations became a bit confusing ***
  *** so I moved this into a separate function.              ***
  **************************************************************/
-    if (graph_size_location(im, i) == -1)
+    if (graph_size_location(im, cnt) == -1)
         return -1;
 
     info.u_cnt = im->xorigin;
@@ -3342,67 +3407,11 @@ int graph_paint(
     ytr(im, DNAN);
 /*   if (im->gridfit)
      apply_gridfit(im); */
-    /* the actual graph is created by going through the individual
-       graph elements and then drawing them */
-    cairo_surface_destroy(im->surface);
-    switch (im->imgformat) {
-    case IF_PNG:
-        im->surface =
-            cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                       im->ximg * im->zoom,
-                                       im->yimg * im->zoom);
-        break;
-    case IF_PDF:
-        im->gridfit = 0;
-        im->surface = strlen(im->graphfile)
-            ? cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom,
-                                       im->yimg * im->zoom)
-            : cairo_pdf_surface_create_for_stream
-            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
-        break;
-    case IF_EPS:
-        im->gridfit = 0;
-        im->surface = strlen(im->graphfile)
-            ?
-            cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom,
-                                    im->yimg * im->zoom)
-            : cairo_ps_surface_create_for_stream
-            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
-        break;
-    case IF_SVG:
-        im->gridfit = 0;
-        im->surface = strlen(im->graphfile)
-            ?
-            cairo_svg_surface_create(im->
-                                     graphfile,
-                                     im->ximg * im->zoom, im->yimg * im->zoom)
-            : cairo_svg_surface_create_for_stream
-            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
-        cairo_svg_surface_restrict_to_version
-            (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);
-    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);
-    gfx_close_path(im);
-    gfx_new_area(im, im->xorigin,
-                 im->yorigin,
-                 im->xorigin +
-                 im->xsize, im->yorigin,
-                 im->xorigin +
-                 im->xsize,
-                 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);
+
+    /* set up cairo */
+    if (graph_cairo_setup(im)) { return -1; }
+
+    /* other stuff */
     if (im->minval > 0.0)
         areazero = im->minval;
     if (im->maxval < 0.0)
@@ -3420,6 +3429,8 @@ int graph_paint(
         case GF_VRULE:
         case GF_XPORT:
         case GF_SHIFT:
+        case GF_XAXIS:
+        case GF_YAXIS:
             break;
         case GF_TICK:
             for (ii = 0; ii < im->xsize; ii++) {
@@ -3448,17 +3459,27 @@ int graph_paint(
             break;
         case GF_LINE:
         case GF_AREA:
-               case GF_GRAD:
-            /* fix data points at oo and -oo */
+        case GF_GRAD: {
+            rrd_value_t diffval = im->maxval - im->minval;
+            rrd_value_t maxlimit = im->maxval + 9 * diffval;
+            rrd_value_t minlimit = im->minval - 9 * diffval;        
             for (ii = 0; ii < im->xsize; ii++) {
+                /* fix data points at oo and -oo */
                 if (isinf(im->gdes[i].p_data[ii])) {
                     if (im->gdes[i].p_data[ii] > 0) {
                         im->gdes[i].p_data[ii] = im->maxval;
                     } else {
                         im->gdes[i].p_data[ii] = im->minval;
                     }
-
                 }
+                /* some versions of cairo go unstable when trying
+                   to draw way out of the canvas ... lets not even try */
+               if (im->gdes[i].p_data[ii] > maxlimit) {
+                   im->gdes[i].p_data[ii] = maxlimit;
+               }
+               if (im->gdes[i].p_data[ii] < minlimit) {
+                   im->gdes[i].p_data[ii] = minlimit;
+               }
             }           /* for */
 
             /* *******************************************************
@@ -3726,6 +3747,7 @@ int graph_paint(
             }
             lastgdes = &(im->gdes[i]);
             break;
+        } /* GF_AREA, GF_LINE, GF_GRAD */
         case GF_STACK:
             rrd_set_error
                 ("STACK should already be turned into LINE or AREA here");
@@ -3785,7 +3807,86 @@ int graph_paint(
             break;
         }
     }
+    /* close the graph via cairo*/
+    return graph_cairo_finish(im);
+}
+
+int graph_cairo_setup (image_desc_t *im)
+{
+    /* the actual graph is created by going through the individual
+       graph elements and then drawing them */
+    cairo_surface_destroy(im->surface);
+    switch (im->imgformat) {
+    case IF_PNG:
+        im->surface =
+            cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                       im->ximg * im->zoom,
+                                       im->yimg * im->zoom);
+        break;
+    case IF_PDF:
+        im->gridfit = 0;
+        im->surface = strlen(im->graphfile)
+            ? cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom,
+                                       im->yimg * im->zoom)
+            : cairo_pdf_surface_create_for_stream
+            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+        break;
+    case IF_EPS:
+        im->gridfit = 0;
+        im->surface = strlen(im->graphfile)
+            ?
+            cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom,
+                                    im->yimg * im->zoom)
+            : cairo_ps_surface_create_for_stream
+            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+        break;
+    case IF_SVG:
+        im->gridfit = 0;
+        im->surface = strlen(im->graphfile)
+            ?
+            cairo_svg_surface_create(im->
+                                     graphfile,
+                                     im->ximg * im->zoom, im->yimg * im->zoom)
+            : cairo_svg_surface_create_for_stream
+            (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom);
+        cairo_svg_surface_restrict_to_version
+            (im->surface, CAIRO_SVG_VERSION_1_1);
+        break;
+    case IF_XML:
+    case IF_XMLENUM:
+    case IF_CSV:
+    case IF_TSV:
+    case IF_SSV:
+    case IF_JSON:
+    case IF_JSONTIME:
+        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);
+    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);
+    gfx_close_path(im);
+    gfx_new_area(im, im->xorigin,
+                 im->yorigin,
+                 im->xorigin +
+                 im->xsize, im->yorigin,
+                 im->xorigin +
+                 im->xsize,
+                 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);
+    return 0;
+}
 
+int graph_cairo_finish (image_desc_t *im)
+{
 
     switch (im->imgformat) {
     case IF_PNG:
@@ -3803,6 +3904,14 @@ int graph_paint(
         }
         break;
     }
+    case IF_XML:
+    case IF_XMLENUM:
+    case IF_CSV:
+    case IF_TSV:
+    case IF_SSV:
+    case IF_JSON:
+    case IF_JSONTIME:
+      break;
     default:
         if (strlen(im->graphfile)) {
             cairo_show_page(im->cr);
@@ -3815,6 +3924,14 @@ int graph_paint(
     return 0;
 }
 
+int graph_paint_xy(
+                  image_desc_t *im, int lazy, int cnt)
+{
+  /* to stop compiler warnings for now */
+  lazy=cnt=(int)im->gdes_c;
+  rrd_set_error("XY diagramm not implemented");  
+  return -1;
+}
 
 /*****************************************************
  * graph stuff
@@ -3832,6 +3949,8 @@ int gdes_alloc(
         return -1;
     }
 
+    /* set to zero */
+    memset(&(im->gdes[im->gdes_c - 1]),0,sizeof(graph_desc_t));
 
     im->gdes[im->gdes_c - 1].step = im->step;
     im->gdes[im->gdes_c - 1].step_orig = im->step;
@@ -3927,9 +4046,7 @@ int rrd_graph(
                 return 0;
             }
             /* imginfo goes to position 0 in the prdata array */
-            (*prdata)[prlines - 1] = (char*)malloc((strlen(walker->value.u_str)
-                                             + 2) * sizeof(char));
-            strcpy((*prdata)[prlines - 1], walker->value.u_str);
+            (*prdata)[prlines - 1] = strdup(walker->value.u_str);
             (*prdata)[prlines] = NULL;
         }
         /* skip anything else */
@@ -3957,10 +4074,8 @@ int rrd_graph(
                 rrd_set_error("realloc prdata");
                 return 0;
             }
-            (*prdata)[prlines - 1] = (char*)malloc((strlen(walker->value.u_str)
-                                             + 2) * sizeof(char));
+            (*prdata)[prlines - 1] = strdup(walker->value.u_str);
             (*prdata)[prlines] = NULL;
-            strcpy((*prdata)[prlines - 1], walker->value.u_str);
         } else if (strcmp(walker->key, "image") == 0) {
             if ( fwrite(walker->value.u_blo.ptr, walker->value.u_blo.size, 1,
                    (stream ? stream : stdout)) == 0 && ferror(stream ? stream : stdout)){
@@ -3982,6 +4097,7 @@ int rrd_graph(
 ** - options parsing  now in rrd_graph_options()
 ** - script parsing   now in rrd_graph_script()
 */
+
 rrd_info_t *rrd_graph_v(
     int argc,
     char **argv)
@@ -4032,16 +4148,14 @@ rrd_info_t *rrd_graph_v(
         im_free(&im);
         return NULL;
     }
-
+    
     /* Everything is now read and the actual work can start */
-
     if (graph_paint(&im) == -1) {
-        rrd_info_free(im.grinfo);
-        im_free(&im);
-        return NULL;
+      rrd_info_free(im.grinfo);
+      im_free(&im);
+      return NULL;
     }
 
-
     /* The image is generated and needs to be output.
      ** Also, if needed, print a line with information about the image.
      */
@@ -4101,10 +4215,13 @@ void rrd_graph_init(
     static PangoFontMap *fontmap = NULL;
     PangoContext *context;
 
+    /* zero the whole structure first */
+    memset(im,0,sizeof(image_desc_t));
+
 #ifdef HAVE_TZSET
     tzset();
 #endif
-
+    im->graph_type = GTYPE_TIME;
     im->base = 1000;
     im->daemon_addr = NULL;
     im->draw_x_grid = 1;
@@ -4133,6 +4250,7 @@ void rrd_graph_init(
     im->maxval = DNAN;
     im->minval = 0;
     im->minval = DNAN;
+    im->magfact = 1;
     im->prt_c = 0;
     im->rigid = 0;
     im->rendered_image_size = 0;
@@ -4282,6 +4400,8 @@ void rrd_graph_options(
         { "border",             required_argument, 0, 1007},
         { "grid-dash",          required_argument, 0, 1008},
         { "dynamic-labels",     no_argument,       0, 1009},
+        { "week-fmt",           required_argument, 0, 1010},
+        { "graph-type",         required_argument, 0, 1011},
         {  0, 0, 0, 0}
 };
 /* *INDENT-ON* */
@@ -4467,6 +4587,10 @@ void rrd_graph_options(
         case 1009: /* enable dynamic labels */
             im->dynamic_labels = 1;
             break;         
+        case 1010:
+            strncpy(week_fmt,optarg,sizeof week_fmt);
+            week_fmt[(sizeof week_fmt)-1]='\0';
+            break;
         case 1002: /* right y axis */
 
             if(sscanf(optarg,
@@ -4547,6 +4671,13 @@ void rrd_graph_options(
                 return;
             }
             break;
+        case 1011:
+            if ((int)
+                (im->graph_type = type_conv(optarg)) == -1) {
+                rrd_set_error("unsupported graphics type '%s'", optarg);
+                return;
+            }
+            break;
         case 'z':
             im->lazy = 1;
             break;