summaryrefslogtreecommitdiffstats
path: root/bdbobj
diff options
context:
space:
mode:
Diffstat (limited to 'bdbobj')
-rw-r--r--bdbobj/.gitignore1
-rw-r--r--bdbobj/Makefile.am32
-rw-r--r--bdbobj/bdbobj.c294
-rw-r--r--bdbobj/bdbobj.h183
-rw-r--r--bdbobj/bdbobj2.c81
-rw-r--r--bdbobj/bdbobj3.c28
-rw-r--r--bdbobj/configure.in79
-rw-r--r--bdbobj/testbdb.C165
-rwxr-xr-xbdbobj/testsuite14
-rw-r--r--bdbobj/testsuite.txt11
10 files changed, 888 insertions, 0 deletions
diff --git a/bdbobj/.gitignore b/bdbobj/.gitignore
new file mode 100644
index 0000000..96765b2
--- /dev/null
+++ b/bdbobj/.gitignore
@@ -0,0 +1 @@
+/testbdb
diff --git a/bdbobj/Makefile.am b/bdbobj/Makefile.am
new file mode 100644
index 0000000..8f8fb63
--- /dev/null
+++ b/bdbobj/Makefile.am
@@ -0,0 +1,32 @@
+#
+# Copyright 1998 - 2005 Double Precision, Inc. See COPYING for
+# distribution information.
+
+
+LIBDBOBJSOURCES=bdbobj.h bdbobj.c bdbobj2.c bdbobj3.c
+TESTBDBSOURCES=testbdb.C
+
+if FOUND_DB
+noinst_LTLIBRARIES=libbdbobj.la
+noinst_PROGRAMS=testbdb
+
+libbdbobj_la_SOURCES=$(LIBDBOBJSOURCES)
+libbdbobj_la_LIBADD=@LIBDB@
+
+testbdb_SOURCES=$(TESTBDBSOURCES)
+
+testbdb_DEPENDENCIES=libbdbobj.la
+testbdb_LDADD=libbdbobj.la
+testbdb_LDFLAGS=-static
+
+check-am:
+ $(srcdir)/testsuite | cmp -s - $(srcdir)/testsuite.txt
+else
+noinst_SCRIPTS=notfound
+
+notfound:
+ @exit 0
+endif
+
+EXTRA_DIST=$(LIBDBOBJSOURCES) $(TESTBDBSOURCES) testsuite testsuite.txt
+
diff --git a/bdbobj/bdbobj.c b/bdbobj/bdbobj.c
new file mode 100644
index 0000000..1b64876
--- /dev/null
+++ b/bdbobj/bdbobj.c
@@ -0,0 +1,294 @@
+/*
+** Copyright 1998 - 2003 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "bdbobj.h"
+
+void bdbobj_init(struct bdbobj *obj)
+{
+ obj->has_dbf=0;
+
+#if DB_VERSION_MAJOR >= 2
+ obj->has_dbc=0;
+#endif
+}
+
+void bdbobj_close(struct bdbobj *obj)
+{
+#if DB_VERSION_MAJOR >= 2
+ if (obj->has_dbc)
+ {
+ (*obj->dbc->c_close)(obj->dbc);
+ obj->has_dbc=0;
+ }
+#endif
+ if ( obj->has_dbf )
+ {
+#if DB_VERSION_MAJOR < 2
+ (*obj->dbf->close)(obj->dbf);
+#else
+ (*obj->dbf->close)(obj->dbf, 0);
+#endif
+ obj->has_dbf=0;
+ }
+}
+
+int bdbobj_open(struct bdbobj *obj, const char *filename, const char *modestr)
+{
+#if DB_VERSION_MAJOR < 2
+
+int flags=O_RDONLY;
+
+#else
+
+int flags=DB_RDONLY;
+
+#endif
+
+DBTYPE dbtype=DB_HASH;
+
+ for ( ; *modestr; modestr++)
+ switch (*modestr) {
+ case 'c':
+ case 'C':
+#if DB_VERSION_MAJOR < 2
+ flags=O_RDWR|O_CREAT;
+#else
+ flags=DB_CREATE;
+#endif
+ break;
+ case 'w':
+ case 'W':
+#if DB_VERSION_MAJOR < 2
+ flags=O_RDWR;
+#else
+ flags=0;
+#endif
+ break;
+ case 'n':
+ case 'N':
+#if DB_VERSION_MAJOR < 2
+ flags=O_RDWR|O_CREAT|O_TRUNC;
+#else
+ flags=DB_CREATE|DB_TRUNCATE;
+#endif
+
+ break;
+
+ case 'b':
+ case 'B':
+ dbtype=DB_BTREE;
+ break;
+
+ case 'e':
+ case 'E':
+ dbtype=DB_RECNO;
+ break;
+ }
+
+ bdbobj_close(obj);
+
+#if DB_VERSION_MAJOR < 3
+#if DB_VERSION_MAJOR < 2
+ if ( (obj->dbf=dbopen(filename, flags, 0664, dbtype, 0)) != 0)
+#else
+ if ( db_open(filename, dbtype, flags, 0664, 0, 0, &obj->dbf) == 0)
+#endif
+#else
+ obj->dbf=0;
+
+#define DB_40 0
+
+#if DB_VERSION_MAJOR == 4
+#if DB_VERSION_MINOR == 0
+
+#undef DB_40
+#define DB_40 1
+
+#endif
+#endif
+
+#if DB_VERSION_MAJOR == 3
+#undef DB_40
+#define DB_40 1
+#endif
+
+ if (db_create(&obj->dbf, NULL, 0) == 0)
+ {
+ if ( (*obj->dbf->open)(obj->dbf,
+
+#if DB_40
+
+#else
+ NULL,
+#endif
+
+ filename, NULL,
+ dbtype, flags, 0664))
+ {
+ (*obj->dbf->close)(obj->dbf, DB_NOSYNC);
+ obj->dbf=0;
+ }
+ }
+
+ if (obj->dbf)
+#endif
+ {
+#ifdef FD_CLOEXEC
+
+#if DB_VERSION_MAJOR < 2
+ int fd=(*obj->dbf->fd)(obj->dbf);
+#else
+ int fd;
+
+ if ((*obj->dbf->fd)(obj->dbf, &fd))
+ fd= -1;
+#endif
+
+ if (fd >= 0) fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+
+ obj->has_dbf=1;
+ return (0);
+ }
+ return (-1);
+}
+
+int bdbobj_store(struct bdbobj *obj, const char *key, size_t keylen,
+ const char *data,
+ size_t datalen,
+ const char *mode)
+{
+DBT dkey, dval;
+
+ memset(&dkey, 0, sizeof(dkey));
+ memset(&dval, 0, sizeof(dval));
+
+ dkey.data=(void *)key;
+ dkey.size=keylen;
+ dval.data=(void *)data;
+ dval.size=datalen;
+
+#if DB_VERSION_MAJOR < 2
+ return (obj->has_dbf ? (*obj->dbf->put)(obj->dbf, &dkey, &dval, (
+ *mode == 'i' || *mode == 'I' ? R_NOOVERWRITE:0)):-1);
+#else
+ return (obj->has_dbf ? (*obj->dbf->put)(obj->dbf, 0, &dkey, &dval, (
+ *mode == 'i' || *mode == 'I' ? DB_NOOVERWRITE:0)):-1);
+#endif
+}
+
+static char *doquery(struct bdbobj *obj,
+ const char *, size_t, size_t *, const char *);
+
+char *bdbobj_fetch(struct bdbobj *obj, const char *key, size_t keylen,
+ size_t *datalen, const char *options)
+{
+char *p=doquery(obj, key, keylen, datalen, options);
+char *q;
+
+ if (!p) return (0);
+
+ q=(char *)malloc(*datalen);
+
+ if (!q) return (0);
+
+ memcpy(q, p, *datalen);
+ return (q);
+}
+
+char *dofetch(struct bdbobj *, const char *, size_t, size_t *);
+
+static char *doquery(struct bdbobj *obj, const char *key, size_t keylen,
+ size_t *datalen, const char *options)
+{
+char *p;
+
+ for (;;)
+ {
+ if ((p=dofetch(obj, key, keylen, datalen)) != 0)
+ return (p);
+ if (!options) break;
+ if (*options == 'I')
+ {
+ while (keylen && key[--keylen] != '.')
+ ;
+ if (!keylen) break;
+ continue;
+ }
+ if (*options == 'D')
+ {
+ size_t i;
+
+ for (i=0; i<keylen; i++)
+ if (key[i] == '@') { ++i; break; }
+ if (i < keylen)
+ {
+ if ((p=dofetch(obj, key, i, datalen)) != 0)
+ return (p);
+ key += i;
+ keylen -= i;
+ continue;
+ }
+
+ for (i=0; i<keylen; i++)
+ if (key[i] == '.') { ++i; break; }
+ if (i < keylen)
+ {
+ key += i;
+ keylen -= i;
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+ return (0);
+}
+
+char *dofetch(struct bdbobj *obj, const char *key, size_t keylen,
+ size_t *datalen)
+{
+DBT dkey, val;
+
+ if (!obj->has_dbf) return (0);
+
+ memset(&dkey, 0, sizeof(dkey));
+ memset(&val, 0, sizeof(val));
+
+ dkey.data=(void *)key;
+ dkey.size=keylen;
+
+#if DB_VERSION_MAJOR < 2
+ if ( (*obj->dbf->get)(obj->dbf, &dkey, &val, 0)) return (0);
+#else
+ if ( (*obj->dbf->get)(obj->dbf, 0, &dkey, &val, 0)) return (0);
+#endif
+
+ *datalen=val.size;
+ return ((char *)val.data);
+}
+
+int bdbobj_exists(struct bdbobj *obj, const char *key, size_t keylen)
+{
+size_t datalen;
+char *p=doquery(obj, key, keylen, &datalen, 0);
+
+ return (p ? 1:0);
+}
diff --git a/bdbobj/bdbobj.h b/bdbobj/bdbobj.h
new file mode 100644
index 0000000..d3cfcf8
--- /dev/null
+++ b/bdbobj/bdbobj.h
@@ -0,0 +1,183 @@
+#ifndef bdbobj_h
+#define bdbobj_h
+
+/*
+** Copyright 1998 - 2007 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <db.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bdbobj {
+ DB *dbf;
+ int has_dbf;
+
+#if DB_VERSION_MAJOR >= 2
+ DBC *dbc;
+ int has_dbc;
+#endif
+ } ;
+
+void bdbobj_init(struct bdbobj *);
+
+int bdbobj_open(struct bdbobj *, const char *, const char *);
+void bdbobj_close(struct bdbobj *);
+
+#define bdbobj_isopen(p) (!!(p)->has_dbf)
+
+char *bdbobj_fetch(struct bdbobj *, const char *, size_t, size_t *, const char *);
+
+int bdbobj_exists(struct bdbobj *, const char *, size_t);
+int bdbobj_delete(struct bdbobj *, const char *, size_t);
+int bdbobj_store(struct bdbobj *, const char *, size_t, const char *,
+ size_t, const char *);
+
+char *bdbobj_firstkey(struct bdbobj *, size_t *, char **, size_t *);
+char *bdbobj_nextkey(struct bdbobj *, size_t *, char **, size_t *);
+
+#ifdef __cplusplus
+} ;
+
+#include <string>
+
+
+class BDbObj {
+ struct bdbobj obj;
+
+ BDbObj(const BDbObj &); // Undefined
+ BDbObj &operator=(const BDbObj &); // Undefined
+ char *do_fetch(const char *, size_t, size_t &);
+ char *do_query(const char *, size_t, size_t &, const char *);
+
+public:
+ BDbObj() { bdbobj_init(&obj); }
+ ~BDbObj() { bdbobj_close(&obj); }
+ int Open(std::string filename, const char *mode)
+ {
+ return (bdbobj_open(&obj, filename.c_str(), mode));
+ }
+
+ int IsOpen() { return (bdbobj_isopen(&obj)); }
+ void Close() { bdbobj_close(&obj); }
+
+ std::string Fetch(std::string key, std::string mode)
+ {
+ size_t l;
+ char *p=Fetch(key.c_str(), key.size(), l, mode.c_str());
+
+ if (!p) return "";
+
+ std::string v(p, p+l);
+
+ free(p);
+ return v;
+ }
+
+ bool Exists(std::string key)
+ {
+ return !!Exists(key.c_str(), key.size());
+ }
+
+ bool Delete(std::string key)
+ {
+ return !!Delete(key.c_str(), key.size());
+ }
+
+ bool Store(std::string key, std::string val, std::string mode)
+ {
+ return Store(key.c_str(), key.size(),
+ val.c_str(), val.size(), mode.c_str());
+ }
+
+ std::string FetchFirstKeyVal(std::string &valRet)
+ {
+ char *key;
+ size_t keyLen;
+ char *val;
+ size_t valLen;
+
+ key=FetchFirstKeyVal(keyLen, val, valLen);
+
+ if (!key)
+ return "";
+
+ std::string r(key, key+keyLen);
+
+ valRet=std::string(val, val+valLen);
+ free(val);
+ return r;
+ }
+
+ std::string FetchNextKeyVal(std::string &valRet)
+ {
+ char *key;
+ size_t keyLen;
+ char *val;
+ size_t valLen;
+
+ key=FetchNextKeyVal(keyLen, val, valLen);
+
+ if (!key)
+ return "";
+
+ std::string r(key, key+keyLen);
+
+ valRet=std::string(val, val+valLen);
+ free(val);
+ return r;
+ }
+
+
+
+
+
+ char *Fetch(const char *key, size_t keylen, size_t &vallen,
+ const char *mode)
+ {
+ return (bdbobj_fetch(&obj, key, keylen, &vallen, mode));
+ }
+ int Exists(const char *key, size_t keylen)
+ {
+ return (bdbobj_exists(&obj, key, keylen));
+ }
+ int Delete(const char *key, size_t keylen)
+ {
+ return (bdbobj_delete(&obj, key, keylen));
+ }
+
+ int Store(const char *key, size_t keylen, const char *val,
+ size_t vallen, const char *mode)
+ {
+ return (bdbobj_store(&obj, key, keylen, val, vallen,
+ mode));
+ }
+
+ char *FetchFirstKeyVal(size_t &keylen, char *&val, size_t &vallen)
+ {
+ return (bdbobj_firstkey(&obj, &keylen, &val, &vallen));
+ }
+ char *FetchNextKeyVal(size_t &keylen, char *&val, size_t &vallen)
+ {
+ return (bdbobj_nextkey(&obj, &keylen, &val, &vallen));
+ }
+} ;
+
+#endif
+
+#endif
diff --git a/bdbobj/bdbobj2.c b/bdbobj/bdbobj2.c
new file mode 100644
index 0000000..d4311b7
--- /dev/null
+++ b/bdbobj/bdbobj2.c
@@ -0,0 +1,81 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include "bdbobj.h"
+
+char *bdbobj_firstkey(struct bdbobj *obj, size_t *keylen, char **val,
+ size_t *vallen)
+{
+DBT key, value;
+
+ if (!obj->has_dbf) return (0);
+
+ memset(&key, 0, sizeof(key));
+ memset(&value, 0, sizeof(value));
+
+#if DB_VERSION_MAJOR < 2
+ if ((*obj->dbf->seq)(obj->dbf, &key, &value, R_FIRST)) return (0);
+#else
+ if (obj->has_dbc)
+ {
+ (*obj->dbc->c_close)(obj->dbc);
+ obj->has_dbc=0;
+ }
+
+#if DB_VERSION_MAJOR > 2
+ if ((*obj->dbf->cursor)(obj->dbf, 0, &obj->dbc, 0)) return (0);
+#else
+#if DB_VERSION_MINOR >= 5
+ if ((*obj->dbf->cursor)(obj->dbf, 0, &obj->dbc, 0)) return (0);
+#else
+ if ((*obj->dbf->cursor)(obj->dbf, 0, &obj->dbc)) return (0);
+#endif
+#endif
+ obj->has_dbc=1;
+
+ if ((*obj->dbc->c_get)(obj->dbc, &key, &value, DB_FIRST)) return (0);
+#endif
+ *keylen=key.size;
+ *vallen=value.size;
+ if ((*val=(char *)malloc(*vallen)) == 0) return (0);
+
+ memcpy(*val, value.data, *vallen);
+ return ((char *)key.data);
+}
+
+char *bdbobj_nextkey(struct bdbobj *obj, size_t *keylen, char **val,
+ size_t *vallen)
+{
+DBT key, value;
+
+ if (!obj->has_dbf) return (0);
+
+ memset(&key, 0, sizeof(key));
+ memset(&value, 0, sizeof(value));
+
+#if DB_VERSION_MAJOR < 2
+ if ((*obj->dbf->seq)(obj->dbf, &key, &value, R_NEXT)) return (0);
+#else
+ if (!obj->has_dbc) return (0);
+
+ if ((*obj->dbc->c_get)(obj->dbc, &key, &value, DB_NEXT))
+ {
+ (*obj->dbc->c_close)(obj->dbc);
+ obj->has_dbc=0;
+ }
+#endif
+
+ *keylen=key.size;
+ *vallen=value.size;
+ if ((*val=(char *)malloc(*vallen + 1)) == 0) return (0);
+
+ memcpy(*val, value.data, *vallen);
+ (*val)[*vallen]=0;
+
+ return ((char *)key.data);
+}
diff --git a/bdbobj/bdbobj3.c b/bdbobj/bdbobj3.c
new file mode 100644
index 0000000..2914a91
--- /dev/null
+++ b/bdbobj/bdbobj3.c
@@ -0,0 +1,28 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
+** distribution information.
+*/
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include "bdbobj.h"
+
+int bdbobj_delete(struct bdbobj *obj, const char *key, size_t keylen)
+{
+DBT dkey, val;
+
+ if (!obj->has_dbf) return (0);
+
+ memset(&dkey, 0, sizeof(dkey));
+ memset(&val, 0, sizeof(val));
+ dkey.data=(void *)key;
+ dkey.size=keylen;
+
+#if DB_VERSION_MAJOR < 2
+ if ( (*obj->dbf->del)(obj->dbf, &dkey, 0)) return (-1);
+#else
+ if ( (*obj->dbf->del)(obj->dbf, 0, &dkey, 0)) return (-1);
+#endif
+ return (0);
+}
diff --git a/bdbobj/configure.in b/bdbobj/configure.in
new file mode 100644
index 0000000..6ef1ab4
--- /dev/null
+++ b/bdbobj/configure.in
@@ -0,0 +1,79 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright 1998 - 1999 Double Precision, Inc. See COPYING for
+dnl distribution information.
+
+AC_INIT(bdbobj, 0.10, [courier-users@lists.sourceforge.net])
+
+>confdefs.h # Kill PACKAGE_ macros
+
+AC_CONFIG_SRCDIR(bdbobj.h)
+AC_CONFIG_AUX_DIR(../..)
+AM_INIT_AUTOMAKE([foreign no-define])
+AM_CONFIG_HEADER(config.h)
+
+dnl Checks for programs.
+AC_USE_SYSTEM_EXTENSIONS
+AC_PROG_CC
+AC_PROG_AWK
+AC_PROG_CXX
+AC_ISC_POSIX
+AC_PROG_LIBTOOL
+
+dnl Checks for libraries.
+
+saveLIBS="$LIBS"
+AC_CHECK_LIB(db, dbopen, [ LIBDB=-ldb ; LIBS="-ldb $LIBS" ],
+ AC_CHECK_LIB(db, db_open, [ LIBDB=-ldb ; LIBS="-ldb $LIBS"],
+ AC_CHECK_LIB(db, db_env_create, [ LIBDB=-ldb; LIBS="-ldb $LIBS"])
+ ))
+
+FOUND_DB=0
+AC_CHECK_FUNC(dbopen, FOUND_DB=1)
+AC_CHECK_FUNC(db_open, FOUND_DB=1)
+AC_CHECK_FUNC(db_env_create, FOUND_DB=1)
+
+LIBS="$saveLIBS"
+
+AC_SUBST(LIBDB)
+
+AM_CONDITIONAL(FOUND_DB, test "$FOUND_DB" != 0)
+
+dnl Checks for header files.
+
+AC_CHECK_HEADERS(limits.h fcntl.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_SYS_LARGEFILE
+
+AC_LANG_CPLUSPLUS
+AC_CACHE_CHECK([if the C++ compiler needs -fhandle-exceptions],
+ ac_cv_need_handlexceptions,
+
+AC_TRY_COMPILE([],
+[
+throw;
+], ac_cv_need_handlexceptions=no,
+ac_cv_need_handlexceptions=yes)
+)
+
+if test "$ac_cv_need_handlexceptions" = "yes"
+then
+ case "$CXXFLAGS" in
+ *handle-exceptions*)
+ ;;
+ *)
+ CXXFLAGS="-fhandle-exceptions $CXXFLAGS"
+ CXXFLAGS=`echo "$CXXFLAGS" | sed 's/-O2//'`
+ ;;
+ esac
+fi
+
+if test "$GCC" = "yes"
+then
+ CFLAGS="-Wall $CFLAGS"
+fi
+
+AC_OUTPUT(Makefile)
diff --git a/bdbobj/testbdb.C b/bdbobj/testbdb.C
new file mode 100644
index 0000000..dfd7ac1
--- /dev/null
+++ b/bdbobj/testbdb.C
@@ -0,0 +1,165 @@
+#include "config.h"
+#include "bdbobj.h"
+#include <stdio.h>
+#include <string.h>
+
+static void fw(char *p, size_t a, size_t b, FILE *f)
+{
+size_t i, j=a*b;
+
+ for (i=0; i<j; i++)
+ putc(p[i], f);
+}
+
+struct kd {
+ struct kd *next;
+ char *key, *data;
+ } ;
+
+static int kdcmp (const void *a, const void *b)
+{
+ return (strcmp( (*(const struct kd **)a)->key,
+ (*(const struct kd **)b)->key));
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) exit(1);
+
+ if (argc < 3)
+ {
+ BDbObj dbw;
+ char *key, *data;
+ size_t keylen, datalen;
+ struct kd *kdlist, **kdarray;
+ size_t kdcnt;
+
+ if (dbw.Open(argv[1], "R"))
+ {
+ perror("open");
+ exit(1);
+ }
+
+ printf("Dumping %s:\n", argv[1]);
+ kdlist=0;
+ kdcnt=0;
+ for (key=dbw.FetchFirstKeyVal(keylen, data, datalen);
+ key; key=dbw.FetchNextKeyVal(keylen, data, datalen))
+ {
+ struct kd *k=(struct kd *)malloc(sizeof(struct kd));
+
+ if (!k)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ if ((k->key=(char *)malloc(keylen+1)) == 0 ||
+ (k->data=(char *)malloc(datalen+1)) == 0)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ memcpy(k->key, key, keylen);
+ k->key[keylen]=0;
+ memcpy(k->data, data, datalen);
+ k->data[datalen]=0;
+ free(data);
+ ++kdcnt;
+ k->next=kdlist;
+ kdlist=k;
+ }
+
+ if ((kdarray=(struct kd **)
+ malloc( (kdcnt+1)*sizeof(struct kd *))) == 0)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ kdcnt=0;
+ while ( kdlist )
+ {
+ kdarray[kdcnt++]=kdlist;
+ kdlist=kdlist->next;
+ }
+ kdarray[kdcnt]=0;
+
+ qsort( kdarray, kdcnt, sizeof(kdarray[0]), &kdcmp);
+
+ for (kdcnt=0; kdarray[kdcnt]; kdcnt++)
+ {
+ printf("Key: ");
+ fw(kdarray[kdcnt]->key, strlen(kdarray[kdcnt]->key),
+ 1, stdout);
+ printf(", Data: ");
+ fw(kdarray[kdcnt]->data, strlen(kdarray[kdcnt]->data),
+ 1, stdout);
+ printf("\n");
+ free(kdarray[kdcnt]->key);
+ free(kdarray[kdcnt]->data);
+ free(kdarray[kdcnt]);
+ }
+ free(kdarray);
+
+ dbw.Close();
+ } else if (argc < 4 && argv[2][0] == '-')
+ {
+ BDbObj dbw;
+
+ if (dbw.Open(argv[1], "W"))
+ {
+ perror("open");
+ exit(1);
+ }
+
+ printf("Deleting %s from %s:\n", argv[2], argv[1]);
+ if (dbw.Delete(argv[2]+1, strlen(argv[2]+1)))
+ fprintf(stderr, "Not found.\n");
+
+ dbw.Close();
+ } else if (argc < 4)
+ {
+ BDbObj dbw;
+
+ if (dbw.Open(argv[1], "R"))
+ {
+ perror("open");
+ exit(1);
+ }
+
+ size_t len;
+ char *val=dbw.Fetch(argv[2], strlen(argv[2]), len, 0);
+
+ if (!val)
+ {
+ fprintf(stderr, "%s: not found.\n", argv[2]);
+ exit(1);
+ }
+ printf("Fetching %s from %s: ", argv[2], argv[1]);
+ fw(val, len, 1, stdout);
+ printf("\n");
+ free(val);
+ dbw.Close();
+ }
+ else
+ {
+ BDbObj dbw;
+
+ if (dbw.Open(argv[1], "C"))
+ {
+ perror("open");
+ exit(1);
+ }
+
+ printf("Storing %s/%s into %s:\n", argv[2], argv[3], argv[1]);
+ if (dbw.Store(argv[2], strlen(argv[2]),
+ argv[3], strlen(argv[3]), "R"))
+ {
+ perror("write");
+ exit(1);
+ }
+
+ dbw.Close();
+ }
+ exit(0);
+ return (0);
+}
diff --git a/bdbobj/testsuite b/bdbobj/testsuite
new file mode 100755
index 0000000..352e297
--- /dev/null
+++ b/bdbobj/testsuite
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+rm -f testbdb.dat
+
+./testbdb testbdb.dat foo bar
+./testbdb testbdb.dat foo baz
+./testbdb testbdb.dat bar foo
+./testbdb testbdb.dat foo
+./testbdb testbdb.dat bar
+./testbdb testbdb.dat
+./testbdb testbdb.dat -foo
+./testbdb testbdb.dat
+
+rm -f testbdb.dat
diff --git a/bdbobj/testsuite.txt b/bdbobj/testsuite.txt
new file mode 100644
index 0000000..31f4126
--- /dev/null
+++ b/bdbobj/testsuite.txt
@@ -0,0 +1,11 @@
+Storing foo/bar into testbdb.dat:
+Storing foo/baz into testbdb.dat:
+Storing bar/foo into testbdb.dat:
+Fetching foo from testbdb.dat: baz
+Fetching bar from testbdb.dat: foo
+Dumping testbdb.dat:
+Key: bar, Data: foo
+Key: foo, Data: baz
+Deleting -foo from testbdb.dat:
+Dumping testbdb.dat:
+Key: bar, Data: foo