FreeCalypso > hg > fc-magnetite
diff src/aci2/atb/ATBPb.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/atb/ATBPb.c Mon Sep 26 00:29:36 2016 +0000 @@ -0,0 +1,2422 @@ +/******************************************************************************* + + CONDAT (UK) + +******************************************************************************** + + This software product is the property of Condat (UK) Ltd and may not be + disclosed to any third party without the express permission of the owner. + +******************************************************************************** + + $Project name: + $Project code: + $Module: + $File: ATBPb.c + $Revision: + + $Author: Condat(UK) + $Date: + +******************************************************************************** + + Description: + + +******************************************************************************** + + $History: ATBPb.c + + Jan 18, 2004 REF: CRR MMI-SPR-25332 xnkulkar + Description: Moving entries from Sim Card to phone memory fails. + Solution: When entries are moved, corresponding updations are done in cache as well. + + + $End + +*******************************************************************************/ + +#if defined (NEW_FRAME) + +#include "typedefs.h" +#include "vsi.h" +#include "pei.h" +#include "custom.h" +#include "gsm.h" + +#else + +#include "STDDEFS.H" +#include "custom.h" +#include "gsm.h" +#include "vsi.h" + +#endif + +#include <stdio.h> +#include <string.h> + +#include "mfw_mfw.h" +#include "mfw_sys.h" + +#include "cus_aci.h" +#include "prim.h" +#include "pcm.h" + +#include "ATBPb.h" +#include "ATBPb_i.h" + +/* Global data for phonebook */ + +static T_PB_DATA *phonebook[PB_PHONEBOOKS_MAX] = {0}; + + +/******************************************************************************* + + $Function: ATB_pb_GetPhonebook + + $Description: Checks to see which file system is selected + + $Returns: PB_OK Action completed OK. + PB_FILEWRITEFAIL File write encountered an error + + $Arguments: phonebook_id The phonebook identifier + current_type Place to store type of phonebook selected. + +*******************************************************************************/ + +PB_RET ATB_pb_GetPhonebook(SHORT phonebook_id, T_PB_TYPE *current_type) +{ + PB_RET result; + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + tracefunction("ATB_pb_GetPhonebook"); + + if (data) + { + *current_type = data->current_type; + return PB_OK; + } + + result = FS_pb_GetPhonebook(phonebook_id, current_type); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_SetPhonebook + + $Description: Select file system + + $Returns: PB_OK Action completed OK. + PB_FILEREADFAIL File read encountered an error + + $Arguments: phonebook_id The phonebook identifier + current_type Type of phonebook selected. + +*******************************************************************************/ + +PB_RET ATB_pb_SetPhonebook(SHORT phonebook_id, T_PB_TYPE current_type) +{ + PB_RET result; + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + tracefunction("ATB_pb_SetPhonebook"); + + if (data) + data->current_type = current_type; + + result = FS_pb_SetPhonebook(phonebook_id, current_type); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Initialise + + $Description: Initialise an instance of phonebook. Dynamically allocates a record + cache in RAM. Creates the necessary file(s) if they do not already exist. + Sorts the phonebook by name and by number, creating the appropriate + index tables. + IMPORTANT: if the file reading is non-blocking - i.e. if a request to read + a file does not return with an answer straight away, but the system + awaits a callback - then "cache_max" must equal "records_max". This + ensures that all records are stored in RAM and can be retrieved without + waiting for a response. If the file reading is blocking, then cache_max + can be smaller than records_max. + + The memory allocated by this operation will not be freed until + ATB_pb_Exit() is called. + + $Returns: PB_OK Action completed OK. + PB_EXCT Action currently executing, callback awaited. + GI_pb_OK will be called if successful, + GI_pb_Error otherwise. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_FILEWRITEFAIL File write encountered an error + PB_BOOKALREADYEXISTS Tried to initialise a phonebook that already + exists + + $Arguments: phonebook_id The phonebook identifier + type Type of phonebook. + records_max Indicates the maximum number of entries the + phonebook can hold. + cache_max Indicates the maximum number of records that the + PB will store concurrently in RAM. + alpha_max Maximum size of unicode alpha tag in characters + number_max Maximum size of phone number in digits + ext_max Maximum size of extended data in bytes + +*******************************************************************************/ + +PB_RET ATB_pb_Initialise(SHORT phonebook_id, T_PB_TYPE type, SHORT records_max, SHORT cache_max, + SHORT alpha_max, SHORT number_max, SHORT ext_max) +{ + T_PB_DATA *data; + + tracefunction("ATB_pb_Initialise()"); + + /* Check to see if this phonebook has already been allocated */ + + if (ATB_hnd_GetPbData(phonebook_id)!=NULL) + { + trace("* ERROR * - Phonebook already exists"); + GI_pb_Error(phonebook_id, PB_INITIALISE, PB_BOOKALREADYEXISTS); + return PB_BOOKALREADYEXISTS; + } + + /* Allocate memory for phonebook data */ + + data = (T_PB_DATA *)GI_pb_MemAlloc(sizeof(T_PB_DATA)); + ATB_hnd_SetPbData(phonebook_id, data); + + data->records_max = records_max; + data->records_used = 0; + data->search_results = 0; + + data->alpha_max = alpha_max; + data->number_max = number_max; + data->ext_max = ext_max; + + /* Allocate memory for index tables */ + + data->name_table = (SHORT *)GI_pb_MemAlloc(records_max*sizeof(SHORT)); + memset(data->name_table, 0, records_max*sizeof(SHORT)); + data->number_table = (SHORT *)GI_pb_MemAlloc(records_max*sizeof(SHORT)); + memset(data->number_table, 0, records_max*sizeof(SHORT)); + data->search_table = (SHORT *)GI_pb_MemAlloc(records_max*sizeof(SHORT)); + memset(data->search_table, 0, records_max*sizeof(SHORT)); + data->in_memory = (SHORT *)GI_pb_MemAlloc(records_max*sizeof(SHORT)); + memset(data->in_memory, PB_EMPTY_RECORD, records_max*sizeof(SHORT)); + + /* Allocate memory for cache */ + + data->cache_max = cache_max; + data->cache_size = 0; + data->cache = (T_PB_RECORD **)GI_pb_MemAlloc(records_max*sizeof(T_PB_RECORD *)); + memset(data->cache, 0, records_max*sizeof(T_PB_RECORD *)); + + /* Set up command */ + + data->command_id = PB_INITIALISE; + data->status = PB_STATUS_INIT; + data->param.Initialise.type = type; + data->param.Initialise.records_max = records_max; + + return ATB_status_Initialise(phonebook_id); +} + +/* Status function for Initialise */ + +PB_RET ATB_status_Initialise(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + T_PB_INITIALISE *Initialise; + SHORT blocking; + PB_RET result; + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + Initialise = &data->param.Initialise; + blocking = TRUE; + while (blocking) + { + switch(data->status) + { + case PB_STATUS_INIT: + trace("ATB_status_Initialise: INIT"); + result = FS_pb_Initialise(phonebook_id, Initialise->type, Initialise->records_max, + data->alpha_max, data->number_max, data->ext_max); + + /* Select next state */ + + data->status = PB_STATUS_EXEC; + Initialise->phys_index = 0; + Initialise->first_record = TRUE; + Initialise->record = ATB_pb_AllocRec(phonebook_id); + + /* Allow exit from function */ + + if (result!=PB_OK) + blocking = FALSE; + break; + + case PB_STATUS_EXEC: + trace("ATB_status_Initialise: EXEC"); + + /* Try to read in index tables from file system. If we can't find them, the + * records will be read in and sorted. */ + + if (Initialise->first_record) + { + result = FS_pb_ReadTables(phonebook_id, &data->records_used, data->name_table, data->number_table); + if (result==PB_OK) + { + /* Escape to PB_STATUS_COMPLETE */ + result = PB_OK; + data->status = PB_STATUS_COMPLETE; + break; + } + } + /* If we've already read a record, and it's an existing record, add it to the + * index tables and to the cache */ + + else + { + if (Initialise->record->alpha.data[0]!=(USHORT)0xFFFF) + { + ATB_mem_UpdateCache(phonebook_id, Initialise->phys_index, Initialise->record); + ATB_index_AddRec(phonebook_id, INDEX_NAME, Initialise->phys_index, Initialise->record, NULL); + ATB_index_AddRec(phonebook_id, INDEX_NUMBER, Initialise->phys_index, Initialise->record, NULL); + data->records_used++; + } + + Initialise->phys_index++; + } + + /* Start processing after first record is read */ + + Initialise->first_record = FALSE; + + /* If we haven't just read the last record, read the next one */ + + if (Initialise->phys_index<data->records_max) + { + result = FS_pb_ReadRec(phonebook_id, Initialise->phys_index, Initialise->record); + } + else + { + /* Set next state as finished */ + result = PB_OK; + data->status = PB_STATUS_COMPLETE; + } + + + /* Allow exit from function */ + + if (result!=PB_OK) + blocking = FALSE; + break; + + case PB_STATUS_COMPLETE: + trace("ATB_status_Initialise: COMPLETE"); + blocking = FALSE; + + /* Close file */ + + FS_pb_Finished(phonebook_id); + FS_pb_WriteTables(phonebook_id, data->records_used, data->name_table, data->number_table); + + /* Free the allocated record */ + + ATB_pb_FreeRec(phonebook_id, Initialise->record); + + /* Notify the GI of success */ + GI_pb_OK(phonebook_id, data->command_id, NULL); + result = PB_OK; + data->status = PB_STATUS_NONE; + break; + } + } + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Exit + + $Description: Frees memory associated with phonebook. To be called when the + phonebook is no longer required, or at shutdown. + + $Returns: PB_OK Action completed OK. + + $Arguments: phonebook_id The phonebook identifier + +*******************************************************************************/ + +PB_RET ATB_pb_Exit(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT phys_index; + + trace("ATB_pb_Exit"); + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + for (phys_index = 0; phys_index<data->records_max; phys_index++) + { + if (data->cache[phys_index]!=NULL) + ATB_pb_FreeRec(phonebook_id, data->cache[phys_index]); + } + + GI_pb_MemFree((UBYTE *)data->cache, data->records_max*sizeof(T_PB_RECORD *)); + GI_pb_MemFree((UBYTE *)data->in_memory, data->records_max*sizeof(SHORT)); + GI_pb_MemFree((UBYTE *)data->search_table, data->records_max*sizeof(SHORT)); + GI_pb_MemFree((UBYTE *)data->number_table, data->records_max*sizeof(SHORT)); + GI_pb_MemFree((UBYTE *)data->name_table, data->records_max*sizeof(SHORT)); + + GI_pb_MemFree((UBYTE *)data, sizeof(T_PB_DATA)); + + ATB_hnd_SetPbData(phonebook_id, NULL); + return PB_OK; +} + + +/******************************************************************************* + + $Function: ATB_pb_Status + + $Description: Returns PB_OK if the phonebook is ready for a new command, + or PB_BUSY if the phonebook is busy. + + $Returns: PB_OK All tasks completed, phonebook ready. + PB_BUSY Commands currently executing. + + $Arguments: phonebook_id The phonebook identifier + +*******************************************************************************/ + +PB_RET ATB_pb_Status(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + PB_RET result; + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + // Jan 18, 2004 REF: CRR MMI-SPR-25332 xnkulkar + // Description: Moving entries from Sim Card to phone memory fails. + // Solution: result should be set as PB_OK when PB_STATUS_COMPLETE is true also. + if ((data->status==PB_STATUS_NONE) ||(data->status==PB_STATUS_COMPLETE)) + result = PB_OK; + else + result = PB_BUSY; + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Info + + $Description: Returns information about the phonebook, which will be returned + in the data structure pointed to by phonebook_info. The caller must + allocate the T_PB_INFO structure. + + $Returns: PB_OK Action completed OK. + + $Arguments: phonebook_id The phonebook identifier + phonebook_info Pointer to data structure to contain phonebook + information (allocated by caller). + +*******************************************************************************/ + +PB_RET ATB_pb_Info(SHORT phonebook_id, T_PB_INFO *phonebook_info) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + phonebook_info->records_used = data->records_used; + phonebook_info->records_max = data->records_max; + phonebook_info->records_free = data->records_max - data->records_used; + phonebook_info->search_results = data->search_results; + + return PB_OK; +} + + +/******************************************************************************* + + $Function: ATB_pb_ReadRec + + $Description: Reads a record from the logical position index. The record information + will be returned in the data structure pointed to by record. The + T_PB_RECORD structure must be allocated by the user. + + This function calls the ATB_mem_ReadRec function, with an additional + check to make sure no other commands are currently executing. + + $Returns: PB_OK Action completed OK. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + + $Arguments: phonebook_id The phonebook identifier + index_type The index list from which the record is to be read + log_index Logical index in the index list of the record to read + record Structure in which to store record data + +*******************************************************************************/ + +PB_RET ATB_pb_ReadRec(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index, T_PB_RECORD *record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + PB_RET result; + + tracefunction("ATB_pb_ReadRec"); + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + /* Make sure phonebook is not busy */ + + if (ATB_pb_Status(phonebook_id)==PB_BUSY) + { + trace("* ERROR * - Phonebook is busy"); + result = PB_BUSY; + } + else + { + /* Read the record from cache or from file */ + + result = ATB_mem_ReadRec(phonebook_id, index_type, log_index, record); + } + + /* Send success/failure info to the GI */ + + if (result==PB_OK) + GI_pb_OK(phonebook_id, PB_READREC, NULL); + else if (result!=PB_EXCT) + GI_pb_Error(phonebook_id, PB_READREC, result); + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_WriteRec + + $Description: Writes a record to the logical position index. If the index is + PB_NEW_RECORD, a new record is added, otherwise the previous + record at that position is overwritten. The name and number index lists + will be updated with the new entry in the appropriate place in each. + GI_pb_OK will be called to confirm that the write completed successfully, + otherwise GI_pb_Error will be called with an error code. + Since the order of the records may change due to sorting, GI_pb_OK + will receive a pointer to an integer new_log_index, which will store the + new position of the record in the chosen index list. This is allocated + by and will be destroyed by the phonebook, so must be copied by the + GI before function return. + + $Returns: PB_OK Action completed OK. + PB_EXCT Action currently executing, callback awaited. + GI_pb_OK will be called if successful, + GI_pb_Error otherwise. + GI_pb_OK will receive a pointer to the following: + SHORT new_log_index - The new position of the + record in the chosen index list + PB_BUSY Failed, phonebook is busy. + PB_FILEWRITEFAIL File write encountered an error + PB_RECDOESNOTEXIST (Overwriting only) Tried to access a record that + does not exist + + $Arguments: phonebook_id The phonebook identifier + index_type The index list of the record to write + log_index Logical index in the index list of the record to write + record Pointer to record data to write to phonebook + (allocated by caller) + +*******************************************************************************/ + +PB_RET ATB_pb_WriteRec(SHORT phonebook_id, T_PB_TYPE index_type, SHORT log_index, T_PB_RECORD *record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT phys_index; + + tracefunction("ATB_pb_WriteRec"); + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + /* Make sure phonebook is not busy */ + + if (ATB_pb_Status(phonebook_id)==PB_BUSY) + { + trace("* ERROR * - Phonebook is busy"); + GI_pb_Error(phonebook_id, PB_WRITEREC, PB_BUSY); + return PB_BUSY; + } + + /* Are we adding a new record, or overwriting an old one? */ + + if (log_index==PB_NEW_RECORD) + { + /* Is phonebook full? */ + + if (data->records_used==data->records_max) + { + GI_pb_Error(phonebook_id, PB_WRITEREC, PB_BOOKFULL); + return PB_BOOKFULL; + } + + /* Find an empty physical record */ + for (phys_index=0; phys_index<data->records_max; phys_index++) + { + if (data->in_memory[phys_index]==PB_EMPTY_RECORD) + break; + } + } + else + { + /* Check that record exists */ + + if (log_index<0 + || (log_index>=data->records_used && (index_type==INDEX_NAME || index_type==INDEX_NUMBER)) + || (index_type==INDEX_SEARCH && log_index>data->search_results) + || (index_type==INDEX_PHYSICAL && log_index>data->records_max)) + { + GI_pb_Error(phonebook_id, PB_WRITEREC, PB_RECDOESNOTEXIST); + return PB_RECDOESNOTEXIST; + } + + phys_index = ATB_index_GetPhysIndex(phonebook_id, index_type, log_index); + } + + /* Set up command */ + + data->command_id = PB_WRITEREC; + data->status = PB_STATUS_INIT; + + data->param.WriteRec.log_index = log_index; + data->param.WriteRec.index_type = index_type; + data->param.WriteRec.phys_index = phys_index; + data->param.WriteRec.record = record; + + return ATB_status_WriteRec(phonebook_id); +} + +/* Status function for WriteRec */ + +PB_RET ATB_status_WriteRec(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + T_PB_WRITEREC *WriteRec = &data->param.WriteRec; + SHORT blocking; + PB_RET result; + SHORT name_log_index; + SHORT number_log_index; + SHORT *log_index_return; + + blocking = TRUE; + while (blocking) + { + switch(data->status) + { + case PB_STATUS_INIT: + result = FS_pb_WriteRec(phonebook_id, WriteRec->phys_index, WriteRec->record); + + /* Select next state */ + + data->status = PB_STATUS_COMPLETE; + + /* Allow exit from function */ + + if (result!=PB_OK) + blocking = FALSE; + break; + + case PB_STATUS_COMPLETE: + + if (WriteRec->log_index!=PB_NEW_RECORD) + { + name_log_index = ATB_index_GetLogIndex(phonebook_id, INDEX_NAME, WriteRec->phys_index); + ATB_index_RemoveRec(phonebook_id, INDEX_NAME, name_log_index); + number_log_index = ATB_index_GetLogIndex(phonebook_id, INDEX_NUMBER, WriteRec->phys_index); + ATB_index_RemoveRec(phonebook_id, INDEX_NUMBER, number_log_index); + data->records_used--; + } + + /* Indicate that record is new, then add to the cache */ + + data->in_memory[WriteRec->phys_index] = 0; + ATB_mem_UpdateCache(phonebook_id, WriteRec->phys_index, WriteRec->record); + + /* Add the record to the index lists */ + + ATB_index_AddRec(phonebook_id, INDEX_NAME, WriteRec->phys_index, WriteRec->record, &name_log_index); + ATB_index_AddRec(phonebook_id, INDEX_NUMBER, WriteRec->phys_index, WriteRec->record, &number_log_index); + data->records_used++; + + blocking = FALSE; + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + FS_pb_WriteTables(phonebook_id, data->records_used, data->name_table, data->number_table); + + /* Notify the GI of success */ + log_index_return = NULL; + if (WriteRec->index_type==INDEX_NAME) + log_index_return = &name_log_index; + if (WriteRec->index_type==INDEX_NUMBER) + log_index_return = &number_log_index; + + GI_pb_OK(phonebook_id, data->command_id, log_index_return); + result = PB_OK; + data->status = PB_STATUS_NONE; + break; + } + } + + /* Report any errors to the GI */ + + if (result!=PB_OK && result!=PB_EXCT) + { + GI_pb_Error(phonebook_id, PB_WRITEREC, result); + } + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_DeleteRec + + $Description: Deletes a record at a logical position index. + GI_pb_OK will be called to confirm that the delete completed successfully, + otherwise GI_pb_Error will be called with an error code. + + $Returns: PB_OK Action completed OK. + PB_EXCT Action currently executing, callback awaited. + GI_pb_OK will be called if successful, + GI_pb_Error otherwise. + PB_BUSY Failed, phonebook is busy. + PB_FILEWRITEFAIL File write encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + + $Arguments: phonebook_id The phonebook identifier + index_type The index list of the record to delete + log_index Logical index in the index list of the record to delete + +*******************************************************************************/ + +PB_RET ATB_pb_DeleteRec(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + tracefunction("ATB_pb_DeleteRec"); + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + /* Make sure phonebook is not busy */ + + if (ATB_pb_Status(phonebook_id)==PB_BUSY) + { + trace("* ERROR * - Phonebook is busy"); + GI_pb_Error(phonebook_id, PB_DELETEREC, PB_BUSY); + return PB_BUSY; + } + + /* Check that record exists */ + + if (log_index<0 + || (log_index>=data->records_used && (index_type==INDEX_NAME || index_type==INDEX_NUMBER)) + || (index_type==INDEX_SEARCH && log_index>data->search_results) + || (index_type==INDEX_PHYSICAL && log_index>data->records_max)) + { + GI_pb_Error(phonebook_id, PB_DELETEREC, PB_RECDOESNOTEXIST); + return PB_RECDOESNOTEXIST; + } + + /* Set up the command */ + + data->command_id = PB_DELETEREC; + data->status = PB_STATUS_INIT; + + data->param.DeleteRec.log_index = log_index; + data->param.DeleteRec.index_type = index_type; + data->param.DeleteRec.phys_index = ATB_index_GetPhysIndex(phonebook_id, index_type, log_index); + + return ATB_status_DeleteRec(phonebook_id); +} + +/* Status function for DeleteRec */ + +PB_RET ATB_status_DeleteRec(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + T_PB_DELETEREC *DeleteRec = &data->param.DeleteRec; + SHORT blocking; + PB_RET result; + SHORT name_log_index; + SHORT number_log_index; + + blocking = TRUE; + while (blocking) + { + switch(data->status) + { + case PB_STATUS_INIT: + result = FS_pb_DeleteRec(phonebook_id, DeleteRec->phys_index); + + /* Select next state */ + + data->status = PB_STATUS_COMPLETE; + + /* Allow exit from function */ + + if (result!=PB_OK) + blocking = FALSE; + break; + + case PB_STATUS_COMPLETE: + name_log_index = ATB_index_GetLogIndex(phonebook_id, INDEX_NAME, DeleteRec->phys_index); + ATB_index_RemoveRec(phonebook_id, INDEX_NAME, name_log_index); + number_log_index = ATB_index_GetLogIndex(phonebook_id, INDEX_NUMBER, DeleteRec->phys_index); + ATB_index_RemoveRec(phonebook_id, INDEX_NUMBER, number_log_index); + data->records_used--; + data->in_memory[DeleteRec->phys_index] = -1; + + // Jan 18, 2004 REF: CRR MMI-SPR-25332 xnkulkar + // Description: Moving entries from Sim Card to phone memory fails. + // Solution: When entries are moved, corresponding updations are done in cache as well. + if(data->cache[DeleteRec->phys_index]!=NULL) + { + ATB_pb_FreeRec(phonebook_id, data->cache[DeleteRec->phys_index]); + data->cache[DeleteRec->phys_index]=NULL; + data->cache_size--; + } + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + FS_pb_WriteTables(phonebook_id, data->records_used, data->name_table, data->number_table); + + blocking = FALSE; + + /* Notify the GI of success */ + + GI_pb_OK(phonebook_id, data->command_id, NULL); + result = PB_OK; + data->status = PB_STATUS_NONE; + break; + } + } + + /* Report any errors to the GI */ + + if (result!=PB_OK && result!=PB_EXCT) + { + GI_pb_Error(phonebook_id, PB_DELETEREC, result); + } + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Find + + $Description: Find the nearest match to the supplied record. Only the index_type + specified will be considered: if the index_type is INDEX_NAME, then the + name only will be matched; if INDEX_NUMBER, then just the number. + The new_log_index parameter should be a pointer to a user allocated + integer. This will return the logical index of the closest match in the + index list specified. This index either corresponds to a perfect match, + or to the record that would appear just after the provided record in the + list. For example, if the list consisted of record 0, Alice and record 1, + Carol, then a search for Bob would return 1. A search for a record + that would occur before the first record always returns 0. A search for + a record that would occur after the last record returns the index of the + last record +1. + The "match" parameter should be a pointer to a user allocated variable + of type T_PB_MATCH. This returns information about how closely the + found entry matches the record. In the example above, a search for + Bob would return 1 and MATCH_NONE; a search for Ca would return 1 + and MATCH_START, and a search for Carol would return 1 and + MATCH_EXACT. Rarely, match may be MATCH_FRAGMENT: this can be + considered equivalent to MATCH_NONE in this context. + + $Returns: PB_OK Action completed OK. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + (should never happen) + + $Arguments: phonebook_id The phonebook identifier + index_type The index_type of the provided record that is to be + searched for, and the index list that the resulting + new_log_index pertains to + record The record whose index_type is to be matched + new_log_index Returns with the logical index of the closest matching + record + match Specifies how good the resulting match was + (MATCH_NONE, MATCH_START, MATCH_FRAGMENT + or MATCH_EXACT). + +*******************************************************************************/ + + +PB_RET ATB_pb_Find (SHORT phonebook_id, T_PB_INDEX index_type, T_PB_RECORD *record, SHORT *new_log_index, T_PB_MATCH *match) +{ + PB_RET result; + + tracefunction("ATB_pb_Find"); + + result = ATB_index_Find(phonebook_id, index_type, record, new_log_index, match); + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + + /* Send success/failure info to the GI */ + + if (result==PB_OK) + GI_pb_OK(phonebook_id, PB_FIND, NULL); + else if (result!=PB_EXCT) + GI_pb_Error(phonebook_id, PB_FIND, result); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_ReadRecList + + $Description: Fetches record information of sequential records in an index list, starting + at logical record start_log_index and fetching recs_count records in total. + The information will be stored in the caller allocated array of records + provided. + + $Returns: PB_OK Action completed OK. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + + $Arguments: phonebook_id The phonebook identifier + index_type The index list to use + start_log_index Logical index in the index list of the first record to + read + recs_count Total number of sequential records to read. + record Array of entries in which to store the fetched records. + The array must be recs_count in size. (Caller allocated). + +*******************************************************************************/ + +PB_RET ATB_pb_ReadRecList(SHORT phonebook_id, T_PB_INDEX index_type, SHORT start_log_index, SHORT num_recs, T_PB_LIST *list) +{ + PB_RET result; + SHORT log_index; + + tracefunction("ATB_pb_ReadRecList"); + + list->records_used = 0; + + /* Make sure phonebook is not busy */ + + if (ATB_pb_Status(phonebook_id)==PB_BUSY) + { + trace("* ERROR * - Phonebook is busy"); + /* Report any errors to the GI */ + GI_pb_Error(phonebook_id, PB_READRECLIST, PB_BUSY); + return PB_BUSY; + } + + /* Read in list of records */ + + for (log_index = start_log_index; log_index<start_log_index+num_recs && log_index<list->records_max; log_index++) + { + result = ATB_mem_ReadRec(phonebook_id, index_type, log_index, &list->record[log_index-start_log_index]); + if (result!=PB_OK) + break; + list->records_used++; + } + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + + /* Send success/failure info to the GI */ + + if (result==PB_OK) + GI_pb_OK(phonebook_id, PB_READRECLIST, NULL); + else if (result!=PB_EXCT) + GI_pb_Error(phonebook_id, PB_READRECLIST, result); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Search + + $Description: Searches every record in the index list for a fragment. The index list + must be either INDEX_NAME or INDEX_NUMBER. If it is INDEX_NAME, + then a name fragment will be searched for; if it is INDEX_NUMBER, + a number fragment will be searched for. + + The results are stored in an index list. They may be accessed by + using the normal read and write functions, using the index type + INDEX_SEARCH. The size of the search list is returned in the variable + recs_count. + + $Returns: PB_OK Action completed OK. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + (should never happen) + + $Arguments: phonebook_id The phonebook identifier + index_type The index list to use + record Record containing the fragment to search for + recs_count Pointer to an int (user allocated) in which will be returned + the number of search results. + + +*******************************************************************************/ + +PB_RET ATB_pb_Search(SHORT phonebook_id, T_PB_INDEX index_type, T_PB_RECORD *record, SHORT *recs_count) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + PB_RET result; + SHORT count = 0; + SHORT log_index; + T_PB_MATCH match; + T_PB_RECORD *cur_record; + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + /* Allocate record for temporary use */ + + cur_record = ATB_pb_AllocRec(phonebook_id); + + /* Make sure phonebook is not busy */ + + if (ATB_pb_Status(phonebook_id)==PB_BUSY) + { + trace("* ERROR * - Phonebook is busy"); + GI_pb_Error(phonebook_id, PB_SEARCH, PB_BUSY); + return PB_BUSY; + } + + /* Make sure we're searching a valid index type */ + + if (index_type==INDEX_PHYSICAL || index_type==INDEX_SEARCH) + { + GI_pb_Error(phonebook_id, PB_SEARCH, PB_INDEXINVALID); + return PB_INDEXINVALID; + } + + for (log_index=0; log_index<data->records_used; log_index++) + { + result = ATB_mem_ReadRec(phonebook_id, index_type, log_index, cur_record); + if (result!=PB_OK) + break; + + match = ATB_index_Match(record, cur_record, index_type); + + if (match==MATCH_EXACT || match==MATCH_START || match==MATCH_FRAGMENT) + { + data->search_table[count] = ATB_index_GetPhysIndex(phonebook_id, index_type, log_index); + count++; + } + } + + data->search_results = count; + *recs_count = count; + + /* Free allocated record */ + + ATB_pb_FreeRec(phonebook_id, cur_record); + + /* Close any open file */ + + FS_pb_Finished(phonebook_id); + + /* Send success/failure info to the GI */ + + if (result==PB_OK) + GI_pb_OK(phonebook_id, PB_SEARCH, NULL); + else if (result!=PB_EXCT) + GI_pb_Error(phonebook_id, PB_SEARCH, result); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_ConvIndex + + $Description: Returns the index in table dest_index_type corresponding to the index + in table src_index_type. + + $Returns: PB_OK Action completed OK. + + $Arguments: phonebook_id The phonebook identifier. + index_type The index table of the original index. + log_index The original logical index. + new_index_type The index table required. + new_log_index Pointer to where the new logical index will be stored + +*******************************************************************************/ + +PB_RET ATB_pb_ConvIndex(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index, + T_PB_INDEX new_index_type, SHORT *new_log_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT phys_index; + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + if (index_type==new_index_type) + { + *new_log_index = log_index; + } + else + { + phys_index = ATB_index_GetPhysIndex(phonebook_id, index_type, log_index); + *new_log_index = ATB_index_GetLogIndex(phonebook_id, new_index_type, phys_index); + } + + return PB_OK; +} + + +/******************************************************************************* + + $Function: ATB_pb_CharToBCD + + $Description: Converts an ascii string of digits into BCD form, with 4 bits representing + each digit. + + $Returns: None + + $Arguments: src - source string (ascii) + dest - destination string for BCD digits + +*******************************************************************************/ + +void ATB_pb_CharToBCD(UBYTE *dest, char *src, int max_len) +{ + UBYTE srcIndex = 0; + UBYTE destIndex = 0; + BOOL leftbits = TRUE; /* Left or right nibble */ + UBYTE digit = 0; + + while (digit!=0xF && srcIndex<max_len) + { + if (src[srcIndex]==NULL) + digit = 0xF; /* 0xF terminates BCD */ + else + digit = src[srcIndex]-'0'; /* The digit, 0 to 9. */ + + if (leftbits) + { + dest[destIndex] = digit; + leftbits = FALSE; + } + else + { + dest[destIndex] |= digit<<4; /* *16 shifts right 4 bits */ + leftbits = TRUE; + destIndex++; + } + srcIndex++; + } + + return; +} + + +/******************************************************************************* + + $Function: ATB_pb_BCDToChar + + $Description: Converts a BCD string to ascii digits + + $Returns: None + + $Arguments: src - source string (BCD) + dest - destination string for ascii digits + +*******************************************************************************/ + +void ATB_pb_BCDToChar(char *dest, UBYTE *src, int max_len) +{ + SHORT numIndex = 0; + UBYTE digit = 0xF; //dummy + + while (digit!=NULL && numIndex<max_len) + { + /*HELLO!*/ + digit = ATB_num_Digit(src, numIndex); + + if (digit==0xF) + digit = NULL; + else + digit+='0'; + dest[numIndex] = digit; + + numIndex++; + } + + return; +} + + +/******************************************************************************* + + $Function: ATB_pb_AllocRec + + $Description: Allocates memory for a record + + $Returns: + + $Arguments: phonebook_id The phonebook identifier + +*******************************************************************************/ + +T_PB_RECORD *ATB_pb_AllocRec(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + T_PB_RECORD *record; + + record = (T_PB_RECORD *)GI_pb_MemAlloc(sizeof(T_PB_RECORD)); + + record->alpha.data = (USHORT *)GI_pb_MemAlloc(data->alpha_max*sizeof(USHORT)); + record->number = (UBYTE *)GI_pb_MemAlloc(data->number_max/2); + if (data->ext_max>0) + { + record->ext_data = (UBYTE *)GI_pb_MemAlloc(data->ext_max); + } + else + { + record->ext_data = NULL; + } + record->ton_npi = 0; + + return record; +} + + +/******************************************************************************* + + $Function: ATB_pb_FreeRec + + $Description: Frees memory allocated for a record + + $Returns: + + $Arguments: phonebook_id The phonebook identifier + record The record to destroy + +*******************************************************************************/ + +void ATB_pb_FreeRec(SHORT phonebook_id, T_PB_RECORD *record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + if (data->ext_max>0 && record->ext_data!=NULL) + { + GI_pb_MemFree((UBYTE *)record->ext_data, data->ext_max); + } + GI_pb_MemFree((UBYTE *)record->number, data->number_max/2); + GI_pb_MemFree((UBYTE *)record->alpha.data, data->alpha_max*sizeof(USHORT)); + + GI_pb_MemFree((UBYTE *)record, sizeof(T_PB_RECORD)); + + return; +} + + +/******************************************************************************* + + $Function: ATB_pb_AllocRecList + + $Description: Allocates memory for a list of records + + $Returns: + + $Arguments: phonebook_id The phonebook identifier + num_recs The number of records to allocate + +*******************************************************************************/ + +T_PB_LIST *ATB_pb_AllocRecList(SHORT phonebook_id, SHORT num_recs) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + T_PB_LIST *list; + SHORT rec_index; + + list = (T_PB_LIST *)GI_pb_MemAlloc(sizeof(T_PB_LIST)); + list->records_max = num_recs; + list->records_used = 0; + list->record = (T_PB_RECORD *)GI_pb_MemAlloc(sizeof(T_PB_RECORD)*num_recs); + + for (rec_index=0; rec_index<num_recs; rec_index++) + { + list->record[rec_index].alpha.data = (USHORT *)GI_pb_MemAlloc(data->alpha_max*sizeof(USHORT)); + list->record[rec_index].number = (UBYTE *)GI_pb_MemAlloc(data->number_max/2); + if (data->ext_max>0) + { + list->record[rec_index].ext_data = (UBYTE *)GI_pb_MemAlloc(data->ext_max); + } + else + { + list->record[rec_index].ext_data = NULL; + } + } + + return list; +} + + +/******************************************************************************* + + $Function: ATB_pb_FreeRecList + + $Description: Frees memory allocated for a list of records + + $Returns: + + $Arguments: phonebook_id The phonebook identifier + record The records to destroy + num_recs Number of records in the list + +*******************************************************************************/ + +void ATB_pb_FreeRecList(SHORT phonebook_id, T_PB_LIST *list) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT rec_index; + + for (rec_index=0; rec_index<list->records_max; rec_index++) + { + if (data->ext_max>0 && list->record[rec_index].ext_data!=NULL) + { + GI_pb_MemFree((UBYTE *)list->record[rec_index].ext_data, data->ext_max); + } + GI_pb_MemFree((UBYTE *)list->record[rec_index].number, data->number_max/2); + GI_pb_MemFree((UBYTE *)list->record[rec_index].alpha.data, data->alpha_max*sizeof(USHORT)); + } + + GI_pb_MemFree((UBYTE *)list->record, sizeof(T_PB_RECORD)*list->records_max); + GI_pb_MemFree((UBYTE *)list, sizeof(T_PB_LIST)); + + return; +} + + +/******************************************************************************* + + $Function: ATB_mem_CopyRec + + $Description: Copies a record from one location to another. The destination should + have memory allocated for its strings. + + $Returns: + + $Arguments: dest_record The destination record + src_record The source record + +*******************************************************************************/ + +void ATB_pb_CopyRec(SHORT phonebook_id, T_PB_RECORD *dest_record, T_PB_RECORD *src_record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + dest_record->alpha.length = src_record->alpha.length; + dest_record->alpha.dcs = src_record->alpha.dcs; + memcpy((UBYTE *)dest_record->alpha.data, (UBYTE *)src_record->alpha.data, data->alpha_max*sizeof(USHORT)); + memcpy(dest_record->number, src_record->number, data->number_max/2); + if (data->ext_max>0) + { + memcpy(dest_record->ext_data, src_record->ext_data, data->ext_max); + } + dest_record->ton_npi = src_record->ton_npi; + + return; +} + + +/******************************************************************************* + + $Function: ATB_pb_OK + + $Description: This function is called if the requested FS command executed successfully. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + +*******************************************************************************/ + + +PB_RET ATB_pb_OK(SHORT phonebook_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + PB_RET result; + + switch(data->command_id) + { + case PB_INITIALISE: + result = ATB_status_Initialise(phonebook_id); + break; + case PB_WRITEREC: + result = ATB_status_WriteRec(phonebook_id); + break; + case PB_DELETEREC: + result = ATB_status_DeleteRec(phonebook_id); + break; + } + + return result; +} + + +/******************************************************************************* + + $Function: ATB_pb_Error + + $Description: This function is called if an error was returned while executing the + requested command. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + error_id Identifies the error that occurred. + +*******************************************************************************/ + +void ATB_pb_Error(SHORT phonebook_id, SHORT error_id) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + + /* Forward the error report to the GI */ + + GI_pb_Error(phonebook_id, data->command_id, error_id); + data->status = PB_STATUS_NONE; + + return; +} + +/******************************************************************************* + + $Function: ATB_index_GetTable + + $Description: Returns a pointer to the index table specified by the index_type + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + index_type The index table required. + +*******************************************************************************/ + +SHORT * ATB_index_GetTable(SHORT phonebook_id, T_PB_INDEX index_type) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT *table = NULL; + + switch(index_type) + { + case INDEX_NAME: + table = data->name_table; + break; + case INDEX_NUMBER: + table = data->number_table; + break; + case INDEX_SEARCH: + table = data->search_table; + break; + default: + table = GI_pb_GetTable(index_type); + break; + } + + return table; +} + + +/******************************************************************************* + + $Function: ATB_index_Find + + $Description: Find the nearest match to the supplied record. See ATB_pb_Find for + more information. + + $Returns: PB_OK Action completed OK. + PB_BUSY Failed, phonebook is busy. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + (should never happen) + + $Arguments: phonebook_id The phonebook identifier + index_type The index_type of the provided record that is to be + searched for, and the index list that the resulting + new_log_index pertains to + record The record whose index_type is to be matched + new_log_index Returns with the logical index of the closest matching + record + match Specifies how good the resulting match was + (MATCH_NONE, MATCH_START, MATCH_FRAGMENT + or MATCH_EXACT). + +*******************************************************************************/ + +PB_RET ATB_index_Find (SHORT phonebook_id, T_PB_INDEX index_type, T_PB_RECORD *record, SHORT *new_log_index, T_PB_MATCH *match) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + PB_RET result = PB_OK; + SHORT *table; + SHORT lower; + SHORT upper; + SHORT middle; + T_PB_RECORD *comp_record; + T_PB_COMPARE compare; + UBYTE searching; + + /* Ensure that phonebook exists */ + if (!data) + { + trace("**ERROR** Phonebook does not exist"); + return PB_BOOKDOESNOTEXIST; + } + + /* Allocate record for comparison */ + + comp_record = ATB_pb_AllocRec(phonebook_id); + + /* Make sure we're searching a valid index type */ + + if (index_type==INDEX_PHYSICAL || index_type==INDEX_SEARCH) + { + GI_pb_Error(phonebook_id, PB_FIND, PB_INDEXINVALID); + return PB_INDEXINVALID; + } + + table = ATB_index_GetTable(phonebook_id, index_type); + + /* The initial upper and lower bounds are the bounds of the array */ + lower = 0; + upper = data->records_used-1; + + searching = TRUE; + + /* If the list is empty, insert at 0 */ + + if (data->records_used==0) + { + middle = 0; + searching = FALSE; + } + + while (searching) + { + /* Compare our record with the middle element of the partition */ + + middle = (lower+upper)/2; + + result = ATB_mem_ReadRec(phonebook_id, index_type, middle, comp_record); + + if (result!=PB_OK) + break; + + compare = ATB_index_Compare(record, comp_record, index_type); + + switch(compare) + { + case COMPARE_IDENTICAL: + /* We've found a match; stop searching */ + searching = FALSE; + break; + + case COMPARE_FIRSTBEFORE: + if (middle==lower) + { + /* The partition is a single element, so stop here. */ + searching = FALSE; + } + else + { + /* Our record comes before the middle element; + * redefine the partiton */ + upper = middle - 1; + } + break; + + case COMPARE_FIRSTAFTER: + if (middle==upper) + { + /* The partition is a single element, so stop here. The record + * we need is the record after this one. */ + middle++; + searching = FALSE; + } + else + { + /* Our record comes after the middle element; + * redefine the partiton */ + lower = middle+1; + } + break; + } + } + + /* Store our results */ + + if (new_log_index) + *new_log_index = middle; + + if (match) + { + ATB_mem_ReadRec(phonebook_id, index_type, middle, comp_record); + *match = ATB_index_Match(record, comp_record, index_type); + } + + /* Free allocated record */ + + ATB_pb_FreeRec(phonebook_id, comp_record); + + /* Send success/failure info to the GI */ + + if (result==PB_OK) + GI_pb_OK(phonebook_id, PB_FIND, NULL); + else if (result!=PB_EXCT) + GI_pb_Error(phonebook_id, PB_FIND, result); + + return result; +} + + +/******************************************************************************* + + $Function: ATB_index_GetPhysIndex + + $Description: Returns the physical index corresponding to the given logical index, in + the index table specified by the index_type. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier. + index_type The index table required. + log_index The logical index. + +*******************************************************************************/ + +SHORT ATB_index_GetPhysIndex(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT phys_index; + SHORT *table; + + switch(index_type) + { + case INDEX_PHYSICAL: + phys_index = log_index; + break; + case INDEX_NAME: + case INDEX_NUMBER: + case INDEX_SEARCH: + table = ATB_index_GetTable(phonebook_id, index_type); + phys_index = table[log_index]; + break; + } + + return phys_index; +} + + +/******************************************************************************* + + $Function: ATB_index_GetLogIndex + + $Description: Provided with the physical index, finds the logical index of the record + in the index table specified. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + index_type The index table required. + phys_index The logical index of the record to find + +*******************************************************************************/ + +SHORT ATB_index_GetLogIndex(SHORT phonebook_id, T_PB_INDEX index_type, SHORT phys_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT *table = ATB_index_GetTable(phonebook_id, index_type); + SHORT log_index; + + if (index_type==INDEX_PHYSICAL) + { + log_index = phys_index; + } + else + { + for (log_index=0; log_index<data->records_used; log_index++) + { + if (table[log_index]==phys_index) + break; + } + } + + return log_index; +} + + +/******************************************************************************* + + $Function: ATB_index_AddRec + + $Description: Adds a record to an index list, sorting automatically as required. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + index_type The index table required. + phys_index The physical index of the record to add. + record The record to add. + new_log_index New logical index of record. + +*******************************************************************************/ + +void ATB_index_AddRec(SHORT phonebook_id, T_PB_INDEX index_type, SHORT phys_index, T_PB_RECORD *record, SHORT *new_log_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT *table = ATB_index_GetTable(phonebook_id, index_type); + SHORT log_index; + SHORT found_log_index; + + ATB_index_Find(phonebook_id, index_type, record, &found_log_index, NULL); + + /* Shift end of index table down */ + + for (log_index=data->records_used; log_index>found_log_index; log_index--) + { + table[log_index] = table[log_index-1]; + } + + table[found_log_index] = phys_index; + + if (new_log_index) + *new_log_index = found_log_index; + + return; +} + +/******************************************************************************* + + $Function: ATB_index_RemoveRec + + $Description: Removes a record reference from an index list, sorting the index list + appropriately. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + index_type The index table required. + log_index The logical index of the record to remove + +*******************************************************************************/ + +void ATB_index_RemoveRec(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT *table = ATB_index_GetTable(phonebook_id, index_type); + SHORT table_index; + + for (table_index = log_index+1; table_index<data->records_used; table_index++) + { + table[table_index-1] = table[table_index]; + } + + return; +} + + +/******************************************************************************* + + $Function: ATB_index_Match + + $Description: This function attempts a match between two records based on the + index_type specified in index_type. It returns a value indicating + whether there is no match (MATCH_NONE), a partial match + (MAX_START), or an exact match (MATCH_EXACT). + The function GI_pb_Match is called first, to check whether there is + any user-specific matching required. If not, then ATB_alpha_Match + is called for an alpha tag, or ATB_num_Match for a phone number. + For any other index_type, MATCH_NONE is returned as default. + + $Returns: MATCH_EXACT, MATCH_START or MATCH_NONE + + $Arguments: record1 The first record to be compared + record2 The second record to be compared + index_type Indicator of the index_type which is to be matched + +*******************************************************************************/ + +T_PB_MATCH ATB_index_Match(T_PB_RECORD *record1, T_PB_RECORD *record2, T_PB_INDEX index_type) +{ + T_PB_MATCH match; + + match = GI_pb_Match(record1, record2, index_type); + + if (match==MATCH_DEFAULT) + { + switch(index_type) + { + case INDEX_NAME: + match = ATB_alpha_Match(&record1->alpha, &record2->alpha); + break; + case INDEX_NUMBER: + match = ATB_num_Match(record1->number, record2->number); + break; + } + } + + return match; +} + + + +/******************************************************************************* + + $Function: ATB_index_Compare + + $Description: This function compares two records based on the index_type specified in + index_type. It returns a value indicating whether the first record should + come before or after the second. + The function GI_pb_Compare is called first, to check whether there is + any user-specific sorting required. If not, then ATB_alpha_Compare is + called for an alpha tag, or ATB_num_Compare for a phone number. + For any other index_type, COMPARE_FIRSTBEFORE is returned as default. + + $Returns: COMPARE_IDENTICAL The two records are identical + COMPARE_FIRSTBEFORE The first record should come before the second record + COMPARE_FIRSTAFTER The first record should come after the second record + + $Arguments: record1 The first record to be compared + record2 The second record to be compared + index_type Indicator of the index_type which is to be compared + +*******************************************************************************/ + +T_PB_COMPARE ATB_index_Compare(T_PB_RECORD *record1, T_PB_RECORD *record2, T_PB_INDEX index_type) +{ + T_PB_COMPARE compare; + + compare = GI_pb_Compare(record1, record2, index_type); + + if (compare==COMPARE_DEFAULT) + { + switch(index_type) + { + case INDEX_NAME: + compare = ATB_alpha_Compare(&record1->alpha, &record2->alpha); + break; + case INDEX_NUMBER: + compare = ATB_num_Compare(record1->number, record2->number); + break; + } + } + + return compare; +} + + +/******************************************************************************* + + $Function: ATB_alpha_Compare + + $Description: This function compares two alpha strings on the basis of an ascending + alphanumeric latin list, and specifies which record would come first. + + + $Returns: COMPARE_FIRSTBEFORE The first record should come before the second record + COMPARE_FIRSTAFTER The first record should come after the second record + + $Arguments: alpha1 The first alpha tag + alpha2 The second alpha tag + +*******************************************************************************/ + +T_PB_COMPARE ATB_alpha_Compare(T_PB_ALPHA *alpha1, T_PB_ALPHA *alpha2) +{ + T_PB_COMPARE compare; + SHORT charIndex; + USHORT length1 = alpha1->length; + USHORT length2 = alpha2->length; + USHORT char1; + USHORT char2; + + compare = COMPARE_IDENTICAL; /* Default */ + + /* Special case, length of first string is 0 */ + + if (length1==0) + compare = COMPARE_FIRSTBEFORE; + + for (charIndex = 0; charIndex < length1; charIndex++) + { + if (charIndex==length2) /* E.g. "Johnson" and "John" */ + { + compare = COMPARE_FIRSTAFTER; + break; + } + + char1 = alpha1->data[charIndex]; + if (char1>=(SHORT)'A' && char1<=(SHORT)'Z') + char1 += (SHORT)('a'-'A'); + char2 = alpha2->data[charIndex]; + if (char2>=(SHORT)'A' && char2<=(SHORT)'Z') + char2 += (SHORT)('a'-'A'); + + if (char1 < char2) + { + compare = COMPARE_FIRSTBEFORE; + break; + } + if (char1 > char2) + { + compare = COMPARE_FIRSTAFTER; + break; + } + if (charIndex==length1-1 && length2>length1) /*E.g. "John" and "Johnson" */ + { + compare = COMPARE_FIRSTBEFORE; + break; + } + } + + return compare; +} + + +/******************************************************************************* + + $Function: ATB_alpha_Match + + $Description: This function matches two alpha strings on the basis of a latin string + matched from the start, and specifies how they match. + + $Returns: MATCH_NONE The strings do not match + MATCH_START The first string matches the start of the second string + MATCH_EXACT The two strings match exactly + + $Arguments: alpha1 The first alpha tag + alpha2 The second alpha tag + +*******************************************************************************/ + +T_PB_COMPARE ATB_alpha_Match(T_PB_ALPHA *alpha1, T_PB_ALPHA *alpha2) +{ + T_PB_MATCH match; + SHORT charIndex; + USHORT length1 = alpha1->length; + USHORT length2 = alpha2->length; + SHORT offset; + UBYTE searching; + UBYTE some_match; + USHORT char1, char2; + + match = MATCH_EXACT; /* Default */ + searching = TRUE; + some_match = FALSE; + offset = 0; + + do + { + for (charIndex = 0; charIndex < length1; charIndex++) + { + + if (charIndex==(length2-offset)) /* E.g. "Johnson" and "John" */ + { + searching = FALSE; + break; /* No match, will exit do/while */ + } + + char1 = alpha1->data[charIndex]; + if (char1>=(SHORT)'A' && char1<=(SHORT)'Z') + char1 += (SHORT)('a'-'A'); + char2 = alpha2->data[charIndex+offset]; + if (char2>=(SHORT)'A' && char2<=(SHORT)'Z') + char2 += (SHORT)('a'-'A'); + + if (char1 != char2) + { + some_match = FALSE; /* Any fragment so far identified does not fit */ + break; /* No match, keep looking */ + } + + some_match = TRUE; + + if (charIndex==length1-1 && length2>length1) /*E.g. "John" and "Johnson" */ + { + if (offset==0) + match = MATCH_START; + else + match = MATCH_FRAGMENT; + break; + } + } + + if (some_match==TRUE) + { + searching = FALSE; + } + else + { + offset++; + + /* If the fragment won't fit, don't keep looking */ + if ((offset+length1)>length2) + { + match=MATCH_NONE; + searching = FALSE; + } + } + }while (searching); + + return match; +} + + +/******************************************************************************* + + $Function: ATB_num_Digit + + $Description: Extracts the four-bit digit from a BCD number + + $Returns: The four bit digit + + $Arguments: num The BCD number + numIndex The position in the BCD number to look + +*******************************************************************************/ + +UBYTE ATB_num_Digit(UBYTE *num, SHORT numIndex) +{ + UBYTE digit; + UBYTE shift = (numIndex&0x1)*0x4; + + digit = num[numIndex>>1]; /* Each BCD digit takes up half a byte */ + digit &= (0xF<<shift); /* Isolate the digit */ + digit >>= shift; /* Shift it so it has a value 0x0 - 0xF */ + + return digit; +} + + +/******************************************************************************* + + $Function: ATB_num_Length + + $Description: Returns the length of a BCD number in digits + + $Returns: Length of BCD number + + $Arguments: num The BCD number + +*******************************************************************************/ + +SHORT ATB_num_Length(UBYTE *num) +{ + SHORT length; + + for (length = 0; ATB_num_Digit(num, length)!=0xF; length++) + { + } + + return length; +} + + +/******************************************************************************* + + $Function: ATB_num_Compare + + $Description: This function compares two phone numbers by the standard comparison + method (ascending numeric, from the end of the number) and specifies + which record would come first if sorted in this method. + + $Returns: COMPARE_FIRSTBEFORE The first record should come before the second record + COMPARE_FIRSTAFTER The first record should come after the second record + + $Arguments: num1 The first number + num2 The second number + +*******************************************************************************/ + +T_PB_COMPARE ATB_num_Compare(UBYTE *num1, UBYTE *num2) +{ + T_PB_COMPARE compare; + SHORT charIndex; + SHORT length1 = ATB_num_Length(num1); + SHORT length2 = ATB_num_Length(num2); + UBYTE digit1; + UBYTE digit2; + + compare = COMPARE_IDENTICAL; /* Default */ + + for (charIndex = 0; charIndex < length1; charIndex++) + { + if (charIndex==length2) /* E.g. "123456" and "1234" */ + { + compare = COMPARE_FIRSTAFTER; + break; + } + + digit1 = ATB_num_Digit(num1, (SHORT)(length1-charIndex-1)); + digit2 = ATB_num_Digit(num2, (SHORT)(length2-charIndex-1)); + + if (digit1 < digit2) + { + compare = COMPARE_FIRSTBEFORE; + break; + } + if (digit1 > digit2) + { + compare = COMPARE_FIRSTAFTER; + break; + } + if (charIndex==length1-1 && length2>length1) /*E.g. "1234" and "123456" */ + { + compare = COMPARE_FIRSTBEFORE; + break; + } + } + + return compare; +} + +/******************************************************************************* + + $Function: ATB_num_Match + + $Description: This function matches phone numbers, from the end backwards, and + specifies how they match. + + $Returns: MATCH_NONE The numbers do not match + MATCH_START The first number matches the end of the second number + MATCH_EXACT The two numbers match exactly + + $Arguments: num1 The first number + num2 The second number + +*******************************************************************************/ + +T_PB_MATCH ATB_num_Match(UBYTE *num1, UBYTE *num2) +{ + T_PB_MATCH match; + SHORT charIndex; + SHORT length1 = ATB_num_Length(num1); + SHORT length2 = ATB_num_Length(num2); + SHORT offset; + UBYTE searching; + UBYTE some_match; + UBYTE digit1; + UBYTE digit2; + + match = MATCH_EXACT; /* Default */ + searching = TRUE; + some_match = FALSE; + offset = 0; + + do + { + for (charIndex = 0; charIndex < length1; charIndex++) + { + if (charIndex==(length2-offset)) /* E.g. "12345" and "123" */ + { + searching = FALSE; + break; /* No match, will exit do/while */ + } + + digit1 = ATB_num_Digit(num1, (SHORT)(length1-charIndex-1)); + digit2 = ATB_num_Digit(num2, (SHORT)(length2-charIndex-1)); + + if (digit1 != digit2) + { + some_match = FALSE; /* Any fragment so far identified does not fit */ + break; /* No match, keep looking */ + } + + some_match = TRUE; + + if (charIndex==length1-1 && length2>length1) /*E.g. "123" and "12345" */ + { + if (offset==0) + match = MATCH_START; + else + match = MATCH_FRAGMENT; + break; + } + } + + if (some_match==TRUE) + { + searching = FALSE; + } + else + { + offset++; + + /* If the fragment won't fit, don't keep looking */ + if ((offset+length1)>length2) + { + match=MATCH_NONE; + searching = FALSE; + } + } + } while (searching); + + return match; +} + + +/******************************************************************************* + + $Function: ATB_mem_UpdateCache + + $Description: Updates the cache with the record provided. If the cache is full, the + least used record is overwritten. + + $Returns: None. + + $Arguments: phonebook_id The phonebook identifier + index_type The index table required. + phys_index The physical index of the record to add. + record The record to add. + +*******************************************************************************/ + +void ATB_mem_UpdateCache(SHORT phonebook_id, SHORT phys_index, T_PB_RECORD *record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT cacheIndex; + SHORT leastUsed; + SHORT leastIndex; + + /* First check if record is already in RAM */ + + if (data->cache[phys_index] != NULL) + { + /* Copy the record in case it has changed */ + + ATB_pb_CopyRec(phonebook_id, data->cache[phys_index], record); + + if (data->in_memory[phys_index]<0xFFFF) + data->in_memory[phys_index]++; + return; + } + + /* If the cache is full, find the least accessed record */ + + if (data->cache_size==data->cache_max) + { + leastIndex = 0; + leastUsed = 255; + + for (cacheIndex=0; cacheIndex<data->records_max; cacheIndex++) + { + if (data->cache[cacheIndex]!=NULL && data->in_memory[cacheIndex] < leastUsed) + { + leastUsed = data->in_memory[cacheIndex]; + leastIndex = cacheIndex; + } + } + + /* Give the new record the memory allocated for the least used record */ + + data->cache[phys_index] = data->cache[leastIndex]; + data->cache[leastIndex] = NULL; + data->in_memory[leastIndex] = 0; + } + + /* If the cache is not full, allocate memory for record */ + + else + { + data->cache[phys_index] = ATB_pb_AllocRec(phonebook_id); + data->cache_size++; + } + + /* Copy the record into cache */ + + ATB_pb_CopyRec(phonebook_id, data->cache[phys_index], record); + data->in_memory[phys_index] = 1; + + return; +} + +/******************************************************************************* + + $Function: ATB_mem_ReadRec + + $Description: Reads a record from the logical position index. Information is read from + cache if it is present in memory, otherwise it will be read from file. + + The record information will be returned in the data structure pointed to + by record. The T_PB_RECORD structure must be allocated by the caller. + + $Returns: PB_OK Action completed OK. + PB_FILEREADFAIL File read encountered an error + PB_RECDOESNOTEXIST Tried to access a record that does not exist + + $Arguments: phonebook_id The phonebook identifier + index_type The index list from which the record is to be read + log_index Logical index in the index list of the record to read + record Structure in which to store record data + +*******************************************************************************/ + +PB_RET ATB_mem_ReadRec(SHORT phonebook_id, T_PB_INDEX index_type, SHORT log_index, T_PB_RECORD *record) +{ + T_PB_DATA *data = ATB_hnd_GetPbData(phonebook_id); + SHORT phys_index; + PB_RET result; + + /* Check that record exists */ + + if (log_index<0 + || (log_index>=data->records_used && (index_type==INDEX_NAME || index_type==INDEX_NUMBER)) + || (index_type==INDEX_SEARCH && log_index>data->search_results) + || (index_type==INDEX_PHYSICAL && log_index>data->records_max)) + { + trace("*** Error - record does not exist ***"); + return PB_RECDOESNOTEXIST; + } + + /* Get the corresponding physical record index */ + + phys_index = ATB_index_GetPhysIndex(phonebook_id, index_type, log_index); + + /* If the record is in the cache, simply copy it. Otherwise, call FS to read the record. */ + + if (data->in_memory[phys_index]>0) + { + ATB_pb_CopyRec(phonebook_id, record, data->cache[phys_index]); + result = PB_OK; + } + else + { + /* NB - assumes blocking read operation. If the read operation is blocking, + * the cache must be large enough to store all the phonebook entries. */ + result = FS_pb_ReadRec(phonebook_id, phys_index, record); + ATB_mem_UpdateCache(phonebook_id, phys_index, record); + } + + return result; +} + + +/******************************************************************************* + + $Function: ATB_hnd_GetPbData + + $Description: Returns phonebook data handle + + $Returns: The phonebook data handle + + $Arguments: phonebook_id The phonebook identifier + +*******************************************************************************/ + +T_PB_DATA* ATB_hnd_GetPbData(SHORT phonebook_id) +{ + return phonebook[phonebook_id]; +} + + +/******************************************************************************* + + $Function: ATB_hnd_SetPbData + + $Description: Sets phonebook data handle + + $Returns: None + + $Arguments: phonebook_id The phonebook identifier + data The phonebook data + +*******************************************************************************/ + +void ATB_hnd_SetPbData(SHORT phonebook_id, T_PB_DATA *data) +{ + phonebook[phonebook_id] = data; + + return; +} +