📄 wipdb.c
字号:
OSConnectorFree(currentElement->data.s);
}
OSConnectorFree(currentElement);
}
#define DB_DUPLICATE_STR(s) {UINT8 error; db_duplicateStrMem(s, DB_flag_str, &error;}
#define DB_DUPLICATE_MEM(s) {UINT8 error; db_duplicateStrMem(s, DB_flag_mem, &error;}
/*
* Copy a string or memory block.
*/
static BYTE*
db_duplicateStrMem (BYTE* s, UINT16 type, UINT8 *errorCode)
{
BYTE* temp;
size_t len;
if (type == DB_flag_str) /* str */
len = strlen((char*) s) + 1;
else /* mem */
len = *(UINT16*) s;
temp = (BYTE*) OSConnectorAlloc(len);
#ifndef HAS_SETJMP
/* NOTE: if this paragraph is removed, also remove the 'errorCode' parameter and change macros! */
if (temp == NULL) {
*errorCode = DB_err_outOfMemory;
return NULL;
}
#endif
memcpy(temp, s, len);
*errorCode = DB_err_success;
return temp;
}
/*
* Create a null-terminated string by allocating new memory and
* copying 'length' characters from 'p'.
*/
BYTE* db_createStr(const char* p, UINT16 length) {
BYTE* ptr = NULL;
if (length > 0 && p != NULL) {
ptr = (BYTE*) OSConnectorAlloc(length + 1);
if (ptr) {
memcpy(ptr, p, length);
ptr[length] = '\0';
}
}
return ptr;
}
/*
* Create a memory block by allocating new memory and
* copying 'length' characters from 'p'.
*/
BYTE* db_createMem(const char* p, UINT16 length) {
BYTE* ptr = NULL;
if (length > 0 && p != NULL) {
ptr = (BYTE*) OSConnectorAlloc(length + sizeof(UINT16));
if (ptr) {
memcpy(ptr + sizeof(UINT16), p, length);
*(UINT16*) ptr = length + sizeof(UINT16);
}
}
return ptr;
}
/*
* Update nextId field in persistent memory. Do not use ';'
* after macro;
*
* ElementPtr element
* UINT32 nextId
*/
#define DB_SET_NEXT_ID(element, nextId) \
{UINT32 temp = (nextId); Storage_Put(&store, db_getBlockId(element), 0, 4, &temp);}
/*
* Update childId field in persistent memory. Do not use ';'
* after macro;
*
* UINT32 id
* UINT32 nextId
*/
#define DB_SET_CHILD_ID(id, nextId) \
{UINT32 temp = (nextId); Storage_Put(&store, (id), 4, 4, &temp);}
/*
* Search through idArr and sets the MSB of the element equal
* to 'id'. Only used at startup by the write-through functions.
*/
static void
db_markId (UINT32 id)
{
UINT32* p;
for (p=idArr; *p != id; p++)
;
*p |= 0x80000000;
}
/* ======== get ======== */
/*
* Return data from element. The element pointed out by 'record'
* and 'key' must be of the of the same type as 'type' indicates,
* with one exception: it is legal to get a pointer from a
* string or memory block.
*
* If 'del' is true, the element is deleted and so is its data
* with a few exceptions. Deleting a pointer element does not delete
* its data. Getting a pointer from a string or memory block element
* and deleting it at the same time does not delete its data.
*
* 'type' takes the values of DB_int, DB_str, DB_mem or DB_ptr.
*/
DB_elementData
db_getElementData (DB_ref record, const BYTE* key, BOOL del, UINT16 type, UINT8* errorCode)
{
FieldPtr field;
DB_elementData temp;
temp.i = 0;
if (db_findRecord(record) == NULL) {
*errorCode = DB_err_record;
return temp;
}
field = db_findField(key);
if (field == NULL) {
*errorCode = DB_err_field;
return temp;
}
{
UINT16 elementType = field->flags & DB_mask_type;
if (elementType != type &&
!(type == DB_flag_ptr && (elementType == DB_flag_str || elementType == DB_flag_mem))) {
*errorCode = DB_err_wrongType;
return temp;
}
}
*errorCode = DB_err_success;
if (del) {
temp = *(DB_elementData*) &field->data;
db_deleteElement(TRUE);
} else {
if (type == DB_flag_ptr) /* ptr or str/mem + db_getPtr() */
temp.p = field->data.p;
else if ((field->flags & DB_mask_type) == DB_flag_int) /* int */
temp.i = field->data.i;
else /* str, mem */
temp.s = db_duplicateStrMem(field->data.s,
(UINT16) (field->flags & DB_mask_type), errorCode);
/* errorCode may signal and error, but may be passed on since
* there is no code between here and the end of the function. */
}
return temp;
}
/*
* Return reference to record element.
*/
DB_ref
db_getRef (DB_ref record, const BYTE* key, UINT8* errorCode)
{
FieldPtr field;
if (db_findRecord(record) == NULL) {
*errorCode = DB_err_record;
return DB_null;
}
field = db_findField(key);
if (field == NULL) {
*errorCode = DB_err_field;
return DB_null;
}
if ((field->flags & DB_mask_dataUse) != DB_flag_dataChild) {
*errorCode = DB_err_wrongType;
return DB_null;
} else {
*errorCode = DB_err_success;
currentRecord = (RecordPtr)field; /* Guess the next search uses the\*/
currentRef = ((RecordPtr)field)->ref; /* returned ref. Cache result. */
return currentRef;
}
}
/*
* Return type of element.
*/
UINT8
db_getType (DB_ref record, const BYTE* key, UINT8* errorCode)
{
FieldPtr field;
if (db_findRecord(record) == NULL) {
*errorCode = DB_err_record;
return 0;
}
field = db_findField(key);
if (field == NULL) {
*errorCode = DB_err_field;
return 0;
}
*errorCode = DB_err_success;
return field->flags & DB_mask_type;
}
/* ======== set ======== */
/*
* Create a new element. 'rec' is used for deciding persistent
* state and and seting key flag. The new element is added
* after 'prev' if 'prev' != NULL, else as first element below
* 'rec'. If 'element' != NULL, it is updated with 'data' and
* no new element is created.
*/
/* BOOKMARK:FLAGS */
ElementPtr
db_createNewElement (RecordPtr rec, const BYTE* key, UINT16 flags, DataUnion data,
ElementPtr prev, ElementPtr element, UINT8 *errorCode)
{
BYTE* s;
int i;
if (rec != db_root)
/* Inherit the parent's persistent status */
flags = (flags & ~ DB_mask_persistent) | (rec->flags & DB_mask_persistent);
if (flags & DB_mask_persistent && (flags & DB_mask_type) == DB_flag_ptr) {
*errorCode = DB_err_persistentTypeError;
return NULL;
}
/* Create element */
if ((rec->flags & DB_mask_type) == DB_flag_set) {
/* -------------------------------------------------------- DB_flag_set */
/* =================================================== Create a new element */
if (flags & DB_mask_writeThrough)
element = (ElementPtr) OSConnectorAlloc(sizeof(ElementBlock));
else
element = (ElementPtr) OSConnectorAlloc(sizeof(Element));
#ifndef HAS_SETJMP
if (element == NULL) {
*errorCode = DB_err_outOfMemory;
return NULL;
}
#endif
element->flags = 0; /* clear DB_flag_key */
} else {
/* -------------------------------------------------------- DB_flag_rec */
if (key == NULL) {
*errorCode = DB_err_nullValue;
return NULL;
}
if (element != NULL) { /* ============================ Update existing element */
if ((element->flags & DB_mask_type) != (flags & DB_mask_type)) {
*errorCode = DB_err_wrongType;
return NULL;
} else {
if ((flags & DB_mask_dataUse) == DB_flag_dataExternal)
OSConnectorFree(element->data.s);
element->data = data;
if (flags & DB_mask_writeThrough)
if (! db_saveElement_wt(rec, element, prev))
/* No persistent save, set warning. Return value still valid. */
*errorCode = DB_err_noPersistentSave;
return element;
}
} else { /* ========================================== Create a new element */
if (flags & DB_mask_writeThrough)
element = (ElementPtr) OSConnectorAlloc(sizeof(FieldBlock));
else
element = (ElementPtr) OSConnectorAlloc(sizeof(Field));
#ifndef HAS_SETJMP
if (element == NULL) {
*errorCode = DB_err_outOfMemory;
return NULL;
}
#endif
/* Copy key */
for (s=((FieldPtr)element)->key, i=1; *s = *key; s++, key++, i++)
if (i == DB_keyLen) { /* In case of too long input keys. */
OSConnectorFree(element);
*errorCode = DB_err_tooLongKey;
return NULL;
}
element->flags = DB_flag_key;
}
}
/* Init data */
element->flags |= flags;
element->data = data;
/* Add element */
if (prev == NULL)
db_addBelow(rec, (ElementPtr) element);
else
db_addAfter(prev, (ElementPtr) element);
/* Save element, if write-through */
*errorCode = DB_err_success;
if (flags & DB_mask_writeThrough && ! db_serviceMode) {
if (element->flags & DB_mask_key)
((FieldBlockPtr) element)->blockId = 0;
else
((ElementBlockPtr) element)->blockId = 0;
if (! db_saveElement_wt(rec, element, prev))
/* No persistent save, set warning. Return value still valid. */
*errorCode = DB_err_noPersistentSave;
}
return element;
}
/*
* Create and insert an Element or Field. If an element named
* 'key' already exists, 'flags' must signal the same type of
* the element. Old strings or memory blocks are freed.
*
* If NULL is returned, an error has occurred and its number
* is returned in 'errorCode'.
*/
static ElementPtr
db_setItem (DB_ref record, const BYTE* key, UINT16 flags, DataUnion data,
UINT8 *errorCode)
{
ElementPtr element;
RecordPtr rec;
*errorCode = DB_err_success;
rec = db_findRecord(record);
if (rec == NULL) {
*errorCode = DB_err_record;
return NULL;
}
db_findField(key);
element = db_createNewElement(rec, key, flags, data, NULL, currentElement, errorCode);
return element;
}
/*
* Update or insert an int field.
*/
UINT8
db_setInt (DB_ref record, const BYTE* key, INT32 value)
{
DataUnion data;
UINT8 error;
data.i = value; /* BOOKMARK:FLAGS */
db_setItem(record, key, DB_flag_int | DB_flag_dataInternal, data, &error);
return error;
}
/*
* Update or insert a string field. 'value' is taken over by
* the database and is deallocated when this element is deleted.
*/
UINT8
db_setStr (DB_ref record, const BYTE* key, BYTE* value)
{
DataUnion data;
UINT8 error;
if (value == NULL)
return DB_err_nullValue;
data.s = value; /* BOOKMARK:FLAGS */
db_setItem(record, key, DB_flag_str | DB_flag_dataExternal, data, &error);
return error;
}
/*
* Update or insert a memory block field. 'value' is taken over by
* the database and is deallocated when this element is deleted.
*/
UINT8
db_setMem (DB_ref record, const BYTE* key, BYTE* value)
{
DataUnion data;
UINT8 error;
if (value == NULL)
return DB_err_nullValue;
data.s = value; /* BOOKMARK:FLAGS */
db_setItem(record, key, DB_flag_mem | DB_flag_dataExternal, data, &error);
return error;
}
/*
* Update or insert a pointer field.
*/
UINT8
db_setPtr (DB_ref record, const BYTE* key, void* value)
{
DataUnion data;
UINT8 error;
data.p = value; /* BOOKMARK:FLAGS */
db_setItem(record, key, DB_flag_ptr | DB_flag_dataInternal, data, &error);
return error;
}
/* ======== structural operations ======== */
/*
* Create a new record.
*
* The only bits of 'flags' used are the persistent flags and
* DB_flag_rec/DB_flag_set.
*/
static RecordPtr
db_createNewRecord (RecordPtr rec, const BYTE* key, UINT16 flags, ElementPtr prev,
UINT8 *errorCode)
{
RecordPtr newRec;
BYTE* s;
int len;
if (rec == db_root) {
if (flags & DB_mask_writeThrough)
/* Write-through and backup cannot be active at the same time */
flags &= ~DB_flag_backup;
} else
/* Inherit the parent's persistent status */
flags = flags & ~ DB_mask_persistent | rec->flags & DB_mask_persistent;
/* Create record */
if (flags & DB_mask_writeThrough)
newRec = (RecordPtr) OSConnectorAlloc(sizeof(RecordBlock));
else
newRec = (RecordPtr) OSConnectorAlloc(sizeof(Record));
#ifndef HAS_SETJMP
if (newRec == NULL) {
*errorCode = DB_err_outOfMemory;
return NULL;
}
#endif
/* Copy key */
for (s=newRec->key, len=1; *s = *key; s++, key++, len++)
if (len == DB_keyLen) {
OSConnectorFree(newRec);
*errorCode = DB_err_tooLongKey;
return NULL;
}
/* Init data */
newRec->data.r = newRec;
newRec->flags = flags & DB_mask_persistent;
if ((flags & DB_mask_type) == DB_flag_rec) /* BOOKMARK:FLAGS */
newRec->flags |= DB_flag_rec | DB_flag_key | DB_flag_dataChild; /* rec */
else
newRec->flags |= DB_flag_set | DB_flag_key | DB_flag_dataChild; /* set */
newRec->ref = ++recordNbr;
/* Add element */
newRec->nextRec = refHashTable[recordNbr & DB_refHashMask];
refHashTable[recordNbr & DB_refHashMask] = newRec;
if (prev == NULL)
db_addBelow(rec, (ElementPtr) newRec);
else
db_addAfter(prev, (ElementPtr) newRec);
/* Save element, if write-through */
*errorCode = DB_err_success;
if (flags & DB_mask_writeThrough && ! db_serviceMode) {
((RecordBlockPtr) newRec)->blockId = 0;
if (! db_saveElement_wt(rec, (ElementPtr) newRec, prev))
/* No persistent save, set warning. Anyway, the record was created. */
*errorCode = DB_err_noPersistentSave;
}
return newRec;
}
/*
* Create a new record. If a field with the same name exists, an
* error will be generated, except when the parent record is a
* set. If 'flags' bit 0 is set, it signals this is a set, not a
* record. This can be done by using paramater DB_set instead of
* DB_rec for record.
*
* 'errorCode' returns the status of the function. DB_err_success
* when the operation i successfully completed.
*
* If 'key' is NULL, the key of the new record will be an empty
* string.
*/
DB_ref
db_createRecord (DB_ref record, const BYTE* key, UINT16 flags, UINT8 *errorCode)
{
RecordPtr newRec;
RecordPtr rec;
if (recordNbr == DB_max) {
*errorCode = DB_err_outOfRefs;
return DB_null;
}
rec = db_findRecord(record);
if (rec == NULL) {
*errorCode = DB_err_record;
return DB_null;
}
if ((rec->flags & DB_mask_type) == DB_flag_rec && db_findField(key)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -