Logo Search packages:      
Sourcecode: db2 version File versions  Download package

utils.c

/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 1996, 1997, 1998
 *    Sleepycat Software.  All rights reserved.
 */

#include "config.h"

#ifndef lint
static const char sccsid[] = "@(#)utils.c 10.70 (Sleepycat) 12/17/98";
#endif /* not lint */

/*
 * This file is divided up into 4 sets of functions:
 * 1. The dbopen command and its support functions.
 * 2. The dbwidget and dbcursor commands.
 * 3. The db support functions (e.g. get, put, del)
 * 4. The cursor support functions (e.g. get put, del)
 */

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#endif
#include <tcl.h>

#include "db_int.h"
#include "db_page.h"
#include "hash.h"
#include "dbtest.h"
#include "test_ext.h"

/* Internal functions */
int db_del_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int db_get_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int db_getbin_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int db_join_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int db_put_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int db_putbin_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DB *dbp));
int dbc_del_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DBC *dbc));
int dbc_get_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DBC *dbc));
int dbc_getbin_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DBC *dbc));
int dbc_put_cmd __P((Tcl_Interp *interp, int argc, char *argv[], DBC *dbc));
int dbt_from_file __P((Tcl_Interp *interp, char *file, DBT *dbt));
int dbt_to_file __P((Tcl_Interp *interp, char *file, DBT *dbt));
u_int8_t *list_to_numarray __P((Tcl_Interp *, char *));
void set_get_result __P((Tcl_Interp *interp, DBT *dbt));

/*
 * dbopen_cmd --
 *    Implements dbopen for dbtest.  Dbopen creates a widget that
 * implements all the commands found off the DB structure.
 */

#define DBOPEN_USAGE "dbopen file flags mode type [options]\n\toptions:\n\t"

int
dbopen_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      static int db_number = 0;
      static const struct {
            char *str;
            DBTYPE type;
      } list[] = {
            {"DB_UNKNOWN",    DB_UNKNOWN},
            {"db_unknown",    DB_UNKNOWN},
            {"UNKNOWN", DB_UNKNOWN},
            {"unknown", DB_UNKNOWN},
            {"DB_BTREE",      DB_BTREE},
            {"db_btree",      DB_BTREE},
            {"BTREE",   DB_BTREE},
            {"btree",   DB_BTREE},
            {"DB_HASH", DB_HASH},
            {"db_hash", DB_HASH},
            {"HASH",    DB_HASH},
            {"hash",    DB_HASH},
            {"DB_RECNO",      DB_RECNO},
            {"db_recno",      DB_RECNO},
            {"RECNO",   DB_RECNO},
            {"recno",   DB_RECNO},
            { 0 }
      }, *lp;
      DB *dbp;
      DBTYPE type;
      DB_ENV *env;
      DB_INFO *openinfo;
      u_int32_t flags;
      int mode, ret, tclint;
      char dbname[50], *name;

      notused = NULL;

      /* Check number of arguments. */
      USAGE_GE(argc, 5, DBOPEN_USAGE, DO_INFO);

      /* Check flags and mode. */
      if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
            goto usage;
      flags = (u_int32_t)tclint;
      if (Tcl_GetInt(interp, argv[3], &mode) != TCL_OK) {
usage:            Tcl_AppendResult(interp,
                "\nUsage: ", DBOPEN_USAGE, DB_INFO_FLAGS, NULL);
            return (TCL_OK);
      }

      name = strcmp(argv[1], "NULL") == 0 ? NULL : argv[1];

      process_am_options(interp, argc - 5, &argv[5], &openinfo);
      process_env_options(interp, argc - 5, &argv[5], &env);

      /* Figure out type. */
      COMPQUIET(type, DB_HASH);
      for (lp = list; lp->str != NULL; ++lp)
            if (strcmp(argv[4], lp->str) == 0) {
                  type = lp->type;
                  break;
            }
      if (lp->str == NULL) {
            Tcl_SetResult(interp, "Invalid type", TCL_STATIC);
            return (TCL_ERROR);
      }

      if (openinfo == NULL && type != DB_UNKNOWN) {
            Tcl_AppendResult(interp, "Usage: ", DBOPEN_USAGE,
                DB_INFO_FLAGS, NULL);
            return (TCL_ERROR);
      }

      debug_check();

      /* Call dbopen. */
      ret = db_open(name, type, flags, mode, env, openinfo, &dbp);
      if (openinfo && openinfo->re_source)
            free(openinfo->re_source);
      if (openinfo)
            free(openinfo);
      if (ret != 0) {
            Tcl_SetResult(interp, "dbopen: ", TCL_STATIC);
            errno = ret;
            Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
            return (TCL_OK);
      }

      /* Create widget command. */
      /* Create new command name. */
      snprintf(dbname, sizeof(dbname), "db%d", db_number);
      db_number++;

      Tcl_CreateCommand(interp, dbname, dbwidget_cmd, (ClientData)dbp, NULL);
      Tcl_SetResult(interp, dbname, TCL_VOLATILE);
      return (TCL_OK);
}

/*
 * process_am_options --
 *    Read the options in the command line and create a DB_INFO structure
 *    to pass to db_open.
 */
