Changes since last time:

* NO CHANGE IN APR_DBM.H (so no diffs ;))
* added licence file to dbm_private and put it in
private/apr_dbm_private.h 
* GDBM is now there
* patch to apr_dbm.c.patch
* vtables are now static constants. (as per buckets)
* code style-cleanup to make it more apache. (might still be a stray
tab)

This version does NOT do:
* apr_dbm_open(XXX,...)
* apr_dbm_registration
* allow for multiple DBMs.

all it really does at the moment is split the file into 3 parts.

All it requires for existing 'users' of the DBM is a re-link to the new
library.

IF this patch is Ok, then I'll get the multi-dbm's working (which means
changing the configure, and adding the registeration/open(XXX))

XXX_Usednames is not part of the hook, as you don't need a DBM open to
call it. (and changing it to require it would break mod_dav, as it
doesn't seem to have a open DBM when it calls the funciton)

??comments???
Ian




On Wed, 2001-08-22 at 02:54, Greg Stein wrote:
> -1 until you put that GDBM support back in. It isn't right to just drop it.
> 
> On Mon, Aug 20, 2001 at 04:50:25PM -0700, Ian Holsman wrote:
> > On Mon, 2001-08-20 at 13:07, Sterling Hughes wrote:
> >...
> > >   Not sure I understand what you're saying?  There are ways to allow
> > >   the registering of module functionality, without modifying the main
> > >   package.  Just provide a function like:
> > > 
> > >   apr_dbm_register()
> > > 
> > >   Which registers a dbm internally, and then have a constant defined
> > >   in a seperate file, and all is clear...
> > that would work,
> > but that wouldn't that mean there would be need to some init code
> > somewhere to call the registration function?
> 
> Every time we load a module, we call registration functions. That is no big
> deal.
> 
> Your solution of apr_dbm_*_open() still requires a recompilation/relink. The
> registration mechanism is completely open-ended.
> 
> > > > 2. I may have a dbm which needs extra parameters to open it. (say for
> > > > exampe cache size, or maybe it requires
> > > >     a fixed key length defined) I couldn't do this simply
> > > >
> > > 
> > >   dbm_set_x() and check the flags, once they're all filled out (a
> > >   va_args implementation could also be done...)
> 
> Not sure what you mean by dbm_set_x() here. You have to open the thing first
> to get an apr_dbm_t. But then you're too late.
> 
> The va_arg solution is a semi-reasonable solution, but that kills any chance
> for type checking.
> 
> > >   Furthermore, the idea of an abstraction layer is too bring all these
> > >   down to a lowest common denominator, at the cost of functionality
> > >   sometimes; usually functions that take extra arguments, can be
> > >   filled in with acceptable defaults.  You'll run into the same
> > >   problems in that some db's don't support certain features, and
> > >   others do, the idea is to concentrate on the functionality that is
> > >   necessary and shared between the different db's (wrap this in a
> > >   large imho :).
> 
> Exactly. apr_dbm exposes DBM-style functionality. Simple key/value pairs.
> That is it. The open functionality does not need flexibility. It has not
> been demonstrated yet that we need more capability there.
> 
> > true, thats why they all return the same thing (apr_dbm_t)
> > the open_DBM function was supposed to be called when the devloper wanted
> > to do something specific with this type of dbm. so in the berkley DB
> > case there could be a apr_dbm_db_getRaw() function which returns the DB*
> > so that developers are not constrained the set of functions we chose to
> > abstract.
> 
> No... we already have patterns for getting at underlying data types. See
> apr_portable.h. Follow that pattern *IF* we are to expose those. IMO, we
> should not do so.
> 
> > (BTW I was planning on implmenting a shared-memory hash table, that I
> > posted ages ago, via this DBM interface, and it required a different set
> > of opening parameters (key/elem size, #elements) these parameters could
> > be passed via a db_set function call but it would look clunky
> 
> No... keys and values are arbitrary length, as specified by an apr_datum_t.
> If your hash cannot handle that, then it cannot be used in the APR DBM
> interface.
> 
> >...
> > so..
> > shall we put it to a vote?
> > 
> > apr_dbm_open_XXX
> > or 
> > apr_dbm_open(XXX)
> 
> Registration and the second form.
> 
> 
> But your patch still has lots of work anyways. The GDBM functionality can't
> just disappear. Sorry, but the DAV functionality uses apr_dbm and you'd
> completely break access to the property files.
> 
> Second, the vtable should not be part of the runtime apr_dbm_t structure.
> You should have a pointer to a static const table, like we do with buckets.
> 
> The formatting may have gone thru "indent" but it still sucks. Just a glance
> over it shows some random gunk. For example, what the heck is up with the
> formatting of apr_datum_t in apr_dbm.h? And all the spacing of the function
> params in apr_dbm.h has been changed. There are extra blank lines at the end
> of some functions (after returns), and some missing blank lines between
> functions.
> 
> We should also see a patch against apr_dbm.h, rather than the whole file. I
> can't see if you've changed the public interface or not.
> 
> dbm_private.h is missing a license and disclaimer. It also has a
> non-standard #ifndef/#define/#endif pattern around it. We never start the
> symbol with "_", and on all the new .h files you specified: toss the "1"
> from the #define ... we don't do that either.
> 
> Why is the "used names" functionality part of the per-db public interface?
> That should be part of the hook stuff just like the rest.
> 
> In any case... the per-db headers should go, in favor of the registration
> mechanism. You would register each DB style with a name. You can then open a
> DB style by name, or using the reserved "any". Note that we would define
> some standard names:
> 
> #define APR_DBM_USE_SDBM "sdbm"
> #define APR_DBM_USE_GDBM "gdbm"
> #define APR_DBM_USE_DB   "db"
> #define APR_DBM_USE_ANY  "any"
> 
> Also, the whole point of this exercise was to link in all of the variations.
> That means the .c files should not have the #if APU_USE_*/#endif stuff
> around them. The APU_USE_* symbols are only used to determine which DB to
> use for the "any" case.
> 
> 
> So... -1 for now. The patch still needs work before it can be applied.
> 
> Cheers,
> -g
> 
-- 
Ian Holsman          [EMAIL PROTECTED]
Performance Measurement & Analysis
CNET Networks   -   (415) 364-8608
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#ifndef APR_DBM_DB_H
#define APR_DBM_DB_H 1

#include "apr.h"
#include "apr_dbm.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Open a Berkley DB file by file name
 * @param dbm The newly opened database
 * @param name The dbm file name to open
 * @param mode The flag value
 * <PRE>
 *           APR_DBM_READONLY   open for read-only access
 *           APR_DBM_READWRITE  open for read-write access
 *           APR_DBM_RWCREATE   open for r/w, create if needed
 * </PRE>
 * @param perm Permissions to apply to if created
 * @param cntxt The pool to use when creating the dbm
 */
APU_DECLARE(apr_status_t) apr_dbm_open_db(apr_dbm_t ** dbm, const char *name,
                                          apr_int32_t mode,
                                          apr_fileperms_t perm,
                                          apr_pool_t * cntxt);

/**
 * If the specified file/path were passed to apr_dbm_open_db(), return the
 * actual file/path names which would be (created and) used. At most, two
 * files may be used; used2 may be NULL if only one file is used.
 * @param pool The pool for allocating used1 and used2.
 * @param pathname The path name to generate used-names from.
 * @param used1 The first pathname used by the apr_dbm implementation.
 * @param used2 The second pathname used by apr_dbm. If only one file is
 *              used by the specific implementation, this will be set to NULL.
 */
APU_DECLARE(void) apr_dbm_get_usednames_db(apr_pool_t * p,
                                           const char *pathname,
                                           const char **used1,
                                           const char **used2);
#ifdef __cplusplus
}
#endif
#endif   /* !APR_DBM_DB_H */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#ifndef APR_DBM_GDBM_H
#define APR_DBM_GDBM_H 1

#include "apr.h"
#include "apr_dbm.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Open a GDBM DB file by file name
 * @param dbm The newly opened database
 * @param name The dbm file name to open
 * @param mode The flag value
 * <PRE>
 *           APR_DBM_READONLY   open for read-only access
 *           APR_DBM_READWRITE  open for read-write access
 *           APR_DBM_RWCREATE   open for r/w, create if needed
 * </PRE>
 * @param perm Permissions to apply to if created
 * @param cntxt The pool to use when creating the dbm
 */
APU_DECLARE(apr_status_t) apr_dbm_open_gdbm(apr_dbm_t ** dbm, const char *name,
                                            apr_int32_t mode,
                                            apr_fileperms_t perm,
                                            apr_pool_t * cntxt);

/**
 * If the specified file/path were passed to apr_dbm_open_db(), return the
 * actual file/path names which would be (created and) used. At most, two
 * files may be used; used2 may be NULL if only one file is used.
 * @param pool The pool for allocating used1 and used2.
 * @param pathname The path name to generate used-names from.
 * @param used1 The first pathname used by the apr_dbm implementation.
 * @param used2 The second pathname used by apr_dbm. If only one file is
 *              used by the specific implementation, this will be set to NULL.
 */
APU_DECLARE(void) apr_dbm_get_usednames_gdbm(apr_pool_t * p,
                                             const char *pathname,
                                             const char **used1,
                                             const char **used2);
#ifdef __cplusplus
}
#endif
#endif    /* !APR_DBM_GDBM_H */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#ifndef APR_DBM_SDBM_H
#define APR_DBM_SDBM_H 1

#include "apr.h"
#include "apr_dbm.h"

#ifdef __cplusplus
extern "C" {
#endif
/**
 * Open a SDBM file by file name
 * @param dbm The newly opened database
 * @param name The dbm file name to open
 * @param mode The flag value
 * <PRE>
 *           APR_DBM_READONLY   open for read-only access
 *           APR_DBM_READWRITE  open for read-write access
 *           APR_DBM_RWCREATE   open for r/w, create if needed
 * </PRE>
 * @param perm Permissions to apply to if created
 * @param cntxt The pool to use when creating the dbm
 * @remark The dbm name may not be a true file name, as many dbm packages
 * append suffixes for seperate data and index files.
 */
APU_DECLARE(apr_status_t) apr_dbm_open_sdbm(apr_dbm_t ** dbm, const char *name,
                                            apr_int32_t mode, 
                                            apr_fileperms_t perm,
                                            apr_pool_t * cntxt);

/**
 * If the specified file/path were passed to apr_dbm_open_sdbm(), return the
 * actual file/path names which would be (created and) used. At most, two
 * files may be used; used2 may be NULL if only one file is used.
 * @param pool The pool for allocating used1 and used2.
 * @param pathname The path name to generate used-names from.
 * @param used1 The first pathname used by the apr_dbm implementation.
 * @param used2 The second pathname used by apr_dbm. If only one file is
 *              used by the specific implementation, this will be set to NULL.
 */
APU_DECLARE(void) apr_dbm_get_usednames_sdbm(apr_pool_t * p,
                                             const char *pathname,
                                             const char **used1,
                                             const char **used2);
#ifdef __cplusplus
}
#endif
#endif /* !APR_DBM_SDBM_H */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */


#ifndef APR_DBM_PRIVATE_H
#define APR_DBM_PRIVATE_H 1
#ifdef __cplusplus
extern "C" {
#endif

/** @internal */

/**
 * Most DBM libraries take a POSIX mode for creating files.  Don't trust
 * the mode_t type, some platforms may not support it, int is safe.
 */
APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm);

/**
 * Structure to describe the operations of the DBM 
 */
typedef struct {
    /** The name of the DBM Type */
    const char *name;
    /** Set the error return code */
    apr_status_t      (*set_error) (apr_dbm_t * dbm, apr_status_t dbm_said);
    /** Close the DBM */
    void              (*close)    (apr_dbm_t * dbm);
    /** Fetch a dbm record value by key */
    apr_status_t      (*fetch)    (apr_dbm_t * dbm, apr_datum_t key, 
                                   apr_datum_t * pvalue);
    /** Store a dbm record value by key */
    apr_status_t      (*store)    (apr_dbm_t * dbm, apr_datum_t key, 
                                   apr_datum_t value);
    /** Delete a dbm record value by key */
    apr_status_t      (*del)      (apr_dbm_t * dbm, apr_datum_t key);
    /** Search for a key within the dbm */
    int               (*exists)   (apr_dbm_t * dbm, apr_datum_t key);
    /** Retrieve the first record key from a dbm */
    apr_status_t      (*firstkey) (apr_dbm_t * dbm, apr_datum_t * pkey);
    /** Retrieve the next record key from a dbm */
    apr_status_t      (*nextkey)  (apr_dbm_t * dbm, apr_datum_t * pkey);
    /** Report more information when an apr_dbm function fails. */
    char *            (*geterror) (apr_dbm_t * dbm, int *errcode, char *errbuf,
                                   apr_size_t errbufsize);

	/** if a DBM needs to call something free data */
	 apr_status_t      (*datum_cleanup) (void *);
    /** Proactively toss any memory associated with the apr_datum_t. */
	 void              (*freedatum) (apr_dbm_t * dbm, apr_datum_t data);
} apr_dbm_type_t;

/**
 * The actual DBM 
 */
struct apr_dbm_t
{
	 apr_pool_t *pool;
	/** pointer to DB Implementation Specific data */
	 void *file;

	 int errcode;
	 const char *errmsg;
     /** the type of DBM */
     const apr_dbm_type_t *type;
};
#ifdef __cplusplus
}
#endif

#endif /* !APR_DBM_PRIVATE_H */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr.h"
#include "apr_errno.h"
#include "apr_pools.h"
#include "apr_strings.h"
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_want.h"

#include "apu_select_dbm.h"
#include "apr_dbm.h"


#if APU_USE_DB
#include "private/apr_dbm_private.h"
#include "apr_dbm_db.h"
#include <db.h>

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_db_t;
/*
 * We pick up all varieties of Berkeley DB through db.h (included through
 * apu_select_dbm.h). This code has been compiled/tested against DB1,
 * DB_185, DB2, and DB3.
 */

#if   defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3)
#define DB_VER 3
#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
#define DB_VER 2
#else
#define DB_VER 1
#endif

typedef struct {
    DB *bdb;
#if DB_VER != 1
    DBC *curs;
#endif
} apr_berkeley_db_t;


#if DB_VER == 1
#include <sys/fcntl.h>
#define APR_DBM_DBMODE_RO       O_RDONLY
#define APR_DBM_DBMODE_RW       O_RDWR
#define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR)
#else
#define APR_DBM_DBMODE_RO       DB_RDONLY
#define APR_DBM_DBMODE_RW       0
#define APR_DBM_DBMODE_RWCREATE DB_CREATE
#endif

/* map a DB error to an apr_status_t */
static apr_status_t db2s(int dberr)
{
    if (dberr != 0) {
        return APR_OS_START_USEERR + dberr;
    }
    return APR_SUCCESS;
}



/* handle the FIRSTKEY functionality */
static apr_status_t do_firstkey(apr_berkeley_db_t * f, DBT * pkey)
{
    int dberr;
    DBT data;

    memset(&data, 0, sizeof(DBT));

#if DB_VER == 1
    dberr = (*f->bdb->seq)(f->bdb, pkey, &data, R_FIRST);
#else
    /* DB_VER 1 doesn't do cursors */
#if DB_VER == 2
    dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs);
#else
    dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs , 0);
#endif /* DB_VER == 2 */
    if (dberr == 0) {
        dberr = (*f->curs->c_get)(f->curs, pkey, &data, DB_FIRST);
        if (dberr == DB_NOTFOUND) {
            memset(pkey, 0, sizeof(*pkey));
            (*f->curs->c_close)(f->curs);
            f->curs = NULL;
            return APR_SUCCESS;
        }
    }
#endif /* DB_VER == 1 */

    return db2s(dberr);
}

/* 
 * handle the NEXTKEY functionality 
 * This function also returns the 'data'
 * as well as the key.
 */
