/****************************************************************************
**
**  Name:  ldrobj.cpp
**
**  Description:
**     Definitions of the Loader Server classes.
**
**  Status:  TESTED
**
**  $Log:   S:/tbird/mt2_186/loader/ldrobj.cpv  $
** 
**    Rev 1.1   26 Feb 1997 11:49:44   Judy
** 
**    Rev 1.0   14 Jun 1996 17:25:34   Judy
** Initial revision.
** 
**    Rev 1.13   13 Oct 1994 17:40:46   nghia
** Added EVENT_LDR_STARTPC to notify when code loading and startPC available.
** 
**    Rev 1.12   11 Oct 1994 11:39:14   nghia
** Added check for valid loader object in table before make the call to the
** loader member function.
** 
**    Rev 1.11   11 Oct 1994 10:26:00   nghia
** Added SaveLoadOptions() and LastLoadOptions() to Loader class.  These methods
** are used in provide the ondemand loading with it original load options.
** Added GetLoadFormat() to validate the supported load format for LdrLauncher
** class.
** 
**    Rev 1.10   28 Sep 1994 12:51:58   nghia
** Checked for load abort to avoid propagate load completed events.
** Added check for correct load format when on demand loading is request.
** 
**    Rev 1.9   02 Sep 1994 13:02:32   nghia
** Fixed bug in GetLoadOptions to set flag when IniGetxxx return GOOD.
** 
**    Rev 1.8   01 Sep 1994 17:59:06   nghia
** Added load option "LoadRegister" to loader option list.
** Revised GetLoadOptions to ignore reading ini item error.
** 
**    Rev 1.7   18 Aug 1994 11:31:18   nghia
** All events notification will be handled by the launcher.
** 
**    Rev 1.6   28 Jul 1994 10:49:30   nghia
** Fixed bug in getLoadOptionsIni() - set flag correctly.
** 
**    Rev 1.5   25 Jul 1994 13:26:42   nghia
** Loader Launcher unload any specific loader in memory when initialize.
** Call SymUpdateSymbolBases if flag is set.
** 
**    Rev 1.4   14 Jul 1994 10:53:16   nghia
** Added function to save/restore load options.
** 
**    Rev 1.3   23 Jun 1994 15:41:54   nghia
** Fixed PPR 9430 - Check for emulation status before down-loading code.
** 
**    Rev 1.2   10 Jun 1994 16:06:42   nghia
** Revised to unload DLL at initialization to avoid using the bogus DLL in
** memory.
** 
**    Rev 1.1   20 May 1994 10:57:52   nghia
** Revised from Code review.
** 
**    Rev 1.0   18 May 1994 16:58:40   nghia
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/loader/ldrobj.cpv   1.1   26 Feb 1997 11:49:44   Judy  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
#include <string.h>
#include <dir.h>
#include <direct.h>

#ifndef _INIUTIL_
#include "iniutil.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _BKROOT_
#include "bkroot.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _LDROBJ_
#include "ldrobj.h"   // LoaderServer Objects
#endif

#ifndef __LDRPROG__
#include "ldrprog.h"  // Load Progress Dialog
#endif


                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
//----------------------------------------------------------------------------
// Initialize LdrLauncher Class Variables (first letter capitalized) 
//
LPSTR LdrLauncher::IniFileName      = "\\Loaders.Ini";
LPSTR LdrLauncher::IniSectionName   = "Loaders";
LPSTR LdrLauncher::IniNumLoaders    = "NumLoaders";
LPSTR LdrLauncher::IniLoaderItem    = "Loader";
CHAR LdrLauncher::PwrViewsDir[]     = "";
BOOLEAN LdrLauncher::HasPwrViewsDir = FALSE;

//----------------------------------------------------------------------------
// PWRVIEWS.INI Source Info Profile
LPSTR LdrLauncher::IniLoadOptions    = "LoadOptions";
LPSTR LdrLauncher::IniLoadCode       = "LoadCode";
LPSTR LdrLauncher::IniLoadSymbol     = "LoadSymbol";
LPSTR LdrLauncher::IniLoadStatus     = "LoadReportStatus";
LPSTR LdrLauncher::IniLoadWarning    = "LoadReportWarning";
LPSTR LdrLauncher::IniLoadAsm        = "LoadAsmModules";
LPSTR LdrLauncher::IniLoadOnDemand   = "LoadOnDemand";
LPSTR LdrLauncher::IniLoadDemangle   = "LoadDemangle";
LPSTR LdrLauncher::IniLoadUpdateBase = "LoadUpdateBase";
LPSTR LdrLauncher::IniLoadRegister   = "LoadRegister";
LPSTR LdrLauncher::IniLoadIgnoreCase = "LoadIgnoreCase";

//----------------------------------------------------------------------------
// Initialize Loader Class Variables (first letter capitalized) 
//
CHAR *Loader::ExportFuncNames[LDR_MAX_FUNC] =
   {
   "LoaderLoad",
   "LoaderLoadModuleByDesc",
   "LoaderGetStartPC",
   "LoaderGetStackInfo"
   };

// Global Loader Server Variable
PTLdrLauncher LoaderServer = NULL;


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern PROCESSOR_FAMILY procFamily;  // defined in LIBMAIN.CPP
extern LDRSTATBLOCK LdrStatus;       // defined in LDRPROG.CPP

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
//----------------------------------------------------------------------------
//
// Class: Loader
//
//----------------------------------------------------------------------------
                         //--------------------------//
                         // CONSTRUCTOR & DESTRUCTOR //
                         //--------------------------//
//-----------------------------------------------------------------------------
// Loader - Ctor
//-----------------------------------------------------------------------------
Loader::Loader(const LPSTR dllName /* = NULL */, U8 numSig /* = 0 */,
               U8* sigList /* = NULL  */,
               LOAD_FORMAT formatId /* = UNKNOWN */) {
   // initialize self
   lastErr = Init(dllName, numSig, sigList, formatId);
}   

