=head1	NAME

dksdbi - Simple database interface

=head1	SYNOPSIS

 #include <dksdbi.h>

 dk_sdbi_t
 dksdbi_open(char *fn, int tp, int acc, int fm, int blks);
 void
 dksdbi_close(dk_sdbi_t db);
 int
 dksdbi_store(dk_sdbi_t db, void *kp, size_t kl, void *vp, size_t vl, int im);
 int
 dksdbi_string_store(dk_sdbi_t db, char *k, char *v, int im);
 int
 dksdbi_fetch(dk_sdbi_t db, char *kp, char *vp, size_t *vl);
 int
 dksdbi_string_fetch(dk_sdbi_t db, char *k, char *vp, size_t vl);
 int
 dksdbi_delete(dk_sdbi_t db, char *kp, size_t kl);
 int
 dksdbi_string_delete(dk_sdbi_t db, char *k);
 int
 dksdbi_traverse(dk_sdbi_t db, void *d, dk_sdbi_fct_t *f);
 int
 dksdbi_sync(dk_sdbi_t db);
 int
 dksdbi_remove_file(char *fn, int tp);

 cc ... -ldksdbi -ldkport -ldb -lgdbm

=head1	DESCRIPTION

The dksdbi library provides a simple interface to databases (Berkeley DB,
NDBM and GDBM).  These databases are used to store and retrieve key/value
pairs. Keys and values are sequences of bytes. Only one database entry can
exist for a given key.

The dksdbi_open() function opens a database, I<fn> contains the filename.
For Berkeley DB and GDBM databases the filename is used as is. NDBM
databases are stored in two files, the suffixes ``.dir'' and ``.pag'' are
appended.
The I<tp> arguments indicates the database type, which can be either
DK_SDBI_TYPE_AUTO (the dksdbi library automatically chooses it's
preferred database type), DK_SDBI_TYPE_BDB, DK_SDBI_TYPE_NDBM or
DK_SDBI_TYPE_GDBM.
The I<acc> mode specifies, which operations are to be performed on
the database. Use either DK_SDBI_MODE_READ, DK_SDBI_MODE_WRITE or
DK_SDBI_MODE_RDWR here. To truncate an exisiting database
(remove all contents) use an or-combination with DK_SDBI_MODE_TRUNCATE.
The I<fm> argument is the file permissions mode used if a new database file
is created. Use a combination of DK_PERM_U_READ...DK_PERM_O_EXECUTE
(from dksfc.h) here.
An optional blocksize can be specified in I<blks>, this argument is used for
GDBM databases only. On success the function returns a pointer to an internal
database information struct. This pointer can be used to perform the database
operations.
Use dksdbi_close() to close the database and release ressources.

If I<tp>==DK_SDBI_TYPE_AUTO the filename can contain a prefix
``bdb:'', ``gdbm:'' or ``ndbm:'' to indicate a database type.
This allows to specify the database type in configuration
files together with the filename.

The dksdbi_close() function closes a database opened by dksdbi_open() and
releases ressources.

The dksdbi_store() function stores a key/value pair into the database.
The I<kp> and I<kl> specify the address and length of the byte buffer
used for the key, I<vp> and I<vl> are used for the value.
If the insertion mode I<im> is 0, the function either inserts a new
entry for the specified key (if no entry for the key is present yet)
or replaces an exisiting entry. If I<im>==DK_SDBI_INSMOD_NO_REPLACE
the function fails if an entry for the specified key already exists.

The dksdbi_fetch() function retrieves data from the database.
The key is specified by I<kp> and I<kl>. The address of a buffer
to store the result is provided in I<vp>. The I<vl> argument is a
pointer to a size specification. This size specification contains
the available buffer size before the function is invoked. If the
function returns successfully the specification contains the
number of used bytes.

The dksdbi_string_store() function stores key/value pairs of strings.
Strings are stored including the finishing 0x00 byte.

The dksdbi_string_fetch() function retrieves a string value.
The result buffer is specified by I<vp> and I<vl>.

The dksdbi_delete() and dk_sdbi_string_delete() functions delete an entry from
from the database.

The dksdbi_traverse() function can be used to inspect all key/value pairs in
a database. In I<f> you provide a function
  int traversal_function(void *d, void *kp, size_t kl, void *vp, size_t vl);
This traversal function is invoked once for each database entry,
I<kp> and I<kl> are used
to specifiy the key, I<vp> and I<vl> are used to specify the value. The
I<d> pointer can be used to collect data. The traversal function returns
0 on success, 1 on minor errors (we can continue traversal) and
-1 on critical errors (we have to stop traversal). The buffers for key
and value are maintained (allocated and released) by the dksdbi_traverse()
function, you should not modify the buffer contents.
The I<d> argument provided to dksdbi_traverse() is provided as
I<d> argument to traversal_function() for each key/value pair.

The dksdbi_sync() function explicitly requests a synchronization of
in-memory buffers to file for Berkeley DB and GDBM databases.

The dksdbi_remove_file() function removes a database file
(or a pair of database files for NDBM).

=head1	RETURN VALUE

All functions return either a valid pointer (dk_sdbi_t) or a positive
value on success.

NULL, or 0 or negative numbers indicate errors.

=head1	EXAMPLE

  #include <dksdbi.h>

  static char dbfilename[] = { "mydbfile" };
  static char k1[] = { "The key number 1" };
  static char k2[] = { "The key number 3" };
  static char v1[] = { "The value number 1" };
  static char v2[] = { "The value number 2" };
  static char v3[] = { "The value number 3" };
  static char v4[] = { "The value number 4" };

  static int traversal_fct(void *d, void *kp, size_t kl, void *vp, size_t vl)
  {
    if((kp) && (vp)) {
      if((kl) && (vl)) {
        /* make sure to have strings properly finished */
        kp[kl-1] = '\0'; vp[vl-1] = '\0';
	/* print key/value pair */
	printf("traversal: \"%s\"=\"%s\"\n", kp, vp);
      }
    }
  }

  void test_fct()
  {
    dk_sdbi_t dbptr = NULL;
    char resbuffer[256];
    size_t rbs;
    res = dksdbi_open(
      dbfilename, DK_SBI_TYPE_AUTO, DK_SDBI_MODE_RDWR,
      (DK_PERM_U_READ | DK_PERM_U_WRITE), 1024
    );
    if(res) {
      dksdbi_store(dbptr, k1, (1+strlen(k1)), v1, (1+strlen(v1)), 0);
      dksdbi_store(dbptr, k2, (1+strlen(k2)), v2, (1+strlen(v2)), 0);
      /* The next instruction will fail */
      dksdbi_store(
        dbptr, k1, (1+strlen(k1)), v3, (1+strlen(v3)),
	DK_SDBI_INSMOD_NO_REPLACE
      );
      /* The next instructions will work */
      dksdbi_store(dbptr, k1, (1+strlen(k1)), v3, (1+strlen(v3)), 0);
      dksdbi_string_store(dbptr, k1, v4);
      dksdbi_traverse(dbptr, NULL, traversal_fct);
      rbs = sizeof(resbuffer);
      if(dksdbi_fetch(dbptr, k1, (1+strlen(k1)), resbuffer, &rbs)) {
        if(rbs) {
	  resbuffer[rbs-1] = '\0';
	  printf("fetch: \"%s\"=\"%s\"\n", k1, resbuffer);
	}
      }
      if(dksdbi_string_fetch(dbptr, k2, resbuffer, sizeof(resbuffer))) {
        printf("string_fetch: \"%s\"=\"%s\"\n", k2, resbuffer);
      }
      dksdbi_delete(dbptr, k1, (1+strlen(k1)));
      dksdbi_string_delete(dbptr, k2);
      dksdbi_close(dbptr); dbptr = NULL;
    }
  }

=head1	FILES

For Berkeley DB and GDBM databases the filename is used
as specified. NDBM databases are stored in two files,
``.dir'' and ``.pag'' is appended to the specified
file name.

=head1	AUTHOR

Dirk Krause.

=head1	COPYRIGHT AND LICENSE

Copyright (c) 2007-2008, Dirk Krause
All rights reserved.

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
   copyright 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 Dirk Krause 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.
