OpenFPGA/libs/EXTERNAL/tcl8.6.12/pkgs/thread2.8.7/generic/psGdbm.c

401 lines
8.5 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file implements wrappers for persistent gdbm storage for the
* shared variable arrays.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
* ----------------------------------------------------------------------------
*/
#ifdef HAVE_GDBM
#include "threadSvCmd.h"
#include <gdbm.h>
#include <stdlib.h> /* For free() */
/*
* Functions implementing the persistent store interface
*/
static ps_open_proc ps_gdbm_open;
static ps_close_proc ps_gdbm_close;
static ps_get_proc ps_gdbm_get;
static ps_put_proc ps_gdbm_put;
static ps_first_proc ps_gdbm_first;
static ps_next_proc ps_gdbm_next;
static ps_delete_proc ps_gdbm_delete;
static ps_free_proc ps_gdbm_free;
static ps_geterr_proc ps_gdbm_geterr;
/*
* This structure collects all the various pointers
* to the functions implementing the gdbm store.
*/
const PsStore GdbmStore = {
"gdbm",
NULL,
ps_gdbm_open,
ps_gdbm_get,
ps_gdbm_put,
ps_gdbm_first,
ps_gdbm_next,
ps_gdbm_delete,
ps_gdbm_close,
ps_gdbm_free,
ps_gdbm_geterr,
NULL
};
/*
*-----------------------------------------------------------------------------
*
* Sv_RegisterGdbmStore --
*
* Register the gdbm store with shared variable implementation.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
void
Sv_RegisterGdbmStore(void)
{
Sv_RegisterPsStore(&GdbmStore);
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_open --
*
* Opens the dbm-based persistent storage.
*
* Results:
* Opaque handle of the opened dbm storage.
*
* Side effects:
* The gdbm file might be created if not found.
*
*-----------------------------------------------------------------------------
*/
static ClientData
ps_gdbm_open(
const char *path)
{
GDBM_FILE dbf;
char *ext;
Tcl_DString toext;
Tcl_DStringInit(&toext);
ext = Tcl_UtfToExternalDString(NULL, path, strlen(path), &toext);
dbf = gdbm_open(ext, 512, GDBM_WRCREAT|GDBM_SYNC|GDBM_NOLOCK, 0666, NULL);
Tcl_DStringFree(&toext);
return dbf;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_close --
*
* Closes the gdbm-based persistent storage.
*
* Results:
* 0 - ok
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
ps_gdbm_close(
ClientData handle)
{
gdbm_close((GDBM_FILE)handle);
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_get --
*
* Retrieves data for the key from the dbm storage.
*
* Results:
* 1 - no such key
* 0 - ok
*
* Side effects:
* Data returned must be freed by the caller.
*
*-----------------------------------------------------------------------------
*/
static int
ps_gdbm_get(
ClientData handle,
const char *key,
char **dataptrptr,
size_t *lenptr)
{
GDBM_FILE dbf = (GDBM_FILE)handle;
datum drec, dkey;
dkey.dptr = (char*)key;
dkey.dsize = strlen(key) + 1;
drec = gdbm_fetch(dbf, dkey);
if (drec.dptr == NULL) {
return 1;
}
*dataptrptr = drec.dptr;
*lenptr = drec.dsize;
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_first --
*
* Starts the iterator over the dbm file and returns the first record.
*
* Results:
* 1 - no more records in the iterator
* 0 - ok
*
* Side effects:
* Data returned must be freed by the caller.
*
*-----------------------------------------------------------------------------
*/
static int
ps_gdbm_first(
ClientData handle,
char **keyptrptr,
char **dataptrptr,
size_t *lenptr)
{
GDBM_FILE dbf = (GDBM_FILE)handle;
datum drec, dkey;
dkey = gdbm_firstkey(dbf);
if (dkey.dptr == NULL) {
return 1;
}
drec = gdbm_fetch(dbf, dkey);
if (drec.dptr == NULL) {
return 1;
}
*dataptrptr = drec.dptr;
*lenptr = drec.dsize;
*keyptrptr = dkey.dptr;
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_next --
*
* Uses the iterator over the dbm file and returns the next record.
*
* Results:
* 1 - no more records in the iterator
* 0 - ok
*
* Side effects:
* Data returned must be freed by the caller.
*
*-----------------------------------------------------------------------------
*/
static int ps_gdbm_next(
ClientData handle,
char **keyptrptr,
char **dataptrptr,
size_t *lenptr)
{
GDBM_FILE dbf = (GDBM_FILE)handle;
datum drec, dkey, dnext;
dkey.dptr = *keyptrptr;
dkey.dsize = strlen(*keyptrptr) + 1;
dnext = gdbm_nextkey(dbf, dkey);
free(*keyptrptr), *keyptrptr = NULL;
if (dnext.dptr == NULL) {
return 1;
}
drec = gdbm_fetch(dbf, dnext);
if (drec.dptr == NULL) {
return 1;
}
*dataptrptr = drec.dptr;
*lenptr = drec.dsize;
*keyptrptr = dnext.dptr;
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_put --
*
* Stores used data bound to a key in dbm storage.
*
* Results:
* 0 - ok
* -1 - error; use ps_dbm_geterr to retrieve the error message
*
* Side effects:
* If the key is already associated with some user data, this will
* be replaced by the new data chunk.
*
*-----------------------------------------------------------------------------
*/
static int
ps_gdbm_put(
ClientData handle,
const char *key,
char *dataptr,
size_t len)
{
GDBM_FILE dbf = (GDBM_FILE)handle;
datum drec, dkey;
int ret;
dkey.dptr = (char*)key;
dkey.dsize = strlen(key) + 1;
drec.dptr = dataptr;
drec.dsize = len;
ret = gdbm_store(dbf, dkey, drec, GDBM_REPLACE);
if (ret == -1) {
return -1;
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_delete --
*
* Deletes the key and associated data from the dbm storage.
*
* Results:
* 0 - ok
* -1 - error; use ps_dbm_geterr to retrieve the error message
*
* Side effects:
* If the key is already associated with some user data, this will
* be replaced by the new data chunk.
*
*-----------------------------------------------------------------------------
*/
static int
ps_gdbm_delete(
ClientData handle,
const char *key)
{
GDBM_FILE dbf = (GDBM_FILE)handle;
datum dkey;
int ret;
dkey.dptr = (char*)key;
dkey.dsize = strlen(key) + 1;
ret = gdbm_delete(dbf, dkey);
if (ret == -1) {
return -1;
}
return 0;
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_free --
*
* Frees memory allocated by the gdbm implementation.
*
* Results:
* None.
*
* Side effects:
* Memory gets reclaimed.
*
*-----------------------------------------------------------------------------
*/
static void
ps_gdbm_free(
ClientData handle,
void *data)
{
(void)handle;
free(data);
}
/*
*-----------------------------------------------------------------------------
*
* ps_gdbm_geterr --
*
* Retrieves the textual representation of the error caused
* by the last dbm command.
*
* Results:
* Pointer to the strimg message.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static const char*
ps_gdbm_geterr(
ClientData handle)
{
(void)handle;
/*
* The problem with gdbm interface is that it uses the global
* gdbm_errno variable which is not per-thread nor mutex
* protected. This variable is used to reference array of gdbm
* error text strings. It is very dangerous to use this in the
* MT-program without proper locking. For this kind of app
* we should not be concerned with that, since all ps_gdbm_xxx
* operations are performed under shared variable lock anyway.
*/
return gdbm_strerror(gdbm_errno);
}
#endif /* HAVE_GDBM */
/* EOF $RCSfile*/
/* Emacs Setup Variables */
/* Local Variables: */
/* mode: C */
/* indent-tabs-mode: nil */
/* c-basic-offset: 4 */
/* End: */