X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_graph.c;h=94616cb44f44cf5f79ec674e440ee6abd3db2a15;hp=d7781f6dec454edd7b6b9d19a8784d6801c1713d;hb=586cc1f6f770892aa24f08e38a6c14c2c47ee560;hpb=40ed0940c50dc10e7820ce5ad55f71940b108b95 diff --git a/src/rrd_graph.c b/src/rrd_graph.c index d7781f6..94616cb 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -91,8 +91,7 @@ xlab_t xlab[] = { , {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_fmt} + {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"} @@ -257,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) { @@ -413,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 */ @@ -428,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( @@ -896,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, @@ -1403,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: @@ -1471,6 +1496,8 @@ time_t find_next_time( time_t madetime; localtime_r(¤t, &tm); + /* let mktime figure this dst on its own */ + tm.tm_isdst = -1; int limit = 2; switch (baseint) { @@ -1649,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; } @@ -1695,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; @@ -1715,7 +1740,6 @@ int leg_place( int leg_c = 0; double leg_x = border; int leg_y = 0; //im->yimg; - int leg_y_prev = 0; // im->yimg; int leg_cc; double glue = 0; int i, ii, mark = 0; @@ -1741,7 +1765,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; @@ -1782,6 +1806,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 @@ -1793,6 +1818,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' && @@ -1886,7 +1915,6 @@ int leg_place( +(double)legspace[ii] + glue; } - leg_y_prev = leg_y; if (leg_x > border || prt_fctn == 's') leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8; if (prt_fctn == 's') @@ -1903,7 +1931,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); } } @@ -1986,7 +2014,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 { @@ -1994,7 +2022,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 */ @@ -2058,15 +2086,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); } } @@ -2074,15 +2102,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); } } @@ -2099,13 +2127,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, @@ -2291,9 +2319,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]; @@ -2303,14 +2331,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, @@ -2939,6 +2967,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; } @@ -3273,13 +3302,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) @@ -3292,19 +3323,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; @@ -3352,67 +3405,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) @@ -3430,6 +3427,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++) { @@ -3806,7 +3805,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: @@ -3824,6 +3902,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); @@ -3836,6 +3922,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 @@ -3853,6 +3947,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; @@ -3948,9 +4044,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 */ @@ -3978,10 +4072,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)){ @@ -4003,6 +4095,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) @@ -4053,16 +4146,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. */ @@ -4122,10 +4213,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; @@ -4154,6 +4248,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; @@ -4304,6 +4399,7 @@ void rrd_graph_options( { "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* */ @@ -4573,6 +4669,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;