sorry bout that.
MSVC does it's own thing with spacing ;(
(ok.. I've run the code through indent so that should help.)

Justin Erenkrantz wrote:

On Mon, Aug 20, 2001 at 09:31:51AM -0700, Ian Holsman wrote:

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


Watch the style. This should be:

return dbm->fetch(dbm, key, pvalue);

No spaces before the ( and spaces in between parameter names.

I think you misnamed the Berkeley DB file/structure. You called it berkley. =-) I can never spell it right either - I had to go to their website (which of course requires spelling berkeley right - a
catch-22 - thanks goodness for Google...).


static void apr_dbm_close_db(apr_dbm_t *dbm)
{
   //APR_DBM_CLOSE(dbm.file);


// is invalid in C. Use /* */.

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_berkley_db_t *real_ptr = dbm->file;
        DB*db=real_ptr->bdb;
   DBT ckey;
   DBT rd;
        int dberr;


Seems like there are tabs and spaces in this fragment. We should only
have 4 space indention (no tab chars).


HTH. Please repost once the style is cleaned-up and then I'll look at it again. My brain doesn't parse code that isn't in the correct style. Sorry.

It generally looks good, but I'll take a deeper look once the style issues are addressed. -- justin



/* ====================================================================
 * 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/>.
 *
 * This file came from the SDBM package (written by [EMAIL PROTECTED]).
 * That package was under public domain. This file has been ported to
 * APR, updated to ANSI C and other, newer idioms, and added to the Apache
 * codebase under the above copyright and license.
 */

#include "apr.h"
#include "apr_general.h"
#include "apr_pools.h"
#include "apr_errno.h"
#include "apr_getopt.h"
#include "apr_time.h"

#if APR_HAVE_STDIO_H
#include <stdio.h>
#endif
#if APR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>             /* for atexit(), malloc() */
#include <string.h>

#include "apr_dbm.h"
#include "apr_dbm_sdbm.h"

static const char *progname;
static int rflag;
static const char *usage = "%s [-R] cat | look |... dbmname";

#define DERROR  0
#define DLOOK   1

#define DDELETE 3
#define DCAT    4
#define DBUILD  5
#define DPRESS  6
#define DCREAT  7
#define DNAME   8

#define LINEMAX 8192

typedef struct
{
    const char *sname;
    int scode;
    int flags;
}
cmd;

static const cmd cmds[] = {

    {"fetch", DLOOK, APR_DBM_READONLY,},
    {"get", DLOOK, APR_DBM_READONLY,},
    {"look", DLOOK, APR_DBM_READONLY,},
    {"add", DBUILD, APR_DBM_READWRITE,},
    {"insert", DBUILD, APR_DBM_READWRITE,},
    {"store", DBUILD, APR_DBM_READWRITE,},
    {"build", DBUILD, APR_DBM_RWCREATE,},                       /** this one 
creates the DB */
    {"delete", DDELETE, APR_DBM_READWRITE,},
    {"remove", DDELETE, APR_DBM_READWRITE,},
    {"dump", DCAT, APR_DBM_READONLY,},
    {"list", DCAT, APR_DBM_READONLY,},
    {"cat", DCAT, APR_DBM_READONLY,},
    {"creat", DCREAT, APR_DBM_RWCREATE,},
    {"new", DCREAT, APR_DBM_RWCREATE,},
    {"names", DNAME, APR_DBM_READONLY,},
#if 0
    {"squash", DPRESS, APR_DBM_READWRITE,},
    {"compact", DPRESS, APR_DBM_READWRITE,},
    {"compress", DPRESS, APR_DBM_READWRITE,},
#endif
};

#define CTABSIZ (sizeof (cmds)/sizeof (cmd))

static void doit(const cmd * act, const char *file, apr_pool_t * pool);
static void badk(const char *word);
static const cmd *parse(const char *str);
static void prdatum(FILE * stream, apr_datum_t d);
static void oops(apr_dbm_t * dbm, apr_status_t rv, const char *s1,
                 const char *s2);


int main(int argc, const char *const *argv)
{
    apr_pool_t *pool;
    const cmd *act;
    apr_getopt_t *os;
    char optch;
    const char *optarg;

    (void) apr_initialize();
    apr_pool_create(&pool, NULL);
    atexit(apr_terminate);

    (void) apr_getopt_init(&os, pool, argc, argv);

    progname = argv[0];

    while (apr_getopt(os, "R", &optch, &optarg) == APR_SUCCESS)
        switch (optch) {
        case 'R':               /* raw processing  */
            rflag++;
            break;

        default:
            oops(NULL, APR_EGENERAL, "(unknown option) usage: %s", usage);
            break;
        }

    if (os->ind + 2 > argc)
        oops(NULL, APR_EGENERAL, "usage: %s", usage);

    if ((act = parse(argv[os->ind])) == NULL)
        badk(argv[os->ind]);
    os->ind++;
    doit(act, argv[os->ind], pool);

    apr_pool_destroy(pool);

    return 0;
}

static void doit(const cmd * act, const char *file, apr_pool_t * pool)
{
    apr_status_t rv;
    apr_datum_t key;
    apr_datum_t val;
    apr_dbm_t *db;
    char *op;
    int n;
    char *line;
    char *use1;
    char *use2;
#ifdef TIME
    long start;
    extern long time();
#endif


        rv = apr_dbm_open(&db, file, act->flags, APR_OS_DEFAULT, pool);
    if (rv != APR_SUCCESS)
        oops(db, rv, "cannot open: %s", file);

    line = (char *) apr_palloc(pool, LINEMAX);
    if (line == NULL) {
        oops(NULL, APR_EGENERAL, "%s: cannot get memory", "line alloc");
    }

    switch (act->scode) {

    case DLOOK:
        while (fgets(line, LINEMAX, stdin) != NULL) {
            n = strlen(line) - 1;
            line[n] = 0;
            if (n == 0)
                break;

            key.dptr = line;
            key.dsize = n;
            rv = apr_dbm_fetch(db, key, &val);
            if (rv == APR_SUCCESS) {
                prdatum(stdout, val);
                putchar('\n');
                continue;
            }
            prdatum(stderr, key);
            fprintf(stderr, ": not found.\n");
        }
        break;

    case DDELETE:
        while (fgets(line, LINEMAX, stdin) != NULL) {
            n = strlen(line) - 1;
            line[n] = 0;
            if (n == 0)
                break;

            key.dptr = line;
            key.dsize = n;
            if (apr_dbm_delete(db, key) != APR_SUCCESS) {
                prdatum(stderr, key);
                fprintf(stderr, ": not found.\n");
            }
        }
        break;
    case DCAT:
        rv = apr_dbm_firstkey(db, &key);
        if (rv != APR_SUCCESS)
            oops(db, rv, "could not fetch first key: %s", file);

        while (key.dptr != NULL) {
            prdatum(stdout, key);
            putchar('\t');
            rv = apr_dbm_fetch(db, key, &val);
            if (rv != APR_SUCCESS)
                oops(db, rv, "apr_dbm_fetch", "failure");
            prdatum(stdout, val);
            putchar('\n');
            rv = apr_dbm_nextkey(db, &key);
            if (rv != APR_SUCCESS)
                oops(db, rv, "NextKey", "failure");
        }

        break;
    case DBUILD:
#ifdef TIME
        start = time(0);
#endif
        while (fgets(line, LINEMAX, stdin) != NULL) {
            n = strlen(line) - 1;
            line[n] = 0;
            if (n == 0)
                break;

            key.dptr = line;
            if ((op = strchr(line, '\t')) != 0) {
                key.dsize = op - line;
                *op++ = 0;
                val.dptr = op;
                val.dsize = line + n - op;
            }
            else {
                oops(NULL, APR_EGENERAL, "bad input: %s", line);
            }

            rv = apr_dbm_store(db, key, val);
            if (rv != APR_SUCCESS) {
                prdatum(stderr, key);
                fprintf(stderr, ": ");
                oops(db, rv, "store: %s", "failed");
            }
        }
#ifdef TIME
        printf("done: %d seconds.\n", time(0) - start);
#endif
        break;
    case DPRESS:
        break;
    case DCREAT:
        break;
    case DNAME:

        apr_dbm_get_usednames(pool, file, &use1, &use2);
        fprintf(stderr, "%s %s %s", file, use1, use2);
        break;
    }

    apr_dbm_close(db);
}

static void badk(const char *word)
{
    int i;

    if (progname)
        fprintf(stderr, "%s: ", progname);
    fprintf(stderr, "bad keywd %s. use one of\n", word);
    for (i = 0; i < (int) CTABSIZ; i++)
        fprintf(stderr, "%-8s%c", cmds[i].sname,
                ((i + 1) % 6 == 0) ? '\n' : ' ');
    fprintf(stderr, "\n");
    exit(1);
 /*NOTREACHED*/
}

static const cmd *parse(const char *str)
{
    int i = CTABSIZ;
    const cmd *p;

    for (p = cmds; i--; p++)
        if (strcmp(p->sname, str) == 0)
            return p;
    return NULL;
}

static void prdatum(FILE * stream, apr_datum_t d)
{
    int c;
    const char *p = d.dptr;
    int n = d.dsize;

    while (n--) {
        c = *p++ & 0377;
        if (c & 0200) {
            fprintf(stream, "M-");
            c &= 0177;
        }
        if (c == 0177 || c < ' ')
            fprintf(stream, "^%c", (c == 0177) ? '?' : c + '@');
        else
            putc(c, stream);
    }
}

static void oops(apr_dbm_t * dbm, apr_status_t rv, const char *s1,
                 const char *s2)
{
    char errbuf[200];


    if (progname)
        fprintf(stderr, "%s: ", progname);
    fprintf(stderr, s1, s2);
    if (errno > 0 && errno < sys_nerr)
        fprintf(stderr, " (%s)", sys_errlist[errno]);
    fprintf(stderr, "\n");
    if (rv != APR_SUCCESS) {
        apr_strerror(rv, errbuf, sizeof(errbuf));
        fprintf(stderr, "APR Error %d - %s\n", rv, errbuf);

        if (dbm) {
            apr_dbm_geterror(dbm, &rv, errbuf, sizeof(errbuf));
            fprintf(stderr, "APR_DB Error %d - %s\n", rv, errbuf);
        }

    }
    exit(1);
}
/* ====================================================================
 * 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
 * @deffunc apr_status_t apr_dbm_open(apr_dbm_t **dbm, const char *name, int 
mode
 * @tip 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_SDBM_H
#define APR_DBM_SDBM_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
 * @deffunc apr_status_t apr_dbm_open(apr_dbm_t **dbm, const char *name, int 
mode
 * @tip 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_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_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_H
#define APR_DBM_H

#include "apu.h"
#include "apr.h"
#include "apr_errno.h"
#include "apr_pools.h"
#include "apr_file_info.h"

#ifdef __cplusplus
extern "C"
{
#endif

/**
 * @package APR-UTIL DBM library
 */

/**
 * Structure for referencing a dbm
 * @defvar apr_dbm_t
 */
typedef struct apr_dbm_t apr_dbm_t;

/**
 * Structure for referencing the datum record within a dbm
 * @defvar apr_datum_t
 */
typedef struct
    {
        char *dptr;
        apr_size_t dsize;
}
    apr_datum_t;

/* modes to open the DB */
#define APR_DBM_READONLY        1       /* open for read-only access */
#define APR_DBM_READWRITE       2       /* open for read-write access */
#define APR_DBM_RWCREATE        3       /* open for r/w, create if needed */

/**
 * Open a dbm 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
 * @deffunc apr_status_t apr_dbm_open(apr_dbm_t **dbm, const char *name, int 
mode
 * @tip 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(apr_dbm_t ** dbm,
                                                const char *name,
                                                apr_int32_t mode,
                                                apr_fileperms_t perm,
                                                apr_pool_t * cntxt);

/**
 * Close a dbm file previously opened by apr_dbm_open
 * @param dbm The database to close
 * @deffunc void apr_dbm_close(apr_dbm_t *dbm)
 */
APU_DECLARE(void) apr_dbm_close(apr_dbm_t * dbm);

/**
 * Fetch a dbm record value by key
 * @param dbm The database 
 * @param key The key datum to find this record
 * @param value The value datum retrieved for this record
 * @deffunc apr_status_t apr_dbm_fetch(apr_dbm_t *dbm, apr_datum_t key
 */
APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t * dbm,
                                                 apr_datum_t key,
                                                 apr_datum_t * pvalue);
/**
 * Store a dbm record value by key
 * @param dbm The database 
 * @param key The key datum to store this record by
 * @param value The value datum to store in this record
 * @deffunc apr_status_t apr_dbm_store(apr_dbm_t *dbm, apr_datum_t key, 
apr_datum_t value)
 */
APU_DECLARE(apr_status_t) apr_dbm_store(apr_dbm_t * dbm,
                                                 apr_datum_t key,
                                                 apr_datum_t value);

/**
 * Delete a dbm record value by key
 * @param dbm The database 
 * @param key The key datum of the record to delete
 * @deffunc apr_status_t apr_dbm_delete(apr_dbm_t *dbm, apr_datum_t key)
 * @tip It is not an error to delete a non-existent record.
 */
APU_DECLARE(apr_status_t) apr_dbm_delete(apr_dbm_t * dbm,
                                                  apr_datum_t key);

/**
 * Search for a key within the dbm
 * @param dbm The database 
 * @param key The datum describing a key to test
 * @deffunc 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);

/**
 * Retrieve the first record key from a dbm
 * @param dbm The database 
 * @param key The key datum of the first record
 * @deffunc 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);

/**
 * Retrieve the next record key from a dbm
 * @param dbm The database 
 * @param key The key datum of the next record
 * @deffunc 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);

/**
 * Proactively toss any memory associated with the apr_datum_t.
 * @param dbm The database 
 * @param data The datum to free.
 * @deffunc 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);

/**
 * Report more information when an apr_dbm function fails.
 * @param dbm The database
 * @param errcode A DBM-specific value for the error (for logging). If this
 *                isn't needed, it may be NULL.
 * @param errbuf Location to store the error text
 * @param errbufsize The size of the provided buffer
 * @return The errbuf parameter, for convenience.
 * @deffunc const char * apr_dbm_geterror(apr_dbm_t *dbm, int *errcode, char 
*errbuf, apr_size_t errbufsize)
 */
APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t * dbm, int *errcode,
                                              char *errbuf,
                                              apr_size_t errbufsize);

