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