rrd_open.c (rrd_read): Mimicing read() behaviour for EOF case and NULL buffer case.
[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                     } \
103                     rrd_freemem(data->key); \
104                     data = data->next; \
105                     rrd_freemem(save); \
106                     } \
107             rrd_freemem(data); \
108             RETVAL = newRV_noinc((SV*)hash);
109
110 /*
111  * should not be needed if libc is linked (see ntmake.pl)
112 #ifdef WIN32
113  #define free free
114  #define malloc malloc
115  #define realloc realloc
116 #endif
117 */
118
119
120 MODULE = RRDs   PACKAGE = RRDs  PREFIX = rrd_
121
122 BOOT:
123 #ifdef MUST_DISABLE_SIGFPE
124         signal(SIGFPE,SIG_IGN);
125 #endif
126 #ifdef MUST_DISABLE_FPMASK
127         fpsetmask(0);
128 #endif 
129         
130
131 SV*
132 rrd_error()
133         CODE:
134                 if (! rrd_test_error()) XSRETURN_UNDEF;
135                 RETVAL = newSVpv(rrd_get_error(),0);
136         OUTPUT:
137                 RETVAL
138
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
163 int
164 rrd_create(...)
165         PROTOTYPE: @    
166         PREINIT:
167         int i;
168         char **argv;
169         CODE:
170                 rrdcode(rrd_create);
171                 RETVAL = 1;
172         OUTPUT:
173                 RETVAL
174
175
176 int
177 rrd_update(...)
178         PROTOTYPE: @    
179         PREINIT:
180         int i;
181         char **argv;
182         CODE:
183                 rrdcode(rrd_update);
184                 RETVAL = 1;
185         OUTPUT:
186                 RETVAL
187
188
189 int
190 rrd_tune(...)
191         PROTOTYPE: @    
192         PREINIT:
193         int i;
194         char **argv;
195         CODE:
196                 rrdcode(rrd_tune);
197                 RETVAL = 1;
198         OUTPUT:
199                 RETVAL
200
201
202 void
203 rrd_graph(...)
204         PROTOTYPE: @    
205         PREINIT:
206         char **calcpr=NULL;
207         int i,xsize,ysize;
208         double ymin,ymax;
209         char **argv;
210         AV *retar;
211         PPCODE:
212                 argv = (char **) malloc((items+1)*sizeof(char *));
213                 argv[0] = "dummy";
214                 for (i = 0; i < items; i++) { 
215                     STRLEN len;
216                     char *handle = SvPV(ST(i),len);
217                     /* actually copy the data to make sure possible modifications
218                        on the argv data does not backfire into perl */ 
219                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
220                     strcpy(argv[i+1],handle);
221                 }
222                 rrd_clear_error();
223                 rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL,&ymin,&ymax); 
224                 for (i=0; i < items; i++) {
225                     free(argv[i+1]);
226                 }
227                 free(argv);
228
229                 if (rrd_test_error()) {
230                         if(calcpr)
231                            for(i=0;calcpr[i];i++)
232                                 rrd_freemem(calcpr[i]);
233                         XSRETURN_UNDEF;
234                 }
235                 retar=newAV();
236                 if(calcpr){
237                         for(i=0;calcpr[i];i++){
238                                  av_push(retar,newSVpv(calcpr[i],0));
239                                  rrd_freemem(calcpr[i]);
240                         }
241                         rrd_freemem(calcpr);
242                 }
243                 EXTEND(sp,4);
244                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
245                 PUSHs(sv_2mortal(newSViv(xsize)));
246                 PUSHs(sv_2mortal(newSViv(ysize)));
247
248 void
249 rrd_fetch(...)
250         PROTOTYPE: @    
251         PREINIT:
252                 time_t        start,end;                
253                 unsigned long step, ds_cnt,i,ii;
254                 rrd_value_t   *data,*datai;
255                 char **argv;
256                 char **ds_namv;
257                 AV *retar,*line,*names;
258         PPCODE:
259                 argv = (char **) malloc((items+1)*sizeof(char *));
260                 argv[0] = "dummy";
261                 for (i = 0; i < items; i++) { 
262                     STRLEN len;
263                     char *handle= SvPV(ST(i),len);
264                     /* actually copy the data to make sure possible modifications
265                        on the argv data does not backfire into perl */ 
266                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
267                     strcpy(argv[i+1],handle);
268                 }
269                 rrd_clear_error();
270                 rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); 
271                 for (i=0; i < items; i++) {
272                     free(argv[i+1]);
273                 }
274                 free(argv);
275                 if (rrd_test_error()) XSRETURN_UNDEF;
276                 /* convert the ds_namv into perl format */
277                 names=newAV();
278                 for (ii = 0; ii < ds_cnt; ii++){
279                     av_push(names,newSVpv(ds_namv[ii],0));
280                     rrd_freemem(ds_namv[ii]);
281                 }
282                 rrd_freemem(ds_namv);                   
283                 /* convert the data array into perl format */
284                 datai=data;
285                 retar=newAV();
286                 for (i = start+step; i <= end; i += step){
287                         line = newAV();
288                         for (ii = 0; ii < ds_cnt; ii++){
289                           av_push(line,(isnan(*datai) ? &PL_sv_undef : newSVnv(*datai)));
290                           datai++;
291                         }
292                         av_push(retar,newRV_noinc((SV*)line));
293                 }
294                 rrd_freemem(data);
295                 EXTEND(sp,5);
296                 PUSHs(sv_2mortal(newSViv(start+step)));
297                 PUSHs(sv_2mortal(newSViv(step)));
298                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
299                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
300
301 void
302 rrd_times(start, end)
303           char *start
304           char *end
305         PREINIT:
306                 struct  rrd_time_value start_tv, end_tv;
307                 char    *parsetime_error = NULL;
308                 time_t  start_tmp, end_tmp;
309         PPCODE:
310                 rrd_clear_error();
311                 if( (parsetime_error = parsetime( start, &start_tv))) {
312                         rrd_set_error( "start time: %s", parsetime_error);
313                         XSRETURN_UNDEF;
314                 }
315                 if( (parsetime_error = parsetime( end, &end_tv))) {
316                         rrd_set_error( "end time: %s", parsetime_error);
317                         XSRETURN_UNDEF;
318                 }
319                 if( proc_start_end( &start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
320                         XSRETURN_UNDEF;
321                 }
322                 EXTEND(sp,2);
323                 PUSHs(sv_2mortal(newSVuv(start_tmp)));
324                 PUSHs(sv_2mortal(newSVuv(end_tmp)));
325
326 int
327 rrd_xport(...)
328         PROTOTYPE: @    
329         PREINIT:
330                 time_t start,end;               
331                 int xsize;
332                 unsigned long step, col_cnt,row_cnt,i,ii;
333                 rrd_value_t *data,*ptr;
334                 char **argv,**legend_v;
335                 AV *retar,*line,*names;
336         PPCODE:
337                 argv = (char **) malloc((items+1)*sizeof(char *));
338                 argv[0] = "dummy";
339                 for (i = 0; i < items; i++) { 
340                     STRLEN len;
341                     char *handle = SvPV(ST(i),len);
342                     /* actually copy the data to make sure possible modifications
343                        on the argv data does not backfire into perl */ 
344                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
345                     strcpy(argv[i+1],handle);
346                 }
347                 rrd_clear_error();
348                 rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); 
349                 for (i=0; i < items; i++) {
350                     free(argv[i+1]);
351                 }
352                 free(argv);
353                 if (rrd_test_error()) XSRETURN_UNDEF;
354
355                 /* convert the legend_v into perl format */
356                 names=newAV();
357                 for (ii = 0; ii < col_cnt; ii++){
358                     av_push(names,newSVpv(legend_v[ii],0));
359                     rrd_freemem(legend_v[ii]);
360                 }
361                 rrd_freemem(legend_v);                  
362
363                 /* convert the data array into perl format */
364                 ptr=data;
365                 retar=newAV();
366                 for (i = start+step; i <= end; i += step){
367                         line = newAV();
368                         for (ii = 0; ii < col_cnt; ii++){
369                           av_push(line,(isnan(*ptr) ? &PL_sv_undef : newSVnv(*ptr)));
370                           ptr++;
371                         }
372                         av_push(retar,newRV_noinc((SV*)line));
373                 }
374                 rrd_freemem(data);
375
376                 EXTEND(sp,7);
377                 PUSHs(sv_2mortal(newSViv(start+step)));
378                 PUSHs(sv_2mortal(newSViv(end)));
379                 PUSHs(sv_2mortal(newSViv(step)));
380                 PUSHs(sv_2mortal(newSViv(col_cnt)));
381                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
382                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
383
384 SV*
385 rrd_info(...)
386         PROTOTYPE: @    
387         PREINIT:
388                 info_t *data,*save;
389                 int i;
390                 char **argv;
391                 HV *hash;
392         CODE:
393                 rrdinfocode(rrd_info);  
394     OUTPUT:
395            RETVAL
396
397 SV*
398 rrd_updatev(...)
399         PROTOTYPE: @    
400         PREINIT:
401                 info_t *data,*save;
402                 int i;
403                 char **argv;
404                 HV *hash;
405         CODE:
406                 rrdinfocode(rrd_update_v);      
407     OUTPUT:
408            RETVAL
409
410 int
411 rrd_dump(...)
412        PROTOTYPE: @
413        PREINIT:
414         int i;
415        char **argv;
416        CODE:
417                rrdcode(rrd_dump);
418                        RETVAL = 1;
419        OUTPUT:
420                RETVAL
421
422 int
423 rrd_restore(...)
424        PROTOTYPE: @
425        PREINIT:
426         int i;
427        char **argv;
428        CODE:
429                rrdcode(rrd_restore);
430                        RETVAL = 1;
431        OUTPUT:
432                RETVAL
433