//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
// 
// Description:
//	 shObjLoader class (implementation)
//	
// Author:  Jie Chen
//
// Revision History:
//   shObjLoader.cc,v
// Revision 1.7  1996/03/22  16:31:59  chen
// support solaris
//
// Revision 1.6  1995/11/14  17:33:46  chen
// fix to work under irix5.3
//
// Revision 1.5  1995/10/26  14:33:18  akers
// Removal of Warnings
//
// Revision 1.4  1995/10/18  17:45:00  chen
// To work under SunOs
//
// Revision 1.3  1995/10/17  13:25:25  chen
// Change load (int flag) to load (void)
//
// Revision 1.2  1995/06/30  15:02:13  chen
// use cxx_shload
//
// Revision 1.1.1.1  1995/06/16  17:14:02  epics
// initial import of cdev
//
//
#include <string.h>
#include <cdevSystem.h>
#include <cdevErrCode.h>
#include "shObjLoader.h"

shObjLoader::shObjLoader (char *path)
{
#ifdef _TRACE_OBJECTS
  printf("Create shObjLoader class \n");
#endif
  libName_ = new char[::strlen (path) + 1];
  ::strcpy (libName_, path);
#ifdef __hpux
  libHandler_ = 0;
  desc_ = 0;
#endif

#if defined (sunos4) || defined (sgi) || defined (solaris) || defined (aix) || defined (__linux)
  libHandler_ = 0;
#endif

#if defined (_WIN32)
  libHandler_ = NULL;
#endif
}

shObjLoader::~shObjLoader (void)
{
#ifdef _TRACE_OBJECTS
  printf("Delete shObjLoader class \n");
#endif  
  this->close ();
}

int
shObjLoader::open (char *name)
{
  if (libName_){
    delete []libName_;
    libName_ = 0;
  }
  libName_ = new char[::strlen(name) + 1];
  ::strcpy (libName_, name);
  return 0;
}


int
shObjLoader::load (void)
{
#ifdef SHOBJ
#ifdef __hpux

  if ((libHandler_ = HP_SHOBJ_LOADER(libName_, BIND_IMMEDIATE | BIND_VERBOSE, 0)) == 0){
    perror ("shl_load: error loading library");
    return -1;
  }
#endif // __hpux

#ifdef sunos4
  libHandler_ = ::dlopen (libName_, RTLD_LAZY);
#endif

#if defined (sgi) || defined (solaris) || defined (aix) || defined (__linux)
  libHandler_ = ::dlopen (libName_, RTLD_NOW);
#endif

#if defined (sunos4) || defined (sgi) || defined (solaris) || defined (aix) || defined (__linux)
  if (libHandler_ == 0) {
    #ifdef __linux
	fprintf(stdout, "Attempt to load library %s failed\n%s\n", libName_, dlerror());
    #endif
	perror ("dlopen: error loading library");
    return -1;
  }
#endif  // endif sun or sgi or linux

#if defined (_WIN32)
  libHandler_ = LoadLibrary (libName_);
  if (libHandler_ == NULL) {
    cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL, 
		"Cannot open dll library %s - ErrorCode %i\n", libName_, GetLastError());
    return -1;
  }
#endif

  return 0;
#else
  return 0;
#endif // end if SHOBJ
}

int 
shObjLoader::findProcedureSym 
#ifdef SHOBJ
  (const char * sym, void** value)
#else
  (const char *, void **)
#endif
{
#ifdef SHOBJ

#ifdef __hpux
  int status = ::shl_findsym (&libHandler_, sym, TYPE_PROCEDURE, 
			      (void *)value);
  return status;
#endif

#if defined (sunos4) || defined (sgi) || defined (solaris) || defined (aix) || defined (__linux)
  int status = 0;
  void *val = 0;
  val = ::dlsym (libHandler_, (char *)sym);
  if (val == 0) {
    status = -1;
    *value = 0;
  }
  else 
    *value = val;
  return status;
#endif // sun or sgi or linux

#if defined (_WIN32)
  int status = 0;
  *value = (void *)GetProcAddress (libHandler_, sym);
  if (*value == NULL) {
    cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"Cannot find function %s\n", sym);
    FreeLibrary (libHandler_);
    status = -1;
  }
  return status;
#endif

#else
  return 0;
#endif
}

#ifdef __hpux
int 
shObjLoader::findDataSym
#ifdef SHOBJ
  (const char * sym, void* value)
#else
  (const char *, void *)
#endif
{
#ifdef SHOBJ
  int status = :: shl_findsym (&libHandler_, sym, TYPE_DATA, value);
  return status;
#else
  return 0;
#endif
}

int 
shObjLoader::findSym
#ifdef SHOBJ
  (const char * sym, void* value)
#else
  (const char *, void *)
#endif
{
#ifdef SHOBJ
  int status = :: shl_findsym (&libHandler_, sym, TYPE_UNDEFINED, value);
  return status;
#else
  return 0;
#endif
}

unsigned long
shObjLoader::textStartAddr (void)
{
#ifdef SHOBJ
  if (!libHandler_){
    cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"No shared library handler yet.");
    return 0;
  }
  if (!desc_){
    int status = shl_gethandle (libHandler_, &desc_);
    if (status == -1){
      cdevSystem::defaultSystem().reportError(
	  	CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"Invalid library handle.");
      desc_ = 0;
      return 0;
    }
    return desc_->tstart;
  }
#endif
  return 0;
}

unsigned long
shObjLoader::textEndAddr (void)
{
#ifdef SHOBJ
  if (!libHandler_){
	cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"No shared library handler yet.");
    return 0;
  }
  if (!desc_){
    int status = shl_gethandle (libHandler_, &desc_);
    if (status == -1){
      cdevSystem::defaultSystem().reportError(
	  	CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"Invalid library handle.");
      desc_ = 0;
      return 0;
    }
    return desc_->tend;
  }
#endif
  return 0;
}

unsigned long
shObjLoader::dataStartAddr (void)
{
#ifdef SHOBJ
  if (!libHandler_){
	cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"No shared library handler yet.");
    return 0;
  }
  if (!desc_){
    int status = shl_gethandle (libHandler_, &desc_);
    if (status == -1){
      cdevSystem::defaultSystem().reportError(
	  	CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"Invalid library handle.");
      desc_ = 0;
      return 0;
    }
    return desc_->dstart;
  }
#endif
  return 0;
}  

unsigned long
shObjLoader::dataEndAddr (void)
{
#ifdef SHOBJ
  if (!libHandler_){
	cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"No shared library handler yet.");
    return 0;
  }
  if (!desc_){
    int status = shl_gethandle (libHandler_, &desc_);
    if (status == -1){
      cdevSystem::defaultSystem().reportError(
	  	CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"Invalid library handle.");
      desc_ = 0;
      return 0;
    }
    return desc_->dend;
  }
#endif
  return 0;
}
#endif // __hpux

const char *
shObjLoader::filename (void)
{
#ifdef SHOBJ
  if (libHandler_ == 0){
	cdevSystem::defaultSystem().reportError(
		CDEV_SEVERITY_ERROR, "shObjLoader", NULL,
		"No shared library handler yet.");
    return 0;
  }
  return libName_;
#else
  return 0;
#endif
}

int
shObjLoader::close (void)
{
#ifdef SHOBJ
  if (libHandler_){
#ifdef __hpux
    int status = HP_SHOBJ_UNLOADER (libHandler_);
    desc_ = 0;
#endif // __hpux

#if defined (sunos4) || defined (sgi) || defined (solaris) || defined (aix) || defined (__linux)
    int status = ::dlclose (libHandler_);
#endif // sun or sgi

#if defined (_WIN32)
    int status;
    if (!FreeLibrary (libHandler_))
      status = -1;
    else
      status = 0;
#endif

    libHandler_ = 0;

    if (libName_)
      delete []libName_;
    libName_ = 0;
    return status;
  }
  else
    return 0;
#endif
  return 0;
}

#ifdef SHOBJ
#include <math.h>
// trick dld to load all these math functions
void touch_math (void)
{
  double x = sin (1.0);
  x = cos (1.0);
  x = tan (1.0);
  x = asin (1.0);
  x = acos (1.0);
  x = atan (1.0);
  x = cosh (1.0);
  x = sinh (1.0);
  x = tanh (1.0);
  x = log (1.0);
  x = exp (1.0);
  x = sqrt (1.0);
  x = log10 (1.0);
  x = ceil (1.0);
  x = floor (1.0);
}
#endif
