/* 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)!!

/* 6/10/1994 15:28  - PUBLIC
  Terminate Loader Server.
*/
Def terminateServer(self)
{
  if pcallLock(self) then
    lastError := pcall(procs[#TERMINATESERVER]) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif;

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

/* 05/12/94 - PUBLIC
  Display Load information dialog 
*/
Def displayLoadInfo(self | parent)
{
  lastError := GOOD;
  if pcallLock(self)
    lastError := pcall(procs[#LDRINFODIALOG], asLong(getHWnd(ThePort)));
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  ^lastError;
}!!

/* PUBLIC - 07/11/94
  Call the loader to load a loadfile
  PARAMETERS:
    parentHwnd = Windows handle
    loadInfo   = tuple(initpath  = "c:\tbird\m332\*.*"
                       loadSpace  = SPACE_SD, SPACE_USER, etc.
                       loadFlags  = U32 number)
    openDlg    = TRUE : open dialog, FALSE : direct load
*/
Def loaderLoad(self, parentHwnd, loadInfo, openDlg)
{
  showWaitCurs();
  /* Validate parameters */
  if not(loadInfo) or (size(loadInfo) <> 3) then
    ^nil;
  endif;  
  nameFg := 0; /* <Judy 7/2/96> */ 
  if pcallLock(self) then
    lastError := pcall( procs[#LDRLOAD],
                        asciiz(loadInfo[0]),  /* LPSTR - loadFileName */
                        asLong(loadInfo[2]),  /* U32   - loadFlags */
                        asLong(parentHwnd),   /* U32   - parent HWND */ 
                        loadInfo[1],          /* ADDR_SPACE - loadspace*/
                        openDlg);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  showOldCurs();
  if (lastError <> GOOD) then
    /* Error will be reported by the LOADER.DLL */
    ^nil;
  endif;
  ^GOOD;
}
!!

/* PUBLIC -
   Let the user pick the compiler. 
*/
Def selectCompiler(self, parentHwnd)
{
  if pcallLock(self) then         /* 1 = open Compilers Select dialog */                              
    lastError := pcall( procs[#LDRGETTOOLUSE], asLong(parentHwnd), 0L, 1);
    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[#LDRCHECKTIMESTAMP], 
      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, loadSpace, loadFlags) or nil. 
  NOTES: 09/23/93 - changed loadFlags to U32
         05/12/94 - Update to use the new LOADER.DLL
         07/11/94 - Update to support multiple load Space. 
*/
Def getLoadOptions(self | fileRef, loadFlagsRef, spaceRef, fileStr, spaceStr)
{ 
  fileRef      := new(Struct, 128); /* optimize to LOADER predefined values */
  loadFlagsRef := new(Struct, 4);
  spaceRef     := new(Struct, 4); 
  if pcallLock(self) then
    lastError := pcall(procs[#LDRGETLOADINFO], fileRef, loadFlagsRef, spaceRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;
  if (lastError <> GOOD) then
    displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    ^nil;
  endif;
  fileStr := nil;
  if (longAt(fileRef, 0) = 0)
    ^nil; 
  endif;  
  if (fileStr  := removeNulls(physicalString(fileRef))) then
     fileStr := asUpperCase(fileStr);
  endif; 
  ^tuple(fileStr,                  /* string | nil */
         longAt(spaceRef, 0),      /* ADDR_SPACE */
         longAt(loadFlagsRef, 0)   /* U32 */
        );    
}
!!

/* 7/6/1992 12:49 - PUBLIC
  Open the LoadFile dialog box to let the user select a loadfile to load.
  Used the old load information if available.
  EX: 
    invokeLoader(LoaderLibClass$Inst, self);
  Return GOOD if success or nil if fail.
*/
Def invokeLoader(self, parent | oldLoadInfo, loadSpace)
{ 
  /* Use the old loadInfo */
  if not(oldLoadInfo := prevLoadInfo(TheProjectInfoObj)) cor
     not(oldLoadInfo[0]) then
    if (TheProcFamily = PROC_FAMILY_X86) then
      loadSpace := ADDR_SPACE_USER;
    else
      loadSpace := ADDR_SPACE_SD;
    endif;    
    oldLoadInfo := tuple("", loadSpace, 0L); /* defaults */
  endif;
  /* Use the global LoadFlags */
  oldLoadInfo[2] := loadFlags(TheProjectInfoObj);
  
  /* Call to loader launcher to do the load - 1 to open a dialog box */   
  ^loaderLoad(self, hWnd(parent), oldLoadInfo, 1);
}
!!

/* 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, #TERMINATESERVER,    1, nil                );
  add( self, #LDRLOAD,            1, #(1, 1, 1, 0, 0)   );
  add( self, #LDRGETSTARTPC,      1, #(1)               );
  add( self, #LDRGETSTACKINFO,    1, #(1, 1)            );
  add( self, #LDRGETLOADINFO,     1, #(1, 1, 1)         );
  add( self, #LDRCHECKTIMESTAMP,  1, #(1, 1)            );
  add( self, #LDRGETTOOLUSE,      1, #(1, 1, 0)         );
  add( self, #LDRINFODIALOG,      1, #(1)               );
}!!

/* 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[#LDRGETSTACKINFO], addrDescRef, stackSizeRef);
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError <> GOOD) then
    if (asLong(lastError) <> ER_NOTYET_IMPL)
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;  
    ^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
    if (asLong(lastError) <> ER_NOTYET_IMPL) then 
      displayError(ErrorTextLibClass$Inst,lastError, CHECK_MODE);
    endif;  
    ^nil;
  endif;
  ^longAt(descRef, 0);
}
!!
