mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
211 lines
8.0 KiB
C
211 lines
8.0 KiB
C
/*
|
||
File: DialogMgrExtensions.c
|
||
|
||
Contains: C language portions of Dialog Mgr fixes
|
||
|
||
Written by: Kevin S. MacDonell
|
||
|
||
Copyright: © 1991-1992 by Apple Computer, Inc., all rights reserved.
|
||
|
||
Change History (most recent first):
|
||
|
||
<8> 11/3/92 DTY Script out unnecessary includes.
|
||
<7> 6/10/92 JSM Moved this file to DialogMgrExtensions.c from DialogMgrPatches.c
|
||
since it’s used by both the ROM and System, keeping all the old
|
||
revisions.
|
||
<6> 3/31/92 KSM #1021993,<DTY>: Exported CitationsCH (previously StdCitations)
|
||
call - now returns OSErr (for dispatcher). Created new calls:
|
||
Cite4 for easy-of-use, and the fully generic CitationsSH.
|
||
<5> 3/24/92 DTY #1021963,<KSM>: Take out last change since Kevin says it should
|
||
never have been rolled in. (It broke ParamText subsitution.)
|
||
<4> 3/4/92 KSM xxx: #1021963: Don't check the length byte as a character when
|
||
searching for a "^".
|
||
<3> 11/19/91 KSM #1016162: (forgot bug # for previous change)
|
||
<2> 11/19/91 KSM Remove ^# when paramtext field is NIL.
|
||
<1> 8/22/91 KSM first checked in
|
||
<0> 8/12/91 KSM New Today.
|
||
|
||
*/
|
||
|
||
#include <Memory.h>
|
||
#include <Script.h>
|
||
#include <TextEdit.h>
|
||
#include <TextUtils.h>
|
||
|
||
#include <DialogsPriv.h>
|
||
#include <ScriptPriv.h>
|
||
|
||
#define BITTST(bits, bitnum) (bits & (1<<(bitnum)))
|
||
#define BITCLR(bits, bitnum) (bits & ~(1<<(bitnum)))
|
||
|
||
#define CARETSTR 0x015E // This is a one char pascal string = '^'
|
||
#define DAStrings 0x0AA0 // Lomem for 4 consecutive string handles
|
||
#define NOPARSETBL -1 // Result if ParseTable is missing
|
||
|
||
typedef struct SSSS {
|
||
CharsHandle s;
|
||
short numCites;
|
||
CiteListPtr pcl;
|
||
CharByteTable table;
|
||
} SSSS;
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
// This routine is the fix to the way the Dialog Manager handles citation replacement.
|
||
// It fixes 2 problems: the recursive substitution infinite loop and the 2-byte '^' search.
|
||
|
||
pascal void ReplaceCitations(CharsHandle baseString)
|
||
{ // Handle the standard ParamText strings
|
||
short i;
|
||
StringHandle *sp;
|
||
StringPtr cl[4];
|
||
StringPtr *cs = &cl; // Save code by pointing into the array
|
||
|
||
// Get each DAString and lock it. Then put the stripped pointer/length into the CiteList.
|
||
sp = (StringHandle *)DAStrings;
|
||
for (i = 3; i >= 0; --i)
|
||
{
|
||
*cs = NULL; // Set the default value
|
||
if (*sp)
|
||
{
|
||
HLock((Handle)*sp); // Lock the handle so we can pass a ptr
|
||
*cs = (StringPtr)StripAddress((Ptr)**sp);
|
||
}
|
||
++sp; // Point to next string
|
||
++cs; // Point to next array loc
|
||
}
|
||
|
||
// Do the substitution(s), then unlock those DAStrings!
|
||
(void)CitationsCH(baseString,0,4,(CiteListPtr)&cl);
|
||
sp = (StringHandle *)DAStrings;
|
||
for (i = 3; i >= 0; --i)
|
||
{
|
||
if (*sp) HUnlock((Handle)*sp);
|
||
++sp;
|
||
}
|
||
return;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
pascal long DepthFirstSubstitution(SSSS *pb, short flags, long startpos, long endpos)
|
||
/* Substitution algorithm:
|
||
We use a depth-first substitution (every thing in the first ^x, then go on).
|
||
In order to avoid the recursive substitution crash, we keep flags to indicate
|
||
which substitutions we have done at each level. Thus ^0 can be substituted
|
||
with ^1^2^3^0 but only ^1^2^3 will be replaced, the ^0 will be unchanged.
|
||
Therefore, we can only recurse 3 times.
|
||
|
||
Steps:
|
||
1) Find a citation between startpos and endpos.
|
||
If there are none, we are done. Endpos is unchanged and we return endpos-startpos.
|
||
If that citation is already used (determined by flags), pass this caret and keep looking.
|
||
2) Use the number after the caret to determine which citation to use and Munge it
|
||
into the stringhandle.
|
||
3) Recurse to substitute the citations only in the Munged-in part of the stringhandle.
|
||
We set the flag for the citation number we just did so that no lower-level substitution
|
||
will do that number over again - thus preventing infinite recursion.
|
||
*/
|
||
{
|
||
if (flags) // When flags is zero, there are no more subs allowed
|
||
{
|
||
long currpos;
|
||
short replStr = CARETSTR;
|
||
StringPtr replStrPtr = (StringPtr)&replStr;
|
||
|
||
for (currpos = startpos;currpos < endpos;)
|
||
{
|
||
short whichCite;
|
||
long afterCitePos,newcount;
|
||
StringPtr sp;
|
||
|
||
// Find the next citation at this level (skip if invalid/illegal)
|
||
// Note that FindCharInSet does not move memory (important since we point into a handle)
|
||
// returns the offset of the caret or -1 to indicate not found
|
||
afterCitePos = FindCharInSet((Ptr)(*(pb->s)+currpos),endpos-currpos,replStrPtr,pb->table);
|
||
if (afterCitePos < 0) break;
|
||
currpos += afterCitePos;
|
||
// What if there is a caret at the end of the handle, and a '0' in the next byte in memory?
|
||
if (endpos-currpos < 2) break; // Don’t munge past end of string!!!
|
||
|
||
// Check for a valid char following the caret
|
||
whichCite = *(*(pb->s)+currpos+1) - '0';
|
||
if (((whichCite < 0) || (whichCite >= pb->numCites)))
|
||
{ // ^ followed by nothing interesting or recursive violation
|
||
++currpos; // Search starting from the char after caret (^^0?)
|
||
continue;
|
||
}
|
||
|
||
// Munge it into the stringhandle, which returns the proper end of the substring pos.
|
||
sp = pb->pcl[whichCite];
|
||
if (!BITTST(flags,whichCite)) // Be sure to munge out the citation entry if nil <2>
|
||
afterCitePos = Munger((Handle)(pb->s), currpos, NULL, 2, (Ptr)(DAStrings), 0);
|
||
else
|
||
afterCitePos = Munger((Handle)(pb->s), currpos, NULL, 2, (Ptr)(sp+1), Length(sp));
|
||
|
||
// Set the flag and do the substitutions within the section we just added
|
||
newcount = DepthFirstSubstitution(pb, BITCLR(flags,whichCite), currpos, afterCitePos);
|
||
endpos += (newcount - 2); // The substitution string became this long - '^x'
|
||
currpos += newcount; // Don't resubstitute in this section (or die)
|
||
}
|
||
}
|
||
return (endpos-startpos);
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
// Entry point to recursive routine.
|
||
// Returns new size or -1 if ParseTable was not available or no citations passed.
|
||
pascal long DoDFS(CharsHandle baseString,long offset,short numCitations,CiteListPtr citations)
|
||
{
|
||
short i;
|
||
SSSS pb; // SaveSomeStackSpace
|
||
short flags = 0;
|
||
StringPtr *cs = citations;
|
||
long rslt = NOPARSETBL;
|
||
|
||
// Set a bit in the flags if the string ptr is non-nil
|
||
if (numCitations > MAXCITATIONS) numCitations = MAXCITATIONS;
|
||
for (i = 0; i < numCitations; ++i)
|
||
if (*cs++) flags |= (short)(1 << i);
|
||
|
||
// Save stack space during recursion by passing this structure
|
||
if (ParseTable(&pb.table))
|
||
{
|
||
pb.s = baseString;
|
||
pb.numCites = numCitations;
|
||
pb.pcl = citations;
|
||
rslt = DepthFirstSubstitution(&pb,flags,offset,GetHandleSize((Handle)baseString));
|
||
}
|
||
return(rslt);
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
// This the the generic call to replace citations in a CharsHandle (e.g., text edit record)
|
||
pascal OSErr __CitationsCH(CharsHandle baseString,long offset,short numCitations,CiteListPtr citations)
|
||
{ // Allows 10 citation replacements (^0 thru ^9)
|
||
(void)DoDFS(baseString,offset,numCitations,citations);
|
||
return(noErr);
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
// Citations in a string handle - the generic routine. <6>
|
||
pascal OSErr __CitationsSH(StringHandle baseString,short numCitations,CiteListPtr citations)
|
||
{
|
||
long newLen;
|
||
newLen = DoDFS(baseString,1,numCitations,citations);
|
||
if (newLen != NOPARSETBL)
|
||
{
|
||
if (newLen > 255) newLen = 255;
|
||
**baseString = (char)newLen;
|
||
}
|
||
return(noErr);
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------------*/
|
||
// The is the easy way to avoid using ParamText. Just replace the citations directly. <6>
|
||
pascal OSErr __Cite4(StringHandle s,ConstStr255Param p0,ConstStr255Param p1,ConstStr255Param p2,ConstStr255Param p3)
|
||
{
|
||
OSErr myErr;
|
||
ConstStr255Param cl[4] = {p0,p1,p2,p3};
|
||
myErr = __CitationsSH(s,4,(CiteListPtr)&cl); // Call via dispatcher
|
||
return(myErr);
|
||
}
|