mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
333 lines
7.6 KiB
C
333 lines
7.6 KiB
C
/*
|
|
File: Utilities.c
|
|
|
|
Contains: Utility routines that could be recoded in assembler for performance
|
|
|
|
Written by: Phil Goldman
|
|
|
|
Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<5> 3/23/92 JSM OSEvents.h is obsolete, use Events.h instead.
|
|
<4> 1/10/91 DFH Updated copyright years.
|
|
<3> 11/1/90 DFH Correct prototyping for DebuggerMsg().
|
|
<2> 10/31/90 DFH Got rid of warnings.
|
|
<1> 10/22/90 DFH First checked in.
|
|
<0> 12/15/86 PYG New Today.
|
|
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <quickdraw.h>
|
|
#include <memory.h>
|
|
#include <resources.h>
|
|
#include <toolutils.h>
|
|
#include <events.h>
|
|
|
|
#include "Glue.h"
|
|
#include "Lomem.h"
|
|
#include "Data.h"
|
|
|
|
#pragma segment kernel_segment
|
|
|
|
Handle GetRsrcHdlMatchingFirstLongword(long, long);
|
|
|
|
#ifdef MSWORKS_FIX
|
|
/* Set up app patch addr.
|
|
* NOTE: Assumes a5 == PROCESSMGRGLOBALS.
|
|
*/
|
|
ProcPtr
|
|
SetOverlayRecoverHandle(ProcPtr apptrap)
|
|
{
|
|
void OverlayRecoverHandle(void);
|
|
|
|
(*pCurrentProcess->p_pcb)->appRecoverHandlePatch = apptrap;
|
|
return ((ProcPtr) OverlayRecoverHandle);
|
|
}
|
|
|
|
ProcPtr
|
|
GetOverlayRecoverHandleOldTrap(void)
|
|
{
|
|
unsigned long olda5;
|
|
ProcPtr appRecoverHandlePatch;
|
|
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
appRecoverHandlePatch = (*pCurrentProcess->p_pcb)->appRecoverHandlePatch;
|
|
A5SimpleRestore(olda5);
|
|
|
|
return appRecoverHandlePatch;
|
|
}
|
|
#endif MSWORKS_FIX
|
|
|
|
/* MemClear. Two-bit routine to clear 'bytes' bytes starting at *'ptr' */
|
|
void
|
|
MemClear(register Ptr ptr, register unsigned long bytes)
|
|
{
|
|
do
|
|
{
|
|
*ptr++ = (char) 0x00;
|
|
}
|
|
while (--bytes != 0);
|
|
|
|
}
|
|
|
|
/* StripLeadingNulls. Can you guess what it does?
|
|
* NOTE: It sets the last leading NULL to the length of the rest of the string,
|
|
* thereby altering the original string. Be careful! But you CAN restore
|
|
* the string by storing a NULL byte through the function result.
|
|
*/
|
|
StringPtr
|
|
StripLeadingNulls(StringPtr pString)
|
|
{
|
|
register Ptr pChar;
|
|
register unsigned char strSize;
|
|
|
|
strSize = Length(pString);
|
|
pChar = &StringByte(pString, 0);
|
|
while ((strSize != 0) && (*pChar == NULL))
|
|
{
|
|
--strSize;
|
|
pChar++;
|
|
}
|
|
|
|
if (strSize != Length(pString))
|
|
{
|
|
pString = (StringPtr) (--pChar);
|
|
Length(pString) = strSize;
|
|
}
|
|
|
|
return(pString);
|
|
}
|
|
|
|
/* NewMungedString. Copy pProtoStr into a NewString, and replace the 0th
|
|
* parameter substring with pSubStr.
|
|
*/
|
|
Handle
|
|
NewMungedString(StringPtr pSubStr, StringPtr pProtoStr)
|
|
{
|
|
unsigned long ParamZeroStr = TWO_CHAR_STRING('^','0');
|
|
StringPtr ptr1, ptr2;
|
|
unsigned long len1,len2;
|
|
StringHandle retVal;
|
|
|
|
if ((retVal = NewString(pProtoStr)) != nil)
|
|
{
|
|
ptr1 = (StringPtr) &ParamZeroStr;
|
|
len1 = (unsigned long) Length(ptr1);
|
|
ptr1 = &StringByte(ptr1, 0);
|
|
len2 = (long) Length(pSubStr);
|
|
ptr2 = &StringByte(pSubStr, 0);
|
|
(void)Munger(retVal,0,ptr1,len1,ptr2,len2);
|
|
if (MEMERROR == noErr)
|
|
Length((*retVal)) += len2 - len1;
|
|
else
|
|
{
|
|
DisposHandle(retVal);
|
|
retVal = nil;
|
|
}
|
|
}
|
|
return (retVal);
|
|
}
|
|
|
|
/* StrInStrList. Use specified function to check whether the specified string is
|
|
* "in" the specified list of strings.
|
|
*/
|
|
StringPtr
|
|
StrInStrList(Ptr strPtr, Ptr strListPtr, short cStrings, RelStringGluePtr relStringGluePtr)
|
|
{
|
|
while (--cStrings >= 0)
|
|
{
|
|
if ((*relStringGluePtr)(strListPtr, strPtr) == 0)
|
|
return(strListPtr);
|
|
strListPtr += Length(strListPtr) + 1;
|
|
}
|
|
|
|
return(nil);
|
|
}
|
|
|
|
/* GetRsrcHdlMatchingFirstLongword. Find the first resource of specified type that
|
|
* has the given value in its first long word. Scope is the entire resource chain.
|
|
*/
|
|
Handle
|
|
GetRsrcHdlMatchingFirstLongword(long resType, long firstLong)
|
|
{
|
|
Handle hdl;
|
|
short resIndex, resLast;
|
|
|
|
resLast = CountResources(resType);
|
|
for (resIndex = 1; resIndex <= resLast; resIndex++)
|
|
{
|
|
hdl = GetIndResource(resType, resIndex);
|
|
if (hdl != nil)
|
|
{
|
|
if (**((long **) hdl) == firstLong)
|
|
return (hdl);
|
|
ReleaseResource(hdl);
|
|
}
|
|
}
|
|
|
|
return (nil);
|
|
}
|
|
|
|
/* GetIconIDFromBundle. Figure out the icon family resource ID for the given type and
|
|
* creator. Starts at the current resource map. Uses the same search path that Finder
|
|
* does (FREF -> BNDL -> icon resource).
|
|
*/
|
|
short
|
|
GetIconIDFromBundle(OSType theType, unsigned long theCreator)
|
|
{
|
|
Ptr pRsrc;
|
|
short typeIndex, icnIndex;
|
|
Handle rsrcHdl;
|
|
short localID, globalID;
|
|
|
|
/* Find the FREF of the type */
|
|
rsrcHdl = GetRsrcHdlMatchingFirstLongword('FREF', theType);
|
|
if (rsrcHdl == nil)
|
|
return(0);
|
|
|
|
pRsrc = *rsrcHdl + 4;
|
|
localID = *((short *) pRsrc);
|
|
ReleaseResource(rsrcHdl);
|
|
|
|
/* Get the BNDL */
|
|
rsrcHdl = GetRsrcHdlMatchingFirstLongword('BNDL', theCreator);
|
|
if (rsrcHdl == nil)
|
|
return(0);
|
|
|
|
pRsrc = *rsrcHdl + 6;
|
|
|
|
/* Major loop -- find global id of icon in bundle */
|
|
globalID = 0;
|
|
for (typeIndex = *((short *) pRsrc)++; typeIndex >= 0; typeIndex--)
|
|
{
|
|
/* Is this type ICN# ? */
|
|
if (*((long *) pRsrc)++ == 'ICN#')
|
|
{
|
|
/* Minor loop - find a match for our given local ID and get it */
|
|
for (icnIndex = *((short *) pRsrc)++; icnIndex >= 0; icnIndex--)
|
|
{
|
|
if (*((short *) pRsrc)++ == localID)
|
|
{
|
|
/* Found it! */
|
|
globalID = *((short *) pRsrc);
|
|
break;
|
|
}
|
|
|
|
pRsrc += 2;
|
|
}
|
|
|
|
/* Either we found it or we looked at all icons */
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* Skip over all of this type's resources, carefully because count
|
|
* is zero-based.
|
|
*/
|
|
((long *) pRsrc) += *((short *) pRsrc)++;
|
|
((long *) pRsrc)++;
|
|
}
|
|
}
|
|
|
|
/* Clean up and go */
|
|
ReleaseResource(rsrcHdl);
|
|
return(globalID);
|
|
}
|
|
|
|
/* OptionKeyIsDown. Figure out if the option-key is depressed. */
|
|
Boolean
|
|
OptionKeyIsDown(void)
|
|
{
|
|
EventRecord evtRecord;
|
|
|
|
(void) GetOSEvent(0, &evtRecord);
|
|
return((evtRecord.modifiers & optionKey) != 0);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* DebuggerMsg. Append message to file name and line number to and pass to debugger */
|
|
void
|
|
DebuggerMsg(char *cFileString, int debugLine, char *cMsgString)
|
|
{
|
|
register char *pch, *pch2;
|
|
Str255 totalMsgString;
|
|
static char assertFailureString[] = "Assertion Failure";
|
|
int len;
|
|
unsigned long olda5;
|
|
|
|
if (*((short *)0xF0) == 0x4E4F) /* 'NO' debugging */
|
|
return;
|
|
|
|
if (PROCESSMGRGLOBALS != (Ptr)(-1))
|
|
olda5 = ProcessMgrA5SimpleSetup();
|
|
|
|
/* Normalize C file string */
|
|
if (PROCESSMGRGLOBALS != (Ptr)(-1))
|
|
cFileString += ((long)PROCESSMGRGLOBALS - (long)olda5); /* Normalize this puppy (HAAAAAAACCK) */
|
|
|
|
/* Find length of file name (C string) */
|
|
len = 0;
|
|
pch = cFileString;
|
|
while (*pch++)
|
|
len++;
|
|
|
|
/* Stick it in buffer (P string) */
|
|
pch = &totalMsgString;
|
|
*pch++ = (char) (len + 5);
|
|
BlockMove(cFileString, pch, len);
|
|
pch += len;
|
|
*pch++ = '+';
|
|
|
|
/* Stick in the line number */
|
|
|
|
if (*pch = debugLine/1000)
|
|
{
|
|
debugLine -= (*pch)*1000;
|
|
*pch++ += '0';
|
|
Length(&totalMsgString)++;
|
|
}
|
|
|
|
if (*pch = debugLine/100)
|
|
{
|
|
debugLine -= (*pch)*100;
|
|
*pch++ += '0';
|
|
Length(&totalMsgString)++;
|
|
}
|
|
*pch = debugLine/10;
|
|
debugLine -= (*pch)*10;
|
|
*pch++ += '0';
|
|
*pch++ = debugLine + '0';
|
|
*pch++ = ':';
|
|
*pch++ = ' ';
|
|
|
|
/* Move in the old message */
|
|
if (cMsgString != NO_MESSAGE_ID)
|
|
{
|
|
if (cMsgString == ASSERTION_FAILURE_ID)
|
|
cMsgString = assertFailureString;
|
|
else
|
|
if (PROCESSMGRGLOBALS != (Ptr)(-1))
|
|
cMsgString += ((long)PROCESSMGRGLOBALS - (long)olda5); /* Normalize this puppy (HAAAAAAACCK) */
|
|
|
|
/* Find length of msg (C string) */
|
|
len = 0;
|
|
pch2 = cMsgString;
|
|
while (*pch2++)
|
|
len++;
|
|
|
|
/* Move it on in */
|
|
BlockMove(cMsgString, pch, len);
|
|
Length(&totalMsgString) += len;
|
|
}
|
|
|
|
/* Restore A5 */
|
|
if (PROCESSMGRGLOBALS != (Ptr)(-1))
|
|
A5SimpleRestore(olda5);
|
|
|
|
/* Call the trap (keep at end of routine so we can jump right back in flow of things) */
|
|
debugger(&totalMsgString);
|
|
}
|
|
#endif DEBUG
|