-- FindProcImpl.mesa
--  Sweet,  6-Oct-83 16:59:47
DIRECTORY
  FindProc
  MFile USING [Handle];
  
FindProc: PROGRAM
  IMPORTS LoadState
  EXPORTS FindProc = {
  
  Lookup: PUBLIC PROC [
      gFrame: LONG POINTER, procName: LONG STRING, objectFile: MFile.Handle ← NIL]
    RETURNS [p: PROCEDURE = {
    procSS: String.SubStringDescriptor ← [
      base: procName, offset: 0, length: procName.length];
    bcd: BcdOps.BcdBase;
    info: LoadStateFormat.ModuleInfo;
    frame: PrincOps.GlobalFrameHandle ← 
      SpecialRuntime.GlobalFrameFromProgram[gFrame];
    loadState: LoadStateFormat.Handle;
    bcdInfo: LoadState.LPBcdInfoTable ← NIL;
    link: PrincOps.ControlLink;
    mtb, enb, sgb, ftb: Table.Base;
    mti: BcdDefs.MTIndex;
    mth: BcdOps.MTHandle;
    ssb: LONG POINTER TO BcdDefs.PackedString;
    ep: CARDINAL;
    fileName: STRING ← [60];
    fileVersion: BcdDefs.VersionStamp;
    symsBase, symsPages: CARDINAL;
    
    BEGIN -- make bcdInfo visible in exits
    Runtime.ValidateGlobalFrame[frame ! Runtime.InvalidFrame => GO TO notFound];
    [loadState, bcdInfo] ← LoadState.LockBcdInfo[]; 
    
    BEGIN ENABLE UNWIND => IF bcdInfo # NIL THEN LoadState.UnlockBcdInfo[];
    info ← LoadState.GetModuleInfo[frame];
    bcd ← bcdInfo[info.index].base;
    mtb ← bcd + bcd.mtOffset;
    sgb ← bcd + bcd.sgOffset;
    ftb ← bcd + bcd.ftOffset;
    ssb ← LOOPHOLE[bcd + bcd.ssOffset];
    mti ← BcdDefs.MTIndex.FIRST + (info.cgfi - 1) * BcdDefs.MTRecord.SIZE;
    mth ← @mtb[mti];
    fileVersion ← ftb[mth.file].version;
    AppendName[fileName, ssb, ftb[sgb[mth.sseg].file].name !
      String.StringBoundsFault => GO TO notFound];
    symsBase
    LoadState.UnlockBcdInfo[];
    
    info ← LoadState.GetModuleInfo[frame];
    bcd ← bcdInfo[info.index].base;
    enb ← bcd + bcd.enOffset;
    END; --  ENABLE UNWIND
    
    IF bcdInfo # NIL THEN LoadState.UnlockBcdInfo[];
    RETURN [LOOPHOLE[link]];
    EXITS
      notFound => {IF bcdInfo # NIL THEN LoadState.UnlockBcdInfo[]; RETURN [NIL]};
    END; -- make bcdInfo visible in exits
    };
    
  SubStringForName: PROC [
    ss: String.SubString, 
    ssb: LONG POINTER TO BcdDefs.PackedString,
    name: BcdDefs.NameRecord] = {
    ss.base ← @ssb.string;
    ssb.offset ← name;
    ssb.length ← ssb.size[name]};
    
  AppendName: PROC [
    str: LONG STRING, ssb: LONG POINTER TO BcdDefs.PackedString, 
    name: BcdDefs.NameRecord] = {
    desc: String.SubStrinDescriptor;
    SubStringForName[@desc, ssb, name];
    String.AppendSubString[str, @desc]};
  }.