//-----------------------------------------------------------------------------
// Loader - Dtor
//-----------------------------------------------------------------------------
Loader::~Loader() {
   // destroy self library instance
   if (hLib) 
      FreeLibrary(hLib);      
}   

                         //--------------------------//
                         //    INITIALIZED METHODS   //
                         //--------------------------//
//-----------------------------------------------------------------------------
// Init
//-----------------------------------------------------------------------------
RETCODE Loader::Init(const LPSTR dllName, U8 numSig, U8* sigList,
                     LOAD_FORMAT formatId) {
   assert(!hLib);    // assert if overwrite an existing object
   assert(libName);  // assert if DLL name is empty
                                  
   // zero out all data members of this object
   memset(this, 0, sizeof(*this));
   
   // save library name and signatures - load loader only when needed.
   if (dllName != NULL) {
      if (!strcpy(libName, dllName))
         return ER_FAILED_STRCPY;
      loadFormat = formatId;
      numSignatures = numSig;
      if (!memcpy(signatureList, sigList, numSig))
         return ER_FAILED_STRCPY;
      HANDLE hLoadedLib = NULL;
      // Make sure that the DLL is not in memory
      // UnLoad the DLL until it is gone
      while ((hLoadedLib = GetModuleHandle((LPSTR) libName)) != NULL) {
         FreeLibrary(hLoadedLib);
      }   
   }
   return GOOD;   
}   

                         //--------------------------//
                         //    ACCESSING METHODS     //
                         //--------------------------//
//-----------------------------------------------------------------------------
// GetFunction
//-----------------------------------------------------------------------------
RETCODE Loader::GetFunction(LDR_FUNC_TYPE funcId, FARPROC *ptFunc) {
   assert(libName);               // assert invalid libName     
   assert(funcId < LDR_MAX_FUNC); // assert invalid function call ID

   // load the DLL if it is not loaded or if it was moved since last loaded
   if (!hLib && ((lastErr = LoadLib()) != GOOD))
      return lastErr;
 
   // retrieve the function directly from funcTable[] of this object
   if (funcTable[funcId] != NULL)
      *ptFunc = funcTable[funcId];
   else
      return ER_LDR_CANNOT_GET_LIB_FUNC;
      
   return lastErr;
} 

//-----------------------------------------------------------------------------
// LastErr
//-----------------------------------------------------------------------------
inline RETCODE Loader::LastErr() { return lastErr; }

//-----------------------------------------------------------------------------
// SaveLoadOptions
//-----------------------------------------------------------------------------
VOID Loader::SaveLoadOptions(U32 flags) { loadOptions = flags; }

//-----------------------------------------------------------------------------
// LastLoadOptions
//-----------------------------------------------------------------------------
inline U32 Loader::LastLoadOptions() { return loadOptions; }

//-----------------------------------------------------------------------------
// LoadFormat
//-----------------------------------------------------------------------------
inline LOAD_FORMAT Loader::LoadFormat() { return loadFormat; }

                         //--------------------------//
                         //    OPERATOR METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATION METHODS     //
                         //--------------------------//
//-----------------------------------------------------------------------------
// LoadLib
//-----------------------------------------------------------------------------
RETCODE Loader::LoadLib() {
   assert(libName);  // assert if no libName to load
   CHAR funcName[MAX_FUNC_NAME], libNameStr[MAX_FILE_NAME];
   CHAR *tmpPtr;

   // Load the DLL if it's not loaded
   if (!hLib && ((hLib = LoadLibrary(libName)) < 32)) {
      LdrWarning(ER_LDR_LOADER_NOT_FOUND, libName, NULL, NULL);
      return ERR_REPORTED(ER_LDR_LOADER_NOT_FOUND);
   }
   if (!strcpy(libNameStr, libName))
      return ER_FAILED_STRCPY;
   // remove the extension part of the library name - <libname>.<ext>
   if ((tmpPtr = strchr(libNameStr, '.')) != NULL)
      *tmpPtr = '\0'; // set terminate character for string
      
   // Load the external interfaces for this object
   for (U8 i = 0; i < LDR_MAX_FUNC; i++) {
      // create the function protocol for specific loader
      if (sprintf(funcName, "%s%s", libNameStr, ExportFuncNames[i]) == NULL) {
         LdrWarning(ER_LDR_CANNOT_CREATE_FUNC_NAME, ExportFuncNames[i],
                    libNameStr, NULL);
         return ERR_REPORTED(ER_LDR_CANNOT_CREATE_FUNC_NAME);
      }
      // Load the export functions into self funcTable
      if ((funcTable[i] = GetProcAddress(hLib, funcName)) == NULL) {
         LdrWarning(ER_LDR_CANNOT_GET_LIB_FUNC, funcName, NULL, NULL);
         return ERR_REPORTED(ER_LDR_CANNOT_GET_LIB_FUNC);
      }
      funcName[0] = '\0'; // reset the function name
   }
   return GOOD;
}

//-----------------------------------------------------------------------------
// UnLoadLib
//-----------------------------------------------------------------------------
RETCODE Loader::UnLoadLib() {

   if (!hLib) 
      return ER_LDR_LOADER_IS_NOT_LOADED;
   // clear the export function table and lastErr 
   memset(funcTable, 0, sizeof(*funcTable) * LDR_MAX_FUNC);     
   // UnLoad the DLL until it is gone
   do {
      FreeLibrary(hLib);
      hLib = GetModuleHandle((LPSTR)libName);
   } while (hLib != NULL);
   
   lastErr = GOOD;
   return GOOD;
}


//-----------------------------------------------------------------------------
// IsLoadFormatMatched
//-----------------------------------------------------------------------------
RETCODE Loader::IsLoadFormatMatched(const LPSTR loadFileName, BOOLEAN *found) {
   FILE *hFile;
   CHAR byte;

   *found = FALSE;
   if ((hFile = fopen(loadFileName, "r")) == NULL) {
      LdrWarning(ER_LDR_LOADFILE_NOT_FOUND, loadFileName, NULL, NULL);
      return ERR_REPORTED(ER_LDR_LOADFILE_NOT_FOUND);
   }
   // seek to beginning of the file 
   if (fseek(hFile, 0, SEEK_SET) != 0) {
      fclose(hFile);
      return ER_BAD_SEEK;
   }
   // get the the first byte
   if ((byte = fgetc(hFile)) == EOF) {
      fclose(hFile);
      return ER_LDR_BAD_LOADFILE;
   }
   // matching Loader signature(s) - 
   for (U8 i = 0; i < numSignatures && !(*found); i++) {
      // matching the signatures and the first byte of the input loadfile
      *found = (byte == signatureList[i]);
   }
   fclose(hFile);
   return GOOD;     
}
                         //--------------------------//
                         //       CLASS METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //       LOCAL METHODS      //
                         //--------------------------//


//// End of Loader

