Your IP : 216.73.216.215


Current Path : /proc/self/root/home/.cpan/build/CDB_File-1.02-9tBhNy/
Upload File :
Current File : //proc/self/root/home/.cpan/build/CDB_File-1.02-9tBhNy/CDB_File.c

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

#line 1 "CDB_File.xs"
/*

Most of this is reasonably straightforward.  The complications arise
when we are "iterating" over the CDB file, that is to say, using `keys'
or `values' or `each' to retrieve all the data in the file in order.
This interface stores extra data to allow us to track iterations: end
is a pointer to the end of data in the CDB file, and also a flag which
indicates whether we are iterating or not (note that the end of data
occurs at a position >= 2048); curkey is a copy of the current key;
curpos is the file offset of curkey; and fetch_advance is 0 for

    FIRSTKEY, fetch, NEXTKEY, fetch, NEXTKEY, fetch, ...

but 1 for

    FIRSTKEY, NEXTKEY, NEXTKEY, ..., fetch, fetch, fetch, ...

Don't tell the OO Police, but there are actually two different objects
called CDB_File.  One is created by TIEHASH, and accessed by the usual
tied hash methods (FETCH, FIRSTKEY, etc.).  The other is created by new,
and accessed by insert and finish.

In both cases, the object is a blessed reference to a scalar.  The
scalar contains either a struct cdbobj or a struct cdbmakeobj.

It gets a little messy in DESTROY: since this method will automatically
be called for both sorts of object, it distinguishes them by their
different sizes.

*/

#ifdef __cplusplus
extern "C" {
#endif

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

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#ifdef WIN32
#define fsync _commit
#endif

#ifdef HASMMAP
#include <sys/mman.h>
#endif

/* We need to whistle up an error number for a file that is not a CDB
file.  The BSDish EFTYPE probably gives the most useful error message;
failing that we'll settle for the Single Unix Specification v2 EPROTO;
and finally the rather inappropriate, but universally(?) implemented,
EINVAL. */
#ifdef EFTYPE
#else
#ifdef EPROTO
#define EFTYPE EPROTO
#else
#define EFTYPE EINVAL
#endif
#endif

#ifdef __cplusplus
}
#endif

#define MIN_PERL_VERSION_FOR_COW  20
#if PERL_REVISION >= 5 && PERL_VERSION >= MIN_PERL_VERSION_FOR_COW
#   define CDB_CAN_COW 1
#else
#   define CDB_CAN_COW 0
#endif

#if CDB_CAN_COW
#	define CDB_DO_COW(sv) STMT_START { SvIsCOW_on(sv); CowREFCNT(sv) = 1; } STMT_END
#else
#	define CDB_DO_COW(sv)
#endif

#define CDB_SET_PV(sv, len) STMT_START { \
		(void) SvPOK_only(sv); \
		SvGROW(sv, len + 2); \
		SvCUR_set(sv,  len); \
		CDB_DO_COW(sv); \
		SvPV(sv, PL_na)[len] = '\0'; \
} STMT_END

struct t_cdb {
	PerlIO *fh;   /* */

#ifdef HASMMAP
	char *map;
#endif

	U32 end;    /* If non zero, the file offset of the first byte of hash tables. */
	SV *curkey; /* While iterating: a copy of the current key; */
	U32 curpos; /*                  the file offset of the current record. */
	int fetch_advance; /* the kludge */
	U32 size; /* initialized if map is nonzero */
	U32 loop; /* number of hash slots searched under this key */
	U32 khash; /* initialized if loop is nonzero */
	U32 kpos; /* initialized if loop is nonzero */
	U32 hpos; /* initialized if loop is nonzero */
	U32 hslots; /* initialized if loop is nonzero */
	U32 dpos; /* initialized if cdb_findnext() returns 1 */
	U32 dlen; /* initialized if cdb_findnext() returns 1 */
} ;

typedef struct t_cdb  cdb;

#define CDB_HPLIST 1000

struct cdb_hp { U32 h; U32 p; } ;

struct cdb_hplist {
	struct cdb_hp hp[CDB_HPLIST];
	struct cdb_hplist *next;
	int num;
} ;

struct t_cdb_make {
	PerlIO *f;            /* Handle of file being created. */
	char *fn;             /* Final name of file. */
	char *fntemp;         /* Temporary name of file. */
	char final[2048];
	char bspace[1024];
	U32 count[256];
	U32 start[256];
	struct cdb_hplist *head;
	struct cdb_hp *split; /* includes space for hash */
	struct cdb_hp *hash;
	U32 numentries;
	U32 pos;
	int fd;
} ;

typedef struct t_cdb_make cdb_make;

static void writeerror() { croak("Write to CDB_File failed: %s", Strerror(errno)); }

static void readerror() { croak("Read of CDB_File failed: %s", Strerror(errno)); }

static void seekerror() { croak("Seek in CDB_File failed: %s", Strerror(errno)); }

static void nomem() { croak("Out of memory!"); }

static int cdb_make_start(cdb_make *c) {
	c->head = 0;
	c->split = 0;
	c->hash = 0;
	c->numentries = 0;
	c->pos = sizeof c->final;
	return PerlIO_seek(c->f, c->pos, SEEK_SET);
}

static int posplus(cdb_make *c, U32 len) {
	U32 newpos = c->pos + len;
	if (newpos < len) { errno = ENOMEM; return -1; }
	c->pos = newpos;
	return 0;
}

static int cdb_make_addend(cdb_make *c, unsigned int keylen, unsigned int datalen, U32 h) {
	struct cdb_hplist *head;

	head = c->head;
	if (!head || (head->num >= CDB_HPLIST)) {
		New(0xCDB, head, 1, struct cdb_hplist);
		head->num = 0;
		head->next = c->head;
		c->head = head;
	}
	head->hp[head->num].h = h;
	head->hp[head->num].p = c->pos;
	++head->num;
	++c->numentries;
	if (posplus(c, 8) == -1) return -1;
	if (posplus(c, keylen) == -1) return -1;
	if (posplus(c, datalen) == -1) return -1;
	return 0;
}

#define CDB_HASHSTART 5381

#define cdb_hashadd(hh, cc) ((hh + (hh << 5)) ^ cc)

static U32 cdb_hash(char *buf, unsigned int len) {
	U32 h;

	h = CDB_HASHSTART;
	while (len) {
		h = cdb_hashadd(h,*buf++);
		--len;
	}
	return h;
}

static void uint32_pack(char s[4], U32 u) {
	s[0] = u & 255;
	u >>= 8;
	s[1] = u & 255;
	u >>= 8;
	s[2] = u & 255;
	s[3] = u >> 8;
}

static void uint32_unpack(char s[4], U32 *u) {
	U32 result;

	result = (unsigned char) s[3];
	result <<= 8;
	result += (unsigned char) s[2];
	result <<= 8;
	result += (unsigned char) s[1];
	result <<= 8;
	result += (unsigned char) s[0];

	*u = result;
}

static void cdb_findstart(cdb *c) {
	c->loop = 0;
}

static int cdb_read(cdb *c, char *buf, unsigned int len, U32 pos) {

#ifdef HASMMAP
	if (c->map) {
		if ((pos > c->size) || (c->size - pos < len)) {
			errno = EFTYPE;
			return -1;
		}
		memcpy(buf, c->map + pos, len);
		return 0;
	}
#endif

	if (PerlIO_seek(c->fh, pos, SEEK_SET) == -1) return -1;
	while (len > 0) {
		int r;
		do
			r = PerlIO_read(c->fh, buf, len);
		while ((r == -1) && (errno == EINTR));
		if (r == -1) return -1;
		if (r == 0) {
			errno = EFTYPE;
			return -1;
		}
		buf += r;
		len -= r;
	}
	return 0;
}

static int match(cdb *c,char *key,unsigned int len, U32 pos) {
	char buf[32];
	int n;

	while (len > 0) {
		n = sizeof buf;
		if (n > len) n = len;
		if (cdb_read(c, buf, n, pos) == -1) return -1;
		if (memcmp(buf, key, n)) return 0;
		pos += n;
		key += n;
		len -= n;
	}
	return 1;
}

static int cdb_findnext(cdb *c,char *key,unsigned int len) {
	char buf[8];
	U32 pos;
	U32 u;

  /* Matt: reset these so if a search fails they are zero'd */
  c->dpos = 0;
  c->dlen = 0;
  if (!c->loop) {
    u = cdb_hash(key,len);
    if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
    uint32_unpack(buf + 4,&c->hslots);
    if (!c->hslots) return 0;
    uint32_unpack(buf,&c->hpos);
    c->khash = u;
    u >>= 8;
    u %= c->hslots;
    u <<= 3;
    c->kpos = c->hpos + u;
  }

  while (c->loop < c->hslots) {
    if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
    uint32_unpack(buf + 4,&pos);
    if (!pos) return 0;
    c->loop += 1;
    c->kpos += 8;
    if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
    uint32_unpack(buf,&u);
    if (u == c->khash) {
      if (cdb_read(c,buf,8,pos) == -1) return -1;
      uint32_unpack(buf,&u);
      if (u == len)
	switch(match(c,key,len,pos + 8)) {
	  case -1:
	    return -1;
	  case 1:
	    uint32_unpack(buf + 4,&c->dlen);
	    c->dpos = pos + 8 + len;
	    return 1;
	}
    }
  }

  return 0;
}

static int cdb_find(cdb *c, char *key, unsigned int len) {
  cdb_findstart(c);
  return cdb_findnext(c,key,len);
}

static void iter_start(cdb *c) {
	char buf[4];

	c->curpos = 2048;
	if (cdb_read(c, buf, 4, 0) == -1) readerror();
	uint32_unpack(buf, &c->end);
	c->curkey = NEWSV(0xcdb, 1);
	c->fetch_advance = 0;
}

static int iter_key(cdb *c) {
	char buf[8];
	U32 klen;

	if (c->curpos < c->end) {
		if (cdb_read(c, buf, 8, c->curpos) == -1) readerror();
		uint32_unpack(buf, &klen);

		CDB_SET_PV(c->curkey, klen);

		if (cdb_read(c, SvPVX(c->curkey), klen, c->curpos + 8) == -1) readerror();
		return 1;
	}
	return 0;
}

static void iter_advance(cdb *c) {
	char buf[8];
	U32 klen, dlen;

	if (cdb_read(c, buf, 8, c->curpos) == -1) readerror();
	uint32_unpack(buf, &klen);
	uint32_unpack(buf + 4, &dlen);
	c->curpos += 8 + klen + dlen;
}

static void iter_end(cdb *c) {
	if (c->end != 0) {
		c->end = 0;
		SvREFCNT_dec(c->curkey);
	}
}

#define cdb_datapos(c) ((c)->dpos)
#define cdb_datalen(c) ((c)->dlen)

typedef PerlIO * InputStream;

#line 388 "CDB_File.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(pTHX_ const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(pTHX_ 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(aTHX_ "Usage: %s::%s(%s)", hvname, gvname, params);
        else
            Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
        Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#ifdef PERL_IMPLICIT_CONTEXT
#define croak_xs_usage(a,b)    S_croak_xs_usage(aTHX_ a,b)
#else
#define croak_xs_usage        S_croak_xs_usage
#endif

#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) */

#line 530 "CDB_File.c"

