📄 addressdb.c
字号:
/******************************************************************************
*
* Copyright (c) 1995-2003 PalmSource, Inc. All rights reserved.
*
* File: AddressDB.c
*
* Release: Palm OS 5 SDK (68K) R3.
*
* Description:
* Address Manager routines
*
*****************************************************************************/
#include "AddressDB.h"
#include "AddrTools.h"
#include "AddressRsc.h"
#include "AddrDefines.h"
#include <UIResources.h>
#include <SysUtils.h>
#include <ErrorMgr.h>
#include <StringMgr.h>
#include <TextMgr.h>
#include <PalmUtils.h>
#include <FeatureMgr.h>
#include "AddressSortLib.h"
/***********************************************************************
*
* Defines
*
***********************************************************************/
// Max length of a field name found in the FieldNamesStrList string list.
#define maxFieldName 31
#define LocalizedAppInfoStr 1000
// Extract the bit at position index from bitfield. 0 is the high bit.
#define BitAtPosition(pos) ((UInt32)1 << (pos))
#define GetBitMacro(bitfield, index) ((bitfield) & BitAtPosition(index))
#define SetBitMacro(bitfield, index) ((bitfield) |= BitAtPosition(index))
#define RemoveBitMacro(bitfield, index) ((bitfield) &= ~BitAtPosition(index))
#define sortKeyFieldBits (BitAtPosition(name) | BitAtPosition(firstName) | BitAtPosition(company))
// Indexes into FieldNamesStrList string list.
enum {
fieldNameStrListCity = 0,
fieldNameStrListState,
fieldNameStrListZip
};
// The following structure doesn't really exist. The first field
// varies depending on the data present. However, it is convient
// (and less error prone) to use when accessing the other information.
typedef struct {
AddrOptionsType options; // Display by company or by name
AddrDBRecordFlags flags;
UInt8 companyFieldOffset; // Offset from firstField
char firstField;
} PrvAddrPackedDBRecord;
/***********************************************************************
*
* Internal Functions
*
***********************************************************************/
static void PrvAddrDBLocalizeAppInfo(AddrAppInfoPtr appInfoP);
static void PrvAddrDBFindKey(PrvAddrPackedDBRecord *r, char **key, UInt16 *whichKey, Int16 sortByCompany);
static Int16 PrvAddrDBComparePackedRecords(PrvAddrPackedDBRecord *r1, PrvAddrPackedDBRecord *r2, Int16 sortByCompany, SortRecordInfoPtr /*info1*/, SortRecordInfoPtr /*info2*/, MemHandle /*appInfoH*/);
static Int16 PrvAddrDBUnpackedSize(AddrDBRecordPtr r);
static void PrvAddrDBPack(AddrDBRecordPtr s, void * recordP);
static void PrvAddrDBUnpack(PrvAddrPackedDBRecord *src, AddrDBRecordPtr dest);
static UInt16 PrvAddrDBFindSortPosition(DmOpenRef dbP, PrvAddrPackedDBRecord *newRecord);
static UInt16 PrvAddrDBStrCmpMatches(const Char* s1, const Char* s2);
static Boolean PrvAddrDBRecordContainsField(PrvAddrPackedDBRecord *packedRecordP, AddressLookupFields field, Int16 * phoneP, Int16 direction, AddressFields lookupFieldMap[]);
static Boolean PrvAddrDBSeekVisibleRecordInCategory (DmOpenRef dbR, UInt16 * indexP, UInt16 offset, Int16 direction, UInt16 category, Boolean masked);
/************************************************************
*
* FUNCTION: AddrDBAppInfoGetPtr
*
* DESCRIPTION: Return a locked pointer to the AddrAppInfo or NULL
*
* PARAMETERS: dbP - open database pointer
*
* RETURNS: locked ptr to the AddrAppInfo or NULL
*
* CREATED: 6/13/95
*
* BY: Roger Flores
*
*************************************************************/
AddrAppInfoPtr AddrDBAppInfoGetPtr(DmOpenRef dbP)
{
UInt16 cardNo;
LocalID dbID;
LocalID appInfoID;
if (DmOpenDatabaseInfo(dbP, &dbID, NULL, NULL, &cardNo, NULL))
return NULL;
if (DmDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &appInfoID, NULL, NULL, NULL))
return NULL;
if (appInfoID == 0)
return NULL;
else
return MemLocalIDToLockedPtr(appInfoID, cardNo);
}
/************************************************************
*
* FUNCTION: AddrDBChangeCountry
*
* DESCRIPTION: Set the field labels to those appropriate
* to the current country (based on system preferences).
*
* PARAMETERS: application info ptr
*
* RETURNS: nothing
*
* HISTORY:
* 07/24/95 rsf Created by Roger Flores
* 07/29/99 kwk Load field names from string list resource.
*
*************************************************************/
void AddrDBChangeCountry(AddrAppInfoPtr appInfoP)
{
CountryType countryCurrent;
AddrAppInfoPtr nilP = NULL;
MemHandle textH;
UInt16 strListID;
Char fieldName[maxFieldName + sizeOf7BitChar(chrNull)];
// Localize the field labels to the current country
countryCurrent = (CountryType) PrefGetPreference(prefCountry);
strListID = (UInt16)countryCurrent + FieldNamesStrList;
textH = DmGetResource(strListRscType, strListID);
if (textH != NULL)
{
AddrDBRecordFlags dirtyFieldLabels;
DmStrCopy(appInfoP, (Int32) nilP->fieldLabels[city],
SysStringByIndex(strListID, fieldNameStrListCity, fieldName, maxFieldName));
DmStrCopy(appInfoP, (Int32) nilP->fieldLabels[state],
SysStringByIndex(strListID, fieldNameStrListState, fieldName, maxFieldName));
DmStrCopy(appInfoP, (Int32) nilP->fieldLabels[zipCode],
SysStringByIndex(strListID, fieldNameStrListZip, fieldName, maxFieldName));
dirtyFieldLabels.allBits = (appInfoP->dirtyFieldLabels.allBits) |
BitAtPosition(city) | BitAtPosition(state) | BitAtPosition(zipCode);
DmWrite(appInfoP, (Int32) &nilP->dirtyFieldLabels, &dirtyFieldLabels, sizeof dirtyFieldLabels);
}
// Record the country.
DmWrite(appInfoP, (Int32) &nilP->country, &countryCurrent, sizeof(countryCurrent));
}
/************************************************************
*
* FUNCTION: AddrDBAppInfoInit
*
* DESCRIPTION: Create an app info chunk if missing. Set
* the strings to a default.
*
* PARAMETERS: dbP - open database pointer
*
* RETURNS: 0 if successful, errorcode if not
*
* CREATED: 1/3/95
*
* BY: Roger Flores
*
* MODIFICATIONS:
* 10/22/96 roger Change to init data via code and resources to
* remove global var use which wasn't always available.
*************************************************************/
Err AddrDBAppInfoInit(DmOpenRef dbP)
{
UInt16 cardNo;
LocalID dbID;
LocalID appInfoID;
MemHandle h;
AddrAppInfoPtr appInfoP;
AddrAppInfoPtr defaultAddrApplicationInfoP;
UInt8 i;
appInfoP = AddrDBAppInfoGetPtr(dbP);
// If there isn't an AddrApplicationInfo make space for one
if (appInfoP == NULL)
{
if (DmOpenDatabaseInfo(dbP, &dbID, NULL, NULL, &cardNo, NULL))
return dmErrInvalidParam;
if (DmDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &appInfoID, NULL, NULL, NULL))
return dmErrInvalidParam;
h = DmNewHandle(dbP, sizeof(AddrAppInfoType));
if (!h) return dmErrMemError;
appInfoID = MemHandleToLocalID( h);
if (DmSetDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &appInfoID, NULL, NULL, NULL))
{
MemHandleFree(h);
return 1;
}
appInfoP = MemHandleLock(h);
}
// Allocate & Clear the app info
defaultAddrApplicationInfoP = MemPtrNew(sizeof(AddrAppInfoType));
if (defaultAddrApplicationInfoP == NULL)
{
ErrDisplay("Unable to init AddressDB");
return 1;
}
MemSet(defaultAddrApplicationInfoP, sizeof(AddrAppInfoType), 0);
// Init the categories
for (i = 0; i < dmRecNumCategories; i++)
{
defaultAddrApplicationInfoP->categoryUniqIDs[i] = i;
}
defaultAddrApplicationInfoP->lastUniqID = dmRecNumCategories - 1;
// Set to sort by name
defaultAddrApplicationInfoP->misc.sortByCompany = false;
// copy in the defaults and free the default app info
DmWrite(appInfoP, 0, defaultAddrApplicationInfoP, sizeof(AddrAppInfoType));
MemPtrFree(defaultAddrApplicationInfoP);
// Try to use localized app info block strings.
PrvAddrDBLocalizeAppInfo(appInfoP);
// Localize the field labels to the current country
AddrDBChangeCountry(appInfoP);
// Unlock
MemPtrUnlock(appInfoP);
return 0;
}
/************************************************************
*
* FUNCTION: AddrDBSetFieldLabel
*
* DESCRIPTION: Set a field's label and mark it dirty.
*
* PARAMETERS: dbP - open database pointer
* fieldNum - field label to change
* fieldLabel - new field label to use
*
* RETURNS: 0 if successful, errorcode if not
*
* CREATED: 6/28/95
*
* BY: Roger Flores
*
*************************************************************/
void AddrDBSetFieldLabel(DmOpenRef dbP, UInt16 fieldNum, Char * fieldLabel)
{
AddrAppInfoPtr appInfoP;
AddrAppInfoType copy;
ErrFatalDisplayIf(fieldNum >= lastLabel,
"fieldNum out of range");
// Get a copy of the app info
appInfoP = AddrDBAppInfoGetPtr(dbP);
ErrFatalDisplayIf(appInfoP == NULL,
"Bad database (invalid or no app info block)");
MemMove(©, appInfoP, sizeof(copy));
// Make the changes
StrCopy(copy.fieldLabels[fieldNum], fieldLabel); //lint !e661
SetBitMacro(copy.dirtyFieldLabels.allBits, fieldNum);
// Write changes to record
DmWrite(appInfoP, 0, ©, sizeof(copy));
// Unlock app info
MemPtrUnlock(appInfoP);
}
/************************************************************
*
* FUNCTION: AddrDBNewRecord
*
* DESCRIPTION: Create a new packed record in sorted position
*
* PARAMETERS: database pointer - open db pointer
* address record - pointer to a record to copy into the DB
* record index - to be set to the new record's index
*
* RETURNS: ##0 if successful, errorcode if not
* index set if a new record is created.
*
* CREATED: 1/10/95
*
* BY: Roger Flores
*
*************************************************************/
Err AddrDBNewRecord(DmOpenRef dbP, AddrDBRecordPtr r, UInt16 *index)
{
MemHandle recordH;
Err err;
PrvAddrPackedDBRecord* recordP;
UInt16 newIndex;
// 1) and 2) (make a new chunk with the correct size)
recordH = DmNewHandle(dbP, (Int32) PrvAddrDBUnpackedSize(r));
if (recordH == NULL)
return dmErrMemError;
// 3) Copy the data from the unpacked record to the packed one.
recordP = MemHandleLock(recordH);
PrvAddrDBPack(r, recordP);
// Get the index
newIndex = PrvAddrDBFindSortPosition(dbP, recordP);
MemPtrUnlock(recordP);
// 4) attach in place
err = DmAttachRecord(dbP, &newIndex, recordH, 0);
if (err)
MemHandleFree(recordH);
else
*index = newIndex;
return err;
}
/************************************************************
*
* FUNCTION: AddrDBChangeRecord
*
* DESCRIPTION: Change a record in the Address Database
*
* PARAMETERS: dbP - open database pointer
* database index
* address record
* changed fields
*
* RETURNS: ##0 if successful, errorcode if not
*
* CREATED: 1/14/95
*
* BY: Roger Flores
*
* COMMENTS: Records are not stored with extra padding - they
* are always resized to their exact storage space. This avoids
* a database compression issue. The code works as follows:
*
* 1) get the size of the new record
* 2) make the new record
* 3) pack the packed record plus the changes into the new record
* 4) if the sort position is changes move to the new position
* 5) attach in position
*
* The MemHandle to the record passed doesn't need to be unlocked
* since that chunk is freed by this routine. It should be discarded.
*
*************************************************************/
Err AddrDBChangeRecord(DmOpenRef dbP, UInt16 *index, AddrDBRecordPtr r, AddrDBRecordFlags changedFields)
{
AddrDBRecordType src;
MemHandle srcH;
Err result;
MemHandle recordH=0;
MemHandle oldH;
Int16 i;
UInt32 changes = changedFields.allBits;
Int16 sortByCompany;
AddrAppInfoPtr appInfoPtr;
Boolean dontMove;
UInt16 attributes; // to contain the deleted flag
PrvAddrPackedDBRecord* cmpP;
PrvAddrPackedDBRecord* recordP;
// We do not assume that r is completely valid so we get a valid
// AddrDBRecordPtr...
if ((result = AddrDBGetRecord(dbP, *index, &src, &srcH)) != 0)
return result;
// and we apply the changes to it.
src.options = r->options; // copy the phone info
for (i = firstAddressField; i < addressFieldsCount; i++)
{
// If the flag is set point to the string else NULL
if (GetBitMacro(changes, i) != 0)
{
src.fields[i] = r->fields[i];
RemoveBitMacro(changes, i);
}
if (changes == 0)
break; // no more changes
}
// 1) and 2) (make a new chunk with the correct size)
recordH = DmNewHandle(dbP, PrvAddrDBUnpackedSize(&src));
if (recordH == NULL)
{
MemHandleUnlock(srcH); // undo lock from AddrGetRecord above
return dmErrMemError;
}
recordP = MemHandleLock(recordH);
// 3) Copy the data from the unpacked record to the packed one.
PrvAddrDBPack(&src, recordP);
// The original record is copied and no longer needed.
MemHandleUnlock(srcH);
// 4) if the sort position changes...
// Check if any of the key fields have changed
if ((changedFields.allBits & sortKeyFieldBits) == 0)
goto attachRecord;
// Make sure *index-1 < *index < *index+1, if so it's in sorted
// order. Leave it there.
appInfoPtr = (AddrAppInfoPtr) AddrDBAppInfoGetPtr(dbP);
sortByCompany = appInfoPtr->misc.sortByCompany;
MemPtrUnlock(appInfoPtr);
if (*index > 0)
{
// This record wasn't deleted and deleted records are at the end of the
// database so the prior record may not be deleted!
cmpP = MemHandleLock(DmQueryRecord(dbP, *index-1));
dontMove = (PrvAddrDBComparePackedRecords (cmpP, recordP, sortByCompany,
NULL, NULL, 0) == -1);
MemPtrUnlock(cmpP);
}
else
dontMove = true;
if (*index+1 < DmNumRecords (dbP))
{
DmRecordInfo(dbP, *index+1, &attributes, NULL, NULL);
if (attributes & dmRecAttrDelete)
; // don't move it after the deleted record!
else {
cmpP = MemHandleLock(DmQueryRecord(dbP, *index+1));
dontMove = dontMove && (PrvAddrDBComparePackedRecords (recordP, cmpP, sortByCompany, NULL, NULL, 0) == -1);
MemPtrUnlock(cmpP);
}
}
if (dontMove)
goto attachRecord;
// The record isn't in the right position. Move it.
i = PrvAddrDBFindSortPosition(dbP, recordP);
DmMoveRecord(dbP, *index, i);
if (i > *index) i--;
*index = i; // return new position
// Attach the new record to the old index, the preserves the
// category and record id.
attachRecord:
result = DmAttachRecord(dbP, index, recordH, &oldH);
MemPtrUnlock(recordP);
if (result) return result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -