⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wipdb.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * Copyright (C) Ericsson Mobile Communications AB, 2000.
 * Licensed to AU-System AB.
 * All rights reserved.
 *
 * This software is covered by the license agreement between
 * the end user and AU-System AB, and may be used and copied
 * only in accordance with the terms of the said agreement.
 *
 * Neither Ericsson Mobile Communications AB nor AU-System AB
 * assumes any responsibility or liability for any errors or inaccuracies in
 * this software, or any consequential, incidental or indirect damage arising
 * out of the use of the Generic WAP Client software.
 */
/*
 * wipdb.c
 *
 * Simple database system.
 *
 *
 * Created by Niclas Kellgren 000606.
 *
 * Revision history:
 *   000703  NKE  first version
 *   000728  NKE  data channel handling added
 *   000804  NKE  data channel handling updated 
 *   000807  NKE  new data channel functions added
 *   000809  NKE  bugfixes
 *   000817  NKE  the object template is changed into a general object
 *   000822  NKE  constants for default fields changed
 *   000906  NKE  pattern matching added for getDataChannel
 *   000914  NKE  data channel handling moved to dbFunct.c
 *   001013  NKE  added persistent memory handling
 *   001101  NKE  write through rewritten
 *   001114  NKE  bugfixes and minor updates
 *   001212  NKE  corrected db_saveElement_wt
 *   010219  NKE  added db prefix to functions
 *   010301  NKE  major restructuring: changed underlying datastructure,
                  removed recursion and added db_getElementData
 *   010302  NKE  added persistent backup handling
 *   010309  NKE  added db_createStr and db_createMem
 *   010314  NKE  corrected db_setItem
 *   010320  NKE  corrected db_getElementData
 *   010321  NKE  minor corrections
 *   010514  NKE  added db_moveRecord	and some enhancements to handle backup/write-through
 *                conflicts generated by the new function.
 */

#include "wipdb.h"



/*************
 * Constants *
 *************/

/* 16-bit flag field

  pos len use
  ------------------
  0-2  3  type
   3   1  key present
   4   1  backup
   5   1  write-through
  6-7  2  data use, compactation of 'type'; what the 'data' field is used for
          rec,set = has child; int, ptr = internal data; str,mem = external data
   8   1  last element in list
   9   1  temporary flag. Signals last element in list and is a copy of bit 8,
          during the backup process. Is also used as a signal to db_copyRecord.

  Only one of the backup and write-through flags can be set at the same time. 

  If more flags are added, be careful to update all places where they are used.
  Search for BOOKMARK:FLAGS.
*/

enum DB_ElementType {
  DB_flag_rec          = 0x0000,
  DB_flag_set          = 0x0001, 
  DB_flag_int          = 0x0002,
  DB_flag_str          = 0x0003,
  DB_flag_mem          = 0x0004,
  DB_flag_ptr          = 0x0005,

  DB_flag_key          = 0x0008,

  DB_flag_backup       = 0x0010,
  DB_flag_writeThrough = 0x0020,

  DB_flag_dataChild    = 0x0000,
  DB_flag_dataInternal = 0x0040,
  DB_flag_dataExternal = 0x0080,

  DB_flag_lastElement  = 0x0100,
  DB_flag_temporary    = 0x0200,

  /* These flags are only used during backup. They reuse backup
   * and writeThrough bits. */
  DB_flag_lastElement2 = DB_flag_temporary,
  DB_flag_hasChild     = DB_flag_backup,
  DB_flag_endOfBuffer  = DB_flag_writeThrough,
	DB_flag_rootLevel		 = DB_flag_lastElement,
	/* The temporary flag is in db_copyRecord to treat str and
	 * mem pointers as ptr, i.e. only copy the pointer and not
	 * the data pointed out. */
  DB_flag_move         = DB_flag_temporary
};


enum MaskType {
  DB_mask_type         = 0x0007,

  DB_mask_key          = DB_flag_key,

  DB_mask_backup       = DB_flag_backup,
  DB_mask_writeThrough = DB_flag_writeThrough,
  DB_mask_persistent   = DB_flag_backup | DB_flag_writeThrough,

  DB_mask_dataUse      = 0x00C0,

  DB_mask_lastElement  = DB_flag_lastElement,

  DB_mask_lastElement2 = DB_flag_lastElement2,
  DB_mask_hasChild     = DB_flag_hasChild,
  DB_mask_endOfBuffer  = DB_flag_endOfBuffer,
	DB_mask_rootLevel    = DB_flag_rootLevel,
  DB_mask_move         = DB_flag_move
};


enum {
  DB_max  = DB_root-1,                   /* Maximum number of created records.                */

  DB_refHashSize = 32,                   /* Must be 2**n, unsigned int n, n > 0.              */
  DB_refHashMask = 32 - 1,               /* Must be DB_refHashSize - 1.                       */

  DB_keyLen = 6                          /* Element key length. Must be at least 6 long.      */
};


#define BUFSIZE 64                       /* Size of persistent storage buffer. Must fit
                                          * everything but the data and be multiple of 8.     */

#define GOING_UP    0
#define GOING_DOWN  1
#define GOING_RIGHT 2


/*********
 * Types *
 *********/

typedef union {
  UINT32                i;
  void*                 p;
  BYTE*                 s;
  struct RecordStruct*  r;
  struct FieldStruct*   f;
  struct ElementStruct* e;

} DataUnion;


typedef struct ElementStruct* ElementPtr;
typedef struct ElementStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;

} Element;

typedef struct ElementBlockStruct* ElementBlockPtr;
typedef struct ElementBlockStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;
  UINT32     blockId;

} ElementBlock;



typedef struct FieldStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;
  BYTE       key[DB_keyLen];

} Field, *FieldPtr;

typedef struct FieldBlockStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;
  BYTE       key[DB_keyLen];
  UINT32     blockId;

} FieldBlock, *FieldBlockPtr;



typedef struct RecordStruct* RecordPtr;
typedef struct RecordStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;
  BYTE       key[DB_keyLen];
  UINT16     ref;
  RecordPtr  nextRec; 

} Record;

typedef struct RecordBlockStruct* RecordBlockPtr;
typedef struct RecordBlockStruct {
  ElementPtr next;
  DataUnion  data;
  UINT16     flags;
  BYTE       key[DB_keyLen];
  UINT16     ref;
  RecordPtr  nextRec; 
  UINT32     blockId;

} RecordBlock;


/*************
 * Variables *
 *************/

static RecordPtr* refHashTable;            /* Hash table of liked list. RecordPtr.nextRec.     */
static DB_ref     recordNbr = 0;           /* Record counter. Null reference is number 0.      */

static RecordPtr  db_root;                 /* Pointer to database root element.                */

static RecordPtr  currentRecord = NULL;    /* Used by db_findField/db_deleteElement.           */
static DB_ref     currentRef    = DB_null; /* Matches currentRecord. Used for caching.         */

static ElementPtr currentElement;          /* Carries information between several functions:
                                            * from db_findField and db_deleteItem_ptr to 
                                            * db_findRecord, db_deleteElement.                 */

static ElementPtr prevElement;             /* Carries information between several functions:
                                            * from db_findField and db_deleteItem_ptr to 
                                            * db_deleteElement                                 */

static StorageObject store;                /* Main object used by storage.c                    */

static BOOL       db_serviceMode;          /* Is set to TRUE at startup or shutdown. Protects
                                            * presistent memory during rebuild or close-down.  */

static BOOL       db_saveDataMode;         /* When set to TRUE, db_deleteItem, db_deleteItem_ptr
                                            * and db_clearRecord will not remove data poined out
                                            * by a mem or str type. They are treated as ptr.   */

static UINT32*    idArr;                   /* Pointer to list of ids of elments on persistent
                                            * memory. Only used during startup.                */

/************************
 * Forward declarations *
 ************************/

UINT8 db_deleteItem_ptr (RecordPtr rec, ElementPtr element);
static UINT32 db_getBlockId(ElementPtr element);
static void db_deleteElement_wt(RecordPtr parent, ElementPtr current, ElementPtr prev);
static BOOL db_saveElement_wt(RecordPtr parent, ElementPtr element, ElementPtr prev);
static BOOL db_loadDB_wt(void);
static void db_saveDB_bu(void);
static BOOL db_loadDB_bu (void);

/*************
 * Functions *
 *************/

/* ============================================ */
/* ==========  Main functionality  ============ */
/* ============================================ */


/*
  This module contains the main functionality of the database.
  It has five parts:

  * help functions
  * get
  * set
  * structural operations
  * administration


  FUNCTIONS

  A list of the most important functions:

  * help functions
  db_findRecord
  db_findField
  db_findPrev_wt
  db_addBelow
  db_addAfter
  db_deleteContent
  db_deleteElement

  * get
  db_getElementData
  db_getRef
  db_getType

  * set
  db_createNewElement
  db_setItem
  db_setInt
  db_setStr
  db_setMem
  db_setPtr

  * structural operations
  db_createNewRecord
  db_createRecord
  db_copyRecord
  db_deleteItem
  db_deleteItem_ptr
  db_clearRecord
  db_moveToFront

  * administration
  db_dbInit
  db_dbTerminate
  
  
*/

/* ======== help functions ======== */


/*
 * Search hash structure for record. Sets currentRecord and 
 * currentRef. Must be called prior to db_findField.
 */
RecordPtr 
db_findRecord (DB_ref record)
{
	RecordPtr rec;
	
	if (record == currentRef) /* Speed up the most common case by caching */
		return currentRecord;
	rec = refHashTable[record & DB_refHashMask];
	while (TRUE) {
		if (rec == NULL) {
			currentRef = DB_null;
			break;
		} else if (rec->ref == record) {
			currentRef = record;
			break;
		} else
			rec = rec->nextRec;
	}
	currentRecord = rec;
	return currentRecord;
}



/*
 * Find field named 'key' if present, else return NULL. Sets 
 * currentElement and prevElement. currentRecord defines the record
 * to search and db_findRecord must be called first to set it.
 *
 * Can only be used on records, NOT on sets. Depends on currentRecord.
 */
