/* 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 #include #include #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