-- RsDebugStack.ms -- Functions for extracting useful info from the Maxscript debug-stack text-stream -- -- Neal D Corbett (R* Leeds, 04/2014) global gRsDebugStack struct RsDebugStack ( -------------------------------------------------------------------------- -- GetStackInfo: -- Returns list of info-items per recursion-stack level -- Or info for a specific level if 'Level' is set: -------------------------------------------------------------------------- fn GetStackInfo Level: GetLocals:True = ( local StackItems = #() local AllLevels = (not isKindOf Level Number) struct RsDebugStackLevel ( CallLine, StackString ) -- Get stack-text as stream: local StackStream = StringStream "" Stack ShowLocals:GetLocals To:StackStream -- Seek to line in stack-level text referring to this current function: Seek StackStream 0 skipToString StackStream "GetStackInfo();" -- Find stack-level header referring to function that called 'GetStackInfo': skipToString StackStream "[stack level:" if (eof StackStream) do (return #()) skipToNextLine StackStream local StackLevel = 0 -- Parse stack-text: while (not eof StackStream) and (AllLevels or (StackLevel < Level)) do ( StackLevel += 1 if AllLevels or (StackLevel == Level) do ( -- Collect text up to next dividing-line, referring to current stack-level: local LevelString = StringStream "" local ThisLine = (readLine StackStream) while (not eof StackStream) and (not matchPattern ThisLine pattern:"*\t------------------------------------------------------") do ( format "%\n" ThisLine To:LevelString ThisLine = (readLine StackStream) ) -- Parse the 'LevelString' stream -- (unless we've reached the bottom of stack-text) if (not eof StackStream) do ( -- Rewind 'LevelString' stream back to beginning: seek LevelString 0 -- Get function-name for this stack-level: skipToString LevelString "\t" CallLine = readDelimitedString LevelString "\n" -- Add parsed data to return-array: local NewItem = (DataPair CallLine:CallLine StackString:(LevelString as string)) append StackItems NewItem ) ) -- Find next stack-level header: if (not eof StackStream) do ( skipToString StackStream "[stack level:" skipToNextLine StackStream ) ) -- Return items for all stack-levels, or for a specific stack-level: if AllLevels then ( return StackItems ) else ( return StackItems[1] ) ), ------------------------------------------------------------------------------ -- GetCallLine: -- Returns function/script/line that called 'GetCallLine': ------------------------------------------------------------------------------ fn GetCallLine Default:"undefined" Level:1 = ( -- No need to get local values: local Caller = GetStackInfo GetLocals:False Level:Level if (Caller == undefined) then ( return Default ) else ( return Caller.CallLine ) ), -------------------------------------------------------------------------- -- PrintLine: -- Returns string describing the function/line/script that -- that 'GetThisLine' is called from: -------------------------------------------------------------------------- fn GetThisLine Level:3 = ( return (GetCallLine Level:Level) ), -------------------------------------------------------------------------- -- GetCallerLine: -- Returns string describing the function/line/script that -- calling function was called from, if 'DebugActive' is true. -------------------------------------------------------------------------- fn GetCallerLine = ( return (GetThisLine Level:5) ) ) gRsDebugStack = RsDebugStack() -- HERE IS A TEST: /* ( fn TestB = ( print (gRsDebugStack.GetThisLine()) print (gRsDebugStack.GetCallerLine()) ) fn TestA = ( TestB() ) TestA() OK ) */