#ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #ifdef __cplusplus } #endif #include "../src/rrd_tool.h" /* perl 5.004 compatibility */ #if PERLPATCHLEVEL < 5 #define PL_sv_undef sv_undef #endif #define rrdcode(name) \ argv = (char **) malloc((items+1)*sizeof(char *));\ argv[0] = "dummy";\ for (i = 0; i < items; i++) { \ STRLEN len; \ char *handle= SvPV(ST(i),len);\ /* actually copy the data to make sure possible modifications \ on the argv data does not backfire into perl */ \ argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \ strcpy(argv[i+1],handle); \ } \ optind=0; opterr=0; \ rrd_clear_error();\ RETVAL=name(items+1,argv); \ for (i=0; i < items; i++) {\ free(argv[i+1]);\ } \ free(argv);\ \ if (rrd_test_error()) XSRETURN_UNDEF; #ifdef WIN32 #define free free #define malloc malloc #define realloc realloc #endif /*WIN32*/ MODULE = RRDs PACKAGE = RRDs PREFIX = rrd_ BOOT: #ifdef MUST_DISABLE_SIGFPE signal(SIGFPE,SIG_IGN); #endif #ifdef MUST_DISABLE_FPMASK fpsetmask(0); #endif SV* rrd_error() CODE: if (! rrd_test_error()) XSRETURN_UNDEF; RETVAL = newSVpv(rrd_get_error(),0); OUTPUT: RETVAL int rrd_last(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_last); OUTPUT: RETVAL int rrd_create(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_create); RETVAL = 1; OUTPUT: RETVAL int rrd_update(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_update); RETVAL = 1; OUTPUT: RETVAL int rrd_tune(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_tune); RETVAL = 1; OUTPUT: RETVAL void rrd_graph(...) PROTOTYPE: @ PREINIT: char **calcpr=NULL; int i,xsize,ysize; char **argv; AV *retar; PPCODE: argv = (char **) malloc((items+1)*sizeof(char *)); argv[0] = "dummy"; for (i = 0; i < items; i++) { STRLEN len; char *handle = SvPV(ST(i),len); /* actually copy the data to make sure possible modifications on the argv data does not backfire into perl */ argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } optind=0; opterr=0; rrd_clear_error(); rrd_graph(items+1,argv,&calcpr,&xsize,&ysize); for (i=0; i < items; i++) { free(argv[i+1]); } free(argv); if (rrd_test_error()) { if(calcpr) for(i=0;calcpr[i];i++) free(calcpr[i]); XSRETURN_UNDEF; } retar=newAV(); if(calcpr){ for(i=0;calcpr[i];i++){ av_push(retar,newSVpv(calcpr[i],0)); free(calcpr[i]); } free(calcpr); } EXTEND(sp,4); PUSHs(sv_2mortal(newRV_noinc((SV*)retar))); PUSHs(sv_2mortal(newSViv(xsize))); PUSHs(sv_2mortal(newSViv(ysize))); void rrd_fetch(...) PROTOTYPE: @ PREINIT: time_t start,end; unsigned long step, ds_cnt,i,ii; rrd_value_t *data,*datai; char **argv; char **ds_namv; AV *retar,*line,*names; PPCODE: argv = (char **) malloc((items+1)*sizeof(char *)); argv[0] = "dummy"; for (i = 0; i < items; i++) { STRLEN len; char *handle= SvPV(ST(i),len); /* actually copy the data to make sure possible modifications on the argv data does not backfire into perl */ argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } optind=0; opterr=0; rrd_clear_error(); rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); for (i=0; i < items; i++) { free(argv[i+1]); } free(argv); if (rrd_test_error()) XSRETURN_UNDEF; /* convert the ds_namv into perl format */ names=newAV(); for (ii = 0; ii < ds_cnt; ii++){ av_push(names,newSVpv(ds_namv[ii],0)); free(ds_namv[ii]); } free(ds_namv); /* convert the data array into perl format */ datai=data; retar=newAV(); for (i = start; i <= end; i += step){ line = newAV(); for (ii = 0; ii < ds_cnt; ii++){ av_push(line,(isnan(*datai) ? &PL_sv_undef : newSVnv(*datai))); datai++; } av_push(retar,newRV_noinc((SV*)line)); } free(data); EXTEND(sp,5); PUSHs(sv_2mortal(newSViv(start))); PUSHs(sv_2mortal(newSViv(step))); PUSHs(sv_2mortal(newRV_noinc((SV*)names))); PUSHs(sv_2mortal(newRV_noinc((SV*)retar))); int rrd_xport(...) PROTOTYPE: @ PREINIT: time_t start,end; int xsize; unsigned long step, col_cnt,row_cnt,i,ii; rrd_value_t *data,*ptr; char **argv; char **legend_v; AV *retar,*line,*names; PPCODE: argv = (char **) malloc((items+1)*sizeof(char *)); argv[0] = "dummy"; for (i = 0; i < items; i++) { STRLEN len; char *handle = SvPV(ST(i),len); /* actually copy the data to make sure possible modifications on the argv data does not backfire into perl */ argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } optind=0; opterr=0; rrd_clear_error(); rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); for (i=0; i < items; i++) { free(argv[i+1]); } free(argv); if (rrd_test_error()) XSRETURN_UNDEF; /* convert the legend_v into perl format */ names=newAV(); for (ii = 0; ii < col_cnt; ii++){ av_push(names,newSVpv(legend_v[ii],0)); free(legend_v[ii]); } free(legend_v); /* convert the data array into perl format */ ptr=data; retar=newAV(); for (i = start; i < end; i += step){ line = newAV(); for (ii = 0; ii < col_cnt; ii++){ av_push(line,(isnan(*ptr) ? &PL_sv_undef : newSVnv(*ptr))); ptr++; } av_push(retar,newRV_noinc((SV*)line)); } free(data); EXTEND(sp,7); PUSHs(sv_2mortal(newSViv(start))); PUSHs(sv_2mortal(newSViv(end))); PUSHs(sv_2mortal(newSViv(step))); PUSHs(sv_2mortal(newSViv(col_cnt))); PUSHs(sv_2mortal(newRV_noinc((SV*)names))); PUSHs(sv_2mortal(newRV_noinc((SV*)retar))); SV* rrd_info(...) PROTOTYPE: @ PREINIT: info_t *data,*save; int i; char **argv; HV *hash; CODE: /* prepare argument list */ argv = (char **) malloc((items+1)*sizeof(char *)); argv[0] = "dummy"; for (i = 0; i < items; i++) { STRLEN len; char *handle= SvPV(ST(i),len); /* actually copy the data to make sure possible modifications on the argv data does not backfire into perl */ argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); strcpy(argv[i+1],handle); } optind=0; opterr=0; rrd_clear_error(); data=rrd_info(items+1, argv); for (i=0; i < items; i++) { free(argv[i+1]); } free(argv); if (rrd_test_error()) XSRETURN_UNDEF; hash = newHV(); while (data) { save=data; /* the newSV will get copied by hv so we create it as a mortal to make sure it does not keep hanging round after the fact */ #define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0) switch (data->type) { case RD_I_VAL: if (isnan(data->value.u_val)) hvs(&PL_sv_undef); else hvs(newSVnv(data->value.u_val)); break; case RD_I_CNT: hvs(newSViv(data->value.u_cnt)); break; case RD_I_STR: hvs(newSVpv(data->value.u_str,0)); free(data->value.u_str); break; } #undefine hvs free(data->key); data = data->next; free(save); } free(data); RETVAL = newRV_noinc((SV*)hash); OUTPUT: RETVAL void rrd_times(start, end) char *start char *end PREINIT: struct rrd_time_value start_tv, end_tv; char *parsetime_error = NULL; time_t start_tmp, end_tmp; PPCODE: rrd_clear_error(); if( (parsetime_error = parsetime( start, &start_tv))) { rrd_set_error( "start time: %s", parsetime_error); XSRETURN_UNDEF; } if( (parsetime_error = parsetime( end, &end_tv))) { rrd_set_error( "end time: %s", parsetime_error); XSRETURN_UNDEF; } if( proc_start_end( &start_tv, &end_tv, &start_tmp, &end_tmp) == -1) { XSRETURN_UNDEF; } EXTEND(sp,2); PUSHs(sv_2mortal(newSViv(start_tmp))); PUSHs(sv_2mortal(newSViv(end_tmp))); int rrd_dump(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_dump); RETVAL = 1; OUTPUT: RETVAL int rrd_restore(...) PROTOTYPE: @ PREINIT: int i; char **argv; CODE: rrdcode(rrd_restore); RETVAL = 1; OUTPUT: RETVAL