int
process_am_options(interp, argc, argv, openinfo)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB_INFO **openinfo;
{
      DB_INFO *oi;
      int err, tclint;
      char *option;

      COMPQUIET(option, NULL);

      err = TCL_OK;
      oi = (DB_INFO *)calloc(sizeof(DB_INFO), 1);

      while (argc >= 1) {
            if (**argv != '-') {          /* Make sure it's an option */
                  argc--;
                  argv++;
                  continue;
            }
            /* Set option to first character after "-" */
            option = argv[0];
            option++;

            if (argc == 1)
                  break;

            if (strcmp(option, "flags") == 0) {
      /* Contains flags for all access methods */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->flags = (u_int32_t)tclint;
            } else if (strcmp(option, "psize") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->db_pagesize = (size_t)tclint;
            } else if (strcmp(option, "order") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->db_lorder = (int)tclint;
            } else if (strcmp(option, "cachesize") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->db_cachesize = (size_t)tclint;
            } else if (strcmp(option, "minkey") == 0) {
      /* Btree flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->bt_minkey = (u_int32_t)tclint;
            } else if (strcmp(option, "compare") == 0) {
                  /* Not sure how to handle this. */
                  err = TCL_ERROR;
            } else if (strcmp(option, "prefix") == 0) {
                  /* Not sure how to handle this. */
                  err = TCL_ERROR;
            } else if (strcmp(option, "ffactor") == 0) {
      /* Hash flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->h_ffactor = (u_int32_t)tclint;
            } else if (strcmp(option, "nelem") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->h_nelem = (u_int32_t)tclint;
            } else if (strcmp(option, "hash") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  switch (tclint) {
                        case 2: oi->h_hash = __ham_func2; break;
                        case 3: oi->h_hash = __ham_func3; break;
                        case 4: oi->h_hash = __ham_func4; break;
                        case 5: oi->h_hash = __ham_func5; break;
                  }
                  if (oi->h_hash == NULL) {
                        err = TCL_ERROR;
                        break;
                  }
            } else if (strcmp(option, "recdelim") == 0) {
      /* Recno flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->re_delim = (int)tclint;
            } else if (strcmp(option, "recpad") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->re_pad = (int)tclint;
            } else if (strcmp(option, "reclen") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  oi->re_len = (u_int32_t)tclint;
            } else if (strcmp(option, "recsrc") == 0)
                   (void)__os_strdup(argv[1], &oi->re_source);

            argc -= 2;
            argv += 2;
      }
      if (err != TCL_OK) {
            Tcl_AppendResult(interp,
                "\nInvalid ", option, " value: ", argv[1], "\n", NULL);
            free(oi);
            oi = NULL;
      }
      *openinfo = oi;
      return (oi ? 0 : 1);
}

/*
 * process_env_options --
 *    Read the options in the command line and create a DB_ENV structure
 *    to pass to db_open.
 */
int
process_env_options(interp, argc, argv, envinfo)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB_ENV **envinfo;
{
      DB_ENV *env;
      Tcl_CmdInfo info;
      u_int32_t flags;
      int err, nconf, tclint;
      char *option, *db_home, **config;
      u_int8_t *conflicts;

      COMPQUIET(option, NULL);
      err = TCL_OK;
      flags = 0;
      db_home = Tcl_GetVar(interp, "testdir", 0);
      config = NULL;
      conflicts = NULL;

      env = (DB_ENV *)calloc(sizeof(DB_ENV), 1);
      while (argc > 1) {
            if (**argv != '-') {          /* Make sure it's an option */
                  argc--;
                  argv++;
                  continue;
            }
            /* Set option to first character after "-" */
            option = argv[0];
            option++;

            if (argv[1] == NULL || argv[1][0] == '-') {
                  Tcl_SetResult(interp, "Invalid options: ",
                      TCL_STATIC);
                  Tcl_AppendResult(interp, argv[0],
                     "requires parameter", 0);
                  return (TCL_ERROR);
            }

            if (strcmp(option, "dbenv") == 0) {
      /* environment already set up. */
                  if (Tcl_GetCommandInfo(interp, argv[1], &info) == 0) {
                        Tcl_SetResult(interp,
                            "Invalid environment: ", TCL_STATIC);
                        Tcl_AppendResult(interp, argv[1], 0);
                        return (TCL_ERROR);
                  }
                  free(env);
                  *envinfo = (DB_ENV *)info.clientData;
                  return (TCL_OK);
            } else if (strcmp(option, "dbflags") == 0) {
      /* db_appinit parameters */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  flags = (u_int32_t)tclint;
                  /*
                   * Don't specify DB_THREAD if the architecture can't
                   * do spinlocks.
                   */
#ifndef HAVE_SPINLOCKS
                  LF_CLR(DB_THREAD);
#endif
            } else if (strcmp(option, "dbhome") == 0) {
                  db_home = argv[1];
            } else if (strcmp(option, "dbconfig") == 0) {
                  err = Tcl_SplitList(interp, argv[1], &nconf, &config);
                  if (err)
                        break;
            } else if (strcmp(option, "maxlocks") == 0) {
      /* Lock flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->lk_max = (u_int32_t)tclint;
            } else if (strcmp(option, "nmodes") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->lk_modes = (u_int32_t)tclint;
            } else if (strcmp(option, "detect") == 0) {
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->lk_detect = (u_int32_t)tclint;
            } else if (strcmp(option, "conflicts") == 0) {
                  conflicts = list_to_numarray(interp, argv[1]);
                  if (conflicts == NULL)
                        break;
                  env->lk_conflicts = conflicts;
            } else if (strcmp(option, "maxsize") == 0) {
      /* Log flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->lg_max = (u_int32_t)tclint;
            } else if (strcmp(option, "cachesize") == 0) {
      /* Mpool flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->mp_size = (size_t)tclint;
            } else if (strcmp(option, "maxtxns") == 0) {
      /* Txn flags */
                  if ((err =
                      Tcl_GetInt(interp, argv[1], &tclint)) != TCL_OK)
                        break;
                  env->tx_max = (u_int32_t)tclint;
            } else if (strcmp(option, "rinit") == 0) {
      /* Region init */
                  if ((err = db_value_set(1, DB_REGION_INIT)) != 0) {
                        if (err == EINVAL) {
                              Tcl_SetResult(interp,
                                  "EINVAL", TCL_STATIC);
                              return (TCL_ERROR);
                        }
                        Tcl_SetResult(interp,
                            "env/rinit:", TCL_STATIC);
                        errno = err;
                        Tcl_AppendResult(interp,
                            Tcl_PosixError(interp), 0);
                        return (TCL_ERROR);
                  }
            } else if (strcmp(option, "shmem") == 0) {
      /* Shared memory specification */
                  if (strcmp(argv[1], "anon") == 0) {
                        if ((err =
                            db_value_set(1, DB_REGION_ANON)) != 0) {
                              if (err == EINVAL) {
                                    Tcl_SetResult(interp,
                                        "EINVAL", TCL_STATIC);
                                    return (TCL_ERROR);
                              }
                              Tcl_SetResult(interp,
                                  "env/shmem:", TCL_STATIC);
                              errno = err;
                              Tcl_AppendResult(interp,
                                  Tcl_PosixError(interp), 0);
                              return (TCL_ERROR);
                        }
                  } else if (strcmp(argv[1], "named") == 0) {
                        if ((err =
                            db_value_set(1, DB_REGION_NAME)) != 0) {
                              if (err == EINVAL) {
                                    Tcl_SetResult(interp,
                                        "EINVAL", TCL_STATIC);
                                    return (TCL_ERROR);
                              }
                              Tcl_SetResult(interp,
                                  "env/shmem:", TCL_STATIC);
                              errno = err;
                              Tcl_AppendResult(interp,
                                  Tcl_PosixError(interp), 0);
                              return (TCL_ERROR);
                        }
                  } else {
                        Tcl_SetResult(interp,
                            "Invalid shmem option", TCL_STATIC);
                        Tcl_AppendResult(interp, argv[1], NULL);
                        return (TCL_OK);
                  }
            }

            argc -= 2;
            argv += 2;
      }
      if (err != TCL_OK) {
            Tcl_AppendResult(interp, "\nInvalid ", option, " value: ",
                argv[1], "\n", NULL);
            if (conflicts != NULL)
                  free(conflicts);
            free(env);
            env = NULL;
      }

      /*
       * Set up error stuff.
       */
      if (env) {
            env->db_errfile = stderr;
            env->db_errpfx = "dbtest";
            env->db_errcall = NULL;
            env->db_verbose = 0;

            if ((errno = db_appinit(db_home, config, env, flags)) != 0) {
                  free(env);
                  env = NULL;
            }
      }

      if (config)
            FREE_TCL(config);

      *envinfo = env;
      return (env ? 0 : 1);
}

/*
 * dbwidget --
 *    Since dbopen creates a widget, we need a command that then
 * handles all the widget commands.  This is that command.  If we
 * ever add new "methods" we add new widget commands here.
 */
#define DBWIDGET_USAGE "dbN option ?arg arg ...?"
#define DBCLOSE_USAGE "dbN close"
#define DBCURS_USAGE "dbN cursor txn [flags]"
#define DBFD_USAGE "dbN fd"
#define DBSYNC_USAGE "dbN sync flags"
#define     DBLOCKER_USAGE "dbN locker"

int
dbwidget_cmd(cd_dbp, interp, argc, argv)
      ClientData cd_dbp;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      static int curs_id = 0;
      DB *dbp;
      DBC *cursor;
      DB_ENV *env;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      u_int32_t flags;
      int fd, ret, tclint;
      char cursname[128];
      u_int8_t *conflicts;

      dbp = (DB *)cd_dbp;

      USAGE_GE(argc, 2, DBWIDGET_USAGE, 0);

      Tcl_SetResult(interp, "0", TCL_STATIC);

      if (strcmp(argv[1], "close") == 0) {
            USAGE(argc, 2, DBCLOSE_USAGE, 0);
            env = dbp->dbenv;
            debug_check();
#ifdef STATISTICS
            if (dbp->stat != NULL)
                  (void)dbp->stat(dbp, stdout);
#endif
            ret = dbp->close(dbp, 0);
            if (env && !F_ISSET(env, DB_ENV_STANDALONE)) {
                  (void)db_appexit(env);
                  conflicts = (u_int8_t *)env->lk_conflicts;
                  if (conflicts != NULL)
                        free(conflicts);
                  free(env);
            }
            (void)Tcl_DeleteCommand(interp, argv[0]);
            if (ret < 0)
                  Tcl_SetResult(interp, "1", TCL_STATIC);
            else if (ret > 0) {
                  Tcl_SetResult(interp, "db_close:", TCL_STATIC);
                  errno = ret;
                  Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
            } else
                  Tcl_SetResult(interp, "0", TCL_STATIC);
            return (TCL_OK);
      } else if (strcmp(argv[1], "cursor") == 0) {
            USAGE_GE(argc, 3, DBCURS_USAGE, 0);
            snprintf(cursname,
                sizeof(cursname), "%s.cursor%d", argv[0], curs_id);
            curs_id++;
            if (argv[2][0] == '0' && argv[2][1] == '\0')
                  txnid = NULL;
            else {
                  if (Tcl_GetCommandInfo(interp, argv[2], &info) == 0) {
                        Tcl_SetResult(interp,
                            "db_del: Invalid argument ", TCL_STATIC);
                        Tcl_AppendResult(interp, argv[2],
                            " not a transaction.", 0);
                        return (TCL_ERROR);
                  }
                  txnid = (DB_TXN *)info.clientData;
            }
            debug_check();
            if (argc == 4) {
                  if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                        return (TCL_ERROR);
                  flags = (u_int32_t)tclint;
            } else
                  flags = 0;
            if ((ret = dbp->cursor(dbp, txnid, &cursor, flags)) == 0) {
                  Tcl_CreateCommand(interp, cursname, dbcursor_cmd,
                      (ClientData)cursor, NULL);
                  Tcl_SetResult(interp, cursname, TCL_VOLATILE);
            } else {
                  Tcl_SetResult(interp, "db_cursor:", TCL_STATIC);
                  errno = ret;
                  Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
            }
            return (TCL_OK);
      } else if (strcmp(argv[1], "del") == 0) {
            return (db_del_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "fd") == 0) {
            USAGE(argc, 2, DBFD_USAGE, 0);
            Tcl_ResetResult(interp);
            debug_check();
            (void)dbp->fd(dbp, &fd);
            /*
             * !!!
             * Safe: interp->result is guaranteed to be at least 200 bytes.
             */
            sprintf(interp->result, "%d", fd);
            return (TCL_OK);
      } else if (strcmp(argv[1], "get") == 0) {
            return (db_get_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "bget") == 0) {
            return (db_get_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "getn") == 0) {
            return (db_get_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "getbin") == 0) {
            return (db_getbin_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "getbinkey") == 0) {
            return (db_getbin_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "join") == 0) {
            return (db_join_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "put") == 0) {
            return (db_put_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "putn") == 0) {
            return (db_put_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "putbin") == 0) {
            return (db_putbin_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "putbinkey") == 0) {
            return (db_putbin_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "put0") == 0) {
            return (db_put_cmd(interp, argc, argv, dbp));
      } else if (strcmp(argv[1], "sync") == 0) {
            USAGE(argc, 3, DBSYNC_USAGE, 0);
            if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            flags = (u_int32_t)tclint;
            debug_check();
            if ((ret = dbp->sync(dbp, flags)) < 0)
                  Tcl_SetResult(interp, "1", TCL_STATIC);
            else if (ret > 0) {
                  Tcl_SetResult(interp, "db_sync:", TCL_STATIC);
                  errno = ret;
                  Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
            } else
                  Tcl_SetResult(interp, "0", TCL_STATIC);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, DBWIDGET_USAGE, TCL_STATIC);
            return (TCL_ERROR);
      }
}

#define DBCURSOR_USAGE "dbN.cursorM ?arg arg ...?"
#define DBCCLOSE_USAGE "dbN.cursorM close"
int
dbcursor_cmd(cd_dbc, interp, argc, argv)
      ClientData cd_dbc;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      DBC *dbc;

      dbc = (DBC *)cd_dbc;
      Tcl_SetResult(interp, "0", TCL_STATIC);

      if (strcmp(argv[1], "close") == 0) {
            USAGE(argc, 2, DBCCLOSE_USAGE, 0);
            debug_check();
            (void)dbc->c_close(dbc);
            return (Tcl_DeleteCommand(interp, argv[0]));
      } else if (strcmp(argv[1], "del") == 0) {
            return (dbc_del_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "get") == 0) {
            return (dbc_get_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "bget") == 0) {
            return (dbc_get_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "getn") == 0) {
            return (dbc_get_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "getbin") == 0) {
            return (dbc_getbin_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "getbinkey") == 0) {
            return (dbc_getbin_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "put") == 0) {
            return (dbc_put_cmd(interp, argc, argv, dbc));
      } else if (strcmp(argv[1], "putn") == 0) {
            return (dbc_put_cmd(interp, argc, argv, dbc));
      } else {
            Tcl_SetResult(interp, DBCURSOR_USAGE, TCL_STATIC);
            return (TCL_ERROR);
      }
      /* NOTREACHED */
}

/* Widget support commands. */

#define DBDEL_USAGE "dbN del txn key flags"
int
db_del_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      DBT key;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      db_recno_t rkey;
      u_int32_t flags;
      int ret, tclint;

      USAGE(argc, 5, DBDEL_USAGE, 0);

      if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBDEL_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (dbp->type == DB_RECNO) {
            if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            rkey = (db_recno_t)tclint;
            key.data = &rkey;
            key.size = sizeof(db_recno_t);
      } else {
            key.data = argv[3];
            key.size = strlen(argv[3]) + 1;           /* Add NULL on end. */
      }

      if (argv[2][0] == '0' && argv[2][1] == '\0')
            txnid = NULL;
      else {
            if (Tcl_GetCommandInfo(interp, argv[2], &info) == 0) {
                  Tcl_SetResult(interp,
                      "db_del: Invalid argument ", TCL_STATIC);
                  Tcl_AppendResult(interp, argv[2],
                      " not a transaction.", 0);
                  return (TCL_ERROR);
            }
            txnid = (DB_TXN *)info.clientData;
      }

      debug_check();

      if ((ret = dbp->del(dbp, txnid, &key, flags)) == 0)
            return (TCL_OK);
      else if (ret == DB_NOTFOUND) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Key ", argv[3], " not found.", NULL);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

