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

211 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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 its 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; // Dont 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);
}