static apr_status_t do_nextkey(apr_berkeley_db_t *f, DBT *pkey, DBT *pdata)
{
    int dberr;

    memset(pdata, 0, sizeof(DBT));

#if DB_VER == 1
    dberr = (*f->bdb->seq)(f->bdb, pkey, pdata, R_NEXT);
#else
    if (f->curs == NULL)
        return APR_EINVAL;

    dberr = (*f->curs->c_get)(f->curs, pkey, pdata, DB_NEXT);
    if (dberr == DB_NOTFOUND) {
        memset(pkey, 0, sizeof(*pkey));
        memset(pdata, 0, sizeof(*pdata));
        (*f->curs->c_close)(f->curs);
        f->curs = NULL;
        return APR_SUCCESS;
    }

#endif /* DB_VER == 1 */

    return db2s(dberr);
}
static apr_status_t apr_dbm_set_error_db(apr_dbm_t *dbm, apr_status_t dbm_said)
{
    apr_status_t rv = APR_SUCCESS;

    /* FIXME: check for error codes that APR already has and map the DB ones to them */

    if (dbm_said == APR_SUCCESS) {
        dbm->errcode = 0;
        dbm->errmsg = NULL;
    }
    else {
        dbm->errcode = dbm_said;
        dbm->errmsg = db_strerror(dbm_said - APR_OS_START_USEERR);
        rv = dbm_said;
    }
    return rv;
}
static void apr_dbm_close_db(apr_dbm_t *dbm)
{
    apr_berkeley_db_t *real_ptr;
    DB *db;

    real_ptr = dbm->file;
    if (real_ptr->bdb) {
        db = real_ptr->bdb;
#if DB_VER == 1
        db->close(db);
#else
        db->close(db, 0);
#endif
//        real_ptr->bdb=NULL;
    }
}

/* make sure we clean up and close things */
static apr_status_t db_cleanup(void *p)
{
    apr_dbm_t **db = p;

    if (*db) {
        apr_dbm_close_db(*db);
        *db = NULL;
    }

    return APR_SUCCESS;
}
static apr_status_t apr_dbm_fetch_db(apr_dbm_t *dbm, apr_datum_t key,
                                     apr_datum_t *pvalue)
{
    apr_status_t rv;
    apr_berkeley_db_t *real_ptr = dbm->file;
    DB *db = real_ptr->bdb;
    DBT ckey;
    DBT rd;
    int dberr;

    memset(&ckey, 0, sizeof(DBT));
    memset(&rd, 0, sizeof(DBT));

    ckey.data = key.dptr;
    ckey.size = key.dsize;

#if DB_VER == 1
    dberr = db->get(db, &ckey, &rd, 0);

#else
    dberr = db->get(db, NULL, &ckey, &rd, 0);
#endif
    rv = db2s(dberr);
    pvalue->dptr = rd.data;
    pvalue->dsize = rd.size;

    /* 
     * store the error info into DBM, and return a status code. Also, note
     * that *pvalue should have been cleared on error. 
     */
    return apr_dbm_set_error_db(dbm, rv);
}

static apr_status_t apr_dbm_store_db(apr_dbm_t *dbm, apr_datum_t key,
				     apr_datum_t value)
{
    apr_status_t rv;
    int dberr;
    apr_berkeley_db_t *real_ptr = dbm->file;
    DB *db = real_ptr->bdb;
    DBT ckey;
    DBT cvalue;

    memset(&ckey, 0, sizeof(DBT));
    ckey.data = key.dptr;
    ckey.size = key.dsize;

    memset(&cvalue, 0, sizeof(DBT));
    cvalue.data = value.dptr;
    cvalue.size = value.dsize;

#if DB_VER == 1
    dberr = db->put(db, &ckey, &cvalue, 0);
#else
    dberr = db->put(db, NULL, &ckey, &cvalue, 0);
#endif
    rv = db2s(dberr);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_db(dbm, rv);

}

static apr_status_t apr_dbm_delete_db(apr_dbm_t *dbm, apr_datum_t key)
{
    apr_status_t rv;
    DBT ckey;
    apr_berkeley_db_t *real_ptr = dbm->file;
    DB *db = real_ptr->bdb;
    int dberr;

    memset(&ckey, 0, sizeof(DBT));
    ckey.data = key.dptr;
    ckey.size = key.dsize;
#if DB_VER ==1
    dberr = db->del(db, &ckey, 0);
#else
    dberr = db->del(db, NULL, &ckey, 0);
#endif
    rv = db2s(dberr);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_db(dbm, rv);

}

static int apr_dbm_exists_db(apr_dbm_t *dbm, apr_datum_t key)
{
    int exists;
    DBT ckey;
    DBT data;
    apr_berkeley_db_t *real_ptr = dbm->file;
    DB *db = real_ptr->bdb;

    int dberr;

    memset(&ckey, 0, sizeof(DBT));
    ckey.data = key.dptr;
    ckey.size = key.dsize;

    memset(&data, 0, sizeof(DBT));
    data.data = key.dptr;
    data.size = key.dsize;

#if DB_VER ==1
    dberr = db->get(db, &ckey, &data, 0);
#else
    dberr = db->get(db, NULL, &ckey, &data, 0);
#endif
    /*
     * DB returns DB_NOTFOUND if it doesn't exist. but we want to say
     * that *any* error means it doesn't exist. 
     */
    exists = dberr == 0;

    return exists;
}

static apr_status_t apr_dbm_firstkey_db(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    DBT rd;
    apr_berkeley_db_t *real_ptr = dbm->file;

    memset(&rd, 0, sizeof(DBT));
    rv = do_firstkey(real_ptr, &rd);

    pkey->dptr = rd.data;
    pkey->dsize = rd.size;
    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_db(dbm, rv);
}

static apr_status_t apr_dbm_nextkey_db(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    DBT ckey;
    DBT rd;
    apr_berkeley_db_t *real_ptr = dbm->file;

    memset(&rd, 0, sizeof(DBT));
    memset(&ckey, 0, sizeof(DBT));
    ckey.data = pkey->dptr;
    ckey.size = pkey->dsize;

    rv = do_nextkey(real_ptr, &ckey, &rd);

    pkey->dptr = ckey.data;
    pkey->dsize = ckey.size;

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_db(dbm, APR_SUCCESS);

}

static void apr_dbm_freedatum_noop(apr_dbm_t *dbm, apr_datum_t data)
{
    /* do nothing */
}
static apr_status_t apr_dbm_datum_cleanup_noop(void *x)
{
    return APR_SUCCESS;
}

