/* CLASS: LoaderLib (LDR695.DLL)
   Provides interface to the IEEE 695 Loader. 
   NOTES: When invoke the loader library, it provides a popup dialog box with
   the default values for loadFlags and loadOndemand.  User can changes 
   these values to suit his/her needs.  These value will be saved into the 
   global PrjInfo object.
   NOTES: call loader to load a loadfile by:
          invokeLoader(LoaderLibClass$Inst, "d:\test", self);

   REQUIRE: LOADOPTI.CLS  CPULIB.CLS MEMLIB.CLS
*/!!

inherit(ProvidedLibs, #LoaderLib, nil, 2, nil)!!

now(class(LoaderLib))!!

/* semiPRIVATE -- should only be called via require(SymbolLib)
   Define entry points and load library.  Define any structs required.
*/
Def provide(self, path)
{
  ^initialise(new(self:ancestor), path);
}!!

now(LoaderLib)!!

/* 12/1/1995 15:33 */
Def ldrSpaceMode(self)
{
  if pcallLock(self) then
    lastError := pcall( procs[#LDRSPACEMODE]);
    pcallUNLock(self);
  else
    displayError(ErrorTextLibClass$Inst, ERR_PCALL_RECURSION, CHECK_MODE);
    ^nil;
  endif;
  ^lastError;
}
!!

/* Let the user pick the compiler. */
Def selectCompiler(self | addrDescRef, stackSizeRef)
{
  if pcallLock(self) then
    lastError := pcall( procs[#LDRGETTOOLUSE]);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil;
  endif;
  ^0;
}
!!

/* 11/18/1992 9:57 - PUBLIC
  Return #true if module file timestamp > loadfile timestamp, else nil.
*/
Def sourceOutOfSynch?(self, moduleName | statusRef )
{ 
  if not(moduleName) then
     ^displayFormattedError(ErrorTextLibClass$Inst, 
        ER_INVALID_MODULE_NAME, FORCE_POPUP, nil, nil, nil);
  endif;
  
  statusRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#LDRGETFILESTATUS], asciiz(moduleName), statusRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  /* Return the result */
  ^(byteAt(statusRef, 0) <> GOOD);
}
!!

/* 4/3/1992 8:35 - PUBLIC 
  Get loader options.
  return #(fileName, onDemand, loadFlags, startModule) or nil. 
  NOTES: 09/23/93 - changed loadFlags to U32
*/
Def getLoadOptions(self | 
fileRef, onDemandRef, loadFlagsRef, loadModuleRef, fileStr, moduleStr)
{ 
  fileRef       := new(Struct, 128); /* optimize to LOADER predefined values */
  onDemandRef   := new(Struct, 4);
  loadFlagsRef  := new(Struct, 4);
  loadModuleRef := new(Struct, 128);
  if pcallLock(self) then
    lastError := pcall(procs[#LDRGETOPTIONS], fileRef, onDemandRef,
                                                 loadFlagsRef, loadModuleRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  fileStr := nil; moduleStr := nil;
  if (longAt(fileRef, 0) <> 0) then
    fileStr := removeNulls(physicalString(fileRef)); 
  endif;     
  
  if (longAt(loadModuleRef, 0) <> 0) then
    moduleStr := removeNulls(physicalString(loadModuleRef));
  endif;
  ^tuple(fileStr,                   /* str | nil */
         byteAt(onDemandRef, 0),    /* BOOLEAN */
         longAt(loadFlagsRef, 0),   /* U32 */
         moduleStr                  /* str | nil */
        );    
}
!!

/* 7/6/1992 12:49 - PUBLIC
  Load a loadfile from the prevUsedpath with the current LoadFlags and loadOnDemand.
  Provides a dialog box to let the user select load options.
  EX: 
    invokeLoader(LoaderLibClass$Inst, self);
  Return GOOD if success or nil if fail.
*/
Def invokeLoader(self, parent | tmpDialog, filePath, oldFilePath, newOptions)
{ 
  nameFg:=0;  /* added by cjchen 1996.11.26*/
  /* oldFilePath includes '\' at end */
  if (oldFilePath := prevUsedPath(TheProjectInfoObj)) then
    if not(indexOf(oldFilePath, '*', 0) cor indexOf(oldFilePath, '?', 0)) then 
      oldFilePath := oldFilePath + "*.ABS";
    else
      oldFilePath := "*.ABS";  
    endif;
  else  
    oldFilePath := "*.ABS";
  endif;
 
  /* Create a modal dialog box and run it */  
  if size(oldFilePath) = 0 then
    oldFilePath := "*.ABS";
  endif;  
  /* Create a LOADFDIALOG dialog */
  tmpDialog := new(LoadFDialog, oldFilePath, 
    tuple(loadFlags(TheProjectInfoObj), loadOnDemand(TheProjectInfoObj)) );
  setHelpEntry(tmpDialog, HE_DLGR_LOAD_FILE);
  if (runModal(tmpDialog, DLG_LOAD_FILE, parent) = IDCANCEL) then
    ^nil;
  endif; 
  /* Get the new loadOptions and LoadFile path */
  newOptions := loadOptions(tmpDialog);
  if not(filePath := loadFile(tmpDialog)) then
    ^nil;
  endif;  
  /* Call to loader to do the load */   
  ^load695(self, filePath, newOptions[1], newOptions[0], hWnd(parent));
}
!!

/* 06/20/92 - PRIVATE 
   Open and initialize library
*/
Def initialise(self, path | lib)
{
  lib := initialise(self:ancestor, path);  
  ^lib;
}
!!

/* PRIVATE
   Define all entry points for library as prototypes.
*/
Def addImportProcs(self)
{
  add( self, #INITCSERVER,        1, #(0, 0)       );
  add( self, #LDRLOADPROGRESS,    1, #(1, 0, 1, 1) );
  add( self, #LDRGETSTARTPC,      1, #(1 )         );
  add( self, #LDRGETSTACK,        1, #(1, 1 )      );
  add( self, #LDRGETOPTIONS,      1, #(1, 1, 1, 1) );
  add( self, #LDRGETLOADREGION,   1, #(0, 1)       );
  add( self, #LDRGETFILESTATUS,   1, #(1, 1)       );
  add( self, #LDRGETTOOLUSE,      1, nil);
  add( self, #LDRSPACEMODE,       0, nil);
}!!

/* 3/23/1992 12:08 - PUBLIC 
  Get the stack base address (stack top) and Size of a loaded loadfile.
  return nil or #(addrDesc, stackSize) 
*/
Def getStackInfo(self | addrDescRef, stackSizeRef)
{ 
  addrDescRef := new(Struct, 4);
  stackSizeRef := new(Struct, 4);

  if pcallLock(self) then
    lastError := pcall( procs[#LDRGETSTACK], addrDescRef, stackSizeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^tuple(longAt(addrDescRef, 0), longAt(stackSizeRef, 0));
}
!!

/* 3/23/1992 12:08 - PUBLIC 
  Get the start PC address of a loaded loadfile.
  return nil and store the error code in lastError if an error occurred
*/
Def getStartPCAddr(self | descRef)
{ 
  descRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall( procs[#LDRGETSTARTPC], descRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^longAt(descRef, 0);
}
!!

/* PUBLIC */
Def load695(self, path, onDemandBool, loadFlags, parentHwnd)
{
  showWaitCurs(); 
  if pcallLock(self) then
    lastError := pcall( procs[#LDRLOADPROGRESS],
                      asciiz(path), onDemandBool, loadFlags, parentHwnd);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  showOldCurs();
  if (lastError <> GOOD) then 
    if ((lastError <> ER_SYM_ALREADY) cand
       (lastError <> ER_LOADFILE_HAD_INCOMPATIBLE_TOOLCHAIN)) then
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;  
    ^nil;
  endif;
  ^GOOD;
}
!!

/* 6/11/1992 10:08 - PUBLIC
  Get the load region of a previous loaded loadfile.
  return nil and store the error code in lastError if an error occurred.
  EX: getLoadedRegionAddr(self, 0);  (Notes 0 = CODE, 1 = DATA, 2 = ROMDATA)
*/
Def getLoadedRegionAddr(self, regionType | descRef)
{
  if (regionType < 0) cor (regionType > 2) then
    ^nil;
  endif;
  descRef := new(Struct, 4);
  if pcallLock(self) then
    lastError := pcall(procs[#LDRGETLOADREGION], asInt(regionType), descRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if lastError <> GOOD then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  ^longAt(descRef, 0);
}
!!
