From 56ef285d15d3d069b4c89b13b5acba6901bb16db Mon Sep 17 00:00:00 2001 From: oetiker Date: Tue, 7 May 2002 21:58:33 +0000 Subject: [PATCH] new command rrdtool xport integrated -- Wolfgang Schrimm git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk@135 a5681a0c-68f1-0310-ab6d-d61299d08faa --- program/CONTRIBUTORS | 2 +- program/bindings/perl-shared/RRDs.xs | 63 +++- program/doc/Makefile.am | 2 +- program/doc/rrdtool.pod | 6 +- program/doc/rrdxport.pod | 140 +++++++++ program/examples/shared-demo.pl.in | 43 +++ program/src/Makefile.am | 4 +- program/src/rrd.h | 11 +- program/src/rrd_graph.c | 8 + program/src/rrd_graph.h | 2 +- program/src/rrd_tool.c | 67 ++++- program/src/rrd_xport.c | 425 +++++++++++++++++++++++++++ program/src/rrd_xport.h | 34 +++ 13 files changed, 796 insertions(+), 11 deletions(-) create mode 100644 program/doc/rrdxport.pod create mode 100644 program/src/rrd_xport.c create mode 100644 program/src/rrd_xport.h diff --git a/program/CONTRIBUTORS b/program/CONTRIBUTORS index fd86627f..7e6f1acb 100644 --- a/program/CONTRIBUTORS +++ b/program/CONTRIBUTORS @@ -54,7 +54,7 @@ Debugging and code contributions Bruce Campbell Sean Summers (RPM .spec) Christophe Van Ginneken (--no-legend) - + Wolfgang Schrimm xport function Documentation diff --git a/program/bindings/perl-shared/RRDs.xs b/program/bindings/perl-shared/RRDs.xs index 4d871e90..a0001f79 100644 --- a/program/bindings/perl-shared/RRDs.xs +++ b/program/bindings/perl-shared/RRDs.xs @@ -204,7 +204,7 @@ rrd_fetch(...) /* convert the data array into perl format */ datai=data; retar=newAV(); - for (i = start; i <= end; i += step){ + for (i = start+step; i <= end; i += step){ line = newAV(); for (ii = 0; ii < ds_cnt; ii++){ av_push(line,(isnan(*datai) ? &PL_sv_undef : newSVnv(*datai))); @@ -214,12 +214,71 @@ rrd_fetch(...) } free(data); EXTEND(sp,5); - PUSHs(sv_2mortal(newSViv(start))); + PUSHs(sv_2mortal(newSViv(start+step))); PUSHs(sv_2mortal(newSViv(step))); PUSHs(sv_2mortal(newRV_noinc((SV*)names))); PUSHs(sv_2mortal(newRV_noinc((SV*)retar))); +int +rrd_xport(...) + PROTOTYPE: @ + PREINIT: + time_t start,end; + int xsize; + unsigned long step, col_cnt,row_cnt,i,ii; + rrd_value_t *data,*ptr; + char **argv,**legend_v; + AV *retar,*line,*names; + PPCODE: + argv = (char **) malloc((items+1)*sizeof(char *)); + argv[0] = "dummy"; + for (i = 0; i < items; i++) { + STRLEN len; + char *handle = SvPV(ST(i),len); + /* actually copy the data to make sure possible modifications + on the argv data does not backfire into perl */ + argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); + strcpy(argv[i+1],handle); + } + optind=0; opterr=0; + rrd_clear_error(); + rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); + for (i=0; i < items; i++) { + free(argv[i+1]); + } + free(argv); + if (rrd_test_error()) XSRETURN_UNDEF; + + /* convert the legend_v into perl format */ + names=newAV(); + for (ii = 0; ii < col_cnt; ii++){ + av_push(names,newSVpv(legend_v[ii],0)); + free(legend_v[ii]); + } + free(legend_v); + + /* convert the data array into perl format */ + ptr=data; + retar=newAV(); + for (i = start+step; i <= end; i += step){ + line = newAV(); + for (ii = 0; ii < col_cnt; ii++){ + av_push(line,(isnan(*ptr) ? &PL_sv_undef : newSVnv(*ptr))); + ptr++; + } + av_push(retar,newRV_noinc((SV*)line)); + } + free(data); + + EXTEND(sp,7); + PUSHs(sv_2mortal(newSViv(start+step))); + PUSHs(sv_2mortal(newSViv(end))); + PUSHs(sv_2mortal(newSViv(step))); + PUSHs(sv_2mortal(newSViv(col_cnt))); + PUSHs(sv_2mortal(newRV_noinc((SV*)names))); + PUSHs(sv_2mortal(newRV_noinc((SV*)retar))); + SV* rrd_info(...) PROTOTYPE: @ diff --git a/program/doc/Makefile.am b/program/doc/Makefile.am index 824fad97..3022e64b 100644 --- a/program/doc/Makefile.am +++ b/program/doc/Makefile.am @@ -14,7 +14,7 @@ SRC = rrdgraph.src rrdgraph_examples.src rrdgraph_rpn.src \ POD = rrdtool.pod rrdlast.pod rrdcreate.pod rrdupdate.pod rrdtutorial.es.pod \ cdeftutorial.pod rpntutorial.pod rrdgraph-old.pod bin_dec_hex.pod \ rrdfetch.pod rrdrestore.pod rrddump.pod rrdtune.pod rrdresize.pod \ - rrdcgi.pod rrdtutorial.pod rrdinfo.pod $(SRC:.src=.pod) + rrdxport.pod rrdcgi.pod rrdtutorial.pod rrdinfo.pod $(SRC:.src=.pod) PMP = RRDs.pm RRDp.pm diff --git a/program/doc/rrdtool.pod b/program/doc/rrdtool.pod index fee6d356..72335922 100644 --- a/program/doc/rrdtool.pod +++ b/program/doc/rrdtool.pod @@ -82,6 +82,10 @@ Find last update time of an RRD. Check L. Change the size of individual RRAs ... Dangerous! Check L. +=item B + +Export data retrieved from one or several RRD. Check L + =item B This is a standalone tool for producing rrd graphs on the fly. Check @@ -245,7 +249,7 @@ will not abort if possible, but follow the ERROR line with an OK line. =head1 SEE ALSO -rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast +rrdcreate, rrdupdate, rrdgraph, rrddump, rrdfetch, rrdtune, rrdlast, rrdxport =head1 BUGS diff --git a/program/doc/rrdxport.pod b/program/doc/rrdxport.pod new file mode 100644 index 00000000..fcaaa0dd --- /dev/null +++ b/program/doc/rrdxport.pod @@ -0,0 +1,140 @@ +=head1 NAME + +rrdtool xport - Export data in XML format based on data from one or several RRD + +=for html
PDF version.
+ +=head1 SYNOPSIS + +B B +S<[B<-s>|B<--start> I]> +S<[B<-e>|B<--end> I]> +S<[B<-m>|B<--maxrows> I]> +S<[B<--step> I]> +S<[BIB<=>IB<:>IB<:>I]> +S<[BIB<=>I]> +S<[BB<:>I[B<:>I]]> + +=head1 DESCRIPTION + +The B functions main purpose is to write XML formatted +representation of the data stored in one or several Bs. It +can also extract numerical reports. + +If no I statements are found, there will be no output. + +=over + +=item B<-s>|B<--start> I (default end-1day) + +The time when the exported range should begin. Time in seconds since +epoch (1970-01-01) is required. Negative numbers are relative to the +current time. By default one day worth of data will be printed. +See also AT-STYLE TIME SPECIFICATION section in the I +documentation for a detailed explanation on how to specify time. + +=item B<-e>|B<--end> I (default now) + +The time when the exported range should end. Time in seconds since epoch. +See also AT-STYLE TIME SPECIFICATION section in the I +documentation for a detailed explanation of ways to specify time. + +=item B<-m>|B<--maxrows> I (default 400 rows) + +This works like the B<-w>|B<--width> parameter of I. +In fact it is exactly the same, but the parameter was renamed to +describe its purpose in this module. See I documentation +for details. + +=item B<--step> I (default automatic) + +See I documentation. + +=item BIB<=>IB<:>IB<:>I + +See I documentation. + +=item BIB<=>I + +See I documentation. + +=item BIB<:>B<:>I + +At least one I statement should be present. The values +referenced by I are printed. Optionally add a legend. + +=over + +=head1 Output format + +The output is enclosed in a B element and contains two +blocks. The first block is enclosed by a B element and +contains some meta data. The second block is enclosed by a +B element and contains the data rows. + +Let's assume that the I command looks like this: + + rrdtool xport \ + --start now-1h --end now \ + DEF:xx=host-inout.lo.rrd:output:AVERAGE \ + DEF:yy=host-inout.lo.rrd:input:AVERAGE \ + CDEF:aa=xx,yy,+,8,* \ + XPORT:xx:"out bytes" \ + XPORT:aa:"in and out bits" + +The resulting meta data section (the values will depend on the +RRD characteristics): + + + 1020611700 + 300 + 1020615600 + 14 + 2 + + out bytes + in and out bits + + + +The resulting data section: + + + 10206117003.4000000000e+005.4400000000e+01 + 10206120003.4000000000e+005.4400000000e+01 + 10206123003.4000000000e+005.4400000000e+01 + 10206126003.4113333333e+005.4581333333e+01 + 10206129003.4000000000e+005.4400000000e+01 + 10206132003.4000000000e+005.4400000000e+01 + 10206135003.4000000000e+005.4400000000e+01 + 10206138003.4000000000e+005.4400000000e+01 + 10206141003.4000000000e+005.4400000000e+01 + 10206144003.4000000000e+005.4400000000e+01 + 10206147003.7333333333e+005.9733333333e+01 + 10206150003.4000000000e+005.4400000000e+01 + 10206153003.4000000000e+005.4400000000e+01 + 1020615600NaNNaN + + + +=head1 EXAMPLE 1 + + rrdtool xport \ + DEF:out=if1-inouts.rrd:outoctets:AVERAGE \ + XPORT:out:"out bytes" + +=head1 EXAMPLE 2 + + rrdtool xport \ + DEF:out1=if1-inouts.rrd:outoctets:AVERAGE \ + DEF:out2=if2-inouts.rrd:outoctets:AVERAGE \ + CDEF:sum=out1,out2,+ \ + XPORT:out1:"if1 out bytes" \ + XPORT:out2:"if2 out bytes" \ + XPORT:sum:"output sum" + + +=head1 AUTHOR + +Tobias Oetiker Eoetiker@ee.ethz.chE + diff --git a/program/examples/shared-demo.pl.in b/program/examples/shared-demo.pl.in index 61df2052..596fb062 100755 --- a/program/examples/shared-demo.pl.in +++ b/program/examples/shared-demo.pl.in @@ -173,3 +173,46 @@ foreach my $line (@$array){ +my ($start,$end,$step,$col_cnt,$legend,$data) = + RRDs::xport ("-m", 400, + "--start", "now-1day", + "--end", "now", + "DEF:alpha=$RRD1:a:AVERAGE", + "DEF:beta=$RRD1:d:AVERAGE", + "CDEF:calc=alpha,beta,+,2,/,100,*,102,/", + "XPORT:alpha:original ds", + "XPORT:calc:calculated values", + ); + +my $ERROR = RRDs::error; +die "$0: unable to xport: $ERROR\n" if $ERROR; + +print "\nrrdxport test:\n\n"; +print "\n\n"; +print "\n"; +print " \n"; +print " $start\n"; +print " $step\n"; +print " $end\n"; +print " ", $#$data + 1, "\n"; +print " $col_cnt\n"; +print " \n"; +foreach my $entry (@$legend) { + print " $entry\n"; +} +print " \n"; +print " \n"; +print " \n"; +my $row_counter = 0; +foreach my $row (@$data) { + $row_counter++; + print " $start"; + $start += $step; + foreach my $val (@$row) { + printf ("%1.10e",$val) if $val ne ''; + print "NaN" if $val eq ''; + } + print "\n"; +} +print " \n"; +print "\n"; diff --git a/program/src/Makefile.am b/program/src/Makefile.am index 5f8d27ab..9e64c24b 100644 --- a/program/src/Makefile.am +++ b/program/src/Makefile.am @@ -62,9 +62,11 @@ RRD_C_FILES = \ rrd_rpncalc.c \ rrd_tune.c \ rrd_update.c \ + rrd_xport.c \ rrd_gfx.c rrd_gfx.h \ rrd_afm.c rrd_afm_data.c \ - getopt.h ntconfig.h parsetime.h rrd_format.h rrd_tool.h rrd.h rrd_hw.h rrd_rpncalc.h + getopt.h ntconfig.h parsetime.h \ + rrd_format.h rrd_tool.h rrd_xport.h rrd.h rrd_hw.h rrd_rpncalc.h # Build two libraries. One is a public one that gets installed in # $prefix/lib. Libtool does not create an archive of the PIC compiled diff --git a/program/src/rrd.h b/program/src/rrd.h index a327a1ba..8172c7f5 100644 --- a/program/src/rrd.h +++ b/program/src/rrd.h @@ -5,8 +5,12 @@ ***************************************************************************** * $Id$ * $Log$ - * Revision 1.1 2001/02/25 22:25:05 oetiker - * Initial revision + * Revision 1.2 2002/05/07 21:58:32 oetiker + * new command rrdtool xport integrated + * -- Wolfgang Schrimm + * + * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker + * checkin * *****************************************************************************/ #ifdef __cplusplus @@ -34,6 +38,9 @@ int rrd_dump(int, char **); int rrd_tune(int, char **); time_t rrd_last(int, char **); int rrd_resize(int, char **); +int rrd_xport(int, char **, int *, time_t *, time_t *, + unsigned long *, unsigned long *, + char ***, rrd_value_t **); /* Transplanted from parsetime.h */ typedef enum { diff --git a/program/src/rrd_graph.c b/program/src/rrd_graph.c index 17ec03a7..a73dbbc6 100644 --- a/program/src/rrd_graph.c +++ b/program/src/rrd_graph.c @@ -186,6 +186,7 @@ enum gf_en gf_conv(char *string){ conv_if(CDEF,GF_CDEF) conv_if(VDEF,GF_VDEF) conv_if(PART,GF_PART) + conv_if(XPORT,GF_XPORT) return (-1); } @@ -814,6 +815,8 @@ data_calc( image_desc_t *im){ * so CDEFs can use VDEFs and vice versa */ switch (im->gdes[gdi].gf) { + case GF_XPORT: + break; case GF_VDEF: /* A VDEF has no DS. This also signals other parts * of rrdtool that this is a VDEF value, not a CDEF. @@ -1030,6 +1033,7 @@ data_proc( image_desc_t *im ){ case GF_CDEF: case GF_VDEF: case GF_PART: + case GF_XPORT: break; } } @@ -1311,6 +1315,7 @@ print_calc(image_desc_t *im, char ***prdata) case GF_CDEF: case GF_VDEF: case GF_PART: + case GF_XPORT: break; } } @@ -2274,6 +2279,7 @@ graph_paint(image_desc_t *im, char ***calcpr) case GF_COMMENT: case GF_HRULE: case GF_VRULE: + case GF_XPORT: break; case GF_TICK: for (ii = 0; ii < im->xsize; ii++) @@ -2999,6 +3005,8 @@ rrd_graph_script(int argc, char *argv[], image_desc_t *im) /* If the error string is set, we exit at the end of the switch */ switch (gdp->gf) { + case GF_XPORT: + break; case GF_COMMENT: if (rrd_graph_legend(gdp,&line[argstart])==0) rrd_set_error("Cannot parse comment in line: %s",line); diff --git a/program/src/rrd_graph.h b/program/src/rrd_graph.h index e61d6b02..1f20a40e 100644 --- a/program/src/rrd_graph.h +++ b/program/src/rrd_graph.h @@ -23,7 +23,7 @@ enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB, 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_PART}; + GF_PART, GF_XPORT}; enum vdef_op_en { VDEF_MAXIMUM /* like the MAX in (G)PRINT */ diff --git a/program/src/rrd_tool.c b/program/src/rrd_tool.c index a86e0ed7..9a1f795d 100644 --- a/program/src/rrd_tool.c +++ b/program/src/rrd_tool.c @@ -5,6 +5,7 @@ *****************************************************************************/ #include "rrd_tool.h" +#include "rrd_xport.h" void PrintUsage(char *cmd); int CountArgs(char *aLine); @@ -24,7 +25,7 @@ void PrintUsage(char *cmd) char help_list[] = "Valid commands: create, update, graph, dump, restore,\n" - "\t\tlast, info, fetch, tune, resize\n\n"; + "\t\tlast, info, fetch, tune, resize, xport\n\n"; char help_create[] = "* create - create a new RRD\n\n" @@ -113,6 +114,15 @@ void PrintUsage(char *cmd) " * resize - alter the lenght of one of the RRAs in an RRD\n\n" "\trrdtool resize filename rranum GROW|SHRINK rows\n\n"; + char help_xport[] = + "* 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[DEF:vname=rrd:ds-name:CF]\n" + "\t\t[CDEF:vname=rpn-expression]\n" + "\t\t[XPORT:vname:legend]\n\n"; + char help_lic[] = "RRDtool is distributed under the Terms of the GNU General\n" "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n" @@ -120,7 +130,7 @@ void PrintUsage(char *cmd) "For more information read the RRD manpages\n\n"; enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, - C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE }; + C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT }; int help_cmd = C_NONE; @@ -146,6 +156,8 @@ void PrintUsage(char *cmd) help_cmd = C_TUNE; else if (!strcmp(cmd,"resize")) help_cmd = C_RESIZE; + else if (!strcmp(cmd,"xport")) + help_cmd = C_XPORT; } fputs(help_main, stdout); switch (help_cmd) @@ -183,6 +195,9 @@ void PrintUsage(char *cmd) case C_RESIZE: fputs(help_resize, stdout); break; + case C_XPORT: + fputs(help_xport, stdout); + break; } fputs(help_lic, stdout); } @@ -347,6 +362,54 @@ int HandleInputLine(int argc, char **argv, FILE* out) free(ds_namv); free (data); } + } else if (strcmp("xport", argv[1]) == 0) { + int xxsize; + int i = 0, j = 0; + time_t start,end; + unsigned long step, col_cnt,row_cnt; + rrd_value_t *data,*ptr; + char **legend_v; + if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) { + row_cnt = (end-start)/step; + ptr = data; + printf("\n\n", XML_ENCODING); + printf("<%s>\n", ROOT_TAG); + printf(" <%s>\n", META_TAG); + printf(" <%s>%lu\n", META_START_TAG, start+step, META_START_TAG); + printf(" <%s>%lu\n", META_STEP_TAG, step, META_STEP_TAG); + printf(" <%s>%lu\n", META_END_TAG, end, META_END_TAG); + printf(" <%s>%lu\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG); + printf(" <%s>%lu\n", META_COLS_TAG, col_cnt, META_COLS_TAG); + printf(" <%s>\n", LEGEND_TAG); + for (j = 0; j < col_cnt; j++) { + char *entry = NULL; + entry = legend_v[j]; + printf(" <%s>%s\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG); + free(entry); + } + free(legend_v); + printf(" \n", LEGEND_TAG); + printf(" \n", META_TAG); + printf(" <%s>\n", DATA_TAG); + for (i = start+step; i <= end; i += step) { + printf (" <%s>", DATA_ROW_TAG); + printf ("<%s>%lu", COL_TIME_TAG, i, COL_TIME_TAG); + for (j = 0; j < col_cnt; j++) { + rrd_value_t newval = DNAN; + newval = *ptr; + if(isnan(newval)){ + printf("<%s>NaN", COL_DATA_TAG, COL_DATA_TAG); + } else { + printf("<%s>%0.10e", COL_DATA_TAG, newval, COL_DATA_TAG); + }; + ptr++; + } + printf("\n", DATA_ROW_TAG); + } + free(data); + printf(" \n", DATA_TAG); + printf("\n", ROOT_TAG); + } } else if (strcmp("graph", argv[1]) == 0) { char **calcpr; diff --git a/program/src/rrd_xport.c b/program/src/rrd_xport.c new file mode 100644 index 00000000..b943fe2e --- /dev/null +++ b/program/src/rrd_xport.c @@ -0,0 +1,425 @@ +/**************************************************************************** + * RRDtool 1.0.37 Copyright Tobias Oetiker, 1997 - 2000 + **************************************************************************** + * rrd_xport.c export RRD data + ****************************************************************************/ + +#include + +#include "rrd_tool.h" +#include "rrd_graph.h" +#include "rrd_xport.h" + +#ifdef WIN32 +#include +#include +#endif + + +int rrd_xport(int, char **, int *, + time_t *, time_t *, + unsigned long *, unsigned long *, + char ***, rrd_value_t **); + +int rrd_xport_fn(image_desc_t *, + time_t *, time_t *, + unsigned long *, unsigned long *, + char ***, rrd_value_t **); + + + + +int +rrd_xport(int argc, char **argv, int *xsize, + time_t *start, + time_t *end, /* which time frame do you want ? + * will be changed to represent reality */ + unsigned long *step, /* which stepsize do you want? + * will be changed to represent reality */ + unsigned long *col_cnt, /* number of data columns in the result */ + char ***legend_v, /* legend entries */ + rrd_value_t **data) /* two dimensional array containing the data */ + +{ + + image_desc_t im; + int i; + long long_tmp; + time_t start_tmp=0,end_tmp=0; + char symname[100]; + long scancount; + struct time_value start_tv, end_tv; + char *parsetime_error = NULL; + + rrd_graph_init(&im); + + parsetime("end-24h", &start_tv); + parsetime("now", &end_tv); + + while (1){ + static struct option long_options[] = + { + {"start", required_argument, 0, 's'}, + {"end", required_argument, 0, 'e'}, + {"maxrows", required_argument, 0, 'm'}, + {"step", required_argument, 0, 261}, + {0,0,0,0} + }; + int option_index = 0; + int opt; + + opt = getopt_long(argc, argv, "s:e:m:", + long_options, &option_index); + + if (opt == EOF) + break; + + switch(opt) { + case 261: + im.step = atoi(optarg); + break; + case 's': + if ((parsetime_error = parsetime(optarg, &start_tv))) { + rrd_set_error( "start time: %s", parsetime_error ); + return -1; + } + break; + case 'e': + if ((parsetime_error = parsetime(optarg, &end_tv))) { + rrd_set_error( "end time: %s", parsetime_error ); + return -1; + } + break; + case 'm': + long_tmp = atol(optarg); + if (long_tmp < 10) { + rrd_set_error("maxrows below 10 rows"); + return -1; + } + im.xsize = long_tmp; + break; + case '?': + rrd_set_error("unknown option '%c'", optopt); + return -1; + } + } + + if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){ + return -1; + } + + if (start_tmp < 3600*24*365*10){ + rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp); + return -1; + } + + if (end_tmp < start_tmp) { + rrd_set_error("start (%ld) should be less than end (%ld)", + start_tmp, end_tmp); + return -1; + } + + im.start = start_tmp; + im.end = end_tmp; + + for(i=optind;i=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; + } + + } + + if (im.gdes_c == 0){ + rrd_set_error("can't make a graph without contents"); + im_free(&im); + return(-1); + } + + if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){ + im_free(&im); + return -1; + } + + im_free(&im); + return 0; +} + + + +int +rrd_xport_fn(image_desc_t *im, + time_t *start, + time_t *end, /* which time frame do you want ? + * will be changed to represent reality */ + unsigned long *step, /* which stepsize do you want? + * will be changed to represent reality */ + unsigned long *col_cnt, /* number of data columns in the result */ + char ***legend_v, /* legend entries */ + rrd_value_t **data) /* two dimensional array containing the data */ +{ + + int i = 0, j = 0; + unsigned long *ds_cnt; /* number of data sources in file */ + unsigned long col, dst_row, row_cnt; + rrd_value_t *srcptr, *dstptr; + + unsigned long nof_xports = 0; + unsigned long xport_counter = 0; + unsigned long *ref_list; + rrd_value_t **srcptr_list; + char **legend_list; + int ii = 0; + + time_t start_tmp = 0; + time_t end_tmp = 0; + unsigned long step_tmp = 1; + + /* pull the data from the rrd files ... */ + if(data_fetch(im)==-1) + return -1; + + /* evaluate CDEF operations ... */ + if(data_calc(im)==-1) + return -1; + + /* how many xports? */ + for(i = 0; i < im->gdes_c; i++) { + switch(im->gdes[i].gf) { + case GF_XPORT: + nof_xports++; + break; + default: + break; + } + } + + if(nof_xports == 0) { + rrd_set_error("no XPORT found, nothing to do"); + return -1; + } + + /* a list of referenced gdes */ + ref_list = malloc(sizeof(int) * nof_xports); + if(ref_list == NULL) + return -1; + + /* a list to save pointers into each gdes data */ + srcptr_list = malloc(sizeof(srcptr) * nof_xports); + if(srcptr_list == NULL) { + free(ref_list); + return -1; + } + + /* a list to save pointers to the column's legend entry */ + /* this is a return value! */ + legend_list = malloc(sizeof(char *) * nof_xports); + if(legend_list == NULL) { + free(srcptr_list); + free(ref_list); + return -1; + } + + /* find referenced gdes and save their index and */ + /* a pointer into their data */ + for(i = 0; i < im->gdes_c; i++) { + switch(im->gdes[i].gf) { + case GF_XPORT: + ii = im->gdes[i].vidx; + if(xport_counter > nof_xports) { + rrd_set_error( "too many xports: should not happen. Hmmm"); + free(srcptr_list); + free(ref_list); + free(legend_list); + return -1; + } + srcptr_list[xport_counter] = im->gdes[ii].data; + ref_list[xport_counter++] = i; + break; + default: + break; + } + } + + start_tmp = im->gdes[0].start; + end_tmp = im->gdes[0].end; + step_tmp = im->gdes[0].step; + + /* fill some return values */ + *col_cnt = nof_xports; + *start = start_tmp; + *end = end_tmp; + *step = step_tmp; + + row_cnt = ((*end)-(*start))/(*step); + + /* room for rearranged data */ + /* this is a return value! */ + if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){ + free(srcptr_list); + free(ref_list); + free(legend_list); + rrd_set_error("malloc xport data area"); + return(-1); + } + dstptr = (*data); + + j = 0; + for(i = 0; i < im->gdes_c; i++) { + switch(im->gdes[i].gf) { + case GF_XPORT: + /* reserve room for one legend entry */ + /* is FMT_LEG_LEN + 5 the correct size? */ + if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) { + free(srcptr_list); + free(ref_list); + free(legend_list); + rrd_set_error("malloc xprint legend entry"); + return(-1); + } + + if (im->gdes[i].legend) + /* omit bounds check, should have the same size */ + strcpy (legend_list[j++], im->gdes[i].legend); + else + legend_list[j++][0] = '\0'; + + break; + default: + break; + } + } + + /* fill data structure */ + for(dst_row = 0; dst_row < row_cnt; dst_row++) { + for(i = 0; i < nof_xports; i++) { + j = ref_list[i]; + ii = im->gdes[j].vidx; + ds_cnt = &im->gdes[ii].ds_cnt; + + srcptr = srcptr_list[i]; + for(col = 0; col < (*ds_cnt); col++) { + rrd_value_t newval = DNAN; + newval = srcptr[col]; + + if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) { + if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0) + (*dstptr++) = newval; + } else { + (*dstptr++) = newval; + } + + } + srcptr_list[i] += (*ds_cnt); + } + } + + *legend_v = legend_list; + free(srcptr_list); + free(ref_list); + return 0; + +} diff --git a/program/src/rrd_xport.h b/program/src/rrd_xport.h new file mode 100644 index 00000000..d8d76d44 --- /dev/null +++ b/program/src/rrd_xport.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * RRDtool 1.0.37 Copyright Tobias Oetiker, 1997 - 2000 + **************************************************************************** + * rrd_xport.h contains XML related constants + ****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _RRD_XPORT_H +#define _RRD_XPORT_H + +#define XML_ENCODING "ISO-8859-1" +#define ROOT_TAG "xport" +#define META_TAG "meta" +#define META_START_TAG "start" +#define META_STEP_TAG "step" +#define META_END_TAG "end" +#define META_ROWS_TAG "rows" +#define META_COLS_TAG "columns" +#define LEGEND_TAG "legend" +#define LEGEND_ENTRY_TAG "entry" +#define DATA_TAG "data" +#define DATA_ROW_TAG "row" +#define COL_TIME_TAG "t" +#define COL_DATA_TAG "v" + + +#endif + + +#ifdef __cplusplus +} +#endif -- 2.30.2