X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_graph.c;h=a037563075bd392780cf1e9456b4a50ef217174a;hp=c58326fa9c4cddb7fb7f620eca377125db79b092;hb=e6d6ed89bc84009c5ea94d5e2c770833afb80f21;hpb=48fb6edebc0e55ad793c40eff8b7a1e7880c9ca8 diff --git a/src/rrd_graph.c b/src/rrd_graph.c index c58326f..a037563 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -4,24 +4,25 @@ * rrd__graph.c make creates ne rrds ****************************************************************************/ -#if 0 -#include "rrd_tool.h" -#endif #include + +#include "rrd_tool.h" + #ifdef WIN32 #include #include #endif + #ifdef HAVE_TIME_H #include #endif + #ifdef HAVE_LOCALE_H #include #endif #include "rrd_graph.h" -#include "rrd_graph_helper.h" /* some constant definitions */ @@ -129,7 +130,7 @@ xtr(image_desc_t *im,time_t mytime){ } /* translate data values into y coordinates */ -int +double ytr(image_desc_t *im, double value){ static double pixie; double yval; @@ -140,26 +141,25 @@ ytr(image_desc_t *im, double value){ pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval)); yval = im->yorigin; } else if(!im->logarithmic) { - yval = im->yorigin - pixie * (value - im->minval) + 0.5; + yval = im->yorigin - pixie * (value - im->minval); } else { if (value < im->minval) { yval = im->yorigin; } else { - yval = im->yorigin - pixie * (log10(value) - log10(im->minval)) + 0.5; + yval = im->yorigin - pixie * (log10(value) - log10(im->minval)); } } /* make sure we don't return anything too unreasonable. GD lib can get terribly slow when drawing lines outside its scope. This is especially problematic in connection with the rigid option */ if (! im->rigid) { - return (int)yval; - } else if ((int)yval > im->yorigin) { - return im->yorigin+2; - } else if ((int) yval < im->yorigin - im->ysize){ - return im->yorigin - im->ysize - 2; - } else { - return (int)yval; + /* keep yval as-is */ + } else if (yval > im->yorigin) { + yval = im->yorigin+2; + } else if (yval < im->yorigin - im->ysize){ + yval = im->yorigin - im->ysize - 2; } + return yval; } @@ -185,6 +185,7 @@ enum gf_en gf_conv(char *string){ conv_if(CDEF,GF_CDEF) conv_if(VDEF,GF_VDEF) conv_if(PART,GF_PART) + conv_if(XPORT,GF_XPORT) return (-1); } @@ -194,6 +195,7 @@ enum gfx_if_en if_conv(char *string){ conv_if(PNG,IF_PNG) conv_if(SVG,IF_SVG) conv_if(EPS,IF_EPS) + conv_if(PDF,IF_PDF) return (-1); } @@ -238,14 +240,13 @@ enum text_prop_en text_prop_conv(char *string){ #undef conv_if - - int im_free(image_desc_t *im) { - long i,ii; + unsigned long i,ii; + if (im == NULL) return 0; - for(i=0;igdes_c;i++){ + 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 */ free (im->gdes[i].data); @@ -438,7 +439,73 @@ expand_range(image_desc_t *im) #endif } - +void +apply_gridfit(image_desc_t *im) +{ + if (isnan(im->minval) || isnan(im->maxval)) + return; + ytr(im,DNAN); + if (im->logarithmic) { + double ya, yb, ypix, ypixfrac; + double log10_range = log10(im->maxval) - log10(im->minval); + ya = pow((double)10, floor(log10(im->minval))); + while (ya < im->minval) + ya *= 10; + if (ya > im->maxval) + return; /* don't have y=10^x gridline */ + yb = ya * 10; + if (yb <= im->maxval) { + /* we have at least 2 y=10^x gridlines. + Make sure distance between them in pixels + are an integer by expanding im->maxval */ + double y_pixel_delta = ytr(im, ya) - ytr(im, yb); + double factor = y_pixel_delta / floor(y_pixel_delta); + double new_log10_range = factor * log10_range; + double new_ymax_log10 = log10(im->minval) + new_log10_range; + im->maxval = pow(10, new_ymax_log10); + ytr(im, DNAN); /* reset precalc */ + log10_range = log10(im->maxval) - log10(im->minval); + } + /* make sure first y=10^x gridline is located on + integer pixel position by moving scale slightly + downwards (sub-pixel movement) */ + ypix = ytr(im, ya) + im->ysize; /* add im->ysize so it always is positive */ + ypixfrac = ypix - floor(ypix); + if (ypixfrac > 0 && ypixfrac < 1) { + double yfrac = ypixfrac / im->ysize; + im->minval = pow(10, log10(im->minval) - yfrac * log10_range); + im->maxval = pow(10, log10(im->maxval) - yfrac * log10_range); + ytr(im, DNAN); /* reset precalc */ + } + } else { + /* Make sure we have an integer pixel distance between + each minor gridline */ + double ypos1 = ytr(im, im->minval); + double ypos2 = ytr(im, im->minval + im->ygrid_scale.gridstep); + double y_pixel_delta = ypos1 - ypos2; + double factor = y_pixel_delta / floor(y_pixel_delta); + double new_range = factor * (im->maxval - im->minval); + double gridstep = im->ygrid_scale.gridstep; + double minor_y, minor_y_px, minor_y_px_frac; + im->maxval = im->minval + new_range; + ytr(im, DNAN); /* reset precalc */ + /* make sure first minor gridline is on integer pixel y coord */ + minor_y = gridstep * floor(im->minval / gridstep); + while (minor_y < im->minval) + minor_y += gridstep; + minor_y_px = ytr(im, minor_y) + im->ysize; /* ensure > 0 by adding ysize */ + minor_y_px_frac = minor_y_px - floor(minor_y_px); + if (minor_y_px_frac > 0 && minor_y_px_frac < 1) { + double yfrac = minor_y_px_frac / im->ysize; + double range = im->maxval - im->minval; + im->minval = im->minval - yfrac * range; + im->maxval = im->maxval - yfrac * range; + ytr(im, DNAN); /* reset precalc */ + } + calc_horizontal_grid(im); /* recalc with changed im->maxval */ + } +} + /* reduce data reimplementation by Alex */ void @@ -612,8 +679,9 @@ for (col=0;colgdes_c;i++){ /* only GF_DEF elements fetch data */ @@ -622,13 +690,17 @@ data_fetch( image_desc_t *im ) skip=0; /* do we have it already ?*/ - for (ii=0;iigdes[ii].gf != GF_DEF) continue; - if((strcmp(im->gdes[i].rrd,im->gdes[ii].rrd) == 0) - && (im->gdes[i].cf == im->gdes[ii].cf)){ - /* OK the data it is here already ... - * we just copy the header portion */ + if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0) + && (im->gdes[i].cf == im->gdes[ii].cf) + && (im->gdes[i].start == im->gdes[ii].start) + && (im->gdes[i].end == im->gdes[ii].end) + && (im->gdes[i].step == im->gdes[ii].step)) { + /* OK, the data is already there. + ** Just copy the header portion + */ im->gdes[i].start = im->gdes[ii].start; im->gdes[i].end = im->gdes[ii].end; im->gdes[i].step = im->gdes[ii].step; @@ -746,6 +818,8 @@ data_calc( image_desc_t *im){ * so CDEFs can use VDEFs and vice versa */ switch (im->gdes[gdi].gf) { + case GF_XPORT: + break; case GF_VDEF: /* A VDEF has no DS. This also signals other parts * of rrdtool that this is a VDEF value, not a CDEF. @@ -779,19 +853,22 @@ data_calc( image_desc_t *im){ * resulting data source. */ for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){ - if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){ + if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE || + im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){ long ptr = im->gdes[gdi].rpnp[rpi].ptr; if (im->gdes[ptr].ds_cnt == 0) { #if 0 -printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n", + printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n", im->gdes[gdi].vname, im->gdes[ptr].vname); -printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val); + printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val); #endif im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val; im->gdes[gdi].rpnp[rpi].op = OP_NUMBER; } else { - if ((steparray = rrd_realloc(steparray, (++stepcnt+1)*sizeof(*steparray)))==NULL){ + if ((steparray = + rrd_realloc(steparray, + (++stepcnt+1)*sizeof(*steparray)))==NULL){ rrd_set_error("realloc steparray"); rpnstack_free(&rpnstack); return -1; @@ -830,7 +907,8 @@ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val); /* move the data pointers to the correct period */ for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){ - if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){ + if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE || + im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){ long ptr = im->gdes[gdi].rpnp[rpi].ptr; if(im->gdes[gdi].start > im->gdes[ptr].start) { im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt; @@ -902,67 +980,71 @@ data_proc( image_desc_t *im ){ unsigned long gr_time; /* memory for the processed data */ - for(i=0;igdes_c;i++){ - if((im->gdes[i].gf==GF_LINE) || - (im->gdes[i].gf==GF_AREA) || - (im->gdes[i].gf==GF_TICK) || - (im->gdes[i].gf==GF_STACK)){ - if((im->gdes[i].p_data = malloc((im->xsize +1) + for(i=0;igdes_c;i++) { + if((im->gdes[i].gf==GF_LINE) || + (im->gdes[i].gf==GF_AREA) || + (im->gdes[i].gf==GF_TICK) || + (im->gdes[i].gf==GF_STACK)) { + if((im->gdes[i].p_data = malloc((im->xsize +1) * sizeof(rrd_value_t)))==NULL){ - rrd_set_error("malloc data_proc"); - return -1; + rrd_set_error("malloc data_proc"); + return -1; + } } - } } - - for(i=0;ixsize;i++){ + + for (i=0;ixsize;i++) { /* for each pixel */ long vidx; - gr_time = im->start+pixstep*i; /* time of the - current step */ + gr_time = im->start+pixstep*i; /* time of the current step */ paintval=0.0; - for(ii=0;iigdes_c;ii++){ - double value; - switch(im->gdes[ii].gf){ - case GF_LINE: - case GF_AREA: + for (ii=0;iigdes_c;ii++) { + double value; + switch (im->gdes[ii].gf) { + case GF_LINE: + case GF_AREA: case GF_TICK: - paintval = 0.0; - case GF_STACK: - vidx = im->gdes[ii].vidx; - - value = - im->gdes[vidx].data[ - ((unsigned long)floor( - (double)(gr_time-im->gdes[vidx].start) / im->gdes[vidx].step - ) - ) *im->gdes[vidx].ds_cnt - +im->gdes[vidx].ds]; - - if (! isnan(value)) { - paintval += value; - im->gdes[ii].p_data[i] = paintval; - /* GF_TICK: the data values are not relevant for min and max */ - if (finite(paintval) && im->gdes[ii].gf != GF_TICK ){ - if (isnan(minval) || paintval < minval) - minval = paintval; - if (isnan(maxval) || paintval > maxval) - maxval = paintval; - } - } else { - im->gdes[ii].p_data[i] = DNAN; - } - break; - case GF_PRINT: - case GF_GPRINT: - case GF_COMMENT: - case GF_HRULE: - case GF_VRULE: - case GF_DEF: - case GF_CDEF: - case GF_VDEF: - case GF_PART: - break; + if (!im->gdes[ii].stack) + paintval = 0.0; + case GF_STACK: + value = im->gdes[ii].yrule; + if (isnan(value)) { /* not a number or VDEF */ + /* The time of the data doesn't necessarily match + ** the time of the graph. Beware. + */ + vidx = im->gdes[ii].vidx; + if ( (gr_time >= im->gdes[vidx].start) && + (gr_time <= im->gdes[vidx].end) ) { + value = im->gdes[vidx].data[ + (unsigned long) floor( + (double)(gr_time - im->gdes[vidx].start) + / im->gdes[vidx].step) + * im->gdes[vidx].ds_cnt + + im->gdes[vidx].ds + ]; + } else { + value = DNAN; + } + }; + + if (! isnan(value)) { + paintval += value; + im->gdes[ii].p_data[i] = paintval; + /* GF_TICK: the data values are not + ** relevant for min and max + */ + if (finite(paintval) && im->gdes[ii].gf != GF_TICK ) { + if (isnan(minval) || paintval < minval) + minval = paintval; + if (isnan(maxval) || paintval > maxval) + maxval = paintval; + } + } else { + im->gdes[ii].p_data[i] = DNAN; + } + break; + default: + break; } } } @@ -976,12 +1058,13 @@ data_proc( image_desc_t *im ){ /* adjust min and max values */ if (isnan(im->minval) - || ((!im->logarithmic && !im->rigid) /* don't adjust low-end with log scale */ - && im->minval > minval)) + /* don't adjust low-end with log scale */ + || ((!im->logarithmic && !im->rigid) && im->minval > minval) + ) im->minval = minval; if (isnan(im->maxval) - || (!im->rigid - && im->maxval < maxval)){ + || (!im->rigid && im->maxval < maxval) + ) { if (im->logarithmic) im->maxval = maxval * 1.1; else @@ -989,16 +1072,14 @@ data_proc( image_desc_t *im ){ } /* make sure min and max are not equal */ if (im->minval == im->maxval) { - im->maxval *= 1.01; - if (! im->logarithmic) { - im->minval *= 0.99; - } - - /* make sure min and max are not both zero */ - if (im->maxval == 0.0) { + im->maxval *= 1.01; + if (! im->logarithmic) { + im->minval *= 0.99; + } + /* make sure min and max are not both zero */ + if (im->maxval == 0.0) { im->maxval = 1.0; - } - + } } return 0; } @@ -1204,6 +1285,7 @@ print_calc(image_desc_t *im, char ***prdata) if (im->gdes[i].gf == GF_PRINT){ (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char)); + (*prdata)[prlines-1] = NULL; if (bad_format(im->gdes[i].format)) { rrd_set_error("bad format for [G]PRINT in '%s'", im->gdes[i].format); return -1; @@ -1213,7 +1295,6 @@ print_calc(image_desc_t *im, char ***prdata) #else sprintf((*prdata)[prlines-2],im->gdes[i].format,printval,si_symb); #endif - (*prdata)[prlines-1] = NULL; } else { /* GF_GPRINT */ @@ -1243,6 +1324,7 @@ print_calc(image_desc_t *im, char ***prdata) case GF_CDEF: case GF_VDEF: case GF_PART: + case GF_XPORT: break; } } @@ -1385,21 +1467,15 @@ leg_place(image_desc_t *im) int -horizontal_grid(image_desc_t *im) +calc_horizontal_grid(image_desc_t *im) { double range; double scaledrange; int pixel,i; - int sgrid,egrid; - double gridstep; - double scaledstep; - char graph_label[100]; - double X0,X1,Y0; - int labfact,gridind; + int gridind; int decimals, fractionals; - char labfmt[64]; - labfact=2; + im->ygrid_scale.labfact=2; gridind=-1; range = im->maxval - im->minval; scaledrange = range / im->magfact; @@ -1421,25 +1497,25 @@ horizontal_grid(image_desc_t *im) fractionals = floor(log10(range)); if(fractionals < 0) /* small amplitude. */ - sprintf(labfmt, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1); + sprintf(im->ygrid_scale.labfmt, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1); else - sprintf(labfmt, "%%%d.1f", decimals + 1); - gridstep = pow((double)10, (double)fractionals); - if(gridstep == 0) /* range is one -> 0.1 is reasonable scale */ - gridstep = 0.1; + sprintf(im->ygrid_scale.labfmt, "%%%d.1f", decimals + 1); + im->ygrid_scale.gridstep = pow((double)10, (double)fractionals); + 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/gridstep < 5) - gridstep /= 10; - if(range/gridstep > 15) - gridstep *= 10; - if(range/gridstep > 5) { - labfact = 1; - if(range/gridstep > 8) - labfact = 2; + if(range/im->ygrid_scale.gridstep < 5) + 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) + im->ygrid_scale.labfact = 2; } else { - gridstep /= 5; - labfact = 5; + im->ygrid_scale.gridstep /= 5; + im->ygrid_scale.labfact = 5; } } else { @@ -1453,33 +1529,40 @@ horizontal_grid(image_desc_t *im) for(i=0; i<4;i++) { if (pixel * ylab[gridind].lfac[i] >= 2 * im->text_prop[TEXT_PROP_AXIS].size) { - labfact = ylab[gridind].lfac[i]; + im->ygrid_scale.labfact = ylab[gridind].lfac[i]; break; } } - gridstep = ylab[gridind].grid * im->magfact; + im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact; } } else { - gridstep = im->ygridstep; - labfact = im->ylabfact; + im->ygrid_scale.gridstep = im->ygridstep; + im->ygrid_scale.labfact = im->ylabfact; } - - X0=im->xorigin; - X1=im->xorigin+im->xsize; + return 1; +} + +int draw_horizontal_grid(image_desc_t *im) +{ + int i; + double scaledstep; + char graph_label[100]; + double X0=im->xorigin; + double X1=im->xorigin+im->xsize; - sgrid = (int)( im->minval / gridstep - 1); - egrid = (int)( im->maxval / gridstep + 1); - scaledstep = gridstep/im->magfact; + int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1); + int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1); + scaledstep = im->ygrid_scale.gridstep/im->magfact; for (i = sgrid; i <= egrid; i++){ - Y0=ytr(im,gridstep*i); + double Y0=ytr(im,im->ygrid_scale.gridstep*i); if ( Y0 >= im->yorigin-im->ysize && Y0 <= im->yorigin){ - if(i % labfact == 0){ + if(i % im->ygrid_scale.labfact == 0){ if (i==0 || im->symbol == ' ') { if(scaledstep < 1){ if(im->extra_flags & ALTYGRID) { - sprintf(graph_label,labfmt,scaledstep*i); + sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*i); } else { sprintf(graph_label,"%4.1f",scaledstep*i); @@ -1502,16 +1585,18 @@ horizontal_grid(image_desc_t *im) im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER, graph_label ); - gfx_new_line ( im->canvas, + gfx_new_dashed_line ( im->canvas, X0-2,Y0, X1+2,Y0, - MGRIDWIDTH, im->graph_col[GRC_MGRID] ); + MGRIDWIDTH, im->graph_col[GRC_MGRID], + im->grid_dash_on, im->grid_dash_off); - } else { - gfx_new_line ( im->canvas, + } else if (!(im->extra_flags & NOMINOR)) { + gfx_new_dashed_line ( im->canvas, X0-1,Y0, X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID] ); + GRIDWIDTH, im->graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } @@ -1562,10 +1647,11 @@ horizontal_log_grid(image_desc_t *im) while(yloglab[minoridx][++i] > 0){ Y0 = ytr(im,value * yloglab[minoridx][i]); if (Y0 <= im->yorigin - im->ysize) break; - gfx_new_line ( im->canvas, + gfx_new_dashed_line ( im->canvas, X0-1,Y0, X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID] ); + GRIDWIDTH, im->graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } @@ -1579,10 +1665,11 @@ horizontal_log_grid(image_desc_t *im) while(yloglab[majoridx][++i] > 0){ Y0 = ytr(im,value * yloglab[majoridx][i]); if (Y0 <= im->yorigin - im->ysize) break; - gfx_new_line ( im->canvas, + gfx_new_dashed_line ( im->canvas, X0-2,Y0, X1+2,Y0, - MGRIDWIDTH, im->graph_col[GRC_MGRID] ); + MGRIDWIDTH, im->graph_col[GRC_MGRID], + im->grid_dash_on, im->grid_dash_off); sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]); gfx_new_text ( im->canvas, @@ -1603,7 +1690,7 @@ vertical_grid( image_desc_t *im ) { int xlab_sel; /* which sort of label and grid ? */ - time_t ti, tilab; + time_t ti, tilab, timajor; long factor; char graph_label[100]; double X0,Y0,Y1; /* points for filled graph and more*/ @@ -1634,17 +1721,30 @@ vertical_grid( /* paint the minor grid */ - for(ti = find_first_time(im->start, - im->xlab_user.gridtm, - im->xlab_user.gridst); - ti < im->end; - ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst) - ){ - /* are we inside the graph ? */ - if (ti < im->start || ti > im->end) continue; - X0 = xtr(im,ti); - gfx_new_line(im->canvas,X0,Y0+1, X0,Y1-1,GRIDWIDTH, im->graph_col[GRC_GRID]); - + if (!(im->extra_flags & NOMINOR)) + { + for(ti = find_first_time(im->start, + im->xlab_user.gridtm, + im->xlab_user.gridst), + timajor = find_first_time(im->start, + im->xlab_user.mgridtm, + im->xlab_user.mgridst); + ti < im->end; + ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst) + ){ + /* are we inside the graph ? */ + if (ti < im->start || ti > im->end) continue; + while (timajor < ti) { + timajor = find_next_time(timajor, + im->xlab_user.mgridtm, im->xlab_user.mgridst); + } + if (ti == timajor) continue; /* skip as falls on major grid line */ + X0 = xtr(im,ti); + gfx_new_dashed_line(im->canvas,X0,Y0+1, X0,Y1-1,GRIDWIDTH, + im->graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); + + } } /* paint the major grid */ @@ -1657,7 +1757,9 @@ vertical_grid( /* are we inside the graph ? */ if (ti < im->start || ti > im->end) continue; X0 = xtr(im,ti); - gfx_new_line(im->canvas,X0,Y0+2, X0,Y1-2,MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_new_dashed_line(im->canvas,X0,Y0+3, X0,Y1-2,MGRIDWIDTH, + im->graph_col[GRC_MGRID], + im->grid_dash_on, im->grid_dash_off); } /* paint the labels below the graph */ @@ -1757,7 +1859,7 @@ grid_paint(image_desc_t *im) if(im->logarithmic){ res = horizontal_log_grid(im); } else { - res = horizontal_grid(im); + res = draw_horizontal_grid(im); } /* dont draw horizontal grid if there is no min and max val */ @@ -2061,6 +2163,7 @@ graph_size_location(image_desc_t *im, int elements, int piechart ) if (Xlegend > im->ximg) { im->ximg = Xlegend; /* reposition Pie */ + } #endif /* The pie is placed in the upper right hand corner, @@ -2135,6 +2238,11 @@ graph_paint(image_desc_t *im, char ***calcpr) expand_range(im); /* make sure the upper and lower limit are sensible values */ + if (!calc_horizontal_grid(im)) + return -1; + if (im->gridfit) + apply_gridfit(im); + /************************************************************** *** Calculating sizes and locations became a bit confusing *** *** so I moved this into a separate function. *** @@ -2184,6 +2292,7 @@ graph_paint(image_desc_t *im, char ***calcpr) case GF_COMMENT: case GF_HRULE: case GF_VRULE: + case GF_XPORT: break; case GF_TICK: for (ii = 0; ii < im->xsize; ii++) @@ -2246,7 +2355,12 @@ graph_paint(image_desc_t *im, char ***calcpr) && ! isnan(im->gdes[i].p_data[ii])){ if (node == NULL){ float ybase = 0.0; +/* if (im->gdes[i].gf == GF_STACK) { +*/ + if ( (im->gdes[i].gf == GF_STACK) + || (im->gdes[i].stack) ) { + ybase = ytr(im,lastgdes->p_data[ii-1]); } else { ybase = ytr(im,areazero); @@ -2265,7 +2379,11 @@ graph_paint(image_desc_t *im, char ***calcpr) if ( node != NULL && (ii+1==im->xsize || isnan(im->gdes[i].p_data[ii]) )){ /* GF_AREA STACK type*/ +/* if (im->gdes[i].gf == GF_STACK ) { +*/ + if ( (im->gdes[i].gf == GF_STACK) + || (im->gdes[i].stack) ) { int iii; for (iii=ii-1;iii>area_start;iii--){ gfx_add_point(node,iii+im->xorigin,ytr(im,lastgdes->p_data[iii])); @@ -2388,6 +2506,8 @@ gdes_alloc(image_desc_t *im){ im->gdes[im->gdes_c-1].step=def_step; + im->gdes[im->gdes_c-1].stack=0; + im->gdes[im->gdes_c-1].debug=0; im->gdes[im->gdes_c-1].start=im->start; im->gdes[im->gdes_c-1].end=im->end; im->gdes[im->gdes_c-1].vname[0]='\0'; @@ -2401,6 +2521,8 @@ gdes_alloc(image_desc_t *im){ im->gdes[im->gdes_c-1].rrd[0]='\0'; im->gdes[im->gdes_c-1].ds=-1; 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; } @@ -2428,7 +2550,6 @@ scan_for_col(char *input, int len, char *output) output[outp] = '\0'; return inp; } - /* Some surgery done on this function, it became ridiculously big. ** Things moved: ** - initializing now in rrd_graph_init() @@ -2439,29 +2560,28 @@ int rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize) { image_desc_t im; - -#ifdef HAVE_TZSET - tzset(); -#endif -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL,""); -#endif - rrd_graph_init(&im); rrd_graph_options(argc,argv,&im); - if (rrd_test_error()) return -1; + if (rrd_test_error()) { + im_free(&im); + return -1; + } if (strlen(argv[optind])>=MAXPATH) { rrd_set_error("filename (including path) too long"); + im_free(&im); return -1; } strncpy(im.graphfile,argv[optind],MAXPATH-1); im.graphfile[MAXPATH-1]='\0'; rrd_graph_script(argc,argv,&im); - if (rrd_test_error()) return -1; + if (rrd_test_error()) { + im_free(&im); + return -1; + } /* Everything is now read and the actual work can start */ @@ -2508,6 +2628,13 @@ rrd_graph_init(image_desc_t *im) { int i; +#ifdef HAVE_TZSET + tzset(); +#endif +#ifdef HAVE_SETLOCALE + setlocale(LC_TIME,""); +#endif + im->xlab_user.minsec = -1; im->ximg=0; im->yimg=0; @@ -2521,6 +2648,7 @@ rrd_graph_init(image_desc_t *im) im->unitsexponent= 9999; im->extra_flags= 0; im->rigid = 0; + im->gridfit = 1; im->imginfo = NULL; im->lazy = 0; im->logarithmic = 0; @@ -2532,6 +2660,8 @@ rrd_graph_init(image_desc_t *im) im->gdes_c = 0; im->gdes = NULL; im->canvas = gfx_new_canvas(); + im->grid_dash_on = 1; + im->grid_dash_off = 1; for(i=0;igraph_col[i]=graph_col[i]; @@ -2580,42 +2710,50 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) {"lazy", no_argument, 0, 'z'}, {"zoom", required_argument, 0, 'm'}, {"no-legend", no_argument, 0, 'g'}, - {"alt-y-grid", no_argument, 0, 257 }, - {"alt-autoscale", no_argument, 0, 258 }, - {"alt-autoscale-max", no_argument, 0, 259 }, - {"units-exponent",required_argument, 0, 260}, - {"step", required_argument, 0, 261}, + {"alt-y-grid", no_argument, 0, 'Y'}, + {"no-minor", no_argument, 0, 'I'}, + {"alt-autoscale", no_argument, 0, 'A'}, + {"alt-autoscale-max", no_argument, 0, 'M'}, + {"units-exponent",required_argument, 0, 'X'}, + {"step", required_argument, 0, 'S'}, + {"no-gridfit", no_argument, 0, 'N'}, {0,0,0,0}}; int option_index = 0; int opt; opt = getopt_long(argc, argv, - "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:z:g", + "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgYAMX:S:N", long_options, &option_index); if (opt == EOF) break; switch(opt) { - case 257: + case 'I': + im->extra_flags |= NOMINOR; + break; + case 'Y': im->extra_flags |= ALTYGRID; break; - case 258: + case 'A': im->extra_flags |= ALTAUTOSCALE; break; - case 259: + case 'M': im->extra_flags |= ALTAUTOSCALE_MAX; break; case 'g': im->extra_flags |= NOLEGEND; break; - case 260: + case 'X': im->unitsexponent = atoi(optarg); break; - case 261: + case 'S': im->step = atoi(optarg); break; + case 262: + im->gridfit = 0; + break; case 's': if ((parsetime_error = parsetime(optarg, &start_tv))) { rrd_set_error( "start time: %s", parsetime_error ); @@ -2848,233 +2986,6 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) im->end = end_tmp; } -void -rrd_graph_script(int argc, char *argv[], image_desc_t *im) -{ - int i; - char symname[100]; - int linepass = 0; /* stack must follow LINE*, AREA or STACK */ - - for (i=optind+1;igdes[im->gdes_c-1]" we use "gdp". - */ - gdes_alloc(im); - gdp=&im->gdes[im->gdes_c-1]; - line=argv[i]; - - /* function:newvname=string[:ds-name:CF] for xDEF - ** function:vname[#color[:string]] for LINEx,AREA,STACK - ** function:vname#color[:num[:string]] for TICK - ** function:vname-or-num#color[:string] for xRULE,PART - ** function:vname:CF:string for xPRINT - ** function:string for COMMENT - */ - argstart=0; - - sscanf(line, "%10[A-Z0-9]:%n", funcname,&argstart); - if (argstart==0) { - rrd_set_error("Cannot parse function in line: %s",line); - im_free(im); - return; - } - if(sscanf(funcname,"LINE%lf",&linewidth)){ - im->gdes[im->gdes_c-1].gf = GF_LINE; - im->gdes[im->gdes_c-1].linewidth = linewidth; - } else { - if ((gdp->gf=gf_conv(funcname))==-1) { - rrd_set_error("'%s' is not a valid function name",funcname); - im_free(im); - return; - } - } - - /* If the error string is set, we exit at the end of the switch */ - switch (gdp->gf) { - case GF_COMMENT: - if (rrd_graph_legend(gdp,&line[argstart])==0) - rrd_set_error("Cannot parse comment in line: %s",line); - break; - case GF_PART: - case GF_VRULE: - case GF_HRULE: - j=k=l=m=0; - sscanf(&line[argstart], "%lf%n#%n", &d, &j, &k); - sscanf(&line[argstart], DEF_NAM_FMT "%n#%n", vname, &l, &m); - if (k+m==0) { - rrd_set_error("Cannot parse name or num in line: %s",line); - break; - } - if (j!=0) { - gdp->xrule=d; - gdp->yrule=d; - argstart+=j; - } else if (!rrd_graph_check_vname(im,vname,line)) { - gdp->xrule=0; - gdp->yrule=DNAN; - argstart+=l; - } else break; /* exit due to wrong vname */ - if ((j=rrd_graph_color(im,&line[argstart],line,0))==0) break; - argstart+=j; - if (strlen(&line[argstart])!=0) { - if (rrd_graph_legend(gdp,&line[++argstart])==0) - rrd_set_error("Cannot parse comment in line: %s",line); - } - break; - case GF_STACK: - if (linepass==0) { - rrd_set_error("STACK must follow another graphing element"); - break; - } - case GF_LINE: - case GF_AREA: - case GF_TICK: - j=k=0; - linepass=1; - sscanf(&line[argstart],DEF_NAM_FMT"%n%1[#:]%n",vname,&j,sep,&k); - if (j+1!=k) - rrd_set_error("Cannot parse vname in line: %s",line); - else if (rrd_graph_check_vname(im,vname,line)) - rrd_set_error("Undefined vname '%s' in line: %s",line); - else - k=rrd_graph_color(im,&line[argstart],line,1); - if (rrd_test_error()) break; - argstart=argstart+j+k; - if ((strlen(&line[argstart])!=0)&&(gdp->gf==GF_TICK)) { - j=0; - sscanf(&line[argstart], ":%lf%n", &gdp->yrule,&j); - argstart+=j; - } - if (strlen(&line[argstart])!=0) - if (rrd_graph_legend(gdp,&line[++argstart])==0) - rrd_set_error("Cannot parse legend in line: %s",line); - break; - case GF_PRINT: - im->prt_c++; - case GF_GPRINT: - j=0; - sscanf(&line[argstart], DEF_NAM_FMT ":%n",gdp->vname,&j); - if (j==0) { - rrd_set_error("Cannot parse vname in line: '%s'",line); - break; - } - argstart+=j; - if (rrd_graph_check_vname(im,gdp->vname,line)) return; - j=0; - sscanf(&line[argstart], CF_NAM_FMT ":%n",symname,&j); - - k=(j!=0)?rrd_graph_check_CF(im,symname,line):1; -#define VIDX im->gdes[gdp->vidx] - switch (k) { - case -1: /* looks CF but is not really CF */ - if (VIDX.gf == GF_VDEF) rrd_clear_error(); - break; - case 0: /* CF present and correct */ - if (VIDX.gf == GF_VDEF) - rrd_set_error("Don't use CF when printing VDEF"); - argstart+=j; - break; - case 1: /* CF not present */ - if (VIDX.gf == GF_VDEF) rrd_clear_error(); - else rrd_set_error("Printing DEF or CDEF needs CF"); - break; - default: - rrd_set_error("Oops, bug in GPRINT scanning"); - } -#undef VIDX - if (rrd_test_error()) break; - - if (strlen(&line[argstart])!=0) { - if (rrd_graph_legend(gdp,&line[argstart])==0) - rrd_set_error("Cannot parse legend in line: %s",line); - } else rrd_set_error("No legend in (G)PRINT line: %s",line); - strcpy(gdp->format, gdp->legend); - break; - case GF_DEF: - case GF_VDEF: - case GF_CDEF: - j=0; - sscanf(&line[argstart], DEF_NAM_FMT "=%n",gdp->vname,&j); - if (j==0) { - rrd_set_error("Could not parse line: %s",line); - break; - } - if (find_var(im,gdp->vname)!=-1) { - rrd_set_error("Variable '%s' in line '%s' already in use\n", - gdp->vname,line); - break; - } - argstart+=j; - switch (gdp->gf) { - case GF_DEF: - argstart+=scan_for_col(&line[argstart],MAXPATH,gdp->rrd); - j=k=0; - sscanf(&line[argstart], - ":" DS_NAM_FMT ":" CF_NAM_FMT "%n%*s%n", - gdp->ds_nam, symname, &j, &k); - if ((j==0)||(k!=0)) { - rrd_set_error("Cannot parse DS or CF in '%s'",line); - break; - } - rrd_graph_check_CF(im,symname,line); - break; - case GF_VDEF: - j=0; - sscanf(&line[argstart],DEF_NAM_FMT ",%n",vname,&j); - if (j==0) { - rrd_set_error("Cannot parse vname in line '%s'",line); - break; - } - argstart+=j; - if (rrd_graph_check_vname(im,vname,line)) return; - if ( im->gdes[gdp->vidx].gf != GF_DEF - && im->gdes[gdp->vidx].gf != GF_CDEF) { - rrd_set_error("variable '%s' not DEF nor " - "CDEF in VDEF '%s'", vname,gdp->vname); - break; - } - vdef_parse(gdp,&line[argstart+strstart]); - break; - case GF_CDEF: - if (strstr(&line[argstart],":")!=NULL) { - rrd_set_error("Error in RPN, line: %s",line); - break; - } - if ((gdp->rpnp = rpn_parse( - (void *)im, - &line[argstart], - &find_var_wrapper) - )==NULL) - rrd_set_error("invalid rpn expression in: %s",line); - break; - default: break; - } - break; - default: rrd_set_error("Big oops"); - } - if (rrd_test_error()) { - im_free(im); - return; - } - } - - if (im->gdes_c==0){ - rrd_set_error("can't make a graph without contents"); - im_free(im); /* ??? is this set ??? */ - return; - } -} int rrd_graph_check_vname(image_desc_t *im, char *varname, char *err) { @@ -3126,15 +3037,6 @@ rrd_graph_color(image_desc_t *im, char *var, char *err, int optional) } } int -rrd_graph_check_CF(image_desc_t *im, char *symname, char *err) -{ - if ((im->gdes[im->gdes_c-1].cf=cf_conv(symname))==-1) { - rrd_set_error("Unknown CF '%s' in %s",symname,err); - return -1; - } - return 0; -} -int rrd_graph_legend(graph_desc_t *gdp, char *line) { int i; @@ -3146,33 +3048,41 @@ rrd_graph_legend(graph_desc_t *gdp, char *line) int bad_format(char *fmt) { - char *ptr; - int n=0; - - ptr = fmt; - while (*ptr != '\0') { - if (*ptr == '%') {ptr++; - if (*ptr == '\0') return 1; - while ((*ptr >= '0' && *ptr <= '9') || *ptr == '.') { - ptr++; - } - if (*ptr == '\0') return 1; - if (*ptr == 'l') { - ptr++; - n++; - if (*ptr == '\0') return 1; - if (*ptr == 'e' || *ptr == 'f') { - ptr++; - } else { return 1; } - } - else if (*ptr == 's' || *ptr == 'S' || *ptr == '%') { ++ptr; } - else { return 1; } - } else { - ++ptr; - } - } - return (n!=1); + char *ptr; + int n=0; + ptr = fmt; + while (*ptr != '\0') + if (*ptr++ == '%') { + + /* line cannot end with percent char */ + if (*ptr == '\0') return 1; + + /* '%s', '%S' and '%%' are allowed */ + if (*ptr == 's' || *ptr == 'S' || *ptr == '%') ptr++; + + /* or else '% 6.2lf' and such are allowed */ + else { + + /* optional padding character */ + if (*ptr == ' ' || *ptr == '+' || *ptr == '-') ptr++; + + /* This should take care of 'm.n' with all three optional */ + while (*ptr >= '0' && *ptr <= '9') ptr++; + if (*ptr == '.') ptr++; + while (*ptr >= '0' && *ptr <= '9') ptr++; + + /* Either 'le', 'lf' or 'lg' must follow here */ + if (*ptr++ != 'l') return 1; + if (*ptr == 'e' || *ptr == 'f' || *ptr == 'g') ptr++; + else return 1; + n++; + } + } + + return (n!=1); } + + int vdef_parse(gdes,str) struct graph_desc_t *gdes; @@ -3259,6 +3169,8 @@ char *str; }; return 0; } + + int vdef_calc(im,gdi) image_desc_t *im; @@ -3299,6 +3211,7 @@ printf("DEBUG: start == %lu, end == %lu, %lu steps\n" field = (steps-1)*dst->vf.param/100; dst->vf.val = array[field]; dst->vf.when = 0; /* no time component */ + free(array); #if 0 for(step=0;step