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