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