/*
	WARNING: This file was generated by dkct.
	Changes you make here will be lost if dkct is run again!
	You should modify the original source and run dkct on it.
	Original source: dk3dbi.ctr
*/

/*
Copyright (C) 2011-2013, Dirk Krause

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above opyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.
* Neither the name of the author nor the names of contributors may be used
  to endorse or promote products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**	@file dk3dbi.c The dk3dbi module.
*/


#line 372 "dk3dbi.ctr"

#include "dk3all.h"
#include "dk3dbi.h"

#ifdef DK3_USE_DB
#undef DK3_USE_DB
#endif
#ifdef DK3_USE_NDBM
#undef DK3_USE_NDBM
#endif

#if DK3_HAVE_DB_H
#include <db.h>
/**	Use Berkeley DB.
*/
#define DK3_USE_DB 1
#endif

#if DK3_HAVE_NDBM_H
#if !DK3_HAVE_GDBM_H
#include <ndbm.h>
/**	Use NDBM.
*/
#define DK3_USE_NDBM	1
#endif
#endif




#line 401 "dk3dbi.ctr"



/**	Data type used in storage.
*/
typedef struct {
  /**	Key data.
  */
  void		*keydata;
  /**	value data.
  */
  void		*valdata;
  /**	Key size (number of bytes in key data).
  */
  size_t	 keysize;
  /**	Value size (number of bytes in value data).
  */
  size_t	 valsize;
} dk3_dbi_node_t;




/**	Names of database types. Order must match the
	definitions in @ref databasetypes.
*/
static dkChar const * const dk3dbi_type_names[] = {
/* 0 */
dkT("mem"),

/* 1 */
dkT("bdb"),

/* 2 */
dkT("ndbm"),

NULL


#line 442 "dk3dbi.ctr"
};



/**	Modes to open file.
*/
static dkChar const * const dk3dbi_file_open_modes[] = {
/*  0 */ dkT("rb"),
/*  1 */ dkT("wb")
};



/**	File name suffixes for NDBM files.
*/
static char const * const dk3dbi_ndbm_suffixes[] = {
".dir", ".pag"
};



/**	Delete one storage node, release memory.
	@param	np	Node to delete.
*/
static
void
dk3dbi_node_delete(dk3_dbi_node_t *np)
{
  if(np) {
    if(np->keydata) {
      dk3_delete(np->keydata);
    }
    if(np->valdata) {
      dk3_delete(np->valdata);
    }
    np->keydata = NULL; np->valdata = NULL;
    np->keysize = 0; np->valsize = 0;
    dk3_delete(np)
  }
}



/**	Create a new node with specified buffer sizes.
	@param	ks	Keys size.
	@param	vs	Value size.
	@param	app	Application structure for diagnostics.
	@return	Pointer to new node on success, NULL on error.
*/
static
dk3_dbi_node_t	*
dk3dbi_node_new(size_t ks, size_t vs, dk3_app_t *app)
{
  dk3_dbi_node_t	*back	= NULL;
  char			*cpk	= NULL;	/* Key buffer pointer. */
  char			*cpv	= NULL;	/* Value buffer pointer. */
  int			 ok	= 0;	/* Flag: Success. */
  

#line 500 "dk3dbi.ctr"
  back = dk3_new_app(dk3_dbi_node_t,1,app);
  if(back) {
    back->keysize = 0; back->valsize = 0;
    back->keydata = NULL; back->valdata = NULL;
    cpk = dk3_new_app(char,ks,app);
    if(cpk) {
      cpv = dk3_new_app(char,vs,app);
      if(cpv) {
        ok = 1;
	back->keydata = (void *)cpk;
	back->valdata = (void *)cpv;
	back->keysize = ks;
	back->valsize = vs;
      }
    }
    if(!(ok)) {
      if(cpk) {
        dk3_delete(cpk)
      }
      if(cpv) {
        dk3_delete(cpv)
      }
      dk3dbi_node_delete(back);
      back = NULL;
    }
  } 

#line 526 "dk3dbi.ctr"
  return back;
}



/**	Comparison of storage nodes.
	@param	l	Left node.
	@param	r	Right node.
	@param	cr	Comparison criteria (0=node/node, 1=node/datum).
	@return	Comparison result.
*/
static
int
dk3dbi_node_compare(void *l, void *r, int cr)
{
  int			back	= 0;
  dk3_dbi_node_t	*pl;		/* Left object pointer. */
  dk3_dbi_node_t	*pr;		/* Right object pointer. */
  dk3_datum_t		*pd;		/* Right object pointer (datum). */
  if(l) {
    if(r) {
      pl = (dk3_dbi_node_t *)l;
      switch(cr) {
        case 1: {
	  pd = (dk3_datum_t *)r;
	  if(pl->keydata) {
	    if(pd->dt) {
	      if(pl->keysize > pd->sz) {
	        back = 1;
	      } else {
	        if(pl->keysize < pd->sz) {
		  back = -1;
		} else {
		  back = dk3mem_cmp(pl->keydata, pd->dt, pl->keysize);
		  if(back < -1) back = -1;
		  if(back >  1) back =  1;
		}
	      }
	    } else {
	      back = 1;
	    }
	  } else {
	    if(pd->dt) {
	      back = -1;
	    }
	  }
	} break;
	default: {
	  pr = (dk3_dbi_node_t *)r;
	  if(pl->keydata) {
	    if(pr->keydata) {
	      if(pl->keysize > pr->keysize) {
	        back = 1;
	      } else {
	        if(pl->keysize < pr->keysize) {
		  back = -1;
		} else {
		  back = dk3mem_cmp(pl->keydata, pr->keydata, pl->keysize);
		  if(back < -1) back = -1;
		  if(back >  1) back =  1;
		}
	      }
	    } else {
	      back = 1;
	    }
	  } else {
	    if(pr->keydata) {
	      back = -1;
	    }
	  }
	} break;
      }
    } else {
      back = 1;
    }
  } else {
    if(r) {
      back = -1;
    }
  }
  return back;
}



/**	Read in-memory database from file.
	@param	dbp	Database to initialize.
	@return	1 on success (even if there is not db file yet), 0 on error.
*/
static
int
dk3dbi_mem_read_file(dk3_dbi_t *dbp)
{
  unsigned char		uc[8];		/* Buffer for key and value size. */
  FILE			*fipo;		/* Input file. */
  dk3_dbi_node_t	*np;		/* Node for record just read. */
  unsigned char		*kd;		/* Key data buffer pointer. */
  unsigned char		*vd;		/* Value data buffer pointer. */
  dkChar const		*oldsourcename;	/* Previous source file name. */
  unsigned long		oldsourceline;	/* Previous source file line. */
  unsigned long		ul1;		/* Key size as unsigned long. */
  unsigned long		ul2;		/* Value size as unsigned long. */
  size_t		nread;		/* Number of bytes read from file. */
  size_t		ks;		/* Key size. */
  size_t		vs;		/* Value size. */
  int			ok	= 0;	/* Flag: Success. */
  int 			back	= 1;
  int			cc	= 1;	/* Flag: Can continue. */
  

#line 635 "dk3dbi.ctr"
  oldsourcename = dk3app_get_source_file(dbp->app);
  oldsourceline = dk3app_get_source_line(dbp->app);
  dk3app_set_source_file(dbp->app, dbp->fn);
  dk3app_set_source_line(dbp->app, 0UL);
  fipo = dk3sf_fopen_app(dbp->fn, dk3dbi_file_open_modes[0], dbp->app);
  if(fipo) {
    while((cc) && (back)) {
      cc = 0;
      kd = vd = NULL;
      nread = dk3sf_fread_app(uc, 1, 8, fipo, dbp->app);
      if(nread > 0) {
        if(nread == 8) {
	  ul1 = ((((unsigned long)(uc[0])) << 24) & 0xFF000000UL)
	      | ((((unsigned long)(uc[1])) << 16) & 0x00FF0000UL)
	      | ((((unsigned long)(uc[2])) <<  8) & 0x0000FF00UL)
	      | (( (unsigned long)(uc[3])       ) & 0x000000FFUL);
	  ul2 = ((((unsigned long)(uc[4])) << 24) & 0xFF000000UL)
	      | ((((unsigned long)(uc[5])) << 16) & 0x00FF0000UL)
	      | ((((unsigned long)(uc[6])) <<  8) & 0x0000FF00UL)
	      | (( (unsigned long)(uc[7])       ) & 0x000000FFUL);
	  ks = (size_t)ul1; vs = (size_t)ul2;
	  if(sizeof(size_t) < 4) {
	    if((ul1 > 0x0000FFFFUL) || (ul2 > 0x0000FFFFUL)) {
	      back = 0;
	      /* ERROR: Entry size too large! */
	      dk3app_log_i1(dbp->app, DK3_LL_ERROR, 245);
	    }
	  }
	  if(back) {
	    kd = dk3_new_app(unsigned char,ks,dbp->app);
	    vd = dk3_new_app(unsigned char,vs,dbp->app);
	    if((kd) && (vd)) {
	      ok = 0;
	      nread = dk3sf_fread_app(kd, 1, ks, fipo, dbp->app);
	      if(nread == ks) {
	        nread = dk3sf_fread_app(vd, 1, vs, fipo, dbp->app);
		if(nread == vs) {
		  np = dk3_new_app(dk3_dbi_node_t,1,dbp->app);
		  if(np) {
		    np->keydata = kd; np->valdata = vd;
		    np->keysize = ks; np->valsize = vs;
		    if(dk3sto_add((dbp->details).mem.s_mem, np)) {
		      cc = 1; ok = 1;
		    } else {
		      np->keydata = np->valdata = NULL;
		      np->keysize = np->valsize = 0;
		      dk3_delete(np)
		      np = NULL;
		      back = 0;
		    }
		  }
		} else {
		  back = 0;
		  /* ERROR: File probably damaged! */
		  dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246);
		}
	      } else {
	        back = 0;
		/* ERROR: File probably damaged! */
		dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246);
	      }
	      if(!(ok)) {
	        dk3_delete(kd)
		dk3_delete(vd)
		kd = vd = NULL; ks = vs = 0;
	      }
	    } else {
	      back = 0;
	      if(kd) {
	        dk3_delete(kd)
	      }
	      if(vd) {
	        dk3_delete(vd)
	      }
	    }
	  }
	} else {
	  back = 0;
	  /* ERROR: File probably damaged! */
	  dk3app_log_i1(dbp->app, DK3_LL_ERROR, 246);
	}
      } else {
        /* End of file reached. */
      }
    }
    fclose(fipo);
  }
  dk3app_set_source_file(dbp->app, oldsourcename);
  dk3app_set_source_line(dbp->app, oldsourceline);
  

#line 725 "dk3dbi.ctr"
  return back;
}



/**	Synchronize memory database to file.
	@param	dbp	Database.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_mem_sync(dk3_dbi_t *dbp)
{
  unsigned char		uc[8];		/* Buffer for key and value size. */
  FILE			*fipo;		/* Output file. */
  dk3_dbi_node_t	*np;		/* Current node to process. */
  unsigned long		ul1;		/* Key size as unsigned long. */
  unsigned long		ul2;		/* Value size as unsigned long. */
  size_t		nwrite;		/* Number of bytes written. */
  int			back	= 0;
  

#line 746 "dk3dbi.ctr"
  if(dbp->fn) {			

#line 747 "dk3dbi.ctr"
    fipo = dk3sf_fopen_app(dbp->fn, dk3dbi_file_open_modes[1], dbp->app);
    if(fipo) {			

#line 749 "dk3dbi.ctr"
      back = 1;
      dk3sto_it_reset((dbp->details).mem.i_mem);
      do {
        np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem);
	if(np) {		

#line 754 "dk3dbi.ctr"
	  ul1 = (unsigned long)(np->keysize);
	  ul2 = (unsigned long)(np->valsize);
	  uc[0] = (unsigned char)((ul1 >> 24) & 0x000000FFUL);
	  uc[1] = (unsigned char)((ul1 >> 16) & 0x000000FFUL);
	  uc[2] = (unsigned char)((ul1 >>  8) & 0x000000FFUL);
	  uc[3] = (unsigned char)( ul1        & 0x000000FFUL);
	  uc[4] = (unsigned char)((ul2 >> 24) & 0x000000FFUL);
	  uc[5] = (unsigned char)((ul2 >> 16) & 0x000000FFUL);
	  uc[6] = (unsigned char)((ul2 >>  8) & 0x000000FFUL);
	  uc[7] = (unsigned char)( ul2        & 0x000000FFUL);
	  nwrite = dk3sf_fwrite_app(uc, 1, 8, fipo, dbp->app);
	  if(nwrite) {			

#line 766 "dk3dbi.ctr"
	    nwrite = dk3sf_fwrite_app(np->keydata,1,np->keysize,fipo,dbp->app);
	    if(nwrite) {		

#line 768 "dk3dbi.ctr"
	      nwrite =
	      dk3sf_fwrite_app(np->valdata,1,np->valsize,fipo,dbp->app);
	      if(!(nwrite)) {		

#line 771 "dk3dbi.ctr"
	        back = 0;
		dbp->ec = DK3_ERROR_DURING_WRITE;
	      }
	    } else {			

#line 775 "dk3dbi.ctr"
	      back = 0;
	      dbp->ec = DK3_ERROR_DURING_WRITE;
	    }
	  } else {			

#line 779 "dk3dbi.ctr"
	    back = 0;
	    dbp->ec = DK3_ERROR_DURING_WRITE;
	  }
	}
      } while((np) && (back));
      if(!dk3sf_fclose_fn_app(fipo, dbp->fn, dbp->app)) {
        back = 0;
      }
    } else {			

#line 788 "dk3dbi.ctr"
      dbp->ec = DK3_ERROR_NOT_OPENED_FOR_WRITING;
    }
  } else {
    /* BUG: No file name, must not happen! */
  } 

#line 793 "dk3dbi.ctr"
  return back;
}



/**	Set entry (in-memory database).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_mem_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  int			back	= 0;
  dk3_dbi_node_t	*np;		/* Current node to process. */
  unsigned char		*nb;		/* New value buffer for node. */
  

#line 812 "dk3dbi.ctr"
  np = (dk3_dbi_node_t *)dk3sto_it_find_like(
    (dbp->details).mem.i_mem, (void *)key, 1
  );
  if(np) {	

#line 816 "dk3dbi.ctr"
    nb = dk3_new_app(unsigned char,val->sz,dbp->app);
    if(nb) {
      dk3mem_cpy(nb, val->dt, val->sz);
      dk3_release(np->valdata)
      np->valdata = nb;
      np->valsize = val->sz;
      back = 1;		

#line 823 "dk3dbi.ctr"
    } else {
      dbp->ec = DK3_ERROR_MEMORY;
    }
  } else {	

#line 827 "dk3dbi.ctr"
    np = dk3dbi_node_new(key->sz, val->sz, dbp->app);
    if(np) {
      dk3mem_cpy(np->keydata, key->dt, key->sz);
      dk3mem_cpy(np->valdata, val->dt, val->sz);
      np->keysize = key->sz;
      np->valsize = val->sz;
      if(dk3sto_add((dbp->details).mem.s_mem, (void *)np)) {
        back = 1;	

#line 835 "dk3dbi.ctr"
      } else {
	dk3dbi_node_delete(np);
	dbp->ec = DK3_ERROR_MEMORY;
      }
    } else {
      dbp->ec = DK3_ERROR_MEMORY;
    }
  } 

#line 843 "dk3dbi.ctr"
  return back;
}



/**	Retrieve entry (in-memory database).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data (input: result buffer size, output:
	buffer size used).
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_mem_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  int			back	= 0;
  dk3_dbi_node_t	*np;		/* Current node to process. */
  

#line 862 "dk3dbi.ctr"
  np = (dk3_dbi_node_t *)dk3sto_it_find_like(
    (dbp->details).mem.i_mem, (void *)key, 1
  );
  if(np) {		

#line 866 "dk3dbi.ctr"
    if(val->sz >= np->valsize) {
      dk3mem_cpy(val->dt, np->valdata, np->valsize);
      val->sz = np->valsize;
      back = 1;		

#line 870 "dk3dbi.ctr"
    } else {		

#line 871 "dk3dbi.ctr"
    }
  } else {		

#line 873 "dk3dbi.ctr"
    if(dbp->rfk) {
      if(dbp->app) {
        /* ERROR: Entry not found! */
	dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249);
      }
    }
  }
  

#line 881 "dk3dbi.ctr"
  return back;
}



/**	Delete entry (in-memory database).
	@param	dbp	Database.
	@param	key	Key data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_mem_delete(dk3_dbi_t *dbp, dk3_datum_t *key)
{
  dk3_dbi_node_t	*np;		/* Current node to process .*/
  int			back	= 1;
  

#line 898 "dk3dbi.ctr"
  np = (dk3_dbi_node_t *)dk3sto_it_find_like(
    (dbp->details).mem.i_mem, (void *)key, 1
  );
  if(np) {
    dk3sto_remove((dbp->details).mem.s_mem, (void *)np);
    dk3dbi_node_delete(np);
  } 

#line 905 "dk3dbi.ctr"
  return back;
}



/**	Traverse database (in-memory database).
	@param	dbp	Database.
	@param	obj	Object to modify during traversal.
	@param	fct	Function to invoke for each key/value pair.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_mem_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct)
{
  dk3_datum_t		key;		/* Key data. */
  dk3_datum_t		val;		/* Value data. */
  dk3_dbi_node_t	*np;		/* Current node to process. */
  int			back	= 1;
  int			res	= 1;	/* Function result for current node. */
  

#line 926 "dk3dbi.ctr"
  dk3sto_it_reset((dbp->details).mem.i_mem);
  do {
    np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem);
    if(np) {
      key.sz = np->keysize;
      key.dt = np->keydata;
      val.sz = np->valsize;
      val.dt = np->valdata;
      res = (*fct)(obj, &key, &val);
      if(res < 1) {			

#line 936 "dk3dbi.ctr"
        back = 0;
      }
    }
  } while((np) && (res >= 0));
  

#line 941 "dk3dbi.ctr"
  return back;
}


#if DK3_USE_DB
/**	Open Berkeley DB file.
	@param	dbp	Database.
	@param	trunc	Flag: Truncate database.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_bdb_open_file(dk3_dbi_t *dbp, int trunc)
{
  char		fnb[DK3_MAX_PATH];	/* File name buffer, 8-bit chars. */
  DB		*db	= NULL;		/* BDB. */
  u_int32_t	flags	= 0UL;		/* Flags to open BDB. */
  int		back	= 0;
  int		ret;			/* BDB operation result. */
  

#line 961 "dk3dbi.ctr"
  if(dk3sf_filename_to_c8(fnb, sizeof(fnb), dbp->fn, dbp->app)) {
    ret = db_create(&db, NULL, 0);
    if(ret == 0) {
      flags = DB_RDONLY;
      if(dbp->wr) {
        flags = DB_CREATE;
        if(trunc) {
          flags |= DB_TRUNCATE;
        }
      }
      ret = db->open(db, NULL, fnb, NULL, DB_BTREE, flags, 0600);
      if(ret == 0) {
        back = 1;
	(dbp->details).bdb.dbptr = (void *)db;
      } else {
        db->close(db, 0);
      }
    } else {
      /* ERROR: Failed to create database */
      dk3app_log_i1(dbp->app, DK3_LL_ERROR, 9);
    }
  } else {
    /* ERROR: File name conversion failed! */
    dbp->ec = DK3_ERROR_INVALID_ARGS;
  } 

#line 986 "dk3dbi.ctr"
  return back;
}

/**	Set entry (Berkeley DB).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_bdb_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  DBT			k;		/* Key datum. */
  DBT			v;		/* Value datum. */
  DB			*db;		/* BDB structure. */
  int			res;		/* BDB operation result. */
  int			back = 0;
  

#line 1005 "dk3dbi.ctr"
  db = (DB *)((dbp->details).bdb.dbptr);
  dk3mem_res((void *)(&k), sizeof(DBT));
  dk3mem_res((void *)(&v), sizeof(DBT));
  k.data = key->dt; k.size = key->sz;
  v.data = val->dt; v.size = val->sz;
  db->del(db, NULL, &k, 0);
  dk3mem_res((void *)(&k), sizeof(DBT));
  k.data = key->dt; k.size = key->sz;
  res = db->put(db, NULL, &k, &v, 0);
  if(res == 0) {
    back = 1;
  } 

#line 1017 "dk3dbi.ctr"
  return back;
}

/**	Retrieve entry (Berkeley DB).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data (input: result buffer size, output:
	buffer size used).
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_bdb_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  DBT			k;		/* Key datum. */
  DBT			v;		/* Value datum. */
  DB			*db;		/* BDB structure. */
  int			res;		/* BDB operation result. */
  int			back	= 0;
  

#line 1037 "dk3dbi.ctr"
  db = (DB *)((dbp->details).bdb.dbptr);
  dk3mem_res((void *)(&k), sizeof(DBT));
  dk3mem_res((void *)(&v), sizeof(DBT));
  k.data = key->dt; k.size = key->sz;
  v.data = val->dt; v.ulen = val->sz; v.flags = DB_DBT_USERMEM;
  res = db->get(db, NULL, &k, &v, 0);
  if(res == 0) {
    back = 1;
    val->sz = v.size;
  } else {
    if(dbp->rfk) {
      if(dbp->app) {
        /* ERROR: Entry not found! */
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249);
      }
    }
  } 

#line 1054 "dk3dbi.ctr"
  return back;
}

/**	Delete entry (Berkeley DB).
	@param	dbp	Database.
	@param	key	Key data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_bdb_delete(dk3_dbi_t *dbp, dk3_datum_t *key)
{
  DBT			k;		/* Key datum. */
  DB			*db;		/* BDB structure. */
  int			res;		/* BDB operation result. */
  int			back = 0;
  

#line 1071 "dk3dbi.ctr"
  db = (DB *)((dbp->details).bdb.dbptr);
  dk3mem_res((void *)(&k), sizeof(DBT));
  k.data = key->dt; k.size = key->sz;
  res = db->del(db, NULL, &k, 0);
  if(res == 0) {
    back = 1;
  } 

#line 1078 "dk3dbi.ctr"
  return back;
}

/**	Traverse database (Berkeley DB).
	@param	dbp	Database.
	@param	obj	Object to modify during traversal.
	@param	fct	Function to invoke for each key/value pair.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_bdb_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct)
{
  DBT			k;		/* Key datum (BDB). */
  DBT			v;		/* Value datum (BDB). */
  dk3_datum_t		key;		/* Key datum (dk3dbi). */
  dk3_datum_t		val;		/* Vaue datum (dk3dbi). */
  DB			*db;		/* BDB structure. */
  DBC			*cp	= NULL;	/* BDB cursor. */
  int			res;		/* BDB operation result. */
  int			cc;		/* Flag: Can continue. */
  int			isfirst;	/* Flag: No record received yet. */
  int			back	= 0;
  

#line 1102 "dk3dbi.ctr"
  db = (DB *)((dbp->details).bdb.dbptr);
  res = db->cursor(db, NULL, &cp, 0);
  if(res == 0) {		

#line 1105 "dk3dbi.ctr"
    if(cp) {			

#line 1106 "dk3dbi.ctr"
      cc = 1;
      back = 1;
      isfirst = 1;
      dk3mem_res((void *)(&k), sizeof(DBT));
      dk3mem_res((void *)(&v), sizeof(DBT));
      do {			

#line 1112 "dk3dbi.ctr"
        cc = 0;
#if DK3_HAVE_DB_CURSOR_C_GET
	/* 2011-10-23: c_get() not in current documentation of BDB. */
	res = cp->c_get(cp, &k, &v, ((isfirst) ? (DB_FIRST) : (DB_NEXT)));
#else
	if(isfirst) {		

#line 1118 "dk3dbi.ctr"
	  res = cp->get(cp, &k, &v, DB_FIRST);
	} else {		

#line 1120 "dk3dbi.ctr"
	  res = cp->get(cp, &k, &v, DB_NEXT);
	}
#endif
	isfirst = 0;
	if(res == 0) {		

#line 1125 "dk3dbi.ctr"
	  cc = 1;
	  key.dt = k.data; key.sz = k.size;
	  val.dt = v.data; val.sz = v.size;
	  res = (*fct)(obj, &key, &val);
	  switch(res) {
	    case 0: {		

#line 1131 "dk3dbi.ctr"
	      back = 0;
	    } break;
	    case -1: {		

#line 1134 "dk3dbi.ctr"
	      back = 0; cc = 0;
	    } break;
	  }
	} else {		

#line 1138 "dk3dbi.ctr"
	  cc = 0;
	  if(res != DB_NOTFOUND) {	

#line 1140 "dk3dbi.ctr"
	    back = 0;
	  }
	}
      } while(cc);
    } else {			

#line 1145 "dk3dbi.ctr"
    }
  } else {			

#line 1147 "dk3dbi.ctr"
  }
  if(cp) {
    cp->c_close(cp);
  } 

#line 1151 "dk3dbi.ctr"
  return back;
}

#endif

#if DK3_USE_NDBM

/**	Open NDBM database file.
	@param	dbp	Database.
	@param	trunc	Flag: Truncate database.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_ndbm_open_file(dk3_dbi_t *dbp, int trunc)
{
  DBM		*dbm	= NULL;	/* NDBM structure. */
  int		back	= 0;
  int		omode	= 0;	/* Output file mode. */
  

#line 1171 "dk3dbi.ctr"
  omode = O_CREAT;
  if(dbp->wr) {		

#line 1173 "dk3dbi.ctr"
    omode |= O_RDWR;
    if(trunc) {		

#line 1175 "dk3dbi.ctr"
      omode |= O_TRUNC;
    }
  } else {		

#line 1178 "dk3dbi.ctr"
    omode |= O_RDONLY;
  } 

#line 1180 "dk3dbi.ctr"
  dbm = dbm_open(dbp->fn, omode, 0600);
  if(dbm) {	

#line 1182 "dk3dbi.ctr"
    (dbp->details).ndbm.dbptr = (void *)dbm;
    back = 1;
  } else {	

#line 1185 "dk3dbi.ctr"
  } 

#line 1186 "dk3dbi.ctr"
  return back;
}

/**	Set entry (NDBM).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_ndbm_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  datum			k;		/* Key datum. */
  datum			v;		/* Value datum. */
  DBM			*dbm;		/* NDBM structure. */
  int			res;		/* Operation result. */
  int			back = 0;
  

#line 1205 "dk3dbi.ctr"
  dbm = (DBM *)((dbp->details).ndbm.dbptr);
  dk3mem_res((void *)(&k),sizeof(datum));
  dk3mem_res((void *)(&v),sizeof(datum));
  k.dptr = key->dt; k.dsize = key->sz; v.dptr = val->dt; v.dsize = val->sz;
  res = dbm_store(dbm, k, v, DBM_INSERT);
  if(res == 0) {
    back = 1;
  } else {
    dk3mem_res((void *)(&k),sizeof(datum));
    dk3mem_res((void *)(&v),sizeof(datum));
    k.dptr = key->dt; k.dsize = key->sz; v.dptr = val->dt; v.dsize = val->sz;
    res = dbm_store(dbm, k, v, DBM_REPLACE);
    if(res == 0) {
      back = 1;
    }
  } 

#line 1221 "dk3dbi.ctr"
  return back;
}

/**	Retrieve entry (NDBM).
	@param	dbp	Database.
	@param	key	Key data.
	@param	val	Value data (input: result buffer size, output:
	buffer size used).
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_ndbm_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  datum			k;		/* Key datum. */
  datum			v;		/* Value datum. */
  DBM			*dbm;		/* NDBM structure. */
  int			back	= 0;
  

#line 1240 "dk3dbi.ctr"
  dbm = (DBM *)((dbp->details).ndbm.dbptr);
  dk3mem_res((void *)(&k), sizeof(datum));
  k.dptr = key->dt; k.dsize = key->sz;
  v = dbm_fetch(dbm, k);
  if((v.dptr) && (v.dsize)) {
    if(v.dsize <= val->sz) {
      dk3mem_cpy(val->dt, v.dptr, v.dsize);
      val->sz = v.dsize;
      back = 1;
    }
  } else {
    if(dbp->rfk) {
      if(dbp->app) {
        /* ERROR: Entry not found! */
	dk3app_log_i1(dbp->app, DK3_LL_ERROR, 249);
      }
    }
  } 

#line 1258 "dk3dbi.ctr"
  return back;
}

/**	Delete entry (NDBM).
	@param	dbp	Database.
	@param	key	Key data.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_ndbm_delete(dk3_dbi_t *dbp, dk3_datum_t *key)
{
  datum			k;		/* Key datum. */
  DBM			*dbm;		/* NDBM structure. */
  int			back	= 0;
  

#line 1274 "dk3dbi.ctr"
  dbm = (DBM *)((dbp->details).ndbm.dbptr);
  dk3mem_res((void *)(&k),sizeof(datum));
  k.dptr = key->dt; k.dsize = key->sz;
  if(dbm_delete(dbm, k) == 0) {
    back = 1;
  } 

#line 1280 "dk3dbi.ctr"
  return back;
}

/**	Traverse database (NDBM).
	@param	dbp	Database.
	@param	obj	Object to modify during traversal.
	@param	fct	Function to invoke for each key/value pair.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_ndbm_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct)
{
  datum			k;		/* Key datum (NDBM). */
  datum			v;		/* Value datum (NDBM). */
  dk3_datum_t		key;		/* Key datum (dk3dbi). */
  dk3_datum_t		val;		/* Value datum (dk3dbi). */
  DBM			*dbm;		/* NDBM structure. */
  int			isfirst = 1;	/* Flag: No record received yet. */
  int			cc;		/* Flag: Can continue. */
  int			res;		/* Operation result. */
  int			back	= 1;
  

#line 1303 "dk3dbi.ctr"
  dbm = (DBM *)((dbp->details).ndbm.dbptr);
  cc = 1;
  do {
    cc = 0;
    if(isfirst) {
      k = dbm_firstkey(dbm);
    } else {
      k = dbm_nextkey(dbm);
    }
    isfirst = 0;
    if((k.dptr) && (k.dsize)) {
      v = dbm_fetch(dbm, k);
      if((v.dptr) && (v.dsize)) {
        cc = 1;
	key.dt = k.dptr;
	key.sz = k.dsize;
	val.dt = v.dptr;
	val.sz = v.dsize;
	res = (*fct)(obj, &key, &val);
	switch(res) {
	  case 0: {
	    back = 0;		

#line 1325 "dk3dbi.ctr"
	  } break;
	  case -1: {
	    back = 0; cc = 0;	

#line 1328 "dk3dbi.ctr"
	  } break;
	}
      }
    }
  } while(cc);
  

#line 1334 "dk3dbi.ctr"
  return back;
}

#endif



int
dk3dbi_type_supported(int tp)
{
  int back = 0;
  

#line 1346 "dk3dbi.ctr"
  switch(tp) {
    case DK3_DB_TYPE_MEMORY:
    {
      back = 1;
    } break;
    case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
      back = 1;
#endif
    } break;
    case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
      back = 1;
#endif
    } break;
  } 

#line 1362 "dk3dbi.ctr"
  return back;
}



/**	If no type is specified use best available database type.
	@return	Best available database type.
*/
static
int
dk3dbi_choose_best_available_type(void)
{
  int back = DK3_DB_TYPE_MEMORY;
  

#line 1376 "dk3dbi.ctr"
#if DK3_USE_DB
  back = DK3_DB_TYPE_BDB;
#else
#if DK3_USE_NDBM
  back = DK3_DB_TYPE_NDBM;
#endif
#endif
  

#line 1384 "dk3dbi.ctr"
  return back;
}



/**	Internal function to close the database.
	@param	dbp	Database to close.
*/
static
void
dk3dbi_close_internal(dk3_dbi_t *dbp)
{
  dk3_dbi_node_t	*np;	/* Current node to process. */
  

#line 1398 "dk3dbi.ctr"
  if(dbp) {
    switch(dbp->tp) {
      case DK3_DB_TYPE_MEMORY: {
	if((dbp->details).mem.s_mem) {
	  if((dbp->details).mem.i_mem) {
	    dk3sto_it_reset((dbp->details).mem.i_mem);
	    do {
	      np = (dk3_dbi_node_t *)dk3sto_it_next((dbp->details).mem.i_mem);
	      if(np) {
	        dk3dbi_node_delete(np);
	      }
	    } while(np);
	    dk3sto_it_close((dbp->details).mem.i_mem);
	  }
	  dk3sto_close((dbp->details).mem.s_mem);
	}
	(dbp->details).mem.s_mem = NULL;
      } break;
      case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
        DB *db;
	if((dbp->details).bdb.dbptr) {
	  db = (DB *)((dbp->details).bdb.dbptr);
	  db->close(db, 0);
	  (dbp->details).bdb.dbptr = NULL;
	}
#endif
      } break;
      case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	DBM *dbm;
	if((dbp->details).ndbm.dbptr) {
	  dbm = (DBM *)((dbp->details).ndbm.dbptr);
	  dbm_close(dbm);
	  (dbp->details).ndbm.dbptr = NULL;
	}
#endif
      } break;
    }
    dbp->app = NULL;
    if(dbp->fn) {
      dk3_delete(dbp->fn);
    }
    dbp->fn = NULL;
    dk3_delete(dbp)
  } 

