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