Sadly gdbm does not seem to provide a libdbm.so library itself, instead
instructing every program using it to link with both libgdbm and
libgdbm_compat for similar behavior. It also specifies that, since every
program will be written in the C language using CPP as a preprocessor,
to use CPP macros to inline out a few of the functions it deems unworthy
of implementing, such as dbm_error.
Easy fix though! Doing that as a fallback when dbm isn't found is pretty
trivial, and also providing catchall alternatives for *cough*
unimplemented functions. So in jaymccarthy's dbm package I just changed
dbm-ffi.ss a little bit so that it now uses gdbm, at least, without
directly erroring out. I would like that this be combined with the dbm
package officially, since the only way for me to retain such modified
behavior is to word-for-word copy that package into some custom, badly
named package under my nom de plume. Well, I would like a fast small
pure scheme DBM implementation, but can't always have what we want.
I might also add that gdbm is the only option on Debian based systems,
besides some weird stuff called Tokyo Cabinet under questionable
licensing. dbm is not anywhere in the package list that I can see. Maybe
this is the wrong approach entirely...
#lang scheme
(require scheme/foreign)
(unsafe!)
(define dbm-lib
(with-handlers
((exn:fail:filesystem? (λ (e)
(ffi-lib "libgdbm")
(ffi-lib "libgdbm_compat"))))
(ffi-lib "libdbm")))
(define alternatives
(make-immutable-hash
`((dbm_error . ,void)
(dbm_clearerr . ,void))))
(define (get-dbm obj typ)
(get-ffi-obj (symbol->string obj) dbm-lib typ
(lambda ()
(hash-ref
alternatives
obj
(lambda ()
(error 'dbm-lib "Installed dbm does not provide: ~a"
obj))))))
(define-syntax-rule (define-dbm obj typ)
(define obj (get-dbm 'obj typ)))
(define-cpointer-type _DBM)
(define _mode_t _uint)
#|
typedef struct {
char *dptr;
int dsize;
} datum;
|#
(define-cstruct _datum
([dptr _string]
[dsize _int]))
(define (string->datum s)
(make-datum s (add1 (string-length s))))
(define (datum->string d)
(datum-dptr d))
; int
; dbm_error(DBM *db);
(define-dbm dbm_error (_fun _DBM -> _int))
; int
; dbm_clearerr(DBM *db);
(define-dbm dbm_clearerr (_fun _DBM -> _int))
; int
; dbm_delete(DBM *db, datum key);
(define-dbm dbm_delete (_fun _DBM _datum -> _int))
; void
; dbm_close(DBM *db);
(define-dbm dbm_close (_fun _DBM -> _int))
; datum
; dbm_nextkey(DBM *db);
(define-dbm dbm_nextkey (_fun _DBM -> _datum))
; datum
; dbm_firstkey(DBM *db);
(define-dbm dbm_firstkey (_fun _DBM -> _datum))
; DBM *
; dbm_open(const char *file, int open_flags, mode_t file_mode);
(define-dbm dbm_open
(_fun _path _uint _mode_t
-> _DBM/null))
(define _store_mode_t
(_enum '(DBM_INSERT DBM_REPLACE)))
; int
; dbm_store(DBM *db, datum key, datum content, int store_mode);
(define-dbm dbm_store
(_fun _DBM _datum _datum _store_mode_t
-> _int))
; datum
; dbm_fetch(DBM *db, datum key);
(define-dbm dbm_fetch
(_fun _DBM _datum
-> _datum))
(provide datum?
string->datum
datum->string
dbm_error
dbm_clearerr
dbm_delete
dbm_close
dbm_nextkey
dbm_firstkey
dbm_open
dbm_store
dbm_fetch)
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users