📄 addressdb.c
字号:
MemHandleFree(oldH);
return 0;
}
/************************************************************
*
* FUNCTION: AddrDBGetRecord
*
* DESCRIPTION: Get a record from the Address Database
*
* PARAMETERS: database pointer - open db pointer
* database index - index of record to lock
* address record pointer - pointer address structure
* address record - MemHandle to unlock when done
*
* RETURNS: ##0 if successful, errorcode if not
* The record's MemHandle is locked so that the pointer to
* strings within the record remain pointing to valid chunk
* versus the record randomly moving. Unlock the MemHandle when
* AddrDBRecord is destroyed.
*
* CREATED: 1/14/95
*
* BY: Roger Flores
*
*************************************************************/
Err AddrDBGetRecord(DmOpenRef dbP, UInt16 index, AddrDBRecordPtr recordP,
MemHandle *recordH)
{
PrvAddrPackedDBRecord *src;
*recordH = DmQueryRecord(dbP, index);
if (*recordH == NULL)
return dmErrMemError;
src = (PrvAddrPackedDBRecord *) MemHandleLock(*recordH);
if (src == NULL)
return dmErrIndexOutOfRange;
PrvAddrDBUnpack(src, recordP);
return 0;
}
/***********************************************************************
*
* FUNCTION: AddrDBRecordContainsData
*
* DESCRIPTION: Checks the record returns true if it contains any data.
*
* PARAMETERS: recordP - a pointer to an address record
*
* RETURNED: true if one of the fields has data
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* rsf 12/3/97 Initial Revision
*
***********************************************************************/
Boolean AddrDBRecordContainsData (AddrDBRecordPtr recordP)
{
UInt16 i;
// Look for a field which isn't empty
for (i = firstAddressField; i < addressFieldsCount; i++)
{
if (recordP->fields[i] != NULL)
return true;
}
return false;
}
/************************************************************
*
* FUNCTION: AddrDBChangeSortOrder
*
* DESCRIPTION: Change the Address Database's sort order
*
* PARAMETERS: dbP - open database pointer
* TRUE if sort by company
*
* RETURNS: nothing
*
* CREATED: 1/17/95
*
* BY: Roger Flores
*
*************************************************************/
Err AddrDBChangeSortOrder(DmOpenRef dbP, Boolean sortByCompany)
{
AddrAppInfoPtr appInfoPtr;
AddrAppInfoPtr nilP=0;
AddrDBMisc misc;
UInt32 paceVersion;
UInt16 addrSortLibRefNum;
appInfoPtr = (AddrAppInfoPtr) AddrDBAppInfoGetPtr(dbP);
misc = appInfoPtr->misc;
misc.sortByCompany = sortByCompany;
DmWrite(appInfoPtr, (Int32) &nilP->misc, &misc, sizeof(misc));
MemPtrUnlock(appInfoPtr);
// Use ARM sort if possible. If we're running PACE... it's ARM :-)
if (FtrGet('pace', 0, &paceVersion ) == ftrErrNoSuchFeature) {
// This is the original code
DmQuickSort(dbP, (DmComparF *) PrvAddrDBComparePackedRecords, (Int16) sortByCompany);
}
else {
#ifndef MAC_SIMULATOR_APP
// Try to load the lib. If it fails, default to the original code
if (SysLibLoad('libr', 'adbs', &addrSortLibRefNum) == errNone) {
// This is the ARM lib code
AddrDBSort(addrSortLibRefNum, dbP, (Int16) sortByCompany);
SysLibRemove(addrSortLibRefNum);
}
else
#endif
{
DmQuickSort(dbP, (DmComparF *) PrvAddrDBComparePackedRecords, (Int16) sortByCompany);
}
}
return 0;
}
/***********************************************************************
*
* FUNCTION: AddrDBLookupSeekRecord
*
* DESCRIPTION: Given the index of a record, scan
* forewards or backwards for displayable records.
*
* PARAMETERS: indexP - pointer to the index of a record to start from;
* the index of the record sought is returned in
* this parameter.
*
* offset - number of records to skip:
* 0 - mean seek from the current record to the
* next display record, if the current record is
* a display record, its index is retuned.
* 1 - mean seek foreward, skipping one displayable
* record
* -1 - means seek backwards, skipping one
* displayable record
*
*
* RETURNED: true if a displayable record was found.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* Roger 7/9/96 Initial Revision
*
***********************************************************************/
Boolean AddrDBLookupSeekRecord (DmOpenRef dbP, UInt16 * indexP, Int16 * phoneP, Int16 offset, Int16 direction, AddressLookupFields field1, AddressLookupFields field2, AddressFields lookupFieldMap[])
{
UInt16 index;
UInt16 oldIndex;
UInt16 count;
UInt16 numRecords;
MemHandle recordH;
Boolean match;
Int16 phone;
Boolean searchPhones;
PrvAddrPackedDBRecord *packedRecordP;
ErrFatalDisplayIf ( (direction != dmSeekForward) && (direction != dmSeekBackward),
"Bad Param");
ErrFatalDisplayIf ( (offset < 0), "Bad param");
index = *indexP;
phone = *phoneP;
searchPhones = IsPhoneLookupField(field1) || IsPhoneLookupField(field2);
numRecords = DmNumRecords(dbP);
if (index >= numRecords)
{
if (direction == dmSeekForward)
return false;
else
index = numRecords - 1;
}
// Moving forward?
if (direction == dmSeekForward )
count = numRecords - index;
else
count = index + 1;
// Loop through the records
while (count--) {
// Make sure the current record isn't hidden. If so skip it and find the
// next non hidden record. Decrease the record count to search by the number
// of records skipped.
oldIndex = index;
if (DmSeekRecordInCategory (dbP, &index, 0, direction, dmAllCategories))
{
// There are no more records.
break;
}
if (index != oldIndex)
{
if (direction == dmSeekForward)
count -= index - oldIndex;
else
count -= oldIndex - index;
}
recordH = DmQueryRecord(dbP, index);
// If we have found a deleted record stop the search.
if (!recordH)
break;
packedRecordP = MemHandleLock(recordH);
if (!packedRecordP)
goto Exit;
match = PrvAddrDBRecordContainsField(packedRecordP, field1, &phone, direction, lookupFieldMap) &&
PrvAddrDBRecordContainsField(packedRecordP, field2, &phone, direction, lookupFieldMap);
MemHandleUnlock(recordH);
if (match)
{
*indexP = index;
*phoneP = phone;
if (offset == 0) return true;
offset--;
}
// Look for another phone in this record if one was found or
// else look at the next record.
if (searchPhones && match)
{
phone += direction;
// We their are no more phones to search so advance to next record
if (phone == -1 || numPhoneFields <= phone)
{
if (direction == dmSeekForward)
phone = 0;
else
phone = numPhoneFields - 1;
index += direction;
}
else
{
// Since we are going to search this record again bump the count up
// by one. This loop is supposed to loop once per record to search.
count++;
}
}
else
index += direction;
}
return false;
Exit:
ErrDisplay("Err seeking rec");
return false;
}
/************************************************************
*
* FUNCTION: AddrDBLookupString
*
* DESCRIPTION: Return which record contains the most of
* the string passed. If no string is passed or there
* aren't any records then false is returned.
*
* PARAMETERS: address record
* key - string to lookup record with
* sortByCompany - how the db is sorted
* category - the category to search in
* recordP - to contain the record found
* completeMatch - true if a record contains all
* of the key
*
* RETURNS: the record in recordP or false
* completeMatch - true if a record contains all
* of the key
*
* CREATED: 6/15/95
*
* BY: Roger Flores
*
*************************************************************/
Boolean AddrDBLookupString(DmOpenRef dbP, Char * key, Boolean sortByCompany, UInt16 category, UInt16 * recordP, Boolean *completeMatch, Boolean masked)
{
Int16 numOfRecords;
MemHandle rH;
PrvAddrPackedDBRecord* r;
UInt16 kmin, probe, probe2, i; // all positions in the database.
Int16 result; // result of comparing two records
UInt16 whichKey;
char* recordKey;
UInt16 matches1, matches2;
// If there isn't a key to search with stop the with the first record.
if (key == NULL || *key == '\0')
{
*completeMatch = true;
return false;
}
numOfRecords = DmNumRecords(dbP);
if (numOfRecords == 0)
return false;
result = 0;
kmin = probe = 0;
rH = 0;
while (numOfRecords > 0)
{
i = numOfRecords / 2;
probe = kmin + i;
// Compare the two records. Treat deleted records as greater.
// If the records are equal look at the following position.
if (rH)
MemHandleUnlock(rH);
rH = DmQueryRecord(dbP, probe);
if (rH == 0)
{
result = -1; // Delete record is greater
}
else
{
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "Addr bsearch: data somehow missing");
// Compare the string to the first sort key only
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
result = 1;
else
result = StrCaselessCompare(key, recordKey);
// If equal stop here! We don't want the position after.
if (result == 0)
goto findRecordInCategory;
}
ErrFatalDisplayIf(result == 0, "Impossible bsearch state");
// More likely than < 0 because of deleted records
if (result < 0)
numOfRecords = i;
else
{
kmin = probe + 1;
numOfRecords = numOfRecords - i - 1;
}
}
if (result >= 0)
probe++;
findRecordInCategory:
if (rH)
MemHandleUnlock(rH);
// At this point probe is the position where the string could be
// inserted. It is in between two entries. Neither the record
// before or after may have ANY letters in common, especially after
// those records in other catergories are skipped. Go with the
// record that has the most letters in common.
// Make sure the record returned is of the same category.
// If not return the first prior record of the same category.
probe2 = probe;
if (!PrvAddrDBSeekVisibleRecordInCategory (dbP, &probe, 0, dmSeekForward, category, masked))
{
// Now count the number of matching characters in probe
rH = DmQueryRecord(dbP, probe); // No deleted record possible
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "Addr bsearch: data somehow missing");
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
matches1 = 0;
else
matches1 = PrvAddrDBStrCmpMatches(key, recordKey);
MemHandleUnlock(rH);
}
else
{
// No record in this category was found or probe is past all
// records in this category. Either way there aren't any matching
// letters.
matches1 = 0;
}
// Sometimes the record before has more matching letters. Check it.
// Passing DmSeekRecordInCategory an offset of 1 doesn't work
// when probe is at the end of the database and there isn't at least
// one record to skip.
probe2 = probe - 1;
if (probe == 0 ||
PrvAddrDBSeekVisibleRecordInCategory (dbP, &probe2, 0, dmSeekBackward, category, masked))
{
if (matches1 > 0)
{
// Go with probe because they have at least some letters in common.
*recordP = probe; //
*completeMatch = (matches1 == StrLen(key));
return true;
}
else
{
// probe has no letters in common and nothing earlier in this category
// was found so this is a failed lookup.
*completeMatch = false;
return false;
}
}
// Now count the number of matching characters in probe2
rH = DmQueryRecord(dbP, probe2); // No deleted record possible
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "Addr bsearch: data somehow missing");
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
matches2 = 0;
else
matches2 = PrvAddrDBStrCmpMatches(key, recordKey);
MemHandleUnlock(rH);
// Now, return the probe which has the most letters in common.
if (matches1 > matches2)
{
*completeMatch = (matches1 == StrLen(key));
*recordP = probe;
}
else
if (matches1 == 0 && matches2 == 0)
{
*completeMatch = false;
return false; // no item with same first letter found
}
else
{
// The first item matches as much or more as the second item
*recordP = probe2;
// If the prior item in the category has the same number of
// matching letters use it instead. Repeat to find the
// earliest such match.
while (!PrvAddrDBSeekVisibleRecordInCategory (dbP, &probe2, 1, dmSeekBackward, category, masked))
{
rH = DmQueryRecord(dbP, probe2);
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "Addr bsearch: data somehow missing");
// Compare the string to the first sort key only
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -