fix spelling and syntax, especially in messages that are printed -- Mike Slifcak
[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     int            i;
47     long           long_tmp;
48     time_t         start_tmp=0,end_tmp=0;
49     char           symname[100];
50     long           scancount;
51     struct rrd_time_value start_tv, end_tv;
52     char           *parsetime_error = NULL;
53
54     rrd_graph_init(&im);
55
56     parsetime("end-24h", &start_tv);
57     parsetime("now", &end_tv);
58
59     while (1){
60         static struct option long_options[] =
61         {
62             {"start",      required_argument, 0,  's'},
63             {"end",        required_argument, 0,  'e'},
64             {"maxrows",    required_argument, 0,  'm'},
65             {"step",       required_argument, 0,   261},
66             {0,0,0,0}
67         };
68         int option_index = 0;
69         int opt;
70         
71         opt = getopt_long(argc, argv, "s:e:m:",
72                           long_options, &option_index);
73
74         if (opt == EOF)
75             break;
76         
77         switch(opt) {
78         case 261:
79             im.step =  atoi(optarg);
80             break;
81         case 's':
82             if ((parsetime_error = parsetime(optarg, &start_tv))) {
83                 rrd_set_error( "start time: %s", parsetime_error );
84                 return -1;
85             }
86             break;
87         case 'e':
88             if ((parsetime_error = parsetime(optarg, &end_tv))) {
89                 rrd_set_error( "end time: %s", parsetime_error );
90                 return -1;
91             }
92             break;
93         case 'm':
94             long_tmp = atol(optarg);
95             if (long_tmp < 10) {
96                 rrd_set_error("maxrows below 10 rows");
97                 return -1;
98             }
99             im.xsize = long_tmp;
100             break;
101         case '?':
102             rrd_set_error("unknown option '%c'", optopt);
103             return -1;
104         }
105     }
106
107     if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
108         return -1;
109     }  
110     
111     if (start_tmp < 3600*24*365*10){
112         rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
113         return -1;
114     }
115     
116     if (end_tmp < start_tmp) {
117         rrd_set_error("start (%ld) should be less than end (%ld)", 
118                start_tmp, end_tmp);
119         return -1;
120     }
121     
122     im.start = start_tmp;
123     im.end = end_tmp;
124
125     for(i=optind;i<argc;i++){
126         int   argstart=0;
127         int   strstart=0;
128         char  varname[30],*rpnex;
129         gdes_alloc(&im);
130         if(sscanf(argv[i],"%10[A-Z0-9]:%n",symname,&argstart)==1){
131             if((im.gdes[im.gdes_c-1].gf=gf_conv(symname))==-1){
132                 im_free(&im);
133                 rrd_set_error("unknown function '%s'",symname);
134                 return -1;
135             }
136         } else {
137             rrd_set_error("can't parse '%s'",argv[i]);
138             im_free(&im);
139             return -1;
140         }
141
142         switch(im.gdes[im.gdes_c-1].gf){
143         case GF_CDEF:
144             if((rpnex = malloc(strlen(&argv[i][argstart])*sizeof(char)))==NULL){
145                 rrd_set_error("malloc for CDEF");
146                 return -1;
147             }
148             if(sscanf(
149                     &argv[i][argstart],
150                     DEF_NAM_FMT "=%[^: ]",
151                     im.gdes[im.gdes_c-1].vname,
152                     rpnex) != 2){
153                 im_free(&im);
154                 free(rpnex);
155                 rrd_set_error("can't parse CDEF '%s'",&argv[i][argstart]);
156                 return -1;
157             }
158             /* checking for duplicate DEF CDEFS */
159             if(find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
160                 im_free(&im);
161                 rrd_set_error("duplicate variable '%s'",
162                               im.gdes[im.gdes_c-1].vname);
163                 return -1; 
164             }      
165             if((im.gdes[im.gdes_c-1].rpnp = rpn_parse(&im,rpnex,&find_var_wrapper))== NULL){
166                 rrd_set_error("invalid rpn expression '%s'", rpnex);
167                 im_free(&im);           
168                 return -1;
169             }
170             free(rpnex);
171             break;
172         case GF_DEF:
173             if (sscanf(
174                 &argv[i][argstart],
175                 DEF_NAM_FMT "=%n",
176                 im.gdes[im.gdes_c-1].vname,
177                 &strstart)== 1 && strstart){ /* is the = did not match %n returns 0 */ 
178                 if(sscanf(&argv[i][argstart
179                                   +strstart
180                                   +scan_for_col(&argv[i][argstart+strstart],
181                                                 MAXPATH,im.gdes[im.gdes_c-1].rrd)],
182                           ":" DS_NAM_FMT ":" CF_NAM_FMT,
183                           im.gdes[im.gdes_c-1].ds_nam,
184                           symname) != 2){
185                     im_free(&im);
186                     rrd_set_error("can't parse DEF '%s' -2",&argv[i][argstart]);
187                     return -1;
188                 }
189             } else {
190                 im_free(&im);
191                 rrd_set_error("can't parse DEF '%s'",&argv[i][argstart]);
192                 return -1;
193             }
194             
195             /* checking for duplicate DEF CDEFS */
196             if (find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){
197                 im_free(&im);
198                 rrd_set_error("duplicate variable '%s'",
199                           im.gdes[im.gdes_c-1].vname);
200                 return -1; 
201             }      
202             if((im.gdes[im.gdes_c-1].cf=cf_conv(symname))==-1){
203                 im_free(&im);
204                 rrd_set_error("unknown cf '%s'",symname);
205                 return -1;
206             }
207             break;
208         case GF_XPORT:
209             if((scancount=sscanf(
210                 &argv[i][argstart],
211                 "%29[^:]:%n",
212                 varname,
213                 &strstart))>=1){
214                 if(strstart <= 0){
215                     im.gdes[im.gdes_c-1].legend[0] = '\0';
216                 } else { 
217                     scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend);
218                 }
219                 if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1){
220                     im_free(&im);
221                     rrd_set_error("unknown variable '%s'",varname);
222                     return -1;
223                 }               
224             } else {
225                 im_free(&im);
226                 rrd_set_error("can't parse '%s'",&argv[i][argstart]);
227                 return -1;
228             }
229             break;
230         default:
231           break;
232         }
233         
234     }
235
236     if (im.gdes_c == 0){
237         rrd_set_error("can't make a graph without contents");
238         im_free(&im);
239         return(-1); 
240     }
241     
242     if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
243         im_free(&im);
244         return -1;
245     }
246
247     im_free(&im);
248     return 0;
249 }
250
251
252
253 int
254 rrd_xport_fn(image_desc_t *im,
255              time_t         *start,
256              time_t         *end,        /* which time frame do you want ?
257                                           * will be changed to represent reality */
258              unsigned long  *step,       /* which stepsize do you want? 
259                                           * will be changed to represent reality */
260              unsigned long  *col_cnt,    /* number of data columns in the result */
261              char           ***legend_v, /* legend entries */
262              rrd_value_t    **data)      /* two dimensional array containing the data */
263 {
264
265     int            i = 0, j = 0;
266     unsigned long  *ds_cnt;    /* number of data sources in file */
267     unsigned long  col, dst_row, row_cnt;
268     rrd_value_t    *srcptr, *dstptr;
269
270     unsigned long nof_xports = 0;
271     unsigned long xport_counter = 0;
272     unsigned long *ref_list;
273     rrd_value_t **srcptr_list;
274     char **legend_list;
275     int ii = 0;
276
277     time_t start_tmp = 0;
278     time_t end_tmp = 0;
279     unsigned long step_tmp = 1;
280
281     /* pull the data from the rrd files ... */
282     if(data_fetch(im)==-1)
283         return -1;
284
285     /* evaluate CDEF  operations ... */
286     if(data_calc(im)==-1)
287         return -1;
288
289     /* how many xports? */
290     for(i = 0; i < im->gdes_c; i++) {   
291         switch(im->gdes[i].gf) {
292         case GF_XPORT:
293           nof_xports++;
294           break;
295         default:
296           break;
297         }
298     }
299
300     if(nof_xports == 0) {
301       rrd_set_error("no XPORT found, nothing to do");
302       return -1;
303     }
304
305     /* a list of referenced gdes */
306     ref_list = malloc(sizeof(int) * nof_xports);
307     if(ref_list == NULL)
308       return -1;
309
310     /* a list to save pointers into each gdes data */
311     srcptr_list = malloc(sizeof(srcptr) * nof_xports);
312     if(srcptr_list == NULL) {
313       free(ref_list);
314       return -1;
315     }
316
317     /* a list to save pointers to the column's legend entry */
318     /* this is a return value! */
319     legend_list = malloc(sizeof(char *) * nof_xports);
320     if(legend_list == NULL) {
321       free(srcptr_list);
322       free(ref_list);
323       return -1;
324     }
325
326     /* find referenced gdes and save their index and */
327     /* a pointer into their data */
328     for(i = 0; i < im->gdes_c; i++) {   
329         switch(im->gdes[i].gf) {
330         case GF_XPORT:
331           ii = im->gdes[i].vidx;
332           if(xport_counter > nof_xports) {
333             rrd_set_error( "too many xports: should not happen. Hmmm");
334             free(srcptr_list);
335             free(ref_list);
336             free(legend_list);
337             return -1;
338           } 
339           srcptr_list[xport_counter] = im->gdes[ii].data;
340           ref_list[xport_counter++] = i;
341           break;
342         default:
343           break;
344         }
345     }
346
347     start_tmp = im->gdes[0].start;
348     end_tmp = im->gdes[0].end;
349     step_tmp = im->gdes[0].step;
350
351     /* fill some return values */
352     *col_cnt = nof_xports;
353     *start = start_tmp;
354     *end = end_tmp;
355     *step = step_tmp;
356
357     row_cnt = ((*end)-(*start))/(*step);
358
359     /* room for rearranged data */
360     /* this is a return value! */
361     if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
362         free(srcptr_list);
363         free(ref_list);
364         free(legend_list);
365         rrd_set_error("malloc xport data area");
366         return(-1);
367     }
368     dstptr = (*data);
369
370     j = 0;
371     for(i = 0; i < im->gdes_c; i++) {   
372         switch(im->gdes[i].gf) {
373         case GF_XPORT:
374           /* reserve room for one legend entry */
375           /* is FMT_LEG_LEN + 5 the correct size? */
376           if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
377             free(srcptr_list);
378             free(ref_list);
379             free(legend_list);
380             rrd_set_error("malloc xprint legend entry");
381             return(-1);
382           }
383
384           if (im->gdes[i].legend)
385             /* omit bounds check, should have the same size */
386             strcpy (legend_list[j++], im->gdes[i].legend);
387           else
388             legend_list[j++][0] = '\0';
389
390           break;
391         default:
392           break;
393         }
394     }
395
396     /* fill data structure */
397     for(dst_row = 0; dst_row < row_cnt; dst_row++) {
398       for(i = 0; i < nof_xports; i++) {
399         j = ref_list[i];
400         ii = im->gdes[j].vidx;
401         ds_cnt = &im->gdes[ii].ds_cnt;
402
403         srcptr = srcptr_list[i];
404         for(col = 0; col < (*ds_cnt); col++) {
405           rrd_value_t newval = DNAN;
406           newval = srcptr[col];
407
408           if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
409             if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
410               (*dstptr++) = newval;
411           } else {
412             (*dstptr++) = newval;
413           }
414
415         }
416         srcptr_list[i] += (*ds_cnt);
417       }
418     }
419
420     *legend_v = legend_list;
421     free(srcptr_list);
422     free(ref_list);
423     return 0;
424
425 }