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

📄 addressdb.c

📁 我的Palm OS 5 SDK zhCN_PIMApps代码。 使用codewarrior 开发环境
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************************
 *
 * 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(&copy, 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, &copy, 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 + -