📄 addressdb.c
字号:
matches1 = 0;
else
matches1 = PrvAddrDBStrCmpMatches(key, recordKey);
MemHandleUnlock(rH);
if (matches1 == matches2)
*recordP = probe2;
else
break;
}
*completeMatch = (matches2 == StrLen(key));
}
return true;
}
/************************************************************
*
* FUNCTION: AddrDBLookupLookupString
*
* 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
* vars - Lookup variables
* recordP - to contain the record found
* phoneP - to contain the phone 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
*
* RETURNED: false is return if a displayable record was not found.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* Roger 7/19/96 Initial Revision
*
*************************************************************/
Boolean AddrDBLookupLookupString(DmOpenRef dbP, Char * key, Boolean sortByCompany, AddressLookupFields field1, AddressLookupFields field2, UInt16 * recordP, Int16 * phoneP, AddressFields lookupFieldMap[], Boolean *completeMatch, Boolean *uniqueMatch)
{
Int16 numOfRecords;
MemHandle rH;
PrvAddrPackedDBRecord* r;
// UInt16 kmin, i; // all positions in the database.
UInt16 probe, probe2 ; // all positions in the database.
Int16 phoneProbe, phoneProbe2;
// Int16 result; // result of comparing two records
UInt16 whichKey;
char* recordKey;
UInt16 matches1, matches2;
AddressFields searchField;
AddrDBRecordFlags searchFieldFlag;
*uniqueMatch = false;
*completeMatch = false;
// 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;
// Performing a lookup on the sort field allows the use a binary search which
// takes advantage of the ordered field.
if (field1 == addrLookupSortField)
{
// Perform the standard lookup on the sort fields looking at all categories.
if (!AddrDBLookupString(dbP, key, sortByCompany, dmAllCategories,
recordP, completeMatch, false))
return false; // nothing matched
// 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 = *recordP;
phoneProbe2 = phoneProbe = 0;
if (AddrDBLookupSeekRecord (dbP, &probe, &phoneProbe, 0, dmSeekForward,
field1, field2, lookupFieldMap))
{
// Now count the number of matching characters in probe
rH = DmQueryRecord(dbP, probe); // No deleted record possible
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "AddrLookup 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;
}
*uniqueMatch = true;
// 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 ||
!AddrDBLookupSeekRecord (dbP, &probe2, &phoneProbe2, 0, dmSeekBackward,
field1, field2, lookupFieldMap))
{
// There isn't an earlier record. Try to find a following record.
probe2 = probe + 1;
phoneProbe2 = phoneProbe;
if (!AddrDBLookupSeekRecord (dbP, &probe2, &phoneProbe2, 0, dmSeekForward,
field1, field2, lookupFieldMap))
{
// There isn't a following record. Try to use the probe.
if (matches1 > 0)
{
// Go with probe because they have at least some letters in common.
*recordP = probe; //
*phoneP = phoneProbe;
*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, "AddrLookup 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;
*phoneP = phoneProbe;
// If the next item has the same number of
// matching letters then the match is not unique.
probe2 = probe;
phoneProbe2 = phoneProbe;
if (AddrDBLookupSeekRecord (dbP, &probe2, &phoneProbe2, 1, dmSeekForward,
field1, field2, lookupFieldMap))
{
rH = DmQueryRecord(dbP, probe2);
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "AddrLookup bsearch: data somehow missing");
// Compare the string to the first sort key only
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
matches2 = 0;
else
matches2 = PrvAddrDBStrCmpMatches(key, recordKey);
MemHandleUnlock(rH);
if (matches1 <= matches2)
{
*uniqueMatch = false;
}
}
}
else
if (matches1 == 0 && matches2 == 0)
{
*completeMatch = false;
*uniqueMatch = 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;
*phoneP = phoneProbe2;
// 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 (AddrDBLookupSeekRecord (dbP, &probe2, &phoneProbe2, 1, dmSeekBackward,
field1, field2, lookupFieldMap))
{
rH = DmQueryRecord(dbP, probe2);
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "AddrLookup bsearch: data somehow missing");
// Compare the string to the first sort key only
whichKey = 1;
PrvAddrDBFindKey(r, &recordKey, &whichKey, sortByCompany);
if (recordKey == NULL)
matches1 = 0;
else
matches1 = PrvAddrDBStrCmpMatches(key, recordKey);
MemHandleUnlock(rH);
if (matches1 == matches2)
{
*recordP = probe2;
*phoneP = phoneProbe2;
}
else
break;
}
*completeMatch = (matches2 == StrLen(key));
*uniqueMatch = false;
}
return true;
}
else
{
// Peform a lookup based on unordered data. This gets real slow with lots of data
// Because to check for uniqueness we must search every record. This means on average
// this lookup is twice as slow as it would be it it could stop with the first match.
AddrDBRecordType record;
*completeMatch = false;
matches1 = 0; // treat this as the most matches
// cache these values
searchField = lookupFieldMap[field1];
searchFieldFlag.allBits = BitAtPosition(field1);
// Start with the first record and look at each record until there are no more.
// Look for the record with the most number of matching records. Even if we found
// a record containing all the record we are searching for we must still look
// for one more complete match to confirm or deny uniqueness of the match.
probe2 = 0;
phoneProbe2 = 0;
while (AddrDBLookupSeekRecord (dbP, &probe2, &phoneProbe2, 1, dmSeekForward,
field1, field2, lookupFieldMap))
{
rH = DmQueryRecord(dbP, probe2);
r = (PrvAddrPackedDBRecord *) MemHandleLock(rH);
ErrFatalDisplayIf(r == 0, "AddrLookup bsearch: data somehow missing");
// Compare the string to the search field
if (r->flags.allBits & searchFieldFlag.allBits)
{
PrvAddrDBUnpack(r, &record);
recordKey = record.fields[searchField];
if (recordKey == NULL)
matches2 = 0;
else
matches2 = PrvAddrDBStrCmpMatches(key, recordKey);
}
else
{
matches2 = 0;
}
MemHandleUnlock(rH);
if (matches2 > matches1)
{
matches1 = matches2; // the most matches so far
*recordP = probe2; // return the best record
*phoneP = phoneProbe2;
*completeMatch = (matches2 == StrLen(key));
}
// Did we find another record which is a complete match?
else if (matches2 > 0 &&
matches1 == matches2 &&
*completeMatch)
{
*uniqueMatch = false;
return true;
}
else
{
// The record is a matching failure. Since AddrLookupSeekRecord is going
// to return this record again for every phone field we cheat by specifying
// the last phone field to skip all other entries.
// phoneProbe2 = numPhoneFields - 1;
}
}
// Was at least one record found with at least one matching character?
if (matches1 > 0)
{
// At this point every record was searched and no other match was found.
*uniqueMatch = true;
return true;
}
}
return false;
}
/***********************************************************************
*
* FUNCTION: AddrDBGetDatabase
*
* DESCRIPTION: Get the application's database. Open the database if it
* exists, create it if neccessary.
*
* PARAMETERS: *dbPP - pointer to a database ref (DmOpenRef) to be set
* mode - how to open the database (dmModeReadWrite)
*
* RETURNED: Err - zero if no error, else the error
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* jmp 10/01/99 Initial Revision
*
***********************************************************************/
Err AddrDBGetDatabase (DmOpenRef *dbPP, UInt16 mode)
{
Err error = 0;
DmOpenRef dbP;
UInt16 cardNo;
LocalID dbID;
*dbPP = NULL;
// Find the application's data file. If it doesn't exist create it.
dbP = DmOpenDatabaseByTypeCreator (addrDBType, sysFileCAddress, mode);
if (!dbP)
{
error = DmCreateDatabase (0, addrDBName, sysFileCAddress, addrDBType, false);
if (error)
return error;
dbP = DmOpenDatabaseByTypeCreator(addrDBType, sysFileCAddress, mode);
if (!dbP)
return (1);
// Set the backup bit. This is to aid syncs with non Palm software.
ToolsSetDBAttrBits(dbP, dmHdrAttrBackup);
error = AddrDBAppInfoInit (dbP);
if (error)
{
DmOpenDatabaseInfo(dbP, &dbID, NULL, NULL, &cardNo, NULL);
DmCloseDatabase(dbP);
DmDeleteDatabase(cardNo, dbID);
return error;
}
}
*dbPP = dbP;
return 0;
}
#pragma mark -
/************************************************************
*
* FUNCTION: PrvAddrDBLocalizeAppInfo
*
* DESCRIPTION: Look for localize app info strings and copy
* them into the app info block.
*
* PARAMETERS: application info ptr
*
* RETURNS: nothing
*
* CREATED: 12/13/95
*
* BY: Roger Flores
*
* MODIFICATIONS:
* 10/22/96 roger Set flags when field modified
*************************************************************/
void PrvAddrDBLocalizeAppInfo(AddrAppInfoPtr appInfoP)
{
MemHandle localizedAppInfoH;
Char * localizedAppInfoP;
AddrAppInfoPtr nilP = 0;
MemHandle stringsH;
Char * *stringsP;
int i;
UInt16 localRenamedCategories;
UInt32 localDirtyFieldLabels;
localizedAppInfoH = DmGetResource(appInfoStringsRsc, LocalizedAppInfoStr);
if (!localizedAppInfoH)
return;
localizedAppInfoP = MemHandleLock(localizedAppInfoH);
stringsH = SysFormPointerArrayToStrings(localizedAppInfoP,
dmRecNumCategories + addrNumFields + numPhoneLabelsStoredSecond);
stringsP = MemHandleLock(stringsH);
// Copy each category
localRenamedCategories = appInfoP->renamedCategories;
for (i = 0; i < dmRecNumCategories; i++)
{
if (stringsP[i][0] != '\0')
{
DmStrCopy(appInfoP, (Int32) nilP->categoryLabels[i], stringsP[i]);
SetBitMacro(localRenamedCategories, i);
}
}
DmWrite(appInfoP, (Int32) &nilP->renamedCategories, &localRenamedCategories,
sizeof(localRenamedCategories));
// Copy each field label
localDirtyFieldLabels = appInfoP->dirtyFieldLabels.allBits;
for (i = 0; i < (addrNumFields + numPhoneLabelsStoredSecond); i++)
{
if (stringsP[i + dmRecNumCategories][0] != '\0')
{
DmStrCopy(appInfoP, (Int32) nilP->fieldLabels[i],
stringsP[i + dmRecNumCategories]);
SetBitMacro(localDirtyFieldLabels, i);
}
}
DmWrite(appInfoP, (Int32) &nilP->dirtyFieldLabels.allBits, &localDirtyFieldLabels,
sizeof(localDirtyFieldLabels));
MemPtrFree(stringsP);
MemPtrUnlock(localizedAppInfoP);
DmReleaseResource(localizedAppInfoH);
}
/************************************************************
*
* FUNCTION: PrvAddrDBFindKey
*
* DESCRIPTION: Return the next valid key
*
* PARAMETERS: database packed record
* <-> key to use (ptr to string or NULL for uniq ID)
* <-> which key (incremented for use again, starts at 1)
* -> sortByCompany
*
* RETURNS:
*
* CREATED: 1/16/95
*
* BY: Roger Flores
*
* COMMENTS: Returns the key which is asked for if possible and
* advances whichKey. If the key is not available the key advances
* to the next one. The order of keys is:
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -