/* CLASS: LOADFILE
    LoadFileModule is a data object of the Source Presenter.
    It contains all information about a loadfile.  Also, It contains the information
    about the debug session of a loadfile such as the startPC, baseStack            address descriptor and stackSize.
    - the loadStartPC will be used for RESTART command in the future.
    - This class is closely coupled with the SourcePresenter class
    - See SourcePresenter for usage details.
    - The Code/Data/RomAddrRange are used by the Source Presenter to set
    disassembly display range. 
*/!!

inherit(Object, #LoadFileModule, #(loadFileName /* loadfile name and path */
status /* boolean true/nil */
numLoadedModules /* number of modules */
modulesDict /* a modules dictionary */
modulesDictUpdated /* ondemand update */
loadStartPC /* the startup PC address  */
loadStackBase  /* the stack base address  */
loadStackSize /* size of runtime stack */
), 2, nil)!!

now(class(LoadFileModule))!!

now(LoadFileModule)!!

/* 3/28/1994 8:52 */
Def numLoadedModules(self)
{ 
  ^numLoadedModules;
}
!!

/* 3/25/1994 13:48 - PUBLIC
  Return the current status of modulesDict
*/
Def modulesDictUpdated(self)
{ 
  ^modulesDictUpdated;
}
!!

/* 3/23/1994 14:07 - PUBLIC*/
Def setNumberOfModules(self, num)
{ 
  numLoadedModules := num;
}
!!

/* 06/20/92 - PRIVATE 
  Get info from module description & add to modulesDict [moduleDesc->ModuleInfo,...]
*/
Def addModuleFromDesc(self, aModuleDesc | aModInfo)
{
  /* Allocate a new ModuleInfo - Use self as root of the new moduleInfo */
  if aModInfo := new(ModuleInfo, aModuleDesc, self) then
    /* add module to Loadfile's modulesDict, using the module descriptor 
       as its key */
    add(modulesDict, aModuleDesc, aModInfo ) ; 
    ^aModInfo
  endif;
  ^nil;
}
!!

/* 2/7/1992 14:59 - PUBLIC
  Delete the LoadFile itself.
*/
Def deleteLoadFile(self)
{ 
  loadFileName := nil;
  status := nil;
  invalidateSymbols(self);
  ^GOOD;
}
!!

/* 2/7/1992 14:59 - PUBLIC
  Delete the LoadFile address descriptors.
*/
Def deleteLoadFileAddr(self)
{ 
  /* Destroy the startPC */
  destroyAddress(self, loadStartPC);
  destroyAddress(self, loadStackBase);
  /* address descriptors */ 
  loadStartPC   := nil;
  loadStackBase := nil;
  loadStackSize := nil;
  ^GOOD;
}
!!

/* 2/13/1992 14:44 - PRIVATE 
  Remove all moduleInfo objects in the LoadFile.
*/
Def deleteModulesDict(self)
{ 
  /* delete its modulesDict - using do(value) enumeration message */
  do (modulesDict, 
    {using(module)
      deleteModuleInfo(module);
    });
  clear(modulesDict);
  numLoadedModules   := 0;
  modulesDictUpdated := nil; /* ondemand update */
}
!!

/* 6/11/1992 12:58 - PRIVATE 
  Destroy self address descriptors.
*/
Def destroyAddress(self, addrDesc)
{ 
  if addrDesc then
    destroyAddress(AddressLibClass$Inst, addrDesc);
    addrDesc := nil;
  endif;  
}
!!

/* 7/12/1992 16:48 - PUBLIC
  Extract modules name from the modulesDict of self.
  Return sortedCollection ([ModuleName, ModuleDescriptor],...)
  NOTES: used by SourcePresenter and BreakpointPresenter
*/
Def getModuleNamesDict(self | modulesNameColl)
{ 
  /* Loading modules dictionary ondemand */
  if (modulesDict(self) cand (size(modulesDict) > 0)) then
    if (modulesNameColl := new(SortedCollection, size(modulesDict))) then
      initWithCompareBlock(modulesNameColl, 
        { using(e1,e2) 
          e1[0] < e2[0] /* ascending order */
        });    
    else
      ^nil;
    endif;
    /* Do associate to create module names dictionary */
    /* ModulesNameColl = ([ModuleName,Module Descriptor],..) */    
    assocsDo (modulesDict, 
      {using(element | addrRange)             
        /* Filter out any data module, which does not have valid address range */ 
        if ((addrRange := addressRange(value(element))) cand
          (isAnAddrRangeDesc?(AddressLibClass$Inst, addrRange))) then
           add(modulesNameColl, tuple(moduleName(value(element)), key(element)));
        endif;   
      });
    if size(modulesNameColl) = 0 then
      ^nil;
    endif;
    ^modulesNameColl;      
  endif;    
  ^nil;  
}
!!

/* 2/5/1992 14:06 - PUBLIC
  Initialize a new loadfile module object by setting object instance
  variables to the values passed in
  EX: init(LoadFileModule, "C:\TEST\DEMO.ABS", true);
  */
Def init(self, fileNameStr, newStatus)
{ 
  loadFileName     := fileNameStr;
  status           := newStatus; 
  modulesDict      := new(Dictionary, 2);
  numLoadedModules := 0;
  clear(modulesDict);
  ^self;   
}
!!

/* 2/13/1992 14:40 - PUBLIC 
  Remove all symbolic information of the loadfile.
*/
Def invalidateSymbols(self)
{ 
  /* Delete all moduleInfo first */
  if modulesDict then
    deleteModulesDict(self);
  endif; 
  ^GOOD;
}
!!

/* 2/12/1992 15:41 - PUBLIC 
  Return #true if current loadfile id loaded, else nil.
*/
Def isLoaded(self)
{ 
  ^status;
}
!!

/* 2/11/1992 13:46 - PUBLIC
  Load a LoadFileModule information from a file into self by initializing */
Def load(self, theFile)
{ 
  /* Read data in and initialize self */
  init(self, readLine(theFile), nil);
}
!!

/* 2/5/1992 15:50 - PUBLIC */
Def loadFileName(self) 
{
  if loadFileName then
    ^loadFileName; 
  endif;
  ^"";  
}
!!

/* 6/4/1992 12:51 - PUBLIC
  Return the pathName of the loadfile.
    ex: "r:\tmp\loadfile\main.abs" -> "r:\tmp\loadfile\"
    ex: "r:main.abs"               -> "r:"
    ex: "r:\main.abs"              -> "r:\"  
*/
Def loadFilePath(self)
{ 
  if loadFileName then
    /* Notes: pathParts return = #(pathString, fileName, fileExt) */
    ^pathParts(loadFileName)[0];
  endif;
  ^"";  
 }
!!

/* 2/5/1992 16:36 - PUBLIC 
  Return the size of a file
*/
Def loadFileSize(self | theFile, fSize ) { 
  
  theFile := new(File);
  setName(theFile, loadFileName);
  open(theFile, 0);
  checkError(theFile);
  fSize := length(theFile);
  close(theFile);
  ^fSize;
}
!!

/* 2/5/1992 16:33 - PUBLIC*/
Def loadFileStatus(self) { 
  if status
  then ^"loaded";
  endif;
  ^" - ";
}
!!

/* 3/22/1992 16:31 - PUBLIC (to its parent) */
Def loadStartPC(self)
{ 
  ^loadStartPC;
}
!!

/* 2/6/1992 8:40 - PUBLIC 
  Rebuild the modulesDict for self.  If modulesDictUpdated is nil
  then build it, else return the current modulesDict.
  NOTES: 
    - Handle constructing modulesDict on demand. 
*/
Def modulesDict(self) 
{ 
  if isLoaded(self) cand not(modulesDictUpdated) then
    /* Update the modulesDict first */
    showWaitCurs();
    rebuildLoadModuleDict(self);
    showOldCurs();
  endif;   
  ^modulesDict;
}
!!

/* 2/5/1992 16:32 - PUBLIC 
  Return the number of modules in the current loadfile.
*/
Def modulesDictsize(self)
{ 
  if isLoaded(self) cand modulesDict then
    ^size(modulesDict); 
  endif;
  ^0;  
}
!!

/* PRIVATE -- Extract load module ids & add info for each */
Def rebuildLoadModuleDict(self | moduleDesc, modInfo)
{
  if (not(SymbolLibClass$Inst) cor 
      not(moduleDesc := getModuleListHead(SymbolLibClass$Inst))) then
    if ((loadFlags(TheProjectInfoObj)  bitAnd 0x1) = 0)
       modulesDictUpdated := GOOD; /* No symbol loaded */
    endif;
    ^nil;
  endif;

  /* get all module descriptors in one shot */
  if (not(modInfo := getAllModules(SymbolLibClass$Inst, numLoadedModules)) cor
     (modInfo[0] = 0)) then   
    ^nil;
  endif;   

  /* Extract all modules from the list and add it to the modulesDict */
  do (modInfo[1],
    {using(module | aModInfoObj)
       /* check for NULL_SYMBOL (0L) */
       if ((module <> 0) cand
          (aModInfoObj := new(ModuleInfo, module, self))) then
         /* add module to modulesDict, using the module descriptor as its key */
         add(modulesDict, module, aModInfoObj); 
       endif;
    });        
  /* update flag to signify that modulesDict is built */
  ^(modulesDictUpdated := GOOD);
}
!!

/* 2/5/1992 15:50 - PUBLIC */
Def setLoadFileName(self, newName) 
{
  ^(loadFileName := newName);
}
!!

/* 3/22/1992 16:24 - PUBLIC 
  Save base address descriptor of the Stack
*/
Def setLoadStackBase(self, newBaseDesc)
{ 
  if isLoaded(self) cor loadStackBase then
    /* destroy the old one first */
    destroyAddress(self, loadStackBase);
  endif;   
  ^(loadStackBase := newBaseDesc);
}
!!

/* 4/3/1992 15:19 - PUBLIC */
Def setLoadStackSize(self, newSize)
{ 
  ^(loadStackSize := newSize);
}
!!

/* 3/22/1992 16:23 - PUBLIC 
  Set the startPC of the loadFile.
*/
Def setLoadStartPC(self, newPC)
{
  if isLoaded(self) cor loadStartPC then
    /* destroy the old one first */
    destroyAddress(self, loadStartPC);
  endif;   
  ^(loadStartPC := newPC); 
}
!!

/* 2/12/1992 15:42 - PUBLIC */
Def setLoadStatus(self, newStatus)
{ ^(status := newStatus); }
!!