static char *apr_dbm_geterror_db(apr_dbm_t *dbm, int *errcode,
				 char *errbuf, apr_size_t errbufsize)
{
    if (errcode != NULL) {
        *errcode = dbm->errcode;
    }

    if (dbm->errmsg == NULL) {
        *errbuf = '\0';
    }
    else {
        (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
    }

    return errbuf;
}

APU_DECLARE(void) apr_dbm_get_usednames_db(apr_pool_t *p,
					   const char *pathname,
					   const char **used1,
					   const char **used2)
{
    *used1 = apr_pstrdup(p, pathname);
    *used2 = NULL;
}


APU_DECLARE(apr_status_t) apr_dbm_open_db(apr_dbm_t **pdb,
					  const char *pathname,
					  apr_int32_t mode,
					  apr_fileperms_t perm,
					  apr_pool_t *pool)
{
    apr_berkeley_db_t *file = apr_pcalloc(pool, sizeof(apr_berkeley_db_t));
    int dbmode;
    int dberr;

    *pdb = NULL;

    switch (mode) {
    case APR_DBM_READONLY:
        dbmode = APR_DBM_DBMODE_RO;
        break;
    case APR_DBM_READWRITE:
        dbmode = APR_DBM_DBMODE_RW;
        break;
    case APR_DBM_RWCREATE:
        dbmode = APR_DBM_DBMODE_RWCREATE;
        break;
    default:
        return APR_EINVAL;
    }
    /* 
     * Allocate the structure before attempting to open
     * the DB.
     * (so we can call a error routine if we fail to open)
     */
    *pdb = apr_pcalloc(pool, sizeof(**pdb));
    (*pdb)->pool = pool;
    (*pdb)->file = file;
    (*pdb)->type = &apr_dbm_type_db_t;

#if DB_VER == 3
    if ((dberr = db_create(&file->bdb, NULL, 0)) == 0) {
        if ((dberr = (*file->bdb->open)(file->bdb, pathname, NULL, DB_HASH, 
                                        dbmode, 
                                        apr_posix_perms2mode(perm))) != 0) {
            /* close the DB handler */
            (void)(*file->bdb->close)(file->bdb, 0);
        }
    }
    file->curs = NULL;

#elif DB_VER == 2
    dberr = db_open(pathname, DB_HASH, dbmode, apr_posix_perms2mode(perm),
	        	    NULL, NULL, &file->bdb);
    file->curs = NULL;
#else
    file->bdb = dbopen(pathname, dbmode, apr_posix_perms2mode(perm),
		               DB_HASH, NULL);

    if (file->bdb == NULL)
        return APR_OS_START_USEERR;	/* ### need a better error */

    dberr = 0;
#endif

    if (dberr != 0)
        return apr_dbm_set_error_db(*pdb, db2s(dberr));

    /* FIXME: 
     * My thinking here is that we should register a cleanup to close the DBM.
     * This should be done as BerkleyDB caches stuff and really needs to be
     * closed down properly.
     *
     * but the current code doesn't do this, and the other DBMs don't do it eiher.
     * (and it segfaults ;( )
     * maybe pool is deleted before this is ??run??
     * apr_pool_cleanup_register(pool, pdb, db_cleanup,apr_pool_cleanup_null);
     */

    return APR_SUCCESS;
}

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_db_t= {
    "DB",
    apr_dbm_set_error_db,
    apr_dbm_close_db,
    apr_dbm_fetch_db,
    apr_dbm_store_db,
    apr_dbm_delete_db,
    apr_dbm_exists_db,
    apr_dbm_firstkey_db,
    apr_dbm_nextkey_db,
    apr_dbm_geterror_db,
    apr_dbm_datum_cleanup_noop,
    apr_dbm_freedatum_noop
};
#endif	/* !APU_USE_DB */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr.h"
#include "apr_errno.h"
#include "apr_pools.h"
#include "apr_strings.h"
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_want.h"

#include "apu_select_dbm.h"
#include "apr_dbm.h"


#if APU_USE_GDBM
#include "private/apr_dbm_private.h"
#include "apr_dbm_gdbm.h"

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_gdbm_t;

#include <gdbm.h>
#include <stdlib.h>     /* for free() */

#define APR_DBM_DBMODE_RO       GDBM_READER
#define APR_DBM_DBMODE_RW       GDBM_WRITER
#define APR_DBM_DBMODE_RWCREATE GDBM_WRCREAT

/* map a GDBM error to an apr_status_t */
static apr_status_t g2s(int gerr)
{
    if (gerr == -1) {
        return APR_OS_START_USEERR+gerr;
    }
    return APR_SUCCESS;
}

static apr_status_t datum_cleanup(void *dptr)
{
    if (dptr) 
        free(dptr);
    return APR_SUCCESS;
}

#define REGISTER_CLEANUP(dbm, pdatum) \
    if ((pdatum)->dptr) \
        apr_pool_cleanup_register((dbm)->pool, (pdatum)->dptr, \
                             datum_cleanup, apr_pool_cleanup_null); \
    else

static apr_status_t apr_dbm_set_error_gdbm(apr_dbm_t *dbm, apr_status_t dbm_said)
{
    apr_status_t rv = APR_SUCCESS;

    /* FIXME: check for error codes that APR already has and map the DB ones to them */

    if ((dbm->errcode = gdbm_errno) == GDBM_NO_ERROR) {
        dbm->errmsg = NULL;
    }
    else {
        dbm->errmsg = gdbm_strerror(gdbm_errno);
        rv = APR_OS_START_USEERR+gdbm_errno;
    }

    /* captured it. clear it now. */
    gdbm_errno = GDBM_NO_ERROR;

    return rv;
}
static void apr_dbm_close_gdbm(apr_dbm_t *dbm)
{
    gdbm_close(f)
}
static apr_status_t apr_dbm_fetch_gdbm(apr_dbm_t *dbm, apr_datum_t key,
                                       apr_datum_t *pvalue)
{
    apr_status_t rv;
    datum* ckey;
    datum rd;

    ckey = (datum *)&key;
    rd = gdbm_fetch(dbm->file,*ckey);


    *pvalue = *(apr_datum_t *)&(rd);

    REGISTER_CLEANUP(dbm, pvalue);

    /* XXX: gdbm_fetch doesn't return an error code?? */
    return apr_dbm_set_error_gdbm(dbm, APR_SUCCESS);
}

static apr_status_t apr_dbm_store_gdbm(apr_dbm_t *dbm, apr_datum_t key,
                                       apr_datum_t value)
{
    apr_status_t rv;
    int gret;
    datum *ckey;
    datum *cvalue;

    ckey = (datum *)&key;
    cvalue = (datum *)&value;
    gret = gdbm_store(dbm->file, *ckey,*cvalue, GDBM_REPLACE);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_gdbm(dbm, g2s(gret) );
}

static apr_status_t apr_dbm_delete_gdbm(apr_dbm_t *dbm, apr_datum_t key)
{
    apr_status_t rv;
    datum* ckey;
    int gret;

    ckey = (datum *)&key;
    gret = gdbm_delete(dbm->file, *ckey);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_gdbm(dbm, g2s(gret));
}


static int apr_dbm_exists_gdbm(apr_dbm_t *dbm, apr_datum_t key)
{
    int exists;
    datum *ckey;

    ckey = (datum *)&key;

    exists = gdbm_exists(dbm->file, *ckey) != 0;

    return exists;
}

static apr_status_t apr_dbm_firstkey_gdbm(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    datum rd;

    rd = gdbm_firstkey(dbm->file);

    *pkey = *(apr_datum_t *)&(rd);

    REGISTER_CLEANUP(dbm, pkey);

    /* store any error info into DBM, and return a status code. */
    /** XXX: gdbm doesn't return a error?? */
    return apr_dbm_set_error_gdbm(dbm, APR_SUCCESS);
}


static apr_status_t apr_dbm_nextkey_gdbm(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    datum *ckey;
    datum rd;

    ckey = (datum *)pkey;

    rv = APR_DBM_NEXTKEY(dbm->file, ckey, rd);
    *pkey = *(apr_datum_t *)&(rd);

    rd = gdbm_nextkey(dbm->file, *ckey);

    REGISTER_CLEANUP(dbm, pkey);

    /* store any error info into DBM, and return a status code. */
    /** XXX: gdbm doesn't return a error?? */
    return apr_dbm_set_error_gdbm(dbm, APR_SUCCESS);
}


static void apr_dbm_freedatum_gdbm(apr_dbm_t *dbm, apr_datum_t data)
{
    (void) apr_pool_cleanup_run(dbm->pool, data.dptr, datum_cleanup);
}

static char *apr_dbm_geterror_gdbm(apr_dbm_t *dbm, int *errcode, char *errbuf,
                                   apr_size_t errbufsize)
{
    if (errcode != NULL)
        *errcode = dbm->errcode;

    if (dbm->errmsg == NULL)
        *errbuf = '\0';
    else
        (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
    return errbuf;
}

APU_DECLARE(void) apr_dbm_get_usednames_gdbm(apr_pool_t *p,
                                             const char *pathname,
                                             const char **used1,
                                             const char **used2)
{
    *used1 = apr_pstrdup(p, pathname);
    *used2 = NULL;
}


APU_DECLARE(apr_status_t) apr_dbm_open_gdbm(apr_dbm_t **pdb,
                                            const char *pathname,
                                            apr_int32_t mode,
                                            apr_fileperms_t perm,
                                            apr_pool_t *pool)
{
    int dbmode;
    int dberr;

    *pdb = NULL;

    switch (mode) {
    case APR_DBM_READONLY:
        dbmode = APR_DBM_DBMODE_RO;
        break;
    case APR_DBM_READWRITE:
        dbmode = APR_DBM_DBMODE_RW;
        break;
    case APR_DBM_RWCREATE:
        dbmode = APR_DBM_DBMODE_RWCREATE;
        break;
    default:
        return APR_EINVAL;
    }
    /* 
     * Allocate the structure before attempting to open
     * the DB.
     * (so we can call a error routine if we fail to open)
     */
    *pdb = apr_pcalloc(pool, sizeof(**pdb));
    (*pdb)->pool = pool;
    (*pdb)->type = &apr_dbm_type_gdbm_t;
    (*pdb)->file = gdbm_open((char *) pathname, 0, dbmode,
                              apr_posix_perms2mode(perm), NULL);
    if ((*pdb)->file == NULL)
        return APR_EGENERAL;      /* ### need a better error */

    return APR_SUCCESS;
}

static apr_status_t  apr_dbm_datum_cleanup_gdbm(void *dptr)
{
    if (dptr)
        free(dptr);

    return APR_SUCCESS;
}

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_gdbm_t= {
    "GDBM",
    apr_dbm_set_error_gdbm,
    apr_dbm_close_gdbm,
    apr_dbm_fetch_gdbm,
    apr_dbm_store_gdbm,
    apr_dbm_delete_gdbm,
    apr_dbm_exists_gdbm,
    apr_dbm_firstkey_gdbm,
    apr_dbm_nextkey_gdbm,
    apr_dbm_geterror_gdbm,
    apr_dbm_datum_cleanup_gdbm,
    apr_dbm_freedatum_gdbm
};

#endif /* !APU_USE_GDBM */

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr.h"

#include "apr_errno.h"
#include "apr_pools.h"
#include "apr_strings.h"
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_want.h"

#include "apu_select_dbm.h"
#include "apr_dbm.h"
#include "apu.h"

#if APU_USE_SDBM

#include "private/apr_dbm_private.h"
#include "apr_dbm_sdbm.h"
#include "apr_sdbm.h"

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_sdbm_t;

#define APR_DBM_DBMODE_RO       APR_READ
#define APR_DBM_DBMODE_RW       (APR_READ | APR_WRITE)
#define APR_DBM_DBMODE_RWCREATE (APR_READ | APR_WRITE | APR_CREATE)

static void apr_dbm_close_sdbm(apr_dbm_t *dbm)
{
    apr_sdbm_close((apr_sdbm_t *) dbm->file);
}

static apr_status_t apr_dbm_set_error_sdbm(apr_dbm_t *dbm,
                                           apr_status_t dbm_said)
{
    apr_status_t rv = APR_SUCCESS;

    /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
    if ((dbm->errcode = dbm_said) == APR_SUCCESS) {
        dbm->errmsg = NULL;
    }
    else {
        dbm->errmsg = "I/O error occurred.";
        /* XXX: SDBM returns APR Error codes*/
        rv = dbm->errcode; 
    }
    return rv;
}

static apr_status_t apr_dbm_fetch_sdbm(apr_dbm_t *dbm, apr_datum_t key,
                                       apr_datum_t *pvalue)
{
    apr_status_t rv;
    apr_sdbm_datum_t *ckey;
    apr_sdbm_datum_t rd;

    ckey = (apr_sdbm_datum_t *) & key;

    rd.dptr = NULL;
    rd.dsize = -1;

    rv = apr_sdbm_fetch(dbm->file, &rd, *ckey);

    *(pvalue) = *(apr_datum_t *) & rd;

    /* store the error info into DBM, and return a status code. Also, note
       that *pvalue should have been cleared on error. */
    return apr_dbm_set_error_sdbm(dbm, rv);
}

static apr_status_t apr_dbm_store_sdbm(apr_dbm_t *dbm, apr_datum_t key,
                                       apr_datum_t value)
{
    apr_status_t rv;
    apr_sdbm_datum_t *ckey;
    apr_sdbm_datum_t *cvalue;

    ckey = (apr_sdbm_datum_t *) & key;
    cvalue = (apr_sdbm_datum_t *) & value;
    rv = apr_sdbm_store(dbm->file, *ckey, *cvalue, APR_SDBM_REPLACE);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_sdbm(dbm, rv);
}

static apr_status_t apr_dbm_delete_sdbm(apr_dbm_t *dbm, apr_datum_t key)
{
    apr_status_t rv;
    apr_sdbm_datum_t *ckey;

    ckey = (apr_sdbm_datum_t *) & key;
    rv = apr_sdbm_delete(dbm->file, *ckey);

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_sdbm(dbm, rv);
}

static int apr_dbm_exists_sdbm(apr_dbm_t *dbm, apr_datum_t key)
{
    int exists;
    apr_sdbm_datum_t *ckey;
    apr_sdbm_datum_t value;

    ckey = (apr_sdbm_datum_t *) & key;
    if (apr_sdbm_fetch(dbm->file, &value, *ckey) != APR_SUCCESS) {
        exists = 0;
    }
    else {
        exists = value.dptr != NULL;
    }
    return exists;
}

static apr_status_t apr_dbm_firstkey_sdbm(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    apr_sdbm_datum_t rd;

    rv = apr_sdbm_firstkey(dbm->file, &rd);
    *pkey = *(apr_datum_t *) & rd;
    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_sdbm(dbm, rv);
}

static apr_status_t apr_dbm_nextkey_sdbm(apr_dbm_t *dbm, apr_datum_t *pkey)
{
    apr_status_t rv;
    apr_sdbm_datum_t *ckey;
    apr_sdbm_datum_t rd;

    ckey = (apr_sdbm_datum_t *) pkey;
    rv = apr_sdbm_nextkey(dbm->file, &rd);
    *pkey = *(apr_datum_t *) & rd;

    /* store any error info into DBM, and return a status code. */
    return apr_dbm_set_error_sdbm(dbm, APR_SUCCESS);
}


APU_DECLARE(void) apr_dbm_get_usednames_sdbm(apr_pool_t *p,
                                             const char *pathname,
                                             const char **used1,
                                             const char **used2)
{
    char *work;

    *used1 = apr_pstrcat(p, pathname, APR_SDBM_DIRFEXT, NULL);
    *used2 = work = apr_pstrdup(p, *used1);

    /* we know the extension is 4 characters */
    memcpy(&work[strlen(work) - 4], APR_SDBM_PAGFEXT, 4);
}

static void apr_dbm_freedatum_noop(apr_dbm_t *dbm, apr_datum_t data)
{
    /* do nothing */
}
static apr_status_t apr_dbm_datum_cleanup_noop(void *x)
{
    return APR_SUCCESS;
}
static char *apr_dbm_geterror_sdbm(apr_dbm_t *dbm, int *errcode, char *errbuf,
                                   apr_size_t errbufsize)
{
    if (errcode != NULL)
        *errcode = dbm->errcode;

    if (dbm->errmsg == NULL) {
        *errbuf = '\0';
    }
    else {
        (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
    }
    return errbuf;
}

APU_DECLARE(apr_status_t) apr_dbm_open_sdbm(apr_dbm_t **pdb, 
                                            const char *pathname, 
                                            apr_int32_t mode,
                                            apr_fileperms_t perm,
                                            apr_pool_t *pool)
{
    apr_sdbm_t *file;
    apr_status_t rv;
    int dbmode;

    *pdb = NULL;

    switch (mode) {
    case APR_DBM_READONLY:
        dbmode = APR_DBM_DBMODE_RO;
        break;
    case APR_DBM_READWRITE:
        dbmode = APR_DBM_DBMODE_RW;
        break;
    case APR_DBM_RWCREATE:
        dbmode = APR_DBM_DBMODE_RWCREATE;
        break;
    default:
        return APR_EINVAL;
    }

    rv = apr_sdbm_open(&file, pathname, dbmode, perm, pool);
    if (rv != APR_SUCCESS)
        return rv;

    *pdb = apr_pcalloc(pool, sizeof(**pdb));
    (*pdb)->pool = pool;
    (*pdb)->file = file;
    (*pdb)->type = &apr_dbm_type_sdbm_t;

    /* we have an open database... return it */
    return APR_SUCCESS;

}

APU_DECLARE_DATA const apr_dbm_type_t apr_dbm_type_sdbm_t= {
    "SDBM",
    apr_dbm_set_error_sdbm,
    apr_dbm_close_sdbm,
    apr_dbm_fetch_sdbm,
    apr_dbm_store_sdbm,
    apr_dbm_delete_sdbm,
    apr_dbm_exists_sdbm,
    apr_dbm_firstkey_sdbm,
    apr_dbm_nextkey_sdbm,
    apr_dbm_geterror_sdbm,
    apr_dbm_datum_cleanup_noop,
    apr_dbm_freedatum_noop
};
#endif /* !APU_USE_SDBM */
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr.h"
#include "apr_errno.h"
#include "apr_pools.h"
#include "apr_strings.h"
#ifdef APR_HAVE_STDIO_H
#include <stdio.h>
#endif
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_want.h"

#include "apu_select_dbm.h"
#include "apr_dbm.h"
#include "private/apr_dbm_private.h"

/* this is so we can select a 'default' open/getnames */
#if APU_USE_SDBM
#include "apr_dbm_sdbm.h"
#elif APU_USE_DB
#include "apr_dbm_db.h"
#elif APU_USE_GDBM
#include "apr_dbm_gdbm.h"
#endif

/* Most DBM libraries take a POSIX mode for creating files.  Don't trust
 * the mode_t type, some platforms may not support it, int is safe.
 */
APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm)
{
    int mode = 0;

    mode |= 0700 & (perm >> 2); /* User  is off-by-2 bits */
    mode |= 0070 & (perm >> 1); /* Group is off-by-1 bit */
    mode |= 0007 & (perm);      /* World maps 1 for 1 */
    return mode;
}



APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t ** pdb, const char *pathname,
                                       apr_int32_t mode, apr_fileperms_t perm,
                                       apr_pool_t * pool)
{
#if APU_USE_SDBM
    return apr_dbm_open_sdbm(pdb, pathname, mode, perm, pool);
#elif APU_USE_DB
    return apr_dbm_open_db(pdb, pathname, mode, perm, pool);
#elif APU_USE_GDBM
    return apr_dbm_open_gdbm(pdb, pathname, mode, perm, pool);
#else
    return APR_ENOTAVAIL;
#endif
}

APU_DECLARE(void) apr_dbm_close(apr_dbm_t * dbm)
{
    dbm->type->close(dbm);
}

APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t * dbm, apr_datum_t key,
                                        apr_datum_t * pvalue)
{
    return dbm->type->fetch(dbm, key, pvalue);
}

APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t * dbm, apr_datum_t key,
                                        apr_datum_t value)
{
    return dbm->type->store(dbm, key, value);
}

APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t * dbm, apr_datum_t key)
{
    return dbm->type->del(dbm, key);
}

APU_DECLARE(int) apr_dbm_exists(apr_dbm_t * dbm, apr_datum_t key)
{
    return dbm->type->exists(dbm, key);
}

APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t * dbm,
                                           apr_datum_t * pkey)
{
    return dbm->type->firstkey(dbm, pkey);
}

APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t * dbm, apr_datum_t * pkey)
{
    return dbm->type->nextkey(dbm, pkey);
}

APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t * dbm, apr_datum_t data)
{
    dbm->type->freedatum(dbm, data);
}


APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t * dbm, int *errcode,
                                     char *errbuf, apr_size_t errbufsize)
{
    return dbm->type->geterror(dbm, errcode, errbuf, errbufsize);
}

APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t * p,
                                        const char *pathname,
                                        const char **used1,
                                        const char **used2)
{
#if APU_USE_SDBM
    apr_dbm_get_usednames_sdbm(p, pathname, used1, used2);
#elif APU_USE_DB
    apr_dbm_get_usednames_db(p, pathname, used1, used2);
#elif APU_USE_GDBM
    apr_dbm_get_usednames_gdbm(p, pathname, used1, used2);
#else
    /* default op. no assumptions made */
    fprintf(stderr, "This Database does not implement apr_dbm_get_usednames");
    *used1 = NULL;
    *used2 = NULL;
#endif
}
Index: apr_dbm.c
===================================================================
RCS file: /home/cvs/apr-util/dbm/apr_dbm.c,v
retrieving revision 1.26
diff -u -u -r1.26 apr_dbm.c
--- apr_dbm.c   2001/05/21 19:14:39     1.26
+++ apr_dbm.c   2001/08/24 18:31:40
@@ -56,49 +56,30 @@
 #include "apr_errno.h"
 #include "apr_pools.h"
 #include "apr_strings.h"
