/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1993-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * $Id:$
 */

/*
 * This file is 'a hell of a file'. It contain _anything_ that is neither
 * POSIX nor ANSI. The meaning is that when these things are needed in 
 * the code, they are located in a wrapper in this file. Thus, if you need 
 * to hack the code, it's likely that you only need to hack this file. 
 * 
 * At least, that's the theory ...
 */

#if defined(WIN32)
# include <windows.h>
#endif

#if defined(OS2)
# define INCL_DOSMODULEMGR
# include <os2.h>
# define DONT_TYPEDEF_PFN
#endif

#ifdef _POSIX_SOURCE
# undef _POSIX_SOURCE
#endif

#include "rexx.h"


#ifdef DYNAMIC

/*
 * Most Unix systems have dlopen(), so set this as the default and
 * unset it for platforms that don't have it
 */
# if defined(HAVE_DLFCN_H)
#  define DYNAMIC_DLOPEN
# endif

# if defined(__hpux)
#  define DYNAMIC_HPSHLOAD
# endif

# if defined(DYNAMIC_DLOPEN)
#  include <dlfcn.h>
   typedef void *handle_type ;
#  ifndef RTLD_LAZY
#   define RTLD_LAZY 1
#  endif

# elif defined(DYNAMIC_AIXLOAD)
#  include <sys/types.h>
#  include <sys/ldr.h>
   typedef int (*handle_type) ;

# elif defined(DYNAMIC_HPSHLOAD)
#  include <dl.h>
   typedef shl_t handle_type ;

# elif defined(DYNAMIC_OS2)
   typedef HMODULE handle_type ;
/*  typedef PHMODULE handle_type ; */

# elif defined(DYNAMIC_WIN32)
   typedef HINSTANCE handle_type ;
#endif /* DYNAMIC */

#include <errno.h>
#include <string.h>

#ifdef DYNAMIC_HPSHLOAD
/* 
 * HP/UX doesn't find symbols unless they are 'true data'; entrypoints
 * for functions are not sufficient! Thus, we need to force it to 
 * 'release' that these symbols are defined. There's no need to do 
 * anything more, once it sets some flag somewhere ... it'll find'em
 * later. Weird!
 *
 * Datatype char only used to save space ... this is never used, so 
 * there is no reason to waste space.
 */

char Food_For_Fuzzy_HP_Linkers[] = {
   (char)exiterror, (char)get_a_chunk, (char)getonechar,
   (char)nullstringptr, (char)get_a_streng, (char)Str_cre,
   (char)atozpos, (char)checkparam, (char)loadrxfunc, (char)Str_cmp,
   (char)Str_cat, (char)give_a_chunk } ;
#endif

#if defined(DYNAMIC_AIXLOAD)
void *wrapper_dummy_for_aix( void )
{
}
#endif

void *wrapper_load( streng *module ) 
{
   streng *new_module=NULL ;
   handle_type handle=NULL ;
   char *msg=NULL;
#if defined(DYNAMIC_OS2)
/*   HMODULE handle_buffer;*/
   CHAR LoadError[256];
   APIRET rc=0L;
#endif
#if defined(DYNAMIC_WIN32)
   char LoadError[256];
#endif

   new_module = Str_ify( module ) ;

#if defined(DYNAMIC_DLOPEN)
   handle = dlopen( new_module->value, RTLD_LAZY ) ;
   if (handle==NULL)
     {
      msg = dlerror();
      if (msg)
        {
         set_err_message( msg ) ;
        }
      else
         set_err_message("");
     }
#elif defined(DYNAMIC_HPSHLOAD)
   handle = shl_load( new_module->value, BIND_IMMEDIATE | BIND_VERBOSE, 0L ) ;
   if (handle==NULL)
      set_err_message( strerror(errno)) ;
#elif defined(DYNAMIC_AIXLOAD)
   handle = load( new_module->value, 1, NULL ) ;
   if (handle)
     {
      int rc=loadbind( 0, (void *)wrapper_dummy_for_aix, (void *)handle ) ;
      if (rc)
         handle = NULL ;
     }
   else
      set_err_message( strerror( errno )) ;
#elif defined(DYNAMIC_OS2)
   rc = DosLoadModule( LoadError, sizeof(LoadError), 
                       new_module->value, &handle ) ;
/*   handle = &handle_buffer;  */
   if (rc)
     {
      set_err_message(LoadError);
      handle = NULL;
     }
#elif defined(DYNAMIC_WIN32)
   handle = LoadLibrary( new_module->value ) ;
   if (handle==NULL)
     {
      FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL ) ;
      set_err_message(LoadError);
     }
#endif

   if (new_module != module)
      Free_string( new_module ) ;

   return (void *)handle ;
}

#ifdef REGINA_0_07A
void *wrapper_getentries( handle_type handle )
{
   void *addr ;

#if defined(DYNAMIC_DLOPEN) 
   addr = (void *)dlsym( handle, "initial" ) ;
   if (addr==NULL)
      set_err_message( dlerror()) ;
#elif defined(DYNAMIC_HPSHLOAD)
   {
      long eaddr ;
      if (shl_findsym( &handle, "initial", TYPE_PROCEDURE, &eaddr ))
      {
         addr = NULL ;
         set_err_message( strerror(errno)) ;
      }
      else 
         addr = (void *)eaddr ;
   }
#elif defined(DYNAMIC_AIXLOAD) 
   addr = handle ;
#elif defined(DYNAMIC_WIN32)
   addr = handle;
#endif
   if (addr)
      return (void *)addr ;
   else
      return NULL ;
}
#endif /* REGINA_0_07A */

PFN wrapper_get_addr( struct library *lptr, streng *name)
{
   PFN addr;
   handle_type handle=(handle_type)lptr->handle;
   streng *newname=NULL ;
#if defined(DYNAMIC_OS2)
   APIRET rc=0L;
#endif

   newname = Str_ify( name ) ;

#if defined(DYNAMIC_DLOPEN) 
   /*
    * Note, the following assignment is not allowed by ANSI, but SVR4.2 
    * includes it as an example, so it is probably safe in this context
    */
   addr = (PFN)(dlsym( handle, newname->value )) ;
   if (addr==NULL)
      set_err_message( dlerror()) ;
#elif defined(DYNAMIC_HPSHLOAD)
   {
      long eaddr ;
      if (shl_findsym( &handle, newname->value, TYPE_PROCEDURE, &eaddr ))
      {
         addr = NULL ;
         set_err_message( strerror(errno)) ;
      }
      else 
         addr = (PFN)eaddr ;
   }
#elif defined(DYNAMIC_AIXLOAD) 
   addr = (PFN)handle ;
#elif defined(DYNAMIC_OS2)
   rc = DosQueryProcAddr(handle,0L,newname->value,&addr);
   if (rc)
      set_err_message( "DosQueryProcAddr() failed") ;
#elif defined(DYNAMIC_WIN32)
   addr = (PFN)GetProcAddress(handle,(HMODULE)newname->value);
   if (addr == NULL)
      set_err_message( strerror(errno)) ;
#endif
   Free_string( newname ) ;
   if (addr)
      return (PFN)addr ;
   else
      return NULL ;
}

#endif /* DYNAMIC */
