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 
434