+#ifdef APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
 #define APR_WANT_MEMFUNC
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
 
 #include "apu_select_dbm.h"
 #include "apr_dbm.h"
-
-
-/* this is used in a few places to define a noop "function". it is needed
-   to stop "no effect" warnings from GCC. */
-#define NOOP_FUNCTION if (0) ; else
+#include "private/apr_dbm_private.h"
 
-
+/* this is so we can select a 'default' open/getnames */
 #if APU_USE_SDBM
-
-#include "apr_sdbm.h"
-
-typedef apr_sdbm_t *real_file_t;
-
-typedef apr_sdbm_datum_t *cvt_datum_t;
-#define CONVERT_DATUM(cvt, pinput) ((cvt) = (apr_sdbm_datum_t *)(pinput))
-
-typedef apr_sdbm_datum_t result_datum_t;
-#define RETURN_DATUM(poutput, rd) (*(poutput) = *(apr_datum_t *)&(rd))
-
-#define APR_DBM_CLOSE(f)       apr_sdbm_close(f)
-#define APR_DBM_FETCH(f, k, v) apr_sdbm_fetch(f, &(v), *(k))
-#define APR_DBM_STORE(f, k, v) apr_sdbm_store(f, *(k), *(v), APR_SDBM_REPLACE)
-#define APR_DBM_DELETE(f, k)   apr_sdbm_delete(f, *(k))
-#define APR_DBM_FIRSTKEY(f, k) apr_sdbm_firstkey(f, &(k))
-#define APR_DBM_NEXTKEY(f, k, nk) apr_sdbm_nextkey(f, &(nk))
-#define APR_DBM_FREEDPTR(dptr) NOOP_FUNCTION
-
-#define APR_DBM_DBMODE_RO       APR_READ
-#define APR_DBM_DBMODE_RW       (APR_READ | APR_WRITE)
-#define APR_DBM_DBMODE_RWCREATE (APR_READ | APR_WRITE | APR_CREATE)
-
-#else /* Not using SDBM: */
+#include "apr_dbm_sdbm.h"
+#elif APU_USE_DB
+#include "apr_dbm_db.h"
+#elif APU_USE_GDBM
+#include "apr_dbm_gdbm.h"
+#endif
 
 /* Most DBM libraries take a POSIX mode for creating files.  Don't trust
  * the mode_t type, some platforms may not support it, int is safe.
  */
-int apr_posix_perms2mode(apr_fileperms_t perm) 
+APU_DECLARE(int) apr_posix_perms2mode(apr_fileperms_t perm)
 {
     int mode = 0;
 
@@ -108,494 +89,88 @@
     return mode;
 }
 