FieldPtr 
db_findField (const BYTE* key) 
{
	const BYTE* t;
	BYTE*       s;

	prevElement = NULL;
	if (key == NULL)
		return NULL;
	if ((currentRecord->flags & DB_mask_type) != DB_flag_rec)
		return NULL;

	currentElement = currentRecord->data.e;
	while (currentElement != (ElementPtr) currentRecord) {
		for (s = ((FieldPtr) currentElement)->key, t = key; *s == *t; s++, t++)
			if (*s == '\0')
				return (FieldPtr) currentElement;
		prevElement = currentElement;
		currentElement = currentElement->next;
	}
	currentElement = NULL;
	return NULL;
}



/*
 * Find the closest predecessor to currentElement with
 * write-through flag set at root level.
 */
static ElementPtr 
db_findPrev_wt (ElementPtr element) 
{
	ElementPtr prev;
	ElementPtr current;

	prev = NULL;
	current = db_root->data.e;
	while (current != (ElementPtr) db_root) {
		if (current == element)
			return prev;
		if (current->flags & DB_mask_lastElement)
			prev = current;
		current = current->next;
	}
	return NULL;
}



/*
 * Insert a new element 'newElement' below 'rec'.
 */
static void 
db_addBelow (RecordPtr rec, ElementPtr newElement)
{
	if (rec->data.e == (ElementPtr) rec)
		newElement->flags |=   DB_flag_lastElement;
	else
		newElement->flags &= ~ DB_flag_lastElement;
	
	newElement->next = rec->data.e;
	rec->data.e = newElement;
}



/*
 * Insert a new element 'newElement' after 'element'.
 */
static void 
db_addAfter (ElementPtr element, ElementPtr newElement)
{
	if (element->flags & DB_mask_lastElement) {
		element->flags &= ~ DB_flag_lastElement;
		newElement->flags |= DB_flag_lastElement;
	} else
		newElement->flags &= ~ DB_flag_lastElement;

	newElement->next = element->next;
	element->next = newElement;
}



/*
 * Remove 'current' element from reference hash list. Used by
 * db_deleteContent and db_deleteElement;
 */
static void 
db_removeElementRef (ElementPtr current)
{
	RecordPtr  rec;
	RecordPtr* prevPtr;

	prevPtr = refHashTable + (((RecordPtr) current)->ref & DB_refHashMask);
	rec = *prevPtr;
	while (rec->ref != ((RecordPtr) current)->ref) {
		prevPtr = &rec->nextRec; 
		rec = rec->nextRec;
	}
	*prevPtr = rec->nextRec;
}



/*
 * Delete entire subtree, excluding 'rec' root element. Does
 * not update rec->data.e. Preserves ref hash structure.
 *
 * Elements are removed bottom up non-recursively. If 'saveData'
 * is TRUE, then external data is not deleted.
 *
 * This is a utility function, intended to be used by other
 * functions. Use db_clearRecord if you want to delete all
 * fields of a record and preserv write-through consistency.
 */
static void 
db_deleteContent (RecordPtr rec, BOOL saveData)
{
	ElementPtr current;
	ElementPtr prev;
	UINT32     id;

	current = rec->data.e;
	while (current != (ElementPtr) rec) {
		switch (current->flags & DB_mask_dataUse) {
		case DB_flag_dataChild:
			if (current->data.e != current) {
				/* This element has a child and cannot be removed (yet) */
				current = current->data.e;
				continue;
			} else
				db_removeElementRef(current);
			break;

		case DB_flag_dataExternal:
			if (! saveData)
				OSConnectorFree(current->data.s);
		}

		if (current->flags & DB_mask_writeThrough && ! db_serviceMode) {
			id = db_getBlockId(current);
			Storage_DeleteBlock(&store, id); 
		}

		prev = current;
		current = current->next;
		if (prev->flags & DB_mask_lastElement)	/* Finished one level */
			current->data.e = current; /* Mark this record as empty, i.e. deletable */
		OSConnectorFree(prev);
	}
}



/*
 * Delete currentElement. If it is a record or set, use 
 * db_deleteContent to remove the subtree. Preserves ref hash 
 * structure. If 'saveData' is TRUE, then external data is
 * not deleted.
 *
 * Depends on currentElement, currentRecord, prevElement. If
 * you change currentRecord, don't forget to update currentRef.
 */
static void 
db_deleteElement (BOOL saveData)
{
	if (currentElement->flags & DB_mask_writeThrough && ! db_serviceMode)
		db_deleteElement_wt(currentRecord, currentElement, prevElement);

	if (prevElement == NULL)
		currentRecord->data.e = currentElement->next;
	else {
		prevElement->next = currentElement->next;
		if (prevElement->next == (ElementPtr) currentRecord)
			prevElement->flags |= DB_flag_lastElement;
	}

	switch (currentElement->flags & DB_mask_dataUse) {
	case DB_flag_dataChild:
		db_removeElementRef(currentElement);
		
		if (currentElement->data.e != currentElement)
			db_deleteContent((RecordPtr) currentElement, saveData);
		break;

	case DB_flag_dataExternal:
		if (! saveData)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -