diff src/aci2/aci/db.c @ 3:93999a60b835

src/aci2, src/condat2: import of g23m/condat source pieces from TCS211
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 26 Sep 2016 00:29:36 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/aci2/aci/db.c	Mon Sep 26 00:29:36 2016 +0000
@@ -0,0 +1,5258 @@
+/* 
++----------------------------------------------------------------------------- 
+|  Project :  PHB
+|  Modul   :  DBM
++----------------------------------------------------------------------------- 
+|  Copyright 2005 Texas Instruments Berlin, AG 
+|                 All rights reserved. 
+| 
+|                 This file is confidential and a trade secret of Texas 
+|                 Instruments Berlin, AG 
+|                 The receipt of or possession of this file does not convey 
+|                 any rights to reproduce or disclose its contents or to 
+|                 manufacture, use, or sell anything it may describe, in 
+|                 whole, or in part, without the specific written consent of 
+|                 Texas Instruments Berlin, AG. 
++----------------------------------------------------------------------------- 
+|  Purpose :  Implementation of DBM functions
++----------------------------------------------------------------------------- 
+*/ 
+
+#ifdef TI_PS_FFS_PHB
+
+#include "db_int.h"
+#include <string.h>
+
+/* For DB Testing */
+
+/* Check if we are closing FFS files properly */
+#define DB_TEST
+
+/* A simple check to make sure that all allocated 
+   memory is freed to avoid memory leak */
+#define DB_MEMORY_CHECK
+
+/* if dir is not empty during deletion, we do not
+   raise the error, rather we go ahead and remove 
+   all the contents and then delete the dir */
+#define FORCED_DIR_REMOVAL
+
+/**************************
+  D E F I N I T I O N S & 
+  D E C L A R A T I O N S
+ **************************/
+
+
+GLOBAL UBYTE              UsedDBs;								          /* Number of existing databases  */
+GLOBAL int                LastFFS_ReturnCode;			          /* Last FFS return code          */
+GLOBAL T_DBM_MASTERRECORD DbmMaster [MAX_DBs];              /* Database Master               */
+GLOBAL T_DBM_STATE        DBM_State = DBM_NOT_INITIALISED;  /* DBM State                     */
+GLOBAL T_DB_CHANGED       DB_History_log;                   /* History log                   */
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+
+  T_FFS_FD Dummy_FFSFileHandle = NULL;
+  #define INVALID_FLD_CTR  0xFF
+  #define NOT_OPENED       0x00
+  #define OPENED_FOR_READ  0x01
+  #define OPENED_FOR_WRITE 0x02
+
+#endif
+
+#ifdef DB_TEST
+
+  S8 db_test_ffs_open_ctr = 0; 
+  T_FFS_SIZE db_test_ffs_ret_code = EFFS_OK;
+
+  #define DB_FFS_OPEN( ret, file, flag ) \
+  { \
+    ret = ffs_open( file, flag ); \
+    \
+    if( ret >= EFFS_OK ) \
+    { \
+      ++db_test_ffs_open_ctr; \
+      TRACE_EVENT_P1( "DB_FFS_OPEN:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \
+    } else { \
+      TRACE_EVENT_P1( "DB_FFS_OPEN:FFS ERROR:%d", ret ); \
+    } \
+  }
+
+
+  #define DB_FFS_CLOSE( fd ) \
+  { \
+    T_FFS_SIZE db_test_ffs_ret_code = ffs_close( fd ); \
+    \
+    if( db_test_ffs_ret_code >= EFFS_OK ) \
+    { \
+      --db_test_ffs_open_ctr; \
+      TRACE_EVENT_P1( "DB_FFS_CLOSE:db_test_ffs_open_ctr:%d", db_test_ffs_open_ctr ); \
+    } else { \
+      TRACE_EVENT_P1( "DB_FFS_CLOSE:FFS ERROR:%d", db_test_ffs_ret_code ); \
+    } \
+    \
+    fd = NULL; \
+  }
+
+  #define DB_RETURN( ret ) \
+  { \
+    TRACE_EVENT_P1( "DB_RETURN:ret:%d", ret ); \
+    return ret; \
+  }
+ 
+  #define DB_VALUE_RETURN( ret ) \
+  { \
+    TRACE_EVENT_P1( "DB_VALUE_RETURN:ret:%d", ret ); \
+    return ret; \
+  }
+ 
+#else
+
+  #define DB_FFS_OPEN( ret, file, flag ) ret = ffs_open( file, flag )
+  #define DB_FFS_CLOSE( fd ) { ffs_close( fd ); fd = NULL; }
+  #define DB_RETURN( ret ) return ret
+  #define DB_VALUE_RETURN( ret ) return ret
+
+#endif
+
+#ifdef DB_MEMORY_CHECK
+
+  UBYTE alloc_ctr = 0;
+
+  #define DB_MALLOC( ptr, num_of_bytes ) \
+  { \
+    ++alloc_ctr; \
+    TRACE_EVENT_P1( "DB Memory Alloc:%d", alloc_ctr ); \
+    ACI_MALLOC( ptr, num_of_bytes ); \
+  }
+
+  #define DB_MFREE( ptr ) \
+  { \
+    --alloc_ctr; \
+    TRACE_EVENT_P1( "DB Memory Free:%d", alloc_ctr ); \
+    ACI_MFREE( ptr ); \
+  }
+
+#else
+
+  #define DB_MALLOC( ptr, num_of_bytes ) ACI_MALLOC( ptr, num_of_bytes )
+  #define DB_MFREE( ptr ) ACI_MFREE( ptr ) 
+
+#endif
+
+
+#ifdef _SIMULATION_
+  #define DB_DIR "/dbm"
+  #define DB_MASTER_FILE "/dbm/DD_master"
+#else
+  #define DB_DIR "/gsm/dbm" 
+  #define DB_MASTER_FILE "/gsm/dbm/DD_master"
+#endif
+
+#define FILENAME_LEN 40
+
+#define T_DB_MASTER_RECORD_SIZE 18        
+/* DBM master record
+   File: DB_DIR/DD_master
+   Data: 
+      1)	DBDirectory (16 bytes, based on MAX_LEN_DIRECTORY=16)
+      2)	NumOfFiles (1 byte, based on MAX_NUM_FILES=255)
+      3)	Tracked (1 byte)
+ */
+
+
+#define T_DB_FIELD_RECORD_SIZE 43         
+/* Based on the following data written into FFS 
+   File: DB_DIR/DD_<DBDirectory>
+   Data: 
+    1)	FieldID (2 bytes, given in Interface)
+    2)	DBType (1 byte)
+    3)	RecordSize (2 bytes, based on MAX_RECORD_SIZE=65kb)
+    4)	NumOfRecords (1 byte, based on MAX_NUM_RECORDS=255)
+    5)	SortIndexes (MAX_NUM_OF_SORT_INDEXS bytes, 1 byte for each index )
+    6)	RecordBitMap (32 bytes, as of now based on MAX_NUM_RECORDS=255)
+    7)	Clean (1 byte, this can be clubbed with DBType )
+ */
+
+#define RecordBitMap_OFFSET 10  /* depending on structure in DB_DIR/DD_<DBDirectory> */
+
+#define SortIndexList_OFFSET 6  /* depending on structure in DB_DIR/DD_<DBDirectory> */
+
+#define QuickSort_BufferStackSize 8 /* For Non recursive quick sort, 
+                                         allows sorting of 2 ^ 8 = 256 elements */
+
+#define SEARCH_FAILED -1
+
+#define MAX_BIT_POS 8
+
+#define BITMAP_INDEX( num ) ( ( num - 1 ) / MAX_BIT_POS )
+#define BIT_POS( num ) ( ( num - 1 ) % MAX_BIT_POS )
+
+/* For RAM strctures */
+#define TRACKED_AND_CLEAN 0x03
+
+#define TRACKED 0x02
+
+#define CLEAN 0x01
+
+#define NOT_CLEAN 0x00
+
+/* For FFS strctures */
+#define FFS_TRACKED 0x01
+
+#define FFS_NOT_TRACKED 0x00
+
+#define NOT !
+
+#define INVALID_RECORD_NUM 0xFF
+
+/*
+    Internal function to initialize RAM structures with FFS
+ */
+T_DB_CODE init_RAM_with_FFS ( void );
+
+#define	DBM_State_check \
+  if ( DBM_State EQ DBM_NOT_INITIALISED ) DB_RETURN( DB_NOT_INITIALISED );
+
+T_DB_CODE db_handle_check ( int db_handle );
+
+UBYTE field_id_search ( int db_handle, 
+                        USHORT field_id );
+
+T_DB_CODE update_history_log ( int    db_handle,
+                               USHORT field_id,
+                               USHORT record_num );
+
+/* functions swap and parition are required for sorting */
+void swap ( UBYTE* sort_list,
+            UBYTE  low,
+            UBYTE  high );
+
+UBYTE split_list ( UBYTE*        sort_list,
+                   UBYTE         low,
+                   UBYTE         high,
+                   T_COMP_FUNC   compare_function, 
+                   ULONG         flags,
+                   int           db_handle,
+                   USHORT        field_id );
+
+void quick_sort ( UBYTE*        sort_list,
+                  UBYTE         num_of_elements,
+                  T_COMP_FUNC   compare_function, 
+                  ULONG         flags,
+                  int           db_handle,
+                  USHORT        field_id ); 
+
+UBYTE search_clear_bit_in_bitmap ( UBYTE* bitmap,
+                                   UBYTE  bitmap_size );
+
+void set_bit_in_bitmap ( UBYTE* bitmap,
+                         UBYTE  bitmap_size,
+                         UBYTE  bit_num );
+
+void reset_bit_in_bitmap ( UBYTE* bitmap,
+                           UBYTE  bitmap_size,
+                           UBYTE  bit_num );
+
+T_DB_CODE populate_sorted_list_from_FFS ( 
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                          UBYTE db_ctr,
+#endif
+                                          char*   sort_file,
+                                          UBYTE   num_of_elements,
+                                          UBYTE** sort_list_ptr );
+
+T_DB_CODE write_sorted_list_to_FFS ( 
+                                     
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE db_ctr,
+#endif
+                                     char*   sort_file,
+                                     UBYTE   num_of_elements,
+                                     UBYTE*  sort_list );
+
+int search ( UBYTE*            sort_list,
+             UBYTE             num_of_elements,
+             UBYTE*            order_num,
+             T_SEARCH_FUNC     search_function, 
+             ULONG             flags, 
+             const UBYTE*      search_tag,
+             int               db_handle,
+             USHORT            field_id );
+
+T_DB_CODE update_field_data_in_FFS ( const char* field_file,
+                                     T_FFS_FD*   filehandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE       db_ctr,
+#endif
+                                     UBYTE       fld_ctr,
+                                     UBYTE       field_data_max_size,
+                                     UBYTE*      field_data,
+                                     USHORT      offset,
+                                     USHORT      length );
+
+UBYTE cal_NextRecordNum ( const char* DBDirectory, 
+                          USHORT	     FieldID,
+                          USHORT	     RecordSize );
+
+T_DB_CODE read_user_record_from_FFS ( const char* user_field_file,
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                      UBYTE       db_ctr,
+                                      UBYTE       fld_ctr,
+#endif
+                                      T_FFS_FD*   filehandle,
+                                      UBYTE       record_num,
+                                      USHORT      record_size,
+                                      USHORT      offset,
+                                      USHORT      length,
+                                      UBYTE*      record_buffer );
+
+T_DB_CODE write_user_record_to_FFS ( const char* user_field_file,
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE       db_ctr,
+                                     UBYTE       fld_ctr,
+#endif
+                                     T_FFS_FD*   filehandle,
+                                     UBYTE       record_num,
+                                     USHORT      record_size,
+                                     USHORT      offset,
+                                     USHORT      length,
+                                     UBYTE*      record_buffer );
+
+T_DB_CODE delete_file_dir_from_FFS ( const char* filename );
+
+T_DB_CODE update_dbm_data_in_FFS ( const char* filename,
+                                   UBYTE       db_ctr,
+                                   UBYTE       db_data_max_size,
+                                   UBYTE*      db_data,
+                                   USHORT      offset,
+                                   USHORT      length );
+
+T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr,
+                                  UBYTE fld_ctr );
+
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+
+T_FFS_FD db_open_user_field_file ( UBYTE            db_ctr, 
+                                   UBYTE            fld_ctr, 
+                                   const char*      user_field_file,
+                                   T_FFS_OPEN_FLAGS open_option );
+
+
+void db_close_user_field_files ( UBYTE db_ctr );
+
+BOOL db_open_full_for_read ( UBYTE db_ctr );
+
+BOOL db_open_full_for_write ( UBYTE db_ctr );
+
+void db_close_for_write ( UBYTE db_ctr );
+
+void db_close_for_read ( UBYTE db_ctr );
+
+UBYTE db_status_user_field_file ( UBYTE db_ctr,
+                                  UBYTE fld_ctr );
+
+
+#endif /* FFS_CLOSE_BEFORE_OPEN */
+
+
+#ifdef FORCED_DIR_REMOVAL
+
+T_DB_CODE delete_dir_forced ( const char* filename );
+
+#endif /* FORCED_DIR_REMOVAL */
+
+#ifdef INSERTION_SORT
+
+void get_sort_lists_from_FFS ( UBYTE db_ctr,
+                               UBYTE fld_ctr );
+
+void new_in_sort_lists ( UBYTE db_ctr,
+                         UBYTE fld_ctr,
+                         UBYTE record_num );
+
+void update_in_sort_lists ( UBYTE db_ctr,
+                            UBYTE fld_ctr,
+                            UBYTE record_num );
+
+void delete_in_sort_lists ( UBYTE db_ctr,
+                            UBYTE fld_ctr,
+                            UBYTE record_num );
+
+void insertion_sort ( UBYTE*        sort_list,
+                      UBYTE         num_of_elements,
+                      T_COMP_FUNC   compare_function, 
+                      ULONG         flags,
+                      int           db_handle,
+                      USHORT        field_id ); 
+
+void insert_element ( UBYTE*        sort_list,
+                      UBYTE         num_of_elements,
+                      UBYTE         bottom,
+                      UBYTE         top,
+                      UBYTE         record_num,
+                      T_COMP_FUNC   compare_function, 
+                      ULONG         flags,
+                      int           db_handle,
+                      USHORT        field_id );
+
+#endif /* INSERTION_SORT */
+
+T_DB_CODE internal_db_sort ( int          db_handle, 
+                             USHORT       field_id, 
+                             UBYTE        sort_index, 
+                             T_COMP_FUNC  compare_function, 
+                             ULONG        flags,
+                             T_DB_SORT    sort_type );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/******************************
+  I M P L E M E N T A T I O N 
+ ******************************/
+
+/**********************/
+/* INTERNAL FUNCTIONS */
+/**********************/
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_handle_check      |
++--------------------------------------------------------------------+
+
+    PURPOSE : DB Handle checks
+*/
+
+T_DB_CODE db_handle_check ( int db_handle )
+{
+  /* Check for db_handle range */
+  if( db_handle >= MAX_DBs )
+    return DB_INVALID_DB;
+  
+  /* Check for DBState of db_handle is CLOSED or UNUSED_ENTRY
+     If yes, return DB_INVALID_DB  */
+
+  if( ( DbmMaster[db_handle].DBState EQ CLOSED       ) OR
+      ( DbmMaster[db_handle].DBState EQ UNUSED_ENTRY ) )
+    return DB_INVALID_DB;
+  
+  return DB_OK;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: field_id_search      |
++--------------------------------------------------------------------+
+
+    PURPOSE : checks for the existence of field id in RAM
+*/
+UBYTE field_id_search ( int     db_handle, 
+                        USHORT  field_id )
+{
+  UBYTE  fld_ctr;
+  
+  for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
+  {
+    if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ field_id )
+    {
+      return fld_ctr;
+    }
+  }
+  return fld_ctr;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: update_history_log   |
++--------------------------------------------------------------------+
+
+    PURPOSE : Updating history log
+*/
+T_DB_CODE update_history_log ( int    db_handle,
+                               USHORT field_id,
+                               USHORT record_num )
+{
+  UBYTE i;
+
+  /* Check if database is tracked */
+  if( NOT ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) ) /* if db is NOT tracked */
+    return DB_OK;
+
+  /* Search history log if the record is present
+     If present, return DB_OK */
+  for( i = 0; i < DB_History_log.entries; ++i )
+  {
+    if( DB_History_log.field_id[i] EQ field_id )
+      if( DB_History_log.record[i] EQ record_num )
+        return DB_OK;
+  }
+
+  /* If the number of existing logs in history is reached limit, DB_MAX_AFFECTED, 
+     return error "DB_HISTORY_FULL". */
+  if( DB_History_log.entries EQ DB_MAX_AFFECTED )
+    return DB_HISTORY_FULL;
+
+  /* Add new entry */
+  DB_History_log.field_id [DB_History_log.entries] = field_id;
+  DB_History_log.record [DB_History_log.entries] = record_num;
+  ++DB_History_log.entries;
+
+  return DB_OK;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: swap                 |
++--------------------------------------------------------------------+
+
+    PURPOSE : Swaps the data
+*/
+void swap ( UBYTE* sort_list,
+            UBYTE  low,
+            UBYTE  high )
+{
+  UBYTE tmp = sort_list[low - 1];
+
+  sort_list[low - 1] = sort_list[high - 1];
+  sort_list[high - 1] = tmp;
+
+  return;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: split_list            |
++--------------------------------------------------------------------+
+
+    PURPOSE : 
+*/
+UBYTE split_list ( UBYTE*        sort_list,
+                   UBYTE         low,
+                   UBYTE         high,
+                   T_COMP_FUNC   compare_function, 
+                   ULONG         flags,
+                   int           db_handle,
+                   USHORT        field_id ) 
+{
+  UBYTE i,
+        pivot_loc;
+
+  /* put pivot at first position */
+  swap( sort_list, low, (UBYTE)((low + high)/2));
+
+  pivot_loc = low;
+
+  for( i = low + 1; i <= high; ++i )
+  {
+    if( compare_function( db_handle, 
+                          field_id,
+                          sort_list[i - 1],
+                          sort_list[low - 1],
+                          flags ) 
+        < 0 )
+    {
+      ++pivot_loc;
+      swap( sort_list, pivot_loc, i );
+    }
+  }
+
+  swap( sort_list, low, pivot_loc );
+
+  return pivot_loc;
+}
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: quick_sort           |
++--------------------------------------------------------------------+
+
+    PURPOSE : Sorts the user data records in FFS based 
+              on non-recursive qsort method
+*/
+void quick_sort ( UBYTE*        sort_list,
+                  UBYTE         num_of_elements,
+                  T_COMP_FUNC   compare_function, 
+                  ULONG         flags,
+                  int           db_handle,
+                  USHORT        field_id )
+{
+  /* This is non-recursive version of QuickSort
+
+     - It requires additional storage of (2 * QuickSort_BufferStackSize) bytes 
+       compared to recursive version of quick sort
+     
+     - It supports sorting of 2 ^ QuickSort_BufferStackSize elements. */
+
+  /* It is assumed that MAX_NUM_RECORDS = 254;if we want to support the 
+     sorting of list bigger than 254 elements, change following UBYTE 
+     to U16, U32 etc. and update QuickSort_BufferStackSize accordingly ! */
+
+  UBYTE low,
+        high,
+        pivot_loc,
+        buff_stack_ctr = 0,
+        buffer_low[QuickSort_BufferStackSize],
+        buffer_high[QuickSort_BufferStackSize];
+
+  low = 1;
+  high = num_of_elements;
+
+  do 
+  {
+    if( buff_stack_ctr > 0 ) 
+    {
+      --buff_stack_ctr;
+      low  = buffer_low[buff_stack_ctr];
+      high = buffer_high[buff_stack_ctr];
+    }
+
+    while( low < high )
+    {
+      pivot_loc = split_list( sort_list, 
+                              low, 
+                              high,
+                              compare_function,
+                              flags,
+                              db_handle, 
+                              field_id );
+
+      if( buff_stack_ctr >= QuickSort_BufferStackSize )
+      {
+        /* This should never happen ! */
+        TRACE_ERROR( "Value set for QuickSort_BufferStackSize is small !");
+        return;
+      }
+
+      /* Remember larger sublist, and process smaller */
+
+      if( (pivot_loc - low) < (high - pivot_loc) )
+      {
+        /* right list is bigger */
+        buffer_low[buff_stack_ctr] = pivot_loc + 1;
+        buffer_high[buff_stack_ctr] = high;
+        ++buff_stack_ctr;
+        high = pivot_loc - 1;
+
+      } else {
+        /* left list is bigger */
+        buffer_low[buff_stack_ctr] = low;
+        buffer_high[buff_stack_ctr] = pivot_loc - 1;
+        ++buff_stack_ctr;
+        low = pivot_loc + 1;
+
+      }
+    }
+  } while( buff_stack_ctr != 0 );
+
+  return;
+}
+
+/*
++-------------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                             |
+|                                       ROUINE: search_clear_bit_in_bitmap      |
++-------------------------------------------------------------------------------+
+
+    PURPOSE : Searches for the bit not set in record bitmap which 
+              indicates free record 
+*/
+UBYTE search_clear_bit_in_bitmap ( UBYTE* bitmap,
+                                   UBYTE  bitmap_size )
+{
+  UBYTE* tmp_byte_ptr = bitmap + bitmap_size - 1 ;
+  UBYTE  bitmap_num = 0, 
+         bit_num,
+         tmp_byte;
+
+  /* we will go byte by byte */
+  while( bitmap_num < ( bitmap_size * MAX_BIT_POS ) )
+  {
+    tmp_byte = *tmp_byte_ptr;
+
+    for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
+    {
+      if( NOT (tmp_byte & 0x01) )
+      {
+        return bitmap_num;
+      }
+      tmp_byte >>= 1;
+      ++bitmap_num;
+    }
+
+    --tmp_byte_ptr;
+  }
+
+  return bitmap_num;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: set_bit_in_bitmap    |
++--------------------------------------------------------------------+
+
+    PURPOSE : Sets a bit in record bitmap
+*/
+void set_bit_in_bitmap ( UBYTE* bitmap,
+                         UBYTE  bitmap_size,
+                         UBYTE  bit_num )
+{
+  bitmap[ bitmap_size - BITMAP_INDEX(bit_num) - 1 ] |= (0x01 << BIT_POS(bit_num) );
+}
+
+/*
++------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                      |
+|                                       ROUINE: reset_bit_in_bitmap      |
++------------------------------------------------------------------------+
+
+    PURPOSE : resets a bit in record bitmap
+*/
+void reset_bit_in_bitmap ( UBYTE* bitmap,
+                           UBYTE  bitmap_size,
+                           UBYTE  bit_num )
+{
+  bitmap[ bitmap_size - BITMAP_INDEX(bit_num) - 1 ] &=  ~ (0x01 << BIT_POS(bit_num));
+}
+
+/*
++----------------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                                |
+|                                       ROUINE: populate_sorted_list_from_FFS      |
++----------------------------------------------------------------------------------+
+
+    PURPOSE : Reads the sorted list from FFS
+*/
+T_DB_CODE populate_sorted_list_from_FFS ( 
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                          UBYTE db_ctr,
+#endif
+                                          char*   sort_file,
+                                          UBYTE   num_of_elements,
+                                          UBYTE** sort_list_ptr )
+{
+  T_FFS_FD   ffs_fd_sort_file;
+  T_FFS_SIZE ffs_ret_code;
+  UBYTE*     sort_list;
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  /* READ */
+  if( db_open_full_for_read( db_ctr ) )
+  {
+     db_close_for_read( db_ctr );  
+  }
+#endif
+
+  DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_RDONLY );
+
+  if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR
+      (ffs_fd_sort_file EQ EFFS_BADNAME     ) OR
+      (ffs_fd_sort_file EQ EFFS_NOTFOUND    ) OR
+      (ffs_fd_sort_file EQ EFFS_INVALID     ) OR
+      (ffs_fd_sort_file EQ EFFS_LOCKED      ) )
+
+  {
+	  TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
+    return DB_FAIL;
+  }
+
+  if( ffs_fd_sort_file < EFFS_OK )
+  {
+    LastFFS_ReturnCode = ffs_fd_sort_file;
+	  TRACE_EVENT_P1( "populate_sorted_list_from_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
+    return DB_FAIL_FS;
+  }
+
+  /* This seek is not required as file pointer will be at start of file,
+     but ffs guide doesn't say so ! This needs to be clarified and 
+     accordingly all ffs_seek at start of file after opening the file
+     can be removed ! */
+  ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET );
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+	  TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_seek %d", ffs_ret_code );
+    return DB_FAIL;
+  }
+
+
+#ifndef INSERTION_SORT
+
+  DB_MALLOC( sort_list, num_of_elements );
+  memset( sort_list, INVALID_RECORD_NUM, num_of_elements );
+
+#else /* INSERTION_SORT */
+
+  DB_MALLOC( sort_list, num_of_elements + 1 );
+  memset( sort_list, INVALID_RECORD_NUM, num_of_elements + 1 );
+
+#endif /* INSERTION_SORT */
+
+  ffs_ret_code = ffs_read( ffs_fd_sort_file, 
+                           sort_list, 
+                           num_of_elements );
+
+  if( (ffs_ret_code EQ EFFS_BADFD ) OR
+      (ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    DB_MFREE( sort_list );
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+	  TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code );
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    LastFFS_ReturnCode = ffs_fd_sort_file;
+    DB_MFREE( sort_list );
+	  TRACE_EVENT_P1( "populate_sorted_list_from_FFS:ffs_read %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+    return DB_FAIL_FS;
+  }
+
+  DB_FFS_CLOSE( ffs_fd_sort_file );
+
+  /* to avoid memory leak */
+  if( *sort_list_ptr NEQ NULL )
+    DB_MFREE( *sort_list_ptr );
+
+  *sort_list_ptr = sort_list;
+
+  return DB_OK;
+}
+
+/*
++-----------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                           |  
+|                                       ROUINE: write_sorted_list_to_FFS      |
++-----------------------------------------------------------------------------+
+
+    PURPOSE : Writes the sorted list into FFS
+*/
+T_DB_CODE write_sorted_list_to_FFS ( 
+                                     
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE db_ctr,
+#endif
+                                     char*   sort_file,
+                                     UBYTE   num_of_elements,
+                                     UBYTE*  sort_list )
+{
+  T_FFS_FD   ffs_fd_sort_file;
+  T_FFS_SIZE ffs_ret_code;
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  /* WRITE */
+  if( db_open_full_for_write( db_ctr ) )
+  {
+     db_close_for_write( db_ctr );  
+  }
+#endif
+
+  /* FFS_O_TRUNC => If file already exists and it is opened for writing, its 
+                    length is truncated to zero. */
+                    
+  DB_FFS_OPEN( ffs_fd_sort_file, sort_file, FFS_O_CREATE | FFS_O_WRONLY | FFS_O_TRUNC );
+
+  if( (ffs_fd_sort_file EQ EFFS_NAMETOOLONG ) OR
+      (ffs_fd_sort_file EQ EFFS_BADNAME     ) )
+  {
+	  TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
+    return DB_FAIL;
+  }
+
+  if( ffs_fd_sort_file < EFFS_OK )
+  {
+	  TRACE_EVENT_P1( "write_sorted_list_to_FFS:DB_FFS_OPEN %d", ffs_fd_sort_file );
+    LastFFS_ReturnCode = ffs_fd_sort_file;
+    return DB_FAIL_FS;
+  }
+
+
+  ffs_ret_code = ffs_seek( ffs_fd_sort_file, 0, FFS_SEEK_SET );
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+	  TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_seek %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+    return DB_FAIL;
+  }
+
+  ffs_ret_code = ffs_write( ffs_fd_sort_file, 
+                            sort_list, 
+                            num_of_elements );
+   
+  if( ( ffs_ret_code EQ EFFS_BADFD ) OR
+      ( ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+    ffs_ret_code = ffs_remove( sort_file );
+	  TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code );
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd_sort_file );
+    ffs_ret_code = ffs_remove( sort_file );
+	  TRACE_EVENT_P1( "write_sorted_list_to_FFS:ffs_write %d", ffs_ret_code );
+    return DB_FAIL_FS;
+  }
+
+  DB_FFS_CLOSE( ffs_fd_sort_file ); /* yeah, we close it here ! */
+
+  return DB_OK;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: search               |
++--------------------------------------------------------------------+
+
+    PURPOSE : Searches for the record; uses binary search and compare
+              function is passed as a parameter.
+*/
+int search ( UBYTE*            sort_list,
+             UBYTE             num_of_elements,
+             UBYTE*            order_num,
+             T_SEARCH_FUNC     search_function, 
+             ULONG             flags, 
+             const UBYTE*      search_tag,
+             int               db_handle,
+             USHORT            field_id ) 
+{
+  /* Binary search is used */
+  UBYTE top,
+        bottom,
+        middle;
+
+  S8 result;
+
+  /* Strictly speaking, this check is not required, but 
+     it would save some processing time */
+  if( num_of_elements EQ 0 )
+    return SEARCH_FAILED;
+
+  if( (*order_num) EQ 0 )
+  {
+    /* Complete list search */
+    top    = num_of_elements - 1;
+    bottom = 0;
+
+  } else {
+
+    /* Strictly speaking, this check is not required, but 
+       it would save some processing time */
+    if( *order_num >= num_of_elements )
+      return SEARCH_FAILED;
+
+    /* Give the next element in sort list if matching */
+    if( search_function( flags,
+                         search_tag,
+                         db_handle,
+                         field_id,
+                         sort_list[ (*order_num) ] )
+        EQ 0 )
+    {
+      *order_num += 1;
+      return *order_num;
+    }
+
+    return SEARCH_FAILED;
+  }
+
+  if( num_of_elements EQ 2 )
+  { 
+    /* Special case of two elements */
+
+    if( search_function( flags,
+                         search_tag,
+                         db_handle,
+                         field_id,
+                         sort_list[ 0 ] )
+       EQ 0 )
+    {
+      *order_num = 1;
+      return 1;
+    }
+
+    if( search_function( flags,
+                         search_tag,
+                         db_handle,
+                         field_id,
+                         sort_list[ 1 ] )
+        EQ 0 )
+    {
+      *order_num = 2;
+      return 2;
+    }
+
+    return SEARCH_FAILED;
+  }
+
+  /* basic concept is here is to get first matching element in sort list and
+     so we need to compare bottom_th element for returning */
+
+  while( top >= bottom )
+  {
+    /* if bottom_th element match, return PASS */
+    if( search_function( flags,
+                         search_tag,
+                         db_handle,
+                         field_id,
+                         sort_list[ bottom ] )
+        EQ 0 )
+    {
+      *order_num = bottom + 1;
+      return *order_num;
+    }
+
+    /* end of list */
+    if( bottom EQ top )
+      return SEARCH_FAILED;
+
+    /* now binary search comes into play */
+
+    middle = (top + bottom) / 2;
+
+    result = search_function( flags,
+                              search_tag,
+                              db_handle,
+                              field_id,
+                              sort_list[ middle ] );
+
+    if( result EQ 0 )
+    {
+      ++bottom;
+
+      if( bottom EQ middle )
+      {
+        /* middle has already matched so, 
+           instead of going to next loop, we return PASS here ! */
+        *order_num = bottom + 1;
+        return *order_num;
+      }
+
+      top = middle;
+
+    } else {
+      
+      if( result > 0 )
+      {
+         ++bottom;         
+
+      } else {
+
+         bottom = middle + 1;
+
+      }
+
+    } /* result EQ 0 */
+      
+  } /* while top >= bottom */
+
+  return SEARCH_FAILED;
+
+}
+
+
+/*
++-----------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                           |
+|                                       ROUINE: update_field_data_in_FFS      |
++-----------------------------------------------------------------------------+
+
+    PURPOSE : Updates elementary file data in FFS
+*/
+T_DB_CODE update_field_data_in_FFS ( const char* field_file,
+                                     T_FFS_FD*   filehandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE       db_ctr,
+#endif
+                                     UBYTE       fld_ctr,
+                                     UBYTE       field_data_max_size,
+                                     UBYTE*      field_data,
+                                     USHORT      offset,
+                                     USHORT      length )
+{
+  T_FFS_FD   ffs_fd = *filehandle;
+  T_FFS_SIZE ffs_ret_code;
+
+  /* Updating field data in FFS in file "field_file" */
+
+  if( ffs_fd EQ NULL )
+  {
+    DB_FFS_OPEN( ffs_fd, field_file, FFS_O_WRONLY );
+
+    if( ( ffs_fd EQ EFFS_NOTFOUND )    OR
+        ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
+        ( ffs_fd EQ EFFS_BADNAME )     OR
+        ( ffs_fd EQ EFFS_INVALID )     )
+    {
+	    TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
+      return DB_FAIL;
+    }
+
+    if( ffs_fd < EFFS_OK )
+    {
+      LastFFS_ReturnCode = ffs_fd;
+	    TRACE_EVENT_P1( "update_field_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
+      return DB_FAIL_FS;
+    }
+
+    *filehandle = ffs_fd;
+
+  } /* filehandle EQ NULL ? */
+
+  /* Seek the file to fld_ctr position to update the entry */
+  ffs_ret_code = ffs_seek( ffs_fd, 
+                           ( fld_ctr * field_data_max_size ) + offset, 
+                           FFS_SEEK_SET );
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+    TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_seek %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL_FS;
+  }
+
+  /* clean is reset in memset, so no processing for it 
+     (in case of non-tracked database, anyway we ignore it ! */ 
+
+  ffs_ret_code = ffs_write( ffs_fd, 
+                            field_data, 
+                            length );
+
+  if( (ffs_ret_code EQ EFFS_BADFD ) OR
+      (ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "update_field_data_in_FFS:ffs_write %d", ffs_ret_code );
+    DB_FFS_CLOSE ( ffs_fd );
+    *filehandle = NULL;
+    LastFFS_ReturnCode = ffs_ret_code;
+    return DB_FAIL_FS;
+  }
+
+  /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
+  /* updation is over */
+
+#ifdef FFS_OPEN_PROBLEM_PATCH
+  DB_FFS_CLOSE( ffs_fd );
+  *filehandle = NULL;
+#endif
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+  /* this is db file, but we do not close it */
+#endif
+
+  return DB_OK;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: cal_NextRecordNum    |
++--------------------------------------------------------------------+
+
+    PURPOSE : Reads the status of the file and returns 
+              the next available record (position)
+*/
+UBYTE cal_NextRecordNum ( const char* db_directory, 
+                          USHORT	    field_id,
+                          USHORT	    record_size )
+{
+  char user_field_file[FILENAME_LEN];
+
+  T_FFS_SIZE ffs_ret_code;
+  T_FFS_STAT ffs_file_stat;
+
+  sprintf( user_field_file, 
+          "%s/UD_%d", 
+          db_directory, 
+          field_id );
+
+  ffs_ret_code = ffs_stat( user_field_file, &ffs_file_stat );
+
+  if( ffs_ret_code EQ EFFS_OK )
+  {
+    return ( (ffs_file_stat.size / record_size) + 1);
+  }
+
+  if( ffs_ret_code EQ EFFS_NOTFOUND )
+  {
+    TRACE_EVENT( "cal_NextRecordNum:ffs_stat:FILE NOT FOUND" );
+    return 1;
+  }
+
+  /* this is a problem with user_field_file, raise an error and 
+     return 0 */
+
+  TRACE_ERROR( "cal_NextRecordNum: PROBLEM with user_field_file" );
+  TRACE_EVENT_P1( "cal_NextRecordNum:ffs_stat %d", ffs_ret_code );
+  return 1;
+
+}
+
+
+/*
++------------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                            |
+|                                       ROUINE: read_user_record_from_FFS      |
++------------------------------------------------------------------------------+
+
+    PURPOSE : Reads a user record from FFS
+*/
+T_DB_CODE read_user_record_from_FFS ( const char* user_field_file,
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                      UBYTE       db_ctr,
+                                      UBYTE       fld_ctr,
+#endif
+                                      T_FFS_FD*   filehandle,
+                                      UBYTE       record_num,
+                                      USHORT      record_size,
+                                      USHORT      offset,
+                                      USHORT      length,
+                                      UBYTE*      record_buffer )
+{
+  T_FFS_FD   ffs_fd = NULL;
+  T_FFS_SIZE ffs_ret_code;
+
+  /* See if file already opened, 
+     if not open it and update the file handle */
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+  ffs_fd = *filehandle;
+
+  if( ffs_fd EQ NULL )
+  {
+    DB_FFS_OPEN( ffs_fd, user_field_file, FFS_O_RDONLY );
+
+    if( (ffs_fd EQ EFFS_NOTFOUND)    OR
+        (ffs_fd EQ EFFS_NAMETOOLONG) OR
+        (ffs_fd EQ EFFS_BADNAME)     OR
+        (ffs_fd EQ EFFS_INVALID)     OR
+        (ffs_fd EQ EFFS_LOCKED)      )
+    {
+      TRACE_EVENT_P1( "read_user_record_from_FFS:DB_FFS_OPEN %d", ffs_fd );
+      return DB_FAIL;
+    }
+
+    if( ffs_fd < EFFS_OK )
+    {
+      TRACE_EVENT_P1( "read_user_record_from_FFS:DB_FFS_OPEN %d", ffs_fd );
+      LastFFS_ReturnCode = ffs_fd;
+      return DB_FAIL_FS;
+    }
+
+    *filehandle = ffs_fd;
+  }
+
+#else /* FFS_CLOSE_BEFORE_OPEN */
+
+  ffs_fd = db_open_user_field_file( db_ctr, fld_ctr, user_field_file, FFS_O_RDONLY );
+
+#endif /* FFS_CLOSE_BEFORE_OPEN */
+
+  ffs_ret_code = ffs_seek( ffs_fd, 
+                           ( (record_num - 1) * (record_size) + offset),
+                           FFS_SEEK_SET ); 
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+    TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_seek %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_seek %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL_FS;
+  }
+
+  ffs_ret_code = ffs_read( ffs_fd, 
+                           record_buffer, 
+                           length ); 
+
+  if( ( ffs_ret_code EQ EFFS_BADFD ) OR
+      ( ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_read %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "read_user_record_from_FFS:ffs_read %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL_FS;
+  }
+
+  /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
+
+#ifdef FFS_OPEN_PROBLEM_PATCH
+  DB_FFS_CLOSE( ffs_fd );
+  *filehandle = NULL;
+#endif
+
+  return DB_OK;
+}
+
+/*
++-------------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                             |
+|                                       ROUINE: write_user_record_to_FFS      |
++-------------------------------------------------------------------------------+
+
+    PURPOSE : Writes user record into FFS
+*/
+T_DB_CODE write_user_record_to_FFS ( const char* user_field_file,
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                     UBYTE       db_ctr,
+                                     UBYTE       fld_ctr,
+#endif
+                                     T_FFS_FD*   filehandle,
+                                     UBYTE       record_num,
+                                     USHORT      record_size,
+                                     USHORT      offset,
+                                     USHORT      length,
+                                     UBYTE*      record_buffer )
+{
+  T_FFS_FD   ffs_fd = NULL;
+  T_FFS_SIZE ffs_ret_code;
+
+  /* See if file already opened, 
+     if not open it and update the file handle */
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+  ffs_fd = *filehandle;
+
+  if( ffs_fd EQ NULL )
+  {
+    DB_FFS_OPEN( ffs_fd, user_field_file, FFS_O_RDWR );
+
+    if( (ffs_fd EQ EFFS_NOTFOUND)    OR
+        (ffs_fd EQ EFFS_NAMETOOLONG) OR
+        (ffs_fd EQ EFFS_BADNAME)     OR
+        (ffs_fd EQ EFFS_INVALID)     OR
+        (ffs_fd EQ EFFS_LOCKED)      )
+    {
+      TRACE_EVENT_P1( "write_user_record_to_FFS:DB_FFS_OPEN %d", ffs_fd );
+      return DB_FAIL;
+    }
+
+    if( ffs_fd < EFFS_OK )
+    {
+      TRACE_EVENT_P1( "write_user_record_to_FFS:DB_FFS_OPEN %d", ffs_fd );
+      LastFFS_ReturnCode = ffs_fd;
+      return DB_FAIL_FS;
+    }
+
+    *filehandle = ffs_fd;
+  }
+
+#else /* FFS_CLOSE_BEFORE_OPEN */
+
+  ffs_fd = db_open_user_field_file( db_ctr, fld_ctr, user_field_file, FFS_O_RDWR );
+
+#endif /* FFS_CLOSE_BEFORE_OPEN */
+
+  ffs_ret_code = ffs_seek( ffs_fd, 
+                           ( (record_num - 1) * (record_size) + offset),
+                           FFS_SEEK_SET ); 
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+    TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_seek %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_seek %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL_FS;
+  }
+
+  ffs_ret_code = ffs_write( ffs_fd, 
+                            record_buffer, 
+                            length ); 
+
+  if( ( ffs_ret_code EQ EFFS_BADFD ) OR
+      ( ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_write %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "write_user_record_to_FFS:ffs_write %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    *filehandle = NULL;
+    return DB_FAIL_FS;
+  }
+
+  /* DB_FFS_CLOSE( ffs_fd ); we will do it in db_flush */
+
+#ifdef FFS_OPEN_PROBLEM_PATCH
+  DB_FFS_CLOSE( ffs_fd );
+  *filehandle = NULL;
+#endif
+
+  return DB_OK;
+}
+
+/*
++-----------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                           |
+|                                       ROUINE: delete_file_dir_from_FFS      |
++-----------------------------------------------------------------------------+
+
+    PURPOSE : Deletes a file from FFS
+*/
+T_DB_CODE delete_file_dir_from_FFS ( const char* filename )
+{
+  T_FFS_SIZE ffs_ret_code;
+
+  TRACE_EVENT_P1( "delete_file_dir_from_FFS %s", filename );
+
+  ffs_ret_code = ffs_remove( filename );
+
+#ifdef FORCED_DIR_REMOVAL
+
+  if( ffs_ret_code EQ EFFS_DIRNOTEMPTY )
+  {
+    TRACE_EVENT( "Inconsistency; going for delete_dir_forced" );
+    return delete_dir_forced( filename ); 
+  }
+
+#endif
+
+  if( ffs_ret_code EQ EFFS_NOTFOUND )
+  {
+    TRACE_EVENT( "delete_file_dir_from_FFS:ffs_remove:FILE NOT FOUND" );
+    return DB_OK;
+  }
+
+  if( ( ffs_ret_code EQ EFFS_ACCESS   ) OR
+      ( ffs_ret_code EQ EFFS_LOCKED   ) )
+  {
+    TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code );
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "delete_file_dir_from_FFS:ffs_remove %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    return DB_FAIL_FS;
+  }
+
+  return DB_OK;
+
+}
+
+/*
++---------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                         |
+|                                       ROUINE: update_dbm_data_in_FFS      |
++---------------------------------------------------------------------------+
+
+    PURPOSE : Updates the database manager information of a 
+              particular database
+*/
+T_DB_CODE update_dbm_data_in_FFS ( const char* filename,
+                                   UBYTE       db_ctr,
+                                   UBYTE       db_data_max_size,
+                                   UBYTE*      db_data,
+                                   USHORT      offset,
+                                   USHORT      length )
+{
+  T_FFS_FD   ffs_fd = NULL;
+  T_FFS_SIZE ffs_ret_code;
+
+  /* See if file already opened, 
+     if not open it and update the file handle */
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  /* WRITE */
+  if( db_open_full_for_write( db_ctr ) )
+  {
+     db_close_for_write( db_ctr );  
+  }
+#endif
+
+  DB_FFS_OPEN( ffs_fd, filename, FFS_O_WRONLY );
+
+  if( ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
+      ( ffs_fd EQ EFFS_BADNAME )     OR
+      ( ffs_fd EQ EFFS_NOTFOUND )    OR
+      ( ffs_fd EQ EFFS_INVALID )     OR
+      ( ffs_fd EQ EFFS_LOCKED )      )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
+     return DB_FAIL;
+  }
+
+  if( ffs_fd < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:DB_FFS_OPEN %d", ffs_fd );
+    LastFFS_ReturnCode = ffs_fd;
+    return DB_FAIL_FS;
+  }
+
+  ffs_ret_code = ffs_seek( ffs_fd, db_ctr * db_data_max_size, FFS_SEEK_SET );
+
+  if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+      ( ffs_ret_code EQ EFFS_INVALID ) OR
+      ( ffs_ret_code EQ EFFS_BADOP )   )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_seek %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_FFS_CLOSE( ffs_fd );
+    return DB_FAIL_FS;
+  }
+
+  ffs_ret_code = ffs_write( ffs_fd, db_data, db_data_max_size );
+   
+  if( ( ffs_ret_code EQ EFFS_BADFD ) OR
+      ( ffs_ret_code EQ EFFS_BADOP ) )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    return DB_FAIL;
+  }
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "update_dbm_data_in_FFS:ffs_write %d", ffs_ret_code );
+    DB_FFS_CLOSE( ffs_fd );
+    LastFFS_ReturnCode = ffs_ret_code;
+    return DB_FAIL_FS;
+  }
+
+  DB_FFS_CLOSE( ffs_fd );  /* yeah, DB file, so ok to close it here ! */
+
+  /* updation of dbm data done */
+
+  return DB_OK;
+}
+
+/*
++--------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                        |
+|                                       ROUINE: remove_field_from_FFS      |
++--------------------------------------------------------------------------+
+
+    PURPOSE : Removes the elementary file and associated Index 
+              file from FFS
+*/
+T_DB_CODE remove_field_from_FFS ( UBYTE db_ctr,
+                                  UBYTE fld_ctr )
+{
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+  char               user_field_file[FILENAME_LEN],
+                     sort_file[FILENAME_LEN];
+  T_DB_CODE          db_ret_code;
+  UBYTE              sort_index_ctr;
+
+  /* Assumed that DBState is not IN_USE */
+
+  tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
+  
+  if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */
+    return DB_OK;
+
+  /* Close of user record files not required as DBState is not IN_USE */
+
+  /* Delete file "<DBDirectory>/UD_<field_id>" */
+
+  sprintf( user_field_file, 
+           "%s/UD_%d", 
+           DbmMaster[db_ctr].DBDirectory, 
+           tmp_ptrFieldRecord -> FieldID );
+
+  db_ret_code = delete_file_dir_from_FFS ( user_field_file );
+
+  if( db_ret_code NEQ DB_OK )
+    return db_ret_code;
+
+  /* For sorted lists */
+
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
+    {
+      /* Sort file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */
+
+      sprintf( sort_file, 
+               "%s/UD_%d_sort_%d", 
+               DbmMaster[db_ctr].DBDirectory, 
+               tmp_ptrFieldRecord -> FieldID,
+               tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
+
+      db_ret_code = delete_file_dir_from_FFS ( sort_file );
+
+      if( db_ret_code NEQ DB_OK )
+        return db_ret_code;        
+    }
+  }
+
+  return DB_OK;
+
+}
+
+
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+
+T_FFS_FD db_open_user_field_file ( UBYTE            db_ctr, 
+                                   UBYTE            fld_ctr, 
+                                   const char*      user_field_file,
+                                   T_FFS_OPEN_FLAGS open_option )
+{
+  UBYTE i;
+  FileHandleRecord* tmp_open_fields;
+  UBYTE*            tmp_old;
+  UBYTE             tmp_max;
+
+  /* sanity checks not done (db_ctr >= MAX_DBs OR fld_ctr EQ INVALID_FLD_CTR) */
+
+  /* note that we store field counters and not field ids */
+
+  /* Search in write/read list */
+  for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
+  {
+    if( DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].fld_ctr EQ fld_ctr )
+      return DbmMaster[db_ctr].WRITE_OPEN_FIELDS[i].filehandle;
+  } /* for */
+
+  /* Search in read only list */
+  for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
+  {
+    if( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr EQ fld_ctr )
+    {
+      if( NOT ( open_option & FFS_O_WRONLY ) ) /* if not opened for writing */
+      {
+        return DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle;
+      }
+
+      /* we need to reopen it in write mode */
+      DB_FFS_CLOSE( DbmMaster[db_ctr].READ_OPEN_FIELDS[i].filehandle );
+
+      DbmMaster[db_ctr].READ_OPEN_FIELDS[i].fld_ctr = INVALID_FLD_CTR;
+
+      break;
+      
+    }
+  } /* for */
+
+  /* field is not present in both lists */
+
+  if( open_option & FFS_O_WRONLY )
+  {
+
+    /* for writing and reading both */
+    tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
+    tmp_old = &(DbmMaster[db_ctr].old_write);
+    tmp_max = MAX_OPEN_WRITE_PER_DB;
+
+  } else {
+
+    /* for reading only */
+    tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
+    tmp_old = &(DbmMaster[db_ctr].old_read);
+    tmp_max = MAX_OPEN_READ_PER_DB;
+  }
+
+
+  /* search the list */
+  for( i = 0; i < tmp_max; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
+    {
+      DB_FFS_OPEN( tmp_open_fields[i].filehandle,
+                   user_field_file,
+                   open_option );
+
+      tmp_open_fields[i].fld_ctr = fld_ctr;
+
+      return tmp_open_fields[i].filehandle;
+    }
+  } /* for */
+
+  /* we need to close the some file for opening this */
+
+  if( *tmp_old >= tmp_max )
+    *tmp_old = 0;
+
+  DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
+
+  DB_FFS_OPEN( tmp_open_fields[*tmp_old].filehandle,
+               user_field_file,
+               open_option );
+
+  if( tmp_open_fields[*tmp_old].filehandle >= EFFS_OK )
+  {
+    tmp_open_fields[*tmp_old].fld_ctr = fld_ctr;
+    ++(*tmp_old);
+    return tmp_open_fields[*tmp_old - 1].filehandle;
+  } 
+  
+  tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
+
+  return tmp_open_fields[*tmp_old].filehandle;
+
+}
+
+void db_close_user_field_files ( UBYTE db_ctr )
+{
+  UBYTE i;
+  FileHandleRecord* tmp_open_fields;
+
+  /* sanity check not done */
+
+  /* for write list */
+
+  tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR )
+    {
+      DB_FFS_CLOSE( tmp_open_fields[i].filehandle );
+      tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR;
+    }
+  }
+
+  /* for read list */
+
+  tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr NEQ INVALID_FLD_CTR )
+    {
+      DB_FFS_CLOSE( tmp_open_fields[i].filehandle );
+      tmp_open_fields[i].fld_ctr = INVALID_FLD_CTR;
+    }
+  }
+
+}
+
+BOOL db_open_full_for_read ( UBYTE db_ctr )
+{
+  UBYTE i;
+  FileHandleRecord* tmp_open_fields;
+
+  /* sanity check not done */
+
+  /* for read list */
+
+  tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+BOOL db_open_full_for_write ( UBYTE db_ctr )
+{
+  UBYTE i;
+  FileHandleRecord* tmp_open_fields;
+
+  /* sanity check not done */
+
+  /* for write list */
+
+  tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr EQ INVALID_FLD_CTR )
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+void db_close_for_read ( UBYTE db_ctr )
+{
+  FileHandleRecord* tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
+  UBYTE *tmp_old = &(DbmMaster[db_ctr].old_read);
+
+  /* sanity check not done */
+
+  /* for read list */
+
+  if( *tmp_old >= MAX_OPEN_READ_PER_DB )
+    *tmp_old = 0;
+
+  DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
+
+  tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
+
+  ++(*tmp_old);
+
+  return;
+
+}
+
+void db_close_for_write ( UBYTE db_ctr )
+{
+  FileHandleRecord* tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
+  UBYTE *tmp_old = &(DbmMaster[db_ctr].old_write);
+
+  /* sanity check not done */
+
+  /* for read list */
+
+  if( *tmp_old >= MAX_OPEN_WRITE_PER_DB )
+    *tmp_old = 0;
+
+  DB_FFS_CLOSE( tmp_open_fields[*tmp_old].filehandle );
+
+  tmp_open_fields[*tmp_old].fld_ctr = INVALID_FLD_CTR;
+
+  ++(*tmp_old);
+
+  return;
+
+}
+
+UBYTE db_status_user_field_file ( UBYTE db_ctr,
+                                  UBYTE fld_ctr )
+{
+  UBYTE i;
+  FileHandleRecord* tmp_open_fields;
+
+  /* sanity check not done */
+
+  /* for write list */
+
+  tmp_open_fields = DbmMaster[db_ctr].WRITE_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_WRITE_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr EQ fld_ctr )
+      return OPENED_FOR_WRITE;
+  }
+
+  /* for read list */
+
+  tmp_open_fields = DbmMaster[db_ctr].READ_OPEN_FIELDS;
+
+  for( i = 0; i < MAX_OPEN_READ_PER_DB; ++i )
+  {
+    if( tmp_open_fields[i].fld_ctr EQ fld_ctr )
+      return OPENED_FOR_READ;
+  }
+
+  return NOT_OPENED;
+
+}
+
+#endif /* FFS_CLOSE_BEFORE_OPEN */
+
+
+#ifdef FORCED_DIR_REMOVAL
+
+/*
++-----------------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                           |
+|                                       ROUINE: delete_dir_forced             |
++-----------------------------------------------------------------------------+
+
+    PURPOSE : Removes contents of dir and then delete the dir
+              (it uses recursion)
+*/
+T_DB_CODE delete_dir_forced ( const char* dir )
+{
+  T_FFS_SIZE ffs_ret_code;
+  T_FFS_DIR  ffs_dir;
+  T_FFS_STAT tmp_ffs_stat;
+
+  char  pathname[FILENAME_LEN];
+  UBYTE dir_len;
+
+  /* Open dir, if does not exist, just return DB_OK */
+
+  ffs_ret_code = ffs_opendir (dir, &ffs_dir);
+
+  if( ffs_ret_code EQ EFFS_NOTFOUND )
+    DB_RETURN( DB_OK );
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P2( "delete_dir_forced:ffs_remove %d, %s", ffs_ret_code, dir );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_RETURN( DB_FAIL_FS );
+  }
+
+  /* read dir recursively */
+  sprintf( pathname, 
+           "%s/", 
+           dir );
+
+  dir_len = strlen( pathname );
+
+  while( 1 )
+  {
+    /* filename inside the directory would be copied at pathname + dirlen */
+
+    ffs_ret_code = ffs_readdir( &ffs_dir,
+                                pathname + dir_len,
+                                FILENAME_LEN - dir_len - 1 );
+
+    if( ffs_ret_code EQ 0 ) /* dir is empty now */
+    {
+      break;
+    }
+
+    if( ffs_ret_code < EFFS_OK )
+    {
+      TRACE_EVENT_P2( "delete_dir_forced:ffs_readdir:%d, %s", ffs_ret_code, dir );
+      LastFFS_ReturnCode = ffs_ret_code;
+      DB_RETURN( DB_FAIL_FS );
+    }
+
+    ffs_ret_code = ffs_stat( pathname, &tmp_ffs_stat );
+
+    if( ffs_ret_code < EFFS_OK )
+    {
+      TRACE_EVENT_P2( "delete_dir_forced:ffs_stat:%d, %s", ffs_ret_code, pathname);
+      LastFFS_ReturnCode = ffs_ret_code;
+      DB_RETURN( DB_FAIL_FS );
+    }
+
+    if( tmp_ffs_stat.type EQ OT_DIR )
+    {
+      /* Directory !! */
+
+      T_DB_CODE db_code;
+
+      TRACE_EVENT_P1( "Warning: directory %s", pathname );
+
+      /* Recursion */
+      db_code = delete_dir_forced( pathname ); 
+
+      if( db_code NEQ DB_OK )
+        DB_RETURN( db_code );
+
+    } else {
+
+      /* normal file (OT_FILE) or symbolic link (OT_LINK) */
+
+      ffs_ret_code = ffs_remove( pathname );
+
+      if( ffs_ret_code < EFFS_OK )
+      {
+        TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, pathname );
+        LastFFS_ReturnCode = ffs_ret_code;
+        DB_RETURN( DB_FAIL_FS );
+      }
+
+    } /* if( tmp_ffs_stat.type EQ OT_DIR ) */
+
+  } /* while( 1 ) */
+
+  /* now delete the directory */
+  ffs_ret_code = ffs_remove( dir );
+
+  if( ffs_ret_code < EFFS_OK )
+  {
+    TRACE_EVENT_P2( "delete_dir_forced:ffs_remove:%d, %s", ffs_ret_code, dir );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_RETURN( DB_FAIL_FS ); 
+  }
+
+  DB_RETURN( DB_OK );
+}
+
+
+#endif /* FORCED_DIR_REMOVAL */
+
+
+#ifdef INSERTION_SORT
+
+void get_sort_lists_from_FFS ( UBYTE db_ctr,
+                               UBYTE fld_ctr )
+{
+  UBYTE sort_index_ctr;
+
+  T_DB_CODE db_ret_code;
+
+  char sort_file[FILENAME_LEN];
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
+
+  /* for all existing sort indexes */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    /* valid index ? */
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
+    {
+      /* Check if we already have sorted list in RAM structure SortedLists */
+
+      if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
+      { 
+        /* If no, populate the sorted list from file, 
+           "<DBDirectory>/UD_<field_id>_sort_<sort_index>". 
+           Sorted lists are freed in db_flush */
+
+        sprintf( sort_file, 
+                 "%s/UD_%d_sort_%d", 
+                 DbmMaster[db_ctr].DBDirectory, 
+                 tmp_ptrFieldRecord -> FieldID,
+                 tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
+
+        db_ret_code = 
+          populate_sorted_list_from_FFS (  
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                          db_ctr,
+#endif
+                                          sort_file,
+                                          tmp_ptrFieldRecord -> NumOfRecords,
+                                          &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
+        if( db_ret_code NEQ DB_OK )
+        {
+          /* Failure, still we can continue as later during actual sorting, 
+             FFS would be retried */
+
+          TRACE_EVENT( "Warning: populate_sorted_list_from_FFS failed" );
+          TRACE_EVENT_P3( "db_ctr %d field_id %d sort_index %d",
+                          db_ctr,
+                          tmp_ptrFieldRecord -> FieldID,
+                          tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
+
+          continue;
+        }
+    
+      } /* if we have sort list */
+
+    } /* if valid index */
+
+  } /* for all sort indexes */
+
+  return;
+
+}
+
+void new_in_sort_lists ( UBYTE db_ctr,
+                         UBYTE fld_ctr,
+                         UBYTE record_num )
+{
+  UBYTE sort_index_ctr;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
+
+  /* make a note that this record needs to be sorted */
+
+  /* for all existing sort indexes */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
+    {
+      /* add it at the end like all sorted records + INVALID RECORD + .... */
+      tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] 
+        = record_num;
+    }
+  }
+
+  return;
+
+}
+
+void update_in_sort_lists ( UBYTE db_ctr,
+                            UBYTE fld_ctr,
+                            UBYTE record_num )
+{
+  UBYTE sort_index_ctr,
+        rec_ctr;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
+
+  /* make a note that this record needs to be sorted */
+
+  /* for all existing sort indexes */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
+    {
+      /* search entry in sorted records */
+      rec_ctr = 0;
+      while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
+      {
+        if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
+        {
+          /* found in sorted records, 
+             now delete this entry */
+
+          memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr,                    /* dest */
+                   (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1), /* source */
+                   tmp_ptrFieldRecord -> UsedRecords - rec_ctr );                                  /* size */   
+
+          tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] 
+            = record_num;
+
+          break;
+        }
+
+        ++rec_ctr;
+      }
+
+    } /* NEQ INVALID_SORT_INDEX */
+
+  } /* for sort_index_ctr */
+
+  return;
+}
+
+void delete_in_sort_lists ( UBYTE db_ctr,
+                            UBYTE fld_ctr,
+                            UBYTE record_num )
+{
+  UBYTE sort_index_ctr,
+        rec_ctr;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord + fld_ctr;
+
+  /* make a note that this record needs to be sorted */
+
+  /* for all existing sort indexes */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] NEQ INVALID_SORT_INDEX )
+    {
+      /* search entry in sorted records */
+      rec_ctr = 0;
+      while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
+      {
+        if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
+          break;
+
+        ++rec_ctr;
+      }
+
+      if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
+      {
+        /* found in sorted records, 
+           now delete this entry */
+
+        memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr,
+                 (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1),
+                 tmp_ptrFieldRecord -> UsedRecords - rec_ctr );
+
+        tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] 
+          = INVALID_RECORD_NUM;
+
+      } else {
+
+        /* search in UN-sorted records */
+
+        ++rec_ctr;
+        while( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] NEQ INVALID_RECORD_NUM )
+        {
+          if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][rec_ctr] EQ record_num )
+          {
+            /* delete this entry */
+            memmove( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr,
+                     (const char*)(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] + rec_ctr + 1),
+                     tmp_ptrFieldRecord -> UsedRecords - rec_ctr );
+
+            tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][tmp_ptrFieldRecord -> UsedRecords] 
+              = INVALID_RECORD_NUM;
+
+            break;
+          }
+          ++rec_ctr;
+        }
+
+      }
+
+    } /* NEQ INVALID_SORT_INDEX */
+
+  } /* for sort_index_ctr */
+
+  return;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: insertion_sort       |
++--------------------------------------------------------------------+
+
+    PURPOSE : Sorts the user data records in FFS based on insertion sort method
+*/
+void insertion_sort ( UBYTE*        sort_list,
+                      UBYTE         num_of_elements,
+                      T_COMP_FUNC   compare_function, 
+                      ULONG         flags,
+                      int           db_handle,
+                      USHORT        field_id )
+{
+  UBYTE rec_ctr;
+
+  /* sanity check */
+  if( num_of_elements EQ 0 )
+    return;
+
+  if( sort_list[0] EQ INVALID_RECORD_NUM )
+  {
+    /* This is beginning of new sort list,
+       Let's add first element */
+    sort_list[0] = sort_list[1];
+    sort_list[1] = INVALID_RECORD_NUM;
+  }
+
+
+  /* So now here we have list something like this
+     { Sorted records } + INVALID_RECORD_NUM + { UNsorted records }
+  */
+
+  /* let's get to Unsorted records */
+  rec_ctr = 1;
+  while( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM )
+  {
+    ++rec_ctr;
+  }
+  ++rec_ctr;
+
+  /* rec_ctr is now pointing at UNsorted records */
+
+  /* now add UNsorted records one by one */
+
+  /* Not required "( sort_list[rec_ctr] NEQ INVALID_RECORD_NUM )", right ? */
+
+  while( rec_ctr <= num_of_elements )
+  {
+    insert_element( sort_list,
+                    rec_ctr,                /* num_of_elements */
+                    0,                      /* bottom */
+                    rec_ctr - 2,            /* top */
+                    sort_list[rec_ctr],     /* record_num to be inserted */
+                    compare_function,
+                    flags,
+                    db_handle,
+                    field_id );
+
+    ++rec_ctr;
+  }
+
+  /* done ! */
+  return;
+}
+
+void insert_element ( UBYTE*        sort_list,
+                      UBYTE         num_of_elements,
+                      UBYTE         bottom,
+                      UBYTE         top,
+                      UBYTE         record_num,
+                      T_COMP_FUNC   compare_function, 
+                      ULONG         flags,
+                      int           db_handle,
+                      USHORT        field_id )
+{
+  UBYTE middle = ( top + bottom ) / 2;
+
+  /* use binary algorithm to find the right place for insertion */
+  while( middle NEQ bottom )
+  {
+    if( compare_function( db_handle, 
+                          field_id,
+                          sort_list[middle],
+                          record_num,
+                          flags ) 
+        < 0 )
+    {
+      bottom = middle;
+    } else {
+      top = middle;
+    }
+    middle = ( top + bottom ) / 2;
+
+  } /* while( middle NEQ bottom ) */
+
+  if( compare_function( db_handle, 
+                        field_id,
+                        sort_list[bottom],
+                        record_num,
+                        flags ) 
+      < 0 )
+  {
+
+    if( compare_function( db_handle, 
+                          field_id,
+                          sort_list[top],
+                          record_num,
+                          flags ) 
+        < 0 )
+    {
+      /* insert at top + 1 */
+      memmove( sort_list + top + 2,            /* dest */
+               sort_list + top + 1,            /* source */
+               num_of_elements - (top + 1) );  /* size */
+
+      sort_list[top + 1] = record_num;
+
+    } else {
+
+      /* insert at bottom + 1 */
+      memmove( sort_list + bottom + 2,            /* dest */
+               sort_list + bottom + 1,            /* source */
+               num_of_elements - (bottom + 1) );  /* size */
+
+      sort_list[bottom + 1] = record_num;
+
+    } /* if top_th < insert_th */
+
+  } else {
+
+    /* insert at bottom */
+    memmove( sort_list + bottom + 1,       /* dest */
+             sort_list + bottom,           /* source */
+             num_of_elements - bottom );   /* size */
+
+    sort_list[bottom] = record_num;
+
+  } /* if bottom_th < insert_th */
+
+  return;
+}
+
+#endif /* INSERTION_SORT */
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: internal_db_sort     |
++--------------------------------------------------------------------+
+
+    PURPOSE : (Internal) Creates or updates a sort index for
+              a given (database, field)
+*/
+T_DB_CODE internal_db_sort ( int          db_handle, 
+                             USHORT       field_id, 
+                             UBYTE        sort_index, 
+                             T_COMP_FUNC  compare_function, 
+                             ULONG        flags,
+                             T_DB_SORT    sort_type )
+{
+  UBYTE  fld_ctr,
+         sort_index_ctr,
+         remb_sort_index_ctr,
+         tmp_byte,
+         bit_num,
+         record_num;
+
+  UBYTE* sort_list;
+  UBYTE* copy_sort_list;
+
+  UBYTE*  tmp_byte_ptr;
+
+  T_DB_CODE  db_ret_code;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  UBYTE* field_data;
+  UBYTE  field_file[FILENAME_LEN];
+
+  TRACE_FUNCTION("internal_db_sort()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Check if this is existing sort index */
+  remb_sort_index_ctr = MAX_NUM_OF_SORT_INDEXS;
+
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
+      break;
+
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ INVALID_SORT_INDEX )
+      remb_sort_index_ctr = sort_index_ctr;
+
+  }
+
+  if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
+  { 
+    /* ok, this is new index, so
+       Check if limit for sort list corresponding to field_id (for a given database) 
+       has reached limit, MAX_NUM_OF_SORT_INDEXS. If so, return DB_FULL. */
+
+    if( remb_sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
+      DB_RETURN( DB_FULL );
+    
+    sort_index_ctr = remb_sort_index_ctr;
+
+    /* update file , "~/dbm/DD_<db_handle>" for SortIndexes. */
+
+    /* create the field data that is to be written */
+
+    DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS );
+    memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS );
+
+    field_data[sort_index_ctr] = sort_index;
+
+    sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+    db_ret_code = 
+      update_field_data_in_FFS ( (const char*)field_file,
+                                 &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                 db_handle,
+#endif
+                                 fld_ctr,
+                                 T_DB_FIELD_RECORD_SIZE,
+                                 field_data,
+                                 SortIndexList_OFFSET,
+                                 MAX_NUM_OF_SORT_INDEXS );
+    if( db_ret_code NEQ DB_OK )
+    {
+      DB_MFREE( field_data );
+      DB_RETURN( db_ret_code );
+    }
+
+    DB_MFREE( field_data );
+    /* updation of DD_<db_handle> is over */
+  }
+
+  if( ( sort_type EQ QUICK_SORT )                                    AND
+      ( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL ) )
+  {
+    /* free earlier list */
+    DB_MFREE( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] );
+    tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
+  }
+
+  /* create sort list (if not there) */
+  if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL )
+  {
+    sort_list = tmp_ptrFieldRecord -> SortedLists[sort_index_ctr];
+  } else {
+
+#ifndef INSERTION_SORT
+    DB_MALLOC( sort_list, tmp_ptrFieldRecord -> NumOfRecords );
+    memset( sort_list, INVALID_RECORD_NUM, tmp_ptrFieldRecord -> NumOfRecords );
+
+    copy_sort_list = sort_list;
+#else
+    DB_MALLOC( sort_list, tmp_ptrFieldRecord -> NumOfRecords + 1 );
+    memset( sort_list, INVALID_RECORD_NUM, tmp_ptrFieldRecord -> NumOfRecords + 1 );
+
+    if( sort_type EQ INCREMENTAL_SORT )
+    {
+      /* the first element would be INVALID_RECORD_NUM (0xFF) */
+      copy_sort_list = sort_list + 1;
+
+    } else {
+
+      copy_sort_list = sort_list;
+    }
+#endif /* INSERTION_SORT */
+
+    /* The list of available records is prepared from RecordBitMap */
+
+    tmp_byte_ptr = tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - 1;
+    record_num = 0;
+
+    while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
+    {
+      tmp_byte = *tmp_byte_ptr;
+      for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
+      {
+        ++record_num;
+
+        if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
+          break;
+
+        if( tmp_byte & 0x01 )
+        {
+          *copy_sort_list = record_num;
+          ++copy_sort_list;
+        }
+
+
+        tmp_byte >>= 1;  
+      }
+      --tmp_byte_ptr;
+
+    } /* population of records */
+
+  } /* sort_list is NULL */
+
+  /* Sort the records with given "comparison_function" (it takes record numbers, 
+     field_id and db_handle). Note that the sorted list would be kept in RAM 
+     (structure SortedLists, part of field record) till db_flush is called and 
+     cleared in db_flush. */
+
+  if( sort_type EQ QUICK_SORT )
+  {
+    quick_sort( sort_list,
+                tmp_ptrFieldRecord -> UsedRecords,   /* only used records */
+                compare_function,
+                flags,
+                db_handle,
+                field_id );
+  }
+
+#ifdef INSERTION_SORT
+
+  if( sort_type EQ INCREMENTAL_SORT )
+  {
+    insertion_sort( sort_list,
+                    tmp_ptrFieldRecord -> UsedRecords,   /* only used records */
+                    compare_function,
+                    flags,
+                    db_handle,
+                    field_id );
+  }
+
+#endif /* INSERTION_SORT */
+
+  /* writing sorted list to FFS would be done in db_flush */
+ 
+  /* Update corresponding field SortIndexList in RAM structures. */
+
+  tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = sort_index;
+  tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = sort_list;
+
+  DB_RETURN( DB_OK );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/***********************/
+/* INTERFACE FUNCTIONS */
+/***********************/
+
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_init              |
++--------------------------------------------------------------------+
+
+    PURPOSE : Initialises database manager
+*/
+ void db_init ( void )
+{
+  UBYTE db_ctr;
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  UBYTE fld_ctr;
+#endif
+
+  TRACE_FUNCTION("db_init()");
+
+  /* 1) Check DBM_State and if already initialized, return DB_OK */
+  if ( DBM_State EQ DBM_INITIALISED )
+    return;
+
+  /* 2)	Initialize DbmMaster structure */
+  for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+  {
+    DbmMaster[db_ctr].DBState = UNUSED_ENTRY;
+
+#ifdef FFS_CLOSE_BEFORE_OPEN 
+
+    for( fld_ctr = 0; fld_ctr < MAX_OPEN_READ_PER_DB; ++fld_ctr )
+    {
+      DbmMaster[db_ctr].READ_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR;
+    }
+    for( fld_ctr = 0; fld_ctr < MAX_OPEN_WRITE_PER_DB; ++fld_ctr )
+    {
+      DbmMaster[db_ctr].WRITE_OPEN_FIELDS[fld_ctr].fld_ctr = INVALID_FLD_CTR;
+    }
+    DbmMaster[db_ctr].old_read = 0;
+    DbmMaster[db_ctr].old_write = 0;
+
+#endif
+
+  }
+
+  UsedDBs = 0;
+
+#ifdef _SIMULATION_
+  {
+    T_FFS_SIZE ffs_ret_code = ffs_init();
+
+    TRACE_EVENT_P1("Initialization of FFS Simulation %d", ffs_ret_code );
+
+    /* Delete existing database */
+    init_RAM_with_FFS();
+
+    for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+    {
+      if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
+        db_remove( DbmMaster[db_ctr].DBDirectory );
+    }
+
+    db_exit();
+  }
+#endif
+
+  return;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: init_RAM_with_FFS    |
++--------------------------------------------------------------------+
+
+    PURPOSE : Initialise DBM RAM structures with FFS data
+*/
+ T_DB_CODE init_RAM_with_FFS ( void )
+{
+  /* Initializing "DBM related data" in RAM from FFS */
+
+  T_FFS_FD            ffs_dbm_fd;
+  T_FFS_SIZE          ffs_ret_code;
+  T_FFS_STAT          ffs_dir_stat;
+  UBYTE*              db_buffer;
+  UBYTE*              remb_db_buffer;
+  UBYTE*              tmp_byte_ptr;
+  UBYTE*              field_buffer;
+  UBYTE*              remb_field_buffer;
+  UBYTE               db_ctr,
+                      fld_ctr,
+                      sort_index_ctr,
+                      tmp_byte,
+                      tmp_num_records,
+                      bit_num,
+                      record_num;
+  char                field_file[FILENAME_LEN];
+  char*               field_file_ptr = field_file;
+  char*               dbm_file = DB_MASTER_FILE;
+  T_DBM_FIELDRECORD*  tmp_ptrFieldRecord;
+
+
+  TRACE_FUNCTION("init_RAM_with_FFS()");
+
+  /* Check the presence of FFS directory DB_DIR */
+  ffs_ret_code = ffs_stat( DB_DIR, &ffs_dir_stat );
+
+  TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_stat %d", ffs_ret_code );
+  /* error values of ffs_ret_code are handled later */
+
+  if( ffs_ret_code >= EFFS_OK )
+  {
+    /* Directory is present */
+     
+    /* Synchronize DB related data between FFS and RAM 
+       i.e. structures DbmMasterRecord and corresponding DbmFieldRecord. */
+
+    /* For DbmMaster */
+
+    DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_RDONLY );
+
+    if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR
+        (ffs_dbm_fd EQ EFFS_BADNAME     ) OR
+        (ffs_dbm_fd EQ EFFS_NOTFOUND    ) OR
+        (ffs_dbm_fd EQ EFFS_INVALID     ) OR
+        (ffs_dbm_fd EQ EFFS_LOCKED      ) )
+
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
+      return DB_FAIL;
+    }
+
+    if( ffs_dbm_fd < EFFS_OK )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
+      LastFFS_ReturnCode = ffs_dbm_fd;
+      return DB_FAIL_FS;
+    }
+
+    ffs_ret_code = ffs_seek( ffs_dbm_fd, 0, FFS_SEEK_SET );
+
+    if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+        ( ffs_ret_code EQ EFFS_INVALID ) OR
+        ( ffs_ret_code EQ EFFS_BADOP )   )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_seek %d", ffs_ret_code );
+      DB_FFS_CLOSE( ffs_dbm_fd );
+      return DB_FAIL;
+    }
+
+    /* buffer for master records */
+    DB_MALLOC( db_buffer, T_DB_MASTER_RECORD_SIZE ); 
+    remb_db_buffer = db_buffer;
+
+    for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+    {
+      db_buffer = remb_db_buffer;
+      ffs_ret_code = ffs_read( ffs_dbm_fd, db_buffer, T_DB_MASTER_RECORD_SIZE );
+
+      if( ( ffs_ret_code EQ EFFS_BADFD ) OR
+          ( ffs_ret_code EQ EFFS_BADOP ) )
+      {
+        TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_read %d", ffs_ret_code );
+        DB_FFS_CLOSE( ffs_dbm_fd );
+        DB_MFREE( db_buffer );
+        return DB_FAIL;
+      }
+
+      if( ffs_ret_code EQ 0 ) /* number of bytes read EQ 0 */
+        break;
+
+      if( *db_buffer EQ 0xFF ) /* if invalid database */
+        continue;
+
+      memcpy( DbmMaster[db_ctr].DBDirectory, db_buffer, MAX_LEN_DIRECTORY );
+      db_buffer += MAX_LEN_DIRECTORY;
+
+      DbmMaster[db_ctr].NumOfFiles = *db_buffer;
+      ++db_buffer;
+
+      DbmMaster[db_ctr].Tracked_Clean = ( *db_buffer ) ? TRACKED_AND_CLEAN : CLEAN;
+      ++db_buffer;
+
+      DbmMaster[db_ctr].UsedFiles = 0;
+
+      DbmMaster[db_ctr].DBState = CLOSED;
+
+      ++UsedDBs;
+
+      /* we need not "seek" here file pointer would have moved to next */
+    }
+    
+    DB_FFS_CLOSE( ffs_dbm_fd ); 
+    DB_MFREE( remb_db_buffer ); /* freeing db_buffer */
+
+    /* For FieldRecords */
+
+    /* buffer for field records */
+    DB_MALLOC( field_buffer, T_DB_FIELD_RECORD_SIZE ); 
+    remb_field_buffer = field_buffer;
+
+    for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+    {
+
+      if( DbmMaster[db_ctr].DBState EQ UNUSED_ENTRY )
+        continue;
+
+      /* Field file = DD_<pos. in DD_master> */
+
+      sprintf( field_file, "%s/DD_%d", DB_DIR, db_ctr);  
+
+      DB_FFS_OPEN( ffs_dbm_fd, field_file_ptr, FFS_O_RDONLY );
+
+      if(  ( ffs_dbm_fd EQ EFFS_NOTFOUND ) OR   /* Field file not found */
+           ( ffs_dbm_fd EQ EFFS_NUMFD )    OR   /* FFS specific errors */
+           ( ffs_dbm_fd EQ EFFS_LOCKED)    )
+      {
+        TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
+        DB_MFREE( field_buffer );
+        return DB_FAIL;
+      }
+
+      ffs_ret_code = ffs_seek( ffs_dbm_fd, 0, FFS_SEEK_SET );
+
+      if( ( ffs_ret_code EQ EFFS_BADFD )   OR
+          ( ffs_ret_code EQ EFFS_INVALID ) OR
+          ( ffs_ret_code EQ EFFS_BADOP )   )
+      {
+        TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_seek %d", ffs_ret_code );
+        DB_FFS_CLOSE( ffs_dbm_fd );
+        DB_MFREE( field_buffer );
+        return DB_FAIL;
+      }
+
+      /* Allocate memory for field records */
+      DB_MALLOC( DbmMaster[db_ctr].ptrFieldRecord, 
+                  DbmMaster[db_ctr].NumOfFiles * sizeof(T_DBM_FIELDRECORD) ); 
+
+      tmp_ptrFieldRecord = DbmMaster[db_ctr].ptrFieldRecord;
+
+      for( fld_ctr = 0; fld_ctr < DbmMaster[db_ctr].NumOfFiles; ++fld_ctr )
+      {
+        field_buffer = remb_field_buffer;
+
+        ffs_ret_code = ffs_read( ffs_dbm_fd, field_buffer, T_DB_FIELD_RECORD_SIZE );
+
+        if( (ffs_ret_code EQ EFFS_BADFD ) OR
+            (ffs_ret_code EQ EFFS_BADOP ) )
+        {
+          TRACE_EVENT_P2( "init_RAM_with_FFS:ffs_seek %d, fld_ctr %d", ffs_ret_code, fld_ctr );
+          DB_FFS_CLOSE ( ffs_dbm_fd );
+          DB_MFREE( field_buffer );
+          DB_MFREE( DbmMaster[db_ctr].ptrFieldRecord );
+          return DB_FAIL; 
+        }
+
+        if( ffs_ret_code EQ 0 ) /* number of bytes read  EQ 0 */
+        {
+          /* we need not go further, just make rest of field ids as invalid (not existing) */
+          for( ; fld_ctr < DbmMaster[db_ctr].NumOfFiles; ++fld_ctr )
+          {
+            tmp_ptrFieldRecord -> FieldID	= INVALID_FIELD_ID;
+            ++tmp_ptrFieldRecord;
+          }
+          break;
+        }
+
+        /* Syncing of field records */
+        
+        tmp_ptrFieldRecord -> FieldID	  = *field_buffer;
+        tmp_ptrFieldRecord -> FieldID <<= MAX_BIT_POS;
+        ++field_buffer;
+        tmp_ptrFieldRecord -> FieldID	 |= *field_buffer;
+        ++field_buffer;
+
+        if ( tmp_ptrFieldRecord -> FieldID NEQ INVALID_FIELD_ID )
+        {
+          tmp_ptrFieldRecord -> DBType = *field_buffer;
+          ++field_buffer;
+
+          tmp_ptrFieldRecord -> RecordSize = *field_buffer;
+          tmp_ptrFieldRecord -> RecordSize <<= MAX_BIT_POS;
+          ++field_buffer;
+          tmp_ptrFieldRecord -> RecordSize |= *field_buffer;
+          ++field_buffer;
+
+          tmp_ptrFieldRecord -> NumOfRecords = *field_buffer;
+          ++field_buffer;
+
+          for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+          {
+            tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = *field_buffer;
+            tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
+            ++field_buffer;
+          }
+
+          memcpy( tmp_ptrFieldRecord -> RecordBitMap, field_buffer, RECORD_BITMAP_SIZE );
+          field_buffer += RECORD_BITMAP_SIZE;
+
+          tmp_ptrFieldRecord -> Clean = *field_buffer;
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+          tmp_ptrFieldRecord -> FFSFileHandle = NULL; 
+#endif
+          /* we need to get size of user file <DBDirectory>/UD_<field_id> 
+             NextRecordNum = (size of user file) / record size */
+          tmp_ptrFieldRecord -> NextRecordNum = 
+                  cal_NextRecordNum ( (const char*)DbmMaster[db_ctr].DBDirectory, 
+                                      tmp_ptrFieldRecord -> FieldID,
+                                      tmp_ptrFieldRecord -> RecordSize );
+                                            
+          /* Update database records for UsedFiles, Clean, and UsedRecords */
+
+          DbmMaster[db_ctr].UsedFiles += 1;
+
+          if( DbmMaster[db_ctr].Tracked_Clean & TRACKED ) /* if db is tracked */
+            if( NOT tmp_ptrFieldRecord -> Clean )          /* if field is not clean */
+              DbmMaster[db_ctr].Tracked_Clean &= ~ CLEAN ;    /* make db as not clean */
+
+
+          /* For calculating UsedRecords */
+
+          tmp_byte_ptr = tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - 1;
+          tmp_num_records = 0;
+          record_num = 0;
+
+          while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
+          {
+            tmp_byte = *tmp_byte_ptr;
+
+            for( bit_num = 0; bit_num < MAX_BIT_POS; ++bit_num )
+            {
+              ++record_num;
+
+              if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
+                break;
+
+              if( tmp_byte & 0x01 )
+                 ++tmp_num_records;
+
+              tmp_byte >>= 1;  
+            }
+
+            --tmp_byte_ptr;
+          }
+
+          tmp_ptrFieldRecord -> UsedRecords = tmp_num_records;
+
+        } /* FieldID NEQ INVALID_FIELD_ID */
+
+        /* go to next field record */
+
+        /* seek is not required here ! */
+
+        ++tmp_ptrFieldRecord;   /* next field */ 
+
+      } /* for( fld_ctr ) ... all fields */
+
+      /* close the DD_<db_handle> file */
+      DB_FFS_CLOSE( ffs_dbm_fd );
+
+    } /* ffs_ret_code >= EFFS_OK */
+
+    DB_MFREE( remb_field_buffer );  /* freeing field buffer */
+
+    DBM_State = DBM_INITIALISED;
+
+    return DB_OK;
+
+  } /* if( ffs_ret_code >= EFFS_OK ) */
+
+  /* Directory not present */
+  if( ffs_ret_code EQ EFFS_NOTFOUND )
+  {
+    /* Create DBM directory */
+    ffs_ret_code = ffs_mkdir( DB_DIR ); 
+    
+    if( (ffs_ret_code EQ EFFS_NAMETOOLONG ) OR
+        (ffs_ret_code EQ EFFS_BADNAME     ) )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code );
+      return DB_FAIL;
+    }
+
+    if( ffs_ret_code < EFFS_OK )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:ffs_mkdir %d", ffs_ret_code );
+      LastFFS_ReturnCode = ffs_ret_code;
+      return DB_FAIL_FS;
+    }
+
+    /* Create empty file DD_master
+       FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and 
+                     the file already exists. */
+
+    DB_FFS_OPEN( ffs_dbm_fd, dbm_file, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
+
+    if( (ffs_dbm_fd EQ EFFS_NAMETOOLONG ) OR
+        (ffs_dbm_fd EQ EFFS_BADNAME     ) )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
+      ffs_ret_code = ffs_remove( DB_DIR ); /* undo creating of DBM directory */
+      return DB_FAIL;
+    }
+
+    if( ffs_dbm_fd < EFFS_OK )
+    {
+      TRACE_EVENT_P1( "init_RAM_with_FFS:DB_FFS_OPEN %d", ffs_dbm_fd );
+      LastFFS_ReturnCode = ffs_dbm_fd;
+      ffs_ret_code = ffs_remove( DB_DIR ); /* undo creating of DBM directory */
+      return DB_FAIL_FS;
+    }
+
+    DB_FFS_CLOSE( ffs_dbm_fd );
+
+    DBM_State = DBM_INITIALISED;
+
+    return DB_OK;
+  }
+
+  /* Unexpected error: Not a directory */
+  return DB_FAIL;
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_create            |
++--------------------------------------------------------------------+
+
+    PURPOSE : Create a new database in the given directory of the FFS. 
+              The directory must not to exist yet, it will be created.
+*/
+int db_create ( const char* directory,
+                UBYTE       num_of_fields,
+                BOOL        tracked )
+{
+  int         db_handle;
+  T_DB_CODE   db_ret_code;
+  UBYTE       fld_ctr;
+  S8          db_ctr;
+  T_FFS_SIZE  ffs_ret_code;
+  T_FFS_FD    ffs_fd;
+  char        field_file[FILENAME_LEN];
+  char*       field_file_ptr = field_file;
+  UBYTE*      dbm_data;
+  UBYTE*      remb_dbm_data;
+
+  TRACE_FUNCTION("db_create()");
+
+  /* If DBM is not in initialized state, call init_RAM_with_FFS (). */
+  if( DBM_State NEQ DBM_INITIALISED )
+  {
+    T_DB_CODE db_ret_code;
+
+    db_ret_code = init_RAM_with_FFS();
+
+    if( db_ret_code NEQ DB_OK )
+      DB_RETURN( db_ret_code );
+  }
+
+  /* See if you have reached the maximum number of DBs, ? 
+     (UsedDBs+1) > MAX_DBs */
+
+  if( UsedDBs EQ MAX_DBs )
+    DB_RETURN( DB_FULL );
+
+
+  /* Check DbmMaster if already database for "directory" exists. 
+     If yes, return error "DB_EXISTS" */
+
+  for( db_ctr = (MAX_DBs - 1); db_ctr >= 0; --db_ctr )
+  {
+    if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
+    {
+        if( memcmp( DbmMaster[db_ctr].DBDirectory, 
+                    directory, 
+                    strlen( directory )          ) EQ 0 )
+          DB_RETURN( DB_EXISTS );
+    } else {
+      db_handle = db_ctr;
+    }
+  }
+
+  /* sanity check */
+  if( num_of_fields <= 0 )
+    DB_RETURN( DB_FAIL );
+
+  /* Create a directory, "<DBDirectory>" (DBDirectory = directory) */
+  ffs_ret_code = ffs_mkdir( directory ); 
+
+  if( ffs_ret_code < EFFS_OK ) 
+  {
+    TRACE_EVENT_P1( "db_create:ffs_mkdir %d", ffs_ret_code );
+    LastFFS_ReturnCode = ffs_ret_code;
+    DB_RETURN( DB_FAIL_FS );
+  }
+
+
+  /* Create a empty file, "~/dbm/DD_<position in DD_master = db_handle>"; 
+     if this FFS operation fails, we need to delete the directory 
+     before returning error. 
+  */
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle);  
+
+  TRACE_EVENT_P1( "field_file %s", field_file );
+
+  /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and 
+                   the file already exists. */
+  DB_FFS_OPEN( ffs_fd, field_file_ptr, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); 
+
+  if( ( ffs_fd EQ EFFS_EXISTS )      OR
+      ( ffs_fd EQ EFFS_NAMETOOLONG ) OR
+      ( ffs_fd EQ EFFS_BADNAME )     OR
+      ( ffs_fd EQ EFFS_INVALID )     )
+  {
+    TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd );
+    ffs_fd = ffs_remove( directory ); 
+    DB_RETURN( DB_FAIL );
+  }
+
+  if( ffs_fd < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "db_create:DB_FFS_OPEN %d", ffs_fd );
+    LastFFS_ReturnCode = ffs_fd;
+    ffs_ret_code = ffs_remove( directory ); 
+    DB_RETURN( DB_FAIL_FS );
+  }
+
+  /* DB_FFS_CLOSE( ffs_fd ); we will close it in db_flush */
+
+#ifdef FFS_OPEN_PROBLEM_PATCH
+  DB_FFS_CLOSE( ffs_fd );
+#endif
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  /* no we do not close it */
+#endif
+
+  /* Update FFS data i.e. file, "~/dbm/DD_master". */
+
+  /* prepare the dbm data and write */
+  DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE );
+  memset( dbm_data, 0, T_DB_MASTER_RECORD_SIZE );
+  remb_dbm_data = dbm_data;
+
+  memcpy( dbm_data, directory, MAX_LEN_DIRECTORY );
+  dbm_data += MAX_LEN_DIRECTORY;
+  
+  *dbm_data = num_of_fields;
+  ++dbm_data;
+
+  *dbm_data = ( tracked ) ? FFS_TRACKED : FFS_NOT_TRACKED;
+
+  dbm_data = remb_dbm_data;
+
+  db_ret_code = 
+    update_dbm_data_in_FFS ( DB_MASTER_FILE,
+                             (UBYTE) db_handle,   /* to supress warning */
+                             T_DB_MASTER_RECORD_SIZE,
+                             dbm_data,
+                             0,
+                             T_DB_MASTER_RECORD_SIZE );
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( dbm_data );
+    ffs_ret_code = ffs_remove( directory );
+    DB_FFS_CLOSE( ffs_fd );
+    ffs_ret_code = ffs_remove( field_file );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( dbm_data );
+  /* updation of DD_master done 
+     now update RAM structures  */
+
+  memcpy( DbmMaster[db_handle].DBDirectory, 
+          directory, 
+          strlen(directory) );
+
+  DbmMaster[db_handle].NumOfFiles    = num_of_fields;
+  DbmMaster[db_handle].UsedFiles     = 0;  
+  DbmMaster[db_handle].Tracked_Clean = ( tracked ) ? TRACKED_AND_CLEAN : CLEAN;
+  DbmMaster[db_handle].DBState       = OPEN;
+  DbmMaster[db_handle].FFSFileHandle = ffs_fd;
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+
+  /* No files corresponding to fields have been opened 
+     This initialization is already done in db_init */
+
+#endif
+  
+  /* Allocate memory for storing field information 
+     and initialize the memory with "FF" */
+
+  DB_MALLOC( DbmMaster[db_handle].ptrFieldRecord, 
+              num_of_fields * sizeof(T_DBM_FIELDRECORD) );
+
+  for( fld_ctr = 0; fld_ctr < num_of_fields; ++fld_ctr )
+  {
+    DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID = INVALID_FIELD_ID; 
+  }
+
+  UsedDBs++;
+
+  DB_RETURN( db_handle );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_open              |
++--------------------------------------------------------------------+
+
+    PURPOSE : Open an existing database
+*/
+int db_open ( const char *directory )
+{
+  T_DB_CODE  db_ret_code;
+  UBYTE      db_ctr;
+
+  TRACE_FUNCTION("db_open()");
+
+  /* If DBM is not in initialized state, call init_RAM_with_FFS (). */
+  if( DBM_State NEQ DBM_INITIALISED )
+  {
+    db_ret_code = init_RAM_with_FFS();
+
+    if( db_ret_code NEQ DB_OK )
+      DB_RETURN( db_ret_code );
+  }
+
+  /* Search for "directory" in DbmMaster */
+  for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+  {
+    if( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
+    {
+        if( memcmp( DbmMaster[db_ctr].DBDirectory, 
+                    directory, 
+                    strlen(directory)                     ) EQ 0 )
+          break;
+    } 
+  }
+
+  /* If "directory" not found, return DB_FAIL. */
+  if( db_ctr EQ MAX_DBs )
+    DB_RETURN( DB_INVALID_DB );
+
+  /* Update DBState as "OPEN". */
+  DbmMaster[db_ctr].DBState = OPEN;
+
+  /* Return corresponding DBHandle. */
+  DB_RETURN( db_ctr );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_create_field      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Create a new elementary file of a given type with a given 
+              numeric identifier and a given record size.
+*/
+T_DB_CODE db_create_field ( int         db_handle, 
+                            T_DB_TYPE   db_type, 
+                            USHORT      field_id, 
+                            USHORT      record_size, 
+                            USHORT      num_of_records )
+{
+  T_DB_CODE          db_ret_code;
+  char               user_field_file[FILENAME_LEN],
+                     field_file[FILENAME_LEN];
+  char*              user_field_file_ptr = user_field_file;
+  char*              field_file_ptr = field_file;
+  UBYTE              fld_ctr,
+                     sort_index_ctr;
+  T_FFS_SIZE         ffs_ret_code;
+  T_FFS_FD           ffs_fd_user_field_file;
+  UBYTE*             field_data;
+  UBYTE*             remb_field_data;
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;  
+
+
+  TRACE_FUNCTION("db_create_field()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field id found, return error DB_FIELD_EXISTS */
+  if( field_id_search( db_handle, field_id ) NEQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_FIELD_EXISTS );
+
+  /* If limit for number of fields for this DB has been reached, return error DB_FULL. */
+  if( DbmMaster[db_handle].UsedFiles  EQ 
+      DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_FULL );
+
+  /* Search for free field entry in field records corresponding to the database. */
+  for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
+  {
+    if( DbmMaster[db_handle].ptrFieldRecord[fld_ctr].FieldID EQ INVALID_FIELD_ID )
+      break;
+  }
+
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+  { /* this is "inconsistency"; should never happen */
+    DB_RETURN( DB_FAIL );
+  }
+
+  /* sanity check */
+  if( ( num_of_records <= 0 ) OR
+      ( record_size <= 0 )    )
+  {
+    DB_RETURN( DB_FAIL );    
+  }
+
+  /* Create file "<DBDirectory>/UD_<field_id>" */
+  sprintf( user_field_file, "%s/UD_%d", DbmMaster[db_handle].DBDirectory, field_id );
+
+  /* FFS_O_EXCL => Generate error if FFS_O_CREATE is also specified and 
+                   the file already exists. */
+#ifndef FFS_CLOSE_BEFORE_OPEN
+
+  DB_FFS_OPEN( ffs_fd_user_field_file, user_field_file_ptr, FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL ); 
+
+#else
+
+  ffs_fd_user_field_file = 
+    db_open_user_field_file( db_handle, 
+                             fld_ctr, 
+                             user_field_file_ptr, 
+                             FFS_O_CREATE | FFS_O_RDWR | FFS_O_EXCL );
+#endif
+
+  if( ( ffs_fd_user_field_file EQ EFFS_EXISTS )      OR
+      ( ffs_fd_user_field_file EQ EFFS_NAMETOOLONG ) OR
+      ( ffs_fd_user_field_file EQ EFFS_BADNAME )     OR
+      ( ffs_fd_user_field_file EQ EFFS_INVALID )     )
+  {
+    TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file );
+    DB_RETURN( DB_FAIL );
+  }
+
+  if( ffs_fd_user_field_file < EFFS_OK )
+  {
+    TRACE_EVENT_P1( "db_create_field:DB_FFS_OPEN %d", ffs_fd_user_field_file );
+    LastFFS_ReturnCode = ffs_fd_user_field_file;
+    DB_RETURN( DB_FAIL_FS );
+  }
+
+  /* We will close this file in db_flush */
+
+#ifdef FFS_OPEN_PROBLEM_PATCH
+  DB_FFS_CLOSE( ffs_fd_user_field_file );
+#endif
+
+  
+  /* file "<DBDirectory>/UD_<field_id>" has been created 
+     Now, Add new field entry in "~/dbm/DD_<db_handle>" */
+
+  /* create the field data that needs to be written */
+
+  DB_MALLOC( field_data, T_DB_FIELD_RECORD_SIZE );
+  memset( field_data, 0, T_DB_FIELD_RECORD_SIZE );
+  remb_field_data = field_data;
+
+  *field_data = (UBYTE) ( (field_id & 0xFF00) >> MAX_BIT_POS ); 
+  ++field_data;
+  *field_data = (UBYTE) (field_id & 0x00FF);
+  ++field_data;
+
+  *field_data = db_type; 
+  ++field_data;
+
+  *field_data = (UBYTE) ( (record_size & 0xFF00) >> MAX_BIT_POS );
+  ++field_data;
+  *field_data = (UBYTE) (record_size & 0x00FF);
+  ++field_data;
+
+  *field_data = (UBYTE)num_of_records;
+  field_data++;
+  
+  memset( field_data, 0xFF, MAX_NUM_OF_SORT_INDEXS ); 
+  field_data += MAX_NUM_OF_SORT_INDEXS;
+
+  memset( field_data, 0, RECORD_BITMAP_SIZE );
+  field_data += RECORD_BITMAP_SIZE;
+
+  *field_data = CLEAN; /* Clean is true */
+  
+  field_data = remb_field_data;
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  db_ret_code = 
+    update_field_data_in_FFS ( (const char*)field_file,
+                               &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                               db_handle,
+#endif
+                               fld_ctr,
+                               T_DB_FIELD_RECORD_SIZE,
+                               field_data,
+                               0,
+                               T_DB_FIELD_RECORD_SIZE );
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( field_data );
+    ffs_ret_code = ffs_remove( user_field_file );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( field_data );
+  /* updation of DD_<db_handle> is over */
+
+  /* Add new field entry in field records in RAM. */
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  tmp_ptrFieldRecord -> FieldID       = field_id;
+  tmp_ptrFieldRecord -> DBType        = db_type;
+  tmp_ptrFieldRecord -> RecordSize    = record_size;
+  tmp_ptrFieldRecord -> NumOfRecords  = (UBYTE)num_of_records;
+  tmp_ptrFieldRecord -> UsedRecords   = 0; 
+  tmp_ptrFieldRecord -> Clean         = CLEAN;
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+  tmp_ptrFieldRecord -> FFSFileHandle = ffs_fd_user_field_file;
+#endif
+
+  tmp_ptrFieldRecord -> NextRecordNum = 1;
+
+  memset( tmp_ptrFieldRecord -> RecordBitMap, 0, RECORD_BITMAP_SIZE );
+
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr]  = INVALID_SORT_INDEX;
+    tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]    = NULL;
+  }
+
+  /* Increment UsedFiles for the particular database in RAM */
+  DbmMaster[db_handle].UsedFiles += 1;
+
+  /* everyting ok */
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_write_record      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Write length bytes at offset into the given record in 
+              (database, field)
+*/
+int db_write_record ( int          db_handle,	 
+                      USHORT       field_id, 
+                      USHORT       record_num, 
+                      USHORT       offset, 
+                      USHORT       length, 
+                      const UBYTE* buffer )
+{
+  T_DB_CODE  db_ret_code;
+
+  UBYTE fld_ctr,
+        tmp_byte,
+        rec_ctr;
+
+  char  user_field_file[FILENAME_LEN],
+        field_file[FILENAME_LEN];              
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  UBYTE*  record_buffer;
+  UBYTE*  field_data;
+
+  BOOL this_is_new_record = TRUE;
+
+  TRACE_FUNCTION("db_write_record()");
+
+  TRACE_EVENT_P1("field_id %d", field_id);
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Check if record exceeds the record size (i.e. offset + length > record size); 
+     if it exceeds, return error DB_INVALID_SIZE */
+  if( (offset + length) > 
+      tmp_ptrFieldRecord -> RecordSize )
+    DB_RETURN( DB_INVALID_SIZE );
+
+  /* Check if FFS file is already opened using FFSFileHandle, part of field record. 
+     If it is not yet opened, open the FFS file and update FFSFileHandle. 
+     This is taken care in read_user_record_from_FFS */
+
+  /* User data file name is "<DBDirectory>/UD_<field_id>" 
+     This would be used below */
+
+  sprintf( user_field_file, 
+           "%s/UD_%d", 
+           DbmMaster[db_handle].DBDirectory, 
+           tmp_ptrFieldRecord -> FieldID );
+
+  if( record_num EQ 0 )
+  {
+    /* If given record is equal to zero, 
+        o	Find a free record using RecordBitMap.
+        o	If free record not found, return DB_FULL */
+
+    record_num = 1 + search_clear_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
+                                                 RECORD_BITMAP_SIZE );
+
+    if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
+      DB_RETURN( DB_FULL );
+                                             
+
+  } else {
+    /* If given record is not equal to zero, 
+        o	Check if record exists using RecordBitMap; 
+          if not found, proceed to writing..
+        o	Read the record from "<DBDirectory>/UD_<field_id>" and 
+          compare it with given record (partially if offset > 0). Memcmp would be used.
+        o	If record match, return DB_OK. */
+
+    /* record_num = bit_pos + (8 * bitmap_idx) + 1; 
+       bitmap_idx  = (record_num - 1) / MAX_BIT_POS;
+       bit_pos     = (record_num - 1) % MAX_BIT_POS;  */
+    
+    tmp_byte = 
+      (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1];
+
+    if( tmp_byte & ( 0x01 << BIT_POS(record_num) )  )  /* record exists */
+    {
+      this_is_new_record = FALSE;
+
+      DB_MALLOC( record_buffer, length); 
+
+      db_ret_code = 
+        read_user_record_from_FFS ( user_field_file,
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+                                    &(tmp_ptrFieldRecord -> FFSFileHandle),
+#else
+                                    db_handle,
+                                    fld_ctr,
+                                    &Dummy_FFSFileHandle,
+#endif
+                                    (UBYTE)record_num,
+                                    tmp_ptrFieldRecord -> RecordSize,
+                                    offset,
+                                    length,
+                                    record_buffer );
+      if( db_ret_code NEQ DB_OK )
+      {
+        DB_MFREE( record_buffer );
+        DB_RETURN( db_ret_code );
+      }
+
+      /* See if there is same data, if so, we need not overwrite */
+      if( memcmp( record_buffer, buffer, length) EQ 0 )
+      { /* matching data */
+        DB_MFREE( record_buffer );
+        DB_RETURN( DB_OK );
+      }
+
+      DB_MFREE( record_buffer );
+
+    } /* record exists */
+
+  } /* record_num EQ 0 ? */
+
+
+  /* As per the request, write record in FFS in "<DBDirectory>/UD_<field_id>" */
+
+  /* in case of new record, we need to create fill unfilled-data with FF */
+
+  if( this_is_new_record )
+  { /* new record */
+
+    DB_MALLOC( record_buffer, tmp_ptrFieldRecord -> RecordSize ); 
+    memset( record_buffer, 0xFF, tmp_ptrFieldRecord -> RecordSize ) ;
+
+    /* To take care of non-sequential write 
+       For example, initially when file is empty, and say user writes
+       3rd record, 1st and 2nd record should be addded as dummy and then
+       3rd record */
+
+    rec_ctr = tmp_ptrFieldRecord -> NextRecordNum;
+
+    while( rec_ctr < record_num   )
+    {
+      db_ret_code = 
+        write_user_record_to_FFS ( user_field_file,
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+                                   &(tmp_ptrFieldRecord -> FFSFileHandle),
+#else
+                                   db_handle,
+                                   fld_ctr,
+                                   &Dummy_FFSFileHandle,
+#endif
+                                   rec_ctr,
+                                   tmp_ptrFieldRecord -> RecordSize,
+                                   0,
+                                   tmp_ptrFieldRecord -> RecordSize,
+                                   record_buffer );
+      if( db_ret_code NEQ DB_OK )
+      {
+        DB_MFREE( record_buffer );
+        DB_RETURN( db_ret_code );
+      }
+
+      ++rec_ctr;
+    }
+
+    /* Add the new record */
+
+    memcpy( record_buffer + offset, buffer, length );
+
+    db_ret_code = 
+      write_user_record_to_FFS ( user_field_file,
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+                                 &(tmp_ptrFieldRecord -> FFSFileHandle),
+#else
+                                 db_handle,
+                                 fld_ctr,
+                                 &Dummy_FFSFileHandle,
+#endif
+                                 (UBYTE)record_num,
+                                 tmp_ptrFieldRecord -> RecordSize,
+                                 0,
+                                 tmp_ptrFieldRecord -> RecordSize,
+                                 record_buffer );
+    if( db_ret_code NEQ DB_OK )
+    {
+      DB_MFREE( record_buffer );
+      DB_RETURN( db_ret_code );
+    }
+
+    DB_MFREE( record_buffer );
+
+    /* writing of record is over, update DBState (as IN_USE). */
+    DbmMaster[db_handle].DBState = IN_USE;
+
+  } else {
+    /* overwritten record */ 
+
+    db_ret_code = 
+      write_user_record_to_FFS ( user_field_file,
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+                                 &(tmp_ptrFieldRecord -> FFSFileHandle),
+#else
+                                 db_handle,
+                                 fld_ctr,
+                                 &Dummy_FFSFileHandle,
+#endif
+                                 (UBYTE)record_num,
+                                 tmp_ptrFieldRecord -> RecordSize,
+                                 offset,
+                                 length,
+                                 (UBYTE*)buffer );  /* type casting to suppress warning */
+    if( db_ret_code NEQ DB_OK )
+    {
+      DB_RETURN( db_ret_code );
+    }
+
+    /* writing of record is over, update DBState (as IN_USE). */
+    DbmMaster[db_handle].DBState = IN_USE;
+
+#ifdef INSERTION_SORT
+
+    /* get the sort lists in RAM from FFS */
+    get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
+
+    /* this is updation of record, so need to be re-sorted */
+    update_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
+
+#endif
+
+    /* if database is not tracked, no need to go further for history log writing */
+    if( NOT ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) )
+      DB_VALUE_RETURN( record_num );
+
+    /* if already Clean has been reset, only history updation */
+    if( NOT ( DbmMaster[db_handle].Tracked_Clean & CLEAN ) )
+    {
+      db_ret_code = update_history_log( db_handle, field_id, record_num );
+
+      if( db_ret_code NEQ DB_OK )
+        DB_RETURN( db_ret_code );
+
+      DB_VALUE_RETURN( record_num );
+    }
+
+  } /* this_is_new_record */
+
+  /* Updating RecordBitMap and Clean in FFS, ~/dbm/DD_<db_handle> */
+
+  /* create the field data that is to be written */
+
+  DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+  memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+  memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE );
+
+  if( this_is_new_record )
+  { /* RecordBitMap to be updated only for new records */
+    set_bit_in_bitmap( field_data,
+                       RECORD_BITMAP_SIZE,
+                       (UBYTE)record_num );
+  } 
+
+  /* clean is reset in memset, so no processing for it 
+     (in case of non-tracked database, anyway we ignore it ! */ 
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  db_ret_code = 
+    update_field_data_in_FFS ( (const char*)field_file,
+                               &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                               db_handle,
+#endif
+                               fld_ctr,
+                               T_DB_FIELD_RECORD_SIZE,
+                               field_data,
+                               RecordBitMap_OFFSET,
+                               ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( field_data );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( field_data );
+  /* updation of DD_<db_handle> is over */
+
+  /* Updating RAM (both DbmMaster and Field records) strctures */
+  tmp_ptrFieldRecord -> Clean = NOT_CLEAN;
+
+  if( this_is_new_record )
+  { /* RecordBitMap to be updated only for new records */
+    set_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
+                       RECORD_BITMAP_SIZE,
+                       (UBYTE)record_num );
+
+    ++tmp_ptrFieldRecord -> UsedRecords;
+
+    tmp_ptrFieldRecord -> NextRecordNum =  
+        ( (record_num + 1) > tmp_ptrFieldRecord -> NextRecordNum ) ?
+          (record_num + 1) : tmp_ptrFieldRecord -> NextRecordNum ;
+
+#ifdef INSERTION_SORT
+
+    /* get the sort lists in RAM from FFS */
+    get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
+
+    /* note the record number for sorting later 
+       yeah, we call it *after* updating UsedRecords */
+    new_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
+
+#endif
+
+  }
+
+  DbmMaster[db_handle].Tracked_Clean &= ~(CLEAN);
+
+  /* history log updation */
+
+  db_ret_code = update_history_log( db_handle, field_id, record_num );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  DB_VALUE_RETURN( record_num );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_create_index      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Creates or updates a sort index for a given (database, field)
+*/
+T_DB_CODE db_create_index ( int          db_handle, 
+                            USHORT       field_id, 
+                            UBYTE        sort_index, 
+                            T_COMP_FUNC  compare_function, 
+                            ULONG        flags )
+{
+
+  return internal_db_sort( db_handle,
+                           field_id,
+                           sort_index,
+                           compare_function,
+                           flags,
+                           QUICK_SORT );
+}
+
+
+#ifdef INSERTION_SORT
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_update_index      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Sort the list for newly added/deleted records (uses incremental
+              sort i.e. add the element at the right place)
+*/
+T_DB_CODE db_update_index ( int          db_handle, 
+                            USHORT       field_id, 
+                            UBYTE        sort_index, 
+                            T_COMP_FUNC  compare_function, 
+                            ULONG        flags )
+{
+
+  return internal_db_sort( db_handle,
+                           field_id,
+                           sort_index,
+                           compare_function,
+                           flags,
+                           INCREMENTAL_SORT );
+}
+#endif /* INSERTION_SORT */
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_get_phy_from_idx  |
++--------------------------------------------------------------------+
+
+    PURPOSE : Translates a logical entry within a given sort index to the 
+              physical record number
+*/
+T_DB_CODE db_get_phy_from_idx ( int    db_handle, 
+                                USHORT field_id, 
+                                UBYTE  sort_index, 
+                                USHORT order_num )
+{
+  T_DB_CODE          db_ret_code;
+  UBYTE              fld_ctr,
+                     sort_index_ctr;
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+  char              sort_file[FILENAME_LEN];
+
+
+  TRACE_FUNCTION("db_get_phy_from_idx()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* sanity check on order_num */
+  if( ( order_num > tmp_ptrFieldRecord -> NumOfRecords ) OR
+      ( order_num EQ 0 ) )
+    DB_RETURN( DB_FAIL );  /* may be we can return 0xFF => no record for it ! */
+
+  /* Search given sort_index in SortIndexList for above field_id; 
+     if not found, return DB_INVALID_INDEX. */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
+      break;
+  }
+
+  if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
+    DB_RETURN( DB_INVALID_INDEX );
+
+  /* Check if we already have sorted list in RAM structure SortedLists */
+
+  if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
+  { 
+    /* If no, populate the sorted list from file, 
+       "<DBDirectory>/UD_<field_id>_sort_<sort_index>". 
+       Sorted lists are freed in db_flush */
+
+    sprintf( sort_file, 
+             "%s/UD_%d_sort_%d", 
+             DbmMaster[db_handle].DBDirectory, 
+             tmp_ptrFieldRecord -> FieldID,
+             sort_index );
+
+    db_ret_code = 
+      populate_sorted_list_from_FFS (  
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                      db_handle,
+#endif
+                                      sort_file,
+                                      tmp_ptrFieldRecord -> NumOfRecords,
+                                      &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
+    if( db_ret_code NEQ DB_OK )
+      DB_RETURN( db_ret_code );
+    
+  } /* if we have sort list */
+
+  /* Get (physical) record number for given order_num from sorted list. */
+  DB_VALUE_RETURN( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][order_num - 1] );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_flush             |
++--------------------------------------------------------------------+
+
+    PURPOSE : Flush all internal data structures of the database described by 
+              db_handle
+*/
+T_DB_CODE db_flush ( int db_handle)
+{
+  UBYTE db_ret_code,
+        clean_byte,
+        fld_ctr,
+        i;
+
+  char field_file[FILENAME_LEN];
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  char sort_file[FILENAME_LEN];
+
+  T_FFS_STAT ffs_file_stat;
+  T_FFS_SIZE ffs_ret_code;
+
+  TRACE_FUNCTION("db_flush()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /* Clear "clean" in "~/dbm/DD_<db_handle>" for fields. 
+     after ffs updation, update RAM data */
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  clean_byte = CLEAN;
+
+  /* Update the affected field records */
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+  db_close_user_field_files( db_handle );
+#endif;
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord;
+
+  for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
+  {
+    if( tmp_ptrFieldRecord -> FieldID EQ INVALID_FIELD_ID ) /* if not valid field id */
+    {
+      ++tmp_ptrFieldRecord;   /* next field */
+      continue;
+    }
+
+    /* Clear file handles */
+#ifndef FFS_CLOSE_BEFORE_OPEN
+
+    if( tmp_ptrFieldRecord -> FFSFileHandle NEQ NULL )
+    {
+      DB_FFS_CLOSE( tmp_ptrFieldRecord -> FFSFileHandle );
+      tmp_ptrFieldRecord -> FFSFileHandle = NULL;
+    }
+
+#else
+    /* Done it closing before for loop */
+#endif
+
+    /* Write sort lists to FFS and clear (free memory) sort lists */
+    for( i = 0; i < MAX_NUM_OF_SORT_INDEXS; ++i )
+    {
+      if( tmp_ptrFieldRecord -> SortedLists[i] NEQ NULL )
+      {
+        /* currently I am not removing unused entries in sort list */
+        /* Write sorted lists to "<DBDirectory>/UD_<field_id>_sort_<sort_index>". */
+
+        sprintf( sort_file, 
+                 "%s/UD_%d_sort_%d", 
+                 DbmMaster[db_handle].DBDirectory, 
+                 tmp_ptrFieldRecord -> FieldID,
+                 tmp_ptrFieldRecord -> SortIndexList[i] );
+
+        /* writing sorted lists to FFS s required in two cases
+           1) the field is not clean and/or
+           2) sort file does not exist, but we have sort list (happen during 
+               bootup time with zero records)
+         */
+        
+        ffs_ret_code = ffs_stat( sort_file, &ffs_file_stat );
+
+        if( ( ffs_ret_code NEQ EFFS_OK )      AND
+            ( ffs_ret_code NEQ EFFS_NOTFOUND ) )
+        {
+          LastFFS_ReturnCode = ffs_ret_code;
+          DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
+          tmp_ptrFieldRecord -> SortedLists[i] = NULL;
+          DB_RETURN( DB_FAIL_FS );
+        }
+
+        if( ( NOT tmp_ptrFieldRecord -> Clean )  OR /* not clean (consistent) */
+            ( ffs_ret_code EQ EFFS_NOTFOUND )    )  /* file does not exist */
+        {
+          db_ret_code =
+            write_sorted_list_to_FFS ( 
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                       db_handle,
+#endif
+                                       sort_file,
+                                       tmp_ptrFieldRecord -> NumOfRecords,
+                                       tmp_ptrFieldRecord -> SortedLists[i] );
+
+          if( db_ret_code NEQ DB_OK )
+          {
+            DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
+            tmp_ptrFieldRecord -> SortedLists[i] = NULL;
+            DB_RETURN( db_ret_code );
+          }
+        }
+
+        /* writing in sort file is over */
+        DB_MFREE( tmp_ptrFieldRecord -> SortedLists[i] );
+        tmp_ptrFieldRecord -> SortedLists[i] = NULL;
+      }
+    }
+
+    if( tmp_ptrFieldRecord -> Clean ) /* is it clean (consistent) ? */
+    {
+      ++tmp_ptrFieldRecord;   /* next field */
+      continue;
+    }
+
+    /* Clear "clean" in "~/dbm/DD_<db_handle>" if not clean  */
+
+    db_ret_code = 
+      update_field_data_in_FFS ( (const char*)field_file,
+                                 &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                 db_handle,
+#endif
+                                 fld_ctr,
+                                 T_DB_FIELD_RECORD_SIZE,
+                                 &clean_byte,
+                                 ( T_DB_FIELD_RECORD_SIZE - 1 ) ,
+                                 1 );       /* "Clean" contained in last one byte */
+
+    if( db_ret_code NEQ DB_OK )
+    {
+      /* this leaves out FFS and RAM in consistent state, 
+         this is ok since FFS is in correct state for some of fields ! */
+      DB_RETURN( db_ret_code );
+    }
+
+    tmp_ptrFieldRecord -> Clean = CLEAN;
+
+    ++tmp_ptrFieldRecord;   /* next field */
+
+  } /* for all field records */
+
+  if( DbmMaster[db_handle].FFSFileHandle NEQ NULL )
+  {
+    DB_FFS_CLOSE( DbmMaster[db_handle].FFSFileHandle );
+  }
+
+  /* updation of FFS is over */
+
+  /* Update corresponding "clean" field for database in RAM data structures, 
+     also DBState = OPEN */
+  DbmMaster[db_handle].Tracked_Clean |= CLEAN;
+  DbmMaster[db_handle].DBState = OPEN;
+
+  /* done */
+  DB_RETURN( DB_OK );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_search            |
++--------------------------------------------------------------------+
+
+    PURPOSE : Searches for an entry within a given database and a given file
+*/
+int db_search ( int               db_handle, 
+                USHORT            field_id, 
+                UBYTE             sort_index, 
+                UBYTE*            order_num,
+                T_SEARCH_FUNC     search_function, 
+                ULONG             flags, 
+                const UBYTE*      search_tag )
+{
+  T_DB_CODE  db_ret_code;
+
+  UBYTE fld_ctr,
+        tmp_byte,
+        sort_index_ctr,
+        bit_num;
+
+  UBYTE* tmp_byte_ptr;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  char sort_file[FILENAME_LEN];              
+
+  int record_num = 0,
+      index_num ;
+
+  TRACE_FUNCTION("db_search()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  if( sort_index EQ 0 )
+  {
+    /* If sort_index is zero, 
+        o	Do linear search using RecordBitMap, search/comparison function is given by caller.
+        o	If search is successful, return the record number.
+        o	Otherwise return DB_RECORD_NOT_FOUND. */
+
+    /* Sanity check */
+    if( (*order_num) > tmp_ptrFieldRecord -> NumOfRecords )
+      DB_RETURN( DB_FAIL );
+
+    /* search from next record,
+       search_node->top would be zero for fresh search */
+
+    record_num = *order_num;
+
+    /* get the correct byte */
+    tmp_byte_ptr = 
+      tmp_ptrFieldRecord -> RecordBitMap + RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1;
+    tmp_byte = *tmp_byte_ptr;
+
+    /* get the correct bit position */
+    bit_num = BIT_POS(record_num);
+    tmp_byte >>= bit_num;
+
+    /* for bytes in bitmap */
+    while( record_num < tmp_ptrFieldRecord -> NumOfRecords )
+    {
+      /* for bits in byte */
+      while( bit_num < MAX_BIT_POS )
+      {
+        if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
+          break;
+
+        if( NOT (tmp_byte & 0x01 ) ) /* if record does not exist, move on to next */
+        {
+          tmp_byte >>= 1;
+          ++bit_num;
+          ++record_num;
+          continue;
+        }
+
+        /* ok, this is a valid record */
+
+        if( search_function( flags,
+                             search_tag, 
+                             db_handle, 
+                             field_id,
+                             (UBYTE)record_num ) 
+            EQ 0 )  /* yeah, "EQ 0" is success */
+        {
+          /* found it ! */
+          *order_num = record_num; /* for next search */
+          DB_VALUE_RETURN( record_num );
+        }
+
+        tmp_byte >>= 1;
+        ++bit_num;
+        ++record_num;
+                             
+      } /* for bits in byte */
+
+      --tmp_byte_ptr;
+      tmp_byte = *tmp_byte_ptr;
+      bit_num = 0;
+
+    } /* for bytes in bitmap */
+
+    /* record not found */
+    DB_RETURN( DB_RECORD_NOT_FOUND );
+
+  } else {
+    /* If sort_index is not zero, search using sorted list */
+
+    /* Search given sort_index in SortIndexList for above field_id; 
+       if not found, return DB_INVALID_INDEX. */
+    for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+    {
+      if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
+        break;
+    }
+
+    if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
+      DB_RETURN( DB_INVALID_INDEX );
+
+    if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] EQ NULL )
+    { 
+      /* If no, populate the sorted list from file, 
+         "<DBDirectory>/UD_<field_id>_sort_<sort_index>". 
+         Sorted lists are freed in db_flush */
+
+      sprintf( sort_file, 
+               "%s/UD_%d_sort_%d", 
+               DbmMaster[db_handle].DBDirectory, 
+               tmp_ptrFieldRecord -> FieldID,
+               sort_index );
+
+      db_ret_code = 
+        populate_sorted_list_from_FFS (  
+
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                                        db_handle,
+#endif
+                                        sort_file,
+                                        tmp_ptrFieldRecord -> NumOfRecords,
+                                        &(tmp_ptrFieldRecord -> SortedLists[sort_index_ctr]) );
+
+      if( db_ret_code NEQ DB_OK )
+        DB_RETURN( db_ret_code );
+
+    }
+
+    /* (Binary) search the sorted list, search/compare function is given by caller. 
+       o	If search is successful, return the record number.
+       o	Otherwise return DB_RECORD_NOT_FOUND */
+
+
+    index_num = 
+           search( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr],
+                   tmp_ptrFieldRecord -> UsedRecords,
+                   order_num,
+                   search_function, 
+                   flags, 
+                   search_tag,
+                   db_handle, 
+                   field_id );
+
+    if( index_num EQ SEARCH_FAILED )
+      DB_RETURN( DB_RECORD_NOT_FOUND );
+
+    DB_VALUE_RETURN( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr][index_num - 1] );
+                   
+  }
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_delete_record     |
++--------------------------------------------------------------------+
+
+    PURPOSE : Delete a record in the given field of the given database
+*/
+T_DB_CODE db_delete_record ( int    db_handle,
+                             USHORT field_id, 
+                             USHORT record_num )
+{
+  T_DB_CODE  db_ret_code;
+
+  UBYTE fld_ctr,
+        tmp_byte;
+
+  char  field_file[FILENAME_LEN];              
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  UBYTE*  field_data;
+
+  TRACE_FUNCTION("db_delete_record()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Using RecordBitMap, check whether record_num exists; 
+     if it does not exist, return DB_OK. */
+
+  tmp_byte = 
+    (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1];
+
+  if( NOT ( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) )  /* if record does *not* exist */
+    DB_RETURN( DB_OK );
+
+  /* Update "Clean" and "RecordBitMap" fields in "~/dbm/DD_<db_handle>" */
+
+  /* create the field data that is to be written */
+
+  DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+  memset( field_data, 0, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+  memcpy( field_data, tmp_ptrFieldRecord -> RecordBitMap, RECORD_BITMAP_SIZE );
+
+  /* updating RecordBitMap */
+  reset_bit_in_bitmap( field_data,
+                       RECORD_BITMAP_SIZE,
+                       (UBYTE)record_num );
+
+  /* clean is reset in memset, so no processing for it 
+     (in case of non-tracked database, anyway we ignore it ! */ 
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  db_ret_code = 
+    update_field_data_in_FFS ( (const char*)field_file,
+                               &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                               db_handle,
+#endif
+                               fld_ctr,
+                               T_DB_FIELD_RECORD_SIZE,
+                               field_data,
+                               RecordBitMap_OFFSET,
+                               ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( field_data );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( field_data );
+  /* updation of DD_<db_handle> is over */
+
+  /* Update corresponding "Clean" and "RecordBitMap" fields in RAM data structures, 
+     also update DBState (as IN_USE) and decrement UsedRecords. */
+
+  tmp_ptrFieldRecord -> Clean = NOT_CLEAN;
+
+  /* updating RecordBitMap */
+  reset_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
+                       RECORD_BITMAP_SIZE,
+                       (UBYTE)record_num );
+
+#ifdef INSERTION_SORT
+
+  /* get the sort lists in RAM from FFS */
+  get_sort_lists_from_FFS( (UBYTE)db_handle, fld_ctr );
+
+  /* delete in available sort lists
+     yeah, we call it *before* updating UsedRecords */
+  delete_in_sort_lists( (UBYTE)db_handle, fld_ctr, (UBYTE)record_num );
+
+#endif /* INSERTION_SORT */
+
+  --tmp_ptrFieldRecord -> UsedRecords;
+
+  DbmMaster[db_handle].Tracked_Clean &= ~ (CLEAN);
+  DbmMaster[db_handle].DBState = IN_USE;
+
+  /* history log updation */
+
+  return update_history_log( db_handle, field_id, record_num );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_read_record       |
++--------------------------------------------------------------------+
+
+    PURPOSE : Read length bytes at offset from the record in given (database, field)
+*/
+int db_read_record ( int     db_handle, 
+                     USHORT  field_id, 
+                     USHORT  record_num, 
+                     USHORT  offset, 
+                     USHORT  length, 
+                     UBYTE*  record_buffer )
+{
+  T_DB_CODE  db_ret_code;
+
+  UBYTE fld_ctr,
+        tmp_byte;
+
+  char  user_field_file[FILENAME_LEN];              
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+
+  TRACE_FUNCTION("db_read_record()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  /* Using RecordBitMap, check whether record_num exists; 
+     if it does not exist, return DB_EMPTY_RECORD. */
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  tmp_byte = 
+    (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1 ];
+
+  if( NOT ( tmp_byte & ( 0x01 << BIT_POS(record_num) ) ) )  /* if record does *not* exist */
+    DB_RETURN( DB_EMPTY_RECORD );
+
+  /* Check if record exceeds the record size (i.e. offset + length > record size); 
+     if it exceeds, return error DB_INVALID_SIZE */
+  if( (offset + length) > 
+      tmp_ptrFieldRecord -> RecordSize )
+    DB_RETURN( DB_INVALID_SIZE );
+
+  /* Check if FFS file is already opened using FFSFileHandle, part of field record. 
+     If it is not yet opened, open the FFS file and update FFSFileHandle. 
+     This is taken care in read_user_record_from_FFS below. */
+
+  /* Read record_num from "<DBDirectory>/UD_<field_id>"
+     Put "length" number of bytes from "offset" in buffer. (assuming that 
+     buffer contain enough memory i.e. caller should take care of allocating 
+     enough memory space for buffer) */
+
+  /* User data file name is "<DBDirectory>/UD_<field_id>" */
+
+  sprintf( user_field_file, 
+           "%s/UD_%d", 
+           DbmMaster[db_handle].DBDirectory, 
+           tmp_ptrFieldRecord -> FieldID );
+
+  db_ret_code =  
+    read_user_record_from_FFS ( user_field_file,
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+                                &(tmp_ptrFieldRecord -> FFSFileHandle),
+#else
+                                db_handle,
+                                fld_ctr,
+                                &Dummy_FFSFileHandle,
+#endif
+                                (UBYTE)record_num,
+                                tmp_ptrFieldRecord -> RecordSize,
+                                offset,
+                                length,
+                                record_buffer );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  DB_VALUE_RETURN( record_num );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_remove            |
++--------------------------------------------------------------------+
+
+    PURPOSE : Remove a database. The database must not be in use.
+*/
+T_DB_CODE db_remove ( const char* directory )
+{
+  int db_handle;
+
+  UBYTE db_ctr,
+        fld_ctr;
+
+  T_DB_CODE          db_ret_code;
+
+  UBYTE* dbm_data;
+  UBYTE field_file[FILENAME_LEN];
+
+
+ 
+  TRACE_FUNCTION("db_remove()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* Search for "directory" in DbmMaster
+     If not found, return DB_INVALID_DB */
+
+  for( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+  {
+    if ( DbmMaster[db_ctr].DBState NEQ UNUSED_ENTRY )
+    {
+        if( memcmp( DbmMaster[db_ctr].DBDirectory, 
+                    directory, 
+                    strlen(directory) ) EQ 0 )
+          break;
+    }
+  }
+
+  if( db_ctr EQ MAX_DBs )
+    DB_RETURN( DB_INVALID_DB );
+
+  db_handle = db_ctr;
+
+  /* If DBState for found database in DbmMaster is OPEN or IN_USE, return error DB_IN_USE */
+
+  if( ( DbmMaster[db_ctr].DBState EQ OPEN ) OR
+      ( DbmMaster[db_ctr].DBState EQ IN_USE ) )
+     DB_RETURN( DB_IN_USE );
+
+
+  /* Delete all files under directory "<DBDirectory>" (DBDirectory = directory) */
+
+  for( fld_ctr = 0; fld_ctr < DbmMaster[db_handle].NumOfFiles; ++fld_ctr )
+  {
+    db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr );
+
+    if( db_ret_code NEQ DB_OK )
+      DB_RETURN( db_ret_code );
+  }
+
+  /* Delete the DBDirectory */
+  db_ret_code = delete_file_dir_from_FFS ( (const char*)DbmMaster[db_handle].DBDirectory );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+  
+  /* Delete Field file = DD_<pos. in DD_master> */
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_ctr);  
+
+  db_ret_code = delete_file_dir_from_FFS ( (const char*)field_file );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /* Update FFS data i.e. file, "~/dbm/DD_master" */
+
+  /* prepare the dbm data and write */
+
+  DB_MALLOC( dbm_data, T_DB_MASTER_RECORD_SIZE );
+  memset( dbm_data, 0xFF, T_DB_MASTER_RECORD_SIZE );
+
+  db_ret_code = 
+    update_dbm_data_in_FFS ( DB_MASTER_FILE,
+                             (UBYTE) db_handle,   /* to supress warning */
+                             T_DB_MASTER_RECORD_SIZE,
+                             dbm_data,
+                             0,
+                             T_DB_MASTER_RECORD_SIZE );
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( dbm_data );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( dbm_data );
+
+  /* updation of DD_master done */
+
+  /* Free the memory for field records. 
+     Update this entry in DbmMaster as unused. (DBState = UNUSED_ENTRY). 
+     Also, decrement UsedDBs. */
+
+  DB_MFREE( DbmMaster[db_handle].ptrFieldRecord );
+
+  DbmMaster[db_handle].DBState = UNUSED_ENTRY;
+
+  --UsedDBs;
+
+  /* everything ok ! */
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_close             |
++--------------------------------------------------------------------+
+
+    PURPOSE : Close a database; if in use, it flushes it before closing it.
+*/
+T_DB_CODE db_close ( int db_handle )
+{
+  TRACE_FUNCTION("db_close()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* Check for db_handle range */
+  if( db_handle >= MAX_DBs )
+    DB_RETURN( DB_INVALID_DB );
+
+  /* If DBState for db_handleth position in DbmMaster is 
+      o	UNUSED_ENTRY, return error DB_INVALID_DB
+      o	CLOSED, return DB_OK.
+      o	OPEN, update DBState as CLOSED and return DB_OK.
+      o	IN_USE, call db_flush, update DBState as CLOSED and return DB_OK */
+
+  switch( DbmMaster[db_handle].DBState )
+  {
+    case UNUSED_ENTRY: DB_RETURN( DB_INVALID_DB );
+
+    case CLOSED: DB_RETURN( DB_OK );
+
+    case OPEN:  
+    case IN_USE:  {
+                    db_flush( db_handle );
+                    DbmMaster[db_handle].DBState = CLOSED; 
+                    DB_RETURN( DB_OK );
+                  }
+
+    default: DB_RETURN( DB_FAIL );
+  }
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_exit              |
++--------------------------------------------------------------------+
+
+    PURPOSE : Shutdown the data base
+*/
+void db_exit ( void )
+{
+  /* It is assumed as "forced" exit and so no error would be 
+     raised even if database is in use. Also, here we will not 
+     delete the database, but just sync the database and free 
+     the RAM structures.
+
+    1)	Call db_flush for all databases present in DbmMaster.
+    2)	Free the memory for field records for all databases.
+    3)	Update all entries in DbmMaster as unused (this step is not required)
+    4)	Set DBM_State as DBM_NOT_INITIALISED. */
+
+  UBYTE db_ctr;
+
+  for ( db_ctr = 0; db_ctr < MAX_DBs; ++db_ctr )
+  {
+    if( DbmMaster[db_ctr].DBState EQ UNUSED_ENTRY )
+      continue;
+
+    db_close( db_ctr );
+
+    DB_MFREE( DbmMaster[db_ctr].ptrFieldRecord );
+
+    DbmMaster[db_ctr].DBState = UNUSED_ENTRY;
+
+  }
+
+  DBM_State = DBM_NOT_INITIALISED;
+
+  UsedDBs = 0;
+
+  return;
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_remove_field      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Delete field in given database
+*/
+T_DB_CODE db_remove_field ( int    db_handle, 
+                            USHORT field_id )
+{
+  UBYTE fld_ctr,
+        db_ret_code;
+
+  UBYTE* field_data;
+
+  char  field_file[FILENAME_LEN]; 
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  TRACE_FUNCTION("db_remove_field()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field id not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+#ifndef FFS_CLOSE_BEFORE_OPEN
+
+  /* Check if FFS file is open using FFSFileHandle, part of field record; 
+     if so, return error DB_IN_USE. */
+  if( tmp_ptrFieldRecord -> FFSFileHandle NEQ NULL )
+    DB_RETURN( DB_IN_USE );
+
+#else
+
+  if( db_status_user_field_file( db_handle, fld_ctr ) EQ OPENED_FOR_WRITE )
+   DB_RETURN( DB_IN_USE );
+  
+#endif
+
+  /* Remove file "<DBDirectory>/UD_<field_id>" */
+
+  db_ret_code = remove_field_from_FFS( (UBYTE)db_handle, fld_ctr );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /* Update "~/dbm/DD_<db_handle>" for removed field id. */
+
+  /* create the field data that is to be written */
+
+  DB_MALLOC( field_data, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+  memset( field_data, 0xFF, ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  db_ret_code = 
+    update_field_data_in_FFS ( (const char*)field_file,
+                               &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                               db_handle,
+#endif
+                               fld_ctr,
+                               T_DB_FIELD_RECORD_SIZE,
+                               field_data,
+                               RecordBitMap_OFFSET,
+                               ( T_DB_FIELD_RECORD_SIZE - RecordBitMap_OFFSET ) );
+
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( field_data );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( field_data );
+  /* updation of DD_<db_handle> is over */
+
+  /* update in RAM */
+
+  tmp_ptrFieldRecord -> FieldID = INVALID_FIELD_ID;
+
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_read_change_log   |
++--------------------------------------------------------------------+
+
+    PURPOSE : Get an information about the changed records since the last 
+              call of this function
+*/
+T_DB_CODE db_read_change_log ( int           db_handle, 
+                               T_DB_CHANGED* changed)
+{
+  T_DB_CODE db_ret_code;
+  TRACE_FUNCTION("db_read_change_log()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /* Copy contents of internal history log to HistoryRecord */
+  *changed = DB_History_log;  /* This would work ?? */
+   
+  /* Clear internal history log. */
+  DB_History_log.entries = 0; /* this is enough for clearing history log ! */
+
+  /* done */
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_remove_index      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Removes a sort index
+*/
+T_DB_CODE db_remove_index ( int    db_handle,
+                            USHORT field_id,
+                            UBYTE  sort_index )
+{
+  UBYTE db_ret_code,
+        fld_ctr,
+        sort_index_ctr;
+  UBYTE field_file[FILENAME_LEN];
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+  char sort_file[FILENAME_LEN];              
+
+  UBYTE* field_data;
+
+   
+  TRACE_FUNCTION("db_remove_index()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Search given sort_index in SortIndexList for above field_id; 
+     if not found, return DB_INVALID_INDEX. */
+  for( sort_index_ctr = 0; sort_index_ctr < MAX_NUM_OF_SORT_INDEXS; ++sort_index_ctr )
+  {
+    if( tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] EQ sort_index )
+      break;
+  }
+
+  if( sort_index_ctr EQ MAX_NUM_OF_SORT_INDEXS )
+    DB_RETURN( DB_INVALID_INDEX );
+
+  /* Remove file, "<DBDirectory>/UD_<field_id>_sort_<sort_index>" */
+
+  sprintf( sort_file, 
+           "%s/UD_%d_sort_%d", 
+           DbmMaster[db_handle].DBDirectory, 
+           tmp_ptrFieldRecord -> FieldID,
+           tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] );
+
+  db_ret_code = delete_file_dir_from_FFS ( sort_file );
+
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );        
+
+  /* Update file , "~/dbm/DD_<db_handle>" for SortIndexes. */
+
+  /* create the field data that is to be written */
+
+  DB_MALLOC( field_data, MAX_NUM_OF_SORT_INDEXS );
+  memcpy( field_data, tmp_ptrFieldRecord -> SortIndexList, MAX_NUM_OF_SORT_INDEXS );
+
+  field_data[sort_index_ctr] = INVALID_SORT_INDEX;
+
+  sprintf( field_file, "%s/DD_%d", DB_DIR, db_handle );
+
+  db_ret_code = 
+    update_field_data_in_FFS ( (const char*)field_file,
+                               &DbmMaster[db_handle].FFSFileHandle,
+#ifdef FFS_CLOSE_BEFORE_OPEN
+                               db_handle,
+#endif
+                               fld_ctr,
+                               T_DB_FIELD_RECORD_SIZE,
+                               field_data,
+                               SortIndexList_OFFSET,
+                               MAX_NUM_OF_SORT_INDEXS );
+  if( db_ret_code NEQ DB_OK )
+  {
+    DB_MFREE( field_data );
+    DB_RETURN( db_ret_code );
+  }
+
+  DB_MFREE( field_data );
+  /* updation of DD_<db_handle> is over */
+
+  /* Update corresponding RAM structure i.e. DbmFieldRecord 
+     Check if we have sort list corresponding to this sort index; if so, free it. */
+
+  tmp_ptrFieldRecord -> SortIndexList[sort_index_ctr] = INVALID_SORT_INDEX;
+  if( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] NEQ NULL )
+  {
+    DB_MFREE( tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] );
+    tmp_ptrFieldRecord -> SortedLists[sort_index_ctr] = NULL;
+  }
+
+  DB_RETURN( DB_OK );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_field_changed     |
++--------------------------------------------------------------------+
+
+    PURPOSE : Check whether a database field has been changed since last 
+              db_flush().
+*/
+T_DB_CODE db_field_changed ( int    db_handle, 
+                             USHORT field_id,
+                             BOOL*  changed )
+{
+  UBYTE fld_ctr;
+  T_DB_CODE db_ret_code;
+
+  TRACE_FUNCTION("db_field_changed()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  /* Check "Clean" field in field record; 
+     a) if (Clean = true), changed = false. */
+
+  *changed = NOT DbmMaster[db_handle].ptrFieldRecord[fld_ctr].Clean;
+
+  DB_RETURN( DB_OK );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_record_empty      |
++--------------------------------------------------------------------+
+
+    PURPOSE : Check whether a database field is empty. The result is 
+              given to the caller in the *empty variable
+*/
+T_DB_CODE db_record_empty ( int    db_handle,
+                            USHORT field_id,
+                            USHORT record_num,
+                            BOOL*  empty )
+{
+  UBYTE fld_ctr,
+        tmp_byte;
+  T_DB_CODE db_ret_code;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+
+  TRACE_FUNCTION("db_record_empty()");
+
+  *empty = TRUE;
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Using RecordBitMap, check whether record_num is free; 
+     if so, empty = true and false otherwise */
+
+  tmp_byte = 
+    (tmp_ptrFieldRecord -> RecordBitMap)[ RECORD_BITMAP_SIZE - BITMAP_INDEX(record_num) - 1 ];
+
+  if( tmp_byte & ( 0x01 << BIT_POS(record_num) ) )  /* if record exist */
+    *empty = FALSE;
+
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_find_free_record  |
++--------------------------------------------------------------------+
+
+    PURPOSE : Find an free record in given (database, field)
+*/
+int db_find_free_record	( int    db_handle,
+                          USHORT field_id )
+{
+  UBYTE fld_ctr;
+  T_DB_CODE  db_ret_code;
+
+  int record_num;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+
+  TRACE_FUNCTION("db_find_free_record()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Using RecordBitMap, search for free record.
+     If found , return the found record_num
+     Return DB_RECORD_NOT_FOUND */
+
+  record_num = 1 + search_clear_bit_in_bitmap( tmp_ptrFieldRecord -> RecordBitMap,
+                                               RECORD_BITMAP_SIZE );
+
+  if( record_num > tmp_ptrFieldRecord -> NumOfRecords )
+    DB_RETURN( DB_RECORD_NOT_FOUND );
+
+  DB_VALUE_RETURN( record_num );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_info              |
++--------------------------------------------------------------------+
+
+    PURPOSE : Get information about an open database
+*/
+T_DB_CODE db_info ( int        db_handle, 
+                    T_DB_INFO* db_info )
+{
+  T_DB_CODE db_ret_code;
+
+  TRACE_FUNCTION("db_info()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  (*db_info).clean   = ( DbmMaster[db_handle].Tracked_Clean & CLEAN ) ? TRUE : FALSE ;
+  (*db_info).tracked = ( DbmMaster[db_handle].Tracked_Clean & TRACKED ) ? TRUE : FALSE ;
+
+  DB_RETURN( DB_OK );
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_info_field        |
++--------------------------------------------------------------------+
+
+    PURPOSE : Get general information about a field in an open database.
+*/
+T_DB_CODE db_info_field ( int              db_handle,	
+                          USHORT           field_id, 
+                          T_DB_INFO_FIELD* info_field )
+{
+  UBYTE fld_ctr;
+  T_DB_CODE db_ret_code;
+
+  T_DBM_FIELDRECORD* tmp_ptrFieldRecord;
+
+
+  TRACE_FUNCTION("db_info_field()");
+
+  /* DBM_State check */
+  DBM_State_check;
+
+  /* db_handle check */
+  db_ret_code = db_handle_check( db_handle );
+  if( db_ret_code NEQ DB_OK )
+    DB_RETURN( db_ret_code );
+
+  /*	field id search; if field not found, return error DB_INVALID_FIELD */
+  fld_ctr = field_id_search( db_handle, field_id );
+  if( fld_ctr EQ DbmMaster[db_handle].NumOfFiles )
+    DB_RETURN( DB_INVALID_FIELD );
+
+  tmp_ptrFieldRecord = DbmMaster[db_handle].ptrFieldRecord + fld_ctr;
+
+  /* Using data available in RAM in field record, fill up info_field 
+     (i.e. clean, db_type, num_of_records and used_records). */
+
+  (*info_field).clean        = tmp_ptrFieldRecord -> Clean;
+  (*info_field).entry_type   = tmp_ptrFieldRecord -> DBType;
+  (*info_field).record_size  = tmp_ptrFieldRecord -> RecordSize;
+  (*info_field).num_records  = tmp_ptrFieldRecord -> NumOfRecords;
+  (*info_field).used_records = tmp_ptrFieldRecord -> UsedRecords;
+
+  DB_RETURN( DB_OK );
+
+}
+
+/*
++--------------------------------------------------------------------+
+| PROJECT: PHB                          MODULE: DBM                  |
+|                                       ROUINE: db_get_last_fs_error |
++--------------------------------------------------------------------+
+
+    PURPOSE : Delivers the last error provided by the (flash) file system
+              that resulted in DB_FAIL_FS.
+*/
+int db_get_last_fs_error ( void )
+{
+   DB_VALUE_RETURN( LastFFS_ReturnCode );
+}
+
+#endif /* #ifdef TI_PS_FFS_PHB */
+