X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_graph.c;h=795a6accf50035f6b9fe567485707beb1bec1ee3;hb=37f9575eecddf13374595b5df550bdcbef4adc24;hp=f7ea57286a4112250d9cf0e92f471e2cbd73614d;hpb=ad6f3441d407ca0c82b86b481f697ca913844d54;p=rrdtool.git diff --git a/src/rrd_graph.c b/src/rrd_graph.c index f7ea572..795a6ac 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -1,5 +1,5 @@ /**************************************************************************** - * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007 + * RRDtool 1.2.99907080300 Copyright by Tobi Oetiker, 1997-2007 **************************************************************************** * rrd__graph.c produce graphs from data in rrdfiles ****************************************************************************/ @@ -308,7 +308,7 @@ int im_free( image_desc_t *im) { unsigned long i, ii; - cairo_status_t status; + cairo_status_t status = 0; if (im == NULL) return 0; @@ -322,6 +322,10 @@ int im_free( free(im->gdes[i].ds_namv); } } + /* free allocated memory used for dashed lines */ + if (im->gdes[i].p_dashes != NULL) + free(im->gdes[i].p_dashes); + free(im->gdes[i].p_data); free(im->gdes[i].rpnp); } @@ -329,14 +333,14 @@ int im_free( if (im->font_options) cairo_font_options_destroy(im->font_options); - status = cairo_status(im->cr); - - if (im->cr) + if (im->cr) { + status = cairo_status(im->cr); cairo_destroy(im->cr); + } if (im->surface) cairo_surface_destroy(im->surface); if (status) - fprintf(stderr, "OOPS: Cairo has issuesm it can't even die: %s\n", + fprintf(stderr, "OOPS: Cairo has issues it can't even die: %s\n", cairo_status_to_string(status)); return 0; @@ -1115,6 +1119,39 @@ int data_calc( return 0; } +static int AlmostEqual2sComplement( + float A, + float B, + int maxUlps) +{ + + int aInt = *(int *) &A; + int bInt = *(int *) &B; + int intDiff; + + /* Make sure maxUlps is non-negative and small enough that the + default NAN won't compare as equal to anything. */ + + /* assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); */ + + /* Make aInt lexicographically ordered as a twos-complement int */ + + if (aInt < 0) + aInt = 0x80000000l - aInt; + + /* Make bInt lexicographically ordered as a twos-complement int */ + + if (bInt < 0) + bInt = 0x80000000l - bInt; + + intDiff = abs(aInt - bInt); + + if (intDiff <= maxUlps) + return 1; + + return 0; +} + /* massage data so, that we get one value for each x coordinate in the graph */ int data_proc( image_desc_t *im) @@ -1227,8 +1264,8 @@ int data_proc( } /* adjust min and max values */ + /* for logscale we add something on top */ if (isnan(im->minval) - /* don't adjust low-end with log scale *//* why not? */ || ((!im->rigid) && im->minval > minval) ) { if (im->logarithmic) @@ -1244,19 +1281,24 @@ int data_proc( else im->maxval = maxval; } + /* make sure min is smaller than max */ if (im->minval > im->maxval) { - im->minval = 0.99 * im->maxval; + if (im->minval > 0) + im->minval = 0.99 * im->maxval; + else + im->minval = 1.01 * im->maxval; } /* make sure min and max are not equal */ - if (im->minval == im->maxval) { - im->maxval *= 1.01; - if (!im->logarithmic) { - im->minval *= 0.99; - } + if (AlmostEqual2sComplement(im->minval, im->maxval, 4)) { + if (im->maxval > 0) + im->maxval *= 1.01; + else + im->maxval *= 0.99; + /* make sure min and max are not both zero */ - if (im->maxval == 0.0) { + if (AlmostEqual2sComplement(im->maxval, 0, 4)) { im->maxval = 1.0; } } @@ -2001,38 +2043,6 @@ double frexp10( /* yes we are loosing precision by doing tos with floats instead of doubles but it seems more stable this way. */ -static int AlmostEqual2sComplement( - float A, - float B, - int maxUlps) -{ - - int aInt = *(int *) &A; - int bInt = *(int *) &B; - int intDiff; - - /* Make sure maxUlps is non-negative and small enough that the - default NAN won't compare as equal to anything. */ - - /* assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); */ - - /* Make aInt lexicographically ordered as a twos-complement int */ - - if (aInt < 0) - aInt = 0x80000000l - aInt; - - /* Make bInt lexicographically ordered as a twos-complement int */ - - if (bInt < 0) - bInt = 0x80000000l - bInt; - - intDiff = abs(aInt - bInt); - - if (intDiff <= maxUlps) - return 1; - - return 0; -} /* logaritmic horizontal grid */ int horizontal_log_grid( @@ -2594,6 +2604,11 @@ void grid_paint( im->graph_col[GRC_FRAME].green, im->graph_col[GRC_FRAME].blue, im->graph_col[GRC_FRAME].alpha); + if (im->gdes[i].dash) { + // make box borders in legend dashed if the graph is dashed + double dashes[] = { 3.0 }; + cairo_set_dash(im->cr, dashes, 1, 0.0); + } cairo_stroke(im->cr); cairo_restore(im->cr); } @@ -3016,9 +3031,9 @@ int graph_paint( break; }; im->cr = cairo_create(im->surface); - pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100); 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, @@ -3114,6 +3129,12 @@ int graph_paint( cairo_new_path(im->cr); cairo_set_line_width(im->cr, im->gdes[i].linewidth); + + if (im->gdes[i].dash) { + cairo_set_dash(im->cr, im->gdes[i].p_dashes, + im->gdes[i].ndash, im->gdes[i].offset); + } + for (ii = 1; ii < im->xsize; ii++) { if (isnan(im->gdes[i].p_data[ii]) || (im->slopemode == 1 @@ -3174,10 +3195,14 @@ int graph_paint( cairo_restore(im->cr); } else { int idxI = -1; - double *foreY = malloc(sizeof(double) * im->xsize * 2); - double *foreX = malloc(sizeof(double) * im->xsize * 2); - double *backY = malloc(sizeof(double) * im->xsize * 2); - double *backX = malloc(sizeof(double) * im->xsize * 2); + double *foreY = + (double *) malloc(sizeof(double) * im->xsize * 2); + double *foreX = + (double *) malloc(sizeof(double) * im->xsize * 2); + double *backY = + (double *) malloc(sizeof(double) * im->xsize * 2); + double *backX = + (double *) malloc(sizeof(double) * im->xsize * 2); int drawem = 0; for (ii = 0; ii <= im->xsize; ii++) { @@ -3321,19 +3346,33 @@ int graph_paint( case GF_HRULE: if (im->gdes[i].yrule >= im->minval && im->gdes[i].yrule <= im->maxval) - gfx_line(im, - im->xorigin, ytr(im, im->gdes[i].yrule), - im->xorigin + im->xsize, ytr(im, - im->gdes[i].yrule), - 1.0, im->gdes[i].col); + cairo_save(im->cr); + if (im->gdes[i].dash) { + cairo_set_dash(im->cr, im->gdes[i].p_dashes, + im->gdes[i].ndash, im->gdes[i].offset); + } + gfx_line(im, + im->xorigin, ytr(im, im->gdes[i].yrule), + im->xorigin + im->xsize, ytr(im, + im->gdes[i].yrule), + 1.0, im->gdes[i].col); + cairo_stroke(im->cr); + cairo_restore(im->cr); break; case GF_VRULE: if (im->gdes[i].xrule >= im->start && im->gdes[i].xrule <= im->end) - gfx_line(im, - xtr(im, im->gdes[i].xrule), im->yorigin, - xtr(im, im->gdes[i].xrule), - im->yorigin - im->ysize, 1.0, im->gdes[i].col); + cairo_save(im->cr); + if (im->gdes[i].dash) { + cairo_set_dash(im->cr, im->gdes[i].p_dashes, + im->gdes[i].ndash, im->gdes[i].offset); + } + gfx_line(im, + xtr(im, im->gdes[i].xrule), im->yorigin, + xtr(im, im->gdes[i].xrule), + im->yorigin - im->ysize, 1.0, im->gdes[i].col); + cairo_stroke(im->cr); + cairo_restore(im->cr); break; default: break; @@ -3409,6 +3448,7 @@ int gdes_alloc( im->gdes[im->gdes_c - 1].data_first = 0; im->gdes[im->gdes_c - 1].p_data = NULL; im->gdes[im->gdes_c - 1].rpnp = NULL; + im->gdes[im->gdes_c - 1].p_dashes = NULL; im->gdes[im->gdes_c - 1].shift = 0.0; im->gdes[im->gdes_c - 1].col.red = 0.0; im->gdes[im->gdes_c - 1].col.green = 0.0; @@ -3421,7 +3461,6 @@ int gdes_alloc( im->gdes[im->gdes_c - 1].ds = -1; im->gdes[im->gdes_c - 1].cf_reduce = CF_AVERAGE; im->gdes[im->gdes_c - 1].cf = CF_AVERAGE; - im->gdes[im->gdes_c - 1].p_data = NULL; im->gdes[im->gdes_c - 1].yrule = DNAN; im->gdes[im->gdes_c - 1].xrule = 0; return 0; @@ -3721,6 +3760,7 @@ void rrd_graph_options( long long_tmp; struct rrd_time_value 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 */ @@ -3816,6 +3856,7 @@ void rrd_graph_options( case LONGOPT_UNITS_SI: if (im->extra_flags & FORCE_UNITS) { rrd_set_error("--units can only be used once!"); + setlocale(LC_NUMERIC, old_locale); return; } if (strcmp(optarg, "si") == 0) @@ -3833,10 +3874,14 @@ void rrd_graph_options( im->forceleftspace = 1; break; case 'T': + old_locale = setlocale(LC_NUMERIC, "C"); im->tabwidth = atof(optarg); + setlocale(LC_NUMERIC, old_locale); break; case 'S': + old_locale = setlocale(LC_NUMERIC, "C"); im->step = atoi(optarg); + setlocale(LC_NUMERIC, old_locale); break; case 'N': im->gridfit = 0; @@ -3896,8 +3941,9 @@ void rrd_graph_options( im->draw_y_grid = 0; break; }; - + old_locale = setlocale(LC_NUMERIC, "C"); if (sscanf(optarg, "%lf:%d", &im->ygridstep, &im->ylabfact) == 2) { + setlocale(LC_NUMERIC, old_locale); if (im->ygridstep <= 0) { rrd_set_error("grid step must be > 0"); return; @@ -3906,6 +3952,7 @@ void rrd_graph_options( return; } } else { + setlocale(LC_NUMERIC, old_locale); rrd_set_error("invalid y-grid format"); return; } @@ -3915,10 +3962,14 @@ void rrd_graph_options( im->ylegend[150] = '\0'; break; case 'u': + old_locale = setlocale(LC_NUMERIC, "C"); im->maxval = atof(optarg); + setlocale(LC_NUMERIC, old_locale); break; case 'l': + old_locale = setlocale(LC_NUMERIC, "C"); im->minval = atof(optarg); + setlocale(LC_NUMERIC, old_locale); break; case 'b': im->base = atol(optarg); @@ -4017,9 +4068,11 @@ void rrd_graph_options( double size = 1; char font[1024] = ""; + old_locale = setlocale(LC_NUMERIC, "C"); if (sscanf(optarg, "%10[A-Z]:%lf:%1000s", prop, &size, font) >= 2) { int sindex, propidx; + setlocale(LC_NUMERIC, old_locale); if ((sindex = text_prop_conv(prop)) != -1) { for (propidx = sindex; propidx < TEXT_PROP_LAST; propidx++) { @@ -4037,13 +4090,16 @@ void rrd_graph_options( return; } } else { + setlocale(LC_NUMERIC, old_locale); rrd_set_error("invalid text property format"); return; } break; } case 'm': + old_locale = setlocale(LC_NUMERIC, "C"); im->zoom = atof(optarg); + setlocale(LC_NUMERIC, old_locale); if (im->zoom <= 0.0) { rrd_set_error("zoom factor must be > 0"); return; @@ -4243,9 +4299,12 @@ int vdef_parse( double param; char func[30]; int n; + char *old_locale; n = 0; + old_locale = setlocale(LC_NUMERIC, "C"); sscanf(str, "%le,%29[A-Z]%n", ¶m, func, &n); + setlocale(LC_NUMERIC, old_locale); if (n == (int) strlen(str)) { /* matched */ ; } else { @@ -4265,6 +4324,8 @@ int vdef_parse( gdes->vf.op = VDEF_MAXIMUM; else if (!strcmp("AVERAGE", func)) gdes->vf.op = VDEF_AVERAGE; + else if (!strcmp("STDEV", func)) + gdes->vf.op = VDEF_STDEV; else if (!strcmp("MINIMUM", func)) gdes->vf.op = VDEF_MINIMUM; else if (!strcmp("TOTAL", func)) @@ -4304,6 +4365,7 @@ int vdef_parse( break; case VDEF_MAXIMUM: case VDEF_AVERAGE: + case VDEF_STDEV: case VDEF_MINIMUM: case VDEF_TOTAL: case VDEF_FIRST: @@ -4392,9 +4454,11 @@ int vdef_calc( } break; case VDEF_TOTAL: + case VDEF_STDEV: case VDEF_AVERAGE:{ int cnt = 0; double sum = 0.0; + double average = 0.0; for (step = 0; step < steps; step++) { if (finite(data[step * src->ds_cnt])) { @@ -4406,9 +4470,19 @@ int vdef_calc( if (dst->vf.op == VDEF_TOTAL) { dst->vf.val = sum * src->step; dst->vf.when = 0; /* no time component */ - } else { + } else if (dst->vf.op == VDEF_AVERAGE) { dst->vf.val = sum / cnt; dst->vf.when = 0; /* no time component */ + } else { + average = sum / cnt; + sum = 0.0; + for (step = 0; step < steps; step++) { + if (finite(data[step * src->ds_cnt])) { + sum += pow((data[step * src->ds_cnt] - average), 2.0); + }; + } + dst->vf.val = pow(sum / cnt, 0.5); + dst->vf.when = 0; /* no time component */ }; } else { dst->vf.val = DNAN;