supermario/base/SuperMarioProj.1994-02-09/Toolbox/DataAccessMgr/DataAccessMgr.c
2019-06-29 23:17:50 +08:00

6124 lines
141 KiB
C

/*
File: DataAccessMgr.c
Contains: C routines for the Data Access Manager (codename SnarfMan).
These internal routines have parallel names to the public
routines to avoid name conflicts (e.g. DBInit is SMInit).
Written by: Jeff Miller
Copyright: © 1989-1992 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<SM2> 11/19/92 RB Set ROMMapInsert to MapTrue just before doing some GetResource
calls so that we look in ROM first.
<30> 3/13/92 JSM Renamed this file DataAccessMgr.c from SnarfMan.c, keeping all
the old revisions.
<29> 7/15/91 dba get rid of MEMERR
<28> 6/12/91 JSM Completely delete about box code, which hasn't been used since
revision 19 anyway.
<27> 10/21/90 gbm Changing .hfileInfo to .hFileInfo again to match interfaces.
<27> 10/2/90 JAL Changed .hfileInfo to .hFileInfo to match interfaces.
<26> 9/12/90 JSM Fix bug when DBGetQueryResults is called async and DBState
returns noErr.
<25> 7/22/90 JSM rcDBNull is a valid return code to get from DBGetItem in
DBGetQueryResults, don't return an error in this case.
<24> 6/4/90 DC changed divide by 2 in FindHandler to right shift 1.
<23> 4/25/90 JSM Remove SMQuitDBPack, since it's no longer implemented.
<22> 4/24/90 JSM More code size reduction: Add CallStatusProc (common code for
most status function calls), calculate resListSize once in
SMGetNewQuery.
<21> 4/23/90 JSM Save and restore current GrafPort across call to qdef in
SMStartQuery.
<20> 4/10/90 JSM Make DBGetNewQuery return more errors, don't explicitly return
resNotFound unless ResErr is noErr, change back to .hfileInfo
(thanks, Dave).
<19> 4/2/90 JSM Even more code size reduction: remove about box and other
changes far too numerous to mention.
<18> 3/28/90 JSM Code size reduction: read ResErr and MemErr directly from
lomem.
<17> 3/13/90 JSM Change names of ResultsHandler routines to ResultHandler, add
support for new status function and result handler interface,
add support for new ResultsRecord format.
<16> 3/12/90 JSM Add support for completion routine in a separate resource.
<15> 3/9/90 JAL Changed .hfileInfo to .hFileInfo to match Files.h change.
<14> 2/26/90 JSM Don't HLock and HNoPurge package, now handled by PACKHelper.
<13> 2/23/90 JSM Add support for results handlers in separate resource.
<12> 2/22/90 JSM Add kDBStartQueryComplete, fix bug where AllDoneProc was never
cleaning up.
<11> 2/20/90 JSM Don't allow NULL query on DBStartQuery.
<10> 2/6/90 JSM Change rcDBCancel and rcDBStatusCancel to userCanceledErr, add
support for new status function message
kDBGetQueryResultsComplete.
<9> 2/5/90 JSM Look for ddevs in Extensions Folder.
<8> 1/31/90 JSM Fix return code bug in DBGetConnInfo.
<7> 1/18/90 JSM Use STR# from System file in default results handlers.
<6> 1/5/90 JSM Change default results handler for text to strip off trailing
spaces.
<5> 1/4/90 JSM Change some variable names in response to suggestions from
documentation.
<4> 12/28/89 dba Use quotes around the SnarfMan.h header file name, since the
file is a local header rather than part of public Interfaces.
<3> 12/22/89 JSM Use kDBLastColFlag in DBGetQueryResults.
<2> 12/20/89 JSM Cleanup for new build system.
<2.9> 12/7/89 JSM Added support for buffering partial rows in DBGetQueryResults.
<2.8> 11/21/89 JSM Set queryList and resList handles to NIL instead of empty
handles in DBGetNewQuery if no queries or resources in 'qrsc'.
<2.7> 11/15/89 JSM Always return sessID from ddev on DBInit, fix bug where calling
DBGetQueryResults async when no results causes problems.
<2.6> 11/7/89 JSM Added status functions, changed DBUnGetVal to DBUnGetItem, keep
track of ddev folder with vRefNum and dirID.
<2.5> 11/6/89 JSM Fixed bug with return codes from DBGetConnInfo.
<2.4> 11/1/89 JSM Fixed error handling for GetResource calls.
<2.3> 10/13/89 JSM Removed hack in DBGetQueryResults processing that worked around
a bug in CL/1 5.022.
<2.2> 10/6/89 JSM Updated to make SnarfMan a PACK.
<2.1> 9/18/89 JSM General cleanup and optimizing, fixed potential problem if null
parameters were passed in on some calls.
<2.0> 8/29/89 JSM Updated for new version 2 API.
<1.9> 8/7/89 JSM Added support for colLens in ResultsRecord, and kill and
results-to-text stuff (not quite done yet).
<1.8> 7/26/89 JSM Added support for ddev flags.
<1.7> 7/19/89 JSM Changed 'type' to 'dataType' in several places.
<1.6> 7/15/89 JSM Async stuff works now.
<1.5> 6/22/89 JSM Don't build ddev list at patch time, updated SMGetRow, messed
around with async some more.
<1.4> 6/9/89 JSM Added more stuff to support async, not quite working yet.
<1.3> 5/31/89 JSM No longer checks for rcDBReady, doesn't return rcDBSize, added
async support.
<1.2> 5/18/89 JSM Now return OSErr for everything, plus numerous other changes.
<1.1> 4/28/89 JSM Added lots o' new stuff, mostly high-level calls.
<1.0> 4/11/89 JSM Added to EASE for the first time.
*/
/* include our private header */
#include "DatabaseAccessPriv.h"
#include <SysEqu.h>
// #define DODPRINTF
/* I M P O R T S */
snarfGlobPtr GetGlobals();
snarfGlobPtr* GetGlobalsPtr();
void mymemclear(char *s, long size);
void CallCompletion(DBAsyncParmBlkPtr asyncPB);
/* E X P O R T S */
pascal OSErr SMInitDBPack(short version);
OSErr InstallDefaultHandlers(snarfGlobPtr glob);
pascal OSErr SMIdle();
OSErr SMOpen(ddevElemHndl ddevH);
OSErr SMClose(ddevElemHndl ddevH);
pascal OSErr SMInit(long *sessID, const Str63 ddevName, const Str255 host,
const Str255 user, const Str255 password, const Str255 connStr,
DBAsyncParmBlkPtr asyncPB);
pascal void SMInitComplete(ddevElemHndl ddevH, long *sessIDPtr,
long sessID, Boolean firstsess);
pascal OSErr SMEnd(long sessID, DBAsyncParmBlkPtr asyncPB);
OSErr SMEndComplete(snarfSessElemHndl snarf);
pascal OSErr SMGetConnInfo(long sessID, short sessNum, long *returnedID,
long *version, Str63 ddevName, Str255 host, Str255 user,
Str255 network, Str255 connStr, long *start, OSErr *state,
DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMGetSessionNum(long sessID, short *sessNum, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMSend(long sessID, char *text, short len, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMSendItem(long sessID, DBType dataType, short len, short places,
short flags, Ptr buffer, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMExec(long sessID, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMState(long sessID, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMGetErr(long sessID, long *err1, long *err2, Str255 item1,
Str255 item2, Str255 errorMsg, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMBreak(long sessID, Boolean abort, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMGetItem(long sessID, long timeout, DBType *dataType, short *len,
short *places, short *flags, Ptr buffer, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMUnGetItem(long sessID, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMGetNewQuery(short queryID, QueryHandle *query);
pascal OSErr SMDisposeQuery(QueryHandle query);
pascal OSErr SMStartQuery(long *sessID, QueryHandle query, statusPtr statusProc,
DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMGetQueryResults(long sessID, ResultsRecord *results,
long timeout, statusPtr statusProc, DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMKill(DBAsyncParmBlkPtr asyncPB);
pascal OSErr SMResultsToText(ResultsRecord *results, Handle *theText);
HandlerPtr GetCorrectResultHandler(DBType dataType);
pascal OSErr SMInstallResultHandler(DBType dataType, ProcPtr theHandler,
Boolean isSysHandler);
pascal OSErr SMRemoveResultHandler(DBType dataType);
pascal OSErr SMGetResultHandler(DBType dataType, ProcPtr *theHandler,
Boolean getSysHandler);
short FindHandler(DBType dataType);
OSErr InsertHandler(HandlerRecord *newRec);
OSErr RemoveHandler(short index);
OSErr SMGeneric(long snarfID, DBAsyncParmBlkPtr asyncPB,
DDEVParams *params);
OSErr InitDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
OSErr SendDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
OSErr ExecDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
OSErr StateDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
OSErr GetItemDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
OSErr AllDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars);
void BuildDDEVList(ddevElemHndl *root);
void ClearDDEVList(ddevElemHndl root);
void PurgeDDEVList(ddevElemHndl *root);
void AddDDEVFile(const Str255 fname, short vRefNum, long dirID,
ddevElemHndl *root);
ddevElemHndl FindAndBuildDDEV(char *name, ddevElemHndl *rootPtr);
ddevElemHndl FindDDEV(char *name, ddevElemHndl root);
OSErr OpenDDEVFile(ddevElemHndl ddevH, short *refNum);
OSErr CallDDEV(ddevElemHndl ddevH, DDEVParams *params);
long GetUniqueSnarfID(snarfSessElemHndl root);
snarfSessElemHndl FindSnarfID(long id, snarfSessElemHndl root);
long ConvertSessIDToSnarfID(long sessID, ddevElemHndl ddevH);
void InsertSessionCell(sessElemHndl *root, sessElemHndl cell);
void InsertSnarfCell(snarfSessElemHndl *root, snarfSessElemHndl cell);
DBAsyncParmBlkPtr MakePB(DDEVParamsPtr params, DBAsyncParmBlkPtr asyncPB);
pascal void InsertPB(DBAsyncParmBlkPtr asyncPB);
pascal void RemovePB(DBAsyncParmBlkPtr asyncPB);
DBAsyncParmBlkPtr FindAppPB(DBAsyncParmBlkPtr appPB);
void GetDDEVFolder(short *vRefNum, long *dirID);
OSErr GrowResultsRecord(ResultsRecord *results, short len,
Boolean inFirstRow);
OSErr SetupResults(long sessID, snarfSessElemHndl *snarfPtr,
ResultsRecord *results, ResultsRecord **oldResultsPtr,
long *currOffset, short *currCol);
pascal void DisposeResultsRecord(ResultsRecord *results);
OSErr InitResultsRecord(ResultsRecord *results, Boolean inSysHeap);
OSErr CallStatusProc(statusPtr statusProc, short message, OSErr rc);
pascal void MyHLock(Handle h, char *state);
/*FORM_FEED*/
/*
*
* OBJECT: SMInitDBPack
*
* DESCRIPTION: Called to initialize SnarfMan by each application. The version
* number is implicitly passed in by the routine definition in
* DatabaseAccess.h. This number is compared to the version in the
* PACK resource. The first time this routine is called, it
* allocates space for globals and installs default result handlers.
*
* INPUTS: version: Version as defined in DatabaseAccess.h.
*
* OUTPUTS: None.
*
* RETURNS: rcDBWrongVersion
* Errors from NewPtrSysClear and InstallDefaultHandlers.
*
* MODIFICATIONS:
* 10-03-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMInitDBPack(short version)
{
register snarfGlobPtr *globPtr;
register snarfGlobPtr glob;
register short rc;
Handle resH;
PackHeaderHndl thePack;
/* compare version numbers */
thePack = DataAccessMgrPack;
if ((**thePack).version != version)
return(rcDBWrongVersion);
/*
For now, we always stay locked down.
Hopefully, we'll be more intelligent about this in
the future.
We no longer need to do this, PACKHelper takes care of it!
*/
// HNoPurge((Handle)thePack);
// HLock((Handle)thePack);
/* see if we need to allocate globals */
globPtr = GetGlobalsPtr();
rc = noErr;
if (*globPtr == NULL)
{
/* allocate a cleared pointer in the system heap for globals */
*globPtr = (snarfGlobPtr)NewPtrSysClear(sizeof(snarfGlob));
rc = MemError();
if (rc == noErr)
{
glob = *globPtr;
/* build the list of installed ddevs */
/*
It turns out we can't do this at patch time because there is
no International Utilities package available yet (AddDDEVFile
calls IUCompStr). So, it gets done at the first DBInit call.
BuildDDEVList(&((*globPtr)->ddevRoot));
*/
/*
Load the standard completion routine.
We have to keep this separate so it doesn't
get unlocked and/or purged at the wrong
time by PACKHelper.
*/
*((short*) RomMapInsert) = mapTrue;
resH = GetResource(COMPCODERESTYPE, COMPCODERESID);
if (resH != NULL)
{
/* detach it */
DetachResource(resH);
/* resource should have locked bit set */
/* save this handle in the globals */
/* we may purge this someday */
glob->completionRes = resH;
}
else
{
/* couldn't get specified 'proc' resource */
if ((rc = RESERR) == noErr)
rc = resNotFound;
/* we better not continue, so get rid of the globals */
DisposPtr((Ptr)glob);
*globPtr = NULL;
}
if (rc == noErr)
{
/* install default result handlers */
rc = InstallDefaultHandlers(glob);
/* even if this fails, it isn't a fatal error, so leave globals around */
}
}
}
return(rc);
} /* SMInitDBPack() */
/*FORM_FEED*/
/*
*
* OBJECT: InstallDefaultHandlers
*
* DESCRIPTION: Called by SMInitDBPack to install the default system result handlers.
* Reads the 'rtt#' resource and 'proc' resource containing the handlers,
* then calls DBInstallResultHandler for each one.
*
* INPUTS: glob: Pointer to globals.
*
* OUTPUTS: None.
*
* RETURNS: resNotFound
* Errors from NewHandleSys and DBInstallResultHandler.
*
* MODIFICATIONS:
* 03-29-90 JSM - Created.
*
* Copyright Apple Computer, Inc. 1990
* All rights reserved.
*
*/
OSErr
InstallDefaultHandlers(snarfGlobPtr glob)
{
register OSErr rc;
register Handle resH;
register Ptr resP;
register short numTypes;
register short handlerID;
Handle handlerH;
ProcPtr p;
/* short numHandlers; */
/* allocate empty array of result handlers */
glob->handlers = (HandlerRecordHandle)NewHandleSys(NULL);
rc = MemError();
/*
Install the default handlers.
These live in a separate 'proc' resource so it can stay locked
down in one place all the time. The 'rtt#' resource specifies
which handlers we have. It looks like:
short numHandlers; number of 'proc' resources
we only support one now
For each 'proc':
short id; id of 'proc'
short numTypes; number of types handled by this 'proc'
DBType typeArray[numTypes]; types handled by this 'proc'
*/
if (rc == noErr)
{
/* get the 'rtt#' */
*((short*) RomMapInsert) = mapTrue;
resH = GetResource(RTTLISTRESTYPE, RTTLISTID);
if (resH != NULL)
{
HLock(resH);
resP = *resH;
/* get number of 'proc' resources */
/* we support one and only one for now */
/* numHandlers = *((short*)resP); */
resP += sizeof(short);
/* get the id of this 'proc' */
handlerID = *((short*)resP);
resP += sizeof(short);
/* get number of types supported by this 'proc' */
numTypes = *((short*)resP);
resP += sizeof(short);
/* load in 'proc' */
*((short*) RomMapInsert) = mapTrue;
handlerH = GetResource(RTTCODERESTYPE, handlerID);
if (handlerH != NULL)
{
/* detach it */
DetachResource(handlerH);
/* resource should have locked bit set */
/* save this handle in the globals */
/* we may purge this someday */
glob->handlerRes = handlerH;
/* make sure we're 32 bit clean */
p = (ProcPtr)StripAddress(*handlerH);
/* now, install it as a result handler for specified types */
while((numTypes != 0) && (rc == noErr))
{
/* install handler for current type */
rc = DBInstallResultHandler(*((DBType*)resP), p, true);
resP += sizeof(DBType);
numTypes--;
}
}
else
{
/* couldn't get specified 'proc' resource */
if ((rc = RESERR) == noErr)
rc = resNotFound;
}
/* get rid of 'rtt#' (no need to unlock it) */
ReleaseResource(resH);
}
/* we could put an else here if 'rtt#' resource not found, but it's not a fatal error */
}
return(rc);
} /* InstallDefaultHandlers() */
/*FORM_FEED*/
/*
*
* OBJECT: SMIdle
*
* DESCRIPTION: Called every time SystemTask called. Sends DBIdle message to any
* ddev with active sessions. Also checks global list of asynchronous
* parameter blocks to see if it needs to perform a task that cannot be
* done at interrupt time.
*
* INPUTS: None.
*
* OUTPUTS: None.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 04-05-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMIdle()
{
register ddevElemHndl ddevH;
register DBAsyncParmBlkPtr myPB;
register asyncVarsPtr myVars;
register short rc;
snarfGlobPtr glob;
DBAsyncParmBlkPtr appPB, nextPB;
DDEVParams params;
glob = GetGlobals();
/* get first ddev in list */
ddevH = glob->ddevRoot;
/****************************************/
/* send idle messages to all open ddevs */
/****************************************/
while (ddevH != NULL)
{
/* see if this ddev has any open sessions */
if ((**ddevH).sessRoot != NULL)
{
/* yes, send it an idle message */
/* fill in parameter block for DBIdle */
ClearParams(params);
params.message = kDBIdle;
/* ignore any errors */
(void)CallDDEV(ddevH, &params);
}
/* get next ddev in list */
ddevH = (**ddevH).next;
}
/***************************************/
/* go through list of parameter blocks */
/***************************************/
myPB = glob->pbRoot;
while (myPB != NULL)
{
myVars = (asyncVarsPtr)myPB->reserved;
/* get next pb here in case we dispose of the current one */
nextPB = myVars->next;
if (!(myVars->executing))
{
/* current pb is done executing */
if (!myVars->highlevel)
{
/********************************/
/* low-level call has completed */
/********************************/
/* have to return parameters and do additional
cleanup for some calls */
switch (myVars->currAction)
{
case kDBInit:
/* finish up using common code */
SMInitComplete(myVars->ddevH, myVars->sessIDPtr,
myVars->params->sessID, myVars->firstsess);
break;
case kDBEnd:
if (myPB->result == noErr)
{
/* session ended OK */
/* finish up using common code */
myPB->result = SMEndComplete(myVars->snarf);
}
break;
case kDBGetConnInfo:
/* return returnedID, version, start, and state */
/*
Note that the returnedID in the DDEVParams is the
ddev's session ID, which we have to convert
to a global Snarf ID.
*/
if (myVars->returnedIDPtr != NULL)
{
if (myPB->result == noErr) /* fix for bug DSL-008 */
{
/* ddev thinks it returned a valid session ID */
*(myVars->returnedIDPtr) =
ConvertSessIDToSnarfID(myVars->params->returnedID,
myVars->ddevH);
if (*(myVars->returnedIDPtr) == NULL)
{
/*
The session ID returned by the ddev does
not match any of the active sessions we
have for it. Hopefully, this should
never happen.
*/
myPB->result = rcDBBadSessID;
}
}
}
if (myVars->versionPtr != NULL)
{
*(myVars->versionPtr) = myVars->params->version;
}
if (myVars->startPtr != NULL)
{
*(myVars->startPtr) = myVars->params->start;
}
if (myVars->statePtr != NULL)
{
*(myVars->statePtr) = myVars->params->state;
}
break;
case kDBGetSessionNum:
/* return sessNum */
*(myVars->sessNumPtr) = myVars->params->sessNum;
break;
case kDBGetErr:
/* return err1 and err2 */
if (myVars->err1Ptr != NULL)
{
*(myVars->err1Ptr) = myVars->params->err1;
}
if (myVars->err2Ptr != NULL)
{
*(myVars->err2Ptr) = myVars->params->err2;
}
break;
case kDBGetItem:
/* return dataType, len, places, and flags */
if (myVars->dataTypePtr != NULL)
{
*(myVars->dataTypePtr) = myVars->params->dataType;
}
if (myVars->lenPtr != NULL)
{
*(myVars->lenPtr) = myVars->params->len;
}
if (myVars->placesPtr != NULL)
{
*(myVars->placesPtr) = myVars->params->places;
}
if (myVars->flagsPtr != NULL)
{
*(myVars->flagsPtr) = myVars->params->flags;
}
break;
}
/* copy result into application's parameter block */
appPB = myVars->asyncPB;
appPB->result = myPB->result;
/* remove pb from list */
RemovePB(myPB);
/* call application's completion routine, if any */
if (appPB->completionProc != NULL)
{
/* have to use assembly glue to get pb into A0 */
CallCompletion(appPB);
}
}
else
{
/***********************************************************/
/* high-level call has completed, call appropriate routine */
/***********************************************************/
switch (myVars->currAction)
{
/* DBStartQuery actions */
case kDBInit:
rc = InitDoneProc(myPB, myVars);
break;
case kDBSend:
rc = SendDoneProc(myPB, myVars);
break;
case kDBExec:
rc = ExecDoneProc(myPB, myVars);
/* always go to done from here */
rc = AllDoneProc(myPB, myVars);
break;
/* DBGetQueryResults actions */
case kDBState:
rc = StateDoneProc(myPB, myVars);
break;
case kDBGetItem:
rc = GetItemDoneProc(myPB, myVars);
break;
/* all processing complete */
/* this is only from GetItemDoneProc */
case kAllDone:
/* let AllDoneProc know what to clean up */
myVars->currAction = kDBGetItem;
rc = AllDoneProc(myPB, myVars);
break;
} /* switch (myVars->currAction) */
if (rc != noErr)
{
/* error occurred someplace, so we're done */
(void)AllDoneProc(myPB, myVars);
}
} /* if (!myVars->highlevel) */
} /* if (!(myVars->executing)) */
myPB = nextPB;
} /* while (myPB != NULL) */
return(noErr);
} /* SMIdle() */
/*FORM_FEED*/
/*
*
* OBJECT: SMOpen
*
* DESCRIPTION: Called to send a DBOpen to ddev when first session is initiated.
* This is always a synchronous call. Opens file, gets and detaches
* resource, calls ddev, and closes file.
*
* INPUTS: ddevH: Handle to ddevElem with info.
*
* OUTPUTS: None.
*
* RETURNS: Errors from opening resource file, getting ddev resource,
* detaching ddev resource, and CallDDEV.
*
* MODIFICATIONS:
* 05-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SMOpen(ddevElemHndl ddevH)
{
register DDEVPtr *ddevRes;
register OSErr rc;
register short currResFile;
short currVol, refNum = -1;
short vRefNum;
long dirID;
DDEVParams params;
WDPBRec pb;
/* save current file */
currResFile = CURMAP;
/* open ddev file */
rc = OpenDDEVFile(ddevH, &refNum);
if (rc == noErr)
{
/* file open, get the resource */
ddevRes = (DDEVPtr*)Get1Resource(DDEVRESTYPE, kDDEVID);
if (ddevRes != NULL)
{
/* detach ddev resource */
DetachResource((Handle)ddevRes);
rc = RESERR;
}
else
{
/* couldn't get ddev */
/* note that GetResource does not set ResErr for resNotFound! */
if ((rc = RESERR) == noErr)
rc = resNotFound;
}
if (rc == noErr)
{
/* lock down ddev code always */
HLock((Handle)ddevRes);
/* save handle to ddev in ddevH */
(**ddevH).ddev = ddevRes;
/* save old volume and set to ddev's volume */
(void)GetVol(NULL, &currVol);
/********************************************/
/* •WARNING• •WARNING• •WARNING• •WARNING• */
/* */
/* The following is kind of bogus, but it */
/* is probably better than doing an HSetVol.*/
/* We need a working directory, though, to */
/* do a normal SetVol. Darin suggested not */
/* closing it when we're done. */
/* */
/* •WARNING• •WARNING• •WARNING• •WARNING• */
/********************************************/
/* get vRefNum and dirID of ddev folder */
GetDDEVFolder(&vRefNum, &dirID);
/* open a working directory */
pb.ioCompletion = 0L;
pb.ioNamePtr = 0L;
pb.ioVRefNum = vRefNum;
pb.ioWDDirID = dirID;
pb.ioWDProcID = 'ERIK'; /* Darin says use this */
rc = PBOpenWD(&pb, false);
if (rc == noErr)
{
/* opened working directory */
(void)SetVol(NULL, pb.ioVRefNum);
/* set up parameters for open */
ClearParams(params);
params.message = kDBOpen;
/* call ddev - DBOpen */
rc = CallDDEV(ddevH, &params);
/* restore current volume */
(void)SetVol(NULL, currVol);
}
}
if ((rc != noErr) && (ddevRes != NULL))
{
/* error opening ddev, dispose of everything */
/* dispose of ddev code (no need to unlock it) */
DisposHandle((Handle)ddevRes);
(**ddevH).ddev = NULL;
/* no more storage */
(**ddevH).ddevStorage = NULL;
}
}
/* clean up */
if (refNum != -1)
CloseResFile(refNum);
UseResFile(currResFile);
return(rc);
} /* SMOpen() */
/*FORM_FEED*/
/*
*
* OBJECT: SMClose
*
* DESCRIPTION: Called to send a DBClose to ddev when last session has ended.
* Disposes of ddev code. This is always a synchronous call.
*
* INPUTS: ddevH: Handle to ddevElem with info.
*
* OUTPUTS: None.
*
* RETURNS: Return codes from CallDDEV, DisposHandle.
*
* MODIFICATIONS:
* 05-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SMClose(ddevElemHndl ddevH)
{
register short rc;
DDEVParams params;
ClearParams(params);
params.message = kDBClose;
/* call ddev - DBClose */
rc = CallDDEV(ddevH, &params);
/* dispose of ddev code (no need to unlock it) */
DisposHandle((Handle)(**ddevH).ddev);
(**ddevH).ddev = NULL;
/* no more storage */
(**ddevH).ddevStorage = NULL;
/* report errors from DBClose first before MemError */
if (rc == noErr)
{
/* DBClose OK, so report any error from DisposHandle */
rc = MemError();
}
return(rc);
} /* SMClose() */
/*FORM_FEED*/
/*
*
* OBJECT: SMInit
*
* DESCRIPTION: DBInit routine. Searches for specified ddev, opens it if
* this is the first session for it (sending it a DBOpen message),
* sends it a DBInit message, and calls common code which inserts a
* new session and snarf id into the session and snarf id lists.
*
* INPUTS: sessID: Pointer to variable for session ID.
* ddevName: Corresponds to 'STR ' 128 in ddev.
* host: Host name.
* user: User name.
* passwd: Password.
* connStr: Connection string.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: sessID: Pointer to filled in session ID.
*
* RETURNS: rcDBBadDDEV
* rcDBAsyncNotSupp
* Errors from SMOpen and CallDDEV.
*
* MODIFICATIONS:
* 03-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMInit(long *sessID, const Str63 ddevName, const Str255 host,
const Str255 user, const Str255 password, const Str255 connStr, DBAsyncParmBlkPtr asyncPB)
{
register ddevElemHndl ddevH;
register asyncVarsPtr myVars;
register OSErr rc = noErr;
register Boolean firstsess;
snarfGlobPtr glob;
DBAsyncParmBlkPtr myPB;
DDEVParams params;
/* assume no session will come up */
*sessID = 0;
glob = GetGlobals();
/* look for ddevElem with specified ddevName, rebuilding list if necessary */
ddevH = FindAndBuildDDEV((char*)ddevName, &(glob->ddevRoot));
if (ddevH == NULL)
{
/* bad ddev name */
rc = rcDBBadDDEV;
}
if (rc == noErr)
{
/* see if ddev code loaded, if not, then it needs a DBOpen call */
firstsess = ((**ddevH).ddev == NULL);
if (firstsess)
{
/* special case - check for async here so we don't send open */
if (asyncPB && !(**ddevH).canAsync)
{
/* ddev doesn't support async, but DBInit called async */
rc = rcDBAsyncNotSupp;
}
if (rc == noErr)
{
/* call ddev with open message */
rc = SMOpen(ddevH);
}
}
if (rc == noErr)
{
/* fill in parameter block for DBInit */
ClearParams(params);
params.message = kDBInit;
params.host = host;
params.user = user;
params.password = password;
params.connStr = connStr;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track if first session for ddev */
myVars->firstsess = firstsess;
/* keep track of session ID */
myVars->sessIDPtr = sessID;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
return(CallDDEV(ddevH, myVars->params));
}
/* call ddev synchronously - DBInit */
rc = CallDDEV(ddevH, &params);
/* finish up using common code */
SMInitComplete(ddevH, sessID, params.sessID, firstsess);
}
}
return(rc);
} /* SMInit() */
/*FORM_FEED*/
/*
*
* OBJECT: SMInitComplete
*
* DESCRIPTION: Called after a synchronous or asynchronous DBInit call completes.
* Allows code sharing. If DBInit returned a session ID, inserts a
* new session and snarf id into the session and snarf id lists.
*
* Declared as a pascal function because compiler generates smaller code.
*
* INPUTS: ddevH: Handle to ddev called.
* sessIDPtr: Pointer to return session ID.
* sessID: Session ID returned by ddev.
* firstsess: If TRUE, this is the first session for this ddev.
*
* OUTPUTS: sessIDPtr: Pointer to filled in session ID.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 09-07-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal void
SMInitComplete(ddevElemHndl ddevH, long *sessIDPtr, long sessID,
Boolean firstsess)
{
register long snarfID;
snarfGlobPtr glob;
sessElem **sess;
snarfSessElem **snarf;
char currState;
/*
Note that we can't depend on the rc from the ddev
to determine if a session is up. CL/1, for example,
will always return a session ID, even if an error occurs.
*/
if (sessID == 0)
{
/* ddev didn't return a session ID, so definitely no session */
if (firstsess)
{
/* first session for this ddev, so close it */
(void)SMClose(ddevH);
}
}
else
{
/* ddev returned a session ID, but there may still be an error */
/* set up cell for session */
sess = (sessElemHndl)NewHandleSysClear(sizeof(sessElem));
(**sess).parent = ddevH;
(**sess).sessID = sessID;
/* insert it into the list of sessions for this ddev */
MyHLock((Handle)ddevH, &currState);
InsertSessionCell(&((**ddevH).sessRoot), sess);
HSetState((Handle)ddevH, currState);
/* find a unique snarf session ID for this session */
glob = GetGlobals();
snarfID = GetUniqueSnarfID(glob->snarfRoot);
/* set up snarf cell */
snarf = (snarfSessElemHndl)NewHandleSysClear(sizeof(snarfSessElem));
(**snarf).snarfID = snarfID;
/* (**snarf).processID = ?; */
(**snarf).sess = sess;
/* insert it into the global list of sessions */
InsertSnarfCell(&(glob->snarfRoot), snarf);
/* return the ID */
*sessIDPtr = snarfID;
}
} /* SMInitComplete() */
/*FORM_FEED*/
/*
*
* OBJECT: SMEnd
*
* DESCRIPTION: DBEnd routine. Calls DBEnd and, if successful, calls common code
* which removes session id and snarf id from the lists, and, if the
* last session for this ddev was just ended, calls SMClose to send
* the ddev a DBClose message.
*
* INPUTS: sessID: Session ID.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric and SMEndComplete.
*
* MODIFICATIONS:
* 03-26-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMEnd(long sessID, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
snarfGlobPtr glob;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
glob = GetGlobals();
/* fill in parameter block for DBEnd */
ClearParams(params);
params.message = kDBEnd;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of snarf session cell */
myVars->snarf = FindSnarfID(sessID, glob->snarfRoot);
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBEnd */
if ((rc = SMGeneric(sessID, NULL, &params)) == noErr)
{
/* session ended OK, clean up lists */
/* finish up using common code */
rc = SMEndComplete(FindSnarfID(sessID, glob->snarfRoot));
}
}
return(rc);
} /* SMEnd() */
/*FORM_FEED*/
/*
*
* OBJECT: SMEndComplete
*
* DESCRIPTION: Called after a synchronous or asynchronous DBEnd call completes.
* Allows code sharing. This routine should only be called if DBEnd
* was successful. Removes session id and snarf id from the lists,
* and, if the last session for this ddev was just ended, calls
* SMClose to send the ddev a DBClose message.
*
* INPUTS: snarf: Snarf session cell that was just ended.
*
* OUTPUTS: None.
*
* RETURNS: Return codes from SMClose.
*
* MODIFICATIONS:
* 09-09-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SMEndComplete(snarfSessElemHndl snarf)
{
register short rc = noErr;
snarfGlobPtr glob;
ddevElemHndl ddevH;
ddevElemPtr ddevP;
snarfSessElemHndl prevsnarf;
sessElemHndl sess, prevsess;
ResultsRecord *oldResults;
char currState;
glob = GetGlobals();
/* delete any leftover results */
if ((oldResults = (**snarf).oldResults) != NULL)
{
DisposeResultsRecord(oldResults);
DisposPtr((Ptr)oldResults);
}
/* get session and ddev info */
sess = (**snarf).sess;
ddevH = (**sess).parent;
MyHLock((Handle)ddevH, &currState);
ddevP = *ddevH;
/* delete snarf element */
if (snarf == glob->snarfRoot)
{
/* deleting root */
glob->snarfRoot = (**snarf).next;
}
else
{
/* find previous snarf element */
prevsnarf = glob->snarfRoot;
while ((**prevsnarf).next != snarf)
{
prevsnarf = (**prevsnarf).next;
}
/* fix list */
(**prevsnarf).next = (**snarf).next;
}
DisposHandle((Handle)snarf);
/* delete session element */
if (sess == ddevP->sessRoot)
{
/* deleting root */
ddevP->sessRoot = (**sess).next;
}
else
{
/* find previous sess element */
prevsess = ddevP->sessRoot;
while ((**prevsess).next != sess)
{
prevsess = (**prevsess).next;
}
/* fix list */
(**prevsess).next = (**sess).next;
}
DisposHandle((Handle)sess);
/* finally, check if last session for this ddev was just ended */
if (ddevP->sessRoot == NULL)
{
/* yes, need to send close message and close ddev */
rc = SMClose(ddevH);
}
HSetState((Handle)ddevH, currState);
return(rc);
} /* SMEndComplete() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetConnInfo
*
* DESCRIPTION: DBGetConnInfo routine. If sessID is specified, returns
* ddevName. Otherwise, tries to find ddev with specified
* name. After call is made, if sessID is specified, just
* returns it in returnedID, otherwise converts session ID
* returned by ddev to Snarf ID.
*
* INPUTS: sessID: Session ID. If NULL, sessNum and ddevName must
* be specified.
* sessNum: Session number. Only used if sessID is NULL.
* returnedID: Pointer to variable for returned session ID.
* version: Pointer to variable for version.
* ddevName: Name of ddev. Only used if sessID is NULL.
* host: Pointer to variable for host (optional).
* user: Pointer to variable for user (optional).
* network: Pointer to variable for network (optional).
* connStr: Pointer to variable for connStr (optional).
* start: Pointer to variable for start time (optional).
* state: Pointer to variable for state (optional).
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: returnedID: Pointer to filled in returned session ID.
* version: Pointer to filled in version.
* ddevName: Name of ddev. Only set if sessID is NULL.
* host: Pointer to filled in host.
* user: Pointer to filled in user.
* network: Pointer to filled in network.
* connStr: Pointer to filled in connStr.
* start: Pointer to filled in start time.
* state: Pointer to filled in state.
*
* RETURNS: rcDBBadDDEV
* rcDBBadSessID
* rcDBBadSessNum
* Errors from CallDDEV and SMGeneric.
*
* MODIFICATIONS:
* 08-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetConnInfo(long sessID, short sessNum, long *returnedID, long *version,
Str63 ddevName, Str255 host, Str255 user, Str255 network, Str255 connStr,
long *start, OSErr *state, DBAsyncParmBlkPtr asyncPB)
{
register short rc = noErr;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
snarfGlobPtr glob;
ddevElemHndl ddevH;
snarfSessElemHndl snarf;
sessElemHndl sess;
char *theName;
Boolean isSessNumCall;
DDEVParams params;
glob = GetGlobals();
/* special case - if session ID is specified, need to return ddev name */
if (sessID != 0)
{
/* not being called based on session number */
isSessNumCall = false;
/* find snarf ID */
if ((snarf = FindSnarfID(sessID, glob->snarfRoot)) == NULL)
{
/* bad session ID */
rc = rcDBBadSessID;
}
else
{
/* got snarf ID, get session and ddev info */
sess = (**snarf).sess;
ddevH = (**sess).parent;
/* get pointer to ddev name */
theName = (**ddevH).name;
/* return ddev name */
if (ddevName != NULL)
pstrcpy(ddevName, theName);
}
}
else
{
/* session ID not specifed, need to use sessNum and ddevName */
isSessNumCall = true;
/* assume failure */
rc = rcDBBadDDEV; /* fix for bug DSL-008 */
/* look for ddevElem with specified ddevName, rebuilding list if necessary */
ddevH = FindAndBuildDDEV((char*)ddevName, &(glob->ddevRoot));
if (ddevH != NULL)
{
/* found ddev, see if it is loaded */
if ((**ddevH).ddev != NULL)
{
/* yes, we can call it */
rc = noErr;
}
else
{
/* ddev in list, but not loaded */
rc = rcDBBadSessNum; /* fix for bug DSL-012 */
}
}
/* else the ddev doesn't exist, so rcDBBadDDEV is the right error */
}
if (rc == noErr)
{
/* fill in parameter block for DBGetConnInfo */
ClearParams(params);
params.message = kDBGetConnInfo;
params.sessNum = sessNum;
params.host = host;
params.user = user;
params.network = network;
params.connStr = connStr;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of returnedID, version, start, and state pointers */
myVars->returnedIDPtr = returnedID;
myVars->versionPtr = version;
myVars->startPtr = start;
myVars->statePtr = state;
/* set current action */
myVars->currAction = params.message;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
if (isSessNumCall)
{
/* no sessID, have to CallDDEV ourselves */
rc = CallDDEV(ddevH, myVars->params);
}
else
{
rc = SMGeneric(sessID, myPB, myVars->params);
}
}
else
{
/* call ddev synchronously - DBGetConnInfo */
if (isSessNumCall)
{
/* no sessID, have to CallDDEV ourselves */
rc = CallDDEV(ddevH, &params);
}
else
{
rc = SMGeneric(sessID, NULL, &params);
}
/* see if we can return other parameters */
if (isSessNumCall || (rc != rcDBBadSessID))
{
/* ddev was invoked */
if (returnedID != NULL)
{
/*
Note that the returnedID in the DDEVParams is the
ddev's session ID, which we have to convert
to a global Snarf ID.
*/
if (rc == noErr) /* fix for bug DSL-008 */
{
/* ddev thinks it returned a valid session ID */
*returnedID = ConvertSessIDToSnarfID(params.returnedID, ddevH);
if (*returnedID == NULL)
{
/*
The session ID returned by the ddev does
not match any of the active sessions we
have for it. Hopefully, this should
never happen.
*/
rc = rcDBBadSessID;
}
}
}
/* return version, start, and state */
if (version != NULL)
{
*version = params.version;
}
if (start != NULL)
{
*start = params.start;
}
if (state != NULL)
{
*state = params.state;
}
}
}
}
return(rc);
} /* SMGetConnInfo() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetSessionNum
*
* DESCRIPTION: DBGetSessionNum routine. Calls DBGetSessionNum with specified
* parameters.
*
* INPUTS: sessID: Session ID.
* sessNum: Pointer to variable for session number.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: sessNum: Pointer to filled in session number.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 08-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetSessionNum(long sessID, short *sessNum, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBGetErr */
ClearParams(params);
params.message = kDBGetSessionNum;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of session number pointer */
myVars->sessNumPtr = sessNum;
/* set current action */
myVars->currAction = params.message;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBGetSessionNum */
rc = SMGeneric(sessID, NULL, &params);
/* see if we can return other parameters */
if (rc != rcDBBadSessID)
{
/* ddev was invoked */
/* return sessNum */
*sessNum = params.sessNum;
}
}
return(rc);
} /* SMGetSessionNum() */
/*FORM_FEED*/
/*
*
* OBJECT: SMSend
*
* DESCRIPTION: DBSend routine. Calls DBSend with specified parameters.
*
* INPUTS: sessID: Session ID.
* text: Pointer to text to send.
* len: Length of text.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMSend(long sessID, char *text, short len, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBSend */
ClearParams(params);
params.message = kDBSend;
params.buffer = text;
params.len = len;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBSend */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMSend() */
/*FORM_FEED*/
/*
*
* OBJECT: SMSendItem
*
* DESCRIPTION: DBSendItem routine. Calls DBSendItem with specified parameters.
*
* INPUTS: sessID: Session ID.
* dataType: Type of data to send.
* len: Length of data.
* places: Places in data.
* flags: Flags for data.
* buffer: Pointer to data to send.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 08-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMSendItem(long sessID, DBType dataType, short len, short places, short flags,
Ptr buffer, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBGetItem */
ClearParams(params);
params.message = kDBSendItem;
params.buffer = buffer;
params.dataType = dataType;
params.len = len;
params.places = places;
params.flags = flags;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBSendItem */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMSendItem() */
/*FORM_FEED*/
/*
*
* OBJECT: SMExec
*
* DESCRIPTION: DBExec routine. Calls DBExec with specified parameters.
*
* INPUTS: sessID: Session ID.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMExec(long sessID, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBExec */
ClearParams(params);
params.message = kDBExec;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBExec */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMExec() */
/*FORM_FEED*/
/*
*
* OBJECT: SMState
*
* DESCRIPTION: DBState routine. Calls DBState with specified parameters.
*
* INPUTS: sessID: Session ID.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMState(long sessID, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBState */
ClearParams(params);
params.message = kDBState;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBState */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMState() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetErr
*
* DESCRIPTION: DBGetErr routine. Calls DBGetErr with specified parameters.
*
* INPUTS: sessID: Session ID.
* err1: Pointer to error 1 (optional).
* err2: Pointer to error 2 (optional).
* item1: Pointer to item1.
* item2: Pointer to item2.
* errorMsg: Pointer to errorMsg.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: err1: Modified.
* err2: Modified.
* item1: Modified.
* item2: Modified.
* errorMsg: Modified.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetErr(long sessID, long *err1, long *err2, Str255 item1,
Str255 item2, Str255 errorMsg, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBGetErr */
ClearParams(params);
params.message = kDBGetErr;
params.item1 = item1;
params.item2 = item2;
params.errorMsg = errorMsg;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of error pointers */
myVars->err1Ptr = err1;
myVars->err2Ptr = err2;
/* set current action */
myVars->currAction = params.message;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBGetErr */
rc = SMGeneric(sessID, NULL, &params);
/* see if we can return other parameters */
if (rc != rcDBBadSessID)
{
/* ddev was invoked */
/* return err1 and err2 */
if (err1 != NULL)
{
*err1 = params.err1;
}
if (err2 != NULL)
{
*err2 = params.err2;
}
}
}
return(rc);
} /* SMGetErr() */
/*FORM_FEED*/
/*
*
* OBJECT: SMBreak
*
* DESCRIPTION: DBBreak routine. Calls DBBreak with specified parameters.
*
* INPUTS: sessID: Session ID.
* abort: How to break.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMBreak(long sessID, Boolean abort, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBBreak */
ClearParams(params);
params.message = kDBBreak;
params.abort = abort;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBBreak */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMBreak() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetItem
*
* DESCRIPTION: DBGetItem routine. Calls DBGetItem with specified parameters.
*
* INPUTS: sessID: Session ID.
* timeout: How long to wait for data to be available.
* dataType: Pointer to variable with type of data expected (optional).
* len: Pointer to variable for length (optional).
* places: Pointer to variable for places (optional).
* flags: Pointer to variable for flags (optional).
* buffer: Pointer for data to be returned (optional).
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: dataType: Pointer to filled in data type.
* len: Pointer to filled in length.
* places: Pointer to filled in places.
* flags: Pointer to filled in flags.
* buffer: Pointer filled in with data.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 08-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetItem(long sessID, long timeout, DBType *dataType, short *len, short *places,
short *flags, Ptr buffer, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBGetItem */
ClearParams(params);
params.message = kDBGetItem;
params.timeout = timeout;
params.buffer = buffer;
if (dataType != NULL)
{
params.dataType = *dataType;
}
if (len != NULL)
{
params.len = *len;
}
if (places != NULL)
{
params.places = *places;
}
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of len, dataType, places, and flags pointers */
myVars->lenPtr = len;
myVars->dataTypePtr = dataType;
myVars->placesPtr = places;
myVars->flagsPtr = flags;
/* set current action */
myVars->currAction = params.message;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBGetItem */
rc = SMGeneric(sessID, NULL, &params);
/* see if we can return other parameters */
if (rc != rcDBBadSessID)
{
/* ddev was invoked */
/* return len, dataType, places, and flags */
if (len != NULL)
{
*len = params.len;
}
if (dataType != NULL)
{
*dataType = params.dataType;
}
if (places != NULL)
{
*places = params.places;
}
if (flags != NULL)
{
*flags = params.flags;
}
}
}
return(rc);
} /* SMGetItem() */
/*FORM_FEED*/
/*
*
* OBJECT: SMUnGetItem
*
* DESCRIPTION: DBUnGetItem routine. Calls DBUnGetItem with specified parameters.
*
* INPUTS: sessID: Session ID.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SMGeneric.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMUnGetItem(long sessID, DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
DDEVParams params;
/* fill in parameter block for DBUnGetItem */
ClearParams(params);
params.message = kDBUnGetItem;
/* check for asynchronous call */
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(&params, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* put parameter block into global list */
InsertPB(myPB);
/* return immediately */
rc = SMGeneric(sessID, myPB, myVars->params);
}
else
{
/* call ddev synchronously - DBUnGetItem */
rc = SMGeneric(sessID, NULL, &params);
}
return(rc);
} /* SMUnGetItem() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetNewQuery
*
* DESCRIPTION: DBGetNewQuery routine. Gets the specified 'qrsc' resource, and
* builds a QueryRecord from it.
*
* INPUTS: queryID: ID of 'qrsc'.
* query: Pointer to variable to return query in.
*
* OUTPUTS: query: Filled in if successful.
*
* RETURNS: Errors from GetResource and NewHandle.
*
* MODIFICATIONS:
* 03-28-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetNewQuery(short queryID, QueryHandle *query)
{
register short i;
register OSErr rc = noErr;
queryRes **resH, *resP;
QueryRecord **queryH, *queryP;
resArrayList *resList;
Handle *queries;
short *wstrID;
unsigned long resListSize = 0;
/* no query yet */
*query = NULL;
/* get the 'qrsc' */
*((short*) RomMapInsert) = mapTrue;
resH = (queryRes**)GetResource(QRSCRESTYPE, queryID);
if (!resH)
{
/* couldn't get 'qrsc' */
/* note that GetResource does not set ResError for resNotFound! */
if ((rc = RESERR) == noErr)
rc = resNotFound;
}
else
{
queryH = (QueryRecord**)NewHandleClear(sizeof(QueryRecord));
if (!queryH)
{
/* couldn't allocate QueryHandle */
rc = MemError();
/* resH is released below */
}
}
if (rc == noErr)
{
HLock((Handle)resH);
resP = *resH;
HLock((Handle)queryH);
queryP = *queryH;
/* allocate memory for queries and resources first */
if (resP->numQueries > 0) /* fix for bug DSL-010 */
{
/* there are some queries, allocate list */
queryP->queryList = (QueryListHandle)NewHandleClear(resP->numQueries *
sizeof(Handle));
rc = MemError();
}
if (rc == noErr)
{
/* get pointer to list of resources */
resList = (resArrayList*)(&(resP->queryArray[resP->numQueries]));
if (resList->numRes > 0) /* fix for bug DSL-010 */
{
/* there are some resources, allocate list */
/* calculate size of resList once here, as we use it for BlockMove later */
resListSize = sizeof(ResListElem) * resList->numRes;
queryP->resList = (ResListHandle)NewHandleClear(resListSize);
rc = MemError();
}
if (rc == noErr)
{
/* copy info into record */
queryP->version = resP->version; /* version */
queryP->id = queryID; /* id of 'qrsc' */
queryP->currQuery = resP->currQuery; /* current query offset */
queryP->numQueries = resP->numQueries; /* number of queries in array */
queryP->numRes = resList->numRes; /* number of resources in array */
/* get qdef proc - id 0 means no qdef */
if (resP->qdefID != 0)
{
*((short*) RomMapInsert) = mapTrue;
queryP->queryProc = GetResource(QDEFRESTYPE, resP->qdefID);
if (!queryP->queryProc)
{
/* couldn't get qdef */
if ((rc = RESERR) == noErr)
rc = resNotFound;
}
}
if (rc == noErr)
{
/* get DBInit parameters */
GetIndString(queryP->ddevName, resP->strID, DDEVOFFSET);
GetIndString(queryP->host, resP->strID, HOSTOFFSET);
GetIndString(queryP->user, resP->strID, USEROFFSET);
GetIndString(queryP->password, resP->strID, PASSWORDOFFSET);
GetIndString(queryP->connStr, resP->strID, CONNSTROFFSET);
/* set up list of queries */
HLock((Handle)queryP->queryList);
queries = *(queryP->queryList);
wstrID = &(resP->queryArray[0]);
for (i = 0; i < resP->numQueries; i++)
{
*((short*) RomMapInsert) = mapTrue;
*queries = GetResource(QUERYRESTYPE, *wstrID);
if (*queries)
{
DetachResource(*queries);
}
else
{
/* couldn't get specified resource */
if ((rc = RESERR) == noErr)
rc = resNotFound;
}
/* bump pointers */
queries++;
wstrID++;
}
HUnlock((Handle)queryP->queryList);
/*
Set up list of resources.
Since the ResListElem array in the 'qrsc' is the same
as the ResListElem array in the QueryRecord, we can
just blast it in.
*/
if (resListSize > 0)
{
BlockMove((Ptr)&(resList->res[0]), (Ptr)*(queryP->resList), resListSize);
}
}
}
/* check for any errors */
if (rc != noErr)
{
/* an error occurred someplace, so clean up everything */
/* dispose of queryList, if necessary */
if (queryP->queryList)
{
/* queryList was allocated */
HLock((Handle)queryP->queryList);
queries = *(queryP->queryList);
/* dispose of all the 'wstr' handles */
for (i = 0; i < resP->numQueries; i++)
{
if (*queries)
{
/* dispose of the current detached 'wstr' handle */
DisposHandle(*queries);
}
/* bump pointer */
queries++;
}
/* dispose of queryList (no need to unlock it) */
DisposHandle((Handle)queryP->queryList);
}
/* dispose of resList, if necessary */
if (queryP->resList)
DisposHandle((Handle)queryP->resList);
/* finally, get rid of queryH */
DisposHandle((Handle)queryH);
}
else
{
/* everything OK */
HUnlock((Handle)queryH);
/* return query */
*query = queryH;
}
}
}
/* no need to unlock resource before disposing */
if (resH)
ReleaseResource((Handle)resH);
return(rc);
} /* SMGetNewQuery() */
/*FORM_FEED*/
/*
*
* OBJECT: SMDisposeQuery
*
* DESCRIPTION: DBDisposeQuery routine. Unlocks qdef, disposes of all queries in
* queryList and querylist itself, disposes of resList, and finally
* disposes of query record itself.
*
* Questions: Correct strategy for qdef (unlock or dispose?)
* Right now, only checks for last MemError.
*
* INPUTS: query: Handle to query to dispose.
*
* OUTPUTS: None.
*
* RETURNS: nilHandleErr
* Errors from DisposHandle.
*
* MODIFICATIONS:
* 03-28-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMDisposeQuery(QueryHandle query)
QueryHandle query;
{
register short rc = noErr;
register short i;
register QueryRecord *queryP;
register Handle *queries;
if (query == NULL)
{
/* passed in nil handle */
rc = nilHandleErr;
}
else
{
HLock((Handle)query);
queryP = *query;
/* unlock qdef */
if (queryP->queryProc != NULL)
{
HUnlock(queryP->queryProc);
// DisposHandle(queryP->queryProc);
}
/* dispose of queries */
if (queryP->queryList != NULL)
{
HLock((Handle)queryP->queryList);
/* dispose of all the handles in the array */
queries = *(queryP->queryList);
i = queryP->numQueries;
while ((i > 0) && (rc == noErr))
{
DisposHandle(*queries);
rc = MemError();
queries++;
i--;
}
if (rc == noErr)
{
/* no need to unlock handle before disposing */
DisposHandle((Handle)queryP->queryList);
rc = MemError();
}
}
if (rc == noErr)
{
/* dispose of resource list */
if (queryP->resList != NULL)
{
DisposHandle((Handle)queryP->resList);
rc = MemError();
}
if (rc == noErr)
{
/* finally, dispose of query record (no need to unlock it) */
DisposHandle((Handle)query);
rc = MemError();
}
}
}
return(rc);
} /* SMDisposeQuery() */
/*FORM_FEED*/
/*
*
* OBJECT: SMStartQuery
*
* DESCRIPTION: DBStartQuery routine. If query is NULL, prompts for query document.
* Then, calls qdef with query, followed by DBInit, DBSend, and DBExec.
*
* Still need to do async stuff right.
*
* INPUTS: sessID: Pointer for session ID.
* query: Handle to query.
* statusProc: Pointer to user status function, if any.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: sessID: Pointer to filled in session ID.
*
* RETURNS: nilHandleErr (if query is NULL)
* userCanceledErr
* rcDBError (if currQuery not in range)
* Errors from qdef, DBInit, DBSend, and DBExec.
*
* MODIFICATIONS:
* 04-14-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMStartQuery(long *sessID, QueryHandle query, statusPtr statusProc,
DBAsyncParmBlkPtr asyncPB)
{
QDEFPtr qdef;
QueryRecord *qp;
short rc;
Handle queryText, *queries;
short len;
char currState, textState;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
/********************************************/
/* Check for a valid query handle. */
/********************************************/
if (query == NULL)
{
/* query is null, return error */
rc = nilHandleErr;
/* call status function one last time */
rc = CallStatusProc(statusProc, kDBStartQueryComplete, rc);
if (asyncPB)
asyncPB->result = rc;
return(rc);
}
/********************************************/
/* We have a query, now call the qdef if */
/* there is one. */
/********************************************/
if ((**query).queryProc != NULL)
{
GrafPtr oldPort;
/* lock down queryProc and get a pointer to it */
MyHLock((**query).queryProc, &currState);
qdef = (QDEFPtr)(*((**query).queryProc));
/* call qdef with query, saving current GrafPort */
GetPort(&oldPort);
rc = (qdef)(sessID, query);
SetPort(oldPort);
/* restore state of handle */
HSetState((**query).queryProc, currState);
if ((rc == noErr) && (statusProc != NULL))
{
/* qdef completed successfully, call app's
status function */
rc = CallStatusProc(statusProc, kDBUpdateWind, noErr);
}
if (rc != noErr)
{
/* user or status function canceled query or error occurred */
/* call status function one last time */
rc = CallStatusProc(statusProc, kDBStartQueryComplete, rc);
if (asyncPB)
asyncPB->result = rc;
return(rc);
}
}
/* get pointer to QueryRecord */
MyHLock((Handle)query, &currState);
qp = *query;
/********************************************/
/* We've called the qdef, now we need to do */
/* a DBInit if a session is not up yet. */
/********************************************/
/* make sure a valid query is specified */
if ((qp->currQuery >= 1) && (qp->currQuery <= qp->numQueries))
{
/* query valid, check if session is up */
if (*sessID == 0)
{
rc = noErr;
/* call status function, if specified */
rc = CallStatusProc(statusProc, kDBAboutToInit, noErr);
if (rc == noErr)
{
if (asyncPB)
{
/* we have to set up our own parameter block */
myPB = MakePB(NULL, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of session ID */
myVars->sessIDPtr = sessID;
/* keep track of status function */
myVars->statusProc = statusProc;
/* keep track of query for DBSend */
myVars->query = query;
myVars->queryState = currState;
/* get query now */
queries = *(qp->queryList);
myVars->queryText = queryText = queries[qp->currQuery - 1];
MyHLock(queryText, &(myVars->textState));
/* this is a high level call */
myVars->highlevel = true;
/* set current action */
myVars->currAction = kDBInit;
/* put parameter block into global list */
InsertPB(myPB);
/* make the call asynchronously and return */
return(DBInit(sessID, qp->ddevName, qp->host, qp->user, qp->password,
qp->connStr, myPB));
}
else
{
/* app made call synchronously */
/* no session up yet, call DBInit with specified parameters */
rc = DBInit(sessID, qp->ddevName, qp->host, qp->user, qp->password,
qp->connStr, NULL);
/* call status function, if specified */
rc = CallStatusProc(statusProc, kDBInitComplete, rc);
}
}
}
else
{
/* session up already */
rc = noErr;
}
/********************************************/
/* DBInit is done, now do a DBSend to send */
/* the actual query. */
/********************************************/
if (rc == noErr)
{
/* session up, send query */
/* get query now */
queries = *(qp->queryList);
queryText = queries[qp->currQuery - 1];
MyHLock(queryText, &textState);
len = *((short*)(*queryText));
if (asyncPB != NULL)
{
/* we could get here if session was up and we didn't call DBInit */
/* we have to set up our own parameter block */
myPB = MakePB(NULL, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of session ID */
myVars->sessIDPtr = sessID;
/* keep track of status function */
myVars->statusProc = statusProc;
/* keep track of query for DBSend */
myVars->query = query;
myVars->queryState = currState;
/* keep track of query text for DBSend */
myVars->queryText = queryText;
myVars->textState = textState;
/* this is a high level call */
myVars->highlevel = true;
/* set current action */
myVars->currAction = kDBSend;
/* put parameter block into global list */
InsertPB(myPB);
/* make the call asynchronously and return */
return(DBSend(*sessID, *queryText + 2, len, myPB));
}
else
{
/* app made call synchronously */
/* call DBSend with specified query */
rc = DBSend(*sessID, *queryText + 2, len, asyncPB);
/* restore state */
HSetState(queryText, textState);
/* call status function, if specified */
rc = CallStatusProc(statusProc, kDBSendComplete, rc);
}
}
}
else
{
/* currQuery is not in a valid range */
rc = rcDBError; /* do we need another return code here? */
}
/* clean up */
HSetState((Handle)query, currState);
/********************************************/
/* DBSend is done, now do a DBExec. */
/********************************************/
if (rc == noErr)
{
/* everything is OK, execute query */
/* if we get here, we are definitely synchronous */
rc = DBExec(*sessID, asyncPB);
/* call status function, if specified */
rc = CallStatusProc(statusProc, kDBExecComplete, rc);
}
/* call status function one last time */
return(CallStatusProc(statusProc, kDBStartQueryComplete, rc));
} /* SMStartQuery() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetQueryResults
*
* DESCRIPTION: DBGetQueryResults routine.
*
* INPUTS: sessID: Session ID.
* results: Pointer to results record.
* timeout: Timeout value for DBGetItem.
* statusProc: Pointer to user status function, if any.
* asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: results: Pointer to filled in results record.
*
* RETURNS: userCanceledErr
* rcDBValue
* Errors from DBState, SetupResults, DBGetItem, and
* GrowResultsRecord.
*
* MODIFICATIONS:
* 04-19-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetQueryResults(long sessID, ResultsRecord *results, long timeout,
statusPtr statusProc, DBAsyncParmBlkPtr asyncPB)
{
short rc;
DBType dataType, *typeArray;
long currOffset, oldCurrOffset; /* current offset into data */
long endLastRowData, endLastRowInfo; /* end of last row */
short currCol; /* current column */
short len, places, flags;
short retval;
long oldlen;
Handle typeH, dataH, infoH;
Handle oldTypeH, oldDataH, oldInfoH;
Boolean done, firsttime;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
ResultsRecord *oldResults;
snarfSessElemHndl snarf;
DBColInfoRecord *currInfo;
if (asyncPB != NULL)
{
/* we have to set up our own parameter block */
myPB = MakePB(NULL, asyncPB);
myVars = (asyncVarsPtr)myPB->reserved;
/* keep track of session ID */
myVars->sessID = sessID;
/* keep track of status function */
myVars->statusProc = statusProc;
/* keep track of ResultsRecord */
myVars->results = results;
/* this is a high level call */
myVars->highlevel = true;
/* set current action */
myVars->currAction = kDBState;
/* put parameter block into global list */
InsertPB(myPB);
/* make the call asynchronously and return */
return(DBState(sessID, myPB));
}
/* app made call synchronously */
/* check the state of the current session */
rc = DBState(sessID, NULL);
/* we only care if there is data to return */
if (rc != rcDBValue)
{
/* call status function one last time */
return(CallStatusProc(statusProc, kDBGetQueryResultsComplete, rc));
}
#ifdef DODPRINTF
dprintf("DBState returned noErr");
#endif
/* use common code to initialize results */
rc = SetupResults(sessID, &snarf, results, &oldResults,
&currOffset, &currCol);
if (rc != noErr)
{
/* an error occurred initializing results */
/* call status function one last time */
return(CallStatusProc(statusProc, kDBGetQueryResultsComplete, rc));
}
/* current offset in old and user results is the same */
oldCurrOffset = currOffset;
/* save handles in local variables for convenience */
typeH = results->colTypes;
dataH = results->colData;
infoH = results->colInfo;
oldTypeH = oldResults->colTypes;
oldDataH = oldResults->colData;
oldInfoH = oldResults->colInfo;
/* didn't go through a row yet */
endLastRowData = 0;
endLastRowInfo = 0;
done = false;
firsttime = true;
do
{
/* get information on current column without getting data */
dataType = typeAnyType;
/*
dprintf("DBGetItem info: colTypes len = %d, colData len = %d",
GetHandleSize(oldTypeH), GetHandleSize(oldDataH));
dprintf("DBGetItem info: colLens len = %d",
GetHandleSize(oldLenH));
*/
rc = DBGetItem(sessID, timeout, &dataType, &len, &places, &flags, NULL, NULL);
switch (rc)
{
case rcDBNull:
case rcDBValue:
/* information retrieved successfully */
#ifdef DODPRINTF
dprintf("DBGetItem for info - len = %d, dataType = %d, flags = %d", len,
dataType, flags);
#endif
/* grow old results first */
if ((retval = GrowResultsRecord(oldResults, len,
(endLastRowData == 0))) == noErr)
{
/* old results grown successfully, try growing user results */
if ((retval = GrowResultsRecord(results, len,
(endLastRowData == 0))) != noErr)
{
/* couldn't grow user results, resize old results */
SetHandleSize(oldDataH, (long)(oldCurrOffset));
SetHandleSize(oldInfoH, GetHandleSize(oldInfoH) -
sizeof(DBColInfoRecord));
if (endLastRowData == 0)
{
SetHandleSize(oldTypeH, GetHandleSize(oldTypeH) -
sizeof(DBType));
}
done = true;
}
}
else
/* error growing old results */
done = true;
if (!done)
{
/* everything grown OK, update stuff */
/* save info on current column */
oldlen = GetHandleSize(oldInfoH) - sizeof(DBColInfoRecord);
currInfo = (DBColInfoRecord*)(*oldInfoH + oldlen);
currInfo->len = len;
currInfo->places = places;
currInfo->flags = flags;
oldlen = GetHandleSize(infoH) - sizeof(DBColInfoRecord);
currInfo = (DBColInfoRecord*)(*infoH + oldlen);
currInfo->len = len;
currInfo->places = places;
currInfo->flags = flags;
/* save data type, if necessary */
if (endLastRowData == 0)
{
typeArray = (DBType*)(*oldTypeH);
typeArray[currCol] = dataType;
typeArray = (DBType*)(*typeH);
typeArray[currCol] = dataType;
}
}
break;
case noErr:
/* no more data */
#ifdef DODPRINTF
dprintf("DBGetItem for info - got noErr");
#endif
done = true;
if (firsttime)
{
/* first time through, so query had no results */
retval = noErr;
}
else
{
/* not first time, so we have data to return */
retval = rcDBValue;
}
break;
default:
/* some other error */
/* should only be rcDBError from DBGetItem */
#ifdef DODPRINTF
dprintf("DBGetItem for info - got rc = %d", rc);
#endif
done = true;
retval = rc;
break;
}
if (!done)
{
firsttime = false; /* there's at least one column of data */
/* got information on current column successfully, get actual column */
HLock(dataH);
/*
dprintf("DBGetItem data: colTypes len = %d, colData len = %d",
GetHandleSize(oldTypeH), GetHandleSize(oldDataH));
dprintf("DBGetItem data: colLens len = %d",
GetHandleSize(oldLenH));
*/
rc = DBGetItem(sessID, timeout, &dataType, &len, &places, &flags,
*dataH + currOffset, NULL);
/* call status function, if specified */
if (statusProc != NULL)
{
if (!statusProc(kDBGetItemComplete, rc, len, places, flags, dataType,
*dataH + currOffset))
{
/* status function cancelled */
done = true;
retval = userCanceledErr;
}
}
HUnlock(dataH);
switch (rc)
{
case rcDBNull:
case rcDBValue:
/* got data */
#ifdef DODPRINTF
dprintf("DBGetItem - got data of dataType %d len %d, at %X",
dataType, len, (long)*dataH + currOffset);
#endif
/* copy data to old results */
BlockMove(*dataH + currOffset, *oldDataH + oldCurrOffset,
(long)len);
/* update current position in data handle */
currOffset += len;
oldCurrOffset += len;
/* check if end of row */
if (flags & kDBLastColFlag)
{
/* yes, update currCol and endLastRows */
#ifdef DODPRINTF
dprintf("DBGetItem - at end of row, col = %d", currCol);
#endif
if (endLastRowData == 0)
{
/* just went through first row, update results */
results->numCols = currCol + 1;
}
currCol = 0;
endLastRowData = currOffset;
endLastRowInfo = GetHandleSize(infoH);
/* add one to the number of rows processed */
results->numRows++;
/* we got a complete row, shrink down old results */
SetHandleSize(oldDataH, 0);
SetHandleSize(oldInfoH, 0);
oldCurrOffset = 0;
/* keep the old types handle around */
}
else
{
/* still in same row */
currCol++;
}
break;
default:
/* some other error occurred from DBGetItem */
#ifdef DODPRINTF
dprintf("DBGetItem - other error %d", rc);
#endif
done = true;
retval = rc;
break;
}
}
} while (!done);
if (retval != rcDBValue)
{
/* some error occurred, either out of space or ddev error */
/* or status function cancelled */
/* need to back up to last full row */
if (endLastRowData == 0)
{
/* didn't get one full row, need to dispose of everything */
DisposeResultsRecord(results);
results->numRows = 0;
results->numCols = 0;
}
else
{
/* got at least one row */
/* adjust data and info handle */
SetHandleSize(dataH, endLastRowData);
SetHandleSize(infoH, endLastRowInfo);
}
/* update currCol in snarf elem */
(**snarf).currCol = currCol;
/* roll back types array to current column */
SetHandleSize(oldTypeH, (long)((currCol+1) * sizeof(DBType)));
}
else
{
/* we got all the data successfully, so we don't need the old results */
DisposeResultsRecord(oldResults);
DisposPtr((Ptr)oldResults);
(**snarf).oldResults = NULL;
(**snarf).currCol = 0;
}
#ifdef DODPRINTF
dprintf("SMGetQueryResults exit - rc = %d, results = %X", rc, results);
#endif
/* call status function one last time */
retval = CallStatusProc(statusProc, kDBGetQueryResultsComplete, retval);
return(retval);
} /* SMGetQueryResults() */
/*FORM_FEED*/
/*
*
* OBJECT: SMKill
*
* DESCRIPTION: DBKill routine. Calls DBKill with specified parameters.
*
* INPUTS: asyncPB: Pointer to asynchronous parameter block.
*
* OUTPUTS: None.
*
* RETURNS: rcDBBadAsyncPB
* rcDBError
* Errors from CallDDEV.
*
* MODIFICATIONS:
* 07-28-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMKill(DBAsyncParmBlkPtr asyncPB)
{
register short rc;
DBAsyncParmBlkPtr realPB, otherPB;
asyncVarsPtr myVars;
ddevElemHndl ddevH;
Boolean highlevel;
Boolean closeDDEV;
DDEVParams params;
/* assume bad asyncPB */
rc = rcDBBadAsyncPB;
if (asyncPB)
{
/* try to find asyncPB embedded in our list of PBs */
realPB = FindAppPB(asyncPB);
if (realPB)
{
/* got the actual parameter block */
myVars = (asyncVarsPtr)realPB->reserved;
if (highlevel = myVars->highlevel)
{
/* we've found the pb for StartQuery or GetQueryResults */
/* now, we need the pb for the actual call to the ddev */
otherPB = realPB;
realPB = FindAppPB(otherPB);
if (realPB)
{
/* get the right variables */
myVars = (asyncVarsPtr)realPB->reserved;
}
}
if (realPB)
{
/* make sure call is still executing before killing it */
if (myVars->executing)
{
/* fill in parameter block for DBKill */
ClearParams(params);
params.message = kDBKill;
params.asyncPB = realPB;
/* session ID not needed, so just pass 0 */
/* call ddev synchronously - DBKill */
rc = CallDDEV(((asyncVarsPtr)realPB->reserved)->ddevH, &params);
if (rc == noErr)
{
/* copy over the result, just in case */
asyncPB->result = realPB->result;
/* check if this is a DBInit, if so, we have to
close ddev if no sessions are up */
if (closeDDEV = ((myVars->currAction == kDBInit) &&
(myVars->firstsess)))
{
/* save ddev handle to close after removing pbs */
ddevH = myVars->ddevH;
}
if (highlevel)
{
/* we just killed the actual PB, need to
remove the high level PB */
RemovePB(otherPB);
}
/* remove pb from list */
RemovePB(realPB);
/* close ddev, if necessary */
if (closeDDEV)
(void)SMClose(ddevH);
}
}
else
{
/* call has finished executing, we just haven't processed it
yet in DBIdle, so return an error ?? */
rc = rcDBError;
}
}
}
}
return(rc);
} /* SMKill() */
/*FORM_FEED*/
/*
*
* OBJECT: SMResultsToText
*
* DESCRIPTION: DBResultsToText routine. Converts specified ResultsRecord to text.
*
* INPUTS: results: Pointer to ResultsRecord returned by DBGetQueryResults.
*
* OUTPUTS: theText: Handle allocated with converted text.
*
* RETURNS: Errors from NewHandle and the result handler.
*
* MODIFICATIONS:
* 08-03-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMResultsToText(ResultsRecord *results, Handle *theText)
{
Handle textH;
HandlerPtr theHandler, colHandler, rowHandler, unknHandler;
DBType *typeArray;
Ptr buffer;
DBColInfoRecord *infoArray;
short currRow, currCol;
short rc = noErr;
char typeState, dataState, infoState;
/* assume failure */
*theText = NULL;
/* check if this results records contains any results and is valid */
if ((results->numRows == 0) || (results->numCols == 0) ||
(results->colTypes == NULL) || (results->colData == NULL) ||
(results->colInfo == NULL))
{
return(noErr);
}
/* start with empty handle */
textH = NewHandle(NULL);
if (textH == NULL)
rc = MemError();
if (rc == noErr)
{
/* lock everything down */
MyHLock(results->colTypes, &typeState);
MyHLock(results->colData, &dataState);
MyHLock(results->colInfo, &infoState);
/* get pointers to all the arrays */
typeArray = (DBType*)(*(results->colTypes));
buffer = (*(results->colData));
infoArray = (DBColInfoRecord*)(*(results->colInfo));
/* prefetch the unknown, column break, and row break handlers */
unknHandler = GetCorrectResultHandler(typeUnknown);
colHandler = GetCorrectResultHandler(typeColBreak);
rowHandler = GetCorrectResultHandler(typeRowBreak);
/* start at the beginning */
currRow = 0;
/* do all the rows */
while ((currRow < results->numRows) && (rc == noErr))
{
/* do all the columns in this row */
currCol = 0;
while ((currCol < results->numCols) && (rc == noErr))
{
/* try to get the application handler for the type of data in this column */
theHandler = GetCorrectResultHandler(typeArray[currCol]);
if (theHandler == NULL)
{
/* none installed for this type, use the unknown handler */
theHandler = unknHandler;
}
/* call the handler to do the conversion */
rc = (*theHandler)(typeArray[currCol], infoArray->len, infoArray->places,
infoArray->flags, buffer, textH);
/* adjust pointer into buffer */
buffer += infoArray->len;
/* adjust pointer into DBColInfoRecord array */
infoArray++;
/* go to next column */
currCol++;
/* see if we're at the end of a row */
if ((currCol < results->numCols) && (rc == noErr))
{
/* no, do column break */
rc = (*colHandler)(typeColBreak, 0, NULL, NULL, NULL, textH);
}
} /* while ((currCol < results->numCols) && (rc == noErr)) */
/* go to next row */
currRow++;
/* do row break */
if (rc == noErr)
{
rc = (*rowHandler)(typeRowBreak, 0, NULL, NULL, NULL, textH);
}
} /* while ((currRow < results->numRows) && (rc == noErr)) */
/* clean up */
*theText = textH;
HSetState(results->colTypes, typeState);
HSetState(results->colData, dataState);
HSetState(results->colInfo, infoState);
}
return(rc);
} /* SMResultsToText() */
/*FORM_FEED*/
/*
*
* OBJECT: GetCorrectResultHandler
*
* DESCRIPTION: Get the specified result handler. Tries to get application handler first,
* then system handler if there is no application handler.
*
* INPUTS: dataType: Data type for handler.
*
* OUTPUTS: None.
*
* RETURNS: theHandler: Handler ProcPtr.
*
* MODIFICATIONS:
* 04-02-90 JSM - Created.
*
* Copyright Apple Computer, Inc. 1990
* All rights reserved.
*
*/
HandlerPtr
GetCorrectResultHandler(DBType dataType)
{
ProcPtr p;
/* check for application handlers first */
DBGetResultHandler(dataType, &p, false);
if (p == NULL)
{
/* no application handler, get system handler */
DBGetResultHandler(dataType, &p, true);
}
return((HandlerPtr)p);
} /* GetCorrectResultHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: SMInstallResultHandler
*
* DESCRIPTION: DBInstallResultHandler routine. Installs a results
* handler for the specified data type.
*
* INPUTS: dataType: Data type for this handler.
* theHandler: Pointer to handler.
* isSysHandler: If TRUE, install this as a system handler,
* otherwise handler is for current application.
*
* OUTPUTS: None.
*
* RETURNS: Errors from NewHandleSys and InsertHandler.
*
* MODIFICATIONS:
* 08-03-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMInstallResultHandler(DBType dataType, ProcPtr theHandler, Boolean isSysHandler)
{
snarfGlobPtr glob;
HandlerRecord *hArray;
short currIndex;
HandlerRecord newRec, *arrayHandler, **newHandler;
short rc;
char currState;
Boolean foundit;
/* assume success */
rc = noErr;
/* set up new record to put in array */
newRec.type = dataType;
newRec.theHandler = (HandlerPtr)theHandler;
newRec.next = (HandlerRecord**)NULL;
newRec.hZone = GetZone();
newRec.isSysHandler = isSysHandler;
/* see if there already is any handler for this type */
if ((currIndex = FindHandler(dataType)) != -1)
{
/* yes, get the handler in the array */
/* get a pointer to the array */
glob = GetGlobals();
MyHLock((Handle)glob->handlers, &currState);
hArray = *(glob->handlers);
/* arrayHandler is the handler in the array, that is,
the first handler for this type */
arrayHandler = &hArray[currIndex];
if (isSysHandler)
{
/* installing a system handler */
/* if there is a system handler, it is always first in the list */
if (!(arrayHandler->isSysHandler))
{
/* first handler is an app handler, need to move it down
the list, so duplicate it into a new handle */
newHandler = (HandlerRecordHandle)NewHandleSysClear(
sizeof(HandlerRecord));
if ((rc = MemError()) == noErr)
{
BlockMove((Ptr)arrayHandler, (Ptr)*newHandler,
sizeof(HandlerRecord));
/* set the next field of system handler record */
newRec.next = newHandler;
}
}
else
{
/* replacing current system handler, set next field */
newRec.next = arrayHandler->next;
}
/* move in the new system handler */
if (rc == noErr)
{
BlockMove((Ptr)&newRec, (Ptr)arrayHandler, sizeof(HandlerRecord));
}
}
else
{
/* installing an application handler */
/* try and find a current handler for this app */
/* check the array handler first */
if (!(arrayHandler->isSysHandler) &&
(arrayHandler->hZone != newRec.hZone))
{
/* handler in array is the current app handler */
/* just set the proc ptr */
arrayHandler->theHandler = (HandlerPtr)theHandler;
}
else
{
/* have to search list of handlers */
newHandler = arrayHandler->next;
foundit = false;
while (newHandler && !foundit)
{
if ((**newHandler).hZone == newRec.hZone)
{
/* found current app handler */
foundit = true;
}
else
newHandler = (**newHandler).next;
}
if (foundit)
{
/* an app handler already exists, just set the proc ptr */
(**newHandler).theHandler = (HandlerPtr)theHandler;
}
else
{
/* new handler for current app, insert one after array handler */
newRec.next = arrayHandler->next;
newHandler = (HandlerRecordHandle)NewHandleSysClear(
sizeof(HandlerRecord));
if ((rc = MemError()) == noErr)
{
BlockMove((Ptr)&newRec, (Ptr)*newHandler,
sizeof(HandlerRecord));
arrayHandler->next = newHandler;
}
}
}
}
/* restore state of handler array */
HSetState((Handle)glob->handlers, currState);
}
else
{
/* no handler for this type, install new handler into the array */
rc = InsertHandler(&newRec);
}
return(rc);
} /* SMInstallResultHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: SMRemoveResultHandler
*
* DESCRIPTION: DBRemoveResultHandler routine. Remove a result
* handler for the specified data type.
*
* INPUTS: dataType: Data type for handler to remove.
*
* OUTPUTS: None.
*
* RETURNS: rcDBNoHandler
* Errors from DisposHandle, and RemoveHandler.
*
* MODIFICATIONS:
* 08-03-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMRemoveResultHandler(DBType dataType)
{
short index;
snarfGlobPtr glob;
HandlerRecord *hArray, **newHandler, **lastHandler;
THz hZone;
short rc;
Boolean foundit;
char currState;
/* assume failure */
rc = rcDBNoHandler;
/* find the array entry for this data type */
index = FindHandler(dataType);
if (index == -1)
{
/* no handler (system or app) installed */
return(rcDBNoHandler);
}
/* get specific handler element */
glob = GetGlobals();
MyHLock((Handle)(glob->handlers), &currState);
hArray = *(glob->handlers);
/* get current application's zone */
hZone = GetZone();
/* check the array handler first */
if (!(hArray[index].isSysHandler) &&
(hArray[index].hZone == hZone))
{
/* handler in array is the current app handler */
/* see if there are any other handlers left */
if (newHandler = hArray[index].next)
{
/* yes, just move the next one into the array */
BlockMove((Ptr)*newHandler, (Ptr)&(hArray[index]),
sizeof(HandlerRecord));
DisposHandle((Handle)newHandler);
rc = MemError();
}
else
{
/* we're removing the only handler for this data type */
HSetState((Handle)(glob->handlers), currState);
rc = RemoveHandler(index);
}
}
else
{
/* handler in array isn't the right one, check list */
newHandler = hArray[index].next;
lastHandler = NULL;
foundit = false;
while (newHandler && !foundit)
{
if ((**newHandler).hZone == hZone)
{
/* found current app handler */
foundit = true;
}
else
{
lastHandler = newHandler;
newHandler = (**newHandler).next;
}
}
if (foundit)
{
/* found the app handler in the list off the array */
/* fix up list */
if (lastHandler)
{
(**lastHandler).next = (**newHandler).next;
}
else
{
/* removing first handler in list */
hArray[index].next = (**newHandler).next;
}
/* get rid of handler record */
DisposHandle((Handle)newHandler);
rc = MemError();
}
}
HSetState((Handle)(glob->handlers), currState);
return(rc);
} /* SMRemoveResultHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGetResultHandler
*
* DESCRIPTION: DBGetResultHandler routine. Returns a pointer to
* the result handler for the specified data type. getSysHandler
* specifies which handler to return.
*
* INPUTS: dataType: Data type for handler.
* getSysHandler: If TRUE, return system handler, if any.
* Otherwise, return app handler, if any.
*
* OUTPUTS: theHandler: Pointer to handler.
*
* RETURNS: rcDBNoHandler
*
* MODIFICATIONS:
* 08-03-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal OSErr
SMGetResultHandler(DBType dataType, ProcPtr *theHandler, Boolean getSysHandler)
{
short index;
snarfGlobPtr glob;
HandlerRecord *hArray, **newHandler;
short rc;
THz hZone;
Boolean foundit;
char currState;
/* assume failure */
*theHandler = NULL;
rc = rcDBNoHandler;
/* find the array entry for this data type */
index = FindHandler(dataType);
if (index == -1)
{
/* no handler (system or app) installed */
return(rcDBNoHandler);
}
/* get specific handler element */
glob = GetGlobals();
MyHLock((Handle)(glob->handlers), &currState);
hArray = *(glob->handlers);
if (getSysHandler)
{
/* wants system handler, always first one if it exists */
if (hArray[index].isSysHandler)
{
/* this is it */
*theHandler = (ProcPtr)(hArray[index].theHandler);
rc = noErr;
}
}
else
{
/* wants current application's handler */
hZone = GetZone();
/* check the array handler first */
if (!(hArray[index].isSysHandler) &&
(hArray[index].hZone == hZone))
{
/* handler in array is the current app handler */
*theHandler = (ProcPtr)(hArray[index].theHandler);
rc = noErr;
}
else
{
/* have to search list of handlers */
newHandler = hArray[index].next;
foundit = false;
while (newHandler && !foundit)
{
if ((**newHandler).hZone == hZone)
{
/* found current app handler */
foundit = true;
}
else
newHandler = (**newHandler).next;
}
if (foundit)
{
/* found the app handler in the list off the array */
*theHandler = (ProcPtr)((**newHandler).theHandler);
rc = noErr;
}
}
}
HSetState((Handle)(glob->handlers), currState);
return(rc);
} /* SMGetResultHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: FindHandler
*
* DESCRIPTION: Do a binary search of the array of HandlerRecords for the
* handler of the specified type. Returns array index of handler,
* or -1 if not found.
*
* INPUTS: dataType: Data type for handler to find.
*
* OUTPUTS: None.
*
* RETURNS: Index into array of handler, or -1 if not found.
*
* MODIFICATIONS:
* 08-06-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
short
FindHandler(DBType dataType)
{
snarfGlobPtr glob;
HandlerRecord *hArray;
short curr, first, last, rc;
char currState;
glob = GetGlobals();
/* check for empty array */
if ((last = glob->numHandlers) == 0)
{
rc = -1;
}
else
{
/* lock down array */
MyHLock((Handle)glob->handlers, &currState);
hArray = *(glob->handlers);
/* start with whole array */
first = 0;
do
{
curr = (first + last) >> 1;
if (dataType < hArray[curr].type)
/* in first half */
last = curr - 1;
else
/* in second half */
first = curr + 1;
} while ((dataType != hArray[curr].type) && (first <= last));
if (dataType == hArray[curr].type)
rc = curr;
else
rc = -1;
HSetState((Handle)glob->handlers, currState);
}
return(rc);
} /* FindHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: InsertHandler
*
* DESCRIPTION: Insert specified HandlerRecord in array of handlers.
*
* INPUTS: newRec: HandlerRecord to insert.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SetHandleSize.
*
* MODIFICATIONS:
* 08-06-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
InsertHandler(HandlerRecord *newRec)
{
snarfGlobPtr glob;
HandlerRecord *hArray;
short rc;
short numHandlers, i;
char currState;
/* find where to put new record */
glob = GetGlobals();
MyHLock((Handle)glob->handlers, &currState);
hArray = *(glob->handlers);
i = 0;
numHandlers = glob->numHandlers;
while ((i < numHandlers) && (hArray[i].type < newRec->type))
i++;
/* grow array */
HSetState((Handle)glob->handlers, currState);
SetHandleSize((Handle)glob->handlers, GetHandleSize((Handle)glob->handlers)
+ sizeof(HandlerRecord));
if ((rc = MemError()) == noErr)
{
hArray = *(glob->handlers);
/* see if we have to shift array */
if (i != numHandlers) /* are we inserting at the end? */
{
/* no, have to move some records down */
BlockMove((Ptr)&(hArray[i]), (Ptr)&(hArray[i+1]), (numHandlers - i) *
sizeof(HandlerRecord));
}
/* move in new record */
BlockMove((Ptr)newRec, (Ptr)&(hArray[i]), sizeof(HandlerRecord));
glob->numHandlers++;
}
return(rc);
} /* InsertHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: RemoveHandler
*
* DESCRIPTION: Remove handler at specified index in array.
*
* INPUTS: index: Index of record to remove.
*
* OUTPUTS: None.
*
* RETURNS: Errors from SetHandleSize.
*
* MODIFICATIONS:
* 08-09-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
RemoveHandler(short index)
{
snarfGlobPtr glob;
HandlerRecord *hArray;
/* find record to delete */
glob = GetGlobals();
if (index != (glob->numHandlers - 1))
{
/* we're not removing the last record in the array,
need to move other elements up */
hArray = *(glob->handlers);
BlockMove((Ptr)&(hArray[index+1]), (Ptr)&(hArray[index]),
sizeof(HandlerRecord) * (glob->numHandlers - index - 1));
}
/* decrement number of handlers */
glob->numHandlers--;
/* resize handle */
SetHandleSize((Handle)glob->handlers, GetHandleSize((Handle)glob->handlers)
- sizeof(HandlerRecord));
return(MemError());
} /* RemoveHandler() */
/*FORM_FEED*/
/*
*
* OBJECT: SMGeneric
*
* DESCRIPTION: Generic routine to invoke ddev with specified parameter block.
* Converts snarfID to the ddev's session ID, and fills in
* the sessID and asyncPB field of the DDEVParams. We do this
* all here to save code. Note: if caller gets back
* rcDBBadSessID then ddev was not called.
*
* INPUTS: snarfID: Snarf ID of session.
* asyncPB: Pointer to asynchronous parameter block.
* params: Pointer to filled in parameter block for ddev.
*
* OUTPUTS: None.
*
* RETURNS: rcDBBadSessID
* Errors from CallDDEV.
*
* MODIFICATIONS:
* 03-27-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SMGeneric(long snarfID, DBAsyncParmBlkPtr asyncPB, DDEVParams *params)
{
snarfGlobPtr glob;
ddevElemHndl ddevH;
snarfSessElemHndl snarf;
sessElemHndl sess;
short rc;
glob = GetGlobals();
/* find snarf element with specified id */
if ((snarf = FindSnarfID(snarfID, glob->snarfRoot)) == NULL)
{
/* bad session ID */
rc = rcDBBadSessID;
}
else
{
/* got snarf element, get session and ddev info */
sess = (**snarf).sess;
ddevH = (**sess).parent;
/* fill in real session ID */
params->sessID = (**sess).sessID;
/* fill in asyncPB pointer */
params->asyncPB = asyncPB;
/* call ddev with specified parameter block */
rc = CallDDEV(ddevH, params);
}
return(rc);
} /* SMGeneric() */
/*FORM_FEED*/
/*
*
* OBJECT: InitDoneProc
*
* DESCRIPTION: Routine called after DBInit for an asynchronous DBStartQuery
* completes. If DBInit was successful, calls DBSend.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: userCanceledErr
* Errors from just finished DBInit and DBSend.
*
* MODIFICATIONS:
* 06-21-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
InitDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
Handle queryText, *queries;
short len;
OSErr rc;
/* call status function, if specified */
rc = CallStatusProc(myVars->statusProc, kDBInitComplete, myPB->result);
/* check if successful */
if (rc == noErr)
{
/* DBInit completed successfully, call DBSend */
/* get query text */
queries = *((**(myVars->query)).queryList);
myVars->queryText = queryText =
queries[(**(myVars->query)).currQuery - 1];
MyHLock(queryText, &(myVars->textState));
len = *((short*)(*queryText));
/* we are about to be executing */
myVars->executing = true;
/* get next action */
myVars->currAction = kDBSend;
/* call DBSend asynchronously */
rc = DBSend(*(myVars->sessIDPtr), *queryText + 2, len, myPB);
}
myPB->result = rc;
return(rc);
} /* InitDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: SendDoneProc
*
* DESCRIPTION: Routine called after DBSend for an asynchronous DBStartQuery
* completes. If DBSend was successful, calls DBExec.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: userCanceledErr
* Errors from just finished DBSend and DBExec.
*
* MODIFICATIONS:
* 06-21-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SendDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
OSErr rc;
/* call status function, if specified */
rc = CallStatusProc(myVars->statusProc, kDBSendComplete, myPB->result);
/* check if successful */
if (rc == noErr)
{
/* DBSend completed successfully, call DBExec */
/* we are about to be executing */
myVars->executing = true;
/* get next action */
myVars->currAction = kDBExec;
/* call DBExec asynchronously */
rc = DBExec(*(myVars->sessIDPtr), myPB);
}
myPB->result = rc;
return(rc);
} /* SendDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: ExecDoneProc
*
* DESCRIPTION: Routine called after DBExec for an asynchronous DBStartQuery
* completes. Just returns the result.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: userCanceledErr
* Errors from just finished DBExec.
*
* MODIFICATIONS:
* 06-21-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
ExecDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
/* call status function, if specified */
myPB->result = CallStatusProc(myVars->statusProc, kDBExecComplete, myPB->result);
/* this was the last call we needed to do */
/* but we don't need to set currAction since SMIdle knows this */
/* myVars->currAction = kAllDone; */
/* just return result from DBExec */
return(myPB->result);
} /* ExecDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: StateDoneProc
*
* DESCRIPTION: Routine called after DBState for an asynchronous
* DBGetQueryResults completes. If DBState was successful
* and there is data to return, calls DBGetItem.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: Errors from just finished DBState, SetupResults,
* and DBGetItem.
*
* MODIFICATIONS:
* 06-21-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
StateDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
short rc;
/* we only care if there is data to return */
if (myPB->result == rcDBValue)
{
/* program complete, possibly results available */
/* use common code to initialize results */
rc = SetupResults(myVars->sessID, &(myVars->snarf), myVars->results,
&(myVars->oldResults), &(myVars->currOffset), &(myVars->currCol));
if (rc == noErr)
{
/* current offset in old and user results is the same */
myVars->oldCurrOffset = myVars->currOffset;
/* didn't go through a row yet */
myVars->endLastRowData = 0;
myVars->endLastRowInfo = 0;
myVars->firsttime = true;
/* set up to call DBGetItem */
myVars->executing = true;
/* get next action */
myVars->currAction = kDBGetItem;
/* we are about to get info on the current column */
myVars->doingGetItemInfo = true;
/* get information on current column without getting data */
myVars->dataType = typeAnyType;
rc = DBGetItem(myVars->sessID, myVars->timeout, &(myVars->dataType),
&(myVars->len), &(myVars->places), &(myVars->flags), NULL, myPB);
}
if (rc != noErr)
{
/* error occurred in SetupResults or DBGetItem, set up for return */
myPB->result = rc;
}
}
else
{
/* no data or some other error */
rc = myPB->result;
if (rc == noErr)
{
/*
There's no data to return, but we have to call AllDoneProc here
since idle considers noErr to mean that we started the DBGetItem
successfully.
*/
(void)AllDoneProc(myPB, myVars);
}
}
return(rc);
} /* StateDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: GetItemDoneProc
*
* DESCRIPTION: Routine called after DBGetItem for an asynchronous
* DBGetQueryResults completes. Note that DBGetItem can
* either be called with buffer set to NULL, indicating that
* we wanted infomation on the current column only, or with
* buffer set to the value passed into DBGetQueryResults,
* indicating we got the actual data. In the latter case,
* if more data is available, we call DBGetItem again, otherwise
* we indicate to SMIdle that the call has completed.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: rcDBValue
* Errors from just finished DBGetItem, GrowResultsRecord, and
* next DBGetItem.
*
* MODIFICATIONS:
* 08-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
GetItemDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
short rc, oldlen;
ResultsRecord *results, *oldResults;
DBType *typeArray;
DBColInfoRecord *currInfo;
/* see if the DBGetItem that just completed was for info or the
actual data */
if (myVars->doingGetItemInfo)
{
/* just got info */
switch (myPB->result)
{
case rcDBNull:
case rcDBValue:
/* information retrieved successfully */
#ifdef DODPRINTF
dprintf("DBGetItem info - len = %d, dataType = %d, flags = %d", myVars->len,
myVars->dataType, myVars->flags);
#endif
/* grow old results first */
oldResults = myVars->oldResults;
if ((rc = GrowResultsRecord(oldResults, myVars->len,
(myVars->endLastRowData == 0))) == noErr)
{
/* old results grown successfully, try growing user results */
results = myVars->results;
if ((rc = GrowResultsRecord(results, myVars->len,
(myVars->endLastRowData == 0))) != noErr)
{
/* couldn't grow user results, resize old results */
SetHandleSize(oldResults->colData, myVars->oldCurrOffset);
SetHandleSize(oldResults->colInfo,
GetHandleSize(oldResults->colInfo) - sizeof(DBColInfoRecord));
if (myVars->endLastRowData == 0)
{
SetHandleSize(oldResults->colTypes,
GetHandleSize(oldResults->colTypes) -
sizeof(DBType));
}
}
}
if (rc != noErr)
{
/* error resizing results */
myPB->result = rc;
return(myPB->result);
}
/* everything grown OK, update stuff */
/* save info on current column */
oldlen = GetHandleSize(oldResults->colInfo) - sizeof(DBColInfoRecord);
currInfo = (DBColInfoRecord*)(*(oldResults->colInfo) + oldlen);
currInfo->len = myVars->len;
currInfo->places = myVars->places;
currInfo->flags = myVars->flags;
oldlen = GetHandleSize(results->colInfo) - sizeof(DBColInfoRecord);
currInfo = (DBColInfoRecord*)(*(results->colInfo) + oldlen);
currInfo->len = myVars->len;
currInfo->places = myVars->places;
currInfo->flags = myVars->flags;
/* save data type, if necessary */
if (myVars->endLastRowData == 0)
{
typeArray = (DBType*)(*(oldResults->colTypes));
typeArray[myVars->currCol] = myVars->dataType;
typeArray = (DBType*)(*(results->colTypes));
typeArray[myVars->currCol] = myVars->dataType;
}
break;
case noErr:
/* no more data */
#ifdef DODPRINTF
dprintf("DBGetItem info - got noErr");
#endif
/* get next action */
myVars->currAction = kAllDone;
if (myVars->firsttime)
{
/* first time through, so query had no results */
myPB->result = noErr;
}
else
{
/* not first time, so we have data to return */
myPB->result = rcDBValue;
}
return(noErr);
break;
default:
/* some other error */
/* should only be rcDBError from DBGetItem */
#ifdef DODPRINTF
dprintf("DBGetItem info - got rc = %d", myPB->result);
#endif
/* get next action */
myVars->currAction = kAllDone;
return(myPB->result);
break;
}
/* got here if rcDBNull or rcDBValue */
myVars->firsttime = false; /* there's at least one column of data */
/* we are about to get the actual column, not just the info */
myVars->doingGetItemInfo = false;
/* we are about to be executing */
myVars->executing = true;
/* action still the same */
/* myVars->currAction = kDBGetItem; */
/*
dprintf("DBGetItem data: colTypes len = %d, colData len = %d",
GetHandleSize(oldResults->colTypes), GetHandleSize(oldResults->colData));
dprintf("DBGetItem data: colLens len = %d",
GetHandleSize(oldResults->colLens));
*/
/* got information on current column successfully, get actual column */
HLock(results->colData);
rc = DBGetItem(myVars->sessID, myVars->timeout, &(myVars->dataType),
&(myVars->len), &(myVars->places), &(myVars->flags),
*(results->colData) + myVars->currOffset, myPB);
if (rc != noErr)
{
/* error starting DBGetItem, set up for return */
myPB->result = rc;
}
return(rc);
}
else
{
/* just got actual column */
results = myVars->results;
oldResults = myVars->oldResults;
/* save result of DBGetItem */
rc = myPB->result;
/* call status function, if specified */
if (myVars->statusProc != NULL)
{
if (!(myVars->statusProc)(kDBGetItemComplete, myPB->result,
myVars->len, myVars->places, myVars->flags, myVars->dataType, *(results->colData)
+ myVars->currOffset))
{
/* status function cancelled */
rc = userCanceledErr;
}
}
/* unlock data handle */
HUnlock(results->colData);
switch (myPB->result)
{
case rcDBNull:
case rcDBValue:
/* got data */
#ifdef DODPRINTF
dprintf("DBGetItem - got data of dataType %d len %d, at %X",
myVars->dataType, myVars->len, (long)*(results->colData) + currOffset);
#endif
/* copy data to old results */
BlockMove(*(results->colData) + myVars->currOffset,
*(oldResults->colData) + myVars->oldCurrOffset,
(long)myVars->len);
/* update current position in data handle */
myVars->currOffset += myVars->len;
myVars->oldCurrOffset += myVars->len;
/* check if end of row */
if (myVars->flags & kDBLastColFlag)
{
/* yes, update currCol and endLastRows */
#ifdef DODPRINTF
dprintf("DBGetItem - at end of row, col = %d", myVars->currCol);
#endif
if (myVars->endLastRowData == 0)
{
/* just went through first row, update results */
results->numCols = myVars->currCol + 1;
}
myVars->currCol = 0;
myVars->endLastRowData = myVars->currOffset;
myVars->endLastRowInfo = GetHandleSize(results->colInfo);
/* add one to the number of rows processed */
results->numRows++;
/* we got a complete row, shrink down old results */
SetHandleSize(oldResults->colData, 0);
SetHandleSize(oldResults->colInfo, 0);
myVars->oldCurrOffset = 0;
}
else
{
/* still in same row */
myVars->currCol++;
}
if (rc != userCanceledErr)
{
/* set up to call DBGetItem */
myVars->executing = true;
/* action still the same */
/* myVars->currAction = kDBGetItem; */
/* we are about to get info on the current column */
myVars->doingGetItemInfo = true;
/*
dprintf("DBGetItem info: colTypes len = %d, colData len = %d",
GetHandleSize(oldResults->colTypes), GetHandleSize(oldResults->colData));
dprintf("DBGetItem info: colLens len = %d",
GetHandleSize(oldResults->colLens));
*/
/* get information on current column without getting data */
myVars->dataType = typeAnyType;
rc = DBGetItem(myVars->sessID, myVars->timeout, &(myVars->dataType),
&(myVars->len), &(myVars->places), &(myVars->flags), NULL, myPB);
}
if (rc != noErr)
{
/* error starting DBGetItem or status function cancelled, set up for return */
myPB->result = rc;
}
return(rc);
break;
default:
/* some other error occurred from DBGetItem */
#ifdef DODPRINTF
dprintf("DBGetItem - other error %d", myPB->result);
#endif
/* save result in case status function changed it */
myPB->result = rc;
return(myPB->result);
break;
}
}
} /* GetItemDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: AllDoneProc
*
* DESCRIPTION: State routine called after all routines for an asynchronous call
* to DBStartQuery or DBGetQueryResults have completed,
* or a routine ends in an error.
*
* INPUTS: myPB: Async parameter block.
* myVars: Async variables.
*
* OUTPUTS: None.
*
* RETURNS: noErr always.
*
* MODIFICATIONS:
* 06-21-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
AllDoneProc(DBAsyncParmBlkPtr myPB, asyncVarsPtr myVars)
{
DBAsyncParmBlkPtr asyncPB;
ResultsRecord *results, *oldResults;
snarfSessElem **snarf;
/* see what we have to do to clean up */
switch (myVars->currAction)
{
/* are we DBStartQuery? */
case kDBInit:
case kDBSend:
case kDBExec:
/* clean up */
HSetState((Handle)myVars->query, myVars->queryState);
HSetState(myVars->queryText, myVars->textState);
/* call status function, if specified */
myPB->result = CallStatusProc(myVars->statusProc, kDBStartQueryComplete, myPB->result);
break;
/* are we DBGetQueryResults? */
case kDBState:
/* do nothing if DBState didn't return rcDBValue */
/* call status function, if specified */
myPB->result = CallStatusProc(myVars->statusProc, kDBGetQueryResultsComplete, myPB->result);
break; /* fix for bug DSL-009 */
case kDBGetItem:
oldResults = myVars->oldResults;
snarf = myVars->snarf;
if (myPB->result != rcDBValue)
{
/* some error occurred, either out of space or ddev error */
/* need to back up to last full row */
results = myVars->results;
if (myVars->endLastRowData == 0)
{
/* didn't get one full row, need to dispose of everything */
DisposeResultsRecord(results);
results->numRows = 0;
results->numCols = 0;
}
else
{
/* got at least one row */
/* adjust handle */
SetHandleSize(results->colData, myVars->endLastRowData);
SetHandleSize(results->colInfo, myVars->endLastRowInfo);
}
/* update currCol in snarf elem */
(**snarf).currCol = myVars->currCol;
/* roll back types array to current column */
SetHandleSize(oldResults->colTypes,
(long)((myVars->currCol+1) * sizeof(DBType)));
}
else
{
/* we got all the data successfully, so we don't need the old results */
DisposeResultsRecord(oldResults);
DisposPtr((Ptr)oldResults);
(**snarf).oldResults = NULL;
(**snarf).currCol = 0;
}
/* call status function, if specified */
myPB->result = CallStatusProc(myVars->statusProc, kDBGetQueryResultsComplete, myPB->result);
break;
} /* switch (myVars->currAction) */
/* copy result into application's parameter block */
asyncPB = myVars->asyncPB;
asyncPB->result = myPB->result;
/* remove pb from list */
RemovePB(myPB);
/* call application's completion routine, if any */
if (asyncPB->completionProc != NULL)
{
/* have to use assembly glue to get pb into A0 */
CallCompletion(asyncPB);
}
return(noErr);
} /* AllDoneProc() */
/*FORM_FEED*/
/*
*
* OBJECT: BuildDDEVList
*
* DESCRIPTION: Searches ddev folder for ddevs and builds list.
* Thanks to Tech Notes 67 and 68. (Will this work with aliases?)
*
* INPUTS: root: Pointer to root of ddev list.
*
* OUTPUTS: root: Pointer to root of filled in ddev list.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
BuildDDEVList(ddevElemHndl *root)
{
short index = 1;
OSErr err;
short vRefNum;
long dirID;
CInfoPBRec myCPB;
char fName[64];
/* first, mark all current ddevs as not existing in case one was deleted */
ClearDDEVList(*root);
/* get vRefNum and dirID of folder with ddevs */
GetDDEVFolder(&vRefNum, &dirID);
do
{
/* fix for bug DSL-004 - look in ddev folder for ddevs */
fName[0] = '\0';
myCPB.hFileInfo.ioNamePtr = fName;
myCPB.hFileInfo.ioVRefNum = vRefNum; /* folder with ddevs (DSL-004) */
myCPB.hFileInfo.ioFDirIndex = index;
myCPB.hFileInfo.ioDirID = dirID; /* using real vRefNum and dirID */
err = PBGetCatInfo(&myCPB, false);
if (err == noErr)
{
if (((myCPB.hFileInfo.ioFlAttrib >> 4) & 0x01) != 1)
{
/* this is a file, not a folder */
/* check for ddev file type */
if (myCPB.hFileInfo.ioFlFndrInfo.fdType == DDEVTYPE)
{
/* ddev file, add to list */
AddDDEVFile(fName, vRefNum, dirID, root);
}
}
/* get next file */
index++;
}
else if (err != fnfErr)
{
/* some other error occurred, just purge list and return */
PurgeDDEVList(root);
return;
}
} while (err != fnfErr);
/* get rid of any ddevs that were deleted */
PurgeDDEVList(root);
} /* BuildDDEVList() */
/*FORM_FEED*/
/*
*
* OBJECT: ClearDDEVList
*
* DESCRIPTION: Sets "exists" to FALSE in all ddev elements in list.
* Called just before rebuilding list.
*
* INPUTS: root: Root of ddev list.
*
* OUTPUTS: None.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-26-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
ClearDDEVList(ddevElemHndl root)
{
ddevElemHndl curr;
curr = root;
while (curr)
{
(**curr).exists = false;
curr = (**curr).next;
}
} /* ClearDDEVList() */
/*FORM_FEED*/
/*
*
* OBJECT: PurgeDDEVList
*
* DESCRIPTION: Deletes all elements in ddev list with "exists" set to FALSE.
*
* INPUTS: root: Pointer to root of ddev list.
*
* OUTPUTS: root: Pointer to root of purged ddev list.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-26-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
PurgeDDEVList(ddevElemHndl *root)
{
ddevElemHndl curr, next, prev;
ddevElem *p;
curr = *root;
prev = NULL;
while (curr != NULL)
{
if ((**curr).exists == false)
{
/* check if we're removing the root */
if (curr == *root)
*root = (**curr).next;
next = (**curr).next;
/* get rid of string pointers */
HLock((Handle)curr);
p = *curr;
if (p->name)
DisposPtr(p->name);
if (p->fname)
DisposPtr(p->fname);
HUnlock((Handle)curr);
DisposHandle((Handle)curr);
curr = next;
if (prev != NULL)
(**prev).next = curr;
}
else
{
prev = curr;
curr = (**curr).next;
}
}
} /* PurgeDDEVList() */
/*FORM_FEED*/
/*
*
* OBJECT: AddDDEVFile
*
* DESCRIPTION: Adds specified ddev file to list, if it's not there already.
*
* INPUTS: fname: Name of file
* vRefNum: vRefNum of folder with ddevs.
* dirID: dirID of folder with ddevs.
* root: Pointer to root of list.
*
* OUTPUTS: root: Pointer to root of list with file added.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
AddDDEVFile(const Str255 fname, short vRefNum, long dirID, ddevElemHndl *root)
{
ddevElem **curr, *currptr;
char currState;
char **ddevNameRes;
short refNum;
DDEVFlags **flagsRes;
Boolean canAsync;
char ddevName[64];
/* first, search to see if file exists in list already */
curr = *root;
while (curr)
{
MyHLock((Handle)curr, &currState);
/* problem - can't use IUCompString at patch time */
if ((IUCompString((**curr).fname, fname) == 0) &&
((**curr).vRefNum == vRefNum) && ((**curr).dirID == dirID))
{
/* file name already exists, set exists and return */
(**curr).exists = true;
HSetState((Handle)curr, currState);
return;
}
HSetState((Handle)curr, currState);
curr = (**curr).next;
}
/* file not in list already, open it to get STR resource */
refNum = HOpenResFile(vRefNum, dirID, fname, fsRdWrPerm);
if (refNum != -1)
{
/* file open, get STR resource with name */
ddevNameRes = (char**)Get1Resource('STR ', kDDEVName);
if (ddevNameRes != NULL)
{
/* save ddev name - note that not locking ddevNameRes depends on pstrcpy just doing BlockMove */
// HLock((Handle)ddevNameRes);
pstrcpy(ddevName, *ddevNameRes);
// HUnlock((Handle)ddevNameRes);
/* get 'dflg' resource to check async support */
flagsRes = (DDEVFlags**)Get1Resource(DDEVFLAGRESTYPE, kDDEVFlags);
if (flagsRes)
{
canAsync = ((**flagsRes).flags & kAsyncSupported) != 0;
}
else
{
/* no resource, assume we can't do async */
canAsync = false;
}
/* see if we already have a ddev with this name */
if (FindDDEV(ddevName, *root) == NULL)
{
/* no, we have a valid ddev, add it to the list */
curr = (ddevElemHndl)NewHandleSysClear(sizeof(ddevElem));
HLock((Handle)curr);
currptr = *curr;
currptr->next = *root;
currptr->exists = true;
/* allocate string pointers */
currptr->name = (char*)NewPtrSysClear(ddevName[0] + 1);
currptr->fname = (char*)NewPtrSysClear(fname[0] + 1);
pstrcpy(currptr->name, ddevName);
pstrcpy(currptr->fname, fname);
currptr->vRefNum = vRefNum;
currptr->dirID = dirID;
currptr->canAsync = canAsync;
HUnlock((Handle)curr);
/* insert into list */
*root = curr;
}
}
CloseResFile(refNum);
}
} /* AddDDEVFile() */
/*FORM_FEED*/
/*
*
* OBJECT: FindAndBuildDDEV
*
* DESCRIPTION: Looks for ddev with specified name in specified list.
* If not found, tries to rebuild the list again and find it.
* Called by SMInit and SMGetConnInfo.
*
* INPUTS: name: Name of ddev from STR resource. This is
* a Pascal string.
* rootPtr: Pointer to root of list.
*
* OUTPUTS: None.
*
* RETURNS: Handle to ddevElem, or NULL if none found.
*
* MODIFICATIONS:
* 03-30-90 JSM - Created.
*
* Copyright Apple Computer, Inc. 1990
* All rights reserved.
*
*/
ddevElemHndl
FindAndBuildDDEV(char *name, ddevElemHndl *rootPtr)
{
register ddevElemHndl ddevH;
/* look for ddevElem with specified ddevName */
ddevH = FindDDEV(name, *rootPtr);
if (ddevH == NULL)
{
/*
We couldn't find the specified ddev. This means that either
this is the first time DBInit or DBGetConnInfo was called, or
the ddev doesn't exist. Of course, the user may have installed
the ddev since the last time we built the list. Question:
What about ddevs that have INIT code in them? Answer: The
user is hosed if he installs them without rebooting.
*/
BuildDDEVList(rootPtr);
/* try again */
ddevH = FindDDEV(name, *rootPtr);
}
return(ddevH);
} /* FindAndBuildDDEV() */
/*FORM_FEED*/
/*
*
* OBJECT: FindDDEV
*
* DESCRIPTION: Looks for ddev with specified name in specified list.
*
* INPUTS: name: Name of ddev from STR resource. This is
* a Pascal string.
* root: Root of list.
*
* OUTPUTS: None.
*
* RETURNS: Handle to ddevElem, or NULL if none found.
*
* MODIFICATIONS:
* 03-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
ddevElemHndl
FindDDEV(char *name, ddevElemHndl root)
{
ddevElemHndl curr = root;
char currState;
while (curr)
{
MyHLock((Handle)curr, &currState);
if ((**curr).exists && (IUCompString(name, (**curr).name) == 0))
{
/* found ddev */
HSetState((Handle)curr, currState);
return(curr);
}
HSetState((Handle)curr, currState);
curr = (**curr).next;
}
/* couldn't find ddev */
return(NULL);
} /* FindDDEV() */
/*FORM_FEED*/
/*
*
* OBJECT: OpenDDEVFile
*
* DESCRIPTION: Opens specified DDEV file. File is opened in the system heap.
*
* INPUTS: ddevH: Handle to ddevElem to open.
*
* OUTPUTS: refNum: refNum of open file.
*
* RETURNS: Errors from OpenRFPerm.
*
* MODIFICATIONS:
* 03-26-89 JSM - Created.
* 11-07-89 JSM - Use HOpenResFile.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
OpenDDEVFile(ddevElemHndl ddevH, short *refNum)
{
ddevElemPtr ddevP;
short rc;
THz currZone;
char currState;
/* save current zone */
currZone = GetZone();
/* make sure current zone is System Heap */
SetZone(SystemZone());
MyHLock((Handle)ddevH, &currState);
ddevP = *ddevH;
/* open the ddev */
*refNum = HOpenResFile(ddevP->vRefNum, ddevP->dirID,
ddevP->fname, fsRdWrPerm);
rc = RESERR;
HSetState((Handle)ddevH, currState);
/* restore zone */
SetZone(currZone);
/* return any error from OpenRFPerm */
return(rc);
} /* OpenDDEVFile() */
/*FORM_FEED*/
/*
*
* OBJECT: CallDDEV
*
* DESCRIPTION: Calls specified ddev with specified parameter block.
* If an async call is indicated, checks to see if ddev
* will support it. Also sets up ddevStorage in DDEVParams.
* All calls to ddevs pass through here!
*
* INPUTS: ddevH: Handle to ddevElem with info.
* params: Pointer to parameter block for ddev.
*
* OUTPUTS: ddevH: Data may be changed.
*
* RETURNS: rcDBAsyncNotSupp
* Errors from ddev.
*
* MODIFICATIONS:
* 05-23-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
CallDDEV(ddevElemHndl ddevH, DDEVParams *params)
{
ddevElemPtr ddevP;
short rc;
char currState;
MyHLock((Handle)ddevH, &currState);
ddevP = *ddevH;
/* check if we need to support async */
if (params->asyncPB)
{
if (!ddevP->canAsync)
{
/* ddev doesn't support async */
HSetState((Handle)ddevH, currState);
return(rcDBAsyncNotSupp);
}
else
{
/* asynchronous call, we need to save ddev handle
in case of a later DBKill */
((asyncVarsPtr)(params->asyncPB->reserved))->ddevH = ddevH;
}
}
/* pass in storage */
params->ddevStorage = ddevP->ddevStorage;
/* call ddev with specified parameter block */
rc = ((DDEVPtr)StripAddress((Ptr)*(ddevP->ddev)))(params);
/* save ddev's storage for him */
ddevP->ddevStorage = params->ddevStorage;
HSetState((Handle)ddevH, currState);
return(rc);
} /* CallDDEV() */
/*FORM_FEED*/
/*
*
* OBJECT: GetUniqueSnarfID
*
* DESCRIPTION: Returns a unique SnarfMan session ID. Assumes list is ordered.
*
* INPUTS: root: Root of Snarf session list.
*
* OUTPUTS: None.
*
* RETURNS: Unique ID, always greater than 0.
*
* MODIFICATIONS:
* 03-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
long
GetUniqueSnarfID(snarfSessElemHndl root)
{
long id = 1;
Boolean done = false, found;
snarfSessElemHndl curr;
while (true)
{
/* search list for current ID */
curr = root;
found = false;
while (curr && !found)
{
/* see if the current cell matches the id */
if ((**curr).snarfID == id)
{
/* yes, need to try again */
found = true;
}
else
{
/* see if the current cell is greater than the id */
if ((**curr).snarfID > id)
{
/* yes, we can use this id */
return(id);
}
else
{
curr = (**curr).next;
}
}
}
if (!found)
{
/* no matching id found */
return(id);
}
/* id already in use, try again */
id++;
}
} /* GetUniqueSnarfID() */
/*FORM_FEED*/
/*
*
* OBJECT: FindSnarfID
*
* DESCRIPTION: Looks for cell with specified snarf ID in specified list.
*
* INPUTS: id: ID of cell to look for.
* root: Root of list.
*
* OUTPUTS: None.
*
* RETURNS: Handle to snarfSessElem, or NULL if none found.
*
* MODIFICATIONS:
* 03-26-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
snarfSessElemHndl
FindSnarfID(long id, snarfSessElemHndl root)
{
snarfSessElemHndl curr = root;
while (curr)
{
if ((**curr).snarfID == id)
{
/* found ID */
return(curr);
}
curr = (**curr).next;
}
/* couldn't find ID */
return(NULL);
} /* FindSnarfID() */
/*FORM_FEED*/
/*
*
* OBJECT: ConvertSessIDToSnarfID
*
* DESCRIPTION: Convert ddev specific session ID to global Snarf ID.
*
* INPUTS: sessID: Session ID to convert.
* ddevH: ddev which owns session.
*
* OUTPUTS: None.
*
* RETURNS: Snarf ID, or 0 if no match.
*
* MODIFICATIONS:
* 08-28-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
long
ConvertSessIDToSnarfID(long sessID, ddevElemHndl ddevH)
{
sessElemHndl sessH;
snarfSessElemHndl snarfH;
snarfGlobPtr glob;
Boolean found;
found = false;
sessH = (**ddevH).sessRoot;
/* look for session cell hung off of ddev */
while (sessH && !found)
{
if ((**sessH).sessID == sessID)
found = true;
else
sessH = (**sessH).next;
}
if (!found)
/* bad session ID */
return(0);
/* now, scan for this session cell in the snarf list */
found = false;
glob = GetGlobals();
snarfH = glob->snarfRoot;
while (snarfH && !found)
{
if ((**snarfH).sess == sessH)
found = true;
else
snarfH = (**snarfH).next;
}
if (!found)
/* bad session ID */
return(0);
else
return((**snarfH).snarfID);
} /* ConvertSessIDToSnarfID() */
/*FORM_FEED*/
/*
*
* OBJECT: InsertSessionCell
*
* DESCRIPTION: Inserts a session cell into a ddev's list.
*
* INPUTS: root: Handle to root of ddev session list.
* cell: Session cell to insert.
*
* OUTPUTS: root: May be modified.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
InsertSessionCell(sessElemHndl *root, sessElemHndl cell)
{
/* just stick it at the front for now */
(**cell).next = *root;
*root = cell;
} /* InsertSessionCell() */
/*FORM_FEED*/
/*
*
* OBJECT: InsertSnarfCell
*
* DESCRIPTION: Inserts a Snarf session cell into global list.
*
* INPUTS: root: Handle to root of global list.
* cell: Session cell to insert.
*
* OUTPUTS: root: May be modified.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
InsertSnarfCell(snarfSessElemHndl *root, snarfSessElemHndl cell)
{
snarfSessElemHndl curr, last = NULL;
Boolean done = false;
curr = *root;
if (curr == NULL)
{
/* first cell in list */
*root = cell;
return;
}
/* list is ordered numerically */
while (curr && !done)
{
if ((**cell).snarfID > (**curr).snarfID)
{
/* cell goes after curr */
last = curr;
curr = (**curr).next;
}
else
{
/* cell goes before curr */
done = true;
}
}
if (last)
{
/* not adding at root */
(**cell).next = (**last).next;
(**last).next = cell;
}
else
{
(**cell).next = curr;
*root = cell;
}
} /* InsertSnarfCell() */
/*FORM_FEED*/
/*
*
* OBJECT: MakePB
*
* DESCRIPTION: Allocate and initialize a DBAsyncParamBlockRec and its associated
* async variables. We need our own parameter block for every
* async call.
*
* INPUTS: params: DDEVParams to copy.
* asyncPB: DBAsyncParmBlkPtr passed in by application.
*
* OUTPUTS: None.
*
* RETURNS: Pointer to created asyncPB.
*
* MODIFICATIONS:
* 06-29-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
DBAsyncParmBlkPtr
MakePB(DDEVParamsPtr params, DBAsyncParmBlkPtr asyncPB)
{
snarfGlobPtr glob;
DBAsyncParmBlkPtr myPB;
asyncVarsPtr myVars;
glob = GetGlobals();
/* allocate space */
myPB = (DBAsyncParmBlkPtr)NewPtrSysClear(sizeof(DBAsyncParamBlockRec));
myVars = (asyncVarsPtr)NewPtrSysClear(sizeof(asyncVars));
/* make myPB point to variables */
myPB->reserved = (long)myVars;
/* set up completion routine */
myPB->completionProc = (ProcPtr)StripAddress(*(glob->completionRes));
/* keep track of application's asyncPB */
myVars->asyncPB = asyncPB;
/* app made call asynchronously, set result */
asyncPB->result = 1;
/* assume that this is not a high level call */
myVars->highlevel = false;
/* call about to be executing, so tell DBIdle to ignore it */
myVars->executing = true;
if (params)
{
myVars->params = (DDEVParamsPtr)NewPtrSysClear(sizeof(DDEVParams));
/* copy ddev parameters */
BlockMove((Ptr)params, (Ptr)myVars->params, sizeof(DDEVParams));
/* we want ddev to use our asyncPB */
(myVars->params)->asyncPB = myPB;
/* set current action */
myVars->currAction = params->message;
}
return(myPB);
} /* MakePB() */
/*FORM_FEED*/
/*
*
* OBJECT: InsertPB
*
* DESCRIPTION: Inserts a DBAsyncParmBlkPtr into the global list.
*
* Declared as a pascal function because compiler generates smaller code.
*
* INPUTS: asyncPB: Pointer to pb to insert.
*
* OUTPUTS: None.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 06-12-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal void
InsertPB(DBAsyncParmBlkPtr asyncPB)
{
snarfGlobPtr glob;
glob = GetGlobals();
/* just put it at the front of the list */
((asyncVarsPtr)(asyncPB->reserved))->next = glob->pbRoot;
glob->pbRoot = asyncPB;
} /* InsertPB() */
/*FORM_FEED*/
/*
*
* OBJECT: RemovePB
*
* DESCRIPTION: Removes a DBAsyncParmBlkPtr from the global list.
* Disposes of the memory used by it and its variables.
*
* Declared as a pascal function because compiler generates smaller code.
*
* INPUTS: asyncPB: Pointer to pb to remove.
*
* OUTPUTS: None.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 06-12-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal void
RemovePB(DBAsyncParmBlkPtr asyncPB)
{
snarfGlobPtr glob;
asyncVarsPtr myVars, lastVars;
DBAsyncParmBlkPtr curr, last;
glob = GetGlobals();
last = NULL;
curr = glob->pbRoot;
while (curr && (curr != asyncPB))
{
last = curr;
myVars = (asyncVarsPtr)curr->reserved;
curr = myVars->next;
}
if (curr)
{
/* fix up list */
myVars = (asyncVarsPtr)curr->reserved;
if (last)
{
lastVars = (asyncVarsPtr)last->reserved;
lastVars->next = myVars->next;
}
else
{
/* replacing root */
glob->pbRoot = myVars->next;
}
/* dispose of variables and pb */
if (myVars->params)
DisposPtr((Ptr)(myVars->params));
DisposPtr((Ptr)myVars);
DisposPtr((Ptr)asyncPB);
}
} /* RemovePB() */
/*FORM_FEED*/
/*
*
* OBJECT: FindAppPB
*
* DESCRIPTION: Finds the parameter block in the global list that has
* the specified PB in the "asyncPB" field of its async variables.
*
* INPUTS: appPB: Pointer to pb to find.
*
* OUTPUTS: None.
*
* RETURNS: PB with appPB, or NULL if none found.
*
* MODIFICATIONS:
* 07-28-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
DBAsyncParmBlkPtr
FindAppPB(DBAsyncParmBlkPtr appPB)
{
snarfGlobPtr glob;
asyncVarsPtr myVars;
DBAsyncParmBlkPtr realPB, curr;
glob = GetGlobals();
realPB = NULL;
curr = glob->pbRoot;
while (curr && !realPB)
{
/* get variables for this PB */
myVars = (asyncVarsPtr)curr->reserved;
/* check if it points to the application's PB */
if (myVars->asyncPB == appPB)
/* yes, return it */
realPB = curr;
curr = myVars->next;
}
return(realPB);
} /* FindAppPB() */
/*FORM_FEED*/
/*
*
* OBJECT: GetDDEVFolder
*
* DESCRIPTION: Returns vRefNum and dirID of folder with ddevs. This is
* the Extensions Folder.
*
* INPUTS: vRefNum: Pointer where vRefNum is returned.
* dirID: Pointer where dirID is returned.
*
* OUTPUTS: vRefNum: Filled in.
* dirID: Filled in.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 05-23-89 JSM - Created.
* 11-07-89 JSM - Modified to return dirID.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
void
GetDDEVFolder(short *vRefNum, long *dirID)
{
/*
Find the Extensions Folder on the current system disk,
creating it if necessary, and ignoring errors.
*/
FindFolder(kOnSystemDisk, kExtensionFolderType, kCreateFolder,
vRefNum, dirID);
} /* GetDDEVFolder() */
/*FORM_FEED*/
/*
*
* OBJECT: InitResultsRecord
*
* DESCRIPTION: Initialize fields of specified ResultsRecord. Allocates
* empty handles and sets numRows and numCols to 0.
*
* INPUTS: results: Pointer to ResultsRecord.
* inSysHeap: If TRUE, handles allocated in sys heap.
*
* OUTPUTS: results: ResultsRecord initilized.
*
* RETURNS: Errors from NewHandle.
*
* MODIFICATIONS:
* 09-11-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
InitResultsRecord(ResultsRecord *results, Boolean inSysHeap)
{
short rc;
/* zero out whole record first */
mymemclear((char*)results, sizeof(ResultsRecord));
/* allocate empty handles initially */
if (inSysHeap)
results->colTypes = NewHandleSys(NULL);
else
results->colTypes = NewHandle(NULL);
if ((rc = MemError()) == noErr)
{
if (inSysHeap)
results->colData = NewHandleSys(NULL);
else
results->colData = NewHandle(NULL);
if ((rc = MemError()) == noErr)
{
if (inSysHeap)
results->colInfo = NewHandleSys(NULL);
else
results->colInfo = NewHandle(NULL);
rc = MemError();
}
}
if (rc != noErr)
{
/* error occurred on one of the NewHandles */
/* may need to clean up colTypes and/or colData */
if (results->colTypes)
{
DisposHandle(results->colTypes);
results->colTypes = NULL;
if (results->colData)
{
DisposHandle(results->colData);
results->colData = NULL;
}
}
}
return(rc);
} /* InitResultsRecord() */
/*FORM_FEED*/
/*
*
* OBJECT: GrowResultsRecord
*
* DESCRIPTION: Grows handles in specified ResultsRecord in preparation
* for new data. If an error occurs at any time, rolls
* back any changes.
*
* INPUTS: results: Pointer to ResultsRecord.
* len: Length of data about to be added.
* inFirstRow: If TRUE, in first row, and colTypes
* will be grown.
*
* OUTPUTS: results: ResultsRecord with expanded handles.
*
* RETURNS: Errors from SetHandleSize.
*
* MODIFICATIONS:
* 11-29-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
GrowResultsRecord(ResultsRecord *results, short len, Boolean inFirstRow)
{
short rc;
Handle dataH, infoH, typeH;
Boolean dataGrown, infoGrown;
/* we haven't grown anything yet */
dataGrown = false;
infoGrown = false;
/* grow data handle */
dataH = results->colData;
SetHandleSize(dataH, GetHandleSize(dataH) + (long)len);
if ((rc = MemError()) == noErr)
{
/* data handle grown OK, grow length handle */
dataGrown = true;
infoH = results->colInfo;
SetHandleSize(infoH, GetHandleSize(infoH) + sizeof(DBColInfoRecord));
rc = MemError();
}
/* if we're in the first row, have to grow dataType array */
if (inFirstRow && (rc == noErr))
{
/* info handle grown OK */
infoGrown = true;
typeH = results->colTypes;
SetHandleSize(typeH, GetHandleSize(typeH) + sizeof(DBType));
rc = MemError();
}
if (rc != noErr)
{
/* an error occurred, roll back to original sizes */
if (dataGrown)
SetHandleSize(dataH, GetHandleSize(dataH) - (long)len);
if (infoGrown)
SetHandleSize(infoH, GetHandleSize(infoH) - sizeof(DBColInfoRecord));
}
return(rc);
} /* GrowResultsRecord() */
/*FORM_FEED*/
/*
*
* OBJECT: SetupResults
*
* DESCRIPTION: Common code for both synchronous and asynchronous
* DBGetQueryResults. Initializes user results and
* copies over any old results.
*
* INPUTS: sessID: ID of current session.
* snarf: Pointer for snarfSessElemHndl.
* results: Pointer for user's ResultsRecord.
* oldResults: Pointer for old ResultsRecord pointer.
* currOffset: Pointer for currOffset.
* currCol: Pointer for currCol.
*
* OUTPUTS: snarf: Filled in with snarfSessElemHndl.
* results: Initialized user results with any old data.
* oldResults: Allocated, if necessary, and initialized.
* currOffset: Set up based on oldResults.
* currCol: Set up based on oldResults.
*
* RETURNS: rcDBBadSessID
* Errors from InitResultsRecord, NewPtrSys, and SetHandleSize.
*
* MODIFICATIONS:
* 12-06-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
OSErr
SetupResults(long sessID, snarfSessElemHndl *snarfPtr, ResultsRecord *results,
ResultsRecord **oldResultsPtr, long *currOffset, short *currCol)
{
snarfSessElem **snarf;
short rc;
Handle typeH, dataH, infoH;
ResultsRecord *oldResults;
long oldTypesLen, oldDataLen, oldInfoLen;
/* find snarf ID */
if ((snarf = *snarfPtr = FindSnarfID(sessID, (GetGlobals())->snarfRoot))
== NULL)
{
/* bad session ID */
/* this should never happen, or the DBState would have failed */
rc = rcDBBadSessID;
}
else
{
/* initialize results in app heap */
rc = InitResultsRecord(results, false);
}
if (rc == noErr)
{
typeH = results->colTypes;
dataH = results->colData;
infoH = results->colInfo;
/* see if there are any old results */
if ((**snarf).oldResults == NULL)
{
/* there were no previous results that weren't returned */
/* allocate empty ResultsRecord to keep old results */
oldResults = *oldResultsPtr =
(ResultsRecord*)NewPtrSys(sizeof(ResultsRecord));
if ((rc = MemError()) == noErr)
{
/* initialize old results in sys heap */
rc = InitResultsRecord(oldResults, true);
}
if (rc != noErr)
{
/* error allocating or initializing ResultsRecord */
if (oldResults)
DisposPtr((Ptr)oldResults);
/* dispose of user's ResultsRecord */
DisposeResultsRecord(results);
}
else
{
/* save results */
(**snarf).oldResults = oldResults;
/* we're starting at the beginning */
*currCol = 0;
*currOffset = 0;
}
}
else
{
/* there were some old results, copy them to the user */
oldResults = *oldResultsPtr = (**snarf).oldResults;
/* we're starting in the middle of a row */
*currCol = (**snarf).currCol;
/* grow handles accordingly */
SetHandleSize(typeH,
oldTypesLen = GetHandleSize(oldResults->colTypes));
rc = MemError();
if (rc == noErr)
{
SetHandleSize(dataH,
oldDataLen = GetHandleSize(oldResults->colData));
rc = MemError();
}
if (rc == noErr)
{
/* point to end of data */
*currOffset = oldDataLen;
SetHandleSize(infoH,
oldInfoLen = GetHandleSize(oldResults->colInfo));
rc = MemError();
}
if (rc == noErr)
{
/* move in stuff */
BlockMove(*(oldResults->colTypes), *typeH,
oldTypesLen);
BlockMove(*(oldResults->colData), *dataH,
oldDataLen);
BlockMove(*(oldResults->colInfo), *infoH,
oldInfoLen);
}
else
{
/* an error occurred trying to resize handles */
/* dispose of user's ResultsRecord */
DisposeResultsRecord(results);
}
}
}
return(rc);
} /* SetupResults() */
/*FORM_FEED*/
/*
*
* OBJECT: DisposeResultsRecord
*
* DESCRIPTION: Dispose of handles inside a results record.
* Assumes all handles are allocated.
*
* Declared as a pascal function because compiler generates smaller code.
*
* INPUTS: results: Pointer to results to be disposed of.
*
* OUTPUTS: results: colTypes, colData, colInfo are all nulled.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 12-06-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal void
DisposeResultsRecord(ResultsRecord *results)
{
DisposHandle(results->colTypes);
DisposHandle(results->colData);
DisposHandle(results->colInfo);
results->colTypes = NULL;
results->colData = NULL;
results->colInfo = NULL;
} /* DisposeResultsRecord() */
/*FORM_FEED*/
/*
*
* OBJECT: CallStatusProc
*
* DESCRIPTION: Common code to call a status function passed into DBStartQuery or
* DBGetQueryResults with no extra parameters.
*
* INPUTS: statusProc: Pointer to status function passed in by application.
* If NULL, does not call it (obviously).
* message: Message for status function.
* rc: Result for status function.
*
* OUTPUTS: None.
*
* RETURNS: userCanceledErr if status function returns false, otherwise
* original rc passed in.
*
* MODIFICATIONS:
* 04-23-90 JSM - Created.
*
* Copyright Apple Computer, Inc. 1990
* All rights reserved.
*
*/
OSErr
CallStatusProc(statusPtr statusProc, short message, OSErr rc)
{
if (statusProc != NULL)
{
if (!statusProc(message, rc, NULL, NULL, NULL, NULL, NULL))
{
/* status function cancelled */
rc = userCanceledErr;
}
}
/* return original rc or userCanceledErr */
return(rc);
} /* CallStatusProc() */
/*FORM_FEED*/
/*
*
* OBJECT: MyHLock
*
* DESCRIPTION: Smart handle locking. Saves current state of handle, then locks
* it. Just call HSetState to restore.
*
* Declared as a pascal function because compiler generates smaller code.
*
* INPUTS: h: Handle to be locked.
*
* OUTPUTS: state: State of handle before locking.
*
* RETURNS: Nothing.
*
* MODIFICATIONS:
* 03-24-89 JSM - Created.
*
* Copyright Apple Computer, Inc. 1989
* All rights reserved.
*
*/
pascal void
MyHLock(Handle h, char *state)
{
*state = HGetState(h);
HLock(h);
} /* MyHLock() */