//----------------------------------------------------------------------------
//
// Class: LdrLauncher
//
//----------------------------------------------------------------------------
                         //--------------------------//
                         // CONSTRUCTOR & DESTRUCTOR //
                         //--------------------------//
//-----------------------------------------------------------------------------
// LdrLauncher - Ctor
//-----------------------------------------------------------------------------
LdrLauncher::LdrLauncher() {
   // call Init() to initialize
   status = Init();
}

//-----------------------------------------------------------------------------
// LdrLauncher - Dtor
//-----------------------------------------------------------------------------
LdrLauncher::~LdrLauncher() {
   
   // save the last Load Options
   SaveLoadOptions();
   // destroy the loaders table
   if (numLoaders > 0) {                               
      for (U8 i = 0; i < numLoaders; i++)
          delete ldrObjTable[i];   // destroy Loader object
      TFree((LPSTR)ldrObjTable);   // free Loader objects table
   }
}

                         //--------------------------//
                         //    INITIALIZED METHODS   //
                         //--------------------------//
//-----------------------------------------------------------------------------
// Init
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::Init() {
   RETCODE err;
   FILE *hIniFile;
   HANDLE tmphLib;
   
   // zero out all data members of this object
   memset((void*)this, 0, sizeof(*this));

   // get the PWRVIEWS directory - assumed to be the current working dir
   if (!HasPwrViewsDir) {
      if (_getdcwd(_getdrive(), (CHAR *)PwrViewsDir, MAX_PATH_SIZE) == NULL) 
         return ER_LDR_CANNOT_LOCATE_LOADERS_INI;
      // create the path to IniFileName and check the loaders launcher ini file
      strcat(PwrViewsDir, IniFileName);
   }
   
   if ((hIniFile = fopen(PwrViewsDir, "r")) == NULL) 
      return(ER_LDR_CANNOT_LOCATE_LOADERS_INI);  
   fclose(hIniFile);

   // get number of loaders supported
   if (((err = IniGetNumber((LPSTR) IniSectionName, (LPSTR) IniNumLoaders,
          (LPSTR) PwrViewsDir, (U32 FAR *)&numLoaders)) != GOOD) ||
       (numLoaders == 0)) { 
      return (err != GOOD) ? err : ER_LDR_INVALID_NUM_LOADERS;
   }
   
   // get a valid path to PWRVIEWS directory where LOADER.INI located.
   HasPwrViewsDir = TRUE;
   
   // create table of specific loader
   if ((ldrObjTable = (PTLoader*)TMalloc(sizeof(PTLoader) * numLoaders))
       == NULL)
      return ER_OUT_OF_MEMORY;

   // get information of the specific loader
   //
   // LOADERS.INI format: Loader#=<DLL name>,<num Signatures>,<sig>...
   //
   for (U8 i = 0; i < numLoaders; i++) {
      CHAR keyName[10], tmpStr[MAX_STRING_SIZE];
      // loader Item number started from 1
      sprintf(keyName, "%s%d", IniLoaderItem, (i+1)); 
      // get the specific loader information         
      if (((err = IniGetString((LPSTR) IniSectionName, (LPSTR) keyName,
                               (LPSTR) PwrViewsDir, (LPSTR) tmpStr)) != GOOD)
                               || (strlen(tmpStr) == 0)) {
         return (err != GOOD) ? err : ER_LDR_MISSING_LOADER_INFO;
      }

      //
      // Parse tmpStr into DLL name and loader format signature
      // strtok return the pointer to the token found in tmpStr */
      //
      CHAR *dllNameStr, *numSigStr = NULL, *sigStr, *endPtr;
      U8 numSig, signatures[MAX_SIGNATURES];
      
      // loader library name
      if ((dllNameStr = strtok(tmpStr, DELIMITER_SET)) == NULL)
         return ER_LDR_MISSING_LOADER_LIB_NAME;
      
      // remove the loader.DLL if it is in memory
      while ((tmphLib = GetModuleHandle((LPSTR)dllNameStr)) != 0) 
         FreeLibrary(tmphLib);
      
      // loader number of signature
      numSigStr = strtok(NULL, DELIMITER_SET);
      if (!numSigStr || ((numSig = (U8) strtol(numSigStr, &endPtr, 0)) == 0))
         return ER_LDR_MISSING_LOADER_NUM_SIG;
      if (numSig > MAX_SIGNATURES)
         return ER_LDR_TOO_MANY_SIGNATURES;
      
      // parse each load format signature byte 
      for (U8 j = 0; j < numSig; j++) {
         if ((sigStr = strtok(NULL, DELIMITER_SET)) == NULL)
           return ER_LDR_MISSING_LOADER_SIGNATURE;
         // signature byte can be represented as a numeric value
         // or just a single character
         if (strlen(sigStr) > 1) 
            signatures[j] = (U8) strtol(sigStr, &endPtr, 0);
         else
            signatures[j] = (CHAR) *sigStr;     
      }   

      //
      // create a Loader object with the information
      //
      if ((ldrObjTable[i] = new Loader(dllNameStr, numSig,
                                       signatures, (LOAD_FORMAT) i)) == NULL)
         return ER_OUT_OF_MEMORY;
      if (ldrObjTable[i]->LastErr() != GOOD)
         return ldrObjTable[i]->LastErr();
                             
   } /* for */

   // get the PWRVIEWS.INI LoadOptions setting
   if ((err = GetLoadOptions()) != GOOD)
      return err;
      
   // initialize default address space
   if (procFamily == FAMILY_X86)
      lastLoadAddrSpace = SPACE_USER; // default address space for Intel
   else
      lastLoadAddrSpace = SPACE_SD;   // default address space for Moto
   
   // return error
   return err;
}
                                                     
                         //--------------------------//
                         //    ACCESSING METHODS     //
                         //--------------------------//
