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.