XS_EUPXS(XS_CDB_File_handle); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_handle)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "this");
    {
	cdb *	this;
#line 396 "CDB_File.xs"
        GV *gv;
        char *packname;

#line 544 "CDB_File.c"
	InputStream	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_handle() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 400 "CDB_File.xs"
        /* here we dup the filehandle, because perl space will try and close
           it when it goes out of scope */
        RETVAL = PerlIO_fdopen(PerlIO_fileno(this->fh), "r");
#line 558 "CDB_File.c"
	ST(0) = sv_newmortal();
	{
	    GV *gv = newGVgen("CDB_File");
	    if ( do_open(gv, "<&", 2, FALSE, 0, 0, RETVAL) )
		sv_setsv(ST(0), sv_bless(newRV((SV*)gv), gv_stashpv("CDB_File",1)));
	    else
		ST(0) = &PL_sv_undef;
	}
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_datalen); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_datalen)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "db");
    {
	cdb *	db;
	U32	RETVAL;
	dXSTARG;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                db = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_datalen() -- db is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 411 "CDB_File.xs"
	RETVAL = cdb_datalen(db);

#line 593 "CDB_File.c"
	XSprePUSH; PUSHu((UV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_datapos); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_datapos)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "db");
    {
	cdb *	db;
	U32	RETVAL;
	dXSTARG;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                db = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_datapos() -- db is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 421 "CDB_File.xs"
	RETVAL = cdb_datapos(db);

#line 621 "CDB_File.c"
	XSprePUSH; PUSHu((UV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_TIEHASH); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_TIEHASH)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "CLASS, filename");
    {
	char *	CLASS = (char *)SvPV_nolen(ST(0))
;
	char *	filename = (char *)SvPV_nolen(ST(1))
;
#line 432 "CDB_File.xs"
	PerlIO *f;
	IO *io;
	SV *cdbp;

#line 644 "CDB_File.c"
	cdb *	RETVAL;
#line 437 "CDB_File.xs"
        New(0, RETVAL, 1, cdb);
	RETVAL->fh = f = PerlIO_open(filename, "rb");
	if (!f) XSRETURN_NO;
	RETVAL->end = 0;
#ifdef HASMMAP
	{
		struct stat st;
		int fd = PerlIO_fileno(f);

		RETVAL->map = 0;
		if (fstat(fd, &st) == 0) {
			if (st.st_size <= 0xffffffff) {
				char *x;

				x = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
				if (x != (char *)-1) {
					RETVAL->size = st.st_size;
					RETVAL->map = x;
				}
			}
		}
	}
#endif
#line 670 "CDB_File.c"
	ST(0) = sv_newmortal();
        sv_setref_pv( ST(0), CLASS, (void*)RETVAL );
        SvREADONLY_on( SvRV( ST(0) ) );
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_FETCH); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_FETCH)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "this, k");
    {
	cdb *	this;
	SV *	k = ST(1)
;
#line 469 "CDB_File.xs"
	PerlIO *f;
	char buf[8];
	int found;
	off_t pos;
	STRLEN klen, x;
	U32 klen0;
	char *kp;

#line 698 "CDB_File.c"
	SV *	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_FETCH() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 478 "CDB_File.xs"
	if (!SvOK(k)) {
		XSRETURN_UNDEF;
	}
	kp = SvPV(k, klen);
	if (this->end && sv_eq(this->curkey, k)) {
		if (cdb_read(this, buf, 8, this->curpos) == -1) readerror();
		uint32_unpack(buf + 4, &this->dlen);
		this->dpos = this->curpos + 8 + klen;
		if (this->fetch_advance) {
			iter_advance(this);
			if (!iter_key(this)) iter_end(this);
		}
		found = 1;
	} else {
		cdb_findstart(this);
		found = cdb_findnext(this, kp, klen);
		if ((found != 0) && (found != 1)) readerror();
	}
	ST(0) = sv_newmortal();
	if (found) {
		U32 dlen;

		SvUPGRADE(ST(0), SVt_PV);
		dlen = cdb_datalen(this);

		CDB_SET_PV(ST(0), dlen);

		if (cdb_read(this, SvPVX(ST(0)), dlen, cdb_datapos(this)) == -1) readerror();
	}
#line 738 "CDB_File.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_fetch_all); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_fetch_all)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "this");
    {
	cdb *	this;
#line 514 "CDB_File.xs"
	U32 dlen;
	SV *keyvalue;
  int found;
	STRLEN klen;
	char *kp;

#line 759 "CDB_File.c"
	HV *	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_fetch_all() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 521 "CDB_File.xs"
  RETVAL = newHV();
	sv_2mortal((SV *)RETVAL);
  iter_start(this);
	while(iter_key(this)) {
    cdb_findstart(this);
	  kp = SvPV(this->curkey, klen);
		found = cdb_findnext(this, kp, klen);
		if ((found != 0) && (found != 1)) readerror();

		dlen = cdb_datalen(this);

		keyvalue = newSVpvn("", 0);

		CDB_SET_PV(keyvalue, dlen);

		if (cdb_read(this, SvPVX(keyvalue), dlen, cdb_datapos(this)) == -1) readerror();

		if (! hv_store_ent(RETVAL, this->curkey, keyvalue, 0)) {
        SvREFCNT_dec(keyvalue);
    };
		iter_advance(this);
	}
  iter_end(this);

#line 794 "CDB_File.c"
	ST(0) = newRV((SV*)RETVAL);
	sv_2mortal(ST(0));
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_multi_get); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_multi_get)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "this, k");
    {
	cdb *	this;
	SV *	k = ST(1)
;
#line 555 "CDB_File.xs"
	PerlIO *f;
	char buf[8];
	int found;
	off_t pos;
	STRLEN klen;
	U32 dlen, klen0;
	char *kp;
	SV *x;

#line 822 "CDB_File.c"
	AV *	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_multi_get() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 565 "CDB_File.xs"
	if (!SvOK(k)) {
		XSRETURN_UNDEF;
	}
	cdb_findstart(this);
	RETVAL = newAV();
	sv_2mortal((SV *)RETVAL);
	kp = SvPV(k, klen);
	for (;;) {
		found = cdb_findnext(this, kp, klen);
		if ((found != 0) && (found != 1)) readerror();
		if (!found) break;

		dlen = cdb_datalen(this);
		x = newSVpvn("", 0);

		CDB_SET_PV(x, dlen);

		if (cdb_read(this, SvPVX(x), dlen, cdb_datapos(this)) == -1) readerror();
		av_push(RETVAL, x);
	}

#line 854 "CDB_File.c"
	ST(0) = newRV((SV*)RETVAL);
	sv_2mortal(ST(0));
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_EXISTS); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_EXISTS)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "this, k");
    {
	cdb *	this;
	SV *	k = ST(1)
;
#line 595 "CDB_File.xs"
	STRLEN klen;
	char *kp;

#line 876 "CDB_File.c"
	int	RETVAL;
	dXSTARG;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_EXISTS() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 599 "CDB_File.xs"
	if (!SvOK(k)) {
		XSRETURN_NO;
	}
	kp = SvPV(k, klen);
	RETVAL = cdb_find(this, kp, klen);
	if (RETVAL != 0 && RETVAL != 1) readerror();

#line 895 "CDB_File.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "db");
    {
	SV *	db = ST(0)
;
#line 614 "CDB_File.xs"
	cdb *		this;
        IO *io;

#line 915 "CDB_File.c"
#line 618 "CDB_File.xs"
        if (sv_isobject(db) && (SvTYPE(SvRV(db)) == SVt_PVMG) ) {
          this = (cdb*)SvIV(SvRV(db));

          iter_end(this);
#ifdef HASMMAP
          if (this->map) {
            munmap(this->map, this->size);
            this->map = 0;
          }
#endif
          PerlIO_close(this->fh); /* close() on O_RDONLY cannot fail */
          Safefree(this);
        }
#line 930 "CDB_File.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_CDB_File_FIRSTKEY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_FIRSTKEY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "this");
    {
	cdb *	this;
#line 637 "CDB_File.xs"
	char buf[8];
	U32 klen;

#line 948 "CDB_File.c"
	SV *	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_FIRSTKEY() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 641 "CDB_File.xs"
	iter_start(this);
	if (iter_key(this)) {
		ST(0) = sv_mortalcopy(this->curkey);
		CDB_DO_COW(ST(0));
    } else
		XSRETURN_UNDEF; /* empty database */
#line 965 "CDB_File.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_NEXTKEY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_NEXTKEY)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "this, k");
    {
	cdb *	this;
	SV *	k = ST(1)
;
#line 654 "CDB_File.xs"
	char buf[8], *kp;
	int found;
	off_t pos;
	U32 dlen, klen0;
	STRLEN klen1;

#line 988 "CDB_File.c"
	SV *	RETVAL;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::cdb_NEXTKEY() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 661 "CDB_File.xs"
	if (!SvOK(k)) {
		XSRETURN_UNDEF;
    }
	/* Sometimes NEXTKEY gets called before FIRSTKEY if the hash
	 * gets re-tied so we call iter_start() anyway here */
	if (this->end == 0 || !sv_eq(this->curkey, k))
	    iter_start(this);
	iter_advance(this);
	if (iter_key(this)) {
		ST(0) = sv_mortalcopy(this->curkey);
		CDB_DO_COW(ST(0));
	} else {
		iter_start(this);
		(void)iter_key(this); /* prepare curkey for FETCH */
		this->fetch_advance = 1;
		XSRETURN_UNDEF;
	}
#line 1016 "CDB_File.c"
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File_new); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File_new)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "CLASS, fn, fntemp");
    {
	char *	CLASS = (char *)SvPV_nolen(ST(0))
;
	char *	fn = (char *)SvPV_nolen(ST(1))
;
	char *	fntemp = (char *)SvPV_nolen(ST(2))
;
#line 686 "CDB_File.xs"
	cdb_make *cdbmake;
	int i;

#line 1039 "CDB_File.c"
	cdb_make *	RETVAL;
#line 690 "CDB_File.xs"
        New(0, cdbmake, 1, cdb_make);
	cdbmake->f = PerlIO_open(fntemp, "wb");
	if (!cdbmake->f) XSRETURN_UNDEF;

	if (cdb_make_start(cdbmake) < 0) XSRETURN_UNDEF;

	/* Oh, for referential transparency. */
	New(0, cdbmake->fn, strlen(fn) + 1, char);
	New(0, cdbmake->fntemp, strlen(fntemp) + 1, char);
	strncpy(cdbmake->fn, fn, strlen(fn) + 1);
	strncpy(cdbmake->fntemp, fntemp, strlen(fntemp) + 1);

        CLASS = "CDB_File::Maker"; /* OK, so this is a hack */

        RETVAL = cdbmake;

#line 1058 "CDB_File.c"
	ST(0) = sv_newmortal();
        sv_setref_pv( ST(0), CLASS, (void*)RETVAL );
        SvREADONLY_on( SvRV( ST(0) ) );
    }
    XSRETURN(1);
}


XS_EUPXS(XS_CDB_File__Maker_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File__Maker_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "sv");
    {
	SV *	sv = ST(0)
;
#line 716 "CDB_File.xs"
        cdb_make *  this;

#line 1079 "CDB_File.c"
#line 719 "CDB_File.xs"
        if (sv_isobject(sv) && (SvTYPE(SvRV(sv)) == SVt_PVMG) ) {
          this = (cdb_make*)SvIV(SvRV(sv));
          if(this->f){PerlIO_close(this->f);}
          Safefree(this);
        }
#line 1086 "CDB_File.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_CDB_File__Maker_insert); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File__Maker_insert)
{
    dVAR; dXSARGS;
    if (items < 1)
       croak_xs_usage(cv,  "this, ...");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	cdb_make *	this;
#line 730 "CDB_File.xs"
	char *kp, *vp, packbuf[8];
	int c, i, x;
	STRLEN klen, vlen;
	U32 h;
	SV *k;
	SV *v;

#line 1110 "CDB_File.c"

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb_make *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::Maker::cdbmaker_insert() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 738 "CDB_File.xs"
	for (x = 1; x < items; x += 2) {
		k = ST(x);
		v = ST(x+1);
		kp = SvPV(k, klen); vp = SvPV(v, vlen);
		uint32_pack(packbuf, klen);
		uint32_pack(packbuf + 4, vlen);

		if (PerlIO_write(this->f, packbuf, 8) < 8) writeerror();

		h = cdb_hash(kp, klen);
		if (PerlIO_write(this->f, kp, klen) < klen) writeerror();
		if (PerlIO_write(this->f, vp, vlen) < vlen) writeerror();

		if (cdb_make_addend(this, klen, vlen, h) == -1) nomem();
	}
#line 1135 "CDB_File.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_CDB_File__Maker_finish); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_CDB_File__Maker_finish)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "this");
    {
	cdb_make *	this;
#line 759 "CDB_File.xs"
	char buf[8];
	int i;
	U32 len, u;
	U32 count, memsize, where;
	struct cdb_hplist *x, *prev;
	struct cdb_hp *hp;

#line 1158 "CDB_File.c"
	int	RETVAL;
	dXSTARG;

        if( sv_isobject(ST(0)) && (SvTYPE(SvRV(ST(0))) == SVt_PVMG) )
                this = (cdb_make *)SvIV((SV*)SvRV( ST(0) ));
        else{
                warn( "CDB_File::Maker::cdbmaker_finish() -- this is not a blessed SV reference" );
                XSRETURN_UNDEF;
        }
;
#line 767 "CDB_File.xs"
	for (i = 0; i < 256; ++i)
		this->count[i] = 0;

	for (x = this->head; x; x = x->next) {
		i = x->num;
		while (i--)
			++this->count[255 & x->hp[i].h];
	}

	memsize = 1;
	for (i = 0; i < 256; ++i) {
		u = this->count[i] * 2;
		if (u > memsize)
			memsize = u;
	}

	memsize += this->numentries; /* no overflow possible up to now */
	u = (U32) 0 - (U32) 1;
	u /= sizeof(struct cdb_hp);
	if (memsize > u) { errno = ENOMEM; XSRETURN_UNDEF; }

	New(0xCDB, this->split, memsize, struct cdb_hp);

	this->hash = this->split + this->numentries;

	u = 0;
	for (i = 0; i < 256; ++i) {
		u += this->count[i]; /* bounded by numentries, so no overflow */
		this->start[i] = u;
	}

	prev = 0;
	for (x = this->head; x; x = x->next) {
		i = x->num;
		while (i--)
			this->split[--this->start[255 & x->hp[i].h]] = x->hp[i];
		if (prev) Safefree(prev);
		prev = x;
	}
	if (prev) Safefree(prev);

	for (i = 0; i < 256; ++i) {
		count = this->count[i];

		len = count + count; /* no overflow possible */
		uint32_pack(this->final + 8 * i, this->pos);
		uint32_pack(this->final + 8 * i + 4, len);

		for (u = 0; u < len; ++u)
			this->hash[u].h = this->hash[u].p = 0;

		hp = this->split + this->start[i];
		for (u = 0; u < count; ++u) {
			where = (hp->h >> 8) % len;
			while (this->hash[where].p)
				if (++where == len)
					where = 0;
			this->hash[where] = *hp++;
		}

		for (u = 0; u < len; ++u) {
			uint32_pack(buf, this->hash[u].h);
			uint32_pack(buf + 4, this->hash[u].p);
			if (PerlIO_write(this->f, buf, 8) == -1) XSRETURN_UNDEF;
			if (posplus(this, 8) == -1) XSRETURN_UNDEF;
		}
	}

	Safefree(this->split);

	if (PerlIO_flush(this->f) == EOF) writeerror();
	PerlIO_rewind(this->f);

	if (PerlIO_write(this->f, this->final, sizeof this->final) < sizeof this->final) writeerror();
	if (PerlIO_flush(this->f) == EOF) writeerror();

	if (fsync(PerlIO_fileno(this->f)) == -1) XSRETURN_NO;
	if (PerlIO_close(this->f) == EOF) XSRETURN_NO;
     this->f=0;

	if (rename(this->fntemp, this->fn)) {
        croak("Failed to rename %s to %s.", this->fntemp, this->fn);
    }

	Safefree(this->fn);
	Safefree(this->fntemp);

	RETVAL = 1;

#line 1259 "CDB_File.c"
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_CDB_File); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_CDB_File)
{
    dVAR; dXSARGS;
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#endif
    XS_VERSION_BOOTCHECK;

        newXS("CDB_File::handle", XS_CDB_File_handle, file);
        newXS("CDB_File::datalen", XS_CDB_File_datalen, file);
        newXS("CDB_File::datapos", XS_CDB_File_datapos, file);
        newXS("CDB_File::TIEHASH", XS_CDB_File_TIEHASH, file);
        newXS("CDB_File::FETCH", XS_CDB_File_FETCH, file);
        newXS("CDB_File::fetch_all", XS_CDB_File_fetch_all, file);
        newXS("CDB_File::multi_get", XS_CDB_File_multi_get, file);
        newXS("CDB_File::EXISTS", XS_CDB_File_EXISTS, file);
        newXS("CDB_File::DESTROY", XS_CDB_File_DESTROY, file);
        newXS("CDB_File::FIRSTKEY", XS_CDB_File_FIRSTKEY, file);
        newXS("CDB_File::NEXTKEY", XS_CDB_File_NEXTKEY, file);
        newXS("CDB_File::new", XS_CDB_File_new, file);
        newXS("CDB_File::Maker::DESTROY", XS_CDB_File__Maker_DESTROY, file);
        newXS("CDB_File::Maker::insert", XS_CDB_File__Maker_insert, file);
        newXS("CDB_File::Maker::finish", XS_CDB_File__Maker_finish, file);
#if (PERL_REVISION == 5 && PERL_VERSION >= 9)
  if (PL_unitcheckav)
       call_list(PL_scopestack_ix, PL_unitcheckav);
#endif
    XSRETURN_YES;
}