//-----------------------------------------------------------------------------
// GetLoadFormat
//-----------------------------------------------------------------------------
RETCODE EXPORT LdrLauncher::GetLoadFormat(const LPSTR loadFileName,
                                          LOAD_FORMAT *loadFormat) {
   RETCODE err;
   BOOLEAN found = FALSE;
   
   // search for a new loader that support the input loadformat
   for (U8 i = 0; (i < numLoaders) && ldrObjTable[i]; i++) {
      if ((err = ldrObjTable[i]->IsLoadFormatMatched(loadFileName, &found))
          != GOOD) return err;
      if (found) {
         // found the supported load format
         *loadFormat = ldrObjTable[i]->LoadFormat(); 
         return GOOD;
      }
   }
   return ER_LDR_UNKNOWN_LOAD_FORMAT;   
}
                         //--------------------------//
                         //    OPERATOR METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATION METHODS     //
                         //--------------------------//
//-----------------------------------------------------------------------------
// Load
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::Load(const LPSTR loadFileName, U32 loadOptions,
                          HWND parentHwnd, ADDR_SPACE loadAddrSpace) {
   RETCODE err;
   FP_LOADPROC lpFuncLoad = NULL;
   U16 dummy;
   LOAD_FORMAT loadFormat;

   // make sure that procesor is halted - error return if it's not halted
   if ((err = BkProcessorMustBeHaltedAbsolute()) != GOOD) return err;
   
   // make sure that only one load operation can occur at a time
   if (isLoading)
     return ER_LDR_IN_PROGRESS;
   isLoading = TRUE;
  
   // get the specific loader for the input loadfile
   if (((err = GetLoader(loadFileName)) != GOOD) ||
       ((err = GetLoaderFunc(LDR_LOAD, (FARPROC *)&lpFuncLoad)) != GOOD)) {
      isLoading = FALSE;
      return err;
   }

   // Setup initial load options for Intel Hex Loader
   if (((err = GetLoadFormat(loadFileName, &loadFormat)) == GOOD) &&
       (loadFormat == INHEX)) {
      loadOptions &= ~LOAD_SYMBOL;
      loadOptions |= LOAD_CODE;
   }

   // save the load information for call back
   lstrcpy(lastLoadFileName, loadFileName);
   lastLoadOptions   = loadOptions;
   lastParentHwnd    = parentHwnd;
   lastLoadAddrSpace = loadAddrSpace;

   // save the load option to the loader for ondemand loading
   lastActiveLoader->SaveLoadOptions(loadOptions);

   // determine whether the load operation is requested from the Shell
   if (IsLoadFromShell(loadOptions) || !IsReportStatus(loadOptions))
      // call the specific loader to do the loading operation
      err = lpFuncLoad(loadFileName, loadOptions, parentHwnd, loadAddrSpace);
   else
      err = LdrProgressDialog(parentHwnd, lpFuncLoad);

   // handle Update Symbol Base only if load without error
   if ((err == GOOD) && (procFamily == FAMILY_X86)) {
      if (IsUpdateBase(loadOptions))
         err = SymUpdateSymbolBases(&dummy);
   }
   // turn off Loading semaphore
   isLoading = FALSE;
   
   // Only propagate event if no error occurred in loading operation
   if (err != GOOD)
      // filter out Load abort error
      return ((err == ER_LDR_ABORT) ? GOOD : err);
   
   // load code then update memory and stack
   if (IsLoadCode(loadOptions)) {
      EnlEventNotify(EVENT_LDR_MEMCHANGED);   
      // if there is stack information
      if (LdrStatus.stackBase[0] != NULL)
         EnlEventNotify(EVENT_LDR_STACKTOP);
   }
   // notify load complete to update symbol information
   EnlEventNotify(EVENT_LDR_LOADCOMPLETE);
   // if load code and startPC available then notify
   if (IsLoadCode(loadOptions) && (LdrStatus.startPC[0] != NULL)) {  
      EnlEventNotify(EVENT_LDR_STARTPC);   
   }
   return GOOD;
}

