533 lines
14 KiB
C
533 lines
14 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (c) 1995-2000 Palm, Inc. or its subsidiaries.
|
|
* All rights reserved.
|
|
*
|
|
* File: MemoDB.c
|
|
*
|
|
* Release: Palm OS SDK 4.0 (63220)
|
|
*
|
|
* Description:
|
|
* Memo Manager routines
|
|
*
|
|
* History:
|
|
* 1/3/95 rsf - Created
|
|
* 9/13/95 mlb - added MemoNewRecord for use by mbs shell command
|
|
* 10/02/99 jmp - Add MemoGetDatabase() routine.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <PalmOS.h>
|
|
|
|
#include <PalmUtils.h>
|
|
|
|
#include "MemoDB.h"
|
|
#include "MemoMain.h"
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoLocalizeAppInfo
|
|
*
|
|
* 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
|
|
*
|
|
*************************************************************/
|
|
static void MemoLocalizeAppInfo (MemoAppInfoPtr appInfoP)
|
|
{
|
|
Int16 i;
|
|
Char ** stringsP;
|
|
MemHandle stringsH;
|
|
MemHandle localizedAppInfoH;
|
|
Char * localizedAppInfoP;
|
|
MemoAppInfoPtr nilP = 0;
|
|
|
|
|
|
localizedAppInfoH = DmGetResource(appInfoStringsRsc, LocalizedAppInfoStr);
|
|
if (localizedAppInfoH)
|
|
{
|
|
localizedAppInfoP = MemHandleLock(localizedAppInfoH);
|
|
stringsH = SysFormPointerArrayToStrings(localizedAppInfoP,
|
|
dmRecNumCategories);
|
|
stringsP = MemHandleLock(stringsH);
|
|
|
|
// Copy each category
|
|
for (i = 0; i < dmRecNumCategories; i++)
|
|
{
|
|
if (stringsP[i][0] != '\0')
|
|
DmStrCopy(appInfoP, (UInt32) nilP->categoryLabels[i], stringsP[i]);
|
|
}
|
|
|
|
MemPtrFree(stringsP);
|
|
MemPtrUnlock(localizedAppInfoP);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoAppInfoInit
|
|
*
|
|
* DESCRIPTION: Create an app info chunk if missing. Set
|
|
* the strings to a default.
|
|
*
|
|
* PARAMETERS: database pointer
|
|
*
|
|
* RETURNS: 0 if successful, errorcode if not
|
|
*
|
|
* CREATED: 1/3/95
|
|
*
|
|
* BY: Roger Flores
|
|
*
|
|
*************************************************************/
|
|
Err MemoAppInfoInit(DmOpenRef dbP)
|
|
{
|
|
UInt16 cardNo;
|
|
MemHandle h;
|
|
LocalID dbID;
|
|
LocalID appInfoID;
|
|
MemoAppInfoPtr nilP = 0;
|
|
MemoAppInfoPtr appInfoP;
|
|
|
|
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;
|
|
|
|
if (appInfoID == 0)
|
|
{
|
|
h = DmNewHandle (dbP, sizeof (MemoAppInfoType));
|
|
if (! h) return dmErrMemError;
|
|
|
|
appInfoID = MemHandleToLocalID (h);
|
|
DmSetDatabaseInfo(cardNo, dbID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &appInfoID, NULL, NULL, NULL);
|
|
}
|
|
|
|
appInfoP = MemLocalIDToLockedPtr(appInfoID, cardNo);
|
|
|
|
// Clear the app info block.
|
|
DmSet (appInfoP, 0, sizeof(MemoAppInfoType), 0);
|
|
|
|
// Initialize the categories.
|
|
CategoryInitialize ((AppInfoPtr) appInfoP, LocalizedAppInfoStr);
|
|
|
|
// Initialize the sort order.
|
|
DmSet (appInfoP, (UInt32)&nilP->sortOrder, sizeof(appInfoP->sortOrder),
|
|
soAlphabetic);
|
|
|
|
MemPtrUnlock(appInfoP);
|
|
|
|
// The conduit ignores dmHdrAttrAppInfoDirty
|
|
return 0;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoGetAppInfo
|
|
*
|
|
* DESCRIPTION: Get the app info chunk
|
|
*
|
|
* PARAMETERS: database pointer
|
|
*
|
|
* RETURNS: MemHandle to the to do application info block
|
|
* (MemoAppInfoType)
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* art 7/18/96 Initial Revision
|
|
*
|
|
*************************************************************/
|
|
static MemHandle MemoGetAppInfo (DmOpenRef dbP)
|
|
{
|
|
Err error;
|
|
UInt16 cardNo;
|
|
LocalID dbID;
|
|
LocalID appInfoID;
|
|
|
|
error = DmOpenDatabaseInfo (dbP, &dbID, NULL, NULL, &cardNo, NULL);
|
|
ErrFatalDisplayIf (error, "Get getting app info block");
|
|
|
|
error = DmDatabaseInfo (cardNo, dbID, NULL, NULL, NULL, NULL, NULL,
|
|
NULL, NULL, &appInfoID, NULL, NULL, NULL);
|
|
ErrFatalDisplayIf (error, "Get getting app info block");
|
|
|
|
return ((MemHandle) MemLocalIDToGlobal (appInfoID, cardNo));
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoCompareRecords
|
|
*
|
|
* DESCRIPTION: Compare two records.
|
|
*
|
|
* PARAMETERS: database record 1
|
|
* database record 2
|
|
*
|
|
* RETURNS: -n if record one is less (n != 0)
|
|
* n if record two is less
|
|
*
|
|
* COMMENTS: Compare the two records key by key until
|
|
* there is a difference. Return -n if r1 is less or n if r2
|
|
* is less. A zero is never returned because if two records
|
|
* seem identical then their unique IDs are compared!
|
|
*
|
|
* This function accepts record data chunk pointers to avoid
|
|
* requiring that the record be within the database. This is
|
|
* important when adding records to a database. This prevents
|
|
* determining if a record is a deleted record (which are kept
|
|
* at the end of the database and should be considered "greater").
|
|
* The caller should test for deleted records before calling this
|
|
* function!
|
|
*
|
|
* HISTORY:
|
|
* 07/18/96 art Created by Art Lamb.
|
|
* 11/30/00 kwk Use TxtCompare vs. StrCompare to avoid one
|
|
* extra trap call.
|
|
*
|
|
*************************************************************/
|
|
static Int16 MemoCompareRecords (MemoDBRecordPtr r1,
|
|
MemoDBRecordPtr r2, Int16 sortOrder, SortRecordInfoPtr UNUSED_PARAM(info1),
|
|
SortRecordInfoPtr UNUSED_PARAM(info2), MemHandle UNUSED_PARAM(appInfoH))
|
|
{
|
|
Int16 result;
|
|
|
|
// Alphabetize;
|
|
if (sortOrder == soAlphabetic)
|
|
{
|
|
result = TxtCompare( &r1->note, // const Char *s1
|
|
0xFFFF, // UInt16 s1Len,
|
|
NULL, // UInt16 *s1MatchLen,
|
|
&r2->note, // const Char *s2,
|
|
0xFFFF, // UInt16 s2Len,
|
|
NULL); // UInt16 *s2MatchLen
|
|
}
|
|
else
|
|
result = 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoGetSortOrder
|
|
*
|
|
* DESCRIPTION: This routine get the sort order value from the
|
|
* to do application info block.
|
|
*
|
|
* PARAMETERS: database pointer
|
|
*
|
|
* RETURNS: true - if the to do record are sorted by priority,
|
|
* false - if the records are sorted by due date.
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* art 7/18/96 Initial Revision
|
|
*
|
|
*************************************************************/
|
|
UInt8 MemoGetSortOrder (DmOpenRef dbP)
|
|
{
|
|
UInt8 sortOrder;
|
|
MemoAppInfoPtr appInfoP;
|
|
|
|
appInfoP = MemHandleLock (MemoGetAppInfo (dbP));
|
|
sortOrder = appInfoP->sortOrder;
|
|
MemPtrUnlock (appInfoP);
|
|
|
|
return (sortOrder);
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoChangeSortOrder
|
|
*
|
|
* DESCRIPTION: Change the Memo Database's sort order
|
|
*
|
|
* PARAMETERS: database pointer
|
|
* TRUE if sort by company
|
|
*
|
|
* RETURNS: nothing
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* art 7/18/96 Initial Revision
|
|
*
|
|
*************************************************************/
|
|
Err MemoChangeSortOrder(DmOpenRef dbP, Boolean sortOrder)
|
|
{
|
|
MemoAppInfoPtr appInfoP;
|
|
MemoAppInfoPtr nilP = 0;
|
|
|
|
|
|
appInfoP = MemHandleLock (MemoGetAppInfo (dbP));
|
|
|
|
if (appInfoP->sortOrder != sortOrder)
|
|
{
|
|
DmWrite (appInfoP, (UInt32)&nilP->sortOrder, &sortOrder, sizeof(appInfoP->sortOrder));
|
|
|
|
if (sortOrder == soAlphabetic)
|
|
DmInsertionSort (dbP, (DmComparF *) &MemoCompareRecords, (Int16) sortOrder);
|
|
}
|
|
|
|
MemPtrUnlock (appInfoP);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoSort
|
|
*
|
|
* DESCRIPTION: Sort the appointment database.
|
|
*
|
|
* PARAMETERS: database record
|
|
*
|
|
* RETURNS: nothing
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* art 7/18/96 Initial Revision
|
|
* gap 6/29/00 When in manual sort mode this
|
|
* routine was exiting immediately which caused
|
|
* deleted and non-deleted records to be mixed in
|
|
* the database as opposed to having deleted records
|
|
* all appended at the end of the database. Now check
|
|
* to move records above all deleted records (which can
|
|
* occur in the case of receiving multiple beamed records).
|
|
*
|
|
*************************************************************/
|
|
void MemoSort (DmOpenRef dbP)
|
|
{
|
|
Int16 sortOrder;
|
|
|
|
sortOrder = MemoGetSortOrder (dbP);
|
|
DmInsertionSort (dbP, (DmComparF *) &MemoCompareRecords, (Int16) sortOrder);
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoNewRecord
|
|
*
|
|
* DESCRIPTION: Create a new record
|
|
*
|
|
* PARAMETERS: database pointer
|
|
* database record
|
|
*
|
|
* RETURNS: zero if successful, errorcode if not
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* monty 9/13/95 Initial Revision
|
|
*
|
|
*************************************************************/
|
|
Err MemoNewRecord (DmOpenRef dbP, MemoItemPtr item, UInt16 *index)
|
|
{
|
|
Err result;
|
|
int size = 0;
|
|
UInt32 offset;
|
|
MemHandle recordH;
|
|
MemoDBRecordPtr recordP, nilP=0;
|
|
|
|
// Compute the size of the new memo record.
|
|
size = StrLen (item->note);
|
|
|
|
// Allocate a chunk in the database for the new record.
|
|
recordH = (MemHandle)DmNewHandle(dbP, (UInt32) size);
|
|
if (recordH == NULL)
|
|
return dmErrMemError;
|
|
|
|
// Pack the the data into the new record.
|
|
recordP = MemHandleLock (recordH);
|
|
offset = (UInt32)&nilP->note;
|
|
DmStrCopy(recordP, offset, item->note);
|
|
|
|
MemPtrUnlock (recordP);
|
|
|
|
// Insert the record.
|
|
result = DmAttachRecord(dbP, index, recordH, 0);
|
|
if (result)
|
|
MemHandleFree(recordH);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* FUNCTION: MemoSortRecord
|
|
*
|
|
* DESCRIPTION: Move the passed record to its correct sort
|
|
* position.
|
|
*
|
|
* PARAMETERS: database pointer
|
|
* record index
|
|
*
|
|
* RETURNS: zero if successful, errorcode if not
|
|
*
|
|
* REVISION HISTORY:
|
|
* Name Date Description
|
|
* ---- ---- -----------
|
|
* art 7/18/96 Initial Revision
|
|
* gap 6/29/00 When user is in manual sort mode, the sort
|
|
* routine was exiting immediately which caused
|
|
* deleted and non-deleted records to be mixed in
|
|
* the database as opposed to having deleted records
|
|
* all appended at the end of the database. Now check
|
|
* to move record above all deleted records (in the case
|
|
* of new records) before exiting the routine when
|
|
* manual sort is selected.
|
|
*
|
|
*
|
|
*************************************************************/
|
|
Err MemoSortRecord (DmOpenRef dbP, UInt16 * indexP)
|
|
{
|
|
Err err;
|
|
Int16 sortOrder;
|
|
UInt16 index;
|
|
UInt16 attributes;
|
|
UInt32 uniqueID;
|
|
MemHandle recordH;
|
|
MemHandle h;
|
|
Boolean dontMove;
|
|
MemoDBRecordPtr cmp;
|
|
MemoDBRecordPtr recordP;
|
|
|
|
sortOrder = MemoGetSortOrder (dbP);
|
|
|
|
// Check if the record is already in the correct position.
|
|
recordP = MemHandleLock (DmQueryRecord (dbP, *indexP));
|
|
if (*indexP > 0)
|
|
{
|
|
// This record wasn't deleted and deleted records are at the end of the
|
|
// database so the prior record may not be deleted!
|
|
h = DmQueryRecord (dbP, *indexP-1);
|
|
if (! h)
|
|
dontMove = false;
|
|
else
|
|
{
|
|
if (sortOrder == soUnsorted)
|
|
dontMove = true;
|
|
else
|
|
{
|
|
cmp = MemHandleLock (h);
|
|
dontMove = (MemoCompareRecords (cmp, recordP, sortOrder, NULL, NULL, 0) < 1);
|
|
MemPtrUnlock (cmp);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
dontMove = true;
|
|
|
|
if (dontMove && (*indexP+1 < DmNumRecords (dbP)))
|
|
{
|
|
DmRecordInfo(dbP, *indexP+1, &attributes, NULL, NULL);
|
|
if ( ! (attributes & dmRecAttrDelete) )
|
|
{
|
|
cmp = MemHandleLock (DmQueryRecord (dbP, *indexP+1));
|
|
dontMove &= (MemoCompareRecords (recordP, cmp, sortOrder, NULL, NULL, 0) < 1);
|
|
MemPtrUnlock (cmp);
|
|
}
|
|
}
|
|
MemPtrUnlock (recordP);
|
|
|
|
if (dontMove) return (0);
|
|
|
|
|
|
// Since the routine that determines the records sort position uses a
|
|
// binary search algorythm we need to remove the record from the database
|
|
// before we can determine its new position. We will also save and restore the
|
|
// record's attributes and unique ID.
|
|
DmRecordInfo (dbP, *indexP, &attributes, &uniqueID, NULL);
|
|
|
|
err = DmDetachRecord (dbP, *indexP, &recordH);
|
|
if (err) return (err);
|
|
|
|
recordP = MemHandleLock (recordH);
|
|
index = DmFindSortPosition (dbP, recordP, NULL, (DmComparF *)MemoCompareRecords, sortOrder);
|
|
MemPtrUnlock (recordP);
|
|
|
|
err = DmAttachRecord (dbP, &index, recordH, 0);
|
|
if (err) return (err);
|
|
|
|
DmSetRecordInfo (dbP, index, &attributes, &uniqueID);
|
|
|
|
*indexP = index;
|
|
|
|
return (err);
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* FUNCTION: MemoGetDatabase
|
|
*
|
|
* 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/02/99 Initial Revision
|
|
*
|
|
***********************************************************************/
|
|
Err MemoGetDatabase (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 (memoDBType, sysFileCMemo, mode);
|
|
if (!dbP)
|
|
{
|
|
error = DmCreateDatabase (0, memoDBName, sysFileCMemo, memoDBType, false);
|
|
if (error)
|
|
return error;
|
|
|
|
dbP = DmOpenDatabaseByTypeCreator(memoDBType, sysFileCMemo, mode);
|
|
if (!dbP)
|
|
return (1);
|
|
|
|
// Set the backup bit. This is to aid syncs with non Palm software.
|
|
SetDBBackupBit(dbP);
|
|
|
|
error = MemoAppInfoInit (dbP);
|
|
if (error)
|
|
{
|
|
DmOpenDatabaseInfo(dbP, &dbID, NULL, NULL, &cardNo, NULL);
|
|
DmCloseDatabase(dbP);
|
|
DmDeleteDatabase(cardNo, dbID);
|
|
return error;
|
|
}
|
|
}
|
|
|
|
*dbPP = dbP;
|
|
return 0;
|
|
}
|