#define DBGET_USAGE "dbN get txn key flags [beg len]"
#define DBBGET_USAGE "dbN get txn key data flags [beg len]"
int
db_get_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      DBT data, key;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      db_recno_t ikey;
      u_int32_t flags;
      int arg_off, ret, tclint;

      if (strcmp(argv[1], "bget") == 0) {
            USAGE(argc, 6, DBBGET_USAGE, 0);
            arg_off = 5;
      } else {
            USAGE_GE(argc, 5, DBGET_USAGE, 0);
            arg_off = 4;
      }

      if (Tcl_GetInt(interp, argv[arg_off], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBGET_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (dbp->type == DB_RECNO || strcmp(argv[1], "getn") == 0) {
            if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            ikey = (db_recno_t)tclint;
            key.data = &ikey;
            key.size = sizeof(db_recno_t);
      } else {
            key.data = argv[3];
            key.size = strlen(argv[3]) + 1;     /* Add Null on end */
      }

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

      /*
       * If we have "too many" arguments, check for a partial retrieval.
       */
      if (argc > arg_off + 3 &&
          strcmp(argv[arg_off + 1], "DB_DBT_PARTIAL") == 0) {
            /* We have a partial */
            USAGE(argc, arg_off + 4, DBGET_USAGE, 0);
            if (Tcl_GetInt(interp, argv[arg_off + 2], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.doff = (size_t)tclint;
            if (Tcl_GetInt(interp, argv[arg_off + 3], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.dlen = (size_t)tclint;
            data.flags = DB_DBT_PARTIAL;
            flags = 0;
      }
      if (flags == DB_GET_BOTH) {
            data.data = argv[4];
            data.size = strlen(argv[4]) + 1;
      }

      if (argv[2][0] == '0' && argv[2][1] == '\0')
            txnid = NULL;
      else {
            if (Tcl_GetCommandInfo(interp, argv[2], &info) == 0) {
                  Tcl_SetResult(interp,
                      "db_get: Invalid argument ", TCL_STATIC);
                  Tcl_AppendResult(interp, argv[2],
                      " not a transaction.", 0);
                  return (TCL_ERROR);
            }
            txnid = (DB_TXN *)info.clientData;
      }

      debug_check();

      if (F_ISSET(dbp, DB_AM_THREAD))
            F_SET(&data, DB_DBT_MALLOC);
      if ((ret = dbp->get(dbp, txnid, &key, &data, flags)) == 0) {
            Tcl_ResetResult(interp);
            set_get_result(interp, &data);
            if (F_ISSET(&data, DB_DBT_MALLOC))
                  free(data.data);
            return (TCL_OK);
      } else if (ret == DB_NOTFOUND) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Key ", argv[3], " not found.", NULL);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

/*
 * Used for getting and verifying the data associated with a binary
 * data field in the database.  These are big and tend to crash tcl.
 * We do the handling of the big stuff in C.  The path is the file
 * into which to write the large key/data element.
 */
#define DBGETBIN_USAGE "dbN getbin path txn key flags"
int
db_getbin_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      DBT data, key;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      db_recno_t rkey;
      u_int32_t flags;
      int ret, tclint;

      USAGE(argc, 6, DBGETBIN_USAGE, 0);

      if (Tcl_GetInt(interp, argv[5], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBGET_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (strcmp(argv[1], "getbinkey") == 0) {
            if (dbt_from_file(interp, argv[4], &key) != TCL_OK)
                  return (TCL_ERROR);
      } else if (dbp->type == DB_RECNO) {
            if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            rkey = (db_recno_t)tclint;
            key.data = &rkey;
            key.size = sizeof(db_recno_t);
      } else {
            key.data = argv[4];
            key.size = strlen(argv[4]) + 1;     /* Add Null on end */
      }

      memset(&data, 0, sizeof(data));
      if (strcmp(argv[1], "getbinkey") != 0)
            F_SET(&data, DB_DBT_MALLOC);

      if (argv[3][0] == '0' && argv[3][1] == '\0')
            txnid = NULL;
      else {
            if (Tcl_GetCommandInfo(interp, argv[3], &info) == 0) {
                  Tcl_SetResult(interp,
                      "db_getbin: Invalid argument ", TCL_STATIC);
                  Tcl_AppendResult(interp, argv[3],
                      " not a transaction.", 0);
                  return (TCL_ERROR);
            }
            txnid = (DB_TXN *)info.clientData;
      }

      debug_check();

      if ((ret = dbp->get(dbp, txnid, &key, &data, flags)) == DB_NOTFOUND) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Key ", argv[3], " not found.", NULL);
            return (TCL_OK);
      } else if (ret != 0) {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }

      /* Got item; write it to file. */
      if (strcmp(argv[1], "getbinkey") == 0) {
            free(key.data);
            Tcl_SetResult(interp, data.data, TCL_VOLATILE);
      } else {
            if (dbt_to_file(interp, argv[2], &data) != TCL_OK)
                  return (TCL_ERROR);
            Tcl_SetResult(interp, argv[2], TCL_VOLATILE);
      }

      return (TCL_OK);
}

#define DBPUT_USAGE "dbN put txn key data flags"
#define DBPPUT_USAGE "dbN put txn key data flags doff dlen"
int
db_put_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      DBT data, key;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      db_recno_t ikey;
      u_int32_t flags;
      int ret, tclint;
      char numbuf[16];

      USAGE_GE(argc, 6, DBPUT_USAGE, 0);

      if (Tcl_GetInt(interp, argv[5], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBPUT_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (strcmp(argv[1], "putn") == 0 || dbp->type == DB_RECNO) {
            if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            ikey = (db_recno_t)tclint;
            key.data = &ikey;
            key.size = sizeof(db_recno_t);
      } else {
            key.data = argv[3];
            key.size = strlen(argv[3]) + 1;     /* Add Null on end */
      }

      memset(&data, 0, sizeof(data));
      data.data = argv[4];
      data.size = strlen(argv[4]) + (strcmp(argv[1], "put0") == 0 ? 0 : 1);

      /*
       * If the partial flag is set, then arguments 6 and 7 are the
       * offset and length respectively.
       */
      if (argc > 6 && strcmp(argv[6], "DB_DBT_PARTIAL") == 0) {
            USAGE_GE(argc, 9, DBPPUT_USAGE, 0);
            if (Tcl_GetInt(interp, argv[7], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.doff = (size_t)tclint;
            if (Tcl_GetInt(interp, argv[8], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.dlen = (size_t)tclint;
            data.flags = DB_DBT_PARTIAL;
            data.size--;                  /* Remove the NULL */
            flags = 0;
      }

      if (argv[2][0] == '0' && argv[2][1] == '\0')
            txnid = NULL;
      else {
            if (Tcl_GetCommandInfo(interp, argv[2], &info) == 0) {
                  Tcl_SetResult(interp,
                      "db_put: Invalid argument ", TCL_STATIC);
                  Tcl_AppendResult(interp, argv[2],
                      " not a transaction.", 0);
                  return (TCL_ERROR);
            }
            txnid = (DB_TXN *)info.clientData;
      }
      debug_check();

      if ((ret = dbp->put(dbp, txnid, &key, &data, flags)) == 0) {
            if (LF_ISSET(DB_APPEND)) {
                  if (key.size != sizeof(db_recno_t)) {
                        Tcl_SetResult(interp,
                            "Error: key not integer", TCL_STATIC);
                        return (TCL_ERROR);
                  }
                  memcpy(&ikey, key.data, sizeof(db_recno_t));
                  snprintf(numbuf, sizeof(numbuf), "%ld", (long)ikey);
                  Tcl_SetResult(interp, numbuf, TCL_VOLATILE);
            } else {
                  Tcl_SetResult(interp, "0", TCL_STATIC);
            }
      } else if (ret < 0) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Error on put of key ",
                argv[3], " either not found or bad flag values.", NULL);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
      }
      return (TCL_OK);
}

/*
 * Used for putting very large data items into a db file.  Instead of
 * passing the data in a DB, we'll pass a file name and read the data
 * from the file and put it in the db.  This can be checked using the
 * getbin command.
 */
#define DBPUTBIN_USAGE "dbN put txn key data flags"
int
db_putbin_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      DBT data, key;
      DB_TXN *txnid;
      Tcl_CmdInfo info;
      db_recno_t rkey;
      u_int32_t flags;
      int ret, tclint;
      void *p;

      USAGE(argc, 6, DBPUTBIN_USAGE, 0);

      if (Tcl_GetInt(interp, argv[5], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBPUT_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      memset(&data, 0, sizeof(data));
      if (strcmp(argv[1], "putbinkey") == 0) {
            /* Get data from file. */
            if (dbt_from_file(interp, argv[3], &key) != TCL_OK)
                  return (TCL_ERROR);
            data.data = argv[4];
            data.size = strlen(argv[4]) + 1;    /* Add Null on end */
            p = key.data;
      } else {
            if (dbt_from_file(interp, argv[4], &data) != TCL_OK)
                  return (TCL_ERROR);
            p = data.data;

            if (dbp->type == DB_RECNO) {
                  if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                        return (TCL_ERROR);
                  rkey = (db_recno_t)tclint;
                  key.data = &rkey;
                  key.size = sizeof(db_recno_t);
            } else {
                  key.data = argv[3];
                  key.size = strlen(argv[3]) + 1;     /* Add Null on end */
            }
      }

      if (argv[2][0] == '0' && argv[2][1] == '\0')
            txnid = NULL;
      else {
            if (Tcl_GetCommandInfo(interp, argv[2], &info) == 0) {
                  Tcl_SetResult(interp,
                      "db_putbin: Invalid argument ", TCL_STATIC);
                  Tcl_AppendResult(interp, argv[2],
                      " not a transaction.", 0);
                  return (TCL_ERROR);
            }
            txnid = (DB_TXN *)info.clientData;
      }
      debug_check();

      ret = dbp->put(dbp, txnid, &key, &data, flags);
      free(p);

      if (ret == 0)
            return (TCL_OK);
      else if (ret < 0) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Key ", argv[3], " not found.", NULL);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

/* Cursor support commands. */

#define DBCDEL_USAGE "cursorN del flags"
int
dbc_del_cmd(interp, argc, argv, dbc)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DBC *dbc;
{
      u_int32_t flags;
      int ret, tclint;

      USAGE(argc, 3, DBCDEL_USAGE, 0);

      if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBCDEL_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      debug_check();

      if ((ret = dbc->c_del(dbc, flags)) == 0)
            return (TCL_OK);
      else if (ret < 0) {
            Tcl_SetResult(interp, "Uninitialized Cursor", TCL_STATIC);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

#define DBCGET_USAGE "cursorN get key flags [beg len]"
#define DBCBGET_USAGE "cursorN get key data flags [beg len]"
int
dbc_get_cmd(interp, argc, argv, dbc)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DBC *dbc;
{
      DBT data, key;
      db_recno_t rkey;
      u_int32_t flags;
      int arg_off, ret, tclint;
      char numbuf[16];

      if (strcmp(argv[1], "bget") == 0) {
            USAGE(argc, 5, DBCBGET_USAGE, 0);
            arg_off = 4;
      } else {
            USAGE_GE(argc, 4, DBCGET_USAGE, 0);
            arg_off = 3;
      }

      if (Tcl_GetInt(interp, argv[arg_off], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBCGET_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (dbc->dbp->type == DB_RECNO || strcmp(argv[1], "getn") == 0) {
            if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            rkey = (db_recno_t)tclint;
            key.data = &rkey;
            key.size = sizeof(db_recno_t);
      } else {
            key.data = argv[2];
            key.size = strlen(argv[2]) + 1;     /* Add Null on end */
      }

      memset(&data, 0, sizeof(data));
      if (argc > arg_off + 3 &&
          strcmp(argv[arg_off + 1], "DB_DBT_PARTIAL") == 0) {
            /* We have a partial */
            USAGE(argc, arg_off + 4, DBGET_USAGE, 0);
            if (Tcl_GetInt(interp, argv[arg_off + 2], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.doff = (size_t)tclint;
            if (Tcl_GetInt(interp, argv[arg_off + 3], &tclint) != TCL_OK)
                  return (TCL_ERROR);
            data.dlen = (size_t)tclint;
            data.flags = DB_DBT_PARTIAL;
            flags = 0;
      }

      if (flags == DB_GET_BOTH) {
            data.data = argv[3];
            data.size = strlen(argv[3]) + 1;
      }

      debug_check();

      if (F_ISSET(dbc->dbp, DB_AM_THREAD)) {
            F_SET(&data, DB_DBT_MALLOC);
            switch(flags) {
            case DB_FIRST:
            case DB_LAST:
            case DB_NEXT:
            case DB_PREV:
            case DB_CURRENT:
            case DB_SET_RANGE:
            case DB_SET_RECNO:
            case DB_GET_RECNO:
                  F_SET(&key, DB_DBT_MALLOC);
                  break;
            /* case DB_SET: Do nothing */
            /* case DB_GET_BOTH: Do nothing */
            }
      }
      if ((ret = dbc->c_get(dbc, &key, &data, flags)) == 0) {
            if (dbc->dbp->type == DB_RECNO) {
                  if (key.size != sizeof(db_recno_t)) {
                        Tcl_SetResult(interp,
                            "Error: key not integer", TCL_STATIC);
                        if (F_ISSET(&data, DB_DBT_MALLOC))
                              free(&data.data);
                        if (F_ISSET(&key, DB_DBT_MALLOC))
                              free(&key.data);
                        return (TCL_ERROR);
                  }
                  memcpy(&rkey, key.data, sizeof(db_recno_t));
                  snprintf(numbuf, sizeof(numbuf), "%ld", (long)rkey);
                  Tcl_SetResult(interp, numbuf, TCL_VOLATILE);
            } else
                  Tcl_SetResult(interp, key.data, TCL_VOLATILE);

            if ((flags & DB_OPFLAGS_MASK) != DB_JOIN_ITEM) {
                  Tcl_AppendResult(interp, " {", NULL);
                  set_get_result(interp, &data);
                  Tcl_AppendResult(interp, "} ", NULL);
            }
            if (F_ISSET(&data, DB_DBT_MALLOC))
                  free(&data.data);
            if (F_ISSET(&key, DB_DBT_MALLOC))
                  free(&key.data);
            return (TCL_OK);
      } else if (ret < 0) {   /* End/Beginning of file. */
            Tcl_ResetResult(interp);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

#define DBCGETBIN_USAGE "cursorN getbin file key flags"
int
dbc_getbin_cmd(interp, argc, argv, dbc)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DBC *dbc;
{
      DBT data, key, *dbt;
      db_recno_t rkey;
      u_int32_t flags;
      int ret, tclint;
      char nbuf[32];

      USAGE(argc, 5, DBCGET_USAGE, 0);

      if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBCGET_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      memset(&key, 0, sizeof(key));
      if (flags == DB_SET || flags == DB_KEYFIRST || flags == DB_KEYLAST)
            if (strcmp(argv[1], "getbinkey") == 0) {
                  if (dbt_from_file(interp, argv[3], &key) != TCL_OK)
                        return (TCL_ERROR);
            } else if (dbc->dbp->type == DB_RECNO) {
                  if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
                        return (TCL_ERROR);
                  rkey = (db_recno_t)tclint;
                  key.data = &rkey;
                  key.size = sizeof(db_recno_t);
            } else {
                  key.data = argv[3];
                  key.size = strlen(argv[3]) + 1;     /* Add Null on end */
            }

      memset(&data, 0, sizeof(data));
      if (strcmp(argv[1], "getbinkey") != 0 && dbc->dbp->type != DB_RECNO)
            F_SET(&data, DB_DBT_MALLOC);

      debug_check();

      ret = dbc->c_get(dbc, &key, &data, flags);
      if (ret < 0) {    /* End/Beginning of file. */
            Tcl_ResetResult(interp);
            return (TCL_OK);
      } else if (ret != 0) {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }

      /* Got key; write it or its data to a file. */
      if (strcmp(argv[1], "getbinkey") == 0) {
            dbt = &key;
            Tcl_SetResult(interp, data.data, TCL_VOLATILE);
      } else if (dbc->dbp->type == DB_RECNO) {
            dbt = &data;
            memcpy(&rkey, key.data, sizeof(db_recno_t));
            snprintf(nbuf, sizeof(nbuf), "%ld", (long)rkey);
            Tcl_SetResult(interp, nbuf, TCL_VOLATILE);
      } else {
            dbt = &data;
            Tcl_SetResult(interp, key.data, TCL_VOLATILE);
      }

      if (dbt_to_file(interp, argv[2], dbt) != TCL_OK)
            return (TCL_ERROR);

      Tcl_AppendElement(interp, argv[2]);
      return (TCL_OK);
}

#define DBCPUT_USAGE "cursorN put key data flags"
int
dbc_put_cmd(interp, argc, argv, dbc)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DBC *dbc;
{
      DBT data, key;
      db_recno_t ikey;
      u_int32_t flags;
      int ret, tclint;

      USAGE(argc, 5, DBCPUT_USAGE, 0);

      if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK) {
            Tcl_AppendResult(interp, "\n", DBCPUT_USAGE, NULL);
            return (TCL_ERROR);
      }
      flags = (u_int32_t)tclint;

      /*
       * If this is a DB_CURRENT, we should never look at the key, so
       * send it a NULL.
       */
      memset(&key, 0, sizeof(key));
      if (flags != DB_CURRENT)
            if (strcmp(argv[1], "putn") == 0 ||
                dbc->dbp->type == DB_RECNO) {
                  if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
                        return (TCL_ERROR);
                  ikey = (db_recno_t)tclint;
                  key.data = &ikey;
                  key.size = sizeof(db_recno_t);
            } else {
                  key.data = argv[2];
                  key.size = strlen(argv[2]) + 1;     /* Add Null on end */
            }

      memset(&data, 0, sizeof(data));
      data.data = argv[3];
      data.size = strlen(argv[3]) + 1;

      debug_check();

      if ((ret = dbc->c_put(dbc, &key, &data, flags)) == 0)
            return (TCL_OK);
      else if (ret < 0) {
            Tcl_ResetResult(interp);
            Tcl_AppendResult(interp, "Key ", argv[2], " not found.", NULL);
            return (TCL_OK);
      } else {
            Tcl_SetResult(interp, "-1", TCL_STATIC);
            return (TCL_OK);
      }
}

u_int8_t *
list_to_numarray(interp, str)
      Tcl_Interp *interp;
      char *str;
{
      int argc, i, tmp;
      u_int8_t *nums, *np;
      char **argv, **ap;

      if (Tcl_SplitList(interp, str, &argc, &argv) != TCL_OK)
            return (NULL);
      if ((nums = (u_int8_t *)calloc(argc, sizeof(u_int8_t))) == NULL) {
            Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
            return (NULL);
      }

      for (np = nums, ap = argv, i = 0; i < argc; i++, ap++, np++) {
            if (Tcl_GetInt(interp, *ap, &tmp) != TCL_OK) {
                  free (nums);
                  return (NULL);
            }
            *np = (u_int8_t)tmp;          /* XXX: Possible overflow. */
      }
      FREE_TCL(argv);
      return (nums);
}

#define STAMP_USAGE "timestamp [-r]"
int
stamp_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      static time_t start;
      struct tm *tp;
      time_t elapsed, now;
      static char buf[25];

      notused = NULL;

      USAGE_GE(argc, 1, STAMP_USAGE, 0);
      (void)time(&now);
      if (now == (time_t)-1)
            goto err;
      if (argc > 1 && strcmp(argv[1], "-r") == 0) {
            snprintf(buf, sizeof(buf), "%lu", (u_long)now);
            Tcl_SetResult(interp, buf, TCL_STATIC);
            return (TCL_OK);
      }
      if ((tp = localtime(&now)) == NULL)
            goto err;

      if (start == 0)
            start = now;
      elapsed = now - start;
      snprintf(buf, sizeof(buf), "%02d:%02d:%02d (%02d:%02d:%02d)",
          tp->tm_hour, tp->tm_min, tp->tm_sec, (int)(elapsed / 3600),
          (int)((elapsed % 3600) / 60), (int)(((elapsed % 3600) % 60)));
      start = now;

      Tcl_SetResult(interp, buf, TCL_STATIC);
      return (TCL_OK);

err:  Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
      return (TCL_ERROR);
}

int debug_stop;                     /* Stop on each iteration. */

void
debug_check()
{
      if (debug_on == 0)
            return;

      if (debug_print != 0) {
            printf("\r%6d:", debug_on);
            fflush(stdout);
      }

      if (debug_on++ == debug_test || debug_stop)
            __db_loadme();
}

int
dbt_from_file(interp, file, dbt)
      Tcl_Interp *interp;
      char *file;
      DBT *dbt;
{
      size_t len, size;
      ssize_t nr;
      u_int32_t mbytes, bytes;
      int fd;

      /* Get data from file. */
      fd = -1;
      len = strlen(file) + 1;
      if ((errno = __db_open(file, DB_RDONLY, DB_RDONLY, 0, &fd)) != 0)
            goto err;
      if ((errno = __os_ioinfo(file, fd, &mbytes, &bytes, NULL)) != 0)
            goto err;
      size = mbytes * MEGABYTE + bytes;
      if ((dbt->data = (void *)malloc(size + len)) == NULL)
            goto err;
      if ((errno =
          __os_read(fd, ((u_int8_t *)dbt->data) + len, size, &nr)) != 0)
            goto err;
      if (nr != (ssize_t)size) {
            errno = EIO;
            goto err;
      }
      if ((errno =__os_close(fd)) != 0) {
err:        if (fd != -1)
                  close(fd);
            Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
            return (TCL_ERROR);
      }
      strcpy((char *)(dbt->data), file);
      dbt->size = size + (u_int32_t)len;
      dbt->flags = 0;
      return (TCL_OK);
}

/*
 * file is the file we are creating.  ofile is the original file
 * name so we know how many characters to drop off the end.
 */
int
dbt_to_file(interp, file, dbt)
      Tcl_Interp *interp;
      char *file;
      DBT *dbt;
{
      size_t len;
      ssize_t nw;
      int fd;
      char *p;

      /* Got key; write it to file. */
      for (len = 1, p = (char *)(dbt->data); *p != '\0'; len++, p++)
            ;
      p++;

      fd = -1;
      if ((errno = __db_open(file, DB_CREATE | DB_TRUNCATE,
          DB_CREATE | DB_TRUNCATE, 0644, &fd)) != 0 ||
          (errno = __os_write(fd, p, dbt->size - len, &nw) != 0) ||
          nw != (ssize_t)(dbt->size - len) ||
          (errno = __os_close(fd)) != 0) {
            if (errno == 0)
                  errno = EIO;
            if (fd == -1)
                  (void)__os_close(fd);
            Tcl_SetResult(interp, Tcl_PosixError(interp), TCL_STATIC);
            return (TCL_ERROR);
      }
      if (F_ISSET(dbt, DB_DBT_MALLOC))
            free(dbt->data);
      return (TCL_OK);
}

void
set_get_result(interp, dbt)
      Tcl_Interp *interp;
      DBT *dbt;
{
      size_t i, len;
      u_int8_t *p;
      char numbuf[32], sprbuf[128], *outbuf;

      for (i = 0, p = dbt->data; i < dbt->size && *p == '\0'; i++, p++)
            ;
      /*
       * If this is a partial get, we need to make sure that the last
       * character is a NUL so that tcl can handle it.
       */
      if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
            if (dbt->size == 0)
                  ((char *)dbt->data)[0] = '\0';
            else
                  ((char *)dbt->data)[dbt->size - 1] = '\0';
      }

      if (i == 0) {
            if (((u_int8_t *)dbt->data)[dbt->size - 1] != '\0') {
                  outbuf = (char *)malloc(dbt->size + 1);
                  memcpy(outbuf, dbt->data, dbt->size);
                  outbuf[dbt->size] = '\0';
            } else
                  outbuf = dbt->data;
            Tcl_AppendResult(interp, outbuf, NULL);
            if (outbuf != dbt->data)
                  free(outbuf);
      } else {
            snprintf(numbuf, sizeof(numbuf), "%lu", (u_long)i);
            snprintf(sprbuf, sizeof(sprbuf), " %%.%ds", dbt->size - i);
            len = dbt->size - i + 5;
            if ((outbuf = (char *)malloc(len)) != NULL) {
                  snprintf(outbuf, len, sprbuf, p);
                  Tcl_AppendResult(interp, numbuf, outbuf, NULL);
                  free(outbuf);
            }
      }
}

#define SRAND_USAGE "srand seed"
int
srand_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      int ival;

      notused = NULL;
      USAGE(argc, 2, SRAND_USAGE, 0);
      if (Tcl_GetInt(interp, argv[1], &ival) != TCL_OK)
            return (TCL_ERROR);

      srand((u_int)ival);
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return (TCL_OK);
}

#define RAND_USAGE "rand"
int
rand_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      char retbuf[50];

      notused = NULL;
      argv = NULL;
      USAGE(argc, 1, RAND_USAGE, 0);

      snprintf(retbuf, sizeof(retbuf), "%ld", (long)rand());
      Tcl_SetResult(interp, retbuf, TCL_VOLATILE);
      return (TCL_OK);
}

#define RANDOMINT_USAGE "random_int lo hi"
int
randomint_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      long t;
      int lo, hi, ret;
      char retbuf[50];

      notused = NULL;
      USAGE(argc, 3, RANDOMINT_USAGE, 0);
      if (Tcl_GetInt(interp, argv[1], &lo) != TCL_OK ||
          Tcl_GetInt(interp, argv[2], &hi) != TCL_OK)
            return (TCL_ERROR);

#ifndef     RAND_MAX
#define     RAND_MAX    0x7fffffff
#endif
      t = rand();
      if (t > RAND_MAX)
            printf("Max random is higher than %ld\n", (long)RAND_MAX);
      ret = (int)(((double)t / ((double)(RAND_MAX) + 1)) * (hi - lo + 1));
      ret += lo;
      snprintf(retbuf, sizeof(retbuf), "%d", ret);
      Tcl_SetResult(interp, retbuf, TCL_VOLATILE);
      return (TCL_OK);
}

#define VERSION_USAGE "db_version"
int
dbversion_cmd(notused, interp, argc, notused2)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *notused2[];
{
      char *str;

      notused = NULL;
      notused2 = NULL;
      USAGE(argc, 1, VERSION_USAGE, 0);
      str = db_version(NULL, NULL, NULL);
      if (str == NULL) {
            Tcl_SetResult(interp, "db_version: ", TCL_STATIC);
            Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
            return (TCL_ERROR);
      }
      Tcl_SetResult(interp, str, TCL_DYNAMIC);
      return (TCL_OK);
}

/*
 * Create an environment that we can pass around between different
 * calls.
 */
#define DBENV_USAGE "dbenv "
int
dbenv_cmd(notused, interp, argc, argv)
      ClientData notused;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      static int env_number = 0;
      DB_ENV *env;
      char envname[50];

      debug_check();
      notused = NULL;

      /* Check number of arguments. */
      USAGE_GE(argc, 1, DBENV_USAGE, DO_ENV);

      process_env_options(interp, argc - 1, &argv[1], &env);
      if (env == NULL) {
            Tcl_SetResult(interp, "NULL", TCL_STATIC);
            return (TCL_OK);
      }

      F_SET(env, DB_ENV_STANDALONE);

      /* Create new command name. */
      snprintf(envname, sizeof(envname), "env%d", env_number);
      env_number++;

      Tcl_CreateCommand(interp, envname, envwidget_cmd, (ClientData)env,
          envwidget_delcmd);
      Tcl_SetResult(interp, envname, TCL_VOLATILE);
      return (TCL_OK);
}

void
envwidget_delcmd(cd)
      ClientData cd;
{
      DB_ENV *env;
      u_int8_t *conflicts;

      debug_check();
      env = (DB_ENV *)cd;

      if (!F_ISSET(env, DB_ENV_CDB) && env->lk_conflicts != NULL) {
            conflicts = (u_int8_t *)env->lk_conflicts;
            free(conflicts);
      }
      (void)db_appexit(env);
      free(env);
}

#define     ENVWIDGET_USAGE "envN"
#define     ENVWIDGET_SIMPLEDUP "envN simpledup"
int
envwidget_cmd(cd, interp, argc, argv)
      ClientData cd;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      static int nenv_number = 0;
      DB_ENV *env, *newenv;
      char **p, nenvname[50];

      argv = argv;
      env = (DB_ENV *)cd;

      if (argc == 1) {
            USAGE(argc, 1, ENVWIDGET_USAGE, 0);

            Tcl_ResetResult(interp);
            if (env->db_home != NULL)
                  Tcl_AppendResult(interp, " Home: ", env->db_home, 0);
            if ((p = env->db_data_dir) != NULL)
                  for (; *p != NULL; ++p)
                        Tcl_AppendResult(interp, " Data: ", *p, 0);
            if (env->db_log_dir != NULL)
                  Tcl_AppendResult(interp, " Log: ", env->db_log_dir, 0);
            if (env->db_tmp_dir != NULL)
                  Tcl_AppendResult(interp, " Tmp: ", env->db_tmp_dir, 0);
      } else if (strcmp(argv[1], "simpledup") == 0) {
            USAGE(argc, 2, ENVWIDGET_SIMPLEDUP, 0);
            /*
             * Copy the env and then NULL out the log, lock and
             * transaction info pointers so that we only share an
             * mpool.
             */
            newenv = (DB_ENV *)malloc(sizeof(*newenv));
            *newenv = *env;
            newenv->lg_info = NULL;
            newenv->lk_info = NULL;
            newenv->tx_info = NULL;

            /* Create new command name. */
            snprintf(nenvname, sizeof(nenvname), "nenv%d", nenv_number);
            nenv_number++;

            Tcl_CreateCommand(interp, nenvname, envwidget_cmd,
                (ClientData)newenv, NULL);
            Tcl_SetResult(interp, nenvname, TCL_VOLATILE);
      } else {
            Tcl_SetResult(interp, "Invalid command", TCL_STATIC);
            return (TCL_ERROR);
      }

      return (TCL_OK);
}

#define ARGS_USAGE "args"
int
args_cmd(cd, interp, argc, argv)
      ClientData cd;
      Tcl_Interp *interp;
      int argc;
      char *argv[];
{
      cd = cd;
      argv = argv;

      USAGE(argc, 1, ARGS_USAGE, 0);
      printf("Legal environment options are: %s\n", DB_ENV_FLAGS);
      printf("Legal access method options are: %s\n", DB_INFO_FLAGS);
      Tcl_ResetResult(interp);
      return (TCL_OK);
}

#define DEBUG_CHECK_USAGE "debug_check"
int
debugcheck_cmd(notused1, interp, argc, notused2)
      ClientData notused1;
      Tcl_Interp *interp;
      int argc;
      char *notused2[];
{
      USAGE(argc, 1, DEBUG_CHECK_USAGE, 0);
      notused1 = notused1;
      notused2 = notused2;
      debug_check();
      Tcl_ResetResult(interp);
      return (TCL_OK);
}

#define DB_JOIN_USAGE "dbN join {DBC ... DBC} flags"
int
db_join_cmd(interp, argc, argv, dbp)
      Tcl_Interp *interp;
      int argc;
      char *argv[];
      DB *dbp;
{
      static int jcurs_id = 0;
      int i, tclint, ncurs, ret;
      u_int32_t flags;
      char **cursnames;
      char cursname[128];
      Tcl_CmdInfo info;
      DBC *dbc, **curs_array;

      USAGE(argc, 4, DB_JOIN_USAGE, 0);

      if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK) {
            Tcl_SetResult(interp, "\nUsage: ", TCL_STATIC);
            Tcl_AppendResult(interp, DB_JOIN_USAGE, NULL);
            return (TCL_OK);
      }

      flags = (u_int32_t)tclint;

      /* Now, split the cursor list into an array. */
      if (Tcl_SplitList(interp, argv[2], &ncurs, &cursnames) != TCL_OK) {
            Tcl_SetResult(interp, "dbjoin: Invalid list ", TCL_STATIC);
            Tcl_AppendResult(interp, argv[2], NULL);
            return (TCL_OK);
      }

      /* Malloc the array to pass to join. */
      curs_array = (DBC **)malloc(sizeof(DBC *) * (ncurs + 1));
      if (curs_array == NULL) {
            Tcl_SetResult(interp, "dbjoin: ", TCL_STATIC);
            Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
            goto end1;
      }
      for (i = 0; i < ncurs; i++) {
            if (Tcl_GetCommandInfo(interp, cursnames[i], &info) == 0) {
                  Tcl_SetResult(interp,
                      "dbjoin: Invalid cursor ", TCL_STATIC);
                  Tcl_AppendResult(interp, cursnames[i], NULL);
                  goto end2;
            }
            curs_array[i] = (DBC *)info.clientData;
      }
      curs_array[i] = NULL;

      if ((ret = dbp->join(dbp, curs_array, 0, &dbc)) == 0) {
            snprintf(cursname, sizeof(cursname), "join.cursor%d", jcurs_id);
            jcurs_id++;
            Tcl_CreateCommand(interp, cursname, dbcursor_cmd,
                (ClientData)dbc, NULL);
            Tcl_SetResult(interp, cursname, TCL_VOLATILE);
      } else {
            Tcl_SetResult(interp, "db_cursor:", TCL_STATIC);
            errno = ret;
            Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
      }

end2: free(curs_array);
end1: FREE_TCL(cursnames);
      return (TCL_OK);
}

Generated by  Doxygen 1.6.0   Back to index