This is HashFile.m in view mode; [Download] [Up]
/* File: HashFile.m - db(3) to HashTable bridge
*
* By: Christopher Lane <lane@camis.stanford.edu>
* Symbolic Systems Resources Group
* Knowledge Systems Laboratory
* Stanford University
*
* Date: 12 August 1994
*
* Copyright: 1990, 1991, 1992 & 1994 by The Leland Stanford Junior University.
* This program may be distributed without restriction for non-commercial use.
*/
#import <c.h>
#import <libc.h>
#import <string.h>
#import <assert.h>
#import "HashFile.h"
#define OBJECT @encode(id)
#define NXRewind(stream) NXSeek(stream, 0L, NX_FROMSTART)
@implementation HashFile
+ (BOOL) isHashFile:(const char *) name
{
return dbExists((char *) name);
}
- initFromFile:(const char *) name
{
return [self initFromFile:name keyDesc:OBJECT];
}
- initFromFile:(const char *) name keyDesc:(const char *) aKeyDesc
{
return [self initFromFile:name keyDesc:aKeyDesc valueDesc:OBJECT];
}
- initFromFile:(const char *) name keyDesc:(const char *) aKeyDesc valueDesc:(const char *) aValueDesc
{
return [self initFromFile:name keyDesc:aKeyDesc valueDesc:aValueDesc capacity:0];
}
- initFromFile:(const char *) name keyDesc:(const char *) aKeyDesc valueDesc:(const char *) aValueDesc capacity:(unsigned) aCapacity;
{
NXTypedStream *typedStream;
if ((db = dbOpen(filename = (char *) name)) == NULL) return nil;
readOnly = (BOOL) ((db->flag & (dbFlagReadOnly | dbFlagCompressed)) != 0);
cached = (aCapacity != HASHFILE_UNCACHED);
keyDesc = aKeyDesc;
valueDesc = aValueDesc;
if (cached) table = [[HashTable alloc] initKeyDesc:keyDesc valueDesc:valueDesc capacity:aCapacity];
assert((d.k.s = (char *) malloc((size_t) LEAFSIZE)) != NULL);
assert((d.c.s = (char *) malloc((size_t) LEAFSIZE)) != NULL);
d.k.n = malloc_size(d.k.s);
d.c.n = malloc_size(d.c.s);
assert((stream = NXOpenMemory(NULL, 0, NX_READWRITE)) != NULL);
assert((typedStream = NXOpenTypedStream(stream, NX_WRITEONLY)) != NULL); {
offset = NXTell(stream);
NXCloseTypedStream(typedStream);
}
return self;
}
- free
{
free(d.k.s);
free(d.c.s);
NXCloseMemory(stream, NX_FREEBUFFER);
assert(dbClose(db));
if (cached) [table free];
return [super free];
}
- empty
{
if (readOnly || !dbClose(db) || !dbCreate(filename) || (db = dbInit(filename)) == NULL) return nil;
else if (cached) [table empty];
return self;
}
- (unsigned) count
{
unsigned i = 0;
if (dbFirst(db, &d) && d.k.n > 0) do { ++i; } while (dbNext(db, &d));
if (cached) assert(i >= [table count]);
return i;
}
- (BOOL) isKey:(const void *) aKey
{
if (cached && [table isKey:aKey]) return YES;
[self _keyCvtIn:aKey];
return((BOOL) dbFind(db, &d));
}
- (void *) valueForKey:(const void *) aKey
{
void *value = (void *) nil;
if (cached && [table isKey:aKey]) return [table valueForKey:aKey];
[self _keyCvtIn:aKey];
if (dbFetch(db, &d)) {
value = [self _valueCvtOut];
if (cached) (void) [table insertKey:[self _keyCvtOut] value:value];
}
return value;
}
- (void *) insertKey:(const void *) aKey value:(void *) aValue
{
int flag;
void *value;
if (readOnly) return (void *) nil;
value = [self valueForKey:aKey]; /* allows [table insertKey:...] to return previous value */
[self _keyCvtIn:aKey];
[self _valueCvtIn:aValue];
assert(dbLock(db)); {
flag = dbStore(db, &d);
assert(dbUnlock(db));
}
if (!flag) return (void *) nil;
if (cached) return [table insertKey:aKey value:aValue];
return (value);
}
- (void *) removeKey:(const void *) aKey;
{
int flag;
if (readOnly) return (void *) nil;
[self _keyCvtIn:aKey];
assert(dbLock(db)); {
flag = dbDelete(db, &d);
assert(dbUnlock(db));
}
if (!flag) return (void *) nil;
return((cached) ? [table removeKey:aKey] : (void *) nil);
}
- (NXHashState) initState
{
NXHashState state;
state.i = state.j = 0;
return state;
}
- (BOOL) nextState:(NXHashState *) aState key:(const void **) aKey value:(void **) aValue
{
if (aState->j == 0) {
if (aState->i = dbFirst(db, &d)) {
assert((aState->i = d.k.n) != 0);
assert((aState->j = d.c.n) != 0);
}
}
else [[self _conditionalFree:aKey desc:keyDesc] _conditionalFree:aValue desc:valueDesc];
*aKey = *aValue = NULL;
if (aState->i == 0) return NO;
d.k.n = aState->i;
d.c.n = aState->j;
if (dbGet(db, &d)) {
*aKey = [self _keyCvtOut];
*aValue = [self _valueCvtOut];
}
else return NO;
if (aState->i = dbNext(db, &d)) {
assert((aState->i = d.k.n) != 0);
assert((aState->j = d.c.n) != 0);
}
return YES;
}
- (void) _keyCvtIn:(const void *) aKey
{
[self _datumCvtIn:&d.k from:aKey using:keyDesc];
}
- (void) _valueCvtIn:(const void *) aValue
{
[self _datumCvtIn:&d.c from:aValue using:valueDesc];
}
- (void) _datumCvtIn:(Datum *) aDatum from:(const void *) aBuffer using:(const char *) aDesc
{
NXTypedStream *typedStream;
NXRewind(stream);
assert((typedStream = NXOpenTypedStream(stream, NX_WRITEONLY)) != NULL); {
offset = NXTell(stream);
NXWriteType(typedStream, aDesc, &aBuffer);
aDatum->n = NXTell(stream) - offset;
NXCloseTypedStream(typedStream);
}
NXSeek(stream, offset, NX_FROMSTART);
NXRead(stream, (void *) aDatum->s, aDatum->n);
}
- (void *) _keyCvtOut
{
return [self _datumCvtOut:&d.k using:keyDesc];
}
- (void *) _valueCvtOut
{
return [self _datumCvtOut:&d.c using:valueDesc];
}
- (void *) _datumCvtOut:(Datum *) aDatum using:(const char *) aDesc
{
void *pointer;
NXTypedStream *typedStream;
NXSeek(stream, offset, NX_FROMSTART);
NXWrite(stream, (void *) aDatum->s, aDatum->n);
NXRewind(stream);
assert((typedStream = NXOpenTypedStream(stream, NX_READONLY)) != NULL); {
NXReadType(typedStream, aDesc, &pointer);
NXCloseTypedStream(typedStream);
}
return pointer;
}
- _conditionalFree:(const void **) aPointer desc:(const char *) aDesc
{
switch(*aDesc) {
case '*' : free((void *) *aPointer); break;
case '@' : [(id) (*aPointer) free]; break;
default: break;
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.