#line 1444 "dk3dbi.ctr"
}



/**	Synchronize database (write all modifications to file).
	@param	dbp	Database.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_sync_internal(dk3_dbi_t *dbp)
{
  int		back	= 0;
  

#line 1458 "dk3dbi.ctr"
  switch(dbp->tp) {
    case DK3_DB_TYPE_MEMORY: {
      back = dk3dbi_mem_sync(dbp);
    } break;
    case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
      DB	*db;
      db = (DB *)((dbp->details).bdb.dbptr);
      if(db->sync(db, 0) == 0) {
        back = 1;
      }
#endif
    } break;
    case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
      /* There is no sync function! */
      dbp->ec = DK3_ERROR_NOT_SUPPORTED;
#endif
    } break;
  } 

#line 1478 "dk3dbi.ctr"
  return back;
}



/**	Open a database if the type is known.
	This function is invoked with the real file name
	and a known database type.
	@param	fn	File name.
	@param	tp	Database type.
	@param	acc	Access type DK3_DB_ACCESS_xxx,
	see @ref databaseaccess.
	@param	pec	Pointer to variable for error codes, may be NULL.
	@param	app	Application structure for diagnostics, may be NULL.
	@param	trunc	Flag: Truncate database.
	@return	Pointer to database structure on success, NULL on error.
*/
static
dk3_dbi_t *
dk3dbi_open_app_with_tp(
  dkChar const *fn,
  int tp,
  int acc,
  int *pec,
  dk3_app_t *app,
  int trunc
)
{
  dk3_dbi_t		*back	= NULL;
  int			 ok	= 0;	/* Flag: Success. */
  

#line 1509 "dk3dbi.ctr"
  back = dk3_new_app(dk3_dbi_t,1,app);
  if(back) {
      back->ec = 0;
      back->rfk = 0;
      back->wr = ((acc != DK3_DB_ACCESS_READ) ? 1 : 0);
      back->app = app;
      back->fn = NULL;
      back->tp = tp;
      back->mod = 0;
      back->fn = dk3str_dup_app(fn, app);
      if(back->fn) {
        switch(tp) {
	  case DK3_DB_TYPE_MEMORY: {
	    (back->details).mem.s_mem = NULL;
	    (back->details).mem.i_mem = NULL;
	    (back->details).mem.s_mem = dk3sto_open_app(app);
	    if((back->details).mem.s_mem) {
	      dk3sto_set_comp(
	        (back->details).mem.s_mem,
		dk3dbi_node_compare,
		0
	      );
	      (back->details).mem.i_mem = dk3sto_it_open(
	        (back->details).mem.s_mem
	      );
	      if((back->details).mem.i_mem) {
	        if(!(trunc)) {
	          ok = dk3dbi_mem_read_file(back);
		} else {
		  ok = 1;
		}
	      }
	    }
	  } break;
	  case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
	    (back->details).bdb.dbptr = NULL;		

#line 1546 "dk3dbi.ctr"
	    ok = dk3dbi_bdb_open_file(back, trunc);
#else
	    if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; }
	    if(app) {
	      /* ERROR: Database type not supported! */
	      dk3app_log_i3(
	        app, DK3_LL_ERROR, 247, 248, dk3dbi_type_names[1]
	      );
	    }
#endif
	  } break;
	  case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	    (back->details).ndbm.dbptr = NULL;		

#line 1560 "dk3dbi.ctr"
	    ok = dk3dbi_ndbm_open_file(back, trunc);
#else
	    if(pec) { *pec = DK3_ERROR_NOT_SUPPORTED; }	

#line 1563 "dk3dbi.ctr"
	    if(app) {
	      /* ERROR: Database type not supported! */
	      dk3app_log_i3(
	        app, DK3_LL_ERROR, 247, 248, dk3dbi_type_names[2]
	      );
	    }
#endif
	  } break;
        }
      } else {
        if(pec) { *pec = DK3_ERROR_MEMORY; }
      }
      if(!(ok)) {
        dk3dbi_close_internal(back);
        back = NULL;
      }
  } 

#line 1580 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_find_type_and_name(
  dkChar const	**myfn,
  int		 *mytp,
  dkChar const 	 *fn,
  int		  tp,
  int		 *pec,
  dk3_app_t	 *app
)
{
  dkChar		*p1;		/* Start of real file name. */
  int 			back	= 0;
  

#line 1598 "dk3dbi.ctr"
  *mytp = tp;
  p1 = dk3str_chr(fn, dkT(':'));
  if(p1) {			

#line 1601 "dk3dbi.ctr"
    if(p1[1] == dkT(':')) {	

#line 1602 "dk3dbi.ctr"
      *(p1++) = dkT('\0');
      p1++;
      *myfn = p1;
      *mytp = dk3str_array_index(dk3dbi_type_names, fn, 0);
      if(*mytp >= 0) {		

#line 1607 "dk3dbi.ctr"
        if(dk3dbi_type_supported(*mytp)) {
	  back = 1;
	} else {		

#line 1610 "dk3dbi.ctr"
	  if(app) {
	    /* ERROR: Database type not supported! */
	    dk3app_log_i3(app, DK3_LL_ERROR, 247, 248, fn);
	  }
	  if(pec) {
	    *pec = DK3_ERROR_NOT_SUPPORTED;
	  }
	}
      } else {			

#line 1619 "dk3dbi.ctr"
        if(app) {
	  /* ERROR: Database type not found! */
	  dk3app_log_i3(app, DK3_LL_ERROR, 247, 248, fn);
	}
	if(pec) {
	  *pec = DK3_ERROR_INVALID_ARGS;
	}
      }
    } else {			

#line 1628 "dk3dbi.ctr"
      /* Single colon */
      *myfn = fn;
      if(tp < 0) {
        *mytp = dk3dbi_choose_best_available_type();
      }
      back = 1;
    }
  } else {			

#line 1636 "dk3dbi.ctr"
    /* No colon found */
    *myfn = fn;
    if(tp < 0) {
      *mytp = dk3dbi_choose_best_available_type();
    }
    back = 1;
  }
  if(back) {
    if(*mytp >= 0) {
      if(!dk3dbi_type_supported(*mytp)) {
        back = 0;
	if(app) {
	  /* ERROR: Database type not supported! */
	}
	if(pec) {
	  *pec = DK3_ERROR_NOT_SUPPORTED;
	}
      }
    } else {
      back = 0;
    }
  } 

#line 1658 "dk3dbi.ctr"
  return back;
}



/**	Open a database.
	@param	fn	File name.
	@param	tp	Database type.
	@param	acc	Access type.
	@param	pec	Pointer to error code variable.
	@param	app	Application structure for diagnostics, may be NULL.
	@param	trunc	Flag: Truncate database.
	@return	Pointer to new database on success, NULL on error.
*/
static
dk3_dbi_t *
dk3dbi_open_internal(
  dkChar const *fn,
  int tp,
  int acc,
  int *pec,
  dk3_app_t *app,
  int trunc
)
{
  dkChar		 fnb[DK3_MAX_PATH + 16];	/* File name buffer. */
  dk3_dbi_t		*back	= NULL;
  dkChar const		*myfn = NULL;			/* Real file name. */
  int			 mytp = DK3_DB_TYPE_UNKNOWN;	/* Database type. */
  

#line 1688 "dk3dbi.ctr"
  if(fn) {						

#line 1689 "dk3dbi.ctr"
    if(dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) {	

#line 1690 "dk3dbi.ctr"
      dk3str_cpy(fnb, fn);
      if(dk3dbi_find_type_and_name(&myfn ,&mytp, fnb, tp, pec, app))
      {							

#line 1693 "dk3dbi.ctr"
        if((myfn) && (mytp >= 0)) {			

#line 1694 "dk3dbi.ctr"
          back = dk3dbi_open_app_with_tp(myfn, mytp, acc, pec, app, trunc);
	} else {					

#line 1696 "dk3dbi.ctr"
	  /* BUG: Must not happen! */
	}
      }
    } else {						

#line 1700 "dk3dbi.ctr"
      if(app) {
        /* ERROR: File name too long! */
	dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn);
      }
      if(pec) {
	*pec = DK3_ERROR_INVALID_ARGS;
      }
    }
  } else {						

#line 1709 "dk3dbi.ctr"
  } 

