/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.51 from the
 * contents of RRDs.xs. Do not edit this file, edit RRDs.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "RRDs.xs"
#ifdef __cplusplus
extern "C" {
#endif

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#ifdef __cplusplus
}
#endif

/*
 * rrd_tool.h includes config.h, but at least on Ubuntu Breezy Badger
 * 5.10 with gcc 4.0.2, the C preprocessor picks up Perl's config.h
 * which is included from the Perl includes and never reads rrdtool's
 * config.h.  Without including rrdtool's config.h, this module does
 * not compile, so include it here with an explicit path.
 *
 * Because rrdtool's config.h redefines VERSION which is originally
 * set via Perl's Makefile.PL and passed down to the C compiler's
 * command line, save the original value and reset it after the
 * includes.
 */
#define VERSION_SAVED VERSION
#undef VERSION
#ifndef _WIN32
#include "rrd_config.h"
#endif
#include "rrd_tool.h"
#undef VERSION
#define VERSION VERSION_SAVED
#undef VERSION_SAVED

#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); \
 	        } \
		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;

#define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0)

#define rrdinfocode(name) \
		/* 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); \
 	        } \
                rrd_clear_error(); \
                data=name(items+1, argv); \
                for (i=0; i < items; i++) { \
		    free(argv[i+1]); \
		} \
		free(argv); \
                if (rrd_test_error()) XSRETURN_UNDEF; \
                hash = newHV(); \
   	        save=data; \
                while (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 */ \
		    switch (data->type) { \
		    case RD_I_VAL: \
			if (isnan(data->value.u_val)) \
			    hvs(newSV(0)); \
			else \
			    hvs(newSVnv(data->value.u_val)); \
			break; \
			case RD_I_INT: \
			hvs(newSViv(data->value.u_int)); \
			break; \
		    case RD_I_CNT: \
			hvs(newSViv(data->value.u_cnt)); \
			break; \
		    case RD_I_STR: \
			hvs(newSVpv(data->value.u_str,0)); \
			break; \
		    case RD_I_BLO: \
			hvs(newSVpv((char *)data->value.u_blo.ptr,data->value.u_blo.size)); \
			break; \
		    } \
		    data = data->next; \
	        } \
            rrd_info_free(save); \
            RETVAL = newRV_noinc((SV*)hash);

/*
 * should not be needed if libc is linked (see ntmake.pl)
#ifdef _WIN32
 #define free free
 #define malloc malloc
 #define realloc realloc
#endif
*/


static SV * rrd_fetch_cb_svptr = (SV*)NULL;

static int rrd_fetch_cb_wrapper(
    const char     *filename,  /* name of the rrd */
    enum cf_en     cf_idx, /* consolidation function */
    time_t         *start,
    time_t         *end,       /* which time frame do you want ?
                                * will be changed to represent reality */
    unsigned long  *step,      /* which stepsize do you want?
                                * will be changed to represent reality */
    unsigned long  *ds_cnt,    /* number of data sources in file */
    char           ***ds_namv, /* names of data_sources */
    rrd_value_t    **data)     /* two dimensional array containing the data */
  {
    dSP;
    HV *callHV;
    SV *retSV;
    HV *retHV;
    HE *retHE;
    AV *retAV;
    time_t new_start;
    char *cfStr = NULL;
    unsigned long i,ii;
    unsigned long rowCount = 0;
    if (!rrd_fetch_cb_svptr){
        rrd_set_error("Use RRDs::register_fetch_cb to register a fetch callback.");
        return -1;
    }

    ENTER;
    SAVETMPS;
    /* prepare the arguments */
    callHV = newHV();
    hv_store_ent(callHV, sv_2mortal(newSVpv("filename",0)),newSVpv(filename,0),0);
    switch(cf_idx){
        case CF_AVERAGE:
            cfStr = "AVERAGE";
            break;
        case CF_MINIMUM:
            cfStr = "MIN";
            break;
        case CF_MAXIMUM:
            cfStr = "MAX";
            break;
        case CF_LAST:
            cfStr = "LAST";
        default:
            break;
    }
    hv_store_ent(callHV, sv_2mortal(newSVpv("cd",0)),newSVpv(cfStr,0),0);
    hv_store_ent(callHV, sv_2mortal(newSVpv("start",0)),newSVuv(*start),0);
    hv_store_ent(callHV, sv_2mortal(newSVpv("end",0)),newSVuv(*end),0);
    hv_store_ent(callHV, sv_2mortal(newSVpv("step",0)),newSVuv(*step),0);
    PUSHMARK(SP);
    XPUSHs(newRV_noinc((SV *)callHV));
    PUTBACK;
    /* Call the Perl sub to process the callback */
    call_sv(rrd_fetch_cb_svptr , G_EVAL|G_SCALAR);
    SPAGAIN;
    /* Check the eval first */
    if (SvTRUE(ERRSV)) {
        rrd_set_error("perl callback failed: %s",SvPV_nolen(ERRSV));
        POPs; /* there is undef on top of the stack when there is an error
                 and call_sv was initiated with G_EVAL|G_SCALER */
        goto error_out;
    }
    retSV = POPs;
    if (!SvROK(retSV)){
        rrd_set_error("Expected the perl callback function to return a reference");
        goto error_out;
    }
    retHV = (HV*)SvRV(retSV);
    if (SvTYPE(retHV) != SVt_PVHV) {
        rrd_set_error("Expected the perl callback function to return a hash reference");
        goto error_out;
    }

#define loadRet(hashKey) \
    if (( retHE = hv_fetch_ent(retHV,sv_2mortal(newSVpv(hashKey,0)),0,0)) == NULL){ \
        rrd_set_error("Expected the perl callback function to return a '" hashKey "' value"); \
        goto error_out; }

    loadRet("step");
    *step = SvIV(HeVAL(retHE));
    if (*step <= 0){
        rrd_set_error("Expected the perl callback function to return a valid step value");
        goto error_out;
    }

    loadRet("start");
    new_start = SvIV(HeVAL(retHE));
    if (new_start == 0 || new_start > *start){
        rrd_set_error("Expected the perl callback function to return a start value equal or earlier than %lld but got %lld",(long long int)(*start),(long long int)(new_start));
        goto error_out;
    }

    *start = new_start;
/*    rowCount = ((*end - *start) / *step); */

    /* figure out how long things are so that we can allocate the memory */
    loadRet("data");
    retSV = HeVAL(retHE);
    if (!SvROK(retSV)){
        rrd_set_error("Expected the perl callback function to return a valid data element");
        goto error_out;
    }
    retHV = (HV*)SvRV(retSV);
    if (SvTYPE(retHV) != SVt_PVHV){
        rrd_set_error("Expected the perl callback function to return data element pointing to a hash");
        goto error_out;
    }

    *ds_cnt = hv_iterinit(retHV);

    if (((*ds_namv) = (char **) calloc( *ds_cnt , sizeof(char *))) == NULL) {
        rrd_set_error("Failed to allocate memory for ds_namev when returning from perl callback");
        goto error_out;
    }
    for (i=0;i<*ds_cnt;i++){
        char *retKey;
        I32 retKeyLen;
        HE* hash_entry;
        hash_entry = hv_iternext(retHV);
        retKey = hv_iterkey(hash_entry,&retKeyLen);
	if (strlen(retKey) >= DS_NAM_SIZE){
            rrd_set_error("Key '%s' longer than the allowed maximum of %d byte",retKey,DS_NAM_SIZE-1);
            goto error_out;
	}

        if ((((*ds_namv)[i]) = (char*)malloc(sizeof(char) * DS_NAM_SIZE)) == NULL) {
            rrd_set_error("malloc fetch ds_namv entry");
            goto error_out_free_ds_namv;
        }

        strncpy((*ds_namv)[i], retKey, DS_NAM_SIZE - 1);
        (*ds_namv)[i][DS_NAM_SIZE - 1] = '\0';
        retSV = hv_iterval(retHV,hash_entry);
        if (!SvROK(retSV)){
            rrd_set_error("Expected the perl callback function to return an array pointer for {data}->{%s}",(*ds_namv)[i]);
            goto error_out_free_ds_namv;
        }
        retAV = (AV*)SvRV(retSV);
        if (SvTYPE(retAV) != SVt_PVAV){
            rrd_set_error("Expected the perl callback function to return an array pointer for {data}->{%s}",(*ds_namv)[i]);
            goto error_out_free_ds_namv;
        }
        if (av_len(retAV)+1 > rowCount)
            rowCount = av_len(retAV)+1;
    }

    *end = *start + *step * rowCount;

    if (((*data) = (rrd_value_t*)malloc(*ds_cnt * rowCount * sizeof(rrd_value_t))) == NULL) {
        rrd_set_error("malloc fetch data area");
        goto error_out_free_ds_namv;
    }

    for (i=0;i<*ds_cnt;i++){
        retAV = (AV*)SvRV(HeVAL(hv_fetch_ent(retHV,sv_2mortal(newSVpv((*ds_namv)[i],0)),0,0)));
        for (ii=0;ii<rowCount;ii++){
            SV** valP = av_fetch(retAV,ii,0);
            SV* val = valP ? *valP : &PL_sv_undef;
            (*data)[i + ii * (*ds_cnt)] = SvNIOK(val) ? SvNVx(val) : DNAN;
        }
    }


    PUTBACK;
    FREETMPS;
    LEAVE;
    return 1;

    error_out_free_ds_namv:

    for (i = 0; i < *ds_cnt; ++i){
        if ((*ds_namv)[i]){
            free((*ds_namv)[i]);
        }
    }

    free(*ds_namv);

    error_out:
    PUTBACK;
    FREETMPS;
    LEAVE;
    return -1;

    /* prepare return data */
}


#line 318 "RRDs.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#line 462 "RRDs.c"

XS_EUPXS(XS_RRDs_error); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_error)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
	SV *	RETVAL;
#line 321 "RRDs.xs"
		if (! rrd_test_error()) XSRETURN_UNDEF;
                RETVAL = newSVpv(rrd_get_error(),0);
#line 475 "RRDs.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_last); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_last)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 330 "RRDs.xs"
      int i;
      char **argv;
#line 493 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 333 "RRDs.xs"
              rrdcode(rrd_last);
#line 498 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_first); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_first)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 341 "RRDs.xs"
      int i;
      char **argv;
#line 516 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 344 "RRDs.xs"
              rrdcode(rrd_first);
#line 521 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_create); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_create)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 352 "RRDs.xs"
        int i;
	char **argv;
#line 539 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 355 "RRDs.xs"
		rrdcode(rrd_create);
	        RETVAL = 1;
#line 545 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_update); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_update)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 364 "RRDs.xs"
        int i;
	char **argv;
#line 563 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 367 "RRDs.xs"
		rrdcode(rrd_update);
       	        RETVAL = 1;
#line 569 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_tune); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_tune)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 376 "RRDs.xs"
        int i;
	char **argv;
#line 587 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 379 "RRDs.xs"
		rrdcode(rrd_tune);
       	        RETVAL = 1;
#line 593 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#ifdef HAVE_RRD_GRAPH
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_RRDs_graph); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_graph)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 390 "RRDs.xs"
	char **calcpr=NULL;
	int i,xsize,ysize;
	double ymin,ymax;
	char **argv;
	AV *retar;
#line 619 "RRDs.c"
	SV *	RETVAL;
#line 396 "RRDs.xs"
		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);
 	        }
		rrd_clear_error();
		rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL,&ymin,&ymax);
		for (i=0; i < items; i++) {
		    free(argv[i+1]);
		}
		free(argv);

		if (rrd_test_error()) {
			if(calcpr) {
			   for(i=0;calcpr[i];i++)
				rrd_freemem(calcpr[i]);
                           rrd_freemem(calcpr);
                        }
			XSRETURN_UNDEF;
		}
		retar=newAV();
		if(calcpr){
			for(i=0;calcpr[i];i++){
				 av_push(retar,newSVpv(calcpr[i],0));
				 rrd_freemem(calcpr[i]);
			}
			rrd_freemem(calcpr);
		}
		EXTEND(sp,4);
		PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
		PUSHs(sv_2mortal(newSViv(xsize)));
		PUSHs(sv_2mortal(newSViv(ysize)));
#line 659 "RRDs.c"
	PUTBACK;
	return;
    }
}

#endif /* HAVE_RRD_GRAPH */

XS_EUPXS(XS_RRDs_fetch); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_fetch)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 440 "RRDs.xs"
		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;
#line 683 "RRDs.c"
	SV *	RETVAL;
#line 447 "RRDs.xs"
		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);
 	        }
		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));
		    rrd_freemem(ds_namv[ii]);
		}
		rrd_freemem(ds_namv);
		/* convert the data array into perl format */
		datai=data;
		retar=newAV();
		for (i = start+step; i <= end; i += step){
			line = newAV();
			for (ii = 0; ii < ds_cnt; ii++){
 			  av_push(line,(isnan(*datai) ? newSV(0) : newSVnv(*datai)));
			  datai++;
			}
			av_push(retar,newRV_noinc((SV*)line));
		}
		rrd_freemem(data);
		EXTEND(sp,5);
		PUSHs(sv_2mortal(newSViv(start+step)));
		PUSHs(sv_2mortal(newSViv(step)));
		PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
		PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
#line 727 "RRDs.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_RRDs_fetch_cb_register); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_fetch_cb_register)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "cb");
    {
	SV *	cb = ST(0)
;
	SV *	RETVAL;
#line 493 "RRDs.xs"
        if (rrd_fetch_cb_svptr == (SV*)NULL )
            rrd_fetch_cb_svptr = newSVsv(cb);
        else
            SvSetSV(rrd_fetch_cb_svptr,cb);
        rrd_fetch_cb_register(rrd_fetch_cb_wrapper);
#line 750 "RRDs.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_times); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_times)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "start, end");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	char *	start = (char *)SvPV_nolen(ST(0))
;
	char *	end = (char *)SvPV_nolen(ST(1))
;
#line 504 "RRDs.xs"
		rrd_time_value_t start_tv, end_tv;
		char    *parsetime_error = NULL;
		time_t	start_tmp, end_tmp;
#line 773 "RRDs.c"
	SV *	RETVAL;
#line 508 "RRDs.xs"
		rrd_clear_error();
		if ((parsetime_error = rrd_parsetime(start, &start_tv))) {
			rrd_set_error("start time: %s", parsetime_error);
			XSRETURN_UNDEF;
		}
		if ((parsetime_error = rrd_parsetime(end, &end_tv))) {
			rrd_set_error("end time: %s", parsetime_error);
			XSRETURN_UNDEF;
		}
		if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
			XSRETURN_UNDEF;
		}
		EXTEND(sp,2);
		PUSHs(sv_2mortal(newSVuv(start_tmp)));
		PUSHs(sv_2mortal(newSVuv(end_tmp)));
#line 791 "RRDs.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_RRDs_xport); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_xport)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 528 "RRDs.xs"
                time_t start,end;
                int xsize;
		unsigned long step, col_cnt,i,ii;
		rrd_value_t *data,*ptr;
                char **argv,**legend_v;
		AV *retar,*line,*names;
#line 814 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 535 "RRDs.xs"
		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);
 	        }
		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));
		    rrd_freemem(legend_v[ii]);
		}
		rrd_freemem(legend_v);

		/* convert the data array into perl format */
		ptr=data;
		retar=newAV();
		for (i = start+step; i <= end; i += step){
			line = newAV();
			for (ii = 0; ii < col_cnt; ii++){
 			  av_push(line,(isnan(*ptr) ? newSV(0) : newSVnv(*ptr)));
			  ptr++;
			}
			av_push(retar,newRV_noinc((SV*)line));
		}
		rrd_freemem(data);

		EXTEND(sp,7);
		PUSHs(sv_2mortal(newSViv(start+step)));
		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)));
#line 864 "RRDs.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_RRDs_info); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_info)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 586 "RRDs.xs"
		rrd_info_t *data,*save;
                int i;
                char **argv;
		HV *hash;
#line 883 "RRDs.c"
	SV *	RETVAL;
#line 591 "RRDs.xs"
		rrdinfocode(rrd_info);
#line 887 "RRDs.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_updatev); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_updatev)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 599 "RRDs.xs"
		rrd_info_t *data,*save;
                int i;
                char **argv;
		HV *hash;
#line 907 "RRDs.c"
	SV *	RETVAL;
#line 604 "RRDs.xs"
		rrdinfocode(rrd_update_v);
#line 911 "RRDs.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}

#ifdef HAVE_RRD_GRAPH
#define XSubPPtmpAAAB 1


XS_EUPXS(XS_RRDs_graphv); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_graphv)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 614 "RRDs.xs"
		rrd_info_t *data,*save;
                int i;
                char **argv;
		HV *hash;
#line 934 "RRDs.c"
	SV *	RETVAL;
#line 619 "RRDs.xs"
		rrdinfocode(rrd_graph_v);
#line 938 "RRDs.c"
	RETVAL = sv_2mortal(RETVAL);
	ST(0) = RETVAL;
    }
    XSRETURN(1);
}