/**
 * If the specified file/path were passed to apr_dbm_open(), 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(apr_pool_t * pool,
                                                 const char *pathname,
                                                 const char **used1,
                                                 const char **used2);

#ifdef __cplusplus
}
#endif

#endif                          /* !APR_DBM_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"

#include "dbm_private.h"

#if APU_USE_DB
#include "apr_dbm_db.h"
/*
 * 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_berkley_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) {
        /* ### need to fix this */
        return APR_OS_START_USEERR + dberr;
    }

    return APR_SUCCESS;
}



/* handle the FIRSTKEY functionality */
static apr_status_t do_firstkey(apr_berkley_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
    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 
This function also returns the 'data'
as well as the key.
*/
static apr_status_t do_nextkey(apr_berkley_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

    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;

    /* ### ignore whatever the DBM said (dbm_said); ask it explicitly */

    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 = 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_berkley_db_t *real_ptr = dbm->file;
    DB *db;

    if (real_ptr) {
        db = real_ptr->bdb;
#if DB_VER == 1
        db->close(db);
#else
        db->close(db, 0);
#endif
        dbm->file = 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_berkley_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_berkley_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_berkley_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_berkley_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_berkley_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_berkley_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)
{
}
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;

    /* assert: errbufsize > 0 */

    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_berkley_db_t *file = apr_palloc(pool, sizeof(apr_berkley_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)->close = apr_dbm_close_db;
    (*pdb)->set_error = apr_dbm_set_error_db;
    (*pdb)->fetch = apr_dbm_fetch_db;
    (*pdb)->store = apr_dbm_store_db;
    (*pdb)->del = apr_dbm_delete_db;
    (*pdb)->exists = apr_dbm_exists_db;
    (*pdb)->firstkey = apr_dbm_firstkey_db;
    (*pdb)->nextkey = apr_dbm_nextkey_db;

    (*pdb)->geterror = apr_dbm_geterror_db;
    (*pdb)->freedatum = apr_dbm_freedatum_noop;
    (*pdb)->datum_cleanup = apr_dbm_datum_cleanup_noop;

#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));

    apr_pool_cleanup_register(pool, pdb, db_cleanup, apr_pool_cleanup_null);

    return APR_SUCCESS;

}
#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"

#include "apu.h"

#include "dbm_private.h"

#if APU_USE_SDBM

#include "apr_sdbm.h"

#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.";
        rv = APR_EGENERAL;      /* ### need something better */
    }

    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)
{

}
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;

    /* assert: errbufsize > 0 */

    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)->close = apr_dbm_close_sdbm;
    (*pdb)->set_error = apr_dbm_set_error_sdbm;
    (*pdb)->fetch = apr_dbm_fetch_sdbm;
    (*pdb)->store = apr_dbm_store_sdbm;
    (*pdb)->del = apr_dbm_delete_sdbm;
    (*pdb)->exists = apr_dbm_exists_sdbm;
    (*pdb)->firstkey = apr_dbm_firstkey_sdbm;
    (*pdb)->nextkey = apr_dbm_nextkey_sdbm;

    (*pdb)->geterror = apr_dbm_geterror_sdbm;
    (*pdb)->freedatum = apr_dbm_freedatum_noop;
    (*pdb)->datum_cleanup = apr_dbm_datum_cleanup_noop;


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

}
#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"
#define APR_WANT_MEMFUNC
#define APR_WANT_STRFUNC
#include "apr_want.h"