#line 1710 "dk3dbi.ctr"
  return back;
}



dk3_dbi_t *
dk3dbi_open_app(
  dkChar const *fn,
  int tp,
  int acc,
  int *pec,
  dk3_app_t *app
)
{
  dk3_dbi_t *back;
  back = dk3dbi_open_internal(fn, tp, acc, pec, app, 0);
  return back;
}



dk3_dbi_t *
dk3dbi_open_truncate_app(
  dkChar const *fn,
  int tp,
  int acc,
  int *pec,
  dk3_app_t *app
)
{
  dk3_dbi_t *back;
  

#line 1742 "dk3dbi.ctr"
  back = dk3dbi_open_internal(fn, tp, acc, pec, app, 1);
  

#line 1744 "dk3dbi.ctr"
  return back;
}



dk3_dbi_t *
dk3dbi_open(dkChar const *fn, int tp, int acc, int *pec)
{
  dk3_dbi_t		*back	= NULL;
  

#line 1754 "dk3dbi.ctr"
  back = dk3dbi_open_app(fn, tp, acc, pec, NULL);
  

#line 1756 "dk3dbi.ctr"
  return back;
}



dk3_dbi_t *
dk3dbi_open_truncate(dkChar const *fn, int tp, int acc, int *pec)
{
  dk3_dbi_t *back;
  back = dk3dbi_open_truncate_app(fn, tp, acc, pec, NULL);
  return back;
}



int
dk3dbi_close(dk3_dbi_t *dbp)
{
  int back = 0;
  

#line 1776 "dk3dbi.ctr"
  if(dbp) {
    back = 1;
    if(dbp->mod) {	

#line 1779 "dk3dbi.ctr"
      back = dk3dbi_sync_internal(dbp);
    }
    dk3dbi_close_internal(dbp);
  } 

#line 1783 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_set(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  int			back	= 0;
  

#line 1793 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
    if((key->dt) && (key->sz) && (val->dt) && (val->sz)) {
      if(dbp->wr) {
        switch(dbp->tp) {
	  case DK3_DB_TYPE_MEMORY: {
	    back = dk3dbi_mem_set(dbp, key, val);
	    dbp->mod = 1;
	  } break;
	  case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
	    back = dk3dbi_bdb_set(dbp, key, val);
	    dbp->mod = 1;
#endif
	  } break;
	  case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	    back = dk3dbi_ndbm_set(dbp, key, val);
	    dbp->mod = 1;
#endif
	  } break;
        }
      } else {
        /* ERROR: Write operations denied! */
	dbp->ec = DK3_ERROR_NOT_OPENED_FOR_WRITING;
	if(dbp->app) {
	  dk3app_log_i1(dbp->app, DK3_LL_ERROR, 251);
	}
      }
    } else {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 1829 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get(dk3_dbi_t *dbp, dk3_datum_t *key, dk3_datum_t *val)
{
  int			back = 0;
  

#line 1839 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
    if((key->dt) && (key->sz) && (val->dt) && (val->sz)) {
      switch(dbp->tp) {
	case DK3_DB_TYPE_MEMORY: {
	  back = dk3dbi_mem_get(dbp, key, val);
	} break;
	case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
	  back = dk3dbi_bdb_get(dbp, key, val);
#endif
	} break;
	case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	  back = dk3dbi_ndbm_get(dbp, key, val);
#endif
	} break;
      }
    } else {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 1864 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_delete(dk3_dbi_t *dbp, dk3_datum_t *key)
{
  int			back	= 0;
  

#line 1874 "dk3dbi.ctr"
  if((dbp) && (key)) {
    if((key->dt) && (key->sz)) {
      switch(dbp->tp) {
	case DK3_DB_TYPE_MEMORY: {
	  back = dk3dbi_mem_delete(dbp, key);
	  dbp->mod = 1;
	} break;
	case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
	  back = dk3dbi_bdb_delete(dbp, key);
	  dbp->mod = 1;
#endif
	} break;
	case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	  back = dk3dbi_ndbm_delete(dbp, key);
	  dbp->mod = 1;
#endif
	} break;
      }
    } else {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 1902 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_traverse(dk3_dbi_t *dbp, void *obj, dk3_db_traverse_fct_t *fct)
{
  int			back	= 0;
  

#line 1912 "dk3dbi.ctr"
  if((dbp) && (fct)) {
      switch(dbp->tp) {
	case DK3_DB_TYPE_MEMORY: {
	  back = dk3dbi_mem_traverse(dbp, obj, fct);
	} break;
	case DK3_DB_TYPE_BDB: {
#if DK3_USE_DB
	  back = dk3dbi_bdb_traverse(dbp, obj, fct);
#endif
	} break;
	case DK3_DB_TYPE_NDBM: {
#if DK3_USE_NDBM
	  back = dk3dbi_ndbm_traverse(dbp, obj, fct);
#endif
	} break;
      }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 1933 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_sync(dk3_dbi_t *dbp)
{
  int			back	= 0;
  

#line 1943 "dk3dbi.ctr"
  if(dbp) {
    back = 1;
    if(dbp->mod) {
      back = dk3dbi_sync_internal(dbp);
      if(back) { dbp->mod = 0; }
    }
  } 

#line 1950 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get_error(dk3_dbi_t *dbp, int res)
{
  int			back	= 0;
  

#line 1960 "dk3dbi.ctr"
  if(dbp) {
    back = dbp->ec;
    if(res) { dbp->ec = 0; }
  } 

#line 1964 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_set_c8_string(
  dk3_dbi_t	*dbp,
  char const	*key,
  char const	*val
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  size_t	vs;		/* Value size (number of bytes). */
  int		back	= 0;
  

#line 1982 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
    ks = dk3str_c8_len(key);
    vs = dk3str_c8_len(val);
    ks++; vs++;
    if((ks) && (vs)) {
      k.dt = (void *)key; k.sz = ks;
      v.dt = (void *)val; v.sz = vs;
      back = dk3dbi_set(dbp, &k, &v);
    } else {
      /* ERROR: At least one numeric overflow. */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2002 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get_c8_string(
  dk3_dbi_t	*dbp,
  char const	*key,
  char		*vb,
  size_t	 vbsz
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  int		back	= 0;
  int		orfk;
  

#line 2021 "dk3dbi.ctr"
  if((dbp) && (key) && (vb) && (vbsz)) {
    ks = dk3str_c8_len(key);
    ks++;
    if(ks) {
      k.dt = (void *)key; k.sz = ks;
      v.dt = vb; v.sz = vbsz;
      orfk = dbp->rfk;
      dbp->rfk = 0;
      if(dk3dbi_get(dbp, &k, &v)) {
        back = 1;
        if(v.sz > 0) {
	  if(v.sz < vbsz) {
	    vb[v.sz] = '\0';
	  } else {
	    vb[vbsz - 1] = '\0';
	  }
	} else {
	  vb[0] = '\0';
	}
      }
      dbp->rfk = orfk;
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2054 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_delete_c8_string(
  dk3_dbi_t	*dbp,
  char	const	*key
)
{
  dk3_datum_t	k;		/* Key datum. */
  size_t	ks;		/* Key size in bytes. */
  int		back = 0;
  

#line 2069 "dk3dbi.ctr"
  if((dbp) && (key)) {
    ks = dk3str_c8_len(key);
    ks++;
    if(ks) {
      k.dt = (void *)key; k.sz = ks;
      back = dk3dbi_delete(dbp, &k);
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2087 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_set_c16_string(
  dk3_dbi_t		*dbp,
  dk3_c16_t const	*key,
  dk3_c16_t const	*val
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  size_t	vs;		/* Value size (number of bytes). */
  int		back = 0;
  

#line 2105 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
    ks = dk3str_c16_len(key);
    vs = dk3str_c16_len(val);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 2, NULL);
    vs = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(vs, 1, NULL), 2, NULL);
    if((ks) && (vs)) {
      k.dt = (void *)key; k.sz = ks; v.dt = (void *)val; v.sz = vs;
      back = dk3dbi_set(dbp, &k, &v);
    } else {
      /* ERROR: Size overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2125 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get_c16_string(
  dk3_dbi_t		*dbp,
  dk3_c16_t const	*key,
  dk3_c16_t		*vb,
  size_t		 vbsz
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  size_t	vs;		/* Value size (number of bytes). */
  int		back	= 0;
  int		orfk;
  

#line 2145 "dk3dbi.ctr"
  if((dbp) && (key) && (vb) && (vbsz)) {
    ks = dk3str_c16_len(key);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 2, NULL);
    vs = dk3ma_sz_mul_ok(vbsz, 2, NULL);
    if((ks) && (vs)) {
      k.dt = (void *)key; k.sz = ks; v.dt = vb, v.sz = vs;
      orfk = dbp->rfk;
      dbp->rfk = 0;
      if(dk3dbi_get(dbp, &k, &v)) {
        if(!((v.sz) % 2)) {
	  back = 1;
	  v.sz = v.sz / 2;
	  if(v.sz > 0) {
	    if(v.sz < vbsz) {
	      vb[v.sz] = 0U;
	    } else {
	      vb[vbsz - 1] = 0U;
	    }
	  } else {
	    vb[0] = 0U;
	  }
	} else {
	  /* ERROR: Damaged entry! */
	  if(dbp->app) {
	    dk3app_log_i1(dbp->app, DK3_LL_ERROR, 250);
	  }
	  dbp->ec = DK3_ERROR_DATA_DAMAGED;
	}
      }
      dbp->rfk = orfk;
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2187 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_delete_c16_string(
  dk3_dbi_t		*dbp,
  dk3_c16_t const	*key
)
{
  dk3_datum_t	k;		/* Key datum. */
  size_t	ks;		/* Key size (number of bytes). */
  int		back	= 0;
  

#line 2202 "dk3dbi.ctr"
  if((dbp) && (key)) {
    ks = dk3str_c16_len(key);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 2, NULL);
    if(ks) {
      k.dt = (void *)key; k.sz = ks;
      back = dk3dbi_delete(dbp, &k);
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2220 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_set_c32_string(
  dk3_dbi_t		*dbp,
  dk3_c32_t const	*key,
  dk3_c32_t const	*val
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  size_t	vs;		/* Value size (number of bytes). */
  int		back	= 0;
  

#line 2238 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
    ks = dk3str_c32_len(key);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 4, NULL);
    vs = dk3str_c32_len(val);
    vs = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(vs, 1, NULL), 4, NULL);
    if((ks) && (vs)) {
      k.dt = (void *)key; k.sz = ks; v.dt = (void *)val; v.sz = vs;
      back = dk3dbi_set(dbp, &k, &v);
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2258 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get_c32_string(
  dk3_dbi_t		*dbp,
  dk3_c32_t const	*key,
  dk3_c32_t		*vb,
  size_t		 vbsz
)
{
  dk3_datum_t	k;		/* Key datum. */
  dk3_datum_t	v;		/* Value datum. */
  size_t	ks;		/* Key size (number of bytes). */
  size_t	vs;		/* Value size (number of bytes). */
  int		back	= 0;
  int		orfk;
  

#line 2278 "dk3dbi.ctr"
  if((dbp) && (key) && (vb) && (vbsz)) {
    ks = dk3str_c32_len(key);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 4, NULL);
    vs = dk3ma_sz_mul_ok(vbsz, 4, NULL);
    if((ks) && (vs)) {
      k.dt = (void *)key; k.sz = ks; v.dt = vb; v.sz = vs;
      orfk = dbp->rfk;
      dbp->rfk = 0;
      if(dk3dbi_get(dbp, &k, &v)) {
        if(!((v.sz) % 4)) {
	  back = 1;
	  v.sz = v.sz / 4;
	  if(v.sz > 0) {
	    if(v.sz < vbsz) {
	      vb[v.sz] = 0UL;
	    } else {
	      vb[vbsz - 1] = 0UL;
	    }
	  } else {
	    vb[0] = 0UL;
	  }
	} else {
	  /* ERROR: Damaged entry! */
	  if(dbp->app) {
	    dk3app_log_i1(dbp->app, DK3_LL_ERROR, 250);
	  }
	  dbp->ec = DK3_ERROR_DATA_DAMAGED;
	}
      }
      dbp->rfk = orfk;
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2320 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_delete_c32_string(
  dk3_dbi_t		*dbp,
  dk3_c32_t const	*key
)
{
  dk3_datum_t	k;		/* Key datum. */
  size_t	ks;		/* Key size (number of bytes). */
  int		back	= 0;
  

#line 2335 "dk3dbi.ctr"
  if((dbp) && (key)) {
    ks = dk3str_c32_len(key);
    ks = dk3ma_sz_mul_ok(dk3ma_sz_add_ok(ks, 1, NULL), 4, NULL);
    if(ks) {
      k.dt = (void *)key; k.sz = ks;
      back = dk3dbi_delete(dbp, &k);
    } else {
      /* ERROR: Numeric overflow! */
      if(dbp->app) {
        dk3app_log_i1(dbp->app, DK3_LL_ERROR, 15);
      }
      dbp->ec = DK3_ERROR_MATH_OVERFLOW;
    }
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2353 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_set_string(
  dk3_dbi_t	*dbp,
  dkChar const	*key,
  dkChar const	*val
)
{
  int back = 0;
  

#line 2367 "dk3dbi.ctr"
  if((dbp) && (key) && (val)) {
#if DK3_CHAR_SIZE > 1
#if DK3_CHAR_SIZE > 2
    back = dk3dbi_set_c32_string(dbp, key, val);
#else
    back = dk3dbi_set_c16_string(dbp, key, val);
#endif
#else
    back = dk3dbi_set_c8_string(dbp, key, val);
#endif
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2382 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_get_string(
  dk3_dbi_t		*dbp,
  dkChar const		*key,
  dkChar		*vb,
  size_t		 vbsz
)
{
  int		back = 0;
  

#line 2397 "dk3dbi.ctr"
  if((dbp) && (key) && (vb) && (vbsz)) {
#if DK3_CHAR_SIZE > 1
#if DK3_CHAR_SIZE > 2
    back = dk3dbi_get_c32_string(dbp, key, vb, vbsz);
#else
    back = dk3dbi_get_c16_string(dbp, key, vb, vbsz);
#endif
#else
    back = dk3dbi_get_c8_string(dbp, key, vb, vbsz);
#endif
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2412 "dk3dbi.ctr"
  return back;
}


int
dk3dbi_delete_string(
  dk3_dbi_t	*dbp,
  dkChar const	*key
)
{
  int		back = 0;
  

#line 2424 "dk3dbi.ctr"
  if((dbp) && (key)) {
#if DK3_CHAR_SIZE > 1
#if DK3_CHAR_SIZE > 2
    back = dk3dbi_delete_c32_string(dbp, key);
#else
    back = dk3dbi_delete_c16_string(dbp, key);
#endif
#else
    back = dk3dbi_delete_c8_string(dbp, key);
#endif
  } else {
    if(dbp) {
      dbp->ec = DK3_ERROR_INVALID_ARGS;
    }
  } 

#line 2439 "dk3dbi.ctr"
  return back;
}



/**	Delete or truncate a database file.
	@param	fn	File name.
	@param	tp	Database type.
	@param	del	Flag: Delete (non-zero) or truncate (0).
	@param	app	Application structure for diagnostics, may be NULL.
	@return	1 on success, 0 on error.
*/
static
int
dk3dbi_dbfile_del_or_trunc(dkChar const *fn, int tp, int del, dk3_app_t *app)
{
  dkChar		fnb[DK3_MAX_PATH + 16];	/* Copy of file name. */
  char			c8fn[DK3_MAX_PATH];	/* File name as 8-bit. */
  FILE			*fipo;			/* File to truncate. */
  dkChar const		*myfn;			/* File name. */
  int			ec = 0;			/* Error code. */
  int			mytp;			/* DB type. */
  int			back = 0;
  

#line 2463 "dk3dbi.ctr"
  mytp = tp;
  if(fn) {
    if(dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) {
      dk3str_cpy(fnb, fn);
      if(dk3dbi_find_type_and_name(&myfn, &mytp, fnb, tp, &ec, app)) {
        if((myfn) && (mytp >= 0)) {		
	  switch(mytp) {
	    case DK3_DB_TYPE_MEMORY: {		

#line 2471 "dk3dbi.ctr"
	      if(del) {
	        dk3sf_remove_file_app(myfn, app);
		back = 1;
	      } else {
	        fipo = dk3sf_fopen_app(myfn, dk3dbi_file_open_modes[1], app);
		if(fipo) {			

#line 2477 "dk3dbi.ctr"
		  if(dk3sf_fclose_fn_app(fipo, myfn, app)) {
		    back = 1;
		  }
		} else {			

#line 2481 "dk3dbi.ctr"
		}
	      }
	    } break;
	    case DK3_DB_TYPE_BDB: {		

#line 2485 "dk3dbi.ctr"
	      if(dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app)) {
	        if(del) {
		  dk3sf_remove_file_app(myfn, app);
		  back = 1;
		} else {
#if DK3_USE_DB
		  DB		*db = NULL;
		  int		ret;
		  u_int32_t	flags;
		  ret = db_create(&db, NULL, 0);
		  if(ret == 0) {		

#line 2496 "dk3dbi.ctr"
		    flags = DB_CREATE | DB_TRUNCATE;
		    ret = db->open(db, NULL, c8fn, NULL, DB_BTREE, flags, 0600);
		    if(ret == 0) {		

#line 2499 "dk3dbi.ctr"
		      back = 1;
		    } else {			

#line 2501 "dk3dbi.ctr"
		    }
		    if(db) {
		      db->close(db, 0);
		    }
		  } else {			

#line 2506 "dk3dbi.ctr"
		  }
#endif
		}
	      } else {		

#line 2510 "dk3dbi.ctr"
	      }
	    } break;
	    case DK3_DB_TYPE_NDBM: {		

#line 2513 "dk3dbi.ctr"
	      if(dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app)) {
	        if(del) {
		  if((dk3str_c8_len(c8fn)
		      + dk3str_c8_len(dk3dbi_ndbm_suffixes[0])
		     ) < sizeof(c8fn)
		  )
		  {
		    dk3str_c8_cat(c8fn, dk3dbi_ndbm_suffixes[0]);
		    dk3sf_c8_remove_file_app(c8fn, app);
		    dk3sf_filename_to_c8(c8fn, sizeof(c8fn), myfn, app);
		    if((dk3str_c8_len(c8fn)
		        + dk3str_c8_len(dk3dbi_ndbm_suffixes[1])
		       ) < sizeof(c8fn)
		    )
		    {
		      dk3str_c8_cat(c8fn, dk3dbi_ndbm_suffixes[1]);
		      dk3sf_c8_remove_file_app(c8fn, app);
		      back = 1;
		    }
		  }
		} else {
#if DK3_USE_NDBM
		  DBM		*dbm = NULL;
		  dbm = dbm_open(c8fn, (O_RDWR | O_CREAT | O_TRUNC), 0600);
		  if(dbm) {
		    dbm_close(dbm);
		  }
#endif
		}
	      } else {	

#line 2543 "dk3dbi.ctr"
	      }
	    } break;
	    default: {
	      /* BUG: Illegal database type, must not happen! */
	    } break;
	  }
	} else {		

#line 2550 "dk3dbi.ctr"
	  /* BUG: Must not happen! */
	}
      } else {			

#line 2553 "dk3dbi.ctr"
        /* Error: Name or type not found, already reported! */
      }
    } else {			

#line 2556 "dk3dbi.ctr"
      /* ERROR: File name too long! */
      dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, fn);
    }
  } else {			

#line 2560 "dk3dbi.ctr"
  } 

#line 2561 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_dbfile_delete_app(dkChar const *fn, int tp, dk3_app_t *app)
{
  int back;
  

#line 2571 "dk3dbi.ctr"
  back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, app);
  

#line 2573 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_dbfile_truncate_app(dkChar const *fn, int tp, dk3_app_t *app)
{
  int back;
  

#line 2583 "dk3dbi.ctr"
  back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, app);
  

#line 2585 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_dbfile_delete(dkChar const *fn, int tp)
{
  int back;
  

#line 2595 "dk3dbi.ctr"
  back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, NULL);
  

#line 2597 "dk3dbi.ctr"
  return back;
}



int
dk3dbi_dbfile_truncate(dkChar const *fn, int tp)
{
  int back;
  

#line 2607 "dk3dbi.ctr"
  back = dk3dbi_dbfile_del_or_trunc(fn, tp, 1, NULL);
  

#line 2609 "dk3dbi.ctr"
  return back;
}



#if !DK3_ON_WINDOWS
#if DK3_CHAR_SIZE == 1
#if DK3_HAVE_CHOWN && DK3_HAVE_CHMOD
static
int
dk3dbi_change_file_user_and_permissions(
  dk3_dbi_t *db, char const *fn, uid_t uid, gid_t gid, mode_t mode
)
{
  int		 back = 0;
  if(0 == chown(fn, uid, gid)) {
    if(0 == chmod(fn, mode)) {
      back = 1;
    } else {
      /* ERROR: Failed to change file permissions! */
      if(db->app) {
        dk3app_log_i3(db->app, DK3_LL_ERROR, 272, 273, fn);
      }
    }
  } else {
    /* ERROR: Failed to change file ownership! */
    if(db->app) {
      dk3app_log_i3(db->app, DK3_LL_ERROR, 270, 271, fn);
    }
  }
  return  back;
}



int
dk3dbi_change_user_and_permissions(
  dk3_dbi_t		*db,
  uid_t			 uid,
  gid_t			 gid,
  mode_t		 mode
)
{
  dkChar	 fnb[DK3_MAX_PATH];
  int		 back = 0;
  if(db) {
    switch(db->tp) {
      case DK3_DB_TYPE_MEMORY:
      case DK3_DB_TYPE_BDB: {
        if(db->fn) {
	  back = dk3dbi_change_file_user_and_permissions(
	    db, db->fn, uid, gid, mode
	  );
	} else {
	  /* ERROR: No file name for database! */
	  if(db->app) {
	    dk3app_log_i1(db->app, DK3_LL_ERROR, 269);
	  }
	}
      } break;
      case DK3_DB_TYPE_NDBM: {
        if(db->fn) {
	  if(dk3str_len(db->fn) < DK3_SIZEOF(fnb,dkChar)) {
	    back = 1;
	    dk3str_cpy(fnb, db->fn);
	    if((dk3str_len(fnb) + dk3str_len(dk3dbi_ndbm_suffixes[0]))
	       < DK3_SIZEOF(fnb,dkChar)
	    ) 
	    {
	      dk3str_cat(fnb, dk3dbi_ndbm_suffixes[0]);
	      if(!dk3dbi_change_file_user_and_permissions(db,fnb,uid,gid,mode))
	      {
	        back = 0;
	      }
	    }
	    else
	    {
	      /* ERROR: File name too long! */
	      if(db->app) {
	        dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn);
	      }
	      back = 0;
	    }
	    dk3str_cpy(fnb, db->fn);
	    if((dk3str_len(fnb) + dk3str_len(dk3dbi_ndbm_suffixes[1]))
	       < DK3_SIZEOF(fnb,dkChar)
	    ) 
	    {
	      dk3str_cat(fnb, dk3dbi_ndbm_suffixes[1]);
	      if(!dk3dbi_change_file_user_and_permissions(db,fnb,uid,gid,mode))
	      {
	        back = 0;
	      }
	    }
	    else
	    {
	      /* ERROR: File name too long! */
	      if(db->app) {
	        dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn);
	      }
	      back = 0;
	    }
	  } else {
	    /* ERROR: File name too long! */
	    if(db->app) {
	      dk3app_log_i3(db->app, DK3_LL_ERROR, 66, 67, db->fn);
	    }
	  }
	} else {
	  /* ERROR: No file name for database! */
	  if(db->app) {
	    dk3app_log_i1(db->app, DK3_LL_ERROR, 269);
	  }
	}
      } break;
    }
  }
  return back;
}
#endif
#endif
#endif

