/*
* gdbm.c
*
* Created by: Benny Holmgren
* Description: LPC interface to GNU dbm.
*/
#ifdef LATTICE
#include "/lpc_incl.h"
#include "/eoperators.h"
#include "/regexp.h"
#include "/debug.h"
#else
#include "../lpc_incl.h"
#include "../eoperators.h"
#include "../regexp.h"
#include "../debug.h"
#endif
#include "gdbm.h"
#ifdef F_DB_EXISTS
void
f_db_exists PROT((void))
{
int res = db_exists( (sp-1)->u.string, sp->u.string );
pop_n_elems(2);
push_number(res);
}
#endif
#ifdef F_DB_QUERY
void
f_db_query PROT((void))
{
svalue_t res;
if (db_query(&res, (sp-1)->u.string, sp->u.string);
pop_n_elems( 2 );
*sp++ = ret;
if( res ) {
switch(res->type) {
case T_STRING:
switch (respush_string(res->u.string, res->subtype);
break;
case T_ARRAY:
push_array(res->u.arr);
break;
case T_NUMBER:
push_number(res->u.number);
break;
case T_REAL:
push_real(res->u.real);
break;
case T_MAPPING:
push_mapping(res->u.map);
break;
default:
/* Huh? */
fatal("Bogus svalue in db_query(), type %d\n", res->type);
}
free_svalue(res, "f_db_query");
FREE(res);
} else
push_undefined();
}
#endif
#ifdef F_DB_STORE
void
f_db_store PROT((void))
{
int res;
if(!(sp->type & (T_STRING|T_ARRAY|T_NUMBER|T_REAL|T_MAPPING)))
bad_argument(sp, T_STRING|T_ARRAY|T_NUMBER|T_REAL|T_MAPPING, 3, F_DB_STORE);
res = db_store( (sp-2)->u.string, (sp-1)->u.string, sp );
pop_n_elems( 3 );
push_number( res );
}
#endif
#ifdef F_DB_DELETE
void
f_db_delete PROT((void))
{
int res;
res = db_delete((sp-1)->u.string, sp->u.string);
pop_n_elems(2);
push_number(res);
}
#endif
#ifdef F_DB_KEYS
void
f_db_keys PROT((void))
{
array_t *res;
res = db_keys((sp-st_num_arg+1)->u.string,
(st_num_arg == 1 ? (char *)NULL : sp->u.string));
pop_n_elems(st_num_arg);
if(res) {
push_array(res);
res->ref--; /* Ref count back to 1 */
} else
push_null();
}
#endif
/*
* Support functions.
*/
#ifdef PACKAGE_GDBM
#include <gdbm.h>
int
db_exists( db, keystr )
char *db;
char *keystr;
{
int res;
GDBM_FILE dbf;
datum key;
if(!check_valid_path(db, current_object, "db_exists", 0))
error("Denied read permission for database.\n");
dbf = gdbm_open( db, 0, GDBM_READER, 0640, NULL );
if( !dbf ) {
if( gdbm_errno != GDBM_FILE_OPEN_ERROR )
debug(512,("dbm file open error: %s\n",gdbm_strerror(gdbm_errno)));
return(0);
}
key.dptr = keystr;
key.dsize = strlen(keystr)+1;
res = gdbm_exists( dbf, key );
gdbm_close( dbf );
return( (int)res );
}
svalue_t *
db_query P3( svalue_t *, ret, char *, db, char *, keystr )
{
int res;
GDBM_FILE dbf;
datum key, content;
extern svalue_t const0u;
if(!check_valid_path(db, current_object, "db_query", 0))
error("Denied read permission for database.\n");
dbf = gdbm_open( db, 0, GDBM_READER, 0640, NULL );
if( !dbf ) {
if( gdbm_errno != GDBM_FILE_OPEN_ERROR )
debug(512,("dbm file open error: %s\n",gdbm_strerror(gdbm_errno)));
return( (svalue_t *)NULL );
}
key.dptr = keystr;
key.dsize = strlen(keystr)+1;
content = gdbm_fetch( dbf, key );
gdbm_close( dbf );
if( !content.dptr )
return( (svalue_t *)NULL );
res = restore_svalue( content.dptr, ret);
FREE(content.dptr);
switch (res)
{
case -1:
free_svalue(ret, "db_query");
error("db_query(): Illegal array format.\n");
case -2:
free_svalue(ret, "db_query");
error("db_query(): Illegal mapping format.\n");
}
return( val );
}
int
db_store( db, keystr, val )
char *db, *keystr;
svalue_t *val;
{
GDBM_FILE dbf;
int savesize, res;
datum key, content;
extern int save_svalue_depth;
char *savestring, *tmp;
if(!check_valid_path(db, current_object, "db_store", 1))
error("Denied write permission for database.\n");
dbf = gdbm_open( db, 0, GDBM_WRCREAT, 0640, NULL );
if( !dbf ) {
if( gdbm_errno != GDBM_FILE_OPEN_ERROR )
debug(512,("dbm file open error: %s\n",gdbm_strerror(gdbm_errno)));
return( 0 );
}
save_svalue_depth = 0;
savesize = svalue_save_size(val);
if (save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) {
error("Mappings and/or arrays nested too deep (%d) for db_store\n",
MAX_SAVE_SVALUE_DEPTH);
}
savestring = (char *)XALLOC(savesize);
*savestring = '\0';
tmp = savestring;
save_svalue(val, &tmp);
key.dptr = keystr;
key.dsize = strlen( keystr ) +1;
content.dptr = savestring;
content.dsize = strlen( savestring ) +1;
res = gdbm_store( dbf, key, content, GDBM_REPLACE );
gdbm_close( dbf );
FREE(savestring);
if( res ) {
debug(512, ("db_store() failed: %s\n", gdbm_strerror(gdbm_errno)));
return( 0 );
}
return( 1 );
}
int
db_delete(db, keystr)
char *db, *keystr;
{
int res;
datum key;
GDBM_FILE dbf;
if(!check_valid_path(db, current_object, "db_delete", 1))
error("Denied write permission for database.\n");
dbf = gdbm_open( db, 0, GDBM_WRITER, 0640, NULL );
if( !dbf ) {
if( gdbm_errno != GDBM_FILE_OPEN_ERROR )
debug(512,("dbm file open error: %s\n",gdbm_strerror(gdbm_errno)));
return(0);
}
key.dptr = keystr;
key.dsize = strlen( keystr ) +1;
res = gdbm_delete( dbf, key );
gdbm_close( dbf );
if( res != 0 ) /* Not found. */
return(0);
return(1);
}
array_t *
db_keys( db, pattern )
char *db;
char *pattern;
{
datum key, nextkey;
GDBM_FILE dbf;
int keycnt, i;
char *keys[MAX_ARRAY_SIZE];
struct regexp *rexp = (struct regexp *)NULL;
array_t *ret;
extern int eval_cost;
if(!check_valid_path(db, current_object, "db_keys", 0))
error("Denied read permission for database.\n");
if(pattern) {
rexp = regcomp(pattern, 0);
if (!rexp)
return((array_t *)NULL);
}
dbf = gdbm_open( db, 0, GDBM_READER, 0640, NULL );
if( !dbf ) {
if( gdbm_errno != GDBM_FILE_OPEN_ERROR )
debug(512,("dbm file open error: %s\n",gdbm_strerror(gdbm_errno)));
return((array_t *)NULL);
}
keycnt = 0;
key = gdbm_firstkey(dbf);
while(key.dptr) {
nextkey = gdbm_nextkey(dbf, key);
if(pattern && !regexec(rexp, key.dptr))
free(key.dptr);
else
keys[keycnt++] = key.dptr;
key = nextkey;
}
gdbm_close(dbf);
if(rexp)
FREE((char *)rexp);
ret = allocate_array(keycnt);
for(i=0; i < keycnt; i++) {
ret->item[i].type = T_STRING;
ret->item[i].subtype = STRING_MALLOC; /* Should we make it shared? */
ret->item[i].u.string = keys[i]; /* string_copy() for debugging? */
}
return(ret);
}
#endif /* PACKAGE_DBM */