summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 6a4c9f4)
raw | patch | inline | side by side (parent: 6a4c9f4)
author | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Sun, 20 Apr 2008 22:46:39 +0000 (22:46 +0000) | ||
committer | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Sun, 20 Apr 2008 22:46:39 +0000 (22:46 +0000) |
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
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
12 files changed:
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 00468507272a90bf019a0a4cb35471264186bac0..3a33ebe377e2d1d107ef50ed8c750bfac4e0165c 100644 (file)
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
Jost.Krieger <Jost.Krieger with ruhr-uni-bochum.de>
Kai Siering <kai.siering with mediaways.net>
Larry Leszczynski <larryl with furph.com>
+Mark Plaksin <happy@usg.edu> rrd_graph_v
Matt Chambers <matthew.chambers with vanderbilt.edu> --full-size-mode for rrdgraph
McCreary mccreary with xoanon.colorado.edu
Mike Mitchell <mcm with unx.sas.com>
index 32ff16e7bd3d22b6c42ef8f76ce82e9a7fd28c26..e7b29b26a190be4506429a266954e19b2d3cb1ee 100644 (file)
--- a/NEWS
+++ b/NEWS
* 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
index 3e77a2a373d055f6ac1d3a911de86df12bb2c146..757e5ceb4951053247aff070417a2397588c67f7 100644 (file)
print "$key = $$hash{$key}\n";
}
+B<RRDs::graphv> takes the same paramters as B<RRDs::graph> 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<RRDs::updatev> 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
index f84efef67419f876f2c0ff0035eefee0176801cd..5eeba18444e55609674100e660ae4b780ad35d55 100644 (file)
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; \
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 ff747f7013e4b40d777a4d3af2245a281209106d..e5a3e80052d4397a12db1d18ac284560b48573b3 100644 (file)
--- a/bindings/ruby/main.c
+++ b/bindings/ruby/main.c
rrd_clear_error();
}
+/* Simple Calls */
+
VALUE rrd_call(
RRDFUNC func,
VALUE args)
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)
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,
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(
)
{
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 6c7c3305cf7bd9cc0bd9a6076db91eb47943b6af..54fd5b0cbae83ada1ff137f7b4a9ca90c6e20418 100644 (file)
--- a/doc/rrdgraph.pod
+++ b/doc/rrdgraph.pod
=head1 SYNOPSIS
-B<rrdtool graph> I<filename>
+B<rrdtool graph|graphv> I<filename>
[I<L<option|rrdgraph/OPTIONS>> ...]
[I<L<data definition|rrdgraph_data/DEF>> ...]
[I<L<data calculation|rrdgraph_data/CDEF>> ...]
=over 4
+=item B<graphv>
+
+This alternate version of B<graph> takes the same arguments and performs the
+same function. The I<v> stands for I<verbose>, which describes the output
+returned. B<graphv> 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<rrdgraph> gives an overview of how B<rrdtool graph> works.
diff --git a/src/rrd.h b/src/rrd.h
index 978ad1c1b17d2e8a3100037e07d5af2a715f7dd0..3e1a08ad333a7e692eec5f5c6dd827962a899eb7 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
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,
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 0e847869a70984e401520abb293916b46530f5c5..0f84b8085bfe3b4fdc736c1b88b6cb9800a50871 100644 (file)
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
#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[] = {
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)
/* 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;
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
}
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;
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;
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') {
/* 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;
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_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;
}
int calc_horizontal_grid(
- image_desc_t *im)
+ image_desc_t
+ *im)
{
double range;
double scaledrange;
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)) {
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 */
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++) {
}
int draw_horizontal_grid(
- image_desc_t *im)
+ image_desc_t
+ *im)
{
int i;
double scaledstep;
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. */
&& (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) {
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) {
}
}
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);
-
}
}
}
/* 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 */
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)
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
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) {
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;
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
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) {
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);
}
}
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);
}
}
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);
}
}
/* 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 */
/* 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)
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)
) {
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);
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);
-
}
}
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(
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);
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);
}
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 &&
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);
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);
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
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
** 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;
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;
}
}
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.
}
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
** 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}
** 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;
}
/* 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 =
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:
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);
-
}
}
}
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);
}
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;
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);
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]);
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]);
}
if (ii == im->xsize)
break;
-
if (im->slopemode == 0 && ii == 0) {
continue;
}
("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++) {
&& 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);
}
&& 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);
{
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);
}
break;
}
+
return 0;
}
{
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;
}
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];
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,
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;
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;
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';
}
}
void rrd_graph_options(
int argc,
char *argv[],
- image_desc_t *im)
+ image_desc_t
+ *im)
{
int stroff;
char *parsetime_error = NULL;
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;
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,
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;
}
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;
}
case 'E':
im->slopemode = 1;
break;
-
case 'o':
im->logarithmic = 1;
break;
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:
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;
}
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;
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);
}
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;
}
}
int rrd_graph_color(
- image_desc_t *im,
+ image_desc_t
+ *im,
char *var,
char *err,
int optional)
n = rest - color;
else
n = strlen(color);
-
switch (n) {
case 7:
sscanf(color, "#%6lx%n", &col, &n);
/* 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++;
/* 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++;
ptr++;
while (*ptr >= '0' && *ptr <= '9')
ptr++;
-
/* Either 'le', 'lf' or 'lg' must follow here */
if (*ptr++ != 'l')
return 1;
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"
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;
}
}
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) {
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;
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;
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;
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;
SUMxy = 0;
SUMxx = 0;
SUMyy = 0;
-
for (step = 0; step < steps; step++) {
if (finite(data[step * src->ds_cnt])) {
cnt++;
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;
dst->vf.val = correl;
dst->vf.when = 0;
};
-
} else {
dst->vf.val = DNAN;
dst->vf.when = 0;
/* 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.
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
*/
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 51f3d3fbae49860ff27c82e0e8e7976174ace330..3e65df10e7e2ad47d5478b6edfdf357dd518ff86 100644 (file)
--- a/src/rrd_graph.h
+++ b/src/rrd_graph.h
/* 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 */
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 */
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 */
enum tmt_en,
long);
int print_calc(
- image_desc_t *,
- char ***);
+ image_desc_t *);
int leg_place(
image_desc_t *,
int *);
int lazy_check(
image_desc_t *);
int graph_paint(
- image_desc_t *,
- char ***);
+ image_desc_t *);
int gdes_alloc(
image_desc_t *);
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(
const void *);
int graph_size_location(
image_desc_t *,
- int
- );
+ int);
/* create a new line */
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 ff3e35be452e704a55a2fc954feb037a877b7a4f..f9c4604274ab80325c679512e30b04f7f619c2e1 100644 (file)
--- a/src/rrd_info.c
+++ b/src/rrd_info.c
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);
}
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 b5d856d3fca154c6a4ad6504abb983206e0e1019..b16a1942a585ac5b95bbccdcda5da9481c4bd6fb 100644 (file)
--- a/src/rrd_tool.c
+++ b/src/rrd_tool.c
"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");
/* 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"
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"
"\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"
"\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) {
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"))
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);
/ 1000000.0);
#else
printf("OK\n");
-
#endif
}
}
/* Reset errno to 0 before we start.
*/
errno = 0;
-
if (RemoteMode) {
if (argc > 1 && strcmp("quit", argv[1]) == 0) {
if (argc > 2) {
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 ||
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]);
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</%s>", vtag, vtag);
}
}
+ } 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 {
/* sikp leading blanks */
while (*aLine && *aLine <= ' ')
aLine++;
-
pargv[0] = pName;
argc = 1;
getP = aLine;
}
*putP = '\0';
-
if (Quote)
return -1;
else
diff --git a/src/rrd_tool.h b/src/rrd_tool.h
index 70aa3268975ac8f596c1029de0d8b618a0e849a3..802e6d9214395f6a77ef566c552c7fa5ae2079ee 100644 (file)
--- a/src/rrd_tool.h
+++ b/src/rrd_tool.h
#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 **);
char *,
enum info_type,
infoval);
+ void info_print(
+ info_t *data);
+ void info_free(
+ info_t *);
/* HELPER FUNCTIONS */