summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: da83a20)
raw | patch | inline | side by side (parent: da83a20)
author | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Tue, 24 Aug 2004 05:26:09 +0000 (05:26 +0000) | ||
committer | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Tue, 24 Aug 2004 05:26:09 +0000 (05:26 +0000) |
they do. This included removal of redundant code in the
rrd_xport path, replaced with a call to rrd_graph_script().
-- David M. Grimes <dgrimes@navisite.com>
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@290 a5681a0c-68f1-0310-ab6d-d61299d08faa
rrd_xport path, replaced with a call to rrd_graph_script().
-- David M. Grimes <dgrimes@navisite.com>
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@290 a5681a0c-68f1-0310-ab6d-d61299d08faa
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 9254b18d12c018cc8ea440769eb2b811820977ed..b924d24e5358799c59b43f7facd29b1d14bf9c2f 100644 (file)
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
David L. Barker <dave@ncomtech.com> xport function bug fixes
Mike Slifcak <slif@bellsouth.net> many rrdtool-1.1.x fixes
Peter Speck <speck@vitality.dk> eps/svg/pdf file format code in rrdtool-1.x
-
+ David Grimes <dgrimes@navisite.com> SQRT/SORT/REV/SHIFT
Documentation
diff --git a/doc/rrdgraph_rpn.src b/doc/rrdgraph_rpn.src
index b765f9abc8ee86802b3f5c7835e75ccfbbe957bd..ae1a91b80b62eaaaf374c8def1e336681c634619 100644 (file)
--- a/doc/rrdgraph_rpn.src
+++ b/doc/rrdgraph_rpn.src
Add, subtract, multiply, divide, modulo
-B<SIN, COS, LOG, EXP>
+B<SIN, COS, LOG, EXP, SQRT>
-Sine, cosine (input in radians), log, exp (natural logarithm)
+Sine, cosine (input in radians), log, exp (natural logarithm), square root
B<ATAN>
Z<>
+=item Ordering Operations
+
+B<SORT, REV>
+
+Pop one element from the stack. This is the I<count> of items to be sorted
+(or reversed). The top I<count> of the remaining elements are then sorted
+(or reversed) in place on the stack.
+
+Example: C<CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/> will
+compute the average of the values v1..v6 after removing the smallest and
+largest.
+
=item Special values
B<UNKN>
diff --git a/src/rrd_graph.c b/src/rrd_graph.c
index 6d9195490c8c8bef2796e23eb16c59504d6e147d..438b3e1f1eeda741544db44fc9aca46b931c48c8 100644 (file)
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
conv_if(VDEF,GF_VDEF)
conv_if(PART,GF_PART)
conv_if(XPORT,GF_XPORT)
+ conv_if(SHIFT,GF_SHIFT)
return (-1);
}
switch (im->gdes[gdi].gf) {
case GF_XPORT:
break;
+ case GF_SHIFT: {
+ graph_desc_t *vdp = &im->gdes[im->gdes[gdi].vidx];
+
+ /* remove current shift */
+ vdp->start -= vdp->shift;
+ vdp->end -= vdp->shift;
+
+ /* vdef */
+ if (im->gdes[gdi].shidx >= 0)
+ vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val;
+ /* constant */
+ else
+ vdp->shift = im->gdes[gdi].shval;
+
+ /* normalize shift to multiple of consolidated step */
+ vdp->shift = (vdp->shift / vdp->step) * vdp->step;
+
+ /* apply shift */
+ vdp->start += vdp->shift;
+ vdp->end += vdp->shift;
+ break;
+ }
case GF_VDEF:
/* A VDEF has no DS. This also signals other parts
* of rrdtool that this is a VDEF value, not a CDEF.
for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE ||
im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){
- long ptr = im->gdes[gdi].rpnp[rpi].ptr;
- if(im->gdes[gdi].start > im->gdes[ptr].start) {
- im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt
- * ((im->gdes[gdi].start - im->gdes[ptr].start) / im->gdes[ptr].step);
- }
+ long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+ long diff = im->gdes[gdi].start - im->gdes[ptr].start;
+
+ if(diff > 0)
+ im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt;
}
}
-
if(steparray == NULL){
rrd_set_error("rpn expressions without DEF"
** the time of the graph. Beware.
*/
vidx = im->gdes[ii].vidx;
- if ( ((long int)gr_time >= (long int)im->gdes[vidx].start) &&
- ((long int)gr_time <= (long int)im->gdes[vidx].end) ) {
+ if (im->gdes[vidx].gf == GF_VDEF) {
+ value = im->gdes[vidx].vf.val;
+ } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) &&
+ ((long int)gr_time <= (long int)im->gdes[vidx].end) ) {
value = im->gdes[vidx].data[
(unsigned long) floor(
(double)(gr_time - im->gdes[vidx].start)
case GF_CDEF:
case GF_VDEF:
case GF_PART:
+ case GF_SHIFT:
case GF_XPORT:
break;
}
case GF_HRULE:
case GF_VRULE:
case GF_XPORT:
+ case GF_SHIFT:
break;
case GF_TICK:
for (ii = 0; ii < im->xsize; ii++)
im->gdes[im->gdes_c-1].data_first=0;
im->gdes[im->gdes_c-1].p_data=NULL;
im->gdes[im->gdes_c-1].rpnp=NULL;
+ im->gdes[im->gdes_c-1].shift=0;
im->gdes[im->gdes_c-1].col = 0x0;
im->gdes[im->gdes_c-1].legend[0]='\0';
im->gdes[im->gdes_c-1].rrd[0]='\0';
@@ -2631,7 +2658,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *s
strncpy(im.graphfile,argv[optind],MAXPATH-1);
im.graphfile[MAXPATH-1]='\0';
- rrd_graph_script(argc,argv,&im);
+ rrd_graph_script(argc,argv,&im,1);
if (rrd_test_error()) {
im_free(&im);
return -1;
{"lazy", no_argument, 0, 'z'},
{"zoom", required_argument, 0, 'm'},
{"no-legend", no_argument, 0, 'g'},
- {"only-graph", no_argument, 0, 'j'},
+ {"only-graph", no_argument, 0, 'j'},
{"alt-y-grid", no_argument, 0, 'Y'},
{"no-minor", no_argument, 0, 'I'},
{"alt-autoscale", no_argument, 0, 'A'},
diff --git a/src/rrd_graph.h b/src/rrd_graph.h
index 13f7160e9d3101317fa97dbae2217bf4f996758f..607ab70c21622e7e66b172ea45da9dd6550f4bb7 100644 (file)
--- a/src/rrd_graph.h
+++ b/src/rrd_graph.h
enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE,
GF_AREA,GF_STACK,GF_TICK,
- GF_DEF, GF_CDEF, GF_VDEF,
+ GF_DEF, GF_CDEF, GF_VDEF, GF_SHIFT,
GF_PART, GF_XPORT};
enum vdef_op_en {
vdef_t vf; /* instruction for VDEF function */
rpnp_t *rpnp; /* instructions for CDEF function */
+ /* SHIFT implementation */
+ int shidx; /* gdes reference for offset (-1 --> constant) */
+ time_t shval; /* offset if shidx is -1 */
+ time_t shift; /* current shift applied */
+
/* description of data fetched for the graph element */
time_t start,end; /* timestaps for first and last data element */
unsigned long step; /* time between samples */
int rrd_graph(int, char **, char ***, int *, int *, FILE *);
void rrd_graph_init(image_desc_t *);
void rrd_graph_options(int, char **, image_desc_t *);
-void rrd_graph_script(int, char **, image_desc_t *);
+void rrd_graph_script(int, char **, image_desc_t *, int);
int rrd_graph_check_vname(image_desc_t *, char *, char *);
int rrd_graph_color(image_desc_t *, char *, char *, int);
int rrd_graph_legend(graph_desc_t *, char *);
diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c
index a15c0ed1dec7d1c6491cfadb534906b1bb44d637..c359f7ab2391ebe4c4c1dd8cbb99defc07eb13d4 100644 (file)
--- a/src/rrd_graph_helper.c
+++ b/src/rrd_graph_helper.c
int rrd_parse_color (char *, graph_desc_t *);
int rrd_parse_CF (char *, unsigned int *, graph_desc_t *);
int rrd_parse_print (char *, unsigned int *, graph_desc_t *, image_desc_t *);
+int rrd_parse_shift (char *, unsigned int *, graph_desc_t *, image_desc_t *);
+int rrd_parse_xport (char *, unsigned int *, graph_desc_t *, image_desc_t *);
int rrd_parse_PVHLAST (char *, unsigned int *, graph_desc_t *, image_desc_t *);
int rrd_parse_vname (char *, unsigned int *, graph_desc_t *, image_desc_t *);
int rrd_parse_def (char *, unsigned int *, graph_desc_t *, image_desc_t *);
@@ -161,6 +163,77 @@ rrd_parse_print(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
return 0;
}
+int
+rrd_parse_shift(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+ char *l = strdup(line + *eaten), *p;
+ int rc = 1;
+
+ p = strchr(l, ',');
+ if (p == NULL) {
+ rrd_set_error("Invalid SHIFT syntax");
+ goto out;
+ }
+ *p++ = '\0';
+
+ if ((gdp->vidx=find_var(im,l))<0) {
+ rrd_set_error("Not a valid vname: %s in line %s",l,line);
+ goto out;
+ }
+
+ /* constant will parse; otherwise, must be VDEF reference */
+ if (sscanf(p, "%ld", &gdp->shval) != 1) {
+ graph_desc_t *vdp;
+
+ if ((gdp->shidx=find_var(im, p))<0) {
+ rrd_set_error("invalid offset vname: %s", p);
+ goto out;
+ }
+
+ vdp = &im->gdes[gdp->shidx];
+ if (vdp->gf != GF_VDEF) {
+ rrd_set_error("offset must specify value or VDEF");
+ goto out;
+ }
+ } else {
+ gdp->shidx = -1;
+ }
+
+ *eaten = strlen(line);
+ rc = 0;
+
+ out:
+ free(l);
+ return rc;
+}
+
+int
+rrd_parse_xport(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+ char *l = strdup(line + *eaten), *p;
+ int rc = 1;
+
+ p = strchr(l, ':');
+ if (p != NULL)
+ *p++ = '\0';
+ else
+ p = "";
+
+ if ((gdp->vidx=find_var(im, l))==-1){
+ rrd_set_error("unknown variable '%s'",l);
+ goto out;
+ }
+
+ if (strlen(p) >= FMT_LEG_LEN)
+ *(p + FMT_LEG_LEN) = '\0';
+
+ strcpy(gdp->legend, p);
+ *eaten = strlen(line);
+ rc = 0;
+
+ out:
+ free(l);
+ return rc;
+}
+
/* Parsing of PART, VRULE, HRULE, LINE, AREA, STACK and TICK
** is done in one function. Stacking STACK is silently ignored
** as it is redundant. Stacking PART, VRULE, HRULE or TICK is
@@ -463,10 +536,10 @@ rrd_parse_cdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
}
void
-rrd_graph_script(int argc, char *argv[], image_desc_t *im) {
+rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) {
int i;
- for (i=optind+1;i<argc;i++) {
+ for (i=optind+optno;i<argc;i++) {
graph_desc_t *gdp;
unsigned int eaten=0;
if (rrd_parse_find_gf(argv[i],&eaten,gdp)) return;
switch (gdp->gf) {
-#if 0
- /* future command */
- case GF_SHIFT: vname:value
-#endif
+ case GF_SHIFT: /* vname:value */
+ if (rrd_parse_shift(argv[i],&eaten,gdp,im)) return;
+ break;
case GF_XPORT:
+ if (rrd_parse_xport(argv[i],&eaten,gdp,im)) return;
break;
case GF_PRINT: /* vname:CF:format -or- vname:format */
case GF_GPRINT: /* vname:CF:format -or- vname:format */
diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c
index 94796d183500dbca75886514c7ff9794d3be8bb5..75c24cfa49799873f7f08dc5198ef061d488e95e 100644 (file)
--- a/src/rrd_rpncalc.c
+++ b/src/rrd_rpncalc.c
add_op(OP_LTIME,LTIME)
add_op(OP_TIME,TIME)
add_op(OP_ATAN,ATAN)
+ add_op(OP_SQRT,SQRT)
+ add_op(OP_SORT,SORT)
+ add_op(OP_REV,REV)
#undef add_op
}
match_op(OP_NOW,NOW)
match_op(OP_TIME,TIME)
match_op(OP_ATAN,ATAN)
-
+ match_op(OP_SQRT,SQRT)
+ match_op(OP_SORT,SORT)
+ match_op(OP_REV,REV)
#undef match_op
rpnstack -> dc_stacksize = 0;
}
+static int
+rpn_compare_double(const void *x, const void *y)
+{
+ double diff = *((const double *)x) - *((const double *)y);
+
+ return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+}
+
/* rpn_calc: run the RPN calculator; also performs variable substitution;
* moved and modified from data_calc() originally included in rrd_graph.c
* arguments:
stackunderflow(0);
rpnstack->s[stptr] = isinf(rpnstack->s[stptr]) ? 1.0 : 0.0;
break;
+ case OP_SQRT:
+ stackunderflow(0);
+ rpnstack -> s[stptr] = sqrt(rpnstack -> s[stptr]);
+ break;
+ case OP_SORT:
+ stackunderflow(0);
+ {
+ int spn = (int)rpnstack -> s[stptr--];
+
+ stackunderflow(spn-1);
+ qsort(rpnstack -> s + stptr-spn+1, spn, sizeof(double),
+ rpn_compare_double);
+ }
+ break;
+ case OP_REV:
+ stackunderflow(0);
+ {
+ int spn = (int)rpnstack -> s[stptr--];
+ double *p, *q;
+
+ stackunderflow(spn-1);
+
+ p = rpnstack -> s + stptr-spn+1;
+ q = rpnstack -> s + stptr;
+ while (p < q) {
+ double x = *q;
+
+ *q-- = *p;
+ *p++ = x;
+ }
+ }
+ break;
case OP_END:
break;
}
diff --git a/src/rrd_rpncalc.h b/src/rrd_rpncalc.h
index fe456f231ee1ecfdf3ff37b4fbb7b58772a2a39e..9fd547a4629094c86e4f8bb06fd4eed30784b338 100644 (file)
--- a/src/rrd_rpncalc.h
+++ b/src/rrd_rpncalc.h
OP_DIV,OP_SIN, OP_DUP, OP_EXC, OP_POP,
OP_COS,OP_LOG,OP_EXP,OP_LT,OP_LE,OP_GT,OP_GE,OP_EQ,OP_IF,
OP_MIN,OP_MAX,OP_LIMIT, OP_FLOOR, OP_CEIL,
- OP_UN,OP_END,OP_LTIME,OP_NE,OP_ISINF,OP_PREV_OTHER,OP_COUNT,OP_ATAN};
+ OP_UN,OP_END,OP_LTIME,OP_NE,OP_ISINF,OP_PREV_OTHER,OP_COUNT,
+ OP_ATAN,OP_SQRT,OP_SORT,OP_REV};
typedef struct rpnp_t {
enum op_en op;
diff --git a/src/rrd_xport.c b/src/rrd_xport.c
index cceefe26f636d816ad5bc41228d8c621caabb18f..95bf35b67fb431d6fa259df48c9eb72c99730461 100644 (file)
--- a/src/rrd_xport.c
+++ b/src/rrd_xport.c
{
image_desc_t im;
- int i;
- long long_tmp;
time_t start_tmp=0,end_tmp=0;
- char symname[100];
- long scancount;
struct rrd_time_value start_tv, end_tv;
char *parsetime_error = NULL;
}
break;
case 'm':
- long_tmp = atol(optarg);
- if (long_tmp < 10) {
+ im.xsize = atol(optarg);
+ if (im.xsize < 10) {
rrd_set_error("maxrows below 10 rows");
return -1;
}
- im.xsize = long_tmp;
break;
case '?':
rrd_set_error("unknown option '%c'", optopt);
im.start = start_tmp;
im.end = end_tmp;
- for(i=optind;i<argc;i++){
- int argstart=0;
- int strstart=0;
- char varname[30],*rpnex;
- gdes_alloc(&im);
- if(sscanf(argv[i],"%10[A-Z0-9]:%n",symname,&argstart)==1){
- if((int)(im.gdes[im.gdes_c-1].gf=gf_conv(symname))==-1){
- im_free(&im);
- rrd_set_error("unknown function '%s'",symname);
- return -1;
- }
- } else {
- rrd_set_error("can't parse '%s'",argv[i]);
- im_free(&im);
- return -1;
- }
-
- switch(im.gdes[im.gdes_c-1].gf){
- case GF_CDEF:
- if((rpnex = malloc(strlen(&argv[i][argstart])*sizeof(char)))==NULL){
- rrd_set_error("malloc for CDEF");
- return -1;
- }
- if(sscanf(
- &argv[i][argstart],
- DEF_NAM_FMT "=%[^: ]",
- im.gdes[im.gdes_c-1].vname,
- rpnex) != 2){
- im_free(&im);
- free(rpnex);
- rrd_set_error("can't parse CDEF '%s'",&argv[i][argstart]);
- return -1;
- }
- /* checking for duplicate DEF CDEFS */
- if(find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
- im_free(&im);
- rrd_set_error("duplicate variable '%s'",
- im.gdes[im.gdes_c-1].vname);
- return -1;
- }
- if((im.gdes[im.gdes_c-1].rpnp = rpn_parse(&im,rpnex,&find_var_wrapper))== NULL){
- rrd_set_error("invalid rpn expression '%s'", rpnex);
- im_free(&im);
- return -1;
- }
- free(rpnex);
- break;
- case GF_DEF:
- if (sscanf(
- &argv[i][argstart],
- DEF_NAM_FMT "=%n",
- im.gdes[im.gdes_c-1].vname,
- &strstart)== 1 && strstart){ /* is the = did not match %n returns 0 */
- if(sscanf(&argv[i][argstart
- +strstart
- +scan_for_col(&argv[i][argstart+strstart],
- MAXPATH,im.gdes[im.gdes_c-1].rrd)],
- ":" DS_NAM_FMT ":" CF_NAM_FMT,
- im.gdes[im.gdes_c-1].ds_nam,
- symname) != 2){
- im_free(&im);
- rrd_set_error("can't parse DEF '%s' -2",&argv[i][argstart]);
- return -1;
- }
- } else {
- im_free(&im);
- rrd_set_error("can't parse DEF '%s'",&argv[i][argstart]);
- return -1;
- }
-
- /* checking for duplicate DEF CDEFS */
- if (find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
- im_free(&im);
- rrd_set_error("duplicate variable '%s'",
- im.gdes[im.gdes_c-1].vname);
- return -1;
- }
- if((int)(im.gdes[im.gdes_c-1].cf=cf_conv(symname))==-1){
- im_free(&im);
- rrd_set_error("unknown cf '%s'",symname);
- return -1;
- }
- break;
- case GF_XPORT:
- if((scancount=sscanf(
- &argv[i][argstart],
- "%29[^:]:%n",
- varname,
- &strstart))>=1){
- if(strstart <= 0){
- im.gdes[im.gdes_c-1].legend[0] = '\0';
- } else {
- scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
- }
- if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1){
- im_free(&im);
- rrd_set_error("unknown variable '%s'",varname);
- return -1;
- }
- } else {
- im_free(&im);
- rrd_set_error("can't parse '%s'",&argv[i][argstart]);
- return -1;
- }
- break;
- default:
- break;
- }
-
+ rrd_graph_script(argc,argv,&im,0);
+ if (rrd_test_error()) {
+ im_free(&im);
+ return -1;
}
if (im.gdes_c == 0){