-- FIND IN RAM -- -- -- April 2002 -- Revised August 2002 following comments by Robert Walch -- -- This movie script allows you to search RAM space for variables of a -- chosen type. You can search for: -- * a given property name -- * a given value, -- * values of a given ilk -- * members of a given type -- * sprites with members of a given type -- * instances of a given script or xtra. -- -- Results are returned as a series of string access paths. Results -- can be returned either as a list or as a string to put into the -- message window. Individual expressions can be copied and pasted -- into the Watcher window, or evaluated with the put() command. -- -- In a complex movie, a systematic investigation of RAM space can -- take some time. To reassure you that the handler is still -- functioning, a status report will be printed into the Message -- window every second or so. -- -- Example uses: -- * Find the pointer to a MIAW that is preventing the -- window(x).forget() command from destroying the window -- * Find a pointer to the script instance whose values you want to -- study in the Watcher window -- * Discover if a given xtra has been instanciated -- * ... on FindInRAM(aSearchItem, aHostObject, aPath, aPathList, aDoneList) -- -- INPUT: can be -- - A symbol. If the symbol represents a valid ilk, member -- type or property name then this handler returns a list -- of all the access paths to elements with that ilk, -- member type or property name. The symbol is also -- considered to be a value (see below). Special symbols -- are #xtra, #ref and #sound, which return instances of -- the appropriate type, as well as any properties with -- those symbol values. -- - A script or xtra reference. Returns a list of all the -- access paths to instances of that script or xtra, or to -- references to the script or xtra itself. -- - Any Lingo value. Returns a list of all the access -- paths to variables with the given value. -- may be a list, a script or a script -- instance. If this is the case, the search will be -- limited to the host object. Otherwise, this handler -- will search through all accessible objects in RAM: -- * Globals -- * ActorList -- * Behaviors -- * Scripts -- * Windows -- * Target objects of the timeOutList -- , and are used internally -- by the handler when it calls itself recursively. There -- is no need to include these parameters in your initial -- call. You can, however, use #list as the value for -- or in which case the result will be -- returned as a list rather than as a string. -- ACTION: Performs a tree-walk of and returns the -- list of all items whose ilk, type or value is -- -- OUTPUT: A list of strings. Each string is a Lingo expression, -- the value of which will resolve to the value of the item -- found. If you use #string as the second or third -- parameter, a single string will be returned with each -- expression on a different line. -- -- EXAMPLES: -- -- Search for a given ilk -- put FindInRAM(#window) -- -- [#ilk: "(the windowList)[1]", -- #ilk: "window("MIAW")", -- #ilk: "(the globals).gMIAW"] -- -- -- Search for instances of a given script -- put FindInRAM(script("Parent Script) -- -- [#script: "sprite(3).scriptInstanceList[2].ancestor", -- #value: "script(10, 3)", -- #script: "(the globals).gObject"] -- -- -- Search for a given value -- put FindInRAM("search string") -- -- [#value: "sprite(7).scriptInstanceList[1].pString", -- #value: "(the globals).goText.pText"] -- -- -- Search for a given property name -- put FindInRAM(#pmText) -- -- [#pmText: "sprite(21).scriptInstanceList[1]", -- #pmText: "script(13, 3)"] -- -- -- Search in a given object. Note: expressions are clipped -- put FindInRAM(#image, goImageManager) -- -- [#ilk: ".pImage1", -- #ilk: ".pImage2"] -- -- -- Search in a given window, with result as a string -- tell window("Panel") to tScript = script("Behavior") -- put FindInRAM(tScript, window("Panel"), #string) -- -- " -- tell (window 1) to put sprite(6).scriptInstanceList[1] -- script -- tell (window 1) to put script(21, 1) -- value -- " -- -- -- Search for a member of a given type, with result as a string -- put FindInRAM(#text, the stage, #string) -- -- " -- put sprite(21).scriptInstanceList[1].pmText -- member -- put sprite(21).scriptInstanceList[1].psText -- sprite -- " -------------------------------------------------------------------- -- Initialize aDoneList and aPathList when handler is first called if ilk(aDoneList) <> #list then cursor 4 aDoneList = [] if voidP(aHostObject) then tFindEverywhere = TRUE else if aHostObject = #list then tFindEverywhere = TRUE asList = TRUE else if aPath = #list then asList = TRUE end if end if if ilk(aPathList) <> #propList then aPathList = [:] end if -- Ignore objects that have already been searched and link instances tIndex = aDoneList.getPos(aHostObject) if tIndex then -- This object has already been searched if listP(aHostObject) then if mListsAreIdentical(aDoneList[tIndex], aHostObject) then exit end if else exit end if else if ilk(aHostObject, #instance) then -- Ignore link and chain instances tName = string(aHostObject).word[2] if tName = QUOTE&"Link""E then exit else if tName = QUOTE&"Chain""E then exit end if end if -- Explore this object more closely tHostIlk = ilk(aHostObject) case tHostIlk of #list, #propList, #script: -- Continue after the case statement #instance: case string(aHostObject).word[1] of " "" then tHost = script(tMemberNumber, i) tPath = tName&"script("&tMemberNumber&", "&i&")" mAddToList(aPathList, tPath, aSearchItem, tHost) FindInRAM(aSearchItem,tHost,tPath,aPathList,aDoneList) end if end repeat end repeat end tell return List_To_String(aPathList) otherwise: if tFindEverywhere then -- is not defined. Look in all accessible -- places in RAM -- Sprites tCount = the lastChannel repeat with i = 1 to tCount tHost = sprite(i) tPath = "sprite("&i&")" FindInRAM(aSearchItem, tHost, tPath, aPathList, aDoneList) end repeat -- the actorList tPath = "(the actorList)" FindInRAM(aSearchItem,the actorList,tPath,aPathList,aDoneList) -- Scripts tCount = the number of castLibs repeat with i = 1 to tCount tMemberCount = the number of members of castLib i repeat with tMemberNumber = 1 to tMemberCount tMember = member(tMemberNumber, i) if tMember.scriptText <> "" then tHost = script(tMemberNumber, i) tPath = "script("&tMemberNumber&", "&i&")" mAddToList(aPathList,tPath,aSearchItem,tHost) FindInRAM(aSearchItem,tHost,tPath,aPathList,aDoneList) end if end repeat end repeat -- Movies in a Window tPath = "(the windowList)" tList = the windowList FindInRAM(aSearchItem, tList, tPath, aPathList, aDoneList) -- Windows tCount = (the windowList).count() repeat with i = 1 to tCount tHost = (the windowList)[i] if ilk(tHost, #window) then tName = QUOTE&tHost.name"E if tName = "" then tName = i end if tPath = "window("&tName&")" mAddToList(aPathList,tPath,aSearchItem,tHost) FindInRAM(aSearchItem, tHost, tPath, aPathList, aDoneList) else if objectP(tHost) then tPath = "(the windowList)["&i&"]" mAddToList(aPathList,tPath,aSearchItem,tHost) FindInRAM(aSearchItem, tHost, tPath, aPathList, aDoneList) end if end repeat -- Target objects of the timeOutList if value((the globals).version.char[1..3]) < 8 then -- The timeOutList does not exist in Director 7 or earlier else tCount = the timeOutList.count repeat with i = 1 to tCount tHost = timeOut(i) tPath = "timeOut("&i&")" mAddToList(aPathList, tPath, aSearchItem, tHost) tHost = tHost.target tPath = "timeOut("&i&").target" mAddToList(aPathList, tPath, aSearchItem, tHost) if ilk(tHost, #instance) then if string(tHost).word[1] = " #sprite then aDoneList.append(aHostObject) -- Use .count() function, not .count property to ensure that the -- correct value is returned for instances with ancestors if tHostIlk <> #window then tCount = aHostObject.count() tTime = the milliseconds repeat with i = 1 to tCount if keyPressed(" ") then return aPathList end if if the milliseconds - tTime > 1000 then tTime = the milliseconds put "Found: "&aPathList.count&&"Treating: "&aPath if the mouseDown then return aPathList end if end if if tHostIlk = #list then tValue = aHostObject[i] tPath = aPath &"["&i&"]" else tProp = aHostObject.getPropAt(i) tValue = aHostObject.getAProp(tProp) if symbolP(tProp) then tPath = aPath &"."&tProp else if stringP(tProp) then tPath = aPath &".getProp(""E&tProp"E&")" else tPath = aPath &".getProp("&tProp&")" end if if tProp = aSearchItem then case ilk(tProp) of #symbol: tAccess = "."&tProp #string: tAccess = ".getProp(""E&tProp"E&")" otherwise: tAccess = ".getProp("&tProp&")" end case aPathList.addProp(#prop, aPath&tAccess) end if end if mAddToList(aPathList, tPath, aSearchItem, tValue) FindInRAM(aSearchItem, tValue, tPath, aPathList, aDoneList) end repeat end if -- #window end if -- #sprite return List_To_String(aPathList) end FindInRAM on List_To_String(aList) --------------------------------------------- -- INPUT: is a list of strings -- OUTPUT: a Return-delimited list of the items in -------------------------------------------------------------------- tString = "" tCount = aList.count repeat with i = 1 to tCount tExpression = aList[i] if not (tExpression starts "tell ") then put "put " before tExpression end if tSymbol = aList.getPropAt(i) case tSymbol of #prop,#value,#ilk,#member,#sprite,#instance,#xtra,#refOrSound: put RETURN&tExpression&" -- "&tSymbol after tString otherwise if symbolP(tSymbol) then put RETURN&tExpression&"."&tSymbol after tString else put RETURN&tExpression&".getProp("&tSymbol&")" after tString end if end case end repeat -- RETURN is left at the beginning and added at the end so that the -- expressions can be evaluated directly in the Message window put RETURN after tString cursor 0 return tString end List_To_String on mAddToList(aPathList, aPath, aSearchItem, aSuspect) --------------- -- INPUT: is a list of strings -- is a string -- is a symbol ilk, a script reference or -- any other Lingo value -- is a Lingo value that may correspond to the -- (type of) search item we are looking for -------------------------------------------------------------------- if aSuspect = aSearchItem then -- The values match (matches xtras and scripts but not instances) aPathList.addProp(#value, aPath) else if ilk(aSuspect) = aSearchItem then -- aSearchItem is an ilk symbol, and aSuspect is of that ilk aPathList.addProp(#ilk, aPath) else if ilk(aSuspect) = #member then if aSuspect.type = aSearchItem then aPathList.addProp(#member, aPath) end if else if ilk(aSuspect) = #sprite then if aSuspect.member.type = aSearchItem then aPathList.addProp(#sprite, aPath) end if else if ilk(aSuspect, #instance) then case aSearchItem of #ref, #sound, #xtra: tSearchIlk = aSearchItem otherwise tSearchIlk = ilk(aSearchItem) end case case tSearchIlk of #script: -- Check using name of script, since anInstance.script -- returns anInstance.ancestor.script in versions of -- Director up to and including 8.5.1 tName = string(aSuspect) -- "" if tName.word[1] = "" tName = tName.word[2..tName.word.count - 2] -- Remove quotes tName = tName.char[2..tName.char.count - 1] if tName = "" then -- The script doesn't have a name: try using the -- instance's .script property, though this may not be -- accurate if aSuspect.script = aSearchItem then aPathList.addProp(#script, aPath) end if else if the number of member(tName) > 0 then -- Tread carefully, since we may be in a window that -- doesn't have access to the script member we're -- looking for if member(tName).scriptText <> "" then if script(tName) = aSearchItem then aPathList.addProp(#instance, aPath) end if end if end if end if #xtra: -- We are looking for instances of a given xtra tName = string(aSuspect) -- "" if tName.word[1] = "" tName = tName.word[3..tName.word.count - 2] -- Remove quotes tName = tName.char[2..tName.char.count - 1] if xtra(tName) = aSearchItem or aSearchItem = #xtra then aPathList.addProp(#xtra, aPath) end if end if #ref, #sound: tName = string(aSuspect) -- "" if tName.word[1..2] = " and are pointers to the same -- list. Returns FALSE in all other cases. -- -- The test is carried out by adding a new item to and -- checking if it appears in the same place in . The chances -- that happens to contain the test element in the correct -- position are tiny, but non-zero. -------------------------------------------------------------------- listIlk = ilk(list1) if ilk(list2) <> listIlk then return FALSE end if case listIlk of #list: identity = symbol("listCheck"&the ticks) list1.add(identity) position = list1.getPos(identity) if position > list2.count() then identity = FALSE else identity = (list2[position] = identity) end if list1.deleteAt(position) return identity #propList: identity = symbol("listCheck"&the ticks) list1.addProp(identity, identity) position = list1.findPos(identity) if position > list2.count() then identity = FALSE else identity = (list2[position] = identity) end if list1.deleteAt(position) return identity otherwise return FALSE end case end mListsAreIdentical