From ea8c705cc27ef33dee2cc6561ed51e16ddc5d0a9 Mon Sep 17 00:00:00 2001 From: oetiker Date: Sun, 20 Apr 2008 22:46:39 +0000 Subject: [PATCH] Introduced a alternated interface to rrd_graph using rrd_info style return values: rrd_graph_v The graph_v interface returnes additional information about the graph including the location of the graphing area within the image. When called with '-' as filename it will even return the image data. The new interface is supported in the rrdtool command line, RRDs perl and ruby bindings. git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1331 a5681a0c-68f1-0310-ab6d-d61299d08faa --- CONTRIBUTORS | 1 + NEWS | 6 +- bindings/perl-shared/RRDs.pm | 6 + bindings/perl-shared/RRDs.xs | 17 + bindings/ruby/main.c | 170 +++-- doc/rrdgraph.pod | 38 +- src/rrd.h | 42 +- src/rrd_graph.c | 1502 ++++++++++++++++++++++-------------------- src/rrd_graph.h | 30 +- src/rrd_info.c | 60 ++ src/rrd_tool.c | 109 ++- src/rrd_tool.h | 25 +- 12 files changed, 1127 insertions(+), 879 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0046850..3a33ebe 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -33,6 +33,7 @@ Joey Miller php3 and php4 bindings Jost.Krieger Kai Siering Larry Leszczynski +Mark Plaksin rrd_graph_v Matt Chambers --full-size-mode for rrdgraph McCreary mccreary with xoanon.colorado.edu Mike Mitchell diff --git a/NEWS b/NEWS index 32ff16e..e7b29b2 100644 --- a/NEWS +++ b/NEWS @@ -27,9 +27,11 @@ Graphing (Tobi Oetiker) * TRENDNAN filter that ignores NAN values while caculating the TREND data. (Timo Stripf) * --full-size-mode to specify the outer border of the image and not just of the graphing canvas (Matthew Chambers) * TEXTALIGN command to alter default text alignment behaviour -* C API supports in-memory graphing with rrd_graph_in_memory (Evan Miller) +* C API in-memory graphing with rrd_graph_v (Evan Miller) * draw dashed lines in graphs (Thomas Gutzler) - +* new interface graphv which returns inforamation useing the rrd_info + interface (Tobi Oetiker and Mark Plaksin) + Forecasting (Evan Miller) ----------- * the new MHWPREDICT consolidation function uses a variation of the Holt-Winters diff --git a/bindings/perl-shared/RRDs.pm b/bindings/perl-shared/RRDs.pm index 3e77a2a..757e5ce 100644 --- a/bindings/perl-shared/RRDs.pm +++ b/bindings/perl-shared/RRDs.pm @@ -98,6 +98,12 @@ the values of the properties. print "$key = $$hash{$key}\n"; } +B takes the same paramters as B but it returns a +pointer to hash. The hash returned contains meta information about the +graph. Like its size as well as the position of the graph area on the image. +When calling with and empty filename than the contents of the graph will be +returned in the hash as well (key 'image'). + B also returns a pointer to hash. The keys of the hash are concatenated strings of a timestamp, RRA index, and data source name for each consolidated data point (CDP) written to disk as a result of the diff --git a/bindings/perl-shared/RRDs.xs b/bindings/perl-shared/RRDs.xs index f84efef..5eeba18 100644 --- a/bindings/perl-shared/RRDs.xs +++ b/bindings/perl-shared/RRDs.xs @@ -99,6 +99,10 @@ extern "C" { hvs(newSVpv(data->value.u_str,0)); \ rrd_freemem(data->value.u_str); \ break; \ + case RD_I_BLO: \ + hvs(newSVpv(data->value.u_blo.ptr,data->value.u_blo.size)); \ + rrd_freemem(data->value.u_blo.ptr); \ + break; \ } \ rrd_freemem(data->key); \ data = data->next; \ @@ -407,6 +411,19 @@ rrd_updatev(...) OUTPUT: RETVAL +SV* +rrd_graphv(...) + PROTOTYPE: @ + PREINIT: + info_t *data,*save; + int i; + char **argv; + HV *hash; + CODE: + rrdinfocode(rrd_graph_v); + OUTPUT: + RETVAL + int rrd_dump(...) PROTOTYPE: @ diff --git a/bindings/ruby/main.c b/bindings/ruby/main.c index ff747f7..e5a3e80 100644 --- a/bindings/ruby/main.c +++ b/bindings/ruby/main.c @@ -80,6 +80,8 @@ void reset_rrd_state( rrd_clear_error(); } +/* Simple Calls */ + VALUE rrd_call( RRDFUNC func, VALUE args) @@ -108,6 +110,105 @@ VALUE rb_rrd_dump( return rrd_call(rrd_dump, args); } +VALUE rb_rrd_resize( + VALUE self, + VALUE args) +{ + return rrd_call(rrd_resize, args); +} + +VALUE rb_rrd_restore( + VALUE self, + VALUE args) +{ + return rrd_call(rrd_restore, args); +} + +VALUE rb_rrd_tune( + VALUE self, + VALUE args) +{ + return rrd_call(rrd_tune, args); +} + +VALUE rb_rrd_update( + VALUE self, + VALUE args) +{ + return rrd_call(rrd_update, args); +} + + +/* Calls Returning Data via the Info Interface */ + +VALUE rb_rrd_infocall( + RRDFUNC func, + VALUE args) +{ + string_arr a; + info_t *p, *data; + VALUE result; + + a = string_arr_new(args); + data = func(a.len, a.strings); + string_arr_delete(a); + + RRD_CHECK_ERROR result = rb_hash_new(); + + while (data) { + VALUE key = rb_str_new2(data->key); + + switch (data->type) { + case RD_I_VAL: + if (isnan(data->value.u_val)) { + rb_hash_aset(result, key, Qnil); + } else { + rb_hash_aset(result, key, rb_float_new(data->value.u_val)); + } + break; + case RD_I_CNT: + rb_hash_aset(result, key, INT2FIX(data->value.u_cnt)); + break; + case RD_I_STR: + rb_hash_aset(result, key, rb_str_new2(data->value.u_str)); + free(data->value.u_str); + break; + case RD_I_BLO: + rb_hash_aset(result, key, rb_str_new(data->value.u_blo.ptr,data->value.u_blo.size)); + free(data->value.u_blo.ptr); + break; + } + p = data; + data = data->next; + free(p); + } + return result; +} + +VALUE rb_rrd_info( + VALUE self, + VALUE args) +{ + return rrd_infocall(rrd_info, args); +} + +VALUE rb_rrd_updatev( + VALUE self, + VALUE args) +{ + return rrd_infocall(rrd_update_v, args); +} + +VALUE rb_rrd_graphv( + VALUE self, + VALUE args) +{ + return rrd_infocall(rrd_graph_v, args); +} + + +/* Other Calls */ + VALUE rb_rrd_fetch( VALUE self, VALUE args) @@ -185,45 +286,6 @@ VALUE rb_rrd_graph( return result; } -VALUE rb_rrd_info( - VALUE self, - VALUE args) -{ - string_arr a; - info_t *p, *data; - VALUE result; - - a = string_arr_new(args); - data = rrd_info(a.len, a.strings); - string_arr_delete(a); - - RRD_CHECK_ERROR result = rb_hash_new(); - - while (data) { - VALUE key = rb_str_new2(data->key); - - switch (data->type) { - case RD_I_VAL: - if (isnan(data->value.u_val)) { - rb_hash_aset(result, key, Qnil); - } else { - rb_hash_aset(result, key, rb_float_new(data->value.u_val)); - } - break; - case RD_I_CNT: - rb_hash_aset(result, key, INT2FIX(data->value.u_cnt)); - break; - case RD_I_STR: - rb_hash_aset(result, key, rb_str_new2(data->value.u_str)); - free(data->value.u_str); - break; - } - p = data; - data = data->next; - free(p); - } - return result; -} VALUE rb_rrd_last( VALUE self, @@ -241,34 +303,6 @@ VALUE rb_rrd_last( return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last)); } -VALUE rb_rrd_resize( - VALUE self, - VALUE args) -{ - return rrd_call(rrd_resize, args); -} - -VALUE rb_rrd_restore( - VALUE self, - VALUE args) -{ - return rrd_call(rrd_restore, args); -} - -VALUE rb_rrd_tune( - VALUE self, - VALUE args) -{ - return rrd_call(rrd_tune, args); -} - -VALUE rb_rrd_update( - VALUE self, - VALUE args) -{ - return rrd_call(rrd_update, args); -} - void Init_RRD( ) { @@ -285,4 +319,6 @@ void Init_RRD( rb_define_module_function(mRRD, "tune", rb_rrd_tune, -2); rb_define_module_function(mRRD, "update", rb_rrd_update, -2); rb_define_module_function(mRRD, "info", rb_rrd_info, -2); + rb_define_module_function(mRRD, "updatev", rb_rrd_updatev, -2); + rb_define_module_function(mRRD, "graphv", rb_rrd_graphv, -2); } diff --git a/doc/rrdgraph.pod b/doc/rrdgraph.pod index 6c7c330..54fd5b0 100644 --- a/doc/rrdgraph.pod +++ b/doc/rrdgraph.pod @@ -4,7 +4,7 @@ rrdgraph - Round Robin Database tool grapher functions =head1 SYNOPSIS -B I +B I [I> ...] [I> ...] [I> ...] @@ -52,6 +52,14 @@ graph it (or print it). This ends the B sequence. =over 4 +=item B + +This alternate version of B takes the same arguments and performs the +same function. The I stands for I, which describes the output +returned. B will return a lot of information about the graph using +the same format as rrdtool info (key = value). See the bottom of the document for more information. + + =item filename The name and path of the graph to generate. It is recommended to @@ -432,6 +440,34 @@ More details on http://developer.gnome.org/doc/API/2.0/pango/PangoMarkupFormat.h =back +=head2 graphv + +Calling rrdtool with the graphv option will return information in the +rrdtool info format. On the command line this means that all output will be +in key=value format. When used from the perl and ruby bindings a hash +pointer will be returned from the call. + +When the filename '-' is given, the contents of the graph itself will also +be returned through this interface (hash key 'image'). On the command line +the output will look like this: + + print[0] = "0.020833" + print[1] = "0.0440833" + graph_left = 51 + graph_top = 22 + graph_width = 400 + graph_height = 100 + image_width = 481 + image_height = 154 + value_min = 0.0000000000e+00 + value_max = 4.0000000000e-02 + image = BLOB_SIZE:8196 + [... 8196 bytes of image data ...] + +There is more information returned than in the standard interface. +Especially the 'graph_*' keys are new. They help applications that want to +know what is where on the graph. + =head1 SEE ALSO L gives an overview of how B works. diff --git a/src/rrd.h b/src/rrd.h index 978ad1c..3e1a08a 100644 --- a/src/rrd.h +++ b/src/rrd.h @@ -86,6 +86,35 @@ extern "C" { off_t pos; /* current pos in file */ } rrd_file_t; +/* rrd info interface */ + typedef struct rrd_blob_t { + unsigned long size; /* size of the blob */ + unsigned char *ptr; /* pointer */ + } rrd_blob_t; + + enum info_type { RD_I_VAL = 0, + RD_I_CNT, + RD_I_STR, + RD_I_INT, + RD_I_BLO + }; + + typedef union infoval { + unsigned long u_cnt; + rrd_value_t u_val; + char *u_str; + int u_int; + struct rrd_blob_t u_blo; + } infoval; + + typedef struct info_t { + char *key; + enum info_type type; + union infoval value; + struct info_t *next; + } info_t; + + /* main function blocks */ int rrd_create( int, @@ -102,16 +131,9 @@ extern "C" { FILE *, double *, double *); - - unsigned char *rrd_graph_in_memory( - int argc, - char **argv, - char ***prdata, - int *xsize, - int *ysize, - double *ymin, - double *ymax, - size_t * img_size); + info_t *rrd_graph_v( + int, + char **); int rrd_fetch( int, diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 0e84786..0f84b80 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -33,7 +33,7 @@ #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[] = { @@ -337,6 +337,9 @@ int im_free( status = cairo_status(im->cr); cairo_destroy(im->cr); } + if (im->rendered_image) { + free(im->rendered_image); + } if (im->surface) cairo_surface_destroy(im->surface); if (status) @@ -1427,8 +1430,7 @@ time_t find_next_time( /* calculate values required for PRINT and GPRINT functions */ int print_calc( - image_desc_t *im, - char ***prdata) + image_desc_t *im) { long i, ii, validsteps; double printval; @@ -1439,24 +1441,16 @@ int print_calc( double magfact = -1; char *si_symb = ""; char *percent_s; - int prlines = 1; + 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; 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 @@ -1527,44 +1521,44 @@ int print_calc( } if (im->gdes[i].gf == GF_PRINT) { - (*prdata)[prlines - 2] = - malloc((FMT_LEG_LEN + 2) * sizeof(char)); - (*prdata)[prlines - 1] = NULL; + infoval prline; + if (im->gdes[i].strftm) { - strftime((*prdata)[prlines - 2], FMT_LEG_LEN, - im->gdes[i].format, &tmvdef); + prline.u_str = 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 { - if (bad_format(im->gdes[i].format)) { - rrd_set_error("bad format for PRINT in '%s'", - im->gdes[i].format); - return -1; - } -#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 + 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); + 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, + 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; @@ -1637,33 +1631,30 @@ int leg_place( if (im->extra_flags & FULL_SIZE_MODE) leg_y = leg_y_prev = leg_y - (int) (im->text_prop[TEXT_PROP_LEGEND].size * 1.8); - for (i = 0; i < im->gdes_c; i++) { 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->extra_flags & FORCE_RULES_LEGEND)) { - if (im->gdes[i].gf == GF_HRULE && - (im->gdes[i].yrule < im->minval - || im->gdes[i].yrule > im->maxval)) + 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)) + 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'; } 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] == '\\' + 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; @@ -1679,10 +1670,10 @@ int leg_place( 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); + 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') { @@ -1700,16 +1691,21 @@ int leg_place( /* no interleg space if string ends in \g */ 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, - im->text_prop[TEXT_PROP_LEGEND]. - size, im->tabwidth, - im->gdes[i].legend); + fill += + gfx_get_text_width(im, + fill + border, + im-> + text_prop + [TEXT_PROP_LEGEND]. + font, + im-> + text_prop + [TEXT_PROP_LEGEND]. + size, + im->tabwidth, im->gdes[i].legend); leg_c++; } else { legspace[i] = 0; @@ -1763,7 +1759,6 @@ int leg_place( 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 */ @@ -1771,11 +1766,15 @@ int leg_place( im->gdes[ii].leg_y = leg_y; leg_x += gfx_get_text_width(im, leg_x, - im->text_prop[TEXT_PROP_LEGEND]. + im-> + text_prop + [TEXT_PROP_LEGEND]. font, - im->text_prop[TEXT_PROP_LEGEND]. - size, im->tabwidth, - im->gdes[ii].legend) + im-> + text_prop + [TEXT_PROP_LEGEND]. + size, + im->tabwidth, im->gdes[ii].legend) + legspace[ii] + glue; } @@ -1824,7 +1823,8 @@ int leg_place( int calc_horizontal_grid( - image_desc_t *im) + image_desc_t + *im) { double range; double scaledrange; @@ -1835,7 +1835,6 @@ int calc_horizontal_grid( 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)) { @@ -1853,12 +1852,10 @@ int calc_horizontal_grid( 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 = 0.1; /* should have at least 5 lines but no more then 15 */ @@ -1884,15 +1881,16 @@ int calc_horizontal_grid( if (im->unitslength < len + 2) im->unitslength = len + 2; - sprintf(im->ygrid_scale.labfmt, "%%%d.%df%s", len, + 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" : "")); + sprintf(im->ygrid_scale.labfmt, + "%%%d.0f%s", len, (im->symbol != ' ' ? " %c" : "")); } } else { for (i = 0; ylab[i].grid > 0; i++) { @@ -1920,7 +1918,8 @@ int calc_horizontal_grid( } int draw_horizontal_grid( - image_desc_t *im) + image_desc_t + *im) { int i; double scaledstep; @@ -1928,21 +1927,22 @@ int draw_horizontal_grid( 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; + 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)); + 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) { + 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. */ @@ -1951,7 +1951,8 @@ int draw_horizontal_grid( && (YN < im->yorigin - im->ysize || YN > im->yorigin))) { if (im->symbol == ' ') { if (im->extra_flags & ALTYGRID) { - sprintf(graph_label, im->ygrid_scale.labfmt, + sprintf(graph_label, + im->ygrid_scale.labfmt, scaledstep * (double) i); } else { if (MaxY < 10) { @@ -1966,7 +1967,8 @@ int draw_horizontal_grid( char sisym = (i == 0 ? ' ' : im->symbol); if (im->extra_flags & ALTYGRID) { - sprintf(graph_label, im->ygrid_scale.labfmt, + sprintf(graph_label, + im->ygrid_scale.labfmt, scaledstep * (double) i, sisym); } else { if (MaxY < 10) { @@ -1979,39 +1981,42 @@ int draw_horizontal_grid( } } nlabels++; - gfx_text(im, - X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0, + 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_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, + 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_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], + 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, + 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], + GRIDWIDTH, + im-> + graph_col[GRC_GRID], im->grid_dash_on, im->grid_dash_off); - } } } @@ -2046,17 +2051,34 @@ double frexp10( /* logaritmic horizontal grid */ int horizontal_log_grid( - image_desc_t *im) + 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 */ + { + 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 */ @@ -2070,7 +2092,6 @@ int horizontal_log_grid( 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) @@ -2085,11 +2106,11 @@ int horizontal_log_grid( mid++; 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); + } + 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 @@ -2101,10 +2122,8 @@ int horizontal_log_grid( val_exp = tmp; 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) { @@ -2112,27 +2131,21 @@ int horizontal_log_grid( value = yloglab[mid][flab] * pow(10.0, val_exp); if (AlmostEqual2sComplement(value, pre_value, 4)) break; /* it seems we are not converging */ - pre_value = value; - Y0 = ytr(im, value); if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) break; - /* major grid line */ - 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, + 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); - + MGRIDWIDTH, + im-> + graph_col + [GRC_MGRID], im->grid_dash_on, im->grid_dash_off); /* label */ if (im->extra_flags & FORCE_UNITS_SI) { int scale; @@ -2145,23 +2158,27 @@ int horizontal_log_grid( 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)) + 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_text(im, - X0 - im->text_prop[TEXT_PROP_AXIS].size, Y0, + 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); - + 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); /* minor grid */ if (mid < 4 && exfrac == 1) { /* find first and last minor line behind current major line @@ -2183,22 +2200,20 @@ int horizontal_log_grid( value = i * pow(10.0, min_exp); if (value < im->minval) continue; - Y0 = ytr(im, value); if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) break; - /* draw lines */ 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, + 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], + GRIDWIDTH, + im-> + graph_col[GRC_GRID], im->grid_dash_on, im->grid_dash_off); } } else if (exfrac > 1) { @@ -2206,22 +2221,20 @@ int horizontal_log_grid( value = pow(10.0, i); if (value < im->minval) continue; - Y0 = ytr(im, value); if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) break; - /* draw lines */ 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, + 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], + GRIDWIDTH, + im-> + graph_col[GRC_GRID], im->grid_dash_on, im->grid_dash_off); } } @@ -2254,20 +2267,19 @@ int horizontal_log_grid( value = i * pow(10.0, min_exp); if (value < im->minval) continue; - Y0 = ytr(im, value); if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) break; - /* draw lines */ 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, + 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], + GRIDWIDTH, + im-> + graph_col[GRC_GRID], im->grid_dash_on, im->grid_dash_off); } } @@ -2277,20 +2289,19 @@ int horizontal_log_grid( value = pow(10.0, i); if (value < im->minval) continue; - Y0 = ytr(im, value); if (floor(Y0 + 0.5) <= im->yorigin - im->ysize) break; - /* draw lines */ 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, + 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], + GRIDWIDTH, + im-> + graph_col[GRC_GRID], im->grid_dash_on, im->grid_dash_off); } } @@ -2311,16 +2322,15 @@ void vertical_grid( /* 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) { + 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 + 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 */ @@ -2337,16 +2347,21 @@ void vertical_grid( /* y coords are the same for every line ... */ Y0 = im->yorigin; 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); + 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) @@ -2356,27 +2371,33 @@ void vertical_grid( 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_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], + 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); + im-> + xlab_user. + mgridtm, + im-> + xlab_user. + mgridst); ti < im->end; ti = find_next_time(ti, im->xlab_user.mgridtm, im->xlab_user.mgridst) ) { @@ -2384,27 +2405,34 @@ void vertical_grid( 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); - + 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; + 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 HAVE_STRFTIME localtime_r(&tilab, &tm); strftime(graph_label, 99, im->xlab_user.stst, &tm); @@ -2415,10 +2443,13 @@ void vertical_grid( xtr(im, tilab), Y0 + 3, im->graph_col[GRC_FONT], - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 0.0, + im-> + text_prop[TEXT_PROP_AXIS]. + font, + im-> + text_prop[TEXT_PROP_AXIS]. + size, im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, graph_label); - } } @@ -2436,26 +2467,22 @@ void axis_paint( 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]); - - + 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, 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); - - } void grid_paint( @@ -2473,19 +2500,15 @@ void grid_paint( 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]); + 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); @@ -2498,46 +2521,59 @@ void grid_paint( char *nodata = "No Data found"; gfx_text(im, im->ximg / 2, - (2 * im->yorigin - im->ysize) / 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); + 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); } } /* yaxis unit description */ gfx_text(im, - 10, (im->yorigin - im->ysize / 2), + 10, + (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, + im-> + text_prop[TEXT_PROP_UNIT]. + size, im->tabwidth, RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend); - /* graph title */ gfx_text(im, im->ximg / 2, 6, 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_TOP, im->title); + im-> + text_prop[TEXT_PROP_TITLE]. + font, + im-> + text_prop[TEXT_PROP_TITLE]. + size, im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title); /* rrdtool 'logo' */ water_color = im->graph_col[GRC_FONT]; water_color.alpha = 0.3; - gfx_text(im, - im->ximg - 4, 5, + gfx_text(im, im->ximg - 4, 5, water_color, - im->text_prop[TEXT_PROP_AXIS].font, - 5.5, im->tabwidth, -90, - GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER"); - + im-> + text_prop[TEXT_PROP_AXIS]. + font, 5.5, im->tabwidth, + -90, GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER"); /* graph watermark */ if (im->watermark[0] != '\0') { gfx_text(im, im->ximg / 2, im->yimg - 6, water_color, - im->text_prop[TEXT_PROP_AXIS].font, - 5.5, im->tabwidth, 0, + im-> + text_prop[TEXT_PROP_AXIS]. + font, 5.5, im->tabwidth, 0, GFX_H_CENTER, GFX_V_BOTTOM, im->watermark); } @@ -2546,16 +2582,19 @@ void grid_paint( 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, - im->text_prop[TEXT_PROP_LEGEND].size, - im->tabwidth, 0.0, GFX_H_LEFT, GFX_V_BOTTOM, - im->gdes[i].legend); + 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 && @@ -2563,31 +2602,28 @@ void grid_paint( double boxH, boxV; double X1, Y1; - boxH = gfx_get_text_width(im, 0, - im->text_prop[TEXT_PROP_LEGEND]. + im-> + text_prop + [TEXT_PROP_LEGEND]. font, - im->text_prop[TEXT_PROP_LEGEND]. + im-> + text_prop + [TEXT_PROP_LEGEND]. size, 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_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); @@ -2600,13 +2636,24 @@ void grid_paint( 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); + 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 }; + double dashes[] = { + 3.0 + }; cairo_set_dash(im->cr, dashes, 1, 0.0); } cairo_stroke(im->cr); @@ -2630,6 +2677,8 @@ int lazy_check( 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 @@ -2651,7 +2700,8 @@ int lazy_check( int graph_size_location( - image_desc_t *im, + image_desc_t + *im, int elements) { /* The actual size of the image to draw is determined from @@ -2660,8 +2710,10 @@ int graph_size_location( ** and other things outside the graph area */ - int Xvertical = 0, Ytitle = 0, Xylabel = 0, Xmain = 0, Ymain = 0, - Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4; + int Xvertical = 0, Ytitle = + 0, Xylabel = 0, Xmain = 0, Ymain = + 0, Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4; + infoval info; if (im->extra_flags & ONLY_GRAPH) { im->xorigin = 0; @@ -2710,10 +2762,16 @@ int graph_size_location( Yxlabel = im->text_prop[TEXT_PROP_AXIS].size * 2.5; } if (im->draw_y_grid || im->forceleftspace) { - Xylabel = gfx_get_text_width(im, 0, - im->text_prop[TEXT_PROP_AXIS].font, - im->text_prop[TEXT_PROP_AXIS].size, - im->tabwidth, "0") * im->unitslength; + Xylabel = + gfx_get_text_width(im, 0, + im-> + text_prop + [TEXT_PROP_AXIS]. + font, + im-> + text_prop + [TEXT_PROP_AXIS]. + size, im->tabwidth, "0") * im->unitslength; } } @@ -2728,42 +2786,34 @@ int graph_size_location( im->yorigin = im->ysize; Xmain = im->ximg; Ymain = im->yimg; - im->yorigin += Ytitle; - /* Now calculate the total size. Insert some spacing where desired. im->xorigin and im->yorigin need to correspond with the lower left corner of the main graph area or, if this one is not set, the imaginary box surrounding the pie chart area. */ - /* Initial size calculation for the main graph area */ Xmain = im->ximg - (Xylabel + 2 * Xspacing); if (Xmain) Xmain -= Xspacing; /* put space between main graph area and right edge */ - im->xorigin = Xspacing + Xylabel; - /* the length of the title should not influence with width of the graph if (Xtitle > im->ximg) im->ximg = Xtitle; */ - if (Xvertical) { /* unit description */ Xmain -= Xvertical; im->xorigin += Xvertical; } im->xsize = Xmain; xtr(im, 0); - /* The vertical size of the image is known in advance. The main graph area ** (Ymain) and im->yorigin must be set according to the space requirements ** of the legend and the axis labels. */ - if (im->extra_flags & NOLEGEND) { /* set dimensions correctly if using full size mode with no legend */ im->yorigin = - im->yimg - im->text_prop[TEXT_PROP_AXIS].size * 2.5 - - Yspacing; + im->yimg - + im->text_prop[TEXT_PROP_AXIS].size * 2.5 - Yspacing; Ymain = im->yorigin; } else { /* Determine where to place the legends onto the image. @@ -2787,7 +2837,6 @@ int graph_size_location( } im->ysize = Ymain; - } else { /* dimension options -width and -height refer to the dimensions of the main graph area */ /* The actual size of the image to draw is determined from @@ -2831,21 +2880,16 @@ int graph_size_location( ** size already allocated. */ im->ximg = Xylabel + Xmain + 2 * Xspacing; - if (Xmain) im->ximg += Xspacing; - im->xorigin = Xspacing + Xylabel; - /* the length of the title should not influence with width of the graph if (Xtitle > im->ximg) im->ximg = Xtitle; */ - if (Xvertical) { /* unit description */ im->ximg += Xvertical; im->xorigin += Xvertical; } xtr(im, 0); - /* The vertical size is interesting... we need to compare ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel} @@ -2855,14 +2899,9 @@ int graph_size_location( ** then do the legend, then adjust the total height of the img, ** adding space for a watermark if one exists; */ - /* reserve space for main and/or pie */ - im->yimg = Ymain + Yxlabel; - - im->yorigin = im->yimg - Yxlabel; - /* reserve space for the title *or* some padding above the graph */ if (Ytitle) { im->yimg += Ytitle; @@ -2873,126 +2912,111 @@ int graph_size_location( } /* reserve space for padding below the graph */ im->yimg += Yspacing; - /* Determine where to place the legends onto the image. ** Adjust im->yimg to match the space requirements. */ if (leg_place(im, 0) == -1) return -1; - if (im->watermark[0] != '\0') { im->yimg += Ywatermark; } } ytr(im, DNAN); + info.u_cnt = im->xorigin; + grinfo_push(im, sprintf_alloc("graph_left"), RD_I_CNT, info); + info.u_cnt = im->yorigin - Ymain; + grinfo_push(im, sprintf_alloc("graph_top"), RD_I_CNT, info); + info.u_cnt = im->xsize; + grinfo_push(im, sprintf_alloc("graph_width"), RD_I_CNT, info); + info.u_cnt = im->ysize; + grinfo_push(im, sprintf_alloc("graph_height"), RD_I_CNT, info); + info.u_cnt = im->ximg; + grinfo_push(im, sprintf_alloc("image_width"), RD_I_CNT, info); + info.u_cnt = im->yimg; + grinfo_push(im, sprintf_alloc("image_height"), RD_I_CNT, info); return 0; } - - -static cairo_status_t cairo_write_func_filehandle( +static cairo_status_t cairo_output( void *closure, - const unsigned char *data, - unsigned int length) -{ - if (fwrite(data, length, 1, closure) != 1) - return CAIRO_STATUS_WRITE_ERROR; - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t cairo_copy_to_buffer( - void *closure, - const unsigned char *data, + const unsigned char + *data, unsigned int length) { image_desc_t *im = closure; im->rendered_image = realloc(im->rendered_image, im->rendered_image_size + length); - if (im->rendered_image == NULL) { + if (im->rendered_image == NULL) return CAIRO_STATUS_WRITE_ERROR; - } - memcpy(im->rendered_image + im->rendered_image_size, data, length); - im->rendered_image_size += length; - return CAIRO_STATUS_SUCCESS; } /* draw that picture thing ... */ int graph_paint( - image_desc_t *im, - char ***calcpr) + image_desc_t *im) { int i, ii; int lazy = lazy_check(im); - double areazero = 0.0; graph_desc_t *lastgdes = NULL; - + infoval info; PangoFontMap *font_map = pango_cairo_font_map_get_default(); - /* if we are lazy and there is nothing to PRINT ... quit now */ if (lazy && im->prt_c == 0) return 0; - /* pull the data from the rrd files ... */ - if (data_fetch(im) == -1) return -1; - /* evaluate VDEF and CDEF operations ... */ if (data_calc(im) == -1) return -1; - - /* calculate and PRINT and GPRINT definitions. We have to do it at * this point because it will affect the length of the legends * if there are no graph elements we stop here ... * if we are lazy, try to quit ... */ - i = print_calc(im, calcpr); + i = print_calc(im); if (i < 0) return -1; if ((i == 0) || lazy) return 0; - /************************************************************** *** Calculating sizes and locations became a bit confusing *** *** so I moved this into a separate function. *** **************************************************************/ if (graph_size_location(im, i) == -1) return -1; - /* get actual drawing data and find min and max values */ if (data_proc(im) == -1) return -1; - if (!im->logarithmic) { si_unit(im); } + /* identify si magnitude Kilo, Mega Giga ? */ if (!im->rigid && !im->logarithmic) expand_range(im); /* make sure the upper and lower limit are sensible values */ + info.u_val = im->minval; + grinfo_push(im, sprintf_alloc("value_min"), RD_I_VAL, info); + info.u_val = im->maxval; + grinfo_push(im, sprintf_alloc("value_max"), RD_I_VAL, info); + if (!calc_horizontal_grid(im)) return -1; - /* reset precalc */ ytr(im, DNAN); - /* if (im->gridfit) apply_gridfit(im); */ - - /* the actual graph is created by going through the individual graph elements and then drawing them */ cairo_surface_destroy(im->surface); - switch (im->imgformat) { case IF_PNG: im->surface = @@ -3003,59 +3027,56 @@ int graph_paint( case IF_PDF: im->gridfit = 0; im->surface = strlen(im->graphfile) - ? cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom) - : cairo_pdf_surface_create_for_stream(&cairo_copy_to_buffer, im, - im->ximg * im->zoom, - im->yimg * im->zoom); + ? + cairo_pdf_surface_create_for_stream + (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom) + : cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom, + im->yimg * im->zoom); break; case IF_EPS: im->gridfit = 0; im->surface = strlen(im->graphfile) - ? cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom) - : cairo_ps_surface_create_for_stream(&cairo_copy_to_buffer, im, - im->ximg * im->zoom, - im->yimg * im->zoom); + ? + cairo_ps_surface_create_for_stream + (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom) + : cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom, + im->yimg * im->zoom); break; case IF_SVG: im->gridfit = 0; im->surface = strlen(im->graphfile) - ? cairo_svg_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom) - : cairo_svg_surface_create_for_stream(&cairo_copy_to_buffer, im, - im->ximg * im->zoom, - im->yimg * im->zoom); - cairo_svg_surface_restrict_to_version(im->surface, - CAIRO_SVG_VERSION_1_1); + ? + cairo_svg_surface_create_for_stream + (&cairo_output, im, im->ximg * im->zoom, im->yimg * im->zoom) + : cairo_svg_surface_create(im-> + graphfile, + im-> + ximg * im->zoom, im->yimg * im->zoom); + cairo_svg_surface_restrict_to_version + (im->surface, CAIRO_SVG_VERSION_1_1); break; }; im->cr = cairo_create(im->surface); cairo_set_antialias(im->cr, im->graph_antialias); cairo_scale(im->cr, im->zoom, im->zoom); pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100); - - gfx_new_area(im, - 0, 0, - 0, im->yimg, im->ximg, im->yimg, im->graph_col[GRC_BACK]); - + gfx_new_area(im, 0, 0, 0, im->yimg, + im->ximg, im->yimg, im->graph_col[GRC_BACK]); gfx_add_point(im, im->ximg, 0); gfx_close_path(im); - - gfx_new_area(im, - im->xorigin, im->yorigin, - im->xorigin + im->xsize, im->yorigin, - im->xorigin + im->xsize, im->yorigin - im->ysize, - im->graph_col[GRC_CANVAS]); - + gfx_new_area(im, im->xorigin, + im->yorigin, + im->xorigin + + im->xsize, im->yorigin, + im->xorigin + + im->xsize, + im->yorigin - im->ysize, im->graph_col[GRC_CANVAS]); gfx_add_point(im, im->xorigin, im->yorigin - im->ysize); gfx_close_path(im); - if (im->minval > 0.0) areazero = im->minval; if (im->maxval < 0.0) areazero = im->maxval; - for (i = 0; i < im->gdes_c; i++) { switch (im->gdes[i].gf) { case GF_CDEF: @@ -3072,24 +3093,25 @@ int graph_paint( break; case GF_TICK: for (ii = 0; ii < im->xsize; ii++) { - if (!isnan(im->gdes[i].p_data[ii]) && - im->gdes[i].p_data[ii] != 0.0) { + if (!isnan(im->gdes[i].p_data[ii]) + && im->gdes[i].p_data[ii] != 0.0) { if (im->gdes[i].yrule > 0) { gfx_line(im, - im->xorigin + ii, im->yorigin, + im->xorigin + ii, + im->yorigin, im->xorigin + ii, im->yorigin - - im->gdes[i].yrule * im->ysize, 1.0, - im->gdes[i].col); + im->gdes[i].yrule * + im->ysize, 1.0, im->gdes[i].col); } else if (im->gdes[i].yrule < 0) { gfx_line(im, im->xorigin + ii, im->yorigin - im->ysize, im->xorigin + ii, im->yorigin - (1 - - im->gdes[i].yrule) * + im->gdes[i]. + yrule) * im->ysize, 1.0, im->gdes[i].col); - } } } @@ -3127,11 +3149,10 @@ int graph_paint( cairo_save(im->cr); cairo_new_path(im->cr); - cairo_set_line_width(im->cr, im->gdes[i].linewidth); - if (im->gdes[i].dash) { - cairo_set_dash(im->cr, im->gdes[i].p_dashes, + cairo_set_dash(im->cr, + im->gdes[i].p_dashes, im->gdes[i].ndash, im->gdes[i].offset); } @@ -3156,9 +3177,8 @@ int graph_paint( cairo_line_to(im->cr, x, y); } else { double x = ii - 1 + im->xorigin; - double y = ytr(im, - im->gdes[i].p_data[ii - 1]); - + double y = + ytr(im, im->gdes[i].p_data[ii - 1]); gfx_line_fit(im, &x, &y); cairo_move_to(im->cr, x, y); x = ii + im->xorigin; @@ -3183,12 +3203,14 @@ int graph_paint( gfx_line_fit(im, &x1, &y1); cairo_line_to(im->cr, x1, y1); }; - } - cairo_set_source_rgba(im->cr, im->gdes[i].col.red, - im->gdes[i].col.green, - im->gdes[i].col.blue, - im->gdes[i].col.alpha); + cairo_set_source_rgba(im->cr, + im->gdes[i]. + col.red, + im->gdes[i]. + col.green, + im->gdes[i]. + col.blue, im->gdes[i].col.alpha); cairo_set_line_cap(im->cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(im->cr, CAIRO_LINE_JOIN_ROUND); cairo_stroke(im->cr); @@ -3213,29 +3235,36 @@ int graph_paint( int lastI = 0; while (cntI < idxI - && AlmostEqual2sComplement(foreY[lastI], - foreY[cntI], 4) - && AlmostEqual2sComplement(foreY[lastI], - foreY[cntI + 1], - 4)) { + && + AlmostEqual2sComplement(foreY + [lastI], + foreY[cntI], 4) + && + AlmostEqual2sComplement(foreY + [lastI], + foreY + [cntI + 1], 4)) { cntI++; } gfx_new_area(im, backX[0], backY[0], foreX[0], foreY[0], - foreX[cntI], foreY[cntI], - im->gdes[i].col); + foreX[cntI], + foreY[cntI], im->gdes[i].col); while (cntI < idxI) { lastI = cntI; cntI++; while (cntI < idxI && - AlmostEqual2sComplement(foreY[lastI], + AlmostEqual2sComplement(foreY + [lastI], foreY[cntI], 4) && - AlmostEqual2sComplement(foreY[lastI], - foreY[cntI + - 1], 4)) { + AlmostEqual2sComplement(foreY + [lastI], + foreY + [cntI + + 1], 4)) { cntI++; } gfx_add_point(im, foreX[cntI], foreY[cntI]); @@ -3246,12 +3275,15 @@ int graph_paint( idxI--; while (idxI > 1 && - AlmostEqual2sComplement(backY[lastI], + AlmostEqual2sComplement(backY + [lastI], backY[idxI], 4) && - AlmostEqual2sComplement(backY[lastI], - backY[idxI - - 1], 4)) { + AlmostEqual2sComplement(backY + [lastI], + backY + [idxI + - 1], 4)) { idxI--; } gfx_add_point(im, backX[idxI], backY[idxI]); @@ -3266,7 +3298,6 @@ int graph_paint( } if (ii == im->xsize) break; - if (im->slopemode == 0 && ii == 0) { continue; } @@ -3327,18 +3358,14 @@ int graph_paint( ("STACK should already be turned into LINE or AREA here"); return -1; break; - } /* switch */ } /* grid_paint also does the text */ if (!(im->extra_flags & ONLY_GRAPH)) grid_paint(im); - - if (!(im->extra_flags & ONLY_GRAPH)) axis_paint(im); - /* the RULES are the last thing to paint ... */ for (i = 0; i < im->gdes_c; i++) { @@ -3348,14 +3375,14 @@ int graph_paint( && im->gdes[i].yrule <= im->maxval) { cairo_save(im->cr); if (im->gdes[i].dash) { - cairo_set_dash(im->cr, im->gdes[i].p_dashes, + cairo_set_dash(im->cr, + im->gdes[i].p_dashes, im->gdes[i].ndash, im->gdes[i].offset); } - gfx_line(im, - im->xorigin, ytr(im, im->gdes[i].yrule), - im->xorigin + im->xsize, ytr(im, - im->gdes[i].yrule), - 1.0, im->gdes[i].col); + gfx_line(im, im->xorigin, + ytr(im, im->gdes[i].yrule), + im->xorigin + im->xsize, + ytr(im, im->gdes[i].yrule), 1.0, im->gdes[i].col); cairo_stroke(im->cr); cairo_restore(im->cr); } @@ -3365,12 +3392,16 @@ int graph_paint( && im->gdes[i].xrule <= im->end) { cairo_save(im->cr); if (im->gdes[i].dash) { - cairo_set_dash(im->cr, im->gdes[i].p_dashes, + cairo_set_dash(im->cr, + im->gdes[i].p_dashes, im->gdes[i].ndash, im->gdes[i].offset); } gfx_line(im, - xtr(im, im->gdes[i].xrule), im->yorigin, xtr(im, im->gdes[i].xrule), + im->yorigin, xtr(im, + im-> + gdes[i]. + xrule), im->yorigin - im->ysize, 1.0, im->gdes[i].col); cairo_stroke(im->cr); cairo_restore(im->cr); @@ -3387,18 +3418,10 @@ int graph_paint( { cairo_status_t status; - if (strlen(im->graphfile) == 0) { - status = - cairo_surface_write_to_png_stream(im->surface, - &cairo_copy_to_buffer, im); - } else if (strcmp(im->graphfile, "-") == 0) { - status = - cairo_surface_write_to_png_stream(im->surface, - &cairo_write_func_filehandle, - (void *) stdout); - } else { - status = cairo_surface_write_to_png(im->surface, im->graphfile); - } + status = strlen(im->graphfile) ? + cairo_surface_write_to_png(im->surface, im->graphfile) + : cairo_surface_write_to_png_stream(im->surface, &cairo_output, + im); if (status != CAIRO_STATUS_SUCCESS) { rrd_set_error("Could not save png to '%s'", im->graphfile); @@ -3414,6 +3437,7 @@ int graph_paint( } break; } + return 0; } @@ -3427,9 +3451,9 @@ int gdes_alloc( { im->gdes_c++; - if ((im->gdes = (graph_desc_t *) rrd_realloc(im->gdes, (im->gdes_c) - * sizeof(graph_desc_t))) == - NULL) { + if ((im->gdes = (graph_desc_t *) + rrd_realloc(im->gdes, (im->gdes_c) + * sizeof(graph_desc_t))) == NULL) { rrd_set_error("realloc graph_descs"); return -1; } @@ -3481,9 +3505,9 @@ int scan_for_col( int inp, outp = 0; for (inp = 0; inp < len && input[inp] != ':' && input[inp] != '\0'; inp++) { - if (input[inp] == '\\' && - input[inp + 1] != '\0' && - (input[inp + 1] == '\\' || input[inp + 1] == ':')) { + if (input[inp] == '\\' + && input[inp + 1] != '\0' + && (input[inp + 1] == '\\' || input[inp + 1] == ':')) { output[outp++] = input[++inp]; } else { output[outp++] = input[inp]; @@ -3493,12 +3517,7 @@ int scan_for_col( return inp; } -/* Some surgery done on this function, it became ridiculously big. -** Things moved: -** - initializing now in rrd_graph_init() -** - options parsing now in rrd_graph_options() -** - script parsing now in rrd_graph_script() -*/ +/* Now just a wrapper around rrd_graph_v */ int rrd_graph( int argc, char **argv, @@ -3509,144 +3528,155 @@ int rrd_graph( double *ymin, double *ymax) { - image_desc_t im; + int prlines = 0; + info_t *grinfo = NULL; + info_t *walker; + + grinfo = rrd_graph_v(argc, argv); + if (grinfo == NULL) + return -1; + walker = grinfo; + (*prdata) = NULL; + while (walker) { + if (strcmp(walker->key, "image_info") == 0) { + prlines++; + if (((*prdata) = + rrd_realloc((*prdata), + (prlines + 1) * sizeof(char *))) == NULL) { + rrd_set_error("realloc prdata"); + return 0; + } + /* imginfo goes to position 0 in the prdata array */ + (*prdata)[prlines - 1] = malloc((strlen(walker->value.u_str) + + 2) * sizeof(char)); + strcpy((*prdata)[prlines - 1], walker->value.u_str); + (*prdata)[prlines] = NULL; + } + /* skip anything else */ + walker = walker->next; + } + walker = grinfo; + while (walker) { + if (strcmp(walker->key, "image_width") == 0) { + *xsize = walker->value.u_int; + } else if (strcmp(walker->key, "image_height") == 0) { + *ysize = walker->value.u_int; + } else if (strcmp(walker->key, "value_min") == 0) { + *ymin = walker->value.u_val; + } else if (strcmp(walker->key, "value_max") == 0) { + *ymax = walker->value.u_val; + } else if (strncmp(walker->key, "print", 6) == 0) { /* keys are prdate[0..] */ + prlines++; + if (((*prdata) = + rrd_realloc((*prdata), + (prlines + 1) * sizeof(char *))) == NULL) { + rrd_set_error("realloc prdata"); + return 0; + } + (*prdata)[prlines - 1] = malloc((strlen(walker->value.u_str) + + 2) * sizeof(char)); + (*prdata)[prlines] = NULL; + strcpy((*prdata)[prlines - 1], walker->value.u_str); + } else if (strcmp(walker->key, "image") == 0) { + fwrite(walker->value.u_blo.ptr, walker->value.u_blo.size, 1, (stream ? stream : stdout)); + } + /* skip anything else */ + walker = walker->next; + } + info_free(grinfo); + return 0; +} - rrd_graph_init(&im); +/* Some surgery done on this function, it became ridiculously big. +** Things moved: +** - initializing now in rrd_graph_init() +** - options parsing now in rrd_graph_options() +** - script parsing now in rrd_graph_script() +*/ +info_t * rrd_graph_v( + int argc, + char **argv) +{ + image_desc_t im; + info_t *grinfo; + rrd_graph_init(&im); /* a dummy surface so that we can measure text sizes for placements */ im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); im.cr = cairo_create(im.surface); - im.graphhandle = stream; - rrd_graph_options(argc, argv, &im); if (rrd_test_error()) { + info_free(im.grinfo); im_free(&im); - return -1; + return NULL; } if (optind >= argc) { + info_free(im.grinfo); + im_free(&im); rrd_set_error("missing filename"); - return -1; + return NULL; } if (strlen(argv[optind]) >= MAXPATH) { rrd_set_error("filename (including path) too long"); + info_free(im.grinfo); im_free(&im); - return -1; + return NULL; } strncpy(im.graphfile, argv[optind], MAXPATH - 1); im.graphfile[MAXPATH - 1] = '\0'; + if (strcmp(im.graphfile, "-") == 0) { + im.graphfile[0] = '\0'; + } + rrd_graph_script(argc, argv, &im, 1); if (rrd_test_error()) { + info_free(im.grinfo); im_free(&im); - return -1; + return NULL; } /* Everything is now read and the actual work can start */ - (*prdata) = NULL; - if (graph_paint(&im, prdata) == -1) { + if (graph_paint(&im) == -1) { + info_free(im.grinfo); im_free(&im); - return -1; + return NULL; } + /* The image is generated and needs to be output. ** Also, if needed, print a line with information about the image. */ - *xsize = im.ximg; - *ysize = im.yimg; - *ymin = im.minval; - *ymax = im.maxval; if (im.imginfo) { - char *filename; - - if (!(*prdata)) { - /* maybe prdata is not allocated yet ... lets do it now */ - if ((*prdata = calloc(2, sizeof(char *))) == NULL) { - rrd_set_error("malloc imginfo"); - return -1; - }; - } - if (((*prdata)[0] = - malloc((strlen(im.imginfo) + 200 + - strlen(im.graphfile)) * sizeof(char))) - == NULL) { - rrd_set_error("malloc imginfo"); - return -1; - } - filename = im.graphfile + strlen(im.graphfile); - while (filename > im.graphfile) { - if (*(filename - 1) == '/' || *(filename - 1) == '\\') - break; - filename--; - } - - sprintf((*prdata)[0], im.imginfo, filename, - (long) (im.zoom * im.ximg), (long) (im.zoom * im.yimg)); + infoval info; + + info.u_str = + sprintf_alloc(im.imginfo, + im.graphfile, + (long) (im.zoom * + im.ximg), (long) (im.zoom * im.yimg)); + grinfo_push(&im, sprintf_alloc("image_info"), RD_I_STR, info); + free(info.u_str); } - im_free(&im); - return 0; -} - -/* a simplified version of the above that just creates the graph in memory - and returns a pointer to it. */ - -unsigned char *rrd_graph_in_memory( - int argc, - char **argv, - char ***prdata, - int *xsize, - int *ysize, - double *ymin, - double *ymax, - size_t * img_size) -{ - image_desc_t im; - - rrd_graph_init(&im); - - /* a dummy surface so that we can measure text sizes for placements */ - im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); - im.cr = cairo_create(im.surface); - - rrd_graph_options(argc, argv, &im); - if (rrd_test_error()) { - im_free(&im); - return NULL; - } - - rrd_graph_script(argc, argv, &im, 1); - if (rrd_test_error()) { - im_free(&im); - return NULL; + if (im.rendered_image) { + infoval img; + img.u_blo.size = im.rendered_image_size; + img.u_blo.ptr = im.rendered_image; + grinfo_push(&im, sprintf_alloc("image"), RD_I_BLO, img); } - - /* Everything is now read and the actual work can start */ - - /* by not assigning a name to im.graphfile data will be written to - newly allocated memory on im.rendered_image ... */ - - (*prdata) = NULL; - if (graph_paint(&im, prdata) == -1) { - im_free(&im); - return NULL; - } - - *xsize = im.ximg; - *ysize = im.yimg; - *ymin = im.minval; - *ymax = im.maxval; - *img_size = im.rendered_image_size; + grinfo = im.grinfo; im_free(&im); - - return im.rendered_image; + return grinfo; } void rrd_graph_init( - image_desc_t *im) + image_desc_t + *im) { unsigned int i; @@ -3659,62 +3689,59 @@ void rrd_graph_init( setlocale(LC_CTYPE, ""); #endif #endif - im->yorigin = 0; - im->xorigin = 0; + im->base = 1000; + im->cr = NULL; + im->draw_x_grid = 1; + im->draw_y_grid = 1; + im->extra_flags = 0; + im->font_options = cairo_font_options_create(); + im->forceleftspace = 0; + im->gdes_c = 0; + im->gdes = NULL; + im->graph_antialias = CAIRO_ANTIALIAS_GRAY; + im->grid_dash_off = 1; + im->grid_dash_on = 1; + im->gridfit = 1; + im->grinfo = (info_t *) NULL; + im->grinfo_current = (info_t *) NULL; + im->imgformat = IF_PNG; + im->imginfo = NULL; + im->lazy = 0; + im->logarithmic = 0; + im->maxval = DNAN; im->minval = 0; - im->xlab_user.minsec = -1; - im->ximg = 0; - im->yimg = 0; - im->xsize = 400; - im->ysize = 100; + im->minval = DNAN; + im->prt_c = 0; + im->rigid = 0; im->rendered_image_size = 0; im->rendered_image = NULL; + im->slopemode = 0; im->step = 0; - im->ylegend[0] = '\0'; + im->surface = NULL; + im->symbol = ' '; + im->tabwidth = 40.0; im->title[0] = '\0'; - im->watermark[0] = '\0'; - im->minval = DNAN; - im->maxval = DNAN; im->unitsexponent = 9999; im->unitslength = 6; - im->forceleftspace = 0; - im->symbol = ' '; im->viewfactor = 1.0; - im->imgformat = IF_PNG; - im->graphfile[0] = '\0'; - im->cr = NULL; - im->surface = NULL; - im->extra_flags = 0; - im->rigid = 0; - im->gridfit = 1; - im->imginfo = NULL; - im->lazy = 0; - im->slopemode = 0; - im->logarithmic = 0; + im->watermark[0] = '\0'; + im->ximg = 0; + im->xlab_user.minsec = -1; + im->xorigin = 0; + im->xsize = 400; im->ygridstep = DNAN; - im->draw_x_grid = 1; - im->draw_y_grid = 1; - im->base = 1000; - im->prt_c = 0; - im->gdes_c = 0; - im->gdes = NULL; - im->grid_dash_on = 1; - im->grid_dash_off = 1; - im->tabwidth = 40.0; + im->yimg = 0; + im->ylegend[0] = '\0'; + im->yorigin = 0; + im->ysize = 100; im->zoom = 1; - im->font_options = cairo_font_options_create(); - im->graph_antialias = CAIRO_ANTIALIAS_GRAY; - - cairo_font_options_set_hint_style(im->font_options, - CAIRO_HINT_STYLE_FULL); - cairo_font_options_set_hint_metrics(im->font_options, - CAIRO_HINT_METRICS_ON); + cairo_font_options_set_hint_style + (im->font_options, CAIRO_HINT_STYLE_FULL); + cairo_font_options_set_hint_metrics + (im->font_options, CAIRO_HINT_METRICS_ON); cairo_font_options_set_antialias(im->font_options, CAIRO_ANTIALIAS_GRAY); - - for (i = 0; i < DIM(graph_col); i++) im->graph_col[i] = graph_col[i]; - #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) { char *windir; @@ -3728,8 +3755,8 @@ void rrd_graph_init( strcat(rrd_win_default_font, "\\fonts\\"); strcat(rrd_win_default_font, RRD_DEFAULT_FONT); for (i = 0; i < DIM(text_prop); i++) { - strncpy(text_prop[i].font, rrd_win_default_font, - sizeof(text_prop[i].font) - 1); + strncpy(text_prop[i].font, + rrd_win_default_font, sizeof(text_prop[i].font) - 1); text_prop[i].font[sizeof(text_prop[i].font) - 1] = '\0'; } } @@ -3756,7 +3783,8 @@ void rrd_graph_init( void rrd_graph_options( int argc, char *argv[], - image_desc_t *im) + image_desc_t + *im) { int stroff; char *parsetime_error = NULL; @@ -3771,68 +3799,136 @@ void rrd_graph_options( and may not collide with (the ASCII value of) short options */ #define LONGOPT_UNITS_SI 255 struct option long_options[] = { - {"start", required_argument, 0, 's'}, - {"end", required_argument, 0, 'e'}, - {"x-grid", required_argument, 0, 'x'}, - {"y-grid", required_argument, 0, 'y'}, - {"vertical-label", required_argument, 0, 'v'}, - {"width", required_argument, 0, 'w'}, - {"height", required_argument, 0, 'h'}, - {"full-size-mode", no_argument, 0, 'D'}, - {"interlaced", no_argument, 0, 'i'}, - {"upper-limit", required_argument, 0, 'u'}, - {"lower-limit", required_argument, 0, 'l'}, - {"rigid", no_argument, 0, 'r'}, - {"base", required_argument, 0, 'b'}, - {"logarithmic", no_argument, 0, 'o'}, - {"color", required_argument, 0, 'c'}, - {"font", required_argument, 0, 'n'}, - {"title", required_argument, 0, 't'}, - {"imginfo", required_argument, 0, 'f'}, - {"imgformat", required_argument, 0, 'a'}, - {"lazy", no_argument, 0, 'z'}, - {"zoom", required_argument, 0, 'm'}, - {"no-legend", no_argument, 0, 'g'}, - {"force-rules-legend", no_argument, 0, 'F'}, - {"only-graph", no_argument, 0, 'j'}, - {"alt-y-grid", no_argument, 0, 'Y'}, - {"no-minor", no_argument, 0, 'I'}, - {"slope-mode", no_argument, 0, 'E'}, - {"alt-autoscale", no_argument, 0, 'A'}, - {"alt-autoscale-min", no_argument, 0, 'J'}, - {"alt-autoscale-max", no_argument, 0, 'M'}, - {"no-gridfit", no_argument, 0, 'N'}, - {"units-exponent", required_argument, 0, 'X'}, - {"units-length", required_argument, 0, 'L'}, - {"units", required_argument, 0, LONGOPT_UNITS_SI}, - {"step", required_argument, 0, 'S'}, - {"tabwidth", required_argument, 0, 'T'}, - {"font-render-mode", required_argument, 0, 'R'}, - {"graph-render-mode", required_argument, 0, 'G'}, - {"font-smoothing-threshold", required_argument, 0, 'B'}, - {"watermark", required_argument, 0, 'W'}, - {"alt-y-mrtg", no_argument, 0, 1000}, /* this has no effect it is just here to save old apps from crashing when they use it */ - {0, 0, 0, 0} + { + "start", required_argument, 0, 's'}, { + "end", required_argument, 0, + 'e'}, { + "x-grid", + required_argument, 0, + 'x'}, { + "y-grid", + required_argument, + 0, 'y'}, { + "vertical-label", + required_argument, + 0, + 'v'}, { + "width", + required_argument, + 0, + 'w'}, + { + "height", required_argument, 0, 'h'}, { + "full-size-mode", no_argument, + 0, 'D'}, { + "interlaced", + no_argument, 0, + 'i'}, { + "upper-limit", + required_argument, + 0, + 'u'}, { + "lower-limit", + required_argument, + 0, + 'l'}, { + "rigid", + no_argument, + 0, + 'r'}, + { + "base", required_argument, 0, 'b'}, { + "logarithmic", no_argument, 0, + 'o'}, { + "color", + required_argument, 0, + 'c'}, { + "font", + required_argument, + 0, 'n'}, { + "title", + required_argument, + 0, 't'}, + { + "imginfo", required_argument, 0, 'f'}, { + "imgformat", + required_argument, 0, 'a'}, { + "lazy", + no_argument, + 0, + 'z'}, + { + "zoom", required_argument, 0, 'm'}, { + "no-legend", no_argument, 0, + 'g'}, { + "force-rules-legend", + no_argument, + 0, 'F'}, { + "only-graph", + no_argument, 0, + 'j'}, { + "alt-y-grid", + no_argument, + 0, 'Y'}, + { + "no-minor", no_argument, 0, 'I'}, { + "slope-mode", no_argument, 0, + 'E'}, { + "alt-autoscale", + no_argument, 0, 'A'}, { + "alt-autoscale-min", + no_argument, + 0, + 'J'}, { + "alt-autoscale-max", + no_argument, + 0, + 'M'}, { + "no-gridfit", + no_argument, + 0, + 'N'}, + { + "units-exponent", required_argument, + 0, 'X'}, { + "units-length", required_argument, + 0, 'L'}, { + "units", required_argument, 0, + LONGOPT_UNITS_SI}, { + "step", required_argument, 0, + 'S'}, { + "tabwidth", + required_argument, 0, + 'T'}, { + "font-render-mode", + required_argument, + 0, 'R'}, { + "graph-render-mode", + required_argument, + 0, + 'G'}, + { + "font-smoothing-threshold", + required_argument, 0, 'B'}, { + "watermark", required_argument, 0, 'W'}, { + "alt-y-mrtg", no_argument, 0, 1000}, /* this has no effect it is just here to save old apps from crashing when they use it */ + { + 0, 0, 0, 0} }; - optind = 0; opterr = 0; /* initialize getopt */ - parsetime("end-24h", &start_tv); parsetime("now", &end_tv); - while (1) { int option_index = 0; int opt; int col_start, col_end; opt = getopt_long(argc, argv, - "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:", + "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:k", long_options, &option_index); - if (opt == EOF) break; - switch (opt) { case 'I': im->extra_flags |= NOMINOR; @@ -3908,7 +4004,6 @@ void rrd_graph_options( im->draw_x_grid = 0; break; }; - if (sscanf(optarg, "%10[A-Z]:%ld:%10[A-Z]:%ld:%10[A-Z]:%ld:%ld:%n", scan_gtm, @@ -3921,15 +4016,17 @@ void rrd_graph_options( strncpy(im->xlab_form, optarg + stroff, sizeof(im->xlab_form) - 1); im->xlab_form[sizeof(im->xlab_form) - 1] = '\0'; - if ((int) (im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1) { + if ((int) + (im->xlab_user.gridtm = tmt_conv(scan_gtm)) == -1) { rrd_set_error("unknown keyword %s", scan_gtm); return; - } else if ((int) (im->xlab_user.mgridtm = tmt_conv(scan_mtm)) + } else if ((int) + (im->xlab_user.mgridtm = tmt_conv(scan_mtm)) == -1) { rrd_set_error("unknown keyword %s", scan_mtm); return; - } else if ((int) (im->xlab_user.labtm = tmt_conv(scan_ltm)) == - -1) { + } else if ((int) + (im->xlab_user.labtm = tmt_conv(scan_ltm)) == -1) { rrd_set_error("unknown keyword %s", scan_ltm); return; } @@ -4013,7 +4110,8 @@ void rrd_graph_options( im->imginfo = optarg; break; case 'a': - if ((int) (im->imgformat = if_conv(optarg)) == -1) { + if ((int) + (im->imgformat = if_conv(optarg)) == -1) { rrd_set_error("unsupported graphics format '%s'", optarg); return; } @@ -4024,7 +4122,6 @@ void rrd_graph_options( case 'E': im->slopemode = 1; break; - case 'o': im->logarithmic = 1; break; @@ -4037,15 +4134,21 @@ void rrd_graph_options( switch (col_len) { case 3: - color = (((color & 0xF00) * 0x110000) | - ((color & 0x0F0) * 0x011000) | - ((color & 0x00F) * 0x001100) | 0x000000FF); + color = + (((color & 0xF00) * 0x110000) | ((color & 0x0F0) * + 0x011000) | + ((color & 0x00F) + * 0x001100) + | 0x000000FF); break; case 4: - color = (((color & 0xF000) * 0x11000) | - ((color & 0x0F00) * 0x01100) | - ((color & 0x00F0) * 0x00110) | - ((color & 0x000F) * 0x00011) + color = + (((color & 0xF000) * + 0x11000) | ((color & 0x0F00) * + 0x01100) | ((color & + 0x00F0) * + 0x00110) | + ((color & 0x000F) * 0x00011) ); break; case 6: @@ -4079,8 +4182,8 @@ void rrd_graph_options( setlocale(LC_NUMERIC, old_locale); if ((sindex = text_prop_conv(prop)) != -1) { - for (propidx = sindex; propidx < TEXT_PROP_LAST; - propidx++) { + for (propidx = sindex; + propidx < TEXT_PROP_LAST; propidx++) { if (size > 0) { im->text_prop[propidx].size = size; } @@ -4123,23 +4226,22 @@ void rrd_graph_options( strncpy(im->title, optarg, 150); im->title[150] = '\0'; break; - case 'R': if (strcmp(optarg, "normal") == 0) { - cairo_font_options_set_antialias(im->font_options, - CAIRO_ANTIALIAS_GRAY); - cairo_font_options_set_hint_style(im->font_options, - CAIRO_HINT_STYLE_FULL); + cairo_font_options_set_antialias + (im->font_options, CAIRO_ANTIALIAS_GRAY); + cairo_font_options_set_hint_style + (im->font_options, CAIRO_HINT_STYLE_FULL); } else if (strcmp(optarg, "light") == 0) { - cairo_font_options_set_antialias(im->font_options, - CAIRO_ANTIALIAS_GRAY); - cairo_font_options_set_hint_style(im->font_options, - CAIRO_HINT_STYLE_SLIGHT); + cairo_font_options_set_antialias + (im->font_options, CAIRO_ANTIALIAS_GRAY); + cairo_font_options_set_hint_style + (im->font_options, CAIRO_HINT_STYLE_SLIGHT); } else if (strcmp(optarg, "mono") == 0) { - cairo_font_options_set_antialias(im->font_options, - CAIRO_ANTIALIAS_NONE); - cairo_font_options_set_hint_style(im->font_options, - CAIRO_HINT_STYLE_FULL); + cairo_font_options_set_antialias + (im->font_options, CAIRO_ANTIALIAS_NONE); + cairo_font_options_set_hint_style + (im->font_options, CAIRO_HINT_STYLE_FULL); } else { rrd_set_error("unknown font-render-mode '%s'", optarg); return; @@ -4158,12 +4260,10 @@ void rrd_graph_options( case 'B': /* not supported curently */ break; - case 'W': strncpy(im->watermark, optarg, 100); im->watermark[99] = '\0'; break; - case '?': if (optopt != 0) rrd_set_error("unknown option '%c'", optopt); @@ -4185,14 +4285,15 @@ void rrd_graph_options( } if (start_tmp < 3600 * 24 * 365 * 10) { - rrd_set_error("the first entry to fetch should be after 1980 (%ld)", - start_tmp); + rrd_set_error + ("the first entry to fetch should be after 1980 (%ld)", + start_tmp); return; } if (end_tmp < start_tmp) { - rrd_set_error("start (%ld) should be less than end (%ld)", - start_tmp, end_tmp); + rrd_set_error + ("start (%ld) should be less than end (%ld)", start_tmp, end_tmp); return; } @@ -4202,7 +4303,8 @@ void rrd_graph_options( } int rrd_graph_color( - image_desc_t *im, + image_desc_t + *im, char *var, char *err, int optional) @@ -4227,7 +4329,6 @@ int rrd_graph_color( n = rest - color; else n = strlen(color); - switch (n) { case 7: sscanf(color, "#%6lx%n", &col, &n); @@ -4263,11 +4364,9 @@ int bad_format( /* line cannot end with percent char */ if (*ptr == '\0') return 1; - /* '%s', '%S' and '%%' are allowed */ if (*ptr == 's' || *ptr == 'S' || *ptr == '%') ptr++; - /* %c is allowed (but use only with vdef!) */ else if (*ptr == 'c') { ptr++; @@ -4279,7 +4378,6 @@ int bad_format( /* optional padding character */ if (*ptr == ' ' || *ptr == '+' || *ptr == '-') ptr++; - /* This should take care of 'm.n' with all three optional */ while (*ptr >= '0' && *ptr <= '9') ptr++; @@ -4287,7 +4385,6 @@ int bad_format( ptr++; while (*ptr >= '0' && *ptr <= '9') ptr++; - /* Either 'le', 'lf' or 'lg' must follow here */ if (*ptr++ != 'l') return 1; @@ -4304,7 +4401,8 @@ int bad_format( int vdef_parse( - struct graph_desc_t *gdes, + struct graph_desc_t + *gdes, const char *const str) { /* A VDEF currently is either "func" or "param,func" @@ -4327,8 +4425,9 @@ int vdef_parse( if (n == (int) strlen(str)) { /* matched */ param = DNAN; } else { - rrd_set_error("Unknown function string '%s' in VDEF '%s'", str, - gdes->vname); + rrd_set_error + ("Unknown function string '%s' in VDEF '%s'", + str, gdes->vname); return -1; } } @@ -4355,16 +4454,16 @@ int vdef_parse( else if (!strcmp("LSLCORREL", func)) gdes->vf.op = VDEF_LSLCORREL; else { - rrd_set_error("Unknown function '%s' in VDEF '%s'\n", func, - gdes->vname); + rrd_set_error + ("Unknown function '%s' in VDEF '%s'\n", func, gdes->vname); return -1; }; - switch (gdes->vf.op) { case VDEF_PERCENT: if (isnan(param)) { /* no parameter given */ - rrd_set_error("Function '%s' needs parameter in VDEF '%s'\n", - func, gdes->vname); + rrd_set_error + ("Function '%s' needs parameter in VDEF '%s'\n", + func, gdes->vname); return -1; }; if (param >= 0.0 && param <= 100.0) { @@ -4372,8 +4471,9 @@ int vdef_parse( gdes->vf.val = DNAN; /* undefined */ gdes->vf.when = 0; /* undefined */ } else { - rrd_set_error("Parameter '%f' out of range in VDEF '%s'\n", param, - gdes->vname); + rrd_set_error + ("Parameter '%f' out of range in VDEF '%s'\n", + param, gdes->vname); return -1; }; break; @@ -4392,8 +4492,9 @@ int vdef_parse( gdes->vf.val = DNAN; gdes->vf.when = 0; } else { - rrd_set_error("Function '%s' needs no parameter in VDEF '%s'\n", - func, gdes->vname); + rrd_set_error + ("Function '%s' needs no parameter in VDEF '%s'\n", + func, gdes->vname); return -1; }; break; @@ -4414,18 +4515,15 @@ int vdef_calc( src = &im->gdes[dst->vidx]; data = src->data + src->ds; steps = (src->end - src->start) / src->step; - #if 0 - printf("DEBUG: start == %lu, end == %lu, %lu steps\n", src->start, - src->end, steps); + printf + ("DEBUG: start == %lu, end == %lu, %lu steps\n", + src->start, src->end, steps); #endif - switch (dst->vf.op) { case VDEF_PERCENT:{ rrd_value_t *array; int field; - - if ((array = malloc(steps * sizeof(double))) == NULL) { rrd_set_error("malloc VDEV_PERCENT"); return -1; @@ -4434,15 +4532,14 @@ int vdef_calc( array[step] = data[step * src->ds_cnt]; } qsort(array, step, sizeof(double), vdef_percent_compar); - field = (steps - 1) * dst->vf.param / 100; dst->vf.val = array[field]; dst->vf.when = 0; /* no time component */ free(array); #if 0 for (step = 0; step < steps; step++) - printf("DEBUG: %3li:%10.2f %c\n", step, array[step], - step == field ? '*' : ' '); + printf("DEBUG: %3li:%10.2f %c\n", + step, array[step], step == field ? '*' : ' '); #endif } break; @@ -4570,7 +4667,6 @@ int vdef_calc( SUMxy = 0; SUMxx = 0; SUMyy = 0; - for (step = 0; step < steps; step++) { if (finite(data[step * src->ds_cnt])) { cnt++; @@ -4586,12 +4682,9 @@ int vdef_calc( y_intercept = (SUMy - slope * SUMx) / cnt; correl = (SUMxy - - (SUMx * SUMy) / cnt) / sqrt((SUMxx - - (SUMx * SUMx) / cnt) * (SUMyy - - (SUMy * - SUMy) / - cnt)); - + (SUMx * SUMy) / cnt) / + sqrt((SUMxx - + (SUMx * SUMx) / cnt) * (SUMyy - (SUMy * SUMy) / cnt)); if (cnt) { if (dst->vf.op == VDEF_LSLSLOPE) { dst->vf.val = slope; @@ -4603,7 +4696,6 @@ int vdef_calc( dst->vf.val = correl; dst->vf.when = 0; }; - } else { dst->vf.val = DNAN; dst->vf.when = 0; @@ -4616,8 +4708,10 @@ int vdef_calc( /* NaN < -INF < finite_values < INF */ int vdef_percent_compar( - const void *a, - const void *b) + const void + *a, + const void + *b) { /* Equality is not returned; this doesn't hurt except * (maybe) for a little performance. @@ -4628,7 +4722,6 @@ int vdef_percent_compar( return -1; if (isnan(*(double *) b)) return 1; - /* NaN doesn't reach this part so INF and -INF are extremes. * The sign from isinf() is compatible with the sign we return */ @@ -4636,10 +4729,21 @@ int vdef_percent_compar( return isinf(*(double *) a); if (isinf(*(double *) b)) return isinf(*(double *) b); - /* If we reach this, both values must be finite */ if (*(double *) a < *(double *) b) return -1; else return 1; } + +void grinfo_push( + image_desc_t *im, + char *key, + enum info_type type, + infoval value) +{ + im->grinfo_current = info_push(im->grinfo_current, key, type, value); + if (im->grinfo == NULL) { + im->grinfo = im->grinfo_current; + } +} diff --git a/src/rrd_graph.h b/src/rrd_graph.h index 51f3d3f..3e65df1 100644 --- a/src/rrd_graph.h +++ b/src/rrd_graph.h @@ -186,7 +186,6 @@ typedef struct image_desc_t { /* configuration of graph */ char graphfile[MAXPATH]; /* filename for graphic */ - FILE *graphhandle; /* FILE to use if filename is "-" */ long xsize, ysize; /* graph area size in pixels */ struct gfx_color_t graph_col[__GRC_END__]; /* real colors for the graph */ text_prop_t text_prop[TEXT_PROP_LAST]; /* text properties */ @@ -218,6 +217,8 @@ typedef struct image_desc_t { existing one is out of date */ int slopemode; /* connect the dots of the curve directly, not using a stair */ int logarithmic; /* scale the yaxis logarithmic */ + double force_scale_min; /* Force a scale--min */ + double force_scale_max; /* Force a scale--max */ /* status information */ @@ -244,6 +245,9 @@ typedef struct image_desc_t { cairo_t *cr; /* drawin context */ cairo_font_options_t *font_options; /* cairo font options */ cairo_antialias_t graph_antialias; /* antialiasing for the graph */ + + info_t *grinfo; /* root pointer to extra graph info */ + info_t *grinfo_current; /* pointing to current entry */ } image_desc_t; /* Prototypes */ @@ -307,8 +311,7 @@ time_t find_next_time( enum tmt_en, long); int print_calc( - image_desc_t *, - char ***); + image_desc_t *); int leg_place( image_desc_t *, int *); @@ -327,8 +330,7 @@ void grid_paint( int lazy_check( image_desc_t *); int graph_paint( - image_desc_t *, - char ***); + image_desc_t *); int gdes_alloc( image_desc_t *); @@ -336,15 +338,6 @@ int scan_for_col( const char *const, int, char *const); -int rrd_graph( - int, - char **, - char ***, - int *, - int *, - FILE *, - double *, - double *); void rrd_graph_init( image_desc_t *); void rrd_graph_options( @@ -374,8 +367,7 @@ int vdef_percent_compar( const void *); int graph_size_location( image_desc_t *, - int - ); + int); /* create a new line */ @@ -460,3 +452,9 @@ void gfx_area_fit( double *y); #endif + +void grinfo_push( + image_desc_t *im, + char *key, + enum info_type type, + infoval value); diff --git a/src/rrd_info.c b/src/rrd_info.c index ff3e35b..f9c4604 100644 --- a/src/rrd_info.c +++ b/src/rrd_info.c @@ -71,6 +71,11 @@ info_t next->value.u_str = malloc(sizeof(char) * (strlen(value.u_str) + 1)); strcpy(next->value.u_str, value.u_str); break; + case RD_I_BLO: + next->value.u_blo.size = value.u_blo.size; + next->value.u_blo.ptr = malloc(sizeof(unsigned char)*value.u_blo.size); + memcpy(next->value.u_blo.ptr,value.u_blo.ptr,value.u_blo.size); + break; } return (next); } @@ -323,3 +328,58 @@ info_t *rrd_info_r( rrd_free(&rrd); return (data); } + + +void info_print( + info_t *data) +{ + long image_length = 0; + + while (data) { + printf("%s = ", data->key); + + switch (data->type) { + case RD_I_VAL: + if (isnan(data->value.u_val)) + printf("NaN\n"); + else + printf("%0.10e\n", data->value.u_val); + break; + case RD_I_CNT: + printf("%lu\n", data->value.u_cnt); + break; + case RD_I_INT: + printf("%d\n", data->value.u_int); + break; + case RD_I_STR: + printf("\"%s\"\n", data->value.u_str); + break; + case RD_I_BLO: + printf("BLOB_SIZE:%lu\n", data->value.u_blo.size); + fwrite(data->value.u_blo.ptr, data->value.u_blo.size, 1, stdout); + break; + } + data = data->next; + } +} + +void info_free( + info_t *data) +{ + info_t *save; + + while (data) { + save = data; + if (data->key) { + if (data->type == RD_I_STR) { + free(data->value.u_str); + } + if (data->type == RD_I_BLO) { + free(data->value.u_blo.ptr); + } + free(data->key); + } + data = data->next; + free(save); + } +} diff --git a/src/rrd_tool.c b/src/rrd_tool.c index b5d856d..b16a194 100644 --- a/src/rrd_tool.c +++ b/src/rrd_tool.c @@ -52,9 +52,10 @@ void PrintUsage( "Usage: rrdtool [options] command command_options\n\n"); const char *help_list = - N_("Valid commands: create, update, updatev, graph, dump, restore,\n" - "\t\tlast, lastupdate, first, info, fetch, tune,\n" - "\t\tresize, xport\n\n"); + N_ + ("Valid commands: create, update, updatev, graph, graphv, dump, restore,\n" + "\t\tlast, lastupdate, first, info, fetch, tune,\n" + "\t\tresize, xport\n\n"); const char *help_listremote = N_("Valid remote commands: quit, ls, cd, mkdir, pwd\n\n"); @@ -116,10 +117,15 @@ void PrintUsage( /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/ - const char *help_graph1 = + const char *help_graph0 = N_("* graph - generate a graph from one or several RRD\n\n" - "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n" - "\t\t[-x|--x-grid x-axis grid and label]\n" + "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"); + const char *help_graphv0 = + N_("* graphv - generate a graph from one or several RRD\n" + " with meta data printed before the graph\n\n" + "\trrdtool graphv filename [-s|--start seconds] [-e|--end seconds]\n"); + const char *help_graph1 = + N_("\t\t[-x|--x-grid x-axis grid and label]\n" "\t\t[-Y|--alt-y-grid]\n" "\t\t[-y|--y-grid y-axis grid and label]\n" "\t\t[-v|--vertical-label string] [-w|--width pixels]\n" @@ -148,8 +154,9 @@ void PrintUsage( const char *help_graph3 = N_("\t\t[CDEF:vname=rpn-expression]\n" "\t\t[VDEF:vdefname=rpn-expression]\n" - "\t\t[PRINT:vdefname:format]\n" "\t\t[GPRINT:vdefname:format]\n" - "\t\t[COMMENT:text]\n" "\t\t[SHIFT:vname:offset]\n" + "\t\t[PRINT:vdefname:format]\n" + "\t\t[GPRINT:vdefname:format]\n" "\t\t[COMMENT:text]\n" + "\t\t[SHIFT:vname:offset]\n" "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n" "\t\t[HRULE:value#rrggbb[aa][:legend]]\n" "\t\t[VRULE:value#rrggbb[aa][:legend]]\n" @@ -158,7 +165,6 @@ void PrintUsage( "\t\t[PRINT:vname:CF:format] (deprecated)\n" "\t\t[GPRINT:vname:CF:format] (deprecated)\n" "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n"); - const char *help_tune1 = N_(" * tune - Modify some basic properties of an RRD\n\n" "\trrdtool tune filename\n" @@ -176,52 +182,42 @@ void PrintUsage( "\t\t[--gamma adaptation-parameter]\n" "\t\t[--gamma-deviation adaptation-parameter]\n" "\t\t[--aberrant-reset ds-name]\n\n"); - const char *help_resize = - N_(" * resize - alter the length of one of the RRAs in an RRD\n\n" - "\trrdtool resize filename rranum GROW|SHRINK rows\n\n"); - + N_ + (" * resize - alter the length of one of the RRAs in an RRD\n\n" + "\trrdtool resize filename rranum GROW|SHRINK rows\n\n"); const char *help_xport = N_("* xport - generate XML dump from one or several RRD\n\n" "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n" - "\t\t[-m|--maxrows rows]\n" - "\t\t[--step seconds]\n" - "\t\t[--enumds]\n" - "\t\t[DEF:vname=rrd:ds-name:CF]\n" + "\t\t[-m|--maxrows rows]\n" "\t\t[--step seconds]\n" + "\t\t[--enumds]\n" "\t\t[DEF:vname=rrd:ds-name:CF]\n" "\t\t[CDEF:vname=rpn-expression]\n" "\t\t[XPORT:vname:legend]\n\n"); - const char *help_quit = N_(" * quit - closing a session in remote mode\n\n" "\trrdtool quit\n\n"); - const char *help_ls = N_(" * ls - lists all *.rrd files in current directory\n\n" "\trrdtool ls\n\n"); - const char *help_cd = N_(" * cd - changes the current directory\n\n" "\trrdtool cd new directory\n\n"); - const char *help_mkdir = N_(" * mkdir - creates a new directory\n\n" "\trrdtool mkdir newdirectoryname\n\n"); - const char *help_pwd = N_(" * pwd - returns the current working directory\n\n" "\trrdtool pwd\n\n"); - const char *help_lic = N_("RRDtool is distributed under the Terms of the GNU General\n" "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n" "For more information read the RRD manpages\n\n"); - enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, - C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, + C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_GRAPHV, + C_TUNE, C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD, C_UPDATEV }; - int help_cmd = C_NONE; if (cmd) { @@ -247,6 +243,8 @@ void PrintUsage( help_cmd = C_FETCH; else if (!strcmp(cmd, "graph")) help_cmd = C_GRAPH; + else if (!strcmp(cmd, "graphv")) + help_cmd = C_GRAPHV; else if (!strcmp(cmd, "tune")) help_cmd = C_TUNE; else if (!strcmp(cmd, "resize")) @@ -304,9 +302,16 @@ void PrintUsage( fputs(_(help_fetch), stdout); break; case C_GRAPH: + fputs(_(help_graph0), stdout); + fputs(_(help_graph1), stdout); + fputs(_(help_graph2), stdout); + fputs(_(help_graph3), stdout); + break; + case C_GRAPHV: + fputs(_(help_graphv0), stdout); fputs(_(help_graph1), stdout); - fputs(help_graph2, stdout); - fputs(help_graph3, stdout); + fputs(_(help_graph2), stdout); + fputs(_(help_graph3), stdout); break; case C_TUNE: fputs(_(help_tune1), stdout); @@ -469,7 +474,6 @@ int main( / 1000000.0); #else printf("OK\n"); - #endif } } @@ -507,7 +511,6 @@ int HandleInputLine( /* Reset errno to 0 before we start. */ errno = 0; - if (RemoteMode) { if (argc > 1 && strcmp("quit", argv[1]) == 0) { if (argc > 2) { @@ -616,40 +619,15 @@ int HandleInputLine( else if (strcmp("dump", argv[1]) == 0) rrd_dump(argc - 1, &argv[1]); else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) { - info_t *data, *save; + info_t *data; if (strcmp("info", argv[1]) == 0) + data = rrd_info(argc - 1, &argv[1]); else data = rrd_update_v(argc - 1, &argv[1]); - while (data) { - save = data; - printf("%s = ", data->key); - free(data->key); - - switch (data->type) { - case RD_I_VAL: - if (isnan(data->value.u_val)) - printf("NaN"); - else - printf("%0.10e", data->value.u_val); - break; - case RD_I_CNT: - printf("%lu", data->value.u_cnt); - break; - case RD_I_INT: - printf("%d", data->value.u_int); - break; - case RD_I_STR: - printf("\"%s\"", data->value.u_str); - free(data->value.u_str); - break; - } - data = data->next; - free(save); - printf("\n"); - } - free(data); + info_print(data); + info_free(data); } else if (strcmp("--version", argv[1]) == 0 || @@ -657,7 +635,7 @@ int HandleInputLine( strcmp("v", argv[1]) == 0 || strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0) printf("RRDtool " PACKAGE_VERSION - " Copyright by Tobi Oetiker, 1997-2005 (%f)\n", + " Copyright by Tobi Oetiker, 1997-2008 (%f)\n", rrd_version()); else if (strcmp("restore", argv[1]) == 0) rrd_restore(argc - 1, &argv[1]); @@ -770,10 +748,10 @@ int HandleInputLine( rrd_value_t newval = DNAN; if (enumds == 1) + snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j); else snprintf(vtag, vtag_s, "%s", COL_DATA_TAG); - newval = *ptr; if (isnan(newval)) { printf("<%s>NaN", vtag, vtag); @@ -823,6 +801,13 @@ int HandleInputLine( } } + } else if (strcmp("graphv", argv[1]) == 0) { + info_t *grinfo = NULL; /* 1 to distinguish it from the NULL that rrd_graph sends in */ + if (grinfo = rrd_graph_v(argc - 1, &argv[1])) { + info_print(grinfo); + info_free(grinfo); + } + } else if (strcmp("tune", argv[1]) == 0) rrd_tune(argc - 1, &argv[1]); else { @@ -882,7 +867,6 @@ int CreateArgs( /* sikp leading blanks */ while (*aLine && *aLine <= ' ') aLine++; - pargv[0] = pName; argc = 1; getP = aLine; @@ -925,7 +909,6 @@ int CreateArgs( } *putP = '\0'; - if (Quote) return -1; else diff --git a/src/rrd_tool.h b/src/rrd_tool.h index 70aa326..802e6d9 100644 --- a/src/rrd_tool.h +++ b/src/rrd_tool.h @@ -63,27 +63,6 @@ extern "C" { #define DIM(x) (sizeof(x)/sizeof(x[0])) -/* rrd info interface */ - enum info_type { RD_I_VAL = 0, - RD_I_CNT, - RD_I_STR, - RD_I_INT - }; - - typedef union infoval { - unsigned long u_cnt; - rrd_value_t u_val; - char *u_str; - int u_int; - } infoval; - - typedef struct info_t { - char *key; - enum info_type type; - union infoval value; - struct info_t *next; - } info_t; - info_t *rrd_info( int, char **); @@ -105,6 +84,10 @@ extern "C" { char *, enum info_type, infoval); + void info_print( + info_t *data); + void info_free( + info_t *); /* HELPER FUNCTIONS */ -- 2.11.0