-#if APU_USE_GDBM
-
-#include <gdbm.h>
-#include <stdlib.h>     /* for free() */
-
-typedef GDBM_FILE real_file_t;
-
-typedef datum *cvt_datum_t;
-#define CONVERT_DATUM(cvt, pinput) ((cvt) = (datum *)(pinput))
-
-typedef datum result_datum_t;
-#define RETURN_DATUM(poutput, rd) (*(poutput) = *(apr_datum_t *)&(rd))
-
-#define APR_DBM_CLOSE(f)       gdbm_close(f)
-#define APR_DBM_FETCH(f, k, v) ((v) = gdbm_fetch(f, *(k)), APR_SUCCESS)
-#define APR_DBM_STORE(f, k, v) g2s(gdbm_store(f, *(k), *(v), GDBM_REPLACE))
-#define APR_DBM_DELETE(f, k)   g2s(gdbm_delete(f, *(k)))
-#define APR_DBM_FIRSTKEY(f, k) ((k) = gdbm_firstkey(f), APR_SUCCESS)
-#define APR_DBM_NEXTKEY(f, k, nk) ((nk) = gdbm_nextkey(f, *(k)), APR_SUCCESS)
-#define APR_DBM_FREEDPTR(dptr) ((dptr) ? free(dptr) : 0)
-
-#define NEEDS_CLEANUP
-
-#define APR_DBM_DBMODE_RO       GDBM_READER
-#define APR_DBM_DBMODE_RW       GDBM_WRITER
-#define APR_DBM_DBMODE_RWCREATE GDBM_WRCREAT
-
-/* map a GDBM error to an apr_status_t */
-static apr_status_t g2s(int gerr)
-{
-    if (gerr == -1) {
-        /* ### need to fix this */
-        return APR_EGENERAL;
-    }
-
-    return APR_SUCCESS;
-}
-
-#elif APU_USE_DB
-/*
- * We pick up all varieties of Berkeley DB through db.h (included through
- * apu_select_dbm.h). This code has been compiled/tested against DB1,
- * DB_185, DB2, and DB3.
- */
-
-#if   defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 3)
-#define DB_VER 3
-#elif defined(DB_VERSION_MAJOR) && (DB_VERSION_MAJOR == 2)
-#define DB_VER 2
-#else
-#define DB_VER 1
-#endif
-
-typedef struct {
-    DB *bdb;
-#if DB_VER != 1
-    DBC *curs;
-#endif
-} real_file_t;
-
-typedef DBT cvt_datum_t;
-#define CONVERT_DATUM(cvt, pinput) (memset(&(cvt), 0, sizeof(cvt)), \
-                                    (cvt).data = (pinput)->dptr, \
-                                    (cvt).size = (pinput)->dsize)
-
-typedef DBT result_datum_t;
-#define RETURN_DATUM(poutput, rd) ((poutput)->dptr = (rd).data, \
-                                   (poutput)->dsize = (rd).size)
-
-#if DB_VER == 1
-#define TXN_ARG
-#else
-#define TXN_ARG NULL,
-#endif
-
-#if DB_VER == 1
-#define APR_DBM_CLOSE(f)       ((*(f).bdb->close)((f).bdb))
-#else
-#define APR_DBM_CLOSE(f)       ((*(f).bdb->close)((f).bdb, 0))
-#endif
-
-#define do_fetch(f, k, v)       ((*(f)->get)(f, TXN_ARG &(k), &(v), 0))
-#define APR_DBM_FETCH(f, k, v) db2s(do_fetch((f).bdb, k, v))
-#define APR_DBM_STORE(f, k, v) db2s((*(f).bdb->put)((f).bdb, TXN_ARG &(k), 
&(v), 0))
-#define APR_DBM_DELETE(f, k)   db2s((*(f).bdb->del)((f).bdb, TXN_ARG &(k), 0))
-#define APR_DBM_FIRSTKEY(f, k)  do_firstkey(&(f), &(k))
-#define APR_DBM_NEXTKEY(f, k, nk) do_nextkey(&(f), &(k), &(nk))
-#define APR_DBM_FREEDPTR(dptr) NOOP_FUNCTION
-
-#if DB_VER == 1
-#include <sys/fcntl.h>
-#define APR_DBM_DBMODE_RO       O_RDONLY
-#define APR_DBM_DBMODE_RW       O_RDWR
-#define APR_DBM_DBMODE_RWCREATE (O_CREAT | O_RDWR)
-#else
-#define APR_DBM_DBMODE_RO       DB_RDONLY
-#define APR_DBM_DBMODE_RW       0
-#define APR_DBM_DBMODE_RWCREATE DB_CREATE
-#endif
-
-/* map a DB error to an apr_status_t */
-static apr_status_t db2s(int dberr)
-{
-    if (dberr != 0) {
-        /* ### need to fix this */
-        return APR_EGENERAL;
-    }
-
-    return APR_SUCCESS;
-}
-
-/* handle the FIRSTKEY functionality */
-static apr_status_t do_firstkey(real_file_t *f, DBT *pkey)
-{
-    int dberr;
-    DBT data;
-
-#if DB_VER == 1
-    dberr = (*f->bdb->seq)(f->bdb, pkey, &data, R_FIRST);
-#else
-    if ((dberr = (*f->bdb->cursor)(f->bdb, NULL, &f->curs
-#if DB_VER == 3
-                                   , 0
-#endif
-                                   )) == 0) {
-        dberr = (*f->curs->c_get)(f->curs, pkey, &data, DB_FIRST);
-        if (dberr == DB_NOTFOUND) {
-            memset(pkey, 0, sizeof(*pkey));
-            (*f->curs->c_close)(f->curs);
-            f->curs = NULL;
-            return APR_SUCCESS;
-        }
-    }
-#endif
-
-    return db2s(dberr);
-}
-
-/* handle the NEXTKEY functionality */
-static apr_status_t do_nextkey(real_file_t *f, DBT *pkey, DBT *pnext)
-{
-    int dberr;
-    DBT data;
-
-#if DB_VER == 1
-    dberr = (*f->bdb->seq)(f->bdb, pkey, &data, R_NEXT);
-#else
-    if (f->curs == NULL)
-        return APR_EINVAL;
-
-    dberr = (*f->curs->c_get)(f->curs, pkey, &data, DB_NEXT);
-    if (dberr == DB_NOTFOUND) {
-        memset(pkey, 0, sizeof(*pkey));
-        (*f->curs->c_close)(f->curs);
-        f->curs = NULL;
-        return APR_SUCCESS;
-    }
-#endif
-
-    return db2s(dberr);
-}
-
-#else /* Not in the USE_xDBM list above */
-#error a DBM implementation was not specified
-#endif
-
-#endif /* Not USE_SDBM */
-
-struct apr_dbm_t
-{
-    apr_pool_t *pool;
-    real_file_t file;
-
-    int errcode;
-    const char *errmsg;
-};
-
-
-#ifdef NEEDS_CLEANUP
-
-static apr_status_t datum_cleanup(void *dptr)
-{
-    APR_DBM_FREEDPTR(dptr);
-    return APR_SUCCESS;
-}
-
-#define REGISTER_CLEANUP(dbm, pdatum) \
-    if ((pdatum)->dptr) \
-        apr_pool_cleanup_register((dbm)->pool, (pdatum)->dptr, \
-                             datum_cleanup, apr_pool_cleanup_null); \
-    else
-
-#else /* NEEDS_CLEANUP */
-
-#define REGISTER_CLEANUP(dbm, pdatum) NOOP_FUNCTION
-
-#endif /* NEEDS_CLEANUP */
-
-static apr_status_t set_error(apr_dbm_t *dbm, apr_status_t dbm_said)
-{
-    apr_status_t rv = APR_SUCCESS;
-
-    /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */
-
-#if APU_USE_SDBM
-
-    if ((dbm->errcode = dbm_said) == APR_SUCCESS) {
-        dbm->errmsg = NULL;
-    }
-    else {
-        dbm->errmsg = "I/O error occurred.";
-        rv = APR_EGENERAL;        /* ### need something better */
-    }
-
-#elif APU_USE_GDBM
-
-    if ((dbm->errcode = gdbm_errno) == GDBM_NO_ERROR) {
-        dbm->errmsg = NULL;
-    }
-    else {
-        dbm->errmsg = gdbm_strerror(gdbm_errno);
-        rv = APR_EGENERAL;        /* ### need something better */
-    }
-
-    /* captured it. clear it now. */
-    gdbm_errno = GDBM_NO_ERROR;
-
-#elif APU_USE_DB
 
-    if (dbm_said == APR_SUCCESS) {
-        dbm->errcode = 0;
-        dbm->errmsg = NULL;
-    }
-    else {
-        /* ### need to fix. dberr was tossed in db2s(). */
-        /* ### use db_strerror() */
-        dbm->errcode = 1;
-        dbm->errmsg = "DB error occurred.";
-        rv = APR_EGENERAL;
-    }
-#else
-#error set_error has not been coded for this database type
-#endif
-
-    return rv;
-}
 
-APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t **pdb, const char *pathname, 
+APU_DECLARE(apr_status_t) apr_dbm_open(apr_dbm_t ** pdb, const char *pathname,
                                        apr_int32_t mode, apr_fileperms_t perm,
-                                       apr_pool_t *pool)
+                                       apr_pool_t * pool)
 {
-    real_file_t file;
-    int dbmode;
-
-    *pdb = NULL;
-
-    switch (mode) {
-    case APR_DBM_READONLY:
-        dbmode = APR_DBM_DBMODE_RO;
-        break;
-    case APR_DBM_READWRITE:
-        dbmode = APR_DBM_DBMODE_RW;
-        break;
-    case APR_DBM_RWCREATE:
-        dbmode = APR_DBM_DBMODE_RWCREATE;
-        break;
-    default:
-        return APR_EINVAL;
-    }
-
 #if APU_USE_SDBM
-
-    {
-        apr_status_t rv;
-
-        rv = apr_sdbm_open(&file, pathname, dbmode, perm, pool);
-        if (rv != APR_SUCCESS)
-            return rv;
-    }
-
-#elif APU_USE_GDBM
-
-    {
-        /* Note: stupid cast to get rid of "const" on the pathname */
-        file = gdbm_open((char *) pathname, 0, dbmode,
-                         apr_posix_perms2mode(perm), NULL);
-        if (file == NULL)
-            return APR_EGENERAL;      /* ### need a better error */
-    }
-
+    return apr_dbm_open_sdbm(pdb, pathname, mode, perm, pool);
 #elif APU_USE_DB
-
-    {
-        int dberr;
-
-#if DB_VER == 3
-        if ((dberr = db_create(&file.bdb, NULL, 0)) == 0) {
-            if ((dberr = (*file.bdb->open)(file.bdb, pathname, NULL, 
-                                           DB_HASH, dbmode, 
-                                           apr_posix_perms2mode(perm))) != 0) {
-                /* close the DB handler */
-                (void) (*file.bdb->close)(file.bdb, 0);
-            }
-        }
-        file.curs = NULL;
-#elif DB_VER == 2
-        dberr = db_open(pathname, DB_HASH, dbmode, apr_posix_perms2mode(perm),
-                        NULL, NULL, &file.bdb);
-        file.curs = NULL;
+    return apr_dbm_open_db(pdb, pathname, mode, perm, pool);
+#elif APU_USE_GDBM
+    return apr_dbm_open_gdbm(pdb, pathname, mode, perm, pool);
 #else
-        file.bdb = dbopen(pathname, dbmode, apr_posix_perms2mode(perm),
-                          DB_HASH, NULL);
-        if (file.bdb == NULL)
-            return APR_EGENERAL;      /* ### need a better error */
-        dberr = 0;
+    return APR_ENOTAVAIL;
 #endif
-        if (dberr != 0)
-            return db2s(dberr);
-    }
-
-#else
-#error apr_dbm_open has not been coded for this database type
-#endif /* switch on database types */
-
-    /* we have an open database... return it */
-    *pdb = apr_pcalloc(pool, sizeof(**pdb));
-    (*pdb)->pool = pool;
-    (*pdb)->file = file;
-
-    /* ### register a cleanup to close the DBM? */
-
-    return APR_SUCCESS;
 }
 
