283 lines
5.2 KiB
C
283 lines
5.2 KiB
C
/* Copyright 1998 by Abacus Research and
|
|
* Development, Inc. All rights reserved.
|
|
*/
|
|
|
|
#if !defined (OMIT_RCSID_STRINGS)
|
|
char ROMlib_rcsid_faux_dbm[] = "$Id: fauxdbm.c 63 2004-12-24 18:19:43Z ctm $";
|
|
#endif
|
|
|
|
/*
|
|
* The original plan was to use the Registry to simulate dbm, but
|
|
* upon sober reflection, that was decided against, since a fried
|
|
* registry equals a dead machine. Instead, we're implementing an
|
|
* incredibly hokey subset of the functionality that is tailored to
|
|
* the specific way ROMlib calls the dbm routines. Maybe we'll port
|
|
* the BSD dbm routines sometime.
|
|
*/
|
|
|
|
#include "rsys/common.h"
|
|
|
|
#if defined(CYGWIN32) || defined (MSDOS)
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include "rsys/fauxdbm.h"
|
|
|
|
PUBLIC DBM *
|
|
dbm_open (const char *name, int flags, int mode)
|
|
{
|
|
DBM *retval;
|
|
char *open_mode;
|
|
FILE *fp;
|
|
|
|
retval = NULL;
|
|
|
|
if (flags == O_RDONLY)
|
|
open_mode = "rb";
|
|
else
|
|
open_mode = "a+b";
|
|
|
|
fp = fopen (name, open_mode);
|
|
if (fp != NULL)
|
|
{
|
|
retval = malloc (sizeof *retval);
|
|
retval->fp = fp;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC datum
|
|
dbm_firstkey (DBM *file)
|
|
{
|
|
datum retval;
|
|
|
|
if (!file)
|
|
{
|
|
retval.dptr = 0;
|
|
retval.dsize = 0;
|
|
}
|
|
else
|
|
{
|
|
rewind (file->fp);
|
|
retval = dbm_nextkey (file);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#define KEY_ID "key" /* 4 bytes long, counting NUL */
|
|
#define CONTENT_ID "content" /* 8 bytes long, counting NUL */
|
|
|
|
PRIVATE void
|
|
read_datum (DBM *file)
|
|
{
|
|
if (file)
|
|
{
|
|
char *p;
|
|
|
|
p = file->buf;
|
|
if (fread (p, 4, 1, file->fp) != 1)
|
|
*(uint32 *)p = 0;
|
|
else
|
|
{
|
|
int to_read;
|
|
|
|
to_read = sizeof KEY_ID + *(uint32 *)p;
|
|
p += 4;
|
|
while (to_read % 4)
|
|
++to_read;
|
|
if (p + to_read - file->buf <= (int) sizeof file->buf)
|
|
{
|
|
fread (p, to_read, 1, file->fp);
|
|
p += to_read;
|
|
if (fread (p, 4, 1, file->fp) != 1)
|
|
*(uint32 *)p = 0;
|
|
else
|
|
{
|
|
to_read = sizeof CONTENT_ID + *(uint32 *)p;
|
|
p += 4;
|
|
while (to_read % 4)
|
|
++to_read;
|
|
if (p + to_read - file->buf <= (int) sizeof file->buf)
|
|
fread (p, to_read, 1, file->fp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PUBLIC datum
|
|
dbm_nextkey (DBM *file)
|
|
{
|
|
datum retval;
|
|
|
|
if (!file)
|
|
{
|
|
retval.dptr = 0;
|
|
retval.dsize = 0;
|
|
}
|
|
else
|
|
{
|
|
read_datum (file);
|
|
retval.dsize = *(uint32 *) file->buf;
|
|
if (retval.dsize)
|
|
retval.dptr = file->buf + sizeof (uint32) + sizeof KEY_ID;
|
|
else
|
|
retval.dptr = 0;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC datum
|
|
dbm_fetch (DBM *file, datum key)
|
|
{
|
|
datum retval;
|
|
int keysize;
|
|
int offset;
|
|
|
|
keysize = *(uint32 *)file->buf;
|
|
offset = sizeof (uint32) + sizeof (KEY_ID) + keysize;
|
|
while (offset % 4)
|
|
++offset;
|
|
retval.dsize = *(uint32 *)(file->buf + offset);
|
|
if (retval.dsize)
|
|
retval.dptr = file->buf + offset + sizeof (uint32) + sizeof CONTENT_ID;
|
|
else
|
|
retval.dptr = 0;
|
|
return retval;
|
|
}
|
|
|
|
#define RAW_LENGTH(datum, id) (sizeof (uint32) + sizeof (id) + datum.dsize)
|
|
|
|
#define PADDING(n) \
|
|
({ \
|
|
int _n = n; \
|
|
_n % 4 ? 4 - _n % 4 : 0; \
|
|
})
|
|
|
|
PRIVATE void
|
|
buf_from_datum (char **opp, datum d, const char *tag)
|
|
{
|
|
char *op;
|
|
|
|
op = *opp;
|
|
*(uint32 *) op = (uint32) d.dsize;
|
|
op += sizeof (uint32);
|
|
memcpy (op, tag, strlen (tag) + 1);
|
|
op += strlen (tag) + 1;
|
|
memcpy (op, d.dptr, d.dsize);
|
|
op += d.dsize;
|
|
while ((op - *opp) % 4)
|
|
++op;
|
|
*opp = op;
|
|
}
|
|
|
|
PUBLIC int
|
|
dbm_store (DBM *file, datum key, datum content, int flags)
|
|
{
|
|
int retval;
|
|
|
|
retval = -1;
|
|
if (file)
|
|
{
|
|
int key_raw_length, content_raw_length;
|
|
int key_padding , content_padding;
|
|
|
|
key_raw_length = RAW_LENGTH (key , KEY_ID);
|
|
content_raw_length = RAW_LENGTH (content, CONTENT_ID);
|
|
|
|
key_padding = PADDING (key_raw_length);
|
|
content_padding = PADDING (content_raw_length);
|
|
|
|
if (key_raw_length + key_padding + content_raw_length + content_padding
|
|
<= (int) sizeof file->buf)
|
|
{
|
|
char *op;
|
|
|
|
op = file->buf;
|
|
buf_from_datum (&op, key , KEY_ID);
|
|
buf_from_datum (&op, content, CONTENT_ID);
|
|
if (fwrite (file->buf, op - file->buf, 1, file->fp) == 1)
|
|
retval = 0;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
PUBLIC void
|
|
dbm_close (DBM *file)
|
|
{
|
|
if (file)
|
|
{
|
|
fclose (file->fp);
|
|
free (file);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
|
|
#define XXX(datum, size) \
|
|
do \
|
|
{ \
|
|
int i; \
|
|
char *p; \
|
|
\
|
|
datum.dsize = size; \
|
|
datum.dptr = alloca (size); \
|
|
p = datum.dptr; \
|
|
for (i = 0; i < size; ++i) \
|
|
*p++ = '0' + size; \
|
|
} \
|
|
while (0)
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
DBM *db;
|
|
|
|
db = dbm_open ("/tmp/test.fauxdb", O_CREAT|O_RDWR, (LONGINT) 0666);
|
|
if (db)
|
|
{
|
|
int keysize;
|
|
|
|
for (keysize = 1; keysize < 10; ++keysize)
|
|
{
|
|
int contentsize;
|
|
|
|
for (contentsize = 0; contentsize <= 10; ++contentsize)
|
|
{
|
|
datum key, content;
|
|
|
|
XXX (key, keysize);
|
|
XXX (content, contentsize);
|
|
dbm_store (db, key, content, DBM_REPLACE);
|
|
}
|
|
}
|
|
|
|
dbm_close (db);
|
|
}
|
|
|
|
db = dbm_open ("/tmp/test.fauxdb", O_RDONLY, 0);
|
|
if (db)
|
|
{
|
|
datum key, content;
|
|
int i;
|
|
|
|
i = 0;
|
|
key = dbm_firstkey (db);
|
|
while (key.dptr)
|
|
{
|
|
if (i++ % 3)
|
|
content = dbm_fetch (db, key);
|
|
key = dbm_nextkey (db);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#endif
|