#include "apu_select_dbm.h"
#include "apr_dbm.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 "gdbm.h"
#include "gdbmerrno.h"
#endif

#include "dbm_private.h"


/* 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);
#else
    return APR_ENOTAVAIL;
#endif
}

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

APU_DECLARE(apr_status_t) apr_dbm_fetch(apr_dbm_t * dbm, apr_datum_t key,
                                        apr_datum_t * pvalue)
{
    return dbm->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->store(dbm, key, value);
}

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

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

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

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

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


APU_DECLARE(char *) apr_dbm_geterror(apr_dbm_t * dbm, int *errcode,
                                     char *errbuf, apr_size_t errbufsize)
{
    return dbm->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);
#else
    /* default op. no assumptions made */
    fprintf(stderr, "This Database does not implement apr_dbm_get_usednames");
    *used1 = NULL;
    *used2 = NULL;
#endif
}
#ifndef _DBM_PRIVATE_H
#define _DBM_PRIVATE_H 1

/* this is used in a few places to define a noop "function". it is needed
   to stop "no effect" warnings from GCC. */


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


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

         int errcode;
         const char *errmsg;
         apr_status_t      (*set_error) (apr_dbm_t * dbm, apr_status_t 
dbm_said);
         void              (*close) (apr_dbm_t * dbm);
         apr_status_t      (*fetch) (apr_dbm_t * dbm, apr_datum_t key, 
apr_datum_t
                               * pvalue);
         apr_status_t      (*store) (apr_dbm_t * dbm, apr_datum_t key,
                               apr_datum_t value);
         apr_status_t      (*del) (apr_dbm_t * dbm, apr_datum_t key);
         int               (*exists) (apr_dbm_t * dbm, apr_datum_t key);
         apr_status_t      (*firstkey) (apr_dbm_t * dbm, apr_datum_t * pkey);
         apr_status_t      (*nextkey) (apr_dbm_t * dbm, apr_datum_t * pkey);
         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 *);
         void              (*freedatum) (apr_dbm_t * dbm, apr_datum_t data);
};

#endif /* _DBM_PRIVATE_H */

Reply via email to