X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_graph.c;h=40539b3cc0683df30e39033eb2df4d0e8d566353;hp=aae131708b4cf5c483d53c72c6615180f973f3d7;hb=22424d6b1c6a14c1d919482f991427c7e43853a8;hpb=c4f7117a983147777138266b669b9d72dfe20fb6 diff --git a/src/rrd_graph.c b/src/rrd_graph.c index aae1317..40539b3 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -1,15 +1,18 @@ /**************************************************************************** - * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007 + * RRDtool 1.3.2 Copyright by Tobi Oetiker, 1997-2008 **************************************************************************** * rrd__graph.c produce graphs from data in rrdfiles ****************************************************************************/ #include +#include #ifdef WIN32 #include "strftime.h" +#include "plbasename.h" #endif + #include "rrd_tool.h" #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) @@ -26,6 +29,7 @@ #endif #include "rrd_graph.h" +#include "rrd_client.h" /* some constant definitions */ @@ -33,71 +37,127 @@ #ifndef RRD_DEFAULT_FONT /* there is special code later to pick Cour.ttf when running on windows */ -#define RRD_DEFAULT_FONT "DejaVuSansMono-Roman.ttf" +#define RRD_DEFAULT_FONT "DejaVu Sans Mono,Bitstream Vera Sans Mono,monospace,Courier" #endif -text_prop_t text_prop[] = { - { 8.0, RRD_DEFAULT_FONT }, /* default */ - { 9.0, RRD_DEFAULT_FONT }, /* title */ - { 7.0, RRD_DEFAULT_FONT }, /* axis */ - { 8.0, RRD_DEFAULT_FONT }, /* unit */ - { 8.0, RRD_DEFAULT_FONT } /* legend */ +text_prop_t text_prop[] = { + {8.0, RRD_DEFAULT_FONT,NULL} + , /* default */ + {9.0, RRD_DEFAULT_FONT,NULL} + , /* title */ + {7.0, RRD_DEFAULT_FONT,NULL} + , /* axis */ + {8.0, RRD_DEFAULT_FONT,NULL} + , /* unit */ + {8.0, RRD_DEFAULT_FONT,NULL} /* legend */ + , + {5.5, RRD_DEFAULT_FONT,NULL} /* watermark */ }; -xlab_t xlab[] = { - {0, 0, TMT_SECOND,30, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"}, - {2, 0, TMT_MINUTE,1, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"}, - {5, 0, TMT_MINUTE,2, TMT_MINUTE,10, TMT_MINUTE,10, 0,"%H:%M"}, - {10, 0, TMT_MINUTE,5, TMT_MINUTE,20, TMT_MINUTE,20, 0,"%H:%M"}, - {30, 0, TMT_MINUTE,10, TMT_HOUR,1, TMT_HOUR,1, 0,"%H:%M"}, - {60, 0, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,2, 0,"%H:%M"}, - {60, 24*3600, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,4, 0,"%a %H:%M"}, - {180, 0, TMT_HOUR,1, TMT_HOUR,6, TMT_HOUR,6, 0,"%H:%M"}, - {180, 24*3600, TMT_HOUR,1, TMT_HOUR,6, TMT_HOUR,12, 0,"%a %H:%M"}, - /*{300, 0, TMT_HOUR,3, TMT_HOUR,12, TMT_HOUR,12, 12*3600,"%a %p"}, this looks silly*/ - {600, 0, TMT_HOUR,6, TMT_DAY,1, TMT_DAY,1, 24*3600,"%a"}, - {1200, 0, TMT_HOUR,6, TMT_DAY,1, TMT_DAY,1, 24*3600,"%d"}, - {1800, 0, TMT_HOUR,12, TMT_DAY,1, TMT_DAY,2, 24*3600,"%a %d"}, - {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"}, - {3*3600, 0, TMT_WEEK,1, TMT_MONTH,1, TMT_WEEK,2, 7*24*3600,"Week %V"}, - {6*3600, 0, TMT_MONTH,1, TMT_MONTH,1, TMT_MONTH,1, 30*24*3600,"%b"}, - {48*3600, 0, TMT_MONTH,1, TMT_MONTH,3, TMT_MONTH,3, 30*24*3600,"%b"}, - {315360, 0, TMT_MONTH,3, TMT_YEAR,1, TMT_YEAR,1, 365*24*3600,"%Y"}, - {10*24*3600, 0, TMT_YEAR,1, TMT_YEAR,1, TMT_YEAR,1, 365*24*3600,"%y"}, - {-1,0,TMT_MONTH,0,TMT_MONTH,0,TMT_MONTH,0,0,""} +xlab_t xlab[] = { + {0, 0, TMT_SECOND, 30, TMT_MINUTE, 5, TMT_MINUTE, 5, 0, "%H:%M"} + , + {2, 0, TMT_MINUTE, 1, TMT_MINUTE, 5, TMT_MINUTE, 5, 0, "%H:%M"} + , + {5, 0, TMT_MINUTE, 2, TMT_MINUTE, 10, TMT_MINUTE, 10, 0, "%H:%M"} + , + {10, 0, TMT_MINUTE, 5, TMT_MINUTE, 20, TMT_MINUTE, 20, 0, "%H:%M"} + , + {30, 0, TMT_MINUTE, 10, TMT_HOUR, 1, TMT_HOUR, 1, 0, "%H:%M"} + , + {60, 0, TMT_MINUTE, 30, TMT_HOUR, 2, TMT_HOUR, 2, 0, "%H:%M"} + , + {60, 24 * 3600, TMT_MINUTE, 30, TMT_HOUR, 2, TMT_HOUR, 6, 0, "%a %H:%M"} + , + {180, 0, TMT_HOUR, 1, TMT_HOUR, 6, TMT_HOUR, 6, 0, "%H:%M"} + , + {180, 24 * 3600, TMT_HOUR, 1, TMT_HOUR, 6, TMT_HOUR, 12, 0, "%a %H:%M"} + , + /*{300, 0, TMT_HOUR,3, TMT_HOUR,12, TMT_HOUR,12, 12*3600,"%a %p"}, this looks silly */ + {600, 0, TMT_HOUR, 6, TMT_DAY, 1, TMT_DAY, 1, 24 * 3600, "%a"} + , + {1200, 0, TMT_HOUR, 6, TMT_DAY, 1, TMT_DAY, 1, 24 * 3600, "%d"} + , + {1800, 0, TMT_HOUR, 12, TMT_DAY, 1, TMT_DAY, 2, 24 * 3600, "%a %d"} + , + {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"} + , + {3 * 3600, 0, TMT_WEEK, 1, TMT_MONTH, 1, TMT_WEEK, 2, 7 * 24 * 3600, + "Week %V"} + , + {6 * 3600, 0, TMT_MONTH, 1, TMT_MONTH, 1, TMT_MONTH, 1, 30 * 24 * 3600, + "%b"} + , + {48 * 3600, 0, TMT_MONTH, 1, TMT_MONTH, 3, TMT_MONTH, 3, 30 * 24 * 3600, + "%b"} + , + {315360, 0, TMT_MONTH, 3, TMT_YEAR, 1, TMT_YEAR, 1, 365 * 24 * 3600, "%Y"} + , + {10 * 24 * 3600, 0, TMT_YEAR, 1, TMT_YEAR, 1, TMT_YEAR, 1, + 365 * 24 * 3600, "%y"} + , + {-1, 0, TMT_MONTH, 0, TMT_MONTH, 0, TMT_MONTH, 0, 0, ""} }; /* sensible y label intervals ...*/ -ylab_t ylab[]= { - {0.1, {1,2, 5,10}}, - {0.2, {1,5,10,20}}, - {0.5, {1,2, 4,10}}, - {1.0, {1,2, 5,10}}, - {2.0, {1,5,10,20}}, - {5.0, {1,2, 4,10}}, - {10.0, {1,2, 5,10}}, - {20.0, {1,5,10,20}}, - {50.0, {1,2, 4,10}}, - {100.0, {1,2, 5,10}}, - {200.0, {1,5,10,20}}, - {500.0, {1,2, 4,10}}, - {0.0, {0,0,0,0}}}; +ylab_t ylab[] = { + {0.1, {1, 2, 5, 10} + } + , + {0.2, {1, 5, 10, 20} + } + , + {0.5, {1, 2, 4, 10} + } + , + {1.0, {1, 2, 5, 10} + } + , + {2.0, {1, 5, 10, 20} + } + , + {5.0, {1, 2, 4, 10} + } + , + {10.0, {1, 2, 5, 10} + } + , + {20.0, {1, 5, 10, 20} + } + , + {50.0, {1, 2, 4, 10} + } + , + {100.0, {1, 2, 5, 10} + } + , + {200.0, {1, 5, 10, 20} + } + , + {500.0, {1, 2, 4, 10} + } + , + {0.0, {0, 0, 0, 0} + } +}; gfx_color_t graph_col[] = /* default colors */ -{ 0xFFFFFFFF, /* canvas */ - 0xF0F0F0FF, /* background */ - 0xD0D0D0FF, /* shade A */ - 0xA0A0A0FF, /* shade B */ - 0x90909080, /* grid */ - 0xE0505080, /* major grid */ - 0x000000FF, /* font */ - 0x802020FF, /* arrow */ - 0x202020FF, /* axis */ - 0x000000FF /* frame */ -}; +{ + {1.00, 1.00, 1.00, 1.00}, /* canvas */ + {0.95, 0.95, 0.95, 1.00}, /* background */ + {0.81, 0.81, 0.81, 1.00}, /* shade A */ + {0.62, 0.62, 0.62, 1.00}, /* shade B */ + {0.56, 0.56, 0.56, 0.75}, /* grid */ + {0.87, 0.31, 0.31, 0.60}, /* major grid */ + {0.00, 0.00, 0.00, 1.00}, /* font */ + {0.50, 0.12, 0.12, 1.00}, /* arrow */ + {0.12, 0.12, 0.12, 1.00}, /* axis */ + {0.00, 0.00, 0.00, 1.00} /* frame */ +}; /* #define DEBUG */ @@ -110,47 +170,43 @@ gfx_color_t graph_col[] = /* default colors */ /* initialize with xtr(im,0); */ -int -xtr(image_desc_t *im,time_t mytime){ +int xtr( + image_desc_t *im, + time_t mytime) +{ static double pixie; - if (mytime==0){ - pixie = (double) im->xsize / (double)(im->end - im->start); + + if (mytime == 0) { + pixie = (double) im->xsize / (double) (im->end - im->start); return im->xorigin; } - return (int)((double)im->xorigin - + pixie * ( mytime - im->start ) ); + return (int) ((double) im->xorigin + pixie * (mytime - im->start)); } /* translate data values into y coordinates */ -double -ytr(image_desc_t *im, double value){ +double ytr( + image_desc_t *im, + double value) +{ static double pixie; - double yval; - if (isnan(value)){ - if(!im->logarithmic) - pixie = (double) im->ysize / (im->maxval - im->minval); - else - pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval)); - yval = im->yorigin; - } else if(!im->logarithmic) { - yval = im->yorigin - pixie * (value - im->minval); - } else { - if (value < im->minval) { + double yval; + + if (isnan(value)) { + if (!im->logarithmic) + pixie = (double) im->ysize / (im->maxval - im->minval); + else + pixie = + (double) im->ysize / (log10(im->maxval) - log10(im->minval)); yval = im->yorigin; - } else { - 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) { - /* keep yval as-is */ - } else if (yval > im->yorigin) { - yval = im->yorigin +0.00001; - } else if (yval < im->yorigin - im->ysize){ - yval = im->yorigin - im->ysize - 0.00001; - } + } else if (!im->logarithmic) { + 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)); + } + } return yval; } @@ -162,526 +218,581 @@ ytr(image_desc_t *im, double value){ #define conv_if(VV,VVV) \ if (strcmp(#VV, string) == 0) return VVV ; -enum gf_en gf_conv(char *string){ - - conv_if(PRINT,GF_PRINT) - conv_if(GPRINT,GF_GPRINT) - conv_if(COMMENT,GF_COMMENT) - conv_if(HRULE,GF_HRULE) - conv_if(VRULE,GF_VRULE) - conv_if(LINE,GF_LINE) - conv_if(AREA,GF_AREA) - conv_if(STACK,GF_STACK) - conv_if(TICK,GF_TICK) - conv_if(DEF,GF_DEF) - conv_if(CDEF,GF_CDEF) - conv_if(VDEF,GF_VDEF) -#ifdef WITH_PIECHART - conv_if(PART,GF_PART) -#endif - conv_if(XPORT,GF_XPORT) - conv_if(SHIFT,GF_SHIFT) - - return (-1); +enum gf_en gf_conv( + char *string) +{ + + conv_if(PRINT, GF_PRINT); + conv_if(GPRINT, GF_GPRINT); + conv_if(COMMENT, GF_COMMENT); + conv_if(HRULE, GF_HRULE); + conv_if(VRULE, GF_VRULE); + conv_if(LINE, GF_LINE); + conv_if(AREA, GF_AREA); + conv_if(STACK, GF_STACK); + conv_if(TICK, GF_TICK); + conv_if(TEXTALIGN, GF_TEXTALIGN); + conv_if(DEF, GF_DEF); + conv_if(CDEF, GF_CDEF); + conv_if(VDEF, GF_VDEF); + conv_if(XPORT, GF_XPORT); + conv_if(SHIFT, GF_SHIFT); + + return (enum gf_en)(-1); } -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) +enum gfx_if_en if_conv( + char *string) +{ - return (-1); + conv_if(PNG, IF_PNG); + conv_if(SVG, IF_SVG); + conv_if(EPS, IF_EPS); + conv_if(PDF, IF_PDF); + + return (enum gfx_if_en)(-1); } -enum tmt_en tmt_conv(char *string){ +enum tmt_en tmt_conv( + char *string) +{ - conv_if(SECOND,TMT_SECOND) - conv_if(MINUTE,TMT_MINUTE) - conv_if(HOUR,TMT_HOUR) - conv_if(DAY,TMT_DAY) - conv_if(WEEK,TMT_WEEK) - conv_if(MONTH,TMT_MONTH) - conv_if(YEAR,TMT_YEAR) - return (-1); + conv_if(SECOND, TMT_SECOND); + conv_if(MINUTE, TMT_MINUTE); + conv_if(HOUR, TMT_HOUR); + conv_if(DAY, TMT_DAY); + conv_if(WEEK, TMT_WEEK); + conv_if(MONTH, TMT_MONTH); + conv_if(YEAR, TMT_YEAR); + return (enum tmt_en)(-1); } -enum grc_en grc_conv(char *string){ - - conv_if(BACK,GRC_BACK) - conv_if(CANVAS,GRC_CANVAS) - conv_if(SHADEA,GRC_SHADEA) - conv_if(SHADEB,GRC_SHADEB) - conv_if(GRID,GRC_GRID) - conv_if(MGRID,GRC_MGRID) - conv_if(FONT,GRC_FONT) - conv_if(ARROW,GRC_ARROW) - conv_if(AXIS,GRC_AXIS) - conv_if(FRAME,GRC_FRAME) +enum grc_en grc_conv( + char *string) +{ - return -1; + conv_if(BACK, GRC_BACK); + conv_if(CANVAS, GRC_CANVAS); + conv_if(SHADEA, GRC_SHADEA); + conv_if(SHADEB, GRC_SHADEB); + conv_if(GRID, GRC_GRID); + conv_if(MGRID, GRC_MGRID); + conv_if(FONT, GRC_FONT); + conv_if(ARROW, GRC_ARROW); + conv_if(AXIS, GRC_AXIS); + conv_if(FRAME, GRC_FRAME); + + return (enum grc_en)(-1); } -enum text_prop_en text_prop_conv(char *string){ - - conv_if(DEFAULT,TEXT_PROP_DEFAULT) - conv_if(TITLE,TEXT_PROP_TITLE) - conv_if(AXIS,TEXT_PROP_AXIS) - conv_if(UNIT,TEXT_PROP_UNIT) - conv_if(LEGEND,TEXT_PROP_LEGEND) - return -1; +enum text_prop_en text_prop_conv( + char *string) +{ + + conv_if(DEFAULT, TEXT_PROP_DEFAULT); + conv_if(TITLE, TEXT_PROP_TITLE); + conv_if(AXIS, TEXT_PROP_AXIS); + conv_if(UNIT, TEXT_PROP_UNIT); + conv_if(LEGEND, TEXT_PROP_LEGEND); + conv_if(WATERMARK, TEXT_PROP_WATERMARK); + return (enum text_prop_en)(-1); } #undef conv_if -int -im_free(image_desc_t *im) +int im_free( + image_desc_t *im) { - unsigned long i,ii; - - if (im == NULL) return 0; - 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); - if (im->gdes[i].ds_namv){ - for (ii=0;iigdes[i].ds_cnt;ii++) - free(im->gdes[i].ds_namv[ii]); - free(im->gdes[i].ds_namv); - } - } - free (im->gdes[i].p_data); - free (im->gdes[i].rpnp); + unsigned long i, ii; + cairo_status_t status = (cairo_status_t) 0; + + if (im == NULL) + return 0; + + if (im->daemon_addr != NULL) + free(im->daemon_addr); + + for (i = 0; i < (unsigned) im->gdes_c; i++) { + if (im->gdes[i].data_first) { + /* careful here, because a single pointer can occur several times */ + free(im->gdes[i].data); + if (im->gdes[i].ds_namv) { + for (ii = 0; ii < im->gdes[i].ds_cnt; ii++) + free(im->gdes[i].ds_namv[ii]); + 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); } free(im->gdes); - gfx_destroy(im->canvas); + if (im->font_options) + cairo_font_options_destroy(im->font_options); + + if (im->cr) { + status = cairo_status(im->cr); + cairo_destroy(im->cr); + } + if (im->rendered_image) { + free(im->rendered_image); + } + + if (im->layout) { + g_object_unref (im->layout); + } + + if (im->surface) + cairo_surface_destroy(im->surface); + + if (status) + fprintf(stderr, "OOPS: Cairo has issues it can't even die: %s\n", + cairo_status_to_string(status)); + return 0; } /* find SI magnitude symbol for the given number*/ -void -auto_scale( - image_desc_t *im, /* image description */ - double *value, - char **symb_ptr, - double *magfact - ) +void auto_scale( + image_desc_t *im, /* image description */ + double *value, + char **symb_ptr, + double *magfact) { - - char *symbol[] = {"a", /* 10e-18 Atto */ - "f", /* 10e-15 Femto */ - "p", /* 10e-12 Pico */ - "n", /* 10e-9 Nano */ - "u", /* 10e-6 Micro */ - "m", /* 10e-3 Milli */ - " ", /* Base */ - "k", /* 10e3 Kilo */ - "M", /* 10e6 Mega */ - "G", /* 10e9 Giga */ - "T", /* 10e12 Tera */ - "P", /* 10e15 Peta */ - "E"};/* 10e18 Exa */ - - int symbcenter = 6; - int sindex; - - if (*value == 0.0 || isnan(*value) ) { + + char *symbol[] = { "a", /* 10e-18 Atto */ + "f", /* 10e-15 Femto */ + "p", /* 10e-12 Pico */ + "n", /* 10e-9 Nano */ + "u", /* 10e-6 Micro */ + "m", /* 10e-3 Milli */ + " ", /* Base */ + "k", /* 10e3 Kilo */ + "M", /* 10e6 Mega */ + "G", /* 10e9 Giga */ + "T", /* 10e12 Tera */ + "P", /* 10e15 Peta */ + "E" + }; /* 10e18 Exa */ + + int symbcenter = 6; + int sindex; + + if (*value == 0.0 || isnan(*value)) { sindex = 0; *magfact = 1.0; } else { - sindex = floor(log(fabs(*value))/log((double)im->base)); - *magfact = pow((double)im->base, (double)sindex); + sindex = floor(log(fabs(*value)) / log((double) im->base)); + *magfact = pow((double) im->base, (double) sindex); (*value) /= (*magfact); } - if ( sindex <= symbcenter && sindex >= -symbcenter) { - (*symb_ptr) = symbol[sindex+symbcenter]; - } - else { + if (sindex <= symbcenter && sindex >= -symbcenter) { + (*symb_ptr) = symbol[sindex + symbcenter]; + } else { (*symb_ptr) = "?"; } } static char si_symbol[] = { - 'a', /* 10e-18 Atto */ - 'f', /* 10e-15 Femto */ - 'p', /* 10e-12 Pico */ - 'n', /* 10e-9 Nano */ - 'u', /* 10e-6 Micro */ - 'm', /* 10e-3 Milli */ - ' ', /* Base */ - 'k', /* 10e3 Kilo */ - 'M', /* 10e6 Mega */ - 'G', /* 10e9 Giga */ - 'T', /* 10e12 Tera */ - 'P', /* 10e15 Peta */ - 'E', /* 10e18 Exa */ + 'a', /* 10e-18 Atto */ + 'f', /* 10e-15 Femto */ + 'p', /* 10e-12 Pico */ + 'n', /* 10e-9 Nano */ + 'u', /* 10e-6 Micro */ + 'm', /* 10e-3 Milli */ + ' ', /* Base */ + 'k', /* 10e3 Kilo */ + 'M', /* 10e6 Mega */ + 'G', /* 10e9 Giga */ + 'T', /* 10e12 Tera */ + 'P', /* 10e15 Peta */ + 'E', /* 10e18 Exa */ }; static const int si_symbcenter = 6; /* find SI magnitude symbol for the numbers on the y-axis*/ -void -si_unit( - image_desc_t *im /* image description */ -) +void si_unit( + image_desc_t *im /* image description */ + ) { - double digits,viewdigits=0; - - digits = floor( log( max( fabs(im->minval),fabs(im->maxval)))/log((double)im->base)); + double digits, viewdigits = 0; + + digits = + floor(log(max(fabs(im->minval), fabs(im->maxval))) / + log((double) im->base)); if (im->unitsexponent != 9999) { /* unitsexponent = 9, 6, 3, 0, -3, -6, -9, etc */ - viewdigits = floor(im->unitsexponent / 3); + viewdigits = floor((double)(im->unitsexponent / 3)); } else { viewdigits = digits; } - im->magfact = pow((double)im->base , digits); - + im->magfact = pow((double) im->base, digits); + #ifdef DEBUG - printf("digits %6.3f im->magfact %6.3f\n",digits,im->magfact); + printf("digits %6.3f im->magfact %6.3f\n", digits, im->magfact); #endif - im->viewfactor = im->magfact / pow((double)im->base , viewdigits); + im->viewfactor = im->magfact / pow((double) im->base, viewdigits); - if ( ((viewdigits+si_symbcenter) < sizeof(si_symbol)) && - ((viewdigits+si_symbcenter) >= 0) ) - im->symbol = si_symbol[(int)viewdigits+si_symbcenter]; + if (((viewdigits + si_symbcenter) < sizeof(si_symbol)) && + ((viewdigits + si_symbcenter) >= 0)) + im->symbol = si_symbol[(int) viewdigits + si_symbcenter]; else im->symbol = '?'; - } +} /* move min and max values around to become sensible */ -void -expand_range(image_desc_t *im) +void expand_range( + image_desc_t *im) { - double sensiblevalues[] ={1000.0,900.0,800.0,750.0,700.0, - 600.0,500.0,400.0,300.0,250.0, - 200.0,125.0,100.0,90.0,80.0, - 75.0,70.0,60.0,50.0,40.0,30.0, - 25.0,20.0,10.0,9.0,8.0, - 7.0,6.0,5.0,4.0,3.5,3.0, - 2.5,2.0,1.8,1.5,1.2,1.0, - 0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0.0,-1}; - - double scaled_min,scaled_max; - double adj; - int i; - + double sensiblevalues[] = { 1000.0, 900.0, 800.0, 750.0, 700.0, + 600.0, 500.0, 400.0, 300.0, 250.0, + 200.0, 125.0, 100.0, 90.0, 80.0, + 75.0, 70.0, 60.0, 50.0, 40.0, 30.0, + 25.0, 20.0, 10.0, 9.0, 8.0, + 7.0, 6.0, 5.0, 4.0, 3.5, 3.0, + 2.5, 2.0, 1.8, 1.5, 1.2, 1.0, + 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0, -1 + }; + + double scaled_min, scaled_max; + double adj; + int i; + + - #ifdef DEBUG printf("Min: %6.2f Max: %6.2f MagFactor: %6.2f\n", - im->minval,im->maxval,im->magfact); + im->minval, im->maxval, im->magfact); #endif - if (isnan(im->ygridstep)){ - if(im->extra_flags & ALTAUTOSCALE) { + if (isnan(im->ygridstep)) { + if (im->extra_flags & ALTAUTOSCALE) { /* measure the amplitude of the function. Make sure that graph boundaries are slightly higher then max/min vals so we can see amplitude on the graph */ - double delt, fact; - - delt = im->maxval - im->minval; - adj = delt * 0.1; - fact = 2.0 * pow(10.0, - floor(log10(max(fabs(im->minval), fabs(im->maxval))/im->magfact)) - 2); - if (delt < fact) { + double delt, fact; + + delt = im->maxval - im->minval; + adj = delt * 0.1; + fact = 2.0 * pow(10.0, + floor(log10 + (max(fabs(im->minval), fabs(im->maxval)) / + im->magfact)) - 2); + if (delt < fact) { adj = (fact - delt) * 0.55; #ifdef DEBUG - printf("Min: %6.2f Max: %6.2f delt: %6.2f fact: %6.2f adj: %6.2f\n", im->minval, im->maxval, delt, fact, adj); + printf + ("Min: %6.2f Max: %6.2f delt: %6.2f fact: %6.2f adj: %6.2f\n", + im->minval, im->maxval, delt, fact, adj); #endif - } - im->minval -= adj; - im->maxval += adj; - } - else if(im->extra_flags & ALTAUTOSCALE_MIN) { - /* measure the amplitude of the function. Make sure that - graph boundaries are slightly lower than min vals - so we can see amplitude on the graph */ - adj = (im->maxval - im->minval) * 0.1; - im->minval -= adj; - } - else if(im->extra_flags & ALTAUTOSCALE_MAX) { + } + im->minval -= adj; + im->maxval += adj; + } else if (im->extra_flags & ALTAUTOSCALE_MIN) { + /* measure the amplitude of the function. Make sure that + graph boundaries are slightly lower than min vals + so we can see amplitude on the graph */ + adj = (im->maxval - im->minval) * 0.1; + im->minval -= adj; + } else if (im->extra_flags & ALTAUTOSCALE_MAX) { /* measure the amplitude of the function. Make sure that graph boundaries are slightly higher than max vals so we can see amplitude on the graph */ - adj = (im->maxval - im->minval) * 0.1; - im->maxval += adj; - } - else { + adj = (im->maxval - im->minval) * 0.1; + im->maxval += adj; + } else { scaled_min = im->minval / im->magfact; scaled_max = im->maxval / im->magfact; - - for (i=1; sensiblevalues[i] > 0; i++){ - if (sensiblevalues[i-1]>=scaled_min && - sensiblevalues[i]<=scaled_min) - im->minval = sensiblevalues[i]*(im->magfact); - - if (-sensiblevalues[i-1]<=scaled_min && - -sensiblevalues[i]>=scaled_min) - im->minval = -sensiblevalues[i-1]*(im->magfact); - - if (sensiblevalues[i-1] >= scaled_max && + + for (i = 1; sensiblevalues[i] > 0; i++) { + if (sensiblevalues[i - 1] >= scaled_min && + sensiblevalues[i] <= scaled_min) + im->minval = sensiblevalues[i] * (im->magfact); + + if (-sensiblevalues[i - 1] <= scaled_min && + -sensiblevalues[i] >= scaled_min) + im->minval = -sensiblevalues[i - 1] * (im->magfact); + + if (sensiblevalues[i - 1] >= scaled_max && sensiblevalues[i] <= scaled_max) - im->maxval = sensiblevalues[i-1]*(im->magfact); - - if (-sensiblevalues[i-1]<=scaled_max && - -sensiblevalues[i] >=scaled_max) - im->maxval = -sensiblevalues[i]*(im->magfact); + im->maxval = sensiblevalues[i - 1] * (im->magfact); + + if (-sensiblevalues[i - 1] <= scaled_max && + -sensiblevalues[i] >= scaled_max) + im->maxval = -sensiblevalues[i] * (im->magfact); } } } else { /* adjust min and max to the grid definition if there is one */ - im->minval = (double)im->ylabfact * im->ygridstep * - floor(im->minval / ((double)im->ylabfact * im->ygridstep)); - im->maxval = (double)im->ylabfact * im->ygridstep * - ceil(im->maxval /( (double)im->ylabfact * im->ygridstep)); + im->minval = (double) im->ylabfact * im->ygridstep * + floor(im->minval / ((double) im->ylabfact * im->ygridstep)); + im->maxval = (double) im->ylabfact * im->ygridstep * + ceil(im->maxval / ((double) im->ylabfact * im->ygridstep)); } - + #ifdef DEBUG - fprintf(stderr,"SCALED Min: %6.2f Max: %6.2f Factor: %6.2f\n", - im->minval,im->maxval,im->magfact); + fprintf(stderr, "SCALED Min: %6.2f Max: %6.2f Factor: %6.2f\n", + im->minval, im->maxval, im->magfact); #endif } -void -apply_gridfit(image_desc_t *im) + +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; - if (im->maxval > 0.0) - im->maxval = im->minval + new_range; - else - im->minval = im->maxval - 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 */ - } + 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; + + if (im->maxval > 0.0) + im->maxval = im->minval + new_range; + else + im->minval = im->maxval - 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 -reduce_data( - enum cf_en cf, /* which consolidation function ?*/ - unsigned long cur_step, /* step the data currently is in */ - time_t *start, /* start, end and step as requested ... */ - time_t *end, /* ... by the application will be ... */ - unsigned long *step, /* ... adjusted to represent reality */ - unsigned long *ds_cnt, /* number of data sources in file */ - rrd_value_t **data) /* two dimensional array containing the data */ -{ - int i,reduce_factor = ceil((double)(*step) / (double)cur_step); - unsigned long col,dst_row,row_cnt,start_offset,end_offset,skiprows=0; - rrd_value_t *srcptr,*dstptr; - - (*step) = cur_step*reduce_factor; /* set new step size for reduced data */ +void reduce_data( + enum cf_en cf, /* which consolidation function ? */ + unsigned long cur_step, /* step the data currently is in */ + time_t *start, /* start, end and step as requested ... */ + time_t *end, /* ... by the application will be ... */ + unsigned long *step, /* ... adjusted to represent reality */ + unsigned long *ds_cnt, /* number of data sources in file */ + rrd_value_t **data) +{ /* two dimensional array containing the data */ + int i, reduce_factor = ceil((double) (*step) / (double) cur_step); + unsigned long col, dst_row, row_cnt, start_offset, end_offset, skiprows = + 0; + rrd_value_t *srcptr, *dstptr; + + (*step) = cur_step * reduce_factor; /* set new step size for reduced data */ dstptr = *data; srcptr = *data; - row_cnt = ((*end)-(*start))/cur_step; + row_cnt = ((*end) - (*start)) / cur_step; #ifdef DEBUG #define DEBUG_REDUCE #endif #ifdef DEBUG_REDUCE -printf("Reducing %lu rows with factor %i time %lu to %lu, step %lu\n", - row_cnt,reduce_factor,*start,*end,cur_step); -for (col=0;col=reduce_factor;dst_row++) { - for (col=0;col<(*ds_cnt);col++) { - rrd_value_t newval=DNAN; - unsigned long validval=0; + for (dst_row = 0; (long int) row_cnt >= reduce_factor; dst_row++) { + for (col = 0; col < (*ds_cnt); col++) { + rrd_value_t newval = DNAN; + unsigned long validval = 0; - for (i=0;igdes_c;i++){ + for (i = 0; i < (int) im->gdes_c; i++) { /* only GF_DEF elements fetch data */ - if (im->gdes[i].gf != GF_DEF) + if (im->gdes[i].gf != GF_DEF) continue; - skip=0; - /* do we have it already ?*/ - for (ii=0;iigdes[ii].gf != GF_DEF) + skip = 0; + /* do we have it already ? */ + for (ii = 0; ii < i; ii++) { + if (im->gdes[ii].gf != GF_DEF) continue; if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0) - && (im->gdes[i].cf == im->gdes[ii].cf) - && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce) - && (im->gdes[i].start_orig == im->gdes[ii].start_orig) - && (im->gdes[i].end_orig == im->gdes[ii].end_orig) - && (im->gdes[i].step_orig == im->gdes[ii].step_orig)) { + && (im->gdes[i].cf == im->gdes[ii].cf) + && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce) + && (im->gdes[i].start_orig == im->gdes[ii].start_orig) + && (im->gdes[i].end_orig == im->gdes[ii].end_orig) + && (im->gdes[i].step_orig == im->gdes[ii].step_orig)) { /* OK, the data is already there. - ** Just copy the header portion - */ + ** 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; im->gdes[i].ds_cnt = im->gdes[ii].ds_cnt; - im->gdes[i].ds_namv = im->gdes[ii].ds_namv; + im->gdes[i].ds_namv = im->gdes[ii].ds_namv; im->gdes[i].data = im->gdes[ii].data; im->gdes[i].data_first = 0; - skip=1; + skip = 1; } - if (skip) + if (skip) break; } - if (! skip) { - unsigned long ft_step = im->gdes[i].step ; /* ft_step will record what we got from fetch */ - - if((rrd_fetch_fn(im->gdes[i].rrd, - im->gdes[i].cf, - &im->gdes[i].start, - &im->gdes[i].end, - &ft_step, - &im->gdes[i].ds_cnt, - &im->gdes[i].ds_namv, - &im->gdes[i].data)) == -1){ + if (!skip) { + unsigned long ft_step = im->gdes[i].step; /* ft_step will record what we got from fetch */ + + /* Flush the file if + * - a connection to the daemon has been established + * - this is the first occurrence of that RRD file + */ + if (rrdc_is_connected(im->daemon_addr)) + { + int status; + + status = 0; + for (ii = 0; ii < i; ii++) + { + if (strcmp (im->gdes[i].rrd, im->gdes[ii].rrd) == 0) + { + status = 1; + break; + } + } + + if (status == 0) + { + status = rrdc_flush (im->gdes[i].rrd); + if (status != 0) + { + rrd_set_error ("rrdc_flush (%s) failed with status %i.", + im->gdes[i].rrd, status); + return (-1); + } + } + } /* if (rrdc_is_connected()) */ + + if ((rrd_fetch_fn(im->gdes[i].rrd, + im->gdes[i].cf, + &im->gdes[i].start, + &im->gdes[i].end, + &ft_step, + &im->gdes[i].ds_cnt, + &im->gdes[i].ds_namv, + &im->gdes[i].data)) == -1) { return -1; } - im->gdes[i].data_first = 1; - + im->gdes[i].data_first = 1; + if (ft_step < im->gdes[i].step) { reduce_data(im->gdes[i].cf_reduce, ft_step, &im->gdes[i].start, &im->gdes[i].end, &im->gdes[i].step, - &im->gdes[i].ds_cnt, - &im->gdes[i].data); + &im->gdes[i].ds_cnt, &im->gdes[i].data); } else { im->gdes[i].step = ft_step; } } - + /* lets see if the required data source is really there */ - for(ii=0;ii<(int)im->gdes[i].ds_cnt;ii++){ - if(strcmp(im->gdes[i].ds_namv[ii],im->gdes[i].ds_nam) == 0){ - im->gdes[i].ds=ii; } + for (ii = 0; ii < (int) im->gdes[i].ds_cnt; ii++) { + if (strcmp(im->gdes[i].ds_namv[ii], im->gdes[i].ds_nam) == 0) { + im->gdes[i].ds = ii; + } } - if (im->gdes[i].ds== -1){ + if (im->gdes[i].ds == -1) { rrd_set_error("No DS called '%s' in '%s'", - im->gdes[i].ds_nam,im->gdes[i].rrd); - return -1; + im->gdes[i].ds_nam, im->gdes[i].rrd); + return -1; } - + } return 0; } @@ -776,320 +917,376 @@ data_fetch(image_desc_t *im ) * CDEF stuff *************************************************************/ -long -find_var_wrapper(void *arg1, char *key) +long find_var_wrapper( + void *arg1, + char *key) { - return find_var((image_desc_t *) arg1, key); + return find_var((image_desc_t *) arg1, key); } /* find gdes containing var*/ -long -find_var(image_desc_t *im, char *key){ - long ii; - for(ii=0;iigdes_c-1;ii++){ - if((im->gdes[ii].gf == GF_DEF - || im->gdes[ii].gf == GF_VDEF - || im->gdes[ii].gf == GF_CDEF) - && (strcmp(im->gdes[ii].vname,key) == 0)){ - return ii; - } - } +long find_var( + image_desc_t *im, + char *key) +{ + long ii; + + for (ii = 0; ii < im->gdes_c - 1; ii++) { + if ((im->gdes[ii].gf == GF_DEF + || im->gdes[ii].gf == GF_VDEF || im->gdes[ii].gf == GF_CDEF) + && (strcmp(im->gdes[ii].vname, key) == 0)) { + return ii; + } + } return -1; } -/* find the largest common denominator for all the numbers +/* find the greatest common divisor for all the numbers in the 0 terminated num array */ -long -lcd(long *num){ - long rest; - int i; - for (i=0;num[i+1]!=0;i++){ - do { - rest=num[i] % num[i+1]; - num[i]=num[i+1]; num[i+1]=rest; - } while (rest!=0); - num[i+1] = num[i]; +long lcd( + long *num) +{ + long rest; + int i; + + for (i = 0; num[i + 1] != 0; i++) { + do { + rest = num[i] % num[i + 1]; + num[i] = num[i + 1]; + num[i + 1] = rest; + } while (rest != 0); + num[i + 1] = num[i]; } /* return i==0?num[i]:num[i-1]; */ - return num[i]; + return num[i]; } /* run the rpn calculator on all the VDEF and CDEF arguments */ -int -data_calc( image_desc_t *im){ +int data_calc( + image_desc_t *im) +{ int gdi; int dataidx; - long *steparray, rpi; + long *steparray, rpi; int stepcnt; time_t now; rpnstack_t rpnstack; rpnstack_init(&rpnstack); - for (gdi=0;gdigdes_c;gdi++){ + for (gdi = 0; gdi < im->gdes_c; gdi++) { /* Look for GF_VDEF and GF_CDEF in the same loop, * so CDEFs can use VDEFs and vice versa */ switch (im->gdes[gdi].gf) { - case GF_XPORT: - break; - case GF_SHIFT: { - graph_desc_t *vdp = &im->gdes[im->gdes[gdi].vidx]; - - /* remove current shift */ - vdp->start -= vdp->shift; - vdp->end -= vdp->shift; - - /* vdef */ - if (im->gdes[gdi].shidx >= 0) - vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val; - /* constant */ - else - vdp->shift = im->gdes[gdi].shval; + case GF_XPORT: + break; + case GF_SHIFT:{ + graph_desc_t *vdp = &im->gdes[im->gdes[gdi].vidx]; - /* normalize shift to multiple of consolidated step */ - vdp->shift = (vdp->shift / (long)vdp->step) * (long)vdp->step; + /* remove current shift */ + vdp->start -= vdp->shift; + vdp->end -= vdp->shift; - /* apply shift */ - vdp->start += vdp->shift; - vdp->end += vdp->shift; - break; + /* vdef */ + if (im->gdes[gdi].shidx >= 0) + vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val; + /* constant */ + else + vdp->shift = im->gdes[gdi].shval; + + /* normalize shift to multiple of consolidated step */ + vdp->shift = (vdp->shift / (long) vdp->step) * (long) vdp->step; + + /* apply shift */ + vdp->start += vdp->shift; + vdp->end += vdp->shift; + 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. + */ + im->gdes[gdi].ds_cnt = 0; + if (vdef_calc(im, gdi)) { + rrd_set_error("Error processing VDEF '%s'", + im->gdes[gdi].vname); + rpnstack_free(&rpnstack); + return -1; } - case GF_VDEF: - /* A VDEF has no DS. This also signals other parts - * of rrdtool that this is a VDEF value, not a CDEF. - */ - im->gdes[gdi].ds_cnt = 0; - if (vdef_calc(im,gdi)) { - rrd_set_error("Error processing VDEF '%s'" - ,im->gdes[gdi].vname - ); - rpnstack_free(&rpnstack); - return -1; - } - break; - case GF_CDEF: - im->gdes[gdi].ds_cnt = 1; - im->gdes[gdi].ds = 0; - im->gdes[gdi].data_first = 1; - im->gdes[gdi].start = 0; - im->gdes[gdi].end = 0; - steparray=NULL; - stepcnt = 0; - dataidx=-1; - - /* Find the variables in the expression. - * - VDEF variables are substituted by their values - * and the opcode is changed into OP_NUMBER. - * - CDEF variables are analized for their step size, - * the lowest common denominator of all the step - * sizes of the data sources involved is calculated - * and the resulting number is the step size for the - * resulting data source. - */ - for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){ - 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) { /* this is a VDEF data source */ + break; + case GF_CDEF: + im->gdes[gdi].ds_cnt = 1; + im->gdes[gdi].ds = 0; + im->gdes[gdi].data_first = 1; + im->gdes[gdi].start = 0; + im->gdes[gdi].end = 0; + steparray = NULL; + stepcnt = 0; + dataidx = -1; + + /* Find the variables in the expression. + * - VDEF variables are substituted by their values + * and the opcode is changed into OP_NUMBER. + * - CDEF variables are analized for their step size, + * the lowest common denominator of all the step + * sizes of the data sources involved is calculated + * and the resulting number is the step size for the + * resulting data source. + */ + for (rpi = 0; im->gdes[gdi].rpnp[rpi].op != OP_END; rpi++) { + 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) { /* this is a VDEF data source */ #if 0 - 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: 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); #endif - im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val; - im->gdes[gdi].rpnp[rpi].op = OP_NUMBER; - } else { /* normal variables and PREF(variables) */ - - /* add one entry to the array that keeps track of the step sizes of the - * data sources going into the CDEF. */ - if ((steparray = - rrd_realloc(steparray, - (++stepcnt+1)*sizeof(*steparray)))==NULL){ - rrd_set_error("realloc steparray"); - rpnstack_free(&rpnstack); - return -1; - }; + im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val; + im->gdes[gdi].rpnp[rpi].op = OP_NUMBER; + } else { /* normal variables and PREF(variables) */ + + /* add one entry to the array that keeps track of the step sizes of the + * data sources going into the CDEF. */ + if ((steparray = + (long*)rrd_realloc(steparray, + (++stepcnt + + 1) * sizeof(*steparray))) == NULL) { + rrd_set_error("realloc steparray"); + rpnstack_free(&rpnstack); + return -1; + }; + + steparray[stepcnt - 1] = im->gdes[ptr].step; + + /* adjust start and end of cdef (gdi) so + * that it runs from the latest start point + * to the earliest endpoint of any of the + * rras involved (ptr) + */ - steparray[stepcnt-1] = im->gdes[ptr].step; - - /* adjust start and end of cdef (gdi) so - * that it runs from the latest start point - * to the earliest endpoint of any of the - * rras involved (ptr) - */ - - if(im->gdes[gdi].start < im->gdes[ptr].start) - im->gdes[gdi].start = im->gdes[ptr].start; - - if(im->gdes[gdi].end == 0 || - im->gdes[gdi].end > im->gdes[ptr].end) - im->gdes[gdi].end = im->gdes[ptr].end; - - /* store pointer to the first element of - * the rra providing data for variable, - * further save step size and data source - * count of this rra - */ - im->gdes[gdi].rpnp[rpi].data = im->gdes[ptr].data + im->gdes[ptr].ds; - im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step; - im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt; - - /* backoff the *.data ptr; this is done so - * rpncalc() function doesn't have to treat - * the first case differently - */ - } /* if ds_cnt != 0 */ - } /* if OP_VARIABLE */ - } /* loop through all rpi */ - - /* 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 || - im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){ - long ptr = im->gdes[gdi].rpnp[rpi].ptr; - long diff = im->gdes[gdi].start - im->gdes[ptr].start; - - if(diff > 0) - im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt; - } - } + if (im->gdes[gdi].start < im->gdes[ptr].start) + im->gdes[gdi].start = im->gdes[ptr].start; - if(steparray == NULL){ - rrd_set_error("rpn expressions without DEF" - " or CDEF variables are not supported"); - rpnstack_free(&rpnstack); - return -1; + if (im->gdes[gdi].end == 0 || + im->gdes[gdi].end > im->gdes[ptr].end) + im->gdes[gdi].end = im->gdes[ptr].end; + + /* store pointer to the first element of + * the rra providing data for variable, + * further save step size and data source + * count of this rra + */ + im->gdes[gdi].rpnp[rpi].data = + im->gdes[ptr].data + im->gdes[ptr].ds; + im->gdes[gdi].rpnp[rpi].step = im->gdes[ptr].step; + im->gdes[gdi].rpnp[rpi].ds_cnt = im->gdes[ptr].ds_cnt; + + /* backoff the *.data ptr; this is done so + * rpncalc() function doesn't have to treat + * the first case differently + */ + } /* if ds_cnt != 0 */ + } /* if OP_VARIABLE */ + } /* loop through all rpi */ + + /* 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 || + im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER) { + long ptr = im->gdes[gdi].rpnp[rpi].ptr; + long diff = + im->gdes[gdi].start - im->gdes[ptr].start; + + if (diff > 0) + im->gdes[gdi].rpnp[rpi].data += + (diff / im->gdes[ptr].step) * + im->gdes[ptr].ds_cnt; } - steparray[stepcnt]=0; - /* Now find the resulting step. All steps in all - * used RRAs have to be visited + } + + if (steparray == NULL) { + rrd_set_error("rpn expressions without DEF" + " or CDEF variables are not supported"); + rpnstack_free(&rpnstack); + return -1; + } + steparray[stepcnt] = 0; + /* Now find the resulting step. All steps in all + * used RRAs have to be visited + */ + im->gdes[gdi].step = lcd(steparray); + free(steparray); + if ((im->gdes[gdi].data = (rrd_value_t*)malloc(((im->gdes[gdi].end - + im->gdes[gdi].start) + / im->gdes[gdi].step) + * sizeof(double))) == NULL) { + rrd_set_error("malloc im->gdes[gdi].data"); + rpnstack_free(&rpnstack); + return -1; + } + + /* Step through the new cdef results array and + * calculate the values + */ + for (now = im->gdes[gdi].start + im->gdes[gdi].step; + now <= im->gdes[gdi].end; now += im->gdes[gdi].step) { + rpnp_t *rpnp = im->gdes[gdi].rpnp; + + /* 3rd arg of rpn_calc is for OP_VARIABLE lookups; + * in this case we are advancing by timesteps; + * we use the fact that time_t is a synonym for long */ - im->gdes[gdi].step = lcd(steparray); - free(steparray); - if((im->gdes[gdi].data = malloc(( - (im->gdes[gdi].end-im->gdes[gdi].start) - / im->gdes[gdi].step) - * sizeof(double)))==NULL){ - rrd_set_error("malloc im->gdes[gdi].data"); + if (rpn_calc(rpnp, &rpnstack, (long) now, + im->gdes[gdi].data, ++dataidx) == -1) { + /* rpn_calc sets the error string */ rpnstack_free(&rpnstack); return -1; } - - /* Step through the new cdef results array and - * calculate the values - */ - for (now = im->gdes[gdi].start + im->gdes[gdi].step; - now<=im->gdes[gdi].end; - now += im->gdes[gdi].step) - { - rpnp_t *rpnp = im -> gdes[gdi].rpnp; - - /* 3rd arg of rpn_calc is for OP_VARIABLE lookups; - * in this case we are advancing by timesteps; - * we use the fact that time_t is a synonym for long - */ - if (rpn_calc(rpnp,&rpnstack,(long) now, - im->gdes[gdi].data,++dataidx) == -1) { - /* rpn_calc sets the error string */ - rpnstack_free(&rpnstack); - return -1; - } - } /* enumerate over time steps within a CDEF */ - break; - default: - continue; + } /* enumerate over time steps within a CDEF */ + break; + default: + continue; } - } /* enumerate over CDEFs */ + } /* enumerate over CDEFs */ rpnstack_free(&rpnstack); return 0; } +/* from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */ +/* 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; +} + /* massage data so, that we get one value for each x coordinate in the graph */ -int -data_proc( image_desc_t *im ){ - long i,ii; - double pixstep = (double)(im->end-im->start) - /(double)im->xsize; /* how much time - passes in one pixel */ - double paintval; - double minval=DNAN,maxval=DNAN; - - unsigned long gr_time; +int data_proc( + image_desc_t *im) +{ + long i, ii; + double pixstep = (double) (im->end - im->start) + / (double) im->xsize; /* how much time + passes in one pixel */ + double paintval; + double minval = DNAN, maxval = DNAN; + + 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)) { - if((im->gdes[i].p_data = malloc((im->xsize +1) - * sizeof(rrd_value_t)))==NULL){ + for (i = 0; i < im->gdes_c; i++) { + if ((im->gdes[i].gf == GF_LINE) || + (im->gdes[i].gf == GF_AREA) || (im->gdes[i].gf == GF_TICK)) { + if ((im->gdes[i].p_data = (rrd_value_t*)malloc((im->xsize + 1) + * sizeof(rrd_value_t))) == NULL) { rrd_set_error("malloc data_proc"); return -1; } } } - for (i=0;ixsize;i++) { /* for each pixel */ - long vidx; - 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: - case GF_TICK: - if (!im->gdes[ii].stack) - paintval = 0.0; - value = im->gdes[ii].yrule; - if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) { - /* The time of the data doesn't necessarily match - ** the time of the graph. Beware. - */ - vidx = im->gdes[ii].vidx; - if (im->gdes[vidx].gf == GF_VDEF) { - value = im->gdes[vidx].vf.val; - } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) && - ((long int)gr_time <= (long int)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; - } - }; + for (i = 0; i < im->xsize; i++) { /* for each pixel */ + long vidx; - 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 ) && - ! (im->logarithmic && paintval <= 0.0)) - minval = paintval; - if (isnan(maxval) || paintval > maxval) - maxval = paintval; - } + gr_time = im->start + pixstep * i; /* time of the current step */ + paintval = 0.0; + + for (ii = 0; ii < im->gdes_c; ii++) { + double value; + + switch (im->gdes[ii].gf) { + case GF_LINE: + case GF_AREA: + case GF_TICK: + if (!im->gdes[ii].stack) + paintval = 0.0; + value = im->gdes[ii].yrule; + if (isnan(value) || (im->gdes[ii].gf == GF_TICK)) { + /* The time of the data doesn't necessarily match + ** the time of the graph. Beware. + */ + vidx = im->gdes[ii].vidx; + if (im->gdes[vidx].gf == GF_VDEF) { + value = im->gdes[vidx].vf.val; + } else + if (((long int) gr_time >= + (long int) im->gdes[vidx].start) + && ((long int) gr_time <= + (long int) 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 { - im->gdes[ii].p_data[i] = DNAN; + value = DNAN; } - break; - case GF_STACK: - rrd_set_error("STACK should already be turned into LINE or AREA here"); - return -1; - break; - default: - break; + }; + + 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) && + !(im->logarithmic && paintval <= 0.0)) + minval = paintval; + if (isnan(maxval) || paintval > maxval) + maxval = paintval; + } + } else { + im->gdes[ii].p_data[i] = DNAN; + } + break; + case GF_STACK: + rrd_set_error + ("STACK should already be turned into LINE or AREA here"); + return -1; + break; + default: + break; } } } @@ -1099,25 +1296,33 @@ data_proc( image_desc_t *im ){ lets set these to dummy values then ... */ if (im->logarithmic) { - if (isnan(minval)) minval = 0.2; - if (isnan(maxval)) maxval = 5.1; - } - else { - if (isnan(minval)) minval = 0.0; - if (isnan(maxval)) maxval = 1.0; + if (isnan(minval) || isnan(maxval) || maxval <= 0) { + minval = 0.0; /* catching this right away below */ + maxval = 5.1; + } + /* in logarithm mode, where minval is smaller or equal + to 0 make the beast just way smaller than maxval */ + if (minval <= 0) { + minval = maxval / 10e8; + } + } else { + if (isnan(minval) || isnan(maxval)) { + minval = 0.0; + maxval = 1.0; + } } - - /* adjust min and max values */ - if (isnan(im->minval) - /* don't adjust low-end with log scale */ /* why not? */ + + /* adjust min and max values given by the user */ + /* for logscale we add something on top */ + if (isnan(im->minval) || ((!im->rigid) && im->minval > minval) ) { if (im->logarithmic) - im->minval = minval * 0.5; + im->minval = minval / 2.0; else im->minval = minval; } - if (isnan(im->maxval) + if (isnan(im->maxval) || (!im->rigid && im->maxval < maxval) ) { if (im->logarithmic) @@ -1125,19 +1330,24 @@ data_proc( image_desc_t *im ){ else im->maxval = maxval; } + /* make sure min is smaller than max */ if (im->minval > 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; } } @@ -1148,227 +1358,257 @@ data_proc( image_desc_t *im ){ /* identify the point where the first gridline, label ... gets placed */ -time_t -find_first_time( - time_t start, /* what is the initial time */ - enum tmt_en baseint, /* what is the basic interval */ - long basestep /* how many if these do we jump a time */ +time_t find_first_time( + time_t start, /* what is the initial time */ + enum tmt_en baseint, /* what is the basic interval */ + long basestep /* how many if these do we jump a time */ ) { struct tm tm; + localtime_r(&start, &tm); - switch(baseint){ + + switch (baseint) { case TMT_SECOND: - tm.tm_sec -= tm.tm_sec % basestep; break; - case TMT_MINUTE: - tm.tm_sec=0; - tm.tm_min -= tm.tm_min % basestep; + tm. tm_sec -= tm.tm_sec % basestep; + + break; + case TMT_MINUTE: + tm. tm_sec = 0; + tm. tm_min -= tm.tm_min % basestep; + break; case TMT_HOUR: - tm.tm_sec=0; - tm.tm_min = 0; - tm.tm_hour -= tm.tm_hour % basestep; break; + tm. tm_sec = 0; + tm. tm_min = 0; + tm. tm_hour -= tm.tm_hour % basestep; + + break; case TMT_DAY: /* we do NOT look at the basestep for this ... */ - tm.tm_sec=0; - tm.tm_min = 0; - tm.tm_hour = 0; break; + tm. tm_sec = 0; + tm. tm_min = 0; + tm. tm_hour = 0; + + break; case TMT_WEEK: /* we do NOT look at the basestep for this ... */ - tm.tm_sec=0; - tm.tm_min = 0; - tm.tm_hour = 0; - tm.tm_mday -= tm.tm_wday -1; /* -1 because we want the monday */ - if (tm.tm_wday==0) tm.tm_mday -= 7; /* we want the *previous* monday */ + tm. tm_sec = 0; + tm. tm_min = 0; + tm. tm_hour = 0; + tm. tm_mday -= tm.tm_wday - 1; /* -1 because we want the monday */ + + if (tm.tm_wday == 0) + tm. tm_mday -= 7; /* we want the *previous* monday */ + break; case TMT_MONTH: - tm.tm_sec=0; - tm.tm_min = 0; - tm.tm_hour = 0; - tm.tm_mday = 1; - tm.tm_mon -= tm.tm_mon % basestep; break; + tm. tm_sec = 0; + tm. tm_min = 0; + tm. tm_hour = 0; + tm. tm_mday = 1; + tm. tm_mon -= tm.tm_mon % basestep; + + break; case TMT_YEAR: - tm.tm_sec=0; - tm.tm_min = 0; - tm.tm_hour = 0; - tm.tm_mday = 1; - tm.tm_mon = 0; - tm.tm_year -= (tm.tm_year+1900) % basestep; - + tm. tm_sec = 0; + tm. tm_min = 0; + tm. tm_hour = 0; + tm. tm_mday = 1; + tm. tm_mon = 0; + tm. tm_year -= ( + tm.tm_year + 1900) %basestep; + } return mktime(&tm); } + /* identify the point where the next gridline, label ... gets placed */ -time_t -find_next_time( - time_t current, /* what is the initial time */ - enum tmt_en baseint, /* what is the basic interval */ - long basestep /* how many if these do we jump a time */ +time_t find_next_time( + time_t current, /* what is the initial time */ + enum tmt_en baseint, /* what is the basic interval */ + long basestep /* how many if these do we jump a time */ ) { struct tm tm; - time_t madetime; + time_t madetime; + localtime_r(¤t, &tm); + do { - switch(baseint){ + switch (baseint) { case TMT_SECOND: - tm.tm_sec += basestep; break; - case TMT_MINUTE: - tm.tm_min += basestep; break; + tm. tm_sec += basestep; + + break; + case TMT_MINUTE: + tm. tm_min += basestep; + + break; case TMT_HOUR: - tm.tm_hour += basestep; break; + tm. tm_hour += basestep; + + break; case TMT_DAY: - tm.tm_mday += basestep; break; + tm. tm_mday += basestep; + + break; case TMT_WEEK: - tm.tm_mday += 7*basestep; break; + tm. tm_mday += 7 * basestep; + + break; case TMT_MONTH: - tm.tm_mon += basestep; break; + tm. tm_mon += basestep; + + break; case TMT_YEAR: - tm.tm_year += basestep; + tm. tm_year += basestep; } madetime = mktime(&tm); - } while (madetime == -1); /* this is necessary to skip impssible times - like the daylight saving time skips */ + } while (madetime == -1); /* this is necessary to skip impssible times + like the daylight saving time skips */ return madetime; - + } /* calculate values required for PRINT and GPRINT functions */ -int -print_calc(image_desc_t *im, char ***prdata) +int print_calc( + image_desc_t *im) { - long i,ii,validsteps; - double printval; + long i, ii, validsteps; + double printval; struct tm tmvdef; - int graphelement = 0; - long vidx; - int max_ii; - double magfact = -1; - char *si_symb = ""; - char *percent_s; - int prlines = 1; + int graphelement = 0; + long vidx; + int max_ii; + double magfact = -1; + char *si_symb = ""; + char *percent_s; + int prline_cnt = 0; + /* wow initializing tmvdef is quite a task :-) */ - time_t now = time(NULL); - localtime_r(&now,&tmvdef); - if (im->imginfo) prlines++; - for(i=0;igdes_c;i++){ - vidx = im->gdes[i].vidx; - switch(im->gdes[i].gf){ + time_t now = time(NULL); + + localtime_r(&now, &tmvdef); + for (i = 0; i < im->gdes_c; i++) { + vidx = im->gdes[i].vidx; + switch (im->gdes[i].gf) { case GF_PRINT: - prlines++; - if(((*prdata) = rrd_realloc((*prdata),prlines*sizeof(char *)))==NULL){ - rrd_set_error("realloc prdata"); - return 0; - } case GF_GPRINT: /* PRINT and GPRINT can now print VDEF generated values. * There's no need to do any calculations on them as these * calculations were already made. */ - if (im->gdes[vidx].gf==GF_VDEF) { /* simply use vals */ + if (im->gdes[vidx].gf == GF_VDEF) { /* simply use vals */ printval = im->gdes[vidx].vf.val; - localtime_r(&im->gdes[vidx].vf.when,&tmvdef); - } else { /* need to calculate max,min,avg etcetera */ - max_ii =((im->gdes[vidx].end - - im->gdes[vidx].start) - / im->gdes[vidx].step - * im->gdes[vidx].ds_cnt); + localtime_r(&im->gdes[vidx].vf.when, &tmvdef); + } else { /* need to calculate max,min,avg etcetera */ + max_ii = ((im->gdes[vidx].end - im->gdes[vidx].start) + / im->gdes[vidx].step * im->gdes[vidx].ds_cnt); printval = DNAN; validsteps = 0; - for( ii=im->gdes[vidx].ds; - ii < max_ii; - ii+=im->gdes[vidx].ds_cnt){ - if (! finite(im->gdes[vidx].data[ii])) + for (ii = im->gdes[vidx].ds; + ii < max_ii; ii += im->gdes[vidx].ds_cnt) { + if (!finite(im->gdes[vidx].data[ii])) continue; - if (isnan(printval)){ + if (isnan(printval)) { printval = im->gdes[vidx].data[ii]; validsteps++; continue; } - switch (im->gdes[i].cf){ - case CF_HWPREDICT: - case CF_DEVPREDICT: - case CF_DEVSEASONAL: - case CF_SEASONAL: - case CF_AVERAGE: - validsteps++; - printval += im->gdes[vidx].data[ii]; - break; - case CF_MINIMUM: - printval = min( printval, im->gdes[vidx].data[ii]); - break; - case CF_FAILURES: - case CF_MAXIMUM: - printval = max( printval, im->gdes[vidx].data[ii]); - break; - case CF_LAST: - printval = im->gdes[vidx].data[ii]; + switch (im->gdes[i].cf) { + case CF_HWPREDICT: + case CF_MHWPREDICT: + case CF_DEVPREDICT: + case CF_DEVSEASONAL: + case CF_SEASONAL: + case CF_AVERAGE: + validsteps++; + printval += im->gdes[vidx].data[ii]; + break; + case CF_MINIMUM: + printval = min(printval, im->gdes[vidx].data[ii]); + break; + case CF_FAILURES: + case CF_MAXIMUM: + printval = max(printval, im->gdes[vidx].data[ii]); + break; + case CF_LAST: + printval = im->gdes[vidx].data[ii]; } } - if (im->gdes[i].cf==CF_AVERAGE || im->gdes[i].cf > CF_LAST) { + if (im->gdes[i].cf == CF_AVERAGE || im->gdes[i].cf > CF_LAST) { if (validsteps > 1) { printval = (printval / validsteps); } } - } /* prepare printval */ + } /* prepare printval */ - if ((percent_s = strstr(im->gdes[i].format,"%S")) != NULL) { + if ((percent_s = strstr(im->gdes[i].format, "%S")) != NULL) { /* Magfact is set to -1 upon entry to print_calc. If it * is still less than 0, then we need to run auto_scale. * Otherwise, put the value into the correct units. If * the value is 0, then do not set the symbol or magnification * so next the calculation will be performed again. */ if (magfact < 0.0) { - auto_scale(im,&printval,&si_symb,&magfact); + auto_scale(im, &printval, &si_symb, &magfact); if (printval == 0.0) magfact = -1.0; } else { printval /= magfact; } *(++percent_s) = 's'; - } else if (strstr(im->gdes[i].format,"%s") != NULL) { - auto_scale(im,&printval,&si_symb,&magfact); + } else if (strstr(im->gdes[i].format, "%s") != NULL) { + auto_scale(im, &printval, &si_symb, &magfact); } - if (im->gdes[i].gf == GF_PRINT){ - (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char)); - (*prdata)[prlines-1] = NULL; - if (im->gdes[i].strftm){ - strftime((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,&tmvdef); - } else { - if (bad_format(im->gdes[i].format)) { - rrd_set_error("bad format for PRINT in '%s'", im->gdes[i].format); - return -1; - } + if (im->gdes[i].gf == GF_PRINT) { + rrd_infoval_t prline; -#ifdef HAVE_SNPRINTF - snprintf((*prdata)[prlines-2],FMT_LEG_LEN,im->gdes[i].format,printval,si_symb); -#else - sprintf((*prdata)[prlines-2],im->gdes[i].format,printval,si_symb); -#endif - } - } else { + if (im->gdes[i].strftm) { + prline.u_str = (char*)malloc((FMT_LEG_LEN + 2) * sizeof(char)); + strftime(prline.u_str, + FMT_LEG_LEN, im->gdes[i].format, &tmvdef); + } else if (bad_format(im->gdes[i].format)) { + rrd_set_error + ("bad format for PRINT in '%s'", im->gdes[i].format); + return -1; + } else { + prline.u_str = + sprintf_alloc(im->gdes[i].format, printval, si_symb); + } + grinfo_push(im, + sprintf_alloc + ("print[%ld]", prline_cnt++), RD_I_STR, prline); + free(prline.u_str); + } else { /* GF_GPRINT */ - if (im->gdes[i].strftm){ - strftime(im->gdes[i].legend,FMT_LEG_LEN,im->gdes[i].format,&tmvdef); + if (im->gdes[i].strftm) { + strftime(im->gdes[i].legend, + FMT_LEG_LEN, im->gdes[i].format, &tmvdef); } else { if (bad_format(im->gdes[i].format)) { - rrd_set_error("bad format for GPRINT in '%s'", im->gdes[i].format); + rrd_set_error + ("bad format for GPRINT in '%s'", + 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); + 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); + sprintf(im->gdes[i].legend, + im->gdes[i].format, printval, si_symb); #endif } - graphelement = 1; - } + graphelement = 1; + } break; case GF_LINE: case GF_AREA: @@ -1376,21 +1616,22 @@ print_calc(image_desc_t *im, char ***prdata) graphelement = 1; break; case GF_HRULE: - if(isnan(im->gdes[i].yrule)) { /* we must set this here or the legend printer can not decide to print the legend */ - im->gdes[i].yrule=im->gdes[vidx].vf.val; + if (isnan(im->gdes[i].yrule)) { /* we must set this here or the legend printer can not decide to print the legend */ + im->gdes[i].yrule = im->gdes[vidx].vf.val; }; graphelement = 1; break; case GF_VRULE: - if(im->gdes[i].xrule == 0) { /* again ... the legend printer needs it*/ - im->gdes[i].xrule = im->gdes[vidx].vf.when; + if (im->gdes[i].xrule == 0) { /* again ... the legend printer needs it */ + im->gdes[i].xrule = im->gdes[vidx].vf.when; }; graphelement = 1; break; case GF_COMMENT: + case GF_TEXTALIGN: case GF_DEF: - case GF_CDEF: - case GF_VDEF: + case GF_CDEF: + case GF_VDEF: #ifdef WITH_PIECHART case GF_PART: #endif @@ -1398,7 +1639,8 @@ print_calc(image_desc_t *im, char ***prdata) case GF_XPORT: break; case GF_STACK: - rrd_set_error("STACK should already be turned into LINE or AREA here"); + rrd_set_error + ("STACK should already be turned into LINE or AREA here"); return -1; break; } @@ -1408,163 +1650,200 @@ print_calc(image_desc_t *im, char ***prdata) /* place legends with color spots */ -int -leg_place(image_desc_t *im) +int leg_place( + image_desc_t *im, + int *gY) { /* graph labels */ - int interleg = im->text_prop[TEXT_PROP_LEGEND].size*2.0; - int border = im->text_prop[TEXT_PROP_LEGEND].size*2.0; - int fill=0, fill_last; - int leg_c = 0; - int leg_x = border, leg_y = im->yimg; - int leg_y_prev = im->yimg; - int leg_cc; - int glue = 0; - int i,ii, mark = 0; - char prt_fctn; /*special printfunctions */ - int *legspace; - - if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) { - if ((legspace = malloc(im->gdes_c*sizeof(int)))==NULL){ - rrd_set_error("malloc for legspace"); - return -1; - } - - for(i=0;igdes_c;i++){ - fill_last = fill; - - /* hid legends for rules which are not displayed */ - - if(!(im->extra_flags & FORCE_RULES_LEGEND)) { - if (im->gdes[i].gf == GF_HRULE && - (im->gdes[i].yrule < im->minval || im->gdes[i].yrule > im->maxval)) - im->gdes[i].legend[0] = '\0'; + int interleg = im->text_prop[TEXT_PROP_LEGEND].size * 2.0; + int border = im->text_prop[TEXT_PROP_LEGEND].size * 2.0; + int fill = 0, fill_last; + int leg_c = 0; + double leg_x = border; + int leg_y = im->yimg; + int leg_y_prev = im->yimg; + int leg_cc; + double glue = 0; + int i, ii, mark = 0; + char default_txtalign = TXA_JUSTIFIED; /*default line orientation */ + int *legspace; + char *tab; + + if (!(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH)) { + if ((legspace = (int*)malloc(im->gdes_c * sizeof(int))) == NULL) { + rrd_set_error("malloc for legspace"); + return -1; + } + + for (i = 0; i < im->gdes_c; i++) { + char prt_fctn; /*special printfunctions */ + fill_last = fill; + /* hide legends for rules which are not displayed */ + if (im->gdes[i].gf == GF_TEXTALIGN) { + default_txtalign = im->gdes[i].txtalign; + } - if (im->gdes[i].gf == GF_VRULE && - (im->gdes[i].xrule < im->start || im->gdes[i].xrule > im->end)) + if (!(im->extra_flags & FORCE_RULES_LEGEND)) { + if (im->gdes[i].gf == GF_HRULE + && (im->gdes[i].yrule < + im->minval || im->gdes[i].yrule > im->maxval)) im->gdes[i].legend[0] = '\0'; - } + if (im->gdes[i].gf == GF_VRULE + && (im->gdes[i].xrule < + im->start || im->gdes[i].xrule > im->end)) + im->gdes[i].legend[0] = '\0'; + } + + /* turn \\t into tab */ + while ((tab = strstr(im->gdes[i].legend, "\\t"))) { + memmove(tab, tab + 1, strlen(tab)); + tab[0] = (char) 9; + } + leg_cc = strlen(im->gdes[i].legend); + /* is there a controle code at the end of the legend string ? */ + if (leg_cc >= 2 && im->gdes[i].legend[leg_cc - 2] == '\\') { + prt_fctn = im->gdes[i].legend[leg_cc - 1]; + leg_cc -= 2; + im->gdes[i].legend[leg_cc] = '\0'; + } else { + prt_fctn = '\0'; + } + /* only valid control codes */ + if (prt_fctn != 'l' && prt_fctn != 'n' && /* a synonym for l */ + prt_fctn != 'r' && + prt_fctn != 'j' && + prt_fctn != 'c' && + prt_fctn != 's' && prt_fctn != '\0' && prt_fctn != 'g') { + free(legspace); + rrd_set_error + ("Unknown control code at the end of '%s\\%c'", + im->gdes[i].legend, prt_fctn); + return -1; + } + /* \n -> \l */ + if (prt_fctn == 'n') { + prt_fctn = 'l'; + } + + /* remove exess space from the end of the legend for \g */ + while (prt_fctn == 'g' && + leg_cc > 0 && im->gdes[i].legend[leg_cc - 1] == ' ') { + leg_cc--; + im->gdes[i].legend[leg_cc] = '\0'; + } + + if (leg_cc != 0) { - leg_cc = strlen(im->gdes[i].legend); - - /* is there a controle code ant the end of the legend string ? */ - /* and it is not a tab \\t */ - if (leg_cc >= 2 && im->gdes[i].legend[leg_cc-2] == '\\' && im->gdes[i].legend[leg_cc-1] != 't') { - prt_fctn = im->gdes[i].legend[leg_cc-1]; - leg_cc -= 2; - im->gdes[i].legend[leg_cc] = '\0'; - } else { - prt_fctn = '\0'; - } - /* only valid control codes */ - if (prt_fctn != 'l' && - prt_fctn != 'n' && /* a synonym for l */ - prt_fctn != 'r' && - prt_fctn != 'j' && - prt_fctn != 'c' && - prt_fctn != 's' && - prt_fctn != 't' && - prt_fctn != '\0' && - prt_fctn != 'g' ) { - free(legspace); - rrd_set_error("Unknown control code at the end of '%s\\%c'",im->gdes[i].legend,prt_fctn); - return -1; - - } - - /* remove exess space */ - if ( prt_fctn == 'n' ){ - prt_fctn='l'; - } - - while (prt_fctn=='g' && - leg_cc > 0 && - im->gdes[i].legend[leg_cc-1]==' '){ - leg_cc--; - im->gdes[i].legend[leg_cc]='\0'; - } - if (leg_cc != 0 ){ - legspace[i]=(prt_fctn=='g' ? 0 : interleg); - - if (fill > 0){ /* no interleg space if string ends in \g */ - fill += legspace[i]; - } - fill += gfx_get_text_width(im->canvas, fill+border, - im->text_prop[TEXT_PROP_LEGEND].font, - im->text_prop[TEXT_PROP_LEGEND].size, - im->tabwidth, - im->gdes[i].legend, 0); - leg_c++; - } else { - legspace[i]=0; - } - /* who said there was a special tag ... ?*/ - if (prt_fctn=='g') { - prt_fctn = '\0'; - } - if (prt_fctn == '\0') { - if (i == im->gdes_c -1 ) prt_fctn ='l'; - - /* is it time to place the legends ? */ - if (fill > im->ximg - 2*border){ - if (leg_c > 1) { - /* go back one */ - i--; - fill = fill_last; - leg_c--; - prt_fctn = 'j'; - } else { + legspace[i] = (prt_fctn == 'g' ? 0 : interleg); + if (fill > 0) { + fill += legspace[i]; + } + fill += + gfx_get_text_width(im, + fill + border, + im-> + text_prop + [TEXT_PROP_LEGEND]. + font_desc, + im->tabwidth, im->gdes[i].legend); + leg_c++; + } else { + legspace[i] = 0; + } + /* who said there was a special tag ... ? */ + if (prt_fctn == 'g') { + prt_fctn = '\0'; + } + + if (prt_fctn == '\0') { + if (i == im->gdes_c - 1 || fill > im->ximg - 2 * border) { + /* just one legend item is left right or center */ + switch (default_txtalign) { + case TXA_RIGHT: + prt_fctn = 'r'; + break; + case TXA_CENTER: + prt_fctn = 'c'; + break; + case TXA_JUSTIFIED: + prt_fctn = 'j'; + break; + default: + prt_fctn = 'l'; + break; + } + } + /* is it time to place the legends ? */ + if (fill > im->ximg - 2 * border) { + if (leg_c > 1) { + /* go back one */ + i--; + fill = fill_last; + leg_c--; + } + } + if (leg_c == 1 && prt_fctn == 'j') { prt_fctn = 'l'; } - } - } - if (prt_fctn != '\0'){ - leg_x = border; - if (leg_c >= 2 && prt_fctn == 'j') { - glue = (im->ximg - fill - 2* border) / (leg_c-1); - } else { - glue = 0; - } - if (prt_fctn =='c') leg_x = (im->ximg - fill) / 2.0; - if (prt_fctn =='r') leg_x = im->ximg - fill - border; - - for(ii=mark;ii<=i;ii++){ - if(im->gdes[ii].legend[0]=='\0') - continue; /* skip empty legends */ - im->gdes[ii].leg_x = leg_x; - im->gdes[ii].leg_y = leg_y; - leg_x += - gfx_get_text_width(im->canvas, leg_x, - im->text_prop[TEXT_PROP_LEGEND].font, - im->text_prop[TEXT_PROP_LEGEND].size, - im->tabwidth, - im->gdes[ii].legend, 0) - + legspace[ii] - + glue; - } - leg_y_prev = leg_y; - /* only add y space if there was text on the line */ - if (leg_x > border || prt_fctn == 's') - leg_y += im->text_prop[TEXT_PROP_LEGEND].size*1.8; - if (prt_fctn == 's') - leg_y -= im->text_prop[TEXT_PROP_LEGEND].size; - fill = 0; - leg_c = 0; - mark = ii; - } - } - im->yimg = leg_y_prev; - /* if we did place some legends we have to add vertical space */ - if (leg_y != im->yimg){ - im->yimg += im->text_prop[TEXT_PROP_LEGEND].size*1.8; - } - free(legspace); - } - return 0; + if (prt_fctn != '\0') { + leg_x = border; + if (leg_c >= 2 && prt_fctn == 'j') { + glue = (double)(im->ximg - fill - 2 * border) / (double)(leg_c - 1); + } else { + glue = 0; + } + if (prt_fctn == 'c') + leg_x = (double)(im->ximg - fill) / 2.0; + if (prt_fctn == 'r') + leg_x = im->ximg - fill - border; + for (ii = mark; ii <= i; ii++) { + if (im->gdes[ii].legend[0] == '\0') + continue; /* skip empty legends */ + im->gdes[ii].leg_x = leg_x; + im->gdes[ii].leg_y = leg_y; + leg_x += + (double)gfx_get_text_width(im, leg_x, + im-> + text_prop + [TEXT_PROP_LEGEND]. + font_desc, + im->tabwidth, im->gdes[ii].legend) + +(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') + leg_y -= im->text_prop[TEXT_PROP_LEGEND].size; + fill = 0; + leg_c = 0; + mark = ii; + } + } + + if (im->extra_flags & FULL_SIZE_MODE) { + /* now for some backpaddeling. We have to shift up all the + legend items into the graph and tell the caller about the + space we used up. */ + long shift_up = leg_y - im->yimg - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 + border * 0.7; + for (i = 0; i < im->gdes_c; i++) { + im->gdes[i].leg_y -= shift_up; + } + im->yorigin = im->yorigin - leg_y + im->yimg - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 - border; + *gY = im->yorigin; + } else { + im->yimg = + leg_y - im->text_prop[TEXT_PROP_LEGEND].size * 1.8 + + border * 0.6; + } + free(legspace); + } + return 0; } /* create a grid on the graph. it determines what to do @@ -1573,80 +1852,95 @@ leg_place(image_desc_t *im) /* the xaxis labels are determined from the number of seconds per pixel in the requested graph */ - - -int -calc_horizontal_grid(image_desc_t *im) +int calc_horizontal_grid( + image_desc_t + *im) { - double range; - double scaledrange; - int pixel,i; - int gridind=0; - int decimals, fractionals; - - im->ygrid_scale.labfact=2; - range = im->maxval - im->minval; + double range; + double scaledrange; + int pixel, i; + int gridind = 0; + int decimals, fractionals; + + im->ygrid_scale.labfact = 2; + range = im->maxval - im->minval; scaledrange = range / im->magfact; - - /* does the scale of this graph make it impossible to put lines - on it? If so, give up. */ - if (isnan(scaledrange)) { - return 0; - } + /* does the scale of this graph make it impossible to put lines + on it? If so, give up. */ + if (isnan(scaledrange)) { + return 0; + } /* find grid spaceing */ - pixel=1; - if(isnan(im->ygridstep)){ - if(im->extra_flags & ALTYGRID) { + pixel = 1; + if (isnan(im->ygridstep)) { + if (im->extra_flags & ALTYGRID) { /* find the value with max number of digits. Get number of digits */ - decimals = ceil(log10(max(fabs(im->maxval), fabs(im->minval))*im->viewfactor/im->magfact)); - if(decimals <= 0) /* everything is small. make place for zero */ + decimals = + ceil(log10 + (max(fabs(im->maxval), fabs(im->minval)) * + im->viewfactor / im->magfact)); + if (decimals <= 0) /* everything is small. make place for zero */ decimals = 1; - - im->ygrid_scale.gridstep = pow((double)10, floor(log10(range*im->viewfactor/im->magfact)))/im->viewfactor*im->magfact; - - if(im->ygrid_scale.gridstep == 0) /* range is one -> 0.1 is reasonable scale */ + im->ygrid_scale.gridstep = + pow((double) 10, + floor(log10(range * im->viewfactor / im->magfact))) / + im->viewfactor * im->magfact; + if (im->ygrid_scale.gridstep == 0) /* range is one -> 0.1 is reasonable scale */ im->ygrid_scale.gridstep = 0.1; /* should have at least 5 lines but no more then 15 */ - if(range/im->ygrid_scale.gridstep < 5) + if (range / im->ygrid_scale.gridstep < 5 + && im->ygrid_scale.gridstep >= 30) im->ygrid_scale.gridstep /= 10; - if(range/im->ygrid_scale.gridstep > 15) + if (range / im->ygrid_scale.gridstep > 15) im->ygrid_scale.gridstep *= 10; - if(range/im->ygrid_scale.gridstep > 5) { + if (range / im->ygrid_scale.gridstep > 5) { im->ygrid_scale.labfact = 1; - if(range/im->ygrid_scale.gridstep > 8) + if (range / im->ygrid_scale.gridstep > 8 + || im->ygrid_scale.gridstep < + 1.8 * im->text_prop[TEXT_PROP_AXIS].size) im->ygrid_scale.labfact = 2; - } - else { + } else { im->ygrid_scale.gridstep /= 5; im->ygrid_scale.labfact = 5; } - fractionals = floor(log10(im->ygrid_scale.gridstep*(double)im->ygrid_scale.labfact*im->viewfactor/im->magfact)); - if(fractionals < 0) { /* small amplitude. */ - int len = decimals - fractionals + 1; - if (im->unitslength < len+2) im->unitslength = len+2; - sprintf(im->ygrid_scale.labfmt, "%%%d.%df%s", len, -fractionals,(im->symbol != ' ' ? " %c" : "")); + fractionals = + floor(log10 + (im->ygrid_scale.gridstep * + (double) im->ygrid_scale.labfact * im->viewfactor / + im->magfact)); + if (fractionals < 0) { /* small amplitude. */ + int len = decimals - fractionals + 1; + + if (im->unitslength < len + 2) + im->unitslength = len + 2; + sprintf(im->ygrid_scale.labfmt, + "%%%d.%df%s", len, + -fractionals, (im->symbol != ' ' ? " %c" : "")); } else { - int len = decimals + 1; - if (im->unitslength < len+2) im->unitslength = len+2; - sprintf(im->ygrid_scale.labfmt, "%%%d.0f%s", len, ( im->symbol != ' ' ? " %c" : "" )); + int len = decimals + 1; + + if (im->unitslength < len + 2) + im->unitslength = len + 2; + sprintf(im->ygrid_scale.labfmt, + "%%%d.0f%s", len, (im->symbol != ' ' ? " %c" : "")); } - } - else { - for(i=0;ylab[i].grid > 0;i++){ + } else { /* classic rrd grid */ + for (i = 0; ylab[i].grid > 0; i++) { pixel = im->ysize / (scaledrange / ylab[i].grid); - gridind = i; - if (pixel > 7) + gridind = i; + if (pixel >= 5) break; } - - for(i=0; i<4;i++) { - if (pixel * ylab[gridind].lfac[i] >= 2.5 * im->text_prop[TEXT_PROP_AXIS].size) { - im->ygrid_scale.labfact = ylab[gridind].lfac[i]; - break; - } - } - + + for (i = 0; i < 4; i++) { + if (pixel * ylab[gridind].lfac[i] >= + 1.8 * im->text_prop[TEXT_PROP_AXIS].size) { + im->ygrid_scale.labfact = ylab[gridind].lfac[i]; + break; + } + } + im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact; } } else { @@ -1656,88 +1950,153 @@ calc_horizontal_grid(image_desc_t *im) return 1; } -int draw_horizontal_grid(image_desc_t *im) +int draw_horizontal_grid( + image_desc_t + *im) { - int i; - double scaledstep; - char graph_label[100]; - int nlabels=0; - double X0=im->xorigin; - double X1=im->xorigin+im->xsize; - - int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1); - int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1); - double MaxY; - scaledstep = im->ygrid_scale.gridstep/(double)im->magfact*(double)im->viewfactor; - MaxY = scaledstep*(double)egrid; - for (i = sgrid; i <= egrid; i++){ - double Y0=ytr(im,im->ygrid_scale.gridstep*i); - double YN=ytr(im,im->ygrid_scale.gridstep*(i+1)); - if ( round(Y0) >= im->yorigin-im->ysize - && round(Y0) <= im->yorigin){ + int i; + double scaledstep; + char graph_label[100]; + int nlabels = 0; + double X0 = im->xorigin; + double X1 = im->xorigin + im->xsize; + int sgrid = (int) (im->minval / im->ygrid_scale.gridstep - 1); + int egrid = (int) (im->maxval / im->ygrid_scale.gridstep + 1); + double MaxY; + double second_axis_magfact = 0; + char *second_axis_symb = ""; + + scaledstep = + im->ygrid_scale.gridstep / + (double) im->magfact * (double) im->viewfactor; + MaxY = scaledstep * (double) egrid; + for (i = sgrid; i <= egrid; i++) { + double Y0 = ytr(im, + im->ygrid_scale.gridstep * i); + double YN = ytr(im, + im->ygrid_scale.gridstep * (i + 1)); + + if (floor(Y0 + 0.5) >= + im->yorigin - im->ysize && floor(Y0 + 0.5) <= im->yorigin) { /* Make sure at least 2 grid labels are shown, even if it doesn't agree with the chosen settings. Add a label if required by settings, or if there is only one label so far and the next grid line is out of bounds. */ - if(i % im->ygrid_scale.labfact == 0 || ( nlabels==1 && (YN < im->yorigin-im->ysize || YN > im->yorigin) )){ + if (i % im->ygrid_scale.labfact == 0 + || (nlabels == 1 + && (YN < im->yorigin - im->ysize || YN > im->yorigin))) { if (im->symbol == ' ') { - if(im->extra_flags & ALTYGRID) { - sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*(double)i); + if (im->extra_flags & ALTYGRID) { + sprintf(graph_label, + im->ygrid_scale.labfmt, + scaledstep * (double) i); } else { - if(MaxY < 10) { - sprintf(graph_label,"%4.1f",scaledstep*(double)i); - } else { - sprintf(graph_label,"%4.0f",scaledstep*(double)i); + if (MaxY < 10) { + sprintf(graph_label, "%4.1f", + scaledstep * (double) i); + } else { + sprintf(graph_label, "%4.0f", + scaledstep * (double) i); } } - }else { - char sisym = ( i == 0 ? ' ' : im->symbol); - if(im->extra_flags & ALTYGRID) { - sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*(double)i,sisym); + } else { + char sisym = (i == 0 ? ' ' : im->symbol); + + if (im->extra_flags & ALTYGRID) { + sprintf(graph_label, + im->ygrid_scale.labfmt, + scaledstep * (double) i, sisym); } else { - if(MaxY < 10){ - sprintf(graph_label,"%4.1f %c",scaledstep*(double)i, sisym); + if (MaxY < 10) { + sprintf(graph_label, "%4.1f %c", + scaledstep * (double) i, sisym); } else { - sprintf(graph_label,"%4.0f %c",scaledstep*(double)i, sisym); + sprintf(graph_label, "%4.0f %c", + scaledstep * (double) i, sisym); } } } nlabels++; - - gfx_new_text ( im->canvas, - X0-im->text_prop[TEXT_PROP_AXIS].size, Y0, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, - im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER, - graph_label ); - gfx_new_dashed_line ( im->canvas, - X0-2,Y0, - X1+2,Y0, - MGRIDWIDTH, im->graph_col[GRC_MGRID], - im->grid_dash_on, im->grid_dash_off); - - } else if (!(im->extra_flags & NOMINOR)) { - gfx_new_dashed_line ( im->canvas, - X0-1,Y0, - X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID], - im->grid_dash_on, im->grid_dash_off); - - } - } - } + if (im->second_axis_scale != 0){ + char graph_label_right[100]; + double sval = im->ygrid_scale.gridstep*(double)i*im->second_axis_scale+im->second_axis_shift; + if (im->second_axis_format[0] == '\0'){ + if (!second_axis_magfact){ + double dummy = im->ygrid_scale.gridstep*(double)(sgrid+egrid)/2.0*im->second_axis_scale+im->second_axis_shift; + auto_scale(im,&dummy,&second_axis_symb,&second_axis_magfact); + } + sval /= second_axis_magfact; + + if(MaxY < 10) { + sprintf(graph_label_right,"%5.1f %s",sval,second_axis_symb); + } else { + sprintf(graph_label_right,"%5.0f %s",sval,second_axis_symb); + } + } + else { + sprintf(graph_label_right,im->second_axis_format,sval); + } + gfx_text ( im, + X1+7, Y0, + im->graph_col[GRC_FONT], + im->text_prop[TEXT_PROP_AXIS].font_desc, + im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER, + graph_label_right ); + } + + gfx_text(im, + X0 - + im-> + text_prop[TEXT_PROP_AXIS]. + size, Y0, + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_AXIS]. + font_desc, + im->tabwidth, 0.0, + GFX_H_RIGHT, GFX_V_CENTER, graph_label); + gfx_line(im, X0 - 2, Y0, X0, Y0, + MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_dashed_line(im, X0 - 2, Y0, + X1 + 2, Y0, + MGRIDWIDTH, + im-> + graph_col + [GRC_MGRID], + im->grid_dash_on, im->grid_dash_off); + } else if (!(im->extra_flags & NOMINOR)) { + gfx_line(im, + X0 - 2, Y0, + X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0 - 1, Y0, + X1 + 1, Y0, + GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); + } + } + } return 1; } /* this is frexp for base 10 */ -double frexp10(double, double *); -double frexp10(double x, double *e) { - double mnt; - int iexp; +double frexp10( + double, + double *); +double frexp10( + double x, + double *e) +{ + double mnt; + int iexp; - iexp = floor(log(fabs(x)) / log(10)); + iexp = floor(log((double)fabs(x)) / log((double)10)); mnt = x / pow(10.0, iexp); - if(mnt >= 10.0) { + if (mnt >= 10.0) { iexp++; mnt = x / pow(10.0, iexp); } @@ -1745,240 +2104,286 @@ double frexp10(double x, double *e) { return mnt; } -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(image_desc_t *im) +int horizontal_log_grid( + image_desc_t + *im) { - double yloglab[][10] = { - {1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {1.0, 5.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {1.0, 2.0, 5.0, 7.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0}, - {1.0, 2.0, 4.0, 6.0, 8.0, 10., 0.0, 0.0, 0.0, 0.0}, - {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.}, - {0,0,0,0,0, 0,0,0,0,0} /* last line */ }; - - int i, j, val_exp, min_exp; - double nex; /* number of decades in data */ - double logscale; /* scale in logarithmic space */ - int exfrac = 1; /* decade spacing */ - int mid = -1; /* row in yloglab for major grid */ - double mspac; /* smallest major grid spacing (pixels) */ - int flab; /* first value in yloglab to use */ - double value, tmp, pre_value; - double X0,X1,Y0; - char graph_label[100]; + double yloglab[][10] = { + { + 1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0}, { + 1.0, 5.0, 10., 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0}, { + 1.0, 2.0, 5.0, 7.0, 10., 0.0, 0.0, + 0.0, 0.0, 0.0}, { + 1.0, 2.0, 4.0, + 6.0, 8.0, 10., + 0.0, + 0.0, 0.0, 0.0}, { + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.}, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* last line */ + }; + int i, j, val_exp, min_exp; + double nex; /* number of decades in data */ + double logscale; /* scale in logarithmic space */ + int exfrac = 1; /* decade spacing */ + int mid = -1; /* row in yloglab for major grid */ + double mspac; /* smallest major grid spacing (pixels) */ + int flab; /* first value in yloglab to use */ + double value, tmp, pre_value; + double X0, X1, Y0; + char graph_label[100]; nex = log10(im->maxval / im->minval); logscale = im->ysize / nex; - /* major spacing for data with high dynamic range */ - while(logscale * exfrac < 3 * im->text_prop[TEXT_PROP_LEGEND].size) { - if(exfrac == 1) exfrac = 3; - else exfrac += 3; + while (logscale * exfrac < 3 * im->text_prop[TEXT_PROP_LEGEND].size) { + if (exfrac == 1) + exfrac = 3; + else + exfrac += 3; } /* major spacing for less dynamic data */ do { /* search best row in yloglab */ mid++; - for(i = 0; yloglab[mid][i + 1] < 10.0; i++); + for (i = 0; yloglab[mid][i + 1] < 10.0; i++); mspac = logscale * log10(10.0 / yloglab[mid][i]); - } while(mspac > 2 * im->text_prop[TEXT_PROP_LEGEND].size && yloglab[mid][0] > 0); - if(mid) mid--; - + } + while (mspac > + 2 * im->text_prop[TEXT_PROP_LEGEND].size && yloglab[mid][0] > 0); + if (mid) + mid--; /* find first value in yloglab */ - for(flab = 0; yloglab[mid][flab] < 10 && frexp10(im->minval, &tmp) > yloglab[mid][flab] ; flab++); - if(yloglab[mid][flab] == 10.0) { + for (flab = 0; + yloglab[mid][flab] < 10 + && frexp10(im->minval, &tmp) > yloglab[mid][flab]; flab++); + if (yloglab[mid][flab] == 10.0) { tmp += 1.0; flab = 0; } val_exp = tmp; - if(val_exp % exfrac) val_exp += abs(-val_exp % exfrac); - - X0=im->xorigin; - X1=im->xorigin+im->xsize; - + if (val_exp % exfrac) + val_exp += abs(-val_exp % exfrac); + X0 = im->xorigin; + X1 = im->xorigin + im->xsize; /* draw grid */ pre_value = DNAN; - while(1) { + while (1) { value = yloglab[mid][flab] * pow(10.0, val_exp); - if ( AlmostEqual2sComplement(value,pre_value,4) ) break; /* it seems we are not converging */ - + if (AlmostEqual2sComplement(value, pre_value, 4)) + break; /* it seems we are not converging */ pre_value = value; - Y0 = ytr(im, value); - if(Y0 <= im->yorigin - im->ysize) break; - + if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) + break; /* major grid line */ - gfx_new_dashed_line ( im->canvas, - X0-2,Y0, - X1+2,Y0, - MGRIDWIDTH, im->graph_col[GRC_MGRID], - im->grid_dash_on, im->grid_dash_off); - + gfx_line(im, + X0 - 2, Y0, X0, Y0, MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_dashed_line(im, X0 - 2, Y0, + X1 + 2, Y0, + MGRIDWIDTH, + im-> + graph_col + [GRC_MGRID], im->grid_dash_on, im->grid_dash_off); /* label */ if (im->extra_flags & FORCE_UNITS_SI) { - int scale; - double pvalue; - char symbol; + int scale; + double pvalue; + char symbol; scale = floor(val_exp / 3.0); - if( value >= 1.0 ) pvalue = pow(10.0, val_exp % 3); - else pvalue = pow(10.0, ((val_exp + 1) % 3) + 2); + if (value >= 1.0) + pvalue = pow(10.0, val_exp % 3); + else + pvalue = pow(10.0, ((val_exp + 1) % 3) + 2); pvalue *= yloglab[mid][flab]; - - if ( ((scale+si_symbcenter) < (int)sizeof(si_symbol)) && - ((scale+si_symbcenter) >= 0) ) - symbol = si_symbol[scale+si_symbcenter]; + if (((scale + si_symbcenter) < (int) sizeof(si_symbol)) + && ((scale + si_symbcenter) >= 0)) + symbol = si_symbol[scale + si_symbcenter]; else symbol = '?'; - - sprintf(graph_label,"%3.0f %c", pvalue, symbol); - } else - sprintf(graph_label,"%3.0e", value); - gfx_new_text ( im->canvas, - X0-im->text_prop[TEXT_PROP_AXIS].size, Y0, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, - im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER, - graph_label ); - + sprintf(graph_label, "%3.0f %c", pvalue, symbol); + } else { + sprintf(graph_label, "%3.0e", value); + } + if (im->second_axis_scale != 0){ + char graph_label_right[100]; + double sval = value*im->second_axis_scale+im->second_axis_shift; + if (im->second_axis_format[0] == '\0'){ + if (im->extra_flags & FORCE_UNITS_SI) { + double mfac = 1; + char *symb = ""; + auto_scale(im,&sval,&symb,&mfac); + sprintf(graph_label_right,"%4.0f %s", sval,symb); + } + else { + sprintf(graph_label_right,"%3.0e", sval); + } + } + else { + sprintf(graph_label_right,im->second_axis_format,sval); + } + + gfx_text ( im, + X1+7, Y0, + im->graph_col[GRC_FONT], + im->text_prop[TEXT_PROP_AXIS].font_desc, + im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER, + graph_label_right ); + } + + gfx_text(im, + X0 - + im-> + text_prop[TEXT_PROP_AXIS]. + size, Y0, + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_AXIS]. + font_desc, + im->tabwidth, 0.0, + GFX_H_RIGHT, GFX_V_CENTER, graph_label); /* minor grid */ - if(mid < 4 && exfrac == 1) { + if (mid < 4 && exfrac == 1) { /* find first and last minor line behind current major line * i is the first line and j tha last */ - if(flab == 0) { + if (flab == 0) { min_exp = val_exp - 1; - for(i = 1; yloglab[mid][i] < 10.0; i++); + for (i = 1; yloglab[mid][i] < 10.0; i++); i = yloglab[mid][i - 1] + 1; j = 10; - } - else { + } else { min_exp = val_exp; i = yloglab[mid][flab - 1] + 1; j = yloglab[mid][flab]; } /* draw minor lines below current major line */ - for(; i < j; i++) { + for (; i < j; i++) { value = i * pow(10.0, min_exp); - if(value < im->minval) continue; - + if (value < im->minval) + continue; Y0 = ytr(im, value); - if(Y0 <= im->yorigin - im->ysize) break; - + if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) + break; /* draw lines */ - gfx_new_dashed_line ( im->canvas, - X0-1,Y0, - X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID], - im->grid_dash_on, im->grid_dash_off); + gfx_line(im, + X0 - 2, Y0, + X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0 - 1, Y0, + X1 + 1, Y0, + GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } - } - else if(exfrac > 1) { - for(i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { + } else if (exfrac > 1) { + for (i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { value = pow(10.0, i); - if(value < im->minval) continue; - + if (value < im->minval) + continue; Y0 = ytr(im, value); - if(Y0 <= im->yorigin - im->ysize) break; - + if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) + break; /* draw lines */ - gfx_new_dashed_line ( im->canvas, - X0-1,Y0, - X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID], - im->grid_dash_on, im->grid_dash_off); + gfx_line(im, + X0 - 2, Y0, + X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0 - 1, Y0, + X1 + 1, Y0, + GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } /* next decade */ - if(yloglab[mid][++flab] == 10.0) { + if (yloglab[mid][++flab] == 10.0) { flab = 0; val_exp += exfrac; } } /* draw minor lines after highest major line */ - if(mid < 4 && exfrac == 1) { + if (mid < 4 && exfrac == 1) { /* find first and last minor line below current major line * i is the first line and j tha last */ - if(flab == 0) { + if (flab == 0) { min_exp = val_exp - 1; - for(i = 1; yloglab[mid][i] < 10.0; i++); + for (i = 1; yloglab[mid][i] < 10.0; i++); i = yloglab[mid][i - 1] + 1; j = 10; - } - else { + } else { min_exp = val_exp; i = yloglab[mid][flab - 1] + 1; j = yloglab[mid][flab]; } /* draw minor lines below current major line */ - for(; i < j; i++) { + for (; i < j; i++) { value = i * pow(10.0, min_exp); - if(value < im->minval) continue; - + if (value < im->minval) + continue; Y0 = ytr(im, value); - if(Y0 <= im->yorigin - im->ysize) break; - + if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) + break; /* draw lines */ - gfx_new_dashed_line ( im->canvas, - X0-1,Y0, - X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID], - im->grid_dash_on, im->grid_dash_off); + gfx_line(im, + X0 - 2, Y0, X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0 - 1, Y0, + X1 + 1, Y0, + GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } /* fancy minor gridlines */ - else if(exfrac > 1) { - for(i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { + else if (exfrac > 1) { + for (i = val_exp - exfrac / 3 * 2; i < val_exp; i += exfrac / 3) { value = pow(10.0, i); - if(value < im->minval) continue; - + if (value < im->minval) + continue; Y0 = ytr(im, value); - if(Y0 <= im->yorigin - im->ysize) break; - + if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) + break; /* draw lines */ - gfx_new_dashed_line ( im->canvas, - X0-1,Y0, - X1+1,Y0, - GRIDWIDTH, im->graph_col[GRC_GRID], - im->grid_dash_on, im->grid_dash_off); + gfx_line(im, + X0 - 2, Y0, X0, Y0, GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X1, Y0, X1 + 2, Y0, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0 - 1, Y0, + X1 + 1, Y0, + GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } @@ -1986,28 +2391,30 @@ horizontal_log_grid(image_desc_t *im) } -void -vertical_grid( - image_desc_t *im ) -{ - int xlab_sel; /* which sort of label and grid ? */ - time_t ti, tilab, timajor; - long factor; - char graph_label[100]; - double X0,Y0,Y1; /* points for filled graph and more*/ +void vertical_grid( + image_desc_t *im) +{ + int xlab_sel; /* which sort of label and grid ? */ + time_t ti, tilab, timajor; + long factor; + char graph_label[100]; + double X0, Y0, Y1; /* points for filled graph and more */ struct tm tm; /* the type of time grid is determined by finding the number of seconds per pixel in the graph */ - - - if(im->xlab_user.minsec == -1){ - factor=(im->end - im->start)/im->xsize; - xlab_sel=0; - while ( xlab[xlab_sel+1].minsec != -1 - && xlab[xlab_sel+1].minsec <= factor) { xlab_sel++; } /* pick the last one */ - while ( xlab[xlab_sel-1].minsec == xlab[xlab_sel].minsec - && xlab[xlab_sel].length > (im->end - im->start)) { xlab_sel--; } /* go back to the smallest size */ + if (im->xlab_user.minsec == -1) { + factor = (im->end - im->start) / im->xsize; + xlab_sel = 0; + while (xlab[xlab_sel + 1].minsec != + -1 && xlab[xlab_sel + 1].minsec <= factor) { + xlab_sel++; + } /* pick the last one */ + while (xlab[xlab_sel - 1].minsec == + xlab[xlab_sel].minsec + && xlab[xlab_sel].length > (im->end - im->start)) { + xlab_sel--; + } /* go back to the smallest size */ im->xlab_user.gridtm = xlab[xlab_sel].gridtm; im->xlab_user.gridst = xlab[xlab_sel].gridst; im->xlab_user.mgridtm = xlab[xlab_sel].mgridtm; @@ -2017,260 +2424,341 @@ vertical_grid( im->xlab_user.precis = xlab[xlab_sel].precis; im->xlab_user.stst = xlab[xlab_sel].stst; } - + /* y coords are the same for every line ... */ Y0 = im->yorigin; - Y1 = im->yorigin-im->ysize; - - + Y1 = im->yorigin - im->ysize; /* paint the minor 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) - ){ + 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; + if (ti < im->start || ti > im->end) + continue; while (timajor < ti) { timajor = find_next_time(timajor, - im->xlab_user.mgridtm, im->xlab_user.mgridst); + 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); - + if (ti == timajor) + continue; /* skip as falls on major grid line */ + X0 = xtr(im, ti); + gfx_line(im, X0, Y1 - 2, X0, Y1, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_line(im, X0, Y0, X0, Y0 + 2, + GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_dashed_line(im, X0, Y0 + 1, X0, + Y1 - 1, GRIDWIDTH, + im-> + graph_col[GRC_GRID], + im->grid_dash_on, im->grid_dash_off); } } /* paint the major grid */ - for(ti = find_first_time(im->start, - im->xlab_user.mgridtm, - im->xlab_user.mgridst); - ti < im->end; - ti = find_next_time(ti,im->xlab_user.mgridtm,im->xlab_user.mgridst) - ){ + for (ti = find_first_time(im->start, + im-> + xlab_user. + mgridtm, + im-> + xlab_user. + mgridst); + ti < im->end; + ti = find_next_time(ti, im->xlab_user.mgridtm, im->xlab_user.mgridst) + ) { /* are we inside the graph ? */ - if (ti < im->start || ti > im->end) continue; - X0 = xtr(im,ti); - 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); - + if (ti < im->start || ti > im->end) + continue; + X0 = xtr(im, ti); + gfx_line(im, X0, Y1 - 2, X0, Y1, + MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_line(im, X0, Y0, X0, Y0 + 3, + MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_dashed_line(im, 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 */ - for(ti = find_first_time(im->start - im->xlab_user.precis/2, - im->xlab_user.labtm, - im->xlab_user.labst); - ti <= im->end - im->xlab_user.precis/2; - 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 */ + for (ti = + find_first_time(im->start - + im->xlab_user. + precis / 2, + im->xlab_user. + labtm, + im->xlab_user. + labst); + ti <= + im->end - + im->xlab_user.precis / 2; + 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 */ /* are we inside the graph ? */ - if (tilab < im->start || tilab > im->end) continue; - + if (tilab < im->start || tilab > im->end) + continue; #if HAVE_STRFTIME localtime_r(&tilab, &tm); - strftime(graph_label,99,im->xlab_user.stst, &tm); + strftime(graph_label, 99, im->xlab_user.stst, &tm); #else # error "your libc has no strftime I guess we'll abort the exercise here." #endif - gfx_new_text ( im->canvas, - xtr(im,tilab), Y0+im->text_prop[TEXT_PROP_AXIS].size*1.4+5, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, - im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_BOTTOM, - graph_label ); - + gfx_text(im, + xtr(im, tilab), + Y0 + 3, + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_AXIS]. + font_desc, + im->tabwidth, 0.0, + GFX_H_CENTER, GFX_V_TOP, graph_label); } } -void -axis_paint( - image_desc_t *im - ) -{ +void axis_paint( + image_desc_t *im) +{ /* draw x and y axis */ - /* gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin, - im->xorigin+im->xsize,im->yorigin-im->ysize, - GRIDWIDTH, im->graph_col[GRC_AXIS]); - - gfx_new_line ( im->canvas, im->xorigin,im->yorigin-im->ysize, - im->xorigin+im->xsize,im->yorigin-im->ysize, - GRIDWIDTH, im->graph_col[GRC_AXIS]); */ - - gfx_new_line ( im->canvas, im->xorigin-4,im->yorigin, - im->xorigin+im->xsize+4,im->yorigin, - MGRIDWIDTH, im->graph_col[GRC_AXIS]); - - gfx_new_line ( im->canvas, im->xorigin,im->yorigin+4, - im->xorigin,im->yorigin-im->ysize-4, - MGRIDWIDTH, im->graph_col[GRC_AXIS]); - - + /* gfx_line ( im->canvas, im->xorigin+im->xsize,im->yorigin, + im->xorigin+im->xsize,im->yorigin-im->ysize, + GRIDWIDTH, im->graph_col[GRC_AXIS]); + + gfx_line ( im->canvas, im->xorigin,im->yorigin-im->ysize, + im->xorigin+im->xsize,im->yorigin-im->ysize, + GRIDWIDTH, im->graph_col[GRC_AXIS]); */ + + gfx_line(im, im->xorigin - 4, + im->yorigin, + im->xorigin + im->xsize + + 4, im->yorigin, MGRIDWIDTH, im->graph_col[GRC_AXIS]); + gfx_line(im, im->xorigin, + im->yorigin + 4, + im->xorigin, + im->yorigin - im->ysize - + 4, MGRIDWIDTH, im->graph_col[GRC_AXIS]); /* arrow for X and Y axis direction */ - gfx_new_area ( im->canvas, - im->xorigin+im->xsize+2, im->yorigin-2, - im->xorigin+im->xsize+2, im->yorigin+3, - im->xorigin+im->xsize+7, im->yorigin+0.5, /* LINEOFFSET */ - im->graph_col[GRC_ARROW]); - - gfx_new_area ( im->canvas, - im->xorigin-2, im->yorigin-im->ysize-2, - im->xorigin+3, im->yorigin-im->ysize-2, - im->xorigin+0.5, im->yorigin-im->ysize-7, /* LINEOFFSET */ + gfx_new_area(im, im->xorigin + im->xsize + 2, im->yorigin - 3, im->xorigin + im->xsize + 2, im->yorigin + 3, im->xorigin + im->xsize + 7, im->yorigin, /* horyzontal */ + im->graph_col[GRC_ARROW]); + gfx_close_path(im); + gfx_new_area(im, im->xorigin - 3, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin, im->yorigin - im->ysize - 7, /* vertical */ + im->graph_col[GRC_ARROW]); + gfx_close_path(im); + if (im->second_axis_scale != 0){ + gfx_line ( im, im->xorigin+im->xsize,im->yorigin+4, + im->xorigin+im->xsize,im->yorigin-im->ysize-4, + MGRIDWIDTH, im->graph_col[GRC_AXIS]); + gfx_new_area ( im, + im->xorigin+im->xsize-2, im->yorigin-im->ysize-2, + im->xorigin+im->xsize+3, im->yorigin-im->ysize-2, + im->xorigin+im->xsize, im->yorigin-im->ysize-7, /* LINEOFFSET */ im->graph_col[GRC_ARROW]); + gfx_close_path(im); + } } -void -grid_paint(image_desc_t *im) -{ - long i; - int res=0; - double X0,Y0; /* points for filled graph and more*/ - gfx_node_t *node; +void grid_paint( + image_desc_t *im) +{ + long i; + int res = 0; + double X0, Y0; /* points for filled graph and more */ + struct gfx_color_t water_color; /* draw 3d border */ - node = gfx_new_area (im->canvas, 0,im->yimg, - 2,im->yimg-2, - 2,2,im->graph_col[GRC_SHADEA]); - gfx_add_point( node , im->ximg - 2, 2 ); - gfx_add_point( node , im->ximg, 0 ); - gfx_add_point( node , 0,0 ); -/* gfx_add_point( node , 0,im->yimg ); */ - - node = gfx_new_area (im->canvas, 2,im->yimg-2, - im->ximg-2,im->yimg-2, - im->ximg - 2, 2, - im->graph_col[GRC_SHADEB]); - gfx_add_point( node , im->ximg,0); - gfx_add_point( node , im->ximg,im->yimg); - gfx_add_point( node , 0,im->yimg); -/* gfx_add_point( node , 0,im->yimg ); */ - - - if (im->draw_x_grid == 1 ) - vertical_grid(im); - - if (im->draw_y_grid == 1){ - if(im->logarithmic){ - res = horizontal_log_grid(im); + gfx_new_area(im, 0, im->yimg, + 2, im->yimg - 2, 2, 2, im->graph_col[GRC_SHADEA]); + gfx_add_point(im, im->ximg - 2, 2); + gfx_add_point(im, im->ximg, 0); + gfx_add_point(im, 0, 0); + gfx_close_path(im); + gfx_new_area(im, 2, im->yimg - 2, + im->ximg - 2, + im->yimg - 2, im->ximg - 2, 2, im->graph_col[GRC_SHADEB]); + gfx_add_point(im, im->ximg, 0); + gfx_add_point(im, im->ximg, im->yimg); + gfx_add_point(im, 0, im->yimg); + gfx_close_path(im); + if (im->draw_x_grid == 1) + vertical_grid(im); + if (im->draw_y_grid == 1) { + if (im->logarithmic) { + res = horizontal_log_grid(im); } else { - res = draw_horizontal_grid(im); + res = draw_horizontal_grid(im); } - + /* dont draw horizontal grid if there is no min and max val */ - if (! res ) { - char *nodata = "No Data found"; - gfx_new_text(im->canvas,im->ximg/2, (2*im->yorigin-im->ysize) / 2, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, - im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_CENTER, - nodata ); + if (!res) { + char *nodata = "No Data found"; + + gfx_text(im, im->ximg / 2, + (2 * im->yorigin - + im->ysize) / 2, + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_AXIS]. + font_desc, + im->tabwidth, 0.0, + GFX_H_CENTER, GFX_V_CENTER, nodata); } } /* yaxis unit description */ - gfx_new_text( im->canvas, - 10, (im->yorigin - im->ysize/2), + if (im->ylegend[0] != '\0'){ + gfx_text(im, + 10, + (im->yorigin - + im->ysize / 2), + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_UNIT]. + font_desc, + im->tabwidth, + RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend); + } + if (im->second_axis_legend[0] != '\0'){ + double Xylabel=gfx_get_text_width(im, 0, + im->text_prop[TEXT_PROP_AXIS].font_desc, + im->tabwidth, + "0") * im->unitslength + + im->text_prop[TEXT_PROP_UNIT].size *2; + gfx_text( im, + im->xorigin+im->xsize+Xylabel+8, (im->yorigin - im->ysize/2), im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_UNIT].font, - im->text_prop[TEXT_PROP_UNIT].size, im->tabwidth, + im->text_prop[TEXT_PROP_UNIT].font_desc, + im->tabwidth, RRDGRAPH_YLEGEND_ANGLE, - GFX_H_LEFT, GFX_V_CENTER, - im->ylegend); - - /* graph title */ - gfx_new_text( im->canvas, - im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size*1.3+4, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_TITLE].font, - im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_CENTER, - im->title); + im->second_axis_legend); + } + + /* graph title */ + gfx_text(im, + im->ximg / 2, 6, + im->graph_col[GRC_FONT], + im-> + text_prop[TEXT_PROP_TITLE]. + font_desc, + im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title); /* rrdtool 'logo' */ - gfx_new_text( im->canvas, - im->ximg-7, 7, - ( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044, - im->text_prop[TEXT_PROP_AXIS].font, - 5.5, im->tabwidth, 270, - GFX_H_RIGHT, GFX_V_TOP, - "RRDTOOL / TOBI OETIKER"); - + if (!(im->extra_flags & NO_RRDTOOL_TAG)){ + water_color = im->graph_col[GRC_FONT]; + water_color.alpha = 0.3; + gfx_text(im, im->ximg - 4, 5, + water_color, + im-> + text_prop[TEXT_PROP_WATERMARK]. + font_desc, im->tabwidth, + -90, GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER"); + } /* graph watermark */ - if(im->watermark[0] != '\0') { - gfx_new_text( im->canvas, - im->ximg/2, im->yimg-6, - ( im->graph_col[GRC_FONT] & 0xffffff00 ) | 0x00000044, - im->text_prop[TEXT_PROP_AXIS].font, - 5.5, im->tabwidth, 0, - GFX_H_CENTER, GFX_V_BOTTOM, - im->watermark); + if (im->watermark[0] != '\0') { + gfx_text(im, + im->ximg / 2, im->yimg - 6, + water_color, + im-> + text_prop[TEXT_PROP_WATERMARK]. + font_desc, im->tabwidth, 0, + GFX_H_CENTER, GFX_V_BOTTOM, im->watermark); } - + /* graph labels */ - if( !(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH) ) { - for(i=0;igdes_c;i++){ - if(im->gdes[i].legend[0] =='\0') - continue; - - /* im->gdes[i].leg_y is the bottom of the legend */ - X0 = im->gdes[i].leg_x; - Y0 = im->gdes[i].leg_y; - gfx_new_text ( im->canvas, X0, Y0, - im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_LEGEND].font, - im->text_prop[TEXT_PROP_LEGEND].size, - im->tabwidth,0.0, GFX_H_LEFT, GFX_V_BOTTOM, - im->gdes[i].legend ); - /* The legend for GRAPH items starts with "M " to have - enough space for the box */ - if ( im->gdes[i].gf != GF_PRINT && - im->gdes[i].gf != GF_GPRINT && - im->gdes[i].gf != GF_COMMENT) { - int boxH, boxV; - - boxH = gfx_get_text_width(im->canvas, 0, - im->text_prop[TEXT_PROP_LEGEND].font, - im->text_prop[TEXT_PROP_LEGEND].size, - im->tabwidth,"o", 0) * 1.2; - boxV = boxH*1.1; - - /* make sure transparent colors show up the same way as in the graph */ - node = gfx_new_area(im->canvas, - X0,Y0-boxV, - X0,Y0, - X0+boxH,Y0, - im->graph_col[GRC_BACK]); - gfx_add_point ( node, X0+boxH, Y0-boxV ); - - node = gfx_new_area(im->canvas, - X0,Y0-boxV, - X0,Y0, - X0+boxH,Y0, - im->gdes[i].col); - gfx_add_point ( node, X0+boxH, Y0-boxV ); - node = gfx_new_line(im->canvas, - X0,Y0-boxV, - X0,Y0, - 1.0,im->graph_col[GRC_FRAME]); - gfx_add_point(node,X0+boxH,Y0); - gfx_add_point(node,X0+boxH,Y0-boxV); - gfx_close_path(node); - } + if (!(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH)) { + for (i = 0; i < im->gdes_c; i++) { + if (im->gdes[i].legend[0] == '\0') + continue; + /* im->gdes[i].leg_y is the bottom of the legend */ + X0 = im->gdes[i].leg_x; + Y0 = im->gdes[i].leg_y; + gfx_text(im, X0, Y0, + im->graph_col[GRC_FONT], + im-> + text_prop + [TEXT_PROP_LEGEND].font_desc, + im->tabwidth, 0.0, + GFX_H_LEFT, GFX_V_BOTTOM, im->gdes[i].legend); + /* The legend for GRAPH items starts with "M " to have + enough space for the box */ + if (im->gdes[i].gf != GF_PRINT && + im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT) { + double boxH, boxV; + double X1, Y1; + + boxH = gfx_get_text_width(im, 0, + im-> + text_prop + [TEXT_PROP_LEGEND]. + font_desc, + im->tabwidth, "o") * 1.2; + boxV = boxH; + /* shift the box up a bit */ + Y0 -= boxV * 0.4; + /* make sure transparent colors show up the same way as in the graph */ + gfx_new_area(im, + X0, Y0 - boxV, + X0, Y0, X0 + boxH, Y0, im->graph_col[GRC_BACK]); + gfx_add_point(im, X0 + boxH, Y0 - boxV); + gfx_close_path(im); + gfx_new_area(im, X0, Y0 - boxV, X0, + Y0, X0 + boxH, Y0, im->gdes[i].col); + gfx_add_point(im, X0 + boxH, Y0 - boxV); + gfx_close_path(im); + cairo_save(im->cr); + cairo_new_path(im->cr); + cairo_set_line_width(im->cr, 1.0); + X1 = X0 + boxH; + Y1 = Y0 - boxV; + gfx_line_fit(im, &X0, &Y0); + gfx_line_fit(im, &X1, &Y1); + cairo_move_to(im->cr, X0, Y0); + cairo_line_to(im->cr, X1, Y0); + cairo_line_to(im->cr, X1, Y1); + cairo_line_to(im->cr, X0, Y1); + cairo_close_path(im->cr); + cairo_set_source_rgba(im->cr, + im-> + graph_col + [GRC_FRAME]. + red, + 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); } + } } } @@ -2279,675 +2767,806 @@ grid_paint(image_desc_t *im) * lazy check make sure we rely need to create this graph *****************************************************/ -int lazy_check(image_desc_t *im){ - FILE *fd = NULL; - int size = 1; - struct stat imgstat; - - if (im->lazy == 0) return 0; /* no lazy option */ - if (stat(im->graphfile,&imgstat) != 0) - return 0; /* can't stat */ +int lazy_check( + image_desc_t *im) +{ + FILE *fd = NULL; + int size = 1; + struct stat imgstat; + + if (im->lazy == 0) + return 0; /* no lazy option */ + if (strlen(im->graphfile) == 0) + return 0; /* inmemory option */ + if (stat(im->graphfile, &imgstat) != 0) + return 0; /* can't stat */ /* one pixel in the existing graph is more then what we would change here ... */ - if (time(NULL) - imgstat.st_mtime > - (im->end - im->start) / im->xsize) - return 0; - if ((fd = fopen(im->graphfile,"rb")) == NULL) - return 0; /* the file does not exist */ - switch (im->canvas->imgformat) { + if (time(NULL) - imgstat.st_mtime > (im->end - im->start) / im->xsize) + return 0; + if ((fd = fopen(im->graphfile, "rb")) == NULL) + return 0; /* the file does not exist */ + switch (im->imgformat) { case IF_PNG: - size = PngSize(fd,&(im->ximg),&(im->yimg)); - break; + size = PngSize(fd, &(im->ximg), &(im->yimg)); + break; default: - size = 1; + size = 1; } fclose(fd); return size; } -#ifdef WITH_PIECHART -void -pie_part(image_desc_t *im, gfx_color_t color, - double PieCenterX, double PieCenterY, double Radius, - double startangle, double endangle) -{ - gfx_node_t *node; - double angle; - double step=M_PI/50; /* Number of iterations for the circle; - ** 10 is definitely too low, more than - ** 50 seems to be overkill - */ - - /* Strange but true: we have to work clockwise or else - ** anti aliasing nor transparency don't work. - ** - ** This test is here to make sure we do it right, also - ** this makes the for...next loop more easy to implement. - ** The return will occur if the user enters a negative number - ** (which shouldn't be done according to the specs) or if the - ** programmers do something wrong (which, as we all know, never - ** happens anyway :) - */ - if (endangle