707 lines
18 KiB
C
707 lines
18 KiB
C
//
|
|
// Copyright (C) 2001, 2000, 1999, Rildo Pragana, Jim Noeth,
|
|
// Andrew Cameron, David Essex.
|
|
// Copyright (C) 1993, 1991 Rildo Pragana.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation; either version 2.1,
|
|
// 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 Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; see the file COPYING.LIB. If
|
|
// not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
|
// Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
//
|
|
// TinyCOBOL Run Time Library
|
|
// Dynamic CALL statement functions
|
|
//
|
|
|
|
#include "htcoblib.h"
|
|
#include "rterrors.h"
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
|
|
#define SUBR_HASHLEN 128
|
|
#define HTCOB_PATH_PWD_STR "."
|
|
|
|
/* max of 64 chars sub-routine names */
|
|
#define HTCOB_DYNLIBS_MAX_NAME 65
|
|
|
|
#ifdef __MINGW32__
|
|
#include "dlfcnwin32.h"
|
|
#else
|
|
#include <dlfcn.h>
|
|
#include <glob.h>
|
|
#endif // MINGW32
|
|
|
|
#ifdef __WINDOWS__
|
|
#define HTCOB_DYNLIBS_PATTERN "*.dll"
|
|
#define HTCOB_DYNLIBS_SUFIX ".dll"
|
|
#define HTCOB_PATH_SEP_CHAR ';'
|
|
#define HTCOB_PATH_DELIM_STR "\\"
|
|
#else
|
|
#define HTCOB_DYNLIBS_PATTERN "*.so"
|
|
#define HTCOB_DYNLIBS_SUFIX ".so"
|
|
#define HTCOB_PATH_SEP_CHAR ':'
|
|
#define HTCOB_PATH_DELIM_STR "/"
|
|
#endif
|
|
|
|
extern struct runelement_info *running_element; // walter 12-12-05 /* the current run element */
|
|
extern struct element_order *elementorder; // walter 12-12-05
|
|
|
|
/* store sub-routine names */
|
|
static char subrname[PATH_MAX];
|
|
static char subr_libname[PATH_MAX];
|
|
|
|
static struct resolve_handle
|
|
{
|
|
void *handle;
|
|
struct resolve_handle *next;
|
|
} *resolve_handles = NULL;
|
|
|
|
/*
|
|
this mini-symtable will register previously called subroutines
|
|
to speed up resolving their names to pointers
|
|
*/
|
|
static struct subr_desc
|
|
{
|
|
char name[255];
|
|
void *(*subr)();
|
|
struct subr_desc *next;
|
|
|
|
} subrtab[SUBR_HASHLEN];
|
|
|
|
#ifndef __MINGW32__
|
|
static char libs_pattern[] = HTCOB_DYNLIBS_PATTERN;
|
|
#endif
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| subr_hash |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
subr_hash(char *s)
|
|
{
|
|
int val = 0, i;
|
|
for (i = 0; s[i] != '\0'; i++)
|
|
val += s[i];
|
|
return (val % SUBR_HASHLEN);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| savename |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
static char *
|
|
savename(char *s)
|
|
{
|
|
char *ap;
|
|
if ((ap = (char *) tcob_malloc(strlen(s) + 1)) != NULL)
|
|
strcpy(ap, s);
|
|
return (ap);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| subr_lookup |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
static int initialized = 0;
|
|
|
|
static struct subr_desc *
|
|
subr_lookup(char *s)
|
|
{
|
|
struct subr_desc *sd;
|
|
if (!initialized)
|
|
{
|
|
memset(&subrtab[0], 0x00, sizeof (subrtab));
|
|
initialized = 1;
|
|
return NULL;
|
|
}
|
|
|
|
for (sd = &subrtab[subr_hash(s)]; sd != NULL; sd = sd->next)
|
|
if (strcmp(s, sd->name) == 0)
|
|
return sd;
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| subr_install |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
static struct subr_desc *
|
|
subr_install(char *name, void *(*subr)())
|
|
{
|
|
int val;
|
|
struct subr_desc *sd = subr_lookup(name);
|
|
|
|
struct element_order *eo = NULL;
|
|
struct element_order *eop = NULL;
|
|
|
|
if (sd == NULL)
|
|
{
|
|
sd = tcob_malloc(sizeof (struct subr_desc));
|
|
if (sd == NULL)
|
|
return NULL;
|
|
|
|
strcpy(sd->name, name);
|
|
|
|
val = subr_hash(sd->name);
|
|
sd->next = &subrtab[val];
|
|
sd->subr = subr;
|
|
memcpy(&subrtab[val], sd, sizeof (struct subr_desc));
|
|
free(sd);
|
|
}
|
|
|
|
eo = elementorder;
|
|
|
|
eop = eo;
|
|
|
|
while (eo)
|
|
{ // find module name
|
|
if (!strcmp(name, eo->module_name))
|
|
break;
|
|
eop = eo;
|
|
eo = eo->next;
|
|
}
|
|
|
|
if (!eo)
|
|
{
|
|
eo = calloc(1, sizeof (struct element_order));
|
|
|
|
if (!elementorder) // first try
|
|
elementorder = eo;
|
|
else
|
|
eop->next = eo;
|
|
|
|
eo->module_name = savename(name);
|
|
eo->who_call = savename(running_element->name); //calloc(1, strlen(running_element->name)+1);
|
|
eo->next = NULL;
|
|
}
|
|
|
|
return sd;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| subr_uninstall |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
subr_uninstall(char *name)
|
|
{
|
|
struct subr_desc *sd = NULL;
|
|
struct subr_desc *ant = NULL;
|
|
int hash;
|
|
hash = subr_hash(name);
|
|
|
|
for (sd = &subrtab[hash]; sd; sd = sd->next)
|
|
{
|
|
if (strcmp(name, sd->name) == 0)
|
|
{
|
|
if (!ant)
|
|
memcpy(&subrtab[hash], sd->next, sizeof (struct subr_desc));
|
|
else
|
|
ant->next = sd->next;
|
|
|
|
memset(sd,0x00, sizeof (struct subr_desc));
|
|
|
|
return;
|
|
}
|
|
|
|
ant = sd;
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| module_install |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
static void
|
|
module_install(void *module)
|
|
{
|
|
struct resolve_handle *rh;
|
|
|
|
rh = tcob_malloc(sizeof (struct resolve_handle));
|
|
|
|
rh->handle = module;
|
|
rh->next = resolve_handles;
|
|
|
|
resolve_handles = rh;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| tcob_resolve_subr_error |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
void
|
|
tcob_resolve_subr_error(void)
|
|
{
|
|
fprintf(stderr, "*** RT Error: dynamic library call \"%s\" not found!\n",subrname);
|
|
}
|
|
|
|
/*
|
|
*
|
|
* tcob_resolve_in_previous_libs
|
|
*
|
|
* Try to resolve a routine handler on previous opened libs
|
|
*
|
|
*
|
|
*/
|
|
static void *
|
|
tcob_resolve_in_previous_libs(char *subrname)
|
|
{
|
|
struct resolve_handle *rh;
|
|
void *(* _dynsubr)() = NULL;
|
|
|
|
for (rh = resolve_handles; rh != NULL; rh = rh->next)
|
|
{
|
|
|
|
_dynsubr = dlsym(rh->handle, subrname);
|
|
if (_dynsubr != NULL)
|
|
{
|
|
subr_install(subrname, _dynsubr);
|
|
return _dynsubr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* tcob_cancel_subr
|
|
*
|
|
* Cancel a dynamically loaded module and uninstall it.
|
|
*
|
|
*/
|
|
void
|
|
tcob_cancel_subr(char *name, char *running)
|
|
{
|
|
struct element_order *eo;
|
|
struct element_order *eop;
|
|
|
|
eo = elementorder;
|
|
eop = eo;
|
|
|
|
while (eo)
|
|
{
|
|
if (strcmp(name, eo->module_name) != 0)
|
|
break;
|
|
|
|
eop = eo;
|
|
eo = eo->next;
|
|
}
|
|
|
|
if (!eo)
|
|
return;
|
|
|
|
if (strcmp(running, eo->who_call) != 0) // you can't remove module that you did't call
|
|
return;
|
|
|
|
eop->next = NULL;
|
|
if (eo->next)
|
|
eop->next = eo->next;
|
|
if (eo == elementorder)
|
|
{
|
|
free(elementorder);
|
|
elementorder = eop->next;
|
|
}
|
|
else
|
|
free(eo);
|
|
|
|
subr_uninstall(name);
|
|
}
|
|
|
|
/*
|
|
* tcob_find_in_lib
|
|
*
|
|
* Try to find a library handler on a library name
|
|
*
|
|
*/
|
|
static void *
|
|
tcob_find_in_lib(char *rutname, char *libname)
|
|
{
|
|
|
|
void *(* _dynsubr)() = NULL;
|
|
void *module;
|
|
|
|
module = dlopen(libname, RTLD_LAZY);
|
|
|
|
if (module != NULL)
|
|
{
|
|
_dynsubr = dlsym(module, subrname);
|
|
if (_dynsubr != NULL)
|
|
{
|
|
subr_install(rutname, _dynsubr);
|
|
// save for speeding up next search
|
|
module_install(module);
|
|
// return the resolved handler
|
|
return _dynsubr;
|
|
}
|
|
dlclose(module);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* tcob_resolve
|
|
*
|
|
* Try to resolve the routine name
|
|
* The paths specified by LD_LIBRARY_PATH and TCOB_LD_LIBRARY_PATH
|
|
*
|
|
*/
|
|
void *
|
|
tcob_resolve(char *subrname)
|
|
{
|
|
|
|
void *(* _dynsubr)() = NULL;
|
|
#ifndef __MINGW32__
|
|
glob_t g;
|
|
char **libname;
|
|
char *ldlib = NULL, *libs1 = NULL, *libstmp = NULL;
|
|
#else
|
|
char *libs1 = NULL, *libstmp = NULL;
|
|
#endif
|
|
char *libs = NULL;
|
|
struct subr_desc *sd; // walter 25-10-05
|
|
//char *libs1 = NULL, *libstmp=NULL;
|
|
|
|
// search in previously opened library handles
|
|
|
|
// check if we've not seen this before
|
|
if ((sd = subr_lookup(subrname)) != NULL)
|
|
{ // walter 25-10-05
|
|
return (sd->subr);
|
|
}
|
|
|
|
// search our currently linked libraries
|
|
// and the calling program
|
|
|
|
#ifndef __MINGW32__
|
|
_dynsubr = tcob_find_in_lib(subrname, NULL);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// This may be equivalent but does not seam to work on Win32
|
|
// #else
|
|
// GetModuleFileName (NULL, subr_libname, sizeof (subr_libname));
|
|
// _dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
// if (_dynsubr) {
|
|
// return _dynsubr;
|
|
// }
|
|
|
|
#endif
|
|
|
|
// search in previously opened library handles
|
|
_dynsubr = tcob_resolve_in_previous_libs(subrname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// First find a library named as the routine on all the library path
|
|
_dynsubr = tcob_find_in_lib(subrname, subrname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// The following search sequence is not really required on MinGW (Win32)
|
|
#ifndef __MINGW32__
|
|
|
|
// find rutname.so
|
|
strcpy(subr_libname, subrname);
|
|
strcat(subr_libname, HTCOB_DYNLIBS_SUFIX);
|
|
_dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// find ./rutname.so
|
|
strcpy(subr_libname, ".");
|
|
strcat(subr_libname, HTCOB_PATH_DELIM_STR);
|
|
strcat(subr_libname, subrname);
|
|
strcat(subr_libname, HTCOB_DYNLIBS_SUFIX);
|
|
_dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// find ./librutname.so
|
|
strcpy(subr_libname, ".");
|
|
strcat(subr_libname, HTCOB_PATH_DELIM_STR);
|
|
strcat(subr_libname, "lib");
|
|
strcat(subr_libname, subrname);
|
|
strcat(subr_libname, HTCOB_DYNLIBS_SUFIX);
|
|
_dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
#endif
|
|
|
|
// The following functionality is not implimented on MinGW (Win32)
|
|
#ifndef __MINGW32__
|
|
// Now find the modules on the current dir and on the TC library PATH
|
|
// setup our libraries names to search (in current directory)
|
|
g.gl_offs = 0;
|
|
glob(libs_pattern, 0, NULL, &g);
|
|
// add libraries found in HTCOB_LD_PATH
|
|
libs1 = getenv(HTCOB_LD_PATH);
|
|
if (libs1 != NULL)
|
|
{
|
|
libstmp = tcob_malloc(strlen(libs1) + 1);
|
|
strcpy(libstmp, libs1);
|
|
libs1 = libstmp;
|
|
}
|
|
// find all the libraryes on the HTCOB_LD_PATH
|
|
while ((libs = libs1) != NULL)
|
|
{
|
|
if ((libs1 = strchr(libs, HTCOB_PATH_SEP_CHAR)) != NULL)
|
|
{
|
|
*libs1++ = 0;
|
|
}
|
|
ldlib = tcob_malloc(strlen(libs) + strlen(libs_pattern) + 2);
|
|
strcpy(ldlib, libs);
|
|
|
|
strcat(ldlib, HTCOB_PATH_DELIM_STR);
|
|
strcat(ldlib, libs_pattern);
|
|
|
|
glob(ldlib, GLOB_APPEND, NULL, &g);
|
|
free(ldlib);
|
|
}
|
|
|
|
if (libstmp != NULL)
|
|
free(libstmp);
|
|
|
|
// loop until we find a function with the name given
|
|
libname = g.gl_pathv;
|
|
if (libname != NULL)
|
|
{
|
|
for (; *libname != NULL; libname++)
|
|
{
|
|
_dynsubr = tcob_find_in_lib(subrname, *libname);
|
|
if (_dynsubr != NULL)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
}
|
|
}
|
|
globfree(&g);
|
|
#else
|
|
HANDLE findFileHandle = NULL;
|
|
WIN32_FIND_DATA uFindFileData, *lpFindFileData;
|
|
|
|
lpFindFileData = &uFindFileData;
|
|
|
|
// Since the calling program is not a DLL
|
|
// This does not work on Win32
|
|
/*
|
|
//
|
|
// Search the calling program
|
|
//
|
|
fprintf(stderr, "dyncall debug 101 : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
mNameLen = GetModuleFileName (NULL, subr_libname, sizeof (subr_libname));
|
|
if (mNameLen != 0) {
|
|
fprintf(stderr, "dyncall debug 103 : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
mHandle = GetModuleHandle(subr_libname);
|
|
if (mHandle != NULL) {
|
|
fprintf(stderr, "dyncall debug 105 : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
_dynsubr = dlsym(mHandle, subrname);
|
|
if (_dynsubr != NULL) {
|
|
fprintf(stderr, "dyncall debug 107 : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
return _dynsubr;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Search loaded DLL's
|
|
//
|
|
// fprintf(stderr, "dyncall debug 111 : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
_dynsubr = tcob_resolve_in_previous_libs(subrname);
|
|
if (_dynsubr)
|
|
{
|
|
// fprintf(stderr, "Already loaded : subrname=%s, subr_libname=%s;\n", subrname, subr_libname);
|
|
return _dynsubr;
|
|
}
|
|
|
|
//
|
|
// Locate and search DLL's in the TCOB_LD_LIBRARY_PATH paths
|
|
//
|
|
libs1 = getenv(HTCOB_LD_PATH);
|
|
if (libs1 != NULL)
|
|
{
|
|
libstmp = tcob_malloc(strlen(libs1) + 1);
|
|
strcpy(libstmp, libs1);
|
|
libs = libstmp;
|
|
|
|
//
|
|
// Find all DLL's in the TCOB_LD_LIBRARY_PATH paths
|
|
//
|
|
|
|
// libs contains the search path
|
|
// libs1 will point to each directory to search
|
|
char * psc = tcob_malloc(2);
|
|
sprintf(psc, "%c", HTCOB_PATH_SEP_CHAR);
|
|
|
|
libs1 = strtok(libs, psc);
|
|
while (libs1 != NULL)
|
|
{
|
|
strcpy(subr_libname, libs1);
|
|
strcat(subr_libname, HTCOB_PATH_DELIM_STR);
|
|
strcat(subr_libname, HTCOB_DYNLIBS_PATTERN);
|
|
|
|
// printf("Searching on [%s]\n",subr_libname);
|
|
|
|
// get first dll from the current searched directory
|
|
findFileHandle = FindFirstFile(subr_libname, lpFindFileData);
|
|
if (findFileHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
strcpy(subr_libname, lpFindFileData->cFileName);
|
|
_dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
|
|
// get second to last dll from the current searched directory
|
|
while (FindNextFile(findFileHandle, lpFindFileData) == TRUE)
|
|
{
|
|
strcpy(subr_libname, lpFindFileData->cFileName);
|
|
_dynsubr = tcob_find_in_lib(subrname, subr_libname);
|
|
if (_dynsubr)
|
|
{
|
|
return _dynsubr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// did not found yet... will search next directory on the search path
|
|
libs1 = strtok(NULL, psc);
|
|
}
|
|
|
|
free(libstmp);
|
|
}
|
|
|
|
#endif
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*\
|
|
| |
|
|
| tcob_resolve_subr |
|
|
| |
|
|
\*------------------------------------------------------------------------*/
|
|
|
|
void *
|
|
tcob_resolve_subr(struct fld_desc *f, char *s, int stacklen)
|
|
{
|
|
|
|
char *p;
|
|
|
|
// get our subroutine name to call
|
|
strncpy(subrname, s, f->len);
|
|
subrname[f->len] = 0;
|
|
|
|
// remove trailing spaces
|
|
p = subrname;
|
|
while (*p)
|
|
{
|
|
if (*p == ' ')
|
|
*p = '\0';
|
|
if (*p == '-')
|
|
*p = '_';
|
|
p++;
|
|
}
|
|
|
|
// An non-zero stack length implies an WINAPI call convention
|
|
if (stacklen != 0)
|
|
{
|
|
sprintf(subr_libname, "%s@%d", subrname, stacklen - 1);
|
|
strcpy(subrname, subr_libname);
|
|
}
|
|
|
|
#ifndef __MINGW32__
|
|
if (strlen(subrname) > HTCOB_DYNLIBS_MAX_NAME)
|
|
{
|
|
fprintf(
|
|
stderr,
|
|
"*** RT Error: Maximun of length of %d characters in sub-routine name ('%s') execced.\n",
|
|
HTCOB_DYNLIBS_MAX_NAME, subrname);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
// FIXME: check for invalid characters
|
|
// change - by _ on sub name
|
|
// p=subrname;
|
|
// while(*p){
|
|
// if (*p=='-') *p='_';
|
|
// p++;
|
|
// }
|
|
|
|
return tcob_resolve(subrname);
|
|
}
|
|
|
|
int
|
|
tcob_call_loadlib(struct fld_desc *f, char *s)
|
|
{
|
|
int r = 0;
|
|
char *p;
|
|
void *module;
|
|
|
|
strncpy(subrname, s, f->len);
|
|
subrname[f->len] = '\0';
|
|
|
|
// remove traling spaces and add NULL delimiter
|
|
p = subrname; // walter
|
|
while (*p)
|
|
{
|
|
if (*p == ' ')
|
|
*p = '\0';
|
|
p++;
|
|
}
|
|
|
|
// open the library
|
|
module = dlopen(subr_libname, RTLD_LAZY);
|
|
if (module != NULL)
|
|
{
|
|
// save handle to improve search sequence for next search
|
|
module_install(module);
|
|
r = 1;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/* end of dyncall.c */
|