propperly integrate rrd_first
[rrdtool.git] / bindings / perl-shared / RRDs.xs
1 #ifdef __cplusplus
2 extern "C" {
3 #endif
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #ifdef __cplusplus
10 }
11 #endif
12
13 #include "../../src/rrd_tool.h"
14
15 /* perl 5.004 compatibility */
16 #if PERLPATCHLEVEL < 5 
17 #define PL_sv_undef sv_undef
18 #endif
19
20
21 #define rrdcode(name) \
22                 argv = (char **) malloc((items+1)*sizeof(char *));\
23                 argv[0] = "dummy";\
24                 for (i = 0; i < items; i++) { \
25                     STRLEN len; \
26                     char *handle= SvPV(ST(i),len);\
27                     /* actually copy the data to make sure possible modifications \
28                        on the argv data does not backfire into perl */ \
29                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
30                     strcpy(argv[i+1],handle); \
31                 } \
32                 optind=0; opterr=0; \
33                 rrd_clear_error();\
34                 RETVAL=name(items+1,argv); \
35                 for (i=0; i < items; i++) {\
36                     free(argv[i+1]);\
37                 } \
38                 free(argv);\
39                 \
40                 if (rrd_test_error()) XSRETURN_UNDEF;
41
42 #define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0)                 
43
44 #define rrdinfocode(name) \
45                 /* prepare argument list */ \
46                 argv = (char **) malloc((items+1)*sizeof(char *)); \
47                 argv[0] = "dummy"; \
48                 for (i = 0; i < items; i++) { \
49                     STRLEN len; \
50                     char *handle= SvPV(ST(i),len); \
51                     /* actually copy the data to make sure possible modifications \
52                        on the argv data does not backfire into perl */ \
53                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
54                     strcpy(argv[i+1],handle); \
55                 } \
56                 optind=0; opterr=0; \
57                 rrd_clear_error(); \
58                 data=name(items+1, argv); \
59                 for (i=0; i < items; i++) { \
60                     free(argv[i+1]); \
61                 } \
62                 free(argv); \
63                 if (rrd_test_error()) XSRETURN_UNDEF; \
64                 hash = newHV(); \
65                 while (data) { \
66                     save=data; \
67                 /* the newSV will get copied by hv so we create it as a mortal \
68            to make sure it does not keep hanging round after the fact */ \
69                     switch (data->type) { \
70                     case RD_I_VAL: \
71                         if (isnan(data->value.u_val)) \
72                             hvs(&PL_sv_undef); \
73                         else \
74                             hvs(newSVnv(data->value.u_val)); \
75                         break; \
76                         case RD_I_INT: \
77                         hvs(newSViv(data->value.u_int)); \
78                         break; \
79                     case RD_I_CNT: \
80                         hvs(newSViv(data->value.u_cnt)); \
81                         break; \
82                     case RD_I_STR: \
83                         hvs(newSVpv(data->value.u_str,0)); \
84                         rrd_freemem(data->value.u_str); \
85                         break; \
86                     } \
87                     rrd_freemem(data->key); \
88                     data = data->next; \
89                     rrd_freemem(save); \
90                     } \
91             rrd_freemem(data); \
92             RETVAL = newRV_noinc((SV*)hash);
93
94 /*
95  * should not be needed if libc is linked (see ntmake.pl)
96 #ifdef WIN32
97  #define free free
98  #define malloc malloc
99  #define realloc realloc
100 #endif
101 */
102
103
104 MODULE = RRDs   PACKAGE = RRDs  PREFIX = rrd_
105
106 BOOT:
107 #ifdef MUST_DISABLE_SIGFPE
108         signal(SIGFPE,SIG_IGN);
109 #endif
110 #ifdef MUST_DISABLE_FPMASK
111         fpsetmask(0);
112 #endif 
113         
114
115 SV*
116 rrd_error()
117         CODE:
118                 if (! rrd_test_error()) XSRETURN_UNDEF;
119                 RETVAL = newSVpv(rrd_get_error(),0);
120         OUTPUT:
121                 RETVAL
122
123         
124 int
125 rrd_last(...)
126       PROTOTYPE: @
127       PREINIT:
128       int i;
129       char **argv;
130       CODE:
131               rrdcode(rrd_last);
132       OUTPUT:
133             RETVAL
134
135 int
136 rrd_first(...)
137       PROTOTYPE: @
138       PREINIT:
139       int i;
140       char **argv;
141       CODE:
142               rrdcode(rrd_first);
143       OUTPUT:
144             RETVAL
145
146
147 int
148 rrd_create(...)
149         PROTOTYPE: @    
150         PREINIT:
151         int i;
152         char **argv;
153         CODE:
154                 rrdcode(rrd_create);
155                 RETVAL = 1;
156         OUTPUT:
157                 RETVAL
158
159
160 int
161 rrd_update(...)
162         PROTOTYPE: @    
163         PREINIT:
164         int i;
165         char **argv;
166         CODE:
167                 rrdcode(rrd_update);
168                 RETVAL = 1;
169         OUTPUT:
170                 RETVAL
171
172
173 int
174 rrd_tune(...)
175         PROTOTYPE: @    
176         PREINIT:
177         int i;
178         char **argv;
179         CODE:
180                 rrdcode(rrd_tune);
181                 RETVAL = 1;
182         OUTPUT:
183                 RETVAL
184
185
186 void
187 rrd_graph(...)
188         PROTOTYPE: @    
189         PREINIT:
190         char **calcpr=NULL;
191         int i,xsize,ysize;
192         double ymin,ymax;
193         char **argv;
194         AV *retar;
195         PPCODE:
196                 argv = (char **) malloc((items+1)*sizeof(char *));
197                 argv[0] = "dummy";
198                 for (i = 0; i < items; i++) { 
199                     STRLEN len;
200                     char *handle = SvPV(ST(i),len);
201                     /* actually copy the data to make sure possible modifications
202                        on the argv data does not backfire into perl */ 
203                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
204                     strcpy(argv[i+1],handle);
205                 }
206                 optind=0; opterr=0; 
207                 rrd_clear_error();
208                 rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL,&ymin,&ymax); 
209                 for (i=0; i < items; i++) {
210                     free(argv[i+1]);
211                 }
212                 free(argv);
213
214                 if (rrd_test_error()) {
215                         if(calcpr)
216                            for(i=0;calcpr[i];i++)
217                                 rrd_freemem(calcpr[i]);
218                         XSRETURN_UNDEF;
219                 }
220                 retar=newAV();
221                 if(calcpr){
222                         for(i=0;calcpr[i];i++){
223                                  av_push(retar,newSVpv(calcpr[i],0));
224                                  rrd_freemem(calcpr[i]);
225                         }
226                         rrd_freemem(calcpr);
227                 }
228                 EXTEND(sp,4);
229                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
230                 PUSHs(sv_2mortal(newSViv(xsize)));
231                 PUSHs(sv_2mortal(newSViv(ysize)));
232
233 void
234 rrd_fetch(...)
235         PROTOTYPE: @    
236         PREINIT:
237                 time_t        start,end;                
238                 unsigned long step, ds_cnt,i,ii;
239                 rrd_value_t   *data,*datai;
240                 char **argv;
241                 char **ds_namv;
242                 AV *retar,*line,*names;
243         PPCODE:
244                 argv = (char **) malloc((items+1)*sizeof(char *));
245                 argv[0] = "dummy";
246                 for (i = 0; i < items; i++) { 
247                     STRLEN len;
248                     char *handle= SvPV(ST(i),len);
249                     /* actually copy the data to make sure possible modifications
250                        on the argv data does not backfire into perl */ 
251                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
252                     strcpy(argv[i+1],handle);
253                 }
254                 optind=0; opterr=0; 
255                 rrd_clear_error();
256                 rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); 
257                 for (i=0; i < items; i++) {
258                     free(argv[i+1]);
259                 }
260                 free(argv);
261                 if (rrd_test_error()) XSRETURN_UNDEF;
262                 /* convert the ds_namv into perl format */
263                 names=newAV();
264                 for (ii = 0; ii < ds_cnt; ii++){
265                     av_push(names,newSVpv(ds_namv[ii],0));
266                     rrd_freemem(ds_namv[ii]);
267                 }
268                 rrd_freemem(ds_namv);                   
269                 /* convert the data array into perl format */
270                 datai=data;
271                 retar=newAV();
272                 for (i = start+step; i <= end; i += step){
273                         line = newAV();
274                         for (ii = 0; ii < ds_cnt; ii++){
275                           av_push(line,(isnan(*datai) ? &PL_sv_undef : newSVnv(*datai)));
276                           datai++;
277                         }
278                         av_push(retar,newRV_noinc((SV*)line));
279                 }
280                 rrd_freemem(data);
281                 EXTEND(sp,5);
282                 PUSHs(sv_2mortal(newSViv(start+step)));
283                 PUSHs(sv_2mortal(newSViv(step)));
284                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
285                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
286
287 void
288 rrd_times(start, end)
289           char *start
290           char *end
291         PREINIT:
292                 struct  rrd_time_value start_tv, end_tv;
293                 char    *parsetime_error = NULL;
294                 time_t  start_tmp, end_tmp;
295         PPCODE:
296                 rrd_clear_error();
297                 if( (parsetime_error = parsetime( start, &start_tv))) {
298                         rrd_set_error( "start time: %s", parsetime_error);
299                         XSRETURN_UNDEF;
300                 }
301                 if( (parsetime_error = parsetime( end, &end_tv))) {
302                         rrd_set_error( "end time: %s", parsetime_error);
303                         XSRETURN_UNDEF;
304                 }
305                 if( proc_start_end( &start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
306                         XSRETURN_UNDEF;
307                 }
308                 EXTEND(sp,2);
309                 PUSHs(sv_2mortal(newSVuv(start_tmp)));
310                 PUSHs(sv_2mortal(newSVuv(end_tmp)));
311
312 int
313 rrd_xport(...)
314         PROTOTYPE: @    
315         PREINIT:
316                 time_t start,end;               
317                 int xsize;
318                 unsigned long step, col_cnt,row_cnt,i,ii;
319                 rrd_value_t *data,*ptr;
320                 char **argv,**legend_v;
321                 AV *retar,*line,*names;
322         PPCODE:
323                 argv = (char **) malloc((items+1)*sizeof(char *));
324                 argv[0] = "dummy";
325                 for (i = 0; i < items; i++) { 
326                     STRLEN len;
327                     char *handle = SvPV(ST(i),len);
328                     /* actually copy the data to make sure possible modifications
329                        on the argv data does not backfire into perl */ 
330                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
331                     strcpy(argv[i+1],handle);
332                 }
333                 optind=0; opterr=0; 
334                 rrd_clear_error();
335                 rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); 
336                 for (i=0; i < items; i++) {
337                     free(argv[i+1]);
338                 }
339                 free(argv);
340                 if (rrd_test_error()) XSRETURN_UNDEF;
341
342                 /* convert the legend_v into perl format */
343                 names=newAV();
344                 for (ii = 0; ii < col_cnt; ii++){
345                     av_push(names,newSVpv(legend_v[ii],0));
346                     rrd_freemem(legend_v[ii]);
347                 }
348                 rrd_freemem(legend_v);                  
349
350                 /* convert the data array into perl format */
351                 ptr=data;
352                 retar=newAV();
353                 for (i = start+step; i <= end; i += step){
354                         line = newAV();
355                         for (ii = 0; ii < col_cnt; ii++){
356                           av_push(line,(isnan(*ptr) ? &PL_sv_undef : newSVnv(*ptr)));
357                           ptr++;
358                         }
359                         av_push(retar,newRV_noinc((SV*)line));
360                 }
361                 rrd_freemem(data);
362
363                 EXTEND(sp,7);
364                 PUSHs(sv_2mortal(newSViv(start+step)));
365                 PUSHs(sv_2mortal(newSViv(end)));
366                 PUSHs(sv_2mortal(newSViv(step)));
367                 PUSHs(sv_2mortal(newSViv(col_cnt)));
368                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
369                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
370
371 SV*
372 rrd_info(...)
373         PROTOTYPE: @    
374         PREINIT:
375                 info_t *data,*save;
376                 int i;
377                 char **argv;
378                 HV *hash;
379         CODE:
380                 rrdinfocode(rrd_info);  
381     OUTPUT:
382            RETVAL
383
384 SV*
385 rrd_updatev(...)
386         PROTOTYPE: @    
387         PREINIT:
388                 info_t *data,*save;
389                 int i;
390                 char **argv;
391                 HV *hash;
392         CODE:
393                 rrdinfocode(rrd_update_v);      
394     OUTPUT:
395            RETVAL
396
397 int
398 rrd_dump(...)
399        PROTOTYPE: @
400        PREINIT:
401         int i;
402        char **argv;
403        CODE:
404                rrdcode(rrd_dump);
405                        RETVAL = 1;
406        OUTPUT:
407                RETVAL
408
409 int
410 rrd_restore(...)
411        PROTOTYPE: @
412        PREINIT:
413         int i;
414        char **argv;
415        CODE:
416                rrdcode(rrd_restore);
417                        RETVAL = 1;
418        OUTPUT:
419                RETVAL
420