#endif /* HAVE_RRD_GRAPH */

XS_EUPXS(XS_RRDs_dump); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_dump)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 629 "RRDs.xs"
        int i;
       char **argv;
#line 957 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 632 "RRDs.xs"
               rrdcode(rrd_dump);
                       RETVAL = 1;
#line 963 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_restore); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_restore)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 641 "RRDs.xs"
        int i;
       char **argv;
#line 981 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 644 "RRDs.xs"
               rrdcode(rrd_restore);
                       RETVAL = 1;
#line 987 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_flushcached); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_flushcached)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    {
#line 653 "RRDs.xs"
	int i;
	char **argv;
#line 1005 "RRDs.c"
	int	RETVAL;
	dXSTARG;
#line 656 "RRDs.xs"
		rrdcode(rrd_flushcached);
#line 1010 "RRDs.c"
	XSprePUSH;
	PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_RRDs_list); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_RRDs_list)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 664 "RRDs.xs"
                char *data;
                char *ptr, *end;
                int i;
                char **argv;
		AV *list;
#line 1033 "RRDs.c"
	SV *	RETVAL;
#line 670 "RRDs.xs"
		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);
		}

                rrd_clear_error();

		data = rrd_list(items+1, argv);

                for (i=0; i < items; i++) {
		    free(argv[i+1]);
		}
		free(argv);

                if (rrd_test_error())
		    XSRETURN_UNDEF;

		list = newAV();

		ptr = data;
		end = strchr(ptr, '\n');

		while (end) {
		    *end = '\0';
		    av_push(list, newSVpv(ptr, 0));
		    ptr = end + 1;

		    if (strlen(ptr) == 0)
			    break;

		    end = strchr(ptr, '\n');
		}

		rrd_freemem(data);

		XPUSHs(sv_2mortal(newRV_noinc((SV*)list)));
#line 1079 "RRDs.c"
	PUTBACK;
	return;
    }
}

#ifdef __cplusplus
extern "C" {
#endif
XS_EXTERNAL(boot_RRDs); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_RRDs)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if PERL_VERSION_LE(5, 8, 999) /* PERL_VERSION_LT is 5.33+ */
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

        newXS_deffile("RRDs::error", XS_RRDs_error);
        (void)newXSproto_portable("RRDs::last", XS_RRDs_last, file, "@");
        (void)newXSproto_portable("RRDs::first", XS_RRDs_first, file, "@");
        (void)newXSproto_portable("RRDs::create", XS_RRDs_create, file, "@");
        (void)newXSproto_portable("RRDs::update", XS_RRDs_update, file, "@");
        (void)newXSproto_portable("RRDs::tune", XS_RRDs_tune, file, "@");
#if XSubPPtmpAAAA
        (void)newXSproto_portable("RRDs::graph", XS_RRDs_graph, file, "@");
#endif
        (void)newXSproto_portable("RRDs::fetch", XS_RRDs_fetch, file, "@");
        newXS_deffile("RRDs::fetch_cb_register", XS_RRDs_fetch_cb_register);
        newXS_deffile("RRDs::times", XS_RRDs_times);
        (void)newXSproto_portable("RRDs::xport", XS_RRDs_xport, file, "@");
        (void)newXSproto_portable("RRDs::info", XS_RRDs_info, file, "@");
        (void)newXSproto_portable("RRDs::updatev", XS_RRDs_updatev, file, "@");
#if XSubPPtmpAAAB
        (void)newXSproto_portable("RRDs::graphv", XS_RRDs_graphv, file, "@");
#endif
        (void)newXSproto_portable("RRDs::dump", XS_RRDs_dump, file, "@");
        (void)newXSproto_portable("RRDs::restore", XS_RRDs_restore, file, "@");
        (void)newXSproto_portable("RRDs::flushcached", XS_RRDs_flushcached, file, "@");
        (void)newXSproto_portable("RRDs::list", XS_RRDs_list, file, "@");

    /* Initialisation Section */

#line 311 "RRDs.xs"
#ifdef MUST_DISABLE_SIGFPE
	signal(SIGFPE,SIG_IGN);
#endif
#ifdef MUST_DISABLE_FPMASK
	fpsetmask(0);
#endif

#if XSubPPtmpAAAA
#endif
#if XSubPPtmpAAAB
#endif
#line 1150 "RRDs.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

#ifdef __cplusplus
}
#endif
