CDEF operators SHIFT, SQRT, SORT, and REV (reverse). See documentation for what
[rrdtool.git] / src / rrd_xport.c
1 /****************************************************************************
2  * RRDtool 1.0.37  Copyright Tobias Oetiker, 1997 - 2000
3  ****************************************************************************
4  * rrd_xport.c  export RRD data 
5  ****************************************************************************/
6
7 #include <sys/stat.h>
8
9 #include "rrd_tool.h"
10 #include "rrd_graph.h"
11 #include "rrd_xport.h"
12
13 #ifdef WIN32
14 #include <io.h>
15 #include <fcntl.h>
16 #endif
17
18
19 int rrd_xport(int, char **, int *,
20               time_t *, time_t *,
21               unsigned long *, unsigned long *,
22               char ***, rrd_value_t **);
23
24 int rrd_xport_fn(image_desc_t *,
25                  time_t *, time_t *,
26                  unsigned long *, unsigned long *,
27                  char ***, rrd_value_t **);
28
29
30
31
32 int 
33 rrd_xport(int argc, char **argv, int *xsize,
34           time_t         *start,
35           time_t         *end,        /* which time frame do you want ?
36                                        * will be changed to represent reality */
37           unsigned long  *step,       /* which stepsize do you want? 
38                                        * will be changed to represent reality */
39           unsigned long  *col_cnt,    /* number of data columns in the result */
40           char           ***legend_v, /* legend entries */
41           rrd_value_t    **data)      /* two dimensional array containing the data */
42
43 {
44
45     image_desc_t   im;
46     time_t         start_tmp=0,end_tmp=0;
47     struct rrd_time_value start_tv, end_tv;
48     char           *parsetime_error = NULL;
49
50     rrd_graph_init(&im);
51
52     parsetime("end-24h", &start_tv);
53     parsetime("now", &end_tv);
54
55     while (1){
56         static struct option long_options[] =
57         {
58             {"start",      required_argument, 0,  's'},
59             {"end",        required_argument, 0,  'e'},
60             {"maxrows",    required_argument, 0,  'm'},
61             {"step",       required_argument, 0,   261},
62             {0,0,0,0}
63         };
64         int option_index = 0;
65         int opt;
66         
67         opt = getopt_long(argc, argv, "s:e:m:",
68                           long_options, &option_index);
69
70         if (opt == EOF)
71             break;
72         
73         switch(opt) {
74         case 261:
75             im.step =  atoi(optarg);
76             break;
77         case 's':
78             if ((parsetime_error = parsetime(optarg, &start_tv))) {
79                 rrd_set_error( "start time: %s", parsetime_error );
80                 return -1;
81             }
82             break;
83         case 'e':
84             if ((parsetime_error = parsetime(optarg, &end_tv))) {
85                 rrd_set_error( "end time: %s", parsetime_error );
86                 return -1;
87             }
88             break;
89         case 'm':
90             im.xsize = atol(optarg);
91             if (im.xsize < 10) {
92                 rrd_set_error("maxrows below 10 rows");
93                 return -1;
94             }
95             break;
96         case '?':
97             rrd_set_error("unknown option '%c'", optopt);
98             return -1;
99         }
100     }
101
102     if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
103         return -1;
104     }  
105     
106     if (start_tmp < 3600*24*365*10){
107         rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
108         return -1;
109     }
110     
111     if (end_tmp < start_tmp) {
112         rrd_set_error("start (%ld) should be less than end (%ld)", 
113                start_tmp, end_tmp);
114         return -1;
115     }
116     
117     im.start = start_tmp;
118     im.end = end_tmp;
119
120     rrd_graph_script(argc,argv,&im,0);
121     if (rrd_test_error()) {
122         im_free(&im);
123         return -1;
124     }
125
126     if (im.gdes_c == 0){
127         rrd_set_error("can't make a graph without contents");
128         im_free(&im);
129         return(-1); 
130     }
131     
132     if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
133         im_free(&im);
134         return -1;
135     }
136
137     im_free(&im);
138     return 0;
139 }
140
141
142
143 int
144 rrd_xport_fn(image_desc_t *im,
145              time_t         *start,
146              time_t         *end,        /* which time frame do you want ?
147                                           * will be changed to represent reality */
148              unsigned long  *step,       /* which stepsize do you want? 
149                                           * will be changed to represent reality */
150              unsigned long  *col_cnt,    /* number of data columns in the result */
151              char           ***legend_v, /* legend entries */
152              rrd_value_t    **data)      /* two dimensional array containing the data */
153 {
154
155     int            i = 0, j = 0;
156     unsigned long  *ds_cnt;    /* number of data sources in file */
157     unsigned long  col, dst_row, row_cnt;
158     rrd_value_t    *srcptr, *dstptr;
159
160     unsigned long nof_xports = 0;
161     unsigned long xport_counter = 0;
162     unsigned long *ref_list;
163     rrd_value_t **srcptr_list;
164     char **legend_list;
165     int ii = 0;
166
167     time_t start_tmp = 0;
168     time_t end_tmp = 0;
169     unsigned long step_tmp = 1;
170
171     /* pull the data from the rrd files ... */
172     if(data_fetch(im)==-1)
173         return -1;
174
175     /* evaluate CDEF  operations ... */
176     if(data_calc(im)==-1)
177         return -1;
178
179     /* how many xports? */
180     for(i = 0; i < im->gdes_c; i++) {   
181         switch(im->gdes[i].gf) {
182         case GF_XPORT:
183           nof_xports++;
184           break;
185         default:
186           break;
187         }
188     }
189
190     if(nof_xports == 0) {
191       rrd_set_error("no XPORT found, nothing to do");
192       return -1;
193     }
194
195     /* a list of referenced gdes */
196     ref_list = malloc(sizeof(int) * nof_xports);
197     if(ref_list == NULL)
198       return -1;
199
200     /* a list to save pointers into each gdes data */
201     srcptr_list = malloc(sizeof(srcptr) * nof_xports);
202     if(srcptr_list == NULL) {
203       free(ref_list);
204       return -1;
205     }
206
207     /* a list to save pointers to the column's legend entry */
208     /* this is a return value! */
209     legend_list = malloc(sizeof(char *) * nof_xports);
210     if(legend_list == NULL) {
211       free(srcptr_list);
212       free(ref_list);
213       return -1;
214     }
215
216     /* find referenced gdes and save their index and */
217     /* a pointer into their data */
218     for(i = 0; i < im->gdes_c; i++) {   
219         switch(im->gdes[i].gf) {
220         case GF_XPORT:
221           ii = im->gdes[i].vidx;
222           if(xport_counter > nof_xports) {
223             rrd_set_error( "too many xports: should not happen. Hmmm");
224             free(srcptr_list);
225             free(ref_list);
226             free(legend_list);
227             return -1;
228           } 
229           srcptr_list[xport_counter] = im->gdes[ii].data;
230           ref_list[xport_counter++] = i;
231           break;
232         default:
233           break;
234         }
235     }
236
237     start_tmp = im->gdes[0].start;
238     end_tmp = im->gdes[0].end;
239     step_tmp = im->gdes[0].step;
240
241     /* fill some return values */
242     *col_cnt = nof_xports;
243     *start = start_tmp;
244     *end = end_tmp;
245     *step = step_tmp;
246
247     row_cnt = ((*end)-(*start))/(*step);
248
249     /* room for rearranged data */
250     /* this is a return value! */
251     if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
252         free(srcptr_list);
253         free(ref_list);
254         free(legend_list);
255         rrd_set_error("malloc xport data area");
256         return(-1);
257     }
258     dstptr = (*data);
259
260     j = 0;
261     for(i = 0; i < im->gdes_c; i++) {   
262         switch(im->gdes[i].gf) {
263         case GF_XPORT:
264           /* reserve room for one legend entry */
265           /* is FMT_LEG_LEN + 5 the correct size? */
266           if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
267             free(srcptr_list);
268             free(ref_list);
269             free(*data);  *data = NULL;
270             while (--j > -1) free(legend_list[j]);
271             free(legend_list);
272             rrd_set_error("malloc xport legend entry");
273             return(-1);
274           }
275
276           if (im->gdes[i].legend)
277             /* omit bounds check, should have the same size */
278             strcpy (legend_list[j++], im->gdes[i].legend);
279           else
280             legend_list[j++][0] = '\0';
281
282           break;
283         default:
284           break;
285         }
286     }
287
288     /* fill data structure */
289     for(dst_row = 0; (int)dst_row < (int)row_cnt; dst_row++) {
290       for(i = 0; i < (int)nof_xports; i++) {
291         j = ref_list[i];
292         ii = im->gdes[j].vidx;
293         ds_cnt = &im->gdes[ii].ds_cnt;
294
295         srcptr = srcptr_list[i];
296         for(col = 0; col < (*ds_cnt); col++) {
297           rrd_value_t newval = DNAN;
298           newval = srcptr[col];
299
300           if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
301             if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
302               (*dstptr++) = newval;
303           } else {
304             (*dstptr++) = newval;
305           }
306
307         }
308         srcptr_list[i] += (*ds_cnt);
309       }
310     }
311
312     *legend_v = legend_list;
313     free(srcptr_list);
314     free(ref_list);
315     return 0;
316
317 }