// This may look like C code, but it is really -*- C++ -*-
// Gestionnaire de lien dynamique   -   R. Ansari 12/98
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include <stdio.h>
#include <stdlib.h>

#include <iostream.h>

#include "pdlmgr.h"

// Extension de noms de fichiers Shared libs
static const char* sofext = ".so";
static const char* sofext_HPUX = ".sl";

// Variables et methodes static
int PDynLinkMgr::numSO = 0;
string*  PDynLinkMgr::tmpDir = NULL;

/* --Methode-Static-- */
void PDynLinkMgr::SetTmpDir(string const & path)
{
if ( (path.length() > 0) && (path[path.length()] != '/')  ) GetTmpDir() = path + '/';
else GetTmpDir() = path;
#if defined(OSF1) || defined(Linux) || defined(SunOS)
  string cmd = "LD_LIBRARY_PATH=";
  char* varenv=NULL;
  varenv=getenv("LD_LIBRARY_PATH");
#elif defined(IRIX64)
  string cmd = "LD_LIBRARYN32_PATH=";
  char* varenv=NULL;
  varenv=getenv("LD_LIBRARYN32_PATH");

  if (varenv == NULL) { 
    cmd += '.';  
    if (path.length() > 0)  cmd += ':' + path; 
    }
  else { 
    if (varenv[0] != '.') cmd += ".:";
    if (path.length() > 0)  cmd += path + ':';
    cmd += varenv;
    putenv(cmd.c_str());
    }
#elif defined(AIX)
  string cmd = "LIBPATH=";
  char* varenv=NULL;
  varenv=getenv("LIBPATH");
  if (varenv == NULL) { 
    cmd += '.';  
    if (path.length() > 0)  cmd += ':' + path; 
    cmd += ":/usr/lib:/lib";
    }
  else { 
    if (varenv[0] != '.') cmd += ".:";
    if (path.length() > 0)  cmd += path + ':';
    cmd += varenv;
    putenv(const_cast<char *>(cmd.c_str()));
    }

#endif
return;
}

/* --Methode-Static-- */
string& PDynLinkMgr::GetTmpDir()
{
if (tmpDir == NULL) { 
  tmpDir = new string("");
  char* varenv;
  if ( (varenv=getenv("PEIDA_TMP")) != NULL )  *tmpDir = varenv; 
  else if ( (varenv=getenv("TMPDIR")) != NULL )  *tmpDir = varenv; 
  }
return(*tmpDir);
}

/* --Methode-Static-- */
PDynLinkMgr* PDynLinkMgr::BuildFromCFile(string const & fname)
{
size_t l = fname.length();
if (l < 1)  return(NULL);
string fnameobj = GetTmpDir()+"tmp_pdl.o";

string cmd;
int rc;

// Compilation du fichier
#ifndef __mac__
cmd = "cc -c -o " + fnameobj + " " + fname;
#else 
cmd = "Il faut compiler !!!" + fnameobj + " " + fname;
#endif
rc = system(cmd.c_str());
if (rc != 0)  { 
  cerr << "PDynLinkMgr::BuildFromCFile() Error Rc(" << cmd <<")= "<< rc << endl; 
  return(NULL);
  }

char buff[32];
numSO++;
#ifndef HPUX
sprintf(buff,"pdlmgr%d%s", numSO,sofext);
#endif
string fnameso = GetTmpDir()+buff;

// Creation du shared-lib
#if defined(OSF1) 
  cmd = "ld -shared -o " + fnameso + " -all " + fnameobj + " -none -lm -lc";
#elif defined(Linux)
  cmd = "ld -shared -o " + fnameso + " " + fnameobj + " -lm -lc";
#elif defined(SunOS)
  cmd = "ld -G -o " + fnameso + " " + fnameobj + " -lm -lc";
#elif defined(IRIX64)
  cmd = "ld -shared -o " + fnameso + " " + fnameobj + " -lm -lc";
#elif defined(AIX)
  cmd = "ld -G -bnogc -bexpall -bM:1L -o " + fnameso + " " + fnameobj;
#elif defined(HPUX)
  cmd = "ld -b -o " + fnameso + " " + fnameobj + " -lm -lc";
#else 
  cmd = "ld -o " + fnameso + " " + fnameobj + " -lm -lc";
#endif
rc = system(cmd.c_str());
if (rc != 0)  { 
  cerr << "PDynLinkMgr::BuildFromCFile() Error Rc(" << cmd <<")= "<< rc << endl; 
  return(NULL);
  }
PDynLinkMgr* rdyn = new PDynLinkMgr(fnameso, false);
rdyn->copy = true;
return(rdyn);

}

/* --Methode-- */
PDynLinkMgr::PDynLinkMgr(string& soname, bool cp)
{
dlhandle = NULL;
soName = "";

if (soname.find_last_of(".") > soname.length())  
#ifdef HPUX
  soname += sofext_HPUX;
#else
  soname += sofext;
#endif

string fnameso;
if (cp) {
  numSO++;
  char buff[32];
#ifndef HPUX
  sprintf(buff,"pdlmgr%d%s", numSO,sofext);
#else
  sprintf(buff,"pdlmgr%d%s", numSO,sofext_HPUX);
#endif
  fnameso = GetTmpDir()+buff;
  string cmd = "cp " + soname + " " + fnameso;
  int rc = system(cmd.c_str());
  if (rc != 0)  { 
    cerr << "PDynLinkMgr::PDynLinkMgr() Error Rc(" << cmd <<")= "<< rc << endl; 
    return;
    }
  } 
else fnameso = soname;
copy = cp;
soName = fnameso;

#if defined(HPUX)
dlhandle = NULL;
cerr << "PDynLinkMgr::PDynLinkMgr() Not yet available on HP-UX " << endl;
return;
#else
dlhandle =  dlopen(fnameso.c_str(), RTLD_NOW);
if (dlhandle == NULL) { 
  cerr << "PDynLinkMgr::PDynLinkMgr(): Error opening SO " << fnameso 
       << " (" << soname << ")" << endl; 
  string sn = dlerror();
  cerr << "Loader Error (dlerror()) :" << sn << endl;
  return; 
  }
#endif
}

/* --Methode-- */
PDynLinkMgr::~PDynLinkMgr()
{
#if defined(HPUX)
cerr << "PDynLinkMgr::~PDynLinkMgr() Not yet available on HP-UX " << endl;
return;
#else
if (dlhandle) dlclose(dlhandle);    dlhandle = NULL;
if (copy) {
  string cmd = "rm -f " + soName;
  system(cmd.c_str());
  }
#endif
}

/* --Methode-- */
DlFunction PDynLinkMgr::GetFunction(string const & funcname)
{
DlFunction f = NULL;
#if defined(HPUX)
cerr << "PDynLinkMgr::GetFunction() Not yet available on HP-UX " << endl;
return f;
#else
if (dlhandle != NULL)  
  f = (DlFunction)dlsym(dlhandle, funcname.c_str());
if (f == NULL) cerr << "PDynLinkMgr::GetFunction(): Error linking " << funcname << endl;
return(f);
#endif
}