-APU_DECLARE(void) apr_dbm_close(apr_dbm_t *dbm)
+APU_DECLARE(void) apr_dbm_close(apr_dbm_t * dbm)
 {
-    APR_DBM_CLOSE(dbm->file);
+    dbm->type->close(dbm);
 }
 
-APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key,
-                                        apr_datum_t *pvalue)
+APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t * dbm, apr_datum_t key,
+                                        apr_datum_t * pvalue)
 {
-    apr_status_t rv;
-    cvt_datum_t ckey;
-    result_datum_t rd;
-
-    CONVERT_DATUM(ckey, &key);
-    rv = APR_DBM_FETCH(dbm->file, ckey, rd);
-    RETURN_DATUM(pvalue, rd);
-
-    REGISTER_CLEANUP(dbm, pvalue);
-
-    /* store the error info into DBM, and return a status code. Also, note
-       that *pvalue should have been cleared on error. */
-    return set_error(dbm, rv);
+    return dbm->type->fetch(dbm, key, pvalue);
 }
 
-APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key,
+APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t * dbm, apr_datum_t key,
                                         apr_datum_t value)
 {
-    apr_status_t rv;
-    cvt_datum_t ckey;
-    cvt_datum_t cvalue;
-
-    CONVERT_DATUM(ckey, &key);
-    CONVERT_DATUM(cvalue, &value);
-    rv = APR_DBM_STORE(dbm->file, ckey, cvalue);
-
-    /* store any error info into DBM, and return a status code. */
-    return set_error(dbm, rv);
+    return dbm->type->store(dbm, key, value);
 }
 
-APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key)
+APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t * dbm, apr_datum_t key)
 {
-    apr_status_t rv;
-    cvt_datum_t ckey;
-
-    CONVERT_DATUM(ckey, &key);
-    rv = APR_DBM_DELETE(dbm->file, ckey);
-
-    /* store any error info into DBM, and return a status code. */
-    return set_error(dbm, rv);
+    return dbm->type->del(dbm, key);
 }
 
-APU_DECLARE(int) apr_dbm_exists(apr_dbm_t *dbm, apr_datum_t key)
+APU_DECLARE(int) apr_dbm_exists(apr_dbm_t * dbm, apr_datum_t key)
 {
-    int exists;
-    cvt_datum_t ckey;
-
-    CONVERT_DATUM(ckey, &key);
-
-#if APU_USE_SDBM
-    {
-       apr_sdbm_datum_t value;
-        if (apr_sdbm_fetch(dbm->file, &value, *ckey) != APR_SUCCESS) {
-           exists = 0;
-        }
-        else
-            exists = value.dptr != NULL;
-    }
-#elif APU_USE_GDBM
-    exists = gdbm_exists(dbm->file, *ckey) != 0;
-#elif APU_USE_DB
-    {
-        DBT data;
-        int dberr = do_fetch(dbm->file.bdb, ckey, data);
-
-        /* DB returns DB_NOTFOUND if it doesn't exist. but we want to say
-           that *any* error means it doesn't exist. */
-        exists = dberr == 0;
-    }
-#else
-#error apr_dbm_exists has not been coded for this database type
-#endif
-    return exists;
+    return dbm->type->exists(dbm, key);
 }
 
-APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t *dbm, apr_datum_t *pkey)
+APU_DECLARE(apr_status_t) apr_dbm_firstkey(apr_dbm_t * dbm,
+                                           apr_datum_t * pkey)
 {
-    apr_status_t rv;
-    result_datum_t rd;
-
-    rv = APR_DBM_FIRSTKEY(dbm->file, rd);
-    RETURN_DATUM(pkey, rd);
-
-    REGISTER_CLEANUP(dbm, pkey);
-
-    /* store any error info into DBM, and return a status code. */
-    return set_error(dbm, rv);
+    return dbm->type->firstkey(dbm, pkey);
 }
 
-APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t *dbm, apr_datum_t *pkey)
+APU_DECLARE(apr_status_t) apr_dbm_nextkey(apr_dbm_t * dbm, apr_datum_t * pkey)
 {
-    apr_status_t rv;
-    cvt_datum_t ckey;
-    result_datum_t rd;
-
-    CONVERT_DATUM(ckey, pkey);
-    rv = APR_DBM_NEXTKEY(dbm->file, ckey, rd);
-    RETURN_DATUM(pkey, rd);
-
-    REGISTER_CLEANUP(dbm, pkey);
-
-    /* store any error info into DBM, and return a status code. */
-    return set_error(dbm, APR_SUCCESS);
+    return dbm->type->nextkey(dbm, pkey);
 }
 
-APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t *dbm, apr_datum_t data)
+APU_DECLARE(void) apr_dbm_freedatum(apr_dbm_t * dbm, apr_datum_t data)
 {
-#ifdef NEEDS_CLEANUP
-    (void) apr_pool_cleanup_run(dbm->pool, data.dptr, datum_cleanup);
-#else
-    APR_DBM_FREEDPTR(data.dptr);
-#endif
+    dbm->type->freedatum(dbm, data);
 }
+
 
-APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t *dbm, int *errcode,
+APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t * dbm, int *errcode,
                                      char *errbuf, apr_size_t errbufsize)
 {
-    if (errcode != NULL)
-        *errcode = dbm->errcode;
-
-    /* assert: errbufsize > 0 */
-
-    if (dbm->errmsg == NULL)
-        *errbuf = '\0';
-    else
-        (void) apr_cpystrn(errbuf, dbm->errmsg, errbufsize);
-    return errbuf;
+    return dbm->type->geterror(dbm, errcode, errbuf, errbufsize);
 }
 
-APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t *p,
+APU_DECLARE(void) apr_dbm_get_usednames(apr_pool_t * p,
                                         const char *pathname,
                                         const char **used1,
                                         const char **used2)
 {
 #if APU_USE_SDBM
-    char *work;
-
-    *used1 = apr_pstrcat(p, pathname, APR_SDBM_DIRFEXT, NULL);
-    *used2 = work = apr_pstrdup(p, *used1);
-
-    /* we know the extension is 4 characters */
-    memcpy(&work[strlen(work) - 4], APR_SDBM_PAGFEXT, 4);
-#elif APU_USE_GDBM || APU_USE_DB
-    *used1 = apr_pstrdup(p, pathname);
-    *used2 = NULL;
+    apr_dbm_get_usednames_sdbm(p, pathname, used1, used2);
+#elif APU_USE_DB
+    apr_dbm_get_usednames_db(p, pathname, used1, used2);
+#elif APU_USE_GDBM
+    apr_dbm_get_usednames_gdbm(p, pathname, used1, used2);
 #else
-#error apr_dbm_get_usednames has not been coded for this database type
+    /* default op. no assumptions made */
+    fprintf(stderr, "This Database does not implement apr_dbm_get_usednames");
+    *used1 = NULL;
+    *used2 = NULL;
 #endif
 }

Reply via email to