//-----------------------------------------------------------------------------
// LoadModuleByDesc
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::LoadModuleByDesc(const LPSTR loadFileName,
                                      const LPSTR moduleName,
                                      SYM_DESCRIPTOR moduleDesc,
                                      ADDR_SPACE loadAddrSpace) {

   RETCODE err;
   FP_LOADBYDESCPROC lpFuncLoadByDesc = NULL;
         
   // make sure that only one load operation can occur at a time
   if (isLoading)
     return ER_LDR_IN_PROGRESS;
   isLoading = TRUE;

   // use the last active loader 
   if (!lastActiveLoader || (lastActiveLoader->LastErr() != GOOD)) {
      isLoading = FALSE;
      return ER_LDR_LOADER_IS_NOT_LOADED;
   }
   
   // recheck the last active loader for correct load format.
   if (((err = GetLoader(loadFileName)) != GOOD) ||
       ((err = GetLoaderFunc(LDR_LOADBYDESC, (FARPROC *)&lpFuncLoadByDesc))
       != GOOD)) {
      isLoading = FALSE; 
      return err;
   }

   // call the specific loader to load ondemand the module specified
   err = lpFuncLoadByDesc(loadFileName, moduleName, moduleDesc,
                          loadAddrSpace,
                          lastActiveLoader->LastLoadOptions());
   isLoading = FALSE;
   return err;
}

//-----------------------------------------------------------------------------
// GetStartPC
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetStartPC(DESCRIPTOR FAR *lpAddrDesc) {
   RETCODE  err;
   FP_GETPCPROC lpFuncGetPC = NULL;
       
   // use the last active loader
   if (!lastActiveLoader || (lastActiveLoader->LastErr() != GOOD))
      return ER_LDR_LOADER_IS_NOT_LOADED;

   if ((err = GetLoaderFunc(LDR_GETPC, (FARPROC *)&lpFuncGetPC)) != GOOD)
      return err;

   // call the specific loader
   return lpFuncGetPC((DESCRIPTOR FAR*)lpAddrDesc);
}

//-----------------------------------------------------------------------------
// GetStackInfo
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetStackInfo(DESCRIPTOR FAR *lpAddrDesc,
                                             U32 FAR* lpStkSize) {
   RETCODE   err;
   FP_GETSTKPROC lpFuncGetStk;
       
   // use the last active loader
   if (!lastActiveLoader || (lastActiveLoader->LastErr() != GOOD))
      return ER_LDR_LOADER_IS_NOT_LOADED;

   if ((err = GetLoaderFunc(LDR_GETSTK, (FARPROC *)&lpFuncGetStk)) != GOOD)
      return err;

   // call the specific loader
   return lpFuncGetStk(lpAddrDesc, lpStkSize);
}

//-----------------------------------------------------------------------------
// GetLoadInfo
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetLoadInfo(LPSTR lpFileName, U32 FAR* lpOptions,
                                 ADDR_SPACE FAR *lpLoadAddrSpace) {
   // use the last active loader
   if (!lastActiveLoader || (lastActiveLoader->LastErr() != GOOD)) 
      return ER_LDR_LOADER_IS_NOT_LOADED;
   // copy the last load information  
   lstrcpy(lpFileName, (LPSTR)lastLoadFileName);
   *lpOptions       = lastLoadOptions;
   *lpLoadAddrSpace = lastLoadAddrSpace;
   return GOOD;
}


                         //--------------------------//
                         //       CLASS METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //       LOCAL METHODS      //
                         //--------------------------//

//-----------------------------------------------------------------------------
// GetLoader
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetLoader(const LPSTR loadFileName) {
   assert(status == GOOD);  // assert if LdrLauncher object has bad status
   assert(numLoaders && ldrObjTable);
   RETCODE err;
   BOOLEAN found = FALSE;   

   // try the last active loader first - might be the same loader
   if (lastActiveLoader) {
      // reload a new loader if the lastActiveLoader had error or
      // it's not the correct loader for the input loadfile
      if ((lastActiveLoader->LastErr() == GOOD) &&
          (lastActiveLoader->IsLoadFormatMatched(loadFileName, &found)
           == GOOD) && (found)) {
         return GOOD; // use the lastActiveLoader
      }    
      // unload the lastActiveLoader to load a new loader
      lastActiveLoader->UnLoadLib();
      lastActiveLoader = NULL;
   }

   // search for a new loader that support the input loadformat
   for (U8 i = 0; i < numLoaders; i++) {
      if ((err = ldrObjTable[i]->IsLoadFormatMatched(loadFileName, &found))
          != GOOD) return err;
      if (found) break;  // found the loader for the input loadfile format
      
   }
   // found the loader that handles the input loadfile format
   // load the loader into memory and save it as the last active Loader
   if (found) { 
      lastActiveLoader = ldrObjTable[i];
      return lastActiveLoader->LoadLib();
   }
   return ER_LDR_UNKNOWN_LOAD_FORMAT;
}
   
//-----------------------------------------------------------------------------
// GetLoaderFunc
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetLoaderFunc(LDR_FUNC_TYPE funcId, FARPROC *lpLdrFunc) {
   assert(status == GOOD);  // assert if LdrLauncher object has bad status

   if (!lastActiveLoader && (lastActiveLoader->LastErr() != GOOD))
      return ER_LDR_LOADER_IS_NOT_LOADED;

   // let the Loader object  
   return lastActiveLoader->GetFunction(funcId, lpLdrFunc);
}

//-----------------------------------------------------------------------------
// GetLoadOptions
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::GetLoadOptions(VOID) {
   U32 flag;
   
   // all load options off for the default lastLoadOptions 
   lastLoadOptions = 0L;

   // get load option from the PWRVIEWS.INI
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadCode,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_CODE : 0L);

   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadSymbol,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_SYMBOL : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadStatus,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_STATUS : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadWarning,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_WARNING : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadAsm,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_ASM : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadOnDemand,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_ONDEMAND : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadDemangle,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_DEMANGLE : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadUpdateBase,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_UPDATE_BASE : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadRegister,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_REGISTERS : 0L);
   
   if (IniGetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadIgnoreCase,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32 FAR *)&flag) == GOOD)
      lastLoadOptions |= (flag ? LOAD_IGNORE_CASE : 0L);
   
   // done
   return GOOD;
}

//-----------------------------------------------------------------------------
// SaveLoadOptions
//-----------------------------------------------------------------------------
RETCODE LdrLauncher::SaveLoadOptions() {
   RETCODE err;
   
   // save load option to the PWRVIEWS.INI
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadCode,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsLoadCode(lastLoadOptions)))
       != GOOD) return err;

   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadSymbol,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsLoadSymbol(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadStatus,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsReportStatus(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadWarning,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsReportWarning(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadAsm,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsLoadAsm(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadOnDemand,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsLoadOnDemand(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadDemangle,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsDeMangle(lastLoadOptions)))
       != GOOD) return err;

   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadUpdateBase,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsUpdateBase(lastLoadOptions)))
       != GOOD) return err;
   
   if ((err = IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadRegister,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsLoadReg(lastLoadOptions)))
       != GOOD) return err;
   
   return IniSetNumber((LPSTR) IniLoadOptions, (LPSTR) IniLoadIgnoreCase,
       (LPSTR) PWRVIEWS_INI_DEFAULT, (U32) IsIgnoreCase(lastLoadOptions));
}   
//// End of LdrLauncher

/********************************** E O F ***********************************/
