OpenCOBOL 1.1pre-rel
call.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2009 Keisuke Nishida
00003  * Copyright (C) 2007-2009 Roger While
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public License
00007  * as published by the Free Software Foundation; either version 2.1,
00008  * or (at your option) any later version.
00009  * 
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU Lesser General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; see the file COPYING.LIB.  If not write to
00017  * the Free Software Foundation, 51 Franklin Street, Fifth Floor
00018  * Boston, MA 02110-1301 USA
00019  */
00020 
00021 #include "config.h"
00022 #include "defaults.h"
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028 #ifdef  HAVE_UNISTD_H
00029 #include <unistd.h>
00030 #endif
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 
00034 /*      NOTE - The following variable should be uncommented when
00035         it is known that dlopen(NULL) is borked.
00036         This is known to be true for some PA-RISC HP-UX 11.11 systems.
00037         This is fixed with HP patch PHSS_28871. (There are newer but this
00038         fixes dlopen/dlsym problems)
00039 */
00040 /* #define COB_BORKED_DLOPEN */
00041         
00042 #ifdef  USE_LIBDL
00043 
00044 #define __USE_GNU       1
00045 #include <dlfcn.h>
00046 #define lt_dlopen(x)    dlopen(x, RTLD_LAZY | RTLD_GLOBAL)
00047 #define lt_dlsym(x, y)  dlsym(x, y)
00048 #define lt_dlclose(x)   dlclose(x)
00049 #define lt_dlerror()    dlerror()
00050 #define lt_dlhandle     void *
00051 
00052 #elif   defined(_WIN32)
00053 
00054 #define WINDOWS_LEAN_AND_MEAN
00055 #include <windows.h>
00056 /* Prototype */
00057 static char *   lt_dlerror (void);
00058 
00059 static HMODULE
00060 lt_dlopen (const char *x)
00061 {
00062         if (x == NULL) {
00063                 return GetModuleHandle (NULL);
00064         }
00065         return LoadLibrary(x);
00066 }
00067 #define lt_dlsym(x, y)  GetProcAddress(x, y)
00068 #define lt_dlclose(x)   FreeLibrary(x)
00069 static char errbuf[64];
00070 static char *
00071 lt_dlerror ()
00072 {
00073         sprintf(errbuf, "LoadLibrary/GetProcAddress error %d", (int)GetLastError());
00074         return errbuf;
00075 }
00076 #define lt_dlinit()
00077 #define lt_dlhandle     HMODULE
00078 
00079 #else
00080 
00081 #define LT_NON_POSIX_NAMESPACE 1
00082 #include <ltdl.h>
00083 
00084 #endif
00085 
00086 #include "call.h"
00087 #include "common.h"
00088 #include "coblocal.h"
00089 #include "fileio.h"
00090 
00091 #ifdef  _MSC_VER
00092 #define PATHSEPC ';'
00093 #define PATHSEPS ";"
00094 #else
00095 #define PATHSEPC ':'
00096 #define PATHSEPS ":"
00097 #endif
00098 
00099 #define COB_MAX_COBCALL_PARMS   16
00100 #define CALL_BUFF_SIZE          256
00101 #define CALL_FILEBUFF_SIZE      2048
00102 
00103 /* Local variables */
00104 
00105 static char             **resolve_path = NULL;
00106 static char             *resolve_error = NULL;
00107 static char             *resolve_error_buff = NULL;
00108 static lt_dlhandle      mainhandle = NULL;
00109 static size_t           name_convert = 0;
00110 static size_t           resolve_size = 0;
00111 static size_t           cobjmp_primed = 0;
00112 static void             *call_buffer;
00113 static char             *call_filename_buff;
00114 static char             *call_entry_buff;
00115 static unsigned char    *call_entry2_buff;
00116 static size_t           call_lastsize;
00117 
00118 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00119 struct struct_handle {
00120         struct struct_handle    *next;
00121         lt_dlhandle             preload_handle;
00122 };
00123 static struct struct_handle     *pre_handle = NULL;
00124 #endif
00125 
00126 /*
00127  * Call table
00128  */
00129 
00130 #define HASH_SIZE       131
00131 
00132 struct call_hash {
00133         struct call_hash        *next;
00134         const char              *name;
00135         void                    *func;
00136         void                    *cancel;
00137         size_t                  flag_is_active;
00138 };
00139 
00140 #ifdef  COB_ALT_HASH
00141 static struct call_hash *call_table = NULL;
00142 #else
00143 static struct call_hash **call_table = NULL;
00144 #endif
00145 
00146 struct system_table {
00147         const char              *syst_name;
00148         void                    *syst_call;
00149 };
00150 
00151 #undef  COB_SYSTEM_GEN
00152 #define COB_SYSTEM_GEN(x, y, z)         { x, (void *)z },
00153 static const struct system_table        system_tab[] = {
00154 #include "system.def"
00155         { NULL, NULL }
00156 };
00157 #undef  COB_SYSTEM_GEN
00158 
00159 /* Local functions */
00160 
00161 static void * COB_NOINLINE
00162 cob_strdup (const void *stptr)
00163 {
00164         void    *mptr;
00165         size_t  len;
00166 
00167         len = strlen (stptr) + 1;
00168         mptr = cob_malloc (len);
00169         memcpy (mptr, stptr, len);
00170         return mptr;
00171 }
00172 
00173 static void
00174 cob_set_library_path (const char *path)
00175 {
00176         char            *p;
00177         size_t          i;
00178 
00179         /* clear the previous path */
00180         if (resolve_path) {
00181                 free (resolve_path[0]);
00182                 free (resolve_path);
00183         }
00184 
00185         /* count the number of separators */
00186         resolve_size = 1;
00187         for (p = strchr (path, PATHSEPC); p; p = strchr (p + 1, PATHSEPC)) {
00188                 resolve_size++;
00189         }
00190 
00191         /* build path array */
00192         p = cob_strdup (path);
00193         resolve_path = cob_malloc (sizeof (char *) * resolve_size);
00194         resolve_path[0] = strtok (p, PATHSEPS);
00195         for (i = 1; i < resolve_size; ++i) {
00196                 resolve_path[i] = strtok (NULL, PATHSEPS);
00197         }
00198 }
00199 
00200 static void *
00201 cob_get_buff (const size_t buffsize)
00202 {
00203         if (buffsize > call_lastsize) {
00204                 call_lastsize = buffsize;
00205                 free (call_buffer);
00206                 call_buffer = cob_malloc (buffsize);
00207         }
00208         return call_buffer;
00209 }
00210 
00211 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00212 static void
00213 cache_handle (lt_dlhandle libhandle)
00214 {
00215         struct struct_handle    *newhandle;
00216 
00217         newhandle = cob_malloc (sizeof (struct struct_handle));
00218         newhandle->preload_handle = libhandle;
00219         newhandle->next = pre_handle;
00220         pre_handle = newhandle;
00221 }
00222 #endif
00223 
00224 #ifndef COB_ALT_HASH
00225 static COB_INLINE size_t
00226 hash (const unsigned char *s)
00227 {
00228         size_t          val = 0;
00229 
00230         while (*s) {
00231                 val += *s++;
00232         }
00233         return val % HASH_SIZE;
00234 }
00235 #endif
00236 
00237 static void
00238 insert (const char *name, void *func, void *cancel)
00239 {
00240         struct call_hash        *p;
00241 #ifndef COB_ALT_HASH
00242         size_t                  val;
00243 #endif
00244 
00245         p = cob_malloc (sizeof (struct call_hash));
00246         p->name = cob_strdup (name);
00247         p->func = func;
00248         p->cancel = cancel;
00249 #ifdef  COB_ALT_HASH
00250         p->next = call_table;
00251         call_table = p;
00252 #else
00253         val = hash ((const unsigned char *)name);
00254         p->next = call_table[val];
00255         call_table[val] = p;
00256 #endif
00257 }
00258 
00259 static void *
00260 lookup (const char *name)
00261 {
00262         struct call_hash        *p;
00263 
00264 #ifdef  COB_ALT_HASH
00265         for (p = call_table; p; p = p->next) {
00266 #else
00267         for (p = call_table[hash ((const unsigned char *)name)]; p; p = p->next) {
00268 #endif
00269                 if (strcmp (name, p->name) == 0) {
00270                         return p->func;
00271                 }
00272         }
00273         return NULL;
00274 }
00275 
00276 const char *
00277 cob_resolve_error (void)
00278 {
00279         const char      *p = resolve_error;
00280 
00281         resolve_error = NULL;
00282         return p;
00283 }
00284 
00285 void
00286 cob_call_error (void)
00287 {
00288         const char      *s;
00289 
00290         s = cob_resolve_error ();
00291         if (!s) {
00292                 s = "Unknown error";
00293         }
00294         cob_runtime_error ("%s", s);
00295         cob_stop_run (1);
00296 }
00297 
00298 void
00299 cob_set_cancel (const char *name, void *entry, void *cancel)
00300 {
00301         struct call_hash        *p;
00302 
00303 #ifdef  COB_ALT_HASH
00304         for (p = call_table; p; p = p->next) {
00305 #else
00306         for (p = call_table[hash ((const unsigned char *)name)]; p; p = p->next) {
00307 #endif
00308                 if (strcmp (name, p->name) == 0) {
00309                         p->cancel = cancel;
00310                         return;
00311                 }
00312         }
00313         insert (name, entry, cancel);
00314 }
00315 
00316 void *
00317 cob_resolve (const char *name)
00318 {
00319         unsigned char           *p;
00320         const unsigned char     *s;
00321         void                    *func;
00322 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00323         struct struct_handle    *chkhandle;
00324 #endif
00325         lt_dlhandle             handle;
00326         size_t                  i;
00327         struct stat             st;
00328 
00329 /* Checked in generated code
00330         if (!cob_initialized) {
00331                 fputs ("cob_init() must be called before cob_resolve()", stderr);
00332                 cob_stop_run (1);
00333         }
00334 */
00335 
00336         /* search the cache */
00337         cob_exception_code = 0;
00338         func = lookup (name);
00339         if (func) {
00340                 return func;
00341         }
00342 
00343         /* encode program name */
00344         p = (unsigned char *)call_entry_buff;
00345         s = (const unsigned char *)name;
00346         if (unlikely(isdigit (*s))) {
00347                 p += sprintf ((char *)p, "_%02X", *s++);
00348         }
00349         for (; *s; ++s) {
00350                 if (likely(isalnum (*s) || *s == '_')) {
00351                         *p++ = *s;
00352                 } else if (*s == '-') {
00353                         *p++ = '_';
00354                         *p++ = '_';
00355                 } else {
00356                         p += sprintf ((char *)p, "_%02X", *s);
00357                 }
00358         }
00359         *p = 0;
00360 
00361         /* search the main program */
00362         if (mainhandle != NULL && (func = lt_dlsym (mainhandle, call_entry_buff)) != NULL) {
00363                 insert (name, func, NULL);
00364                 resolve_error = NULL;
00365                 return func;
00366         }
00367 
00368         /* Search preloaded modules */
00369 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00370         for (chkhandle = pre_handle; chkhandle; chkhandle = chkhandle->next) {
00371                 if ((func = lt_dlsym (chkhandle->preload_handle, call_entry_buff)) != NULL) {
00372                         insert (name, func, NULL);
00373                         resolve_error = NULL;
00374                         return func;
00375                 }
00376         }
00377 #endif
00378 #if     defined(USE_LIBDL) && defined (RTLD_DEFAULT)
00379         if ((func = lt_dlsym (RTLD_DEFAULT, call_entry_buff)) != NULL) {
00380                 insert (name, func, NULL);
00381                 resolve_error = NULL;
00382                 return func;
00383         }
00384 #endif
00385 
00386         s = (const unsigned char *)name;
00387         if (unlikely(name_convert != 0)) {
00388                 s = (const unsigned char *)name;
00389                 p = call_entry2_buff;
00390                 for (; *s; ++s) {
00391                         if (name_convert == 1 && isupper (*s)) {
00392                                 *p++ = tolower (*s);
00393                         } else if (name_convert == 2 && islower (*s)) {
00394                                 *p++ = toupper (*s);
00395                         } else {
00396                                 *p++ = *s;
00397                         }
00398                 }
00399                 *p = 0;
00400                 s = (const unsigned char *)call_entry2_buff;
00401         }
00402 
00403         /* search external modules */
00404         for (i = 0; i < resolve_size; ++i) {
00405                 call_filename_buff[CALL_FILEBUFF_SIZE - 1] = 0;
00406                 if (resolve_path[i] == NULL) {
00407                         snprintf (call_filename_buff, CALL_FILEBUFF_SIZE - 1,
00408                                   "%s.%s", s, COB_MODULE_EXT);
00409                 } else {
00410                         snprintf (call_filename_buff, CALL_FILEBUFF_SIZE - 1,
00411                                   "%s/%s.%s", resolve_path[i], s, COB_MODULE_EXT);
00412                 }
00413                 if (stat (call_filename_buff, &st) == 0) {
00414                         if ((handle = lt_dlopen (call_filename_buff)) != NULL) {
00415 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00416                                 /* Candidate for future calls */
00417                                 cache_handle (handle);
00418 #endif
00419                                 if ((func = lt_dlsym (handle, call_entry_buff)) != NULL) {
00420                                         insert (name, func, NULL);
00421                                         resolve_error = NULL;
00422                                         return func;
00423                                 }
00424                         }
00425                         resolve_error_buff[CALL_BUFF_SIZE - 1] = 0;
00426                         strncpy (resolve_error_buff, lt_dlerror (),
00427                                  CALL_BUFF_SIZE - 1);
00428                         resolve_error = resolve_error_buff;
00429                         cob_set_exception (COB_EC_PROGRAM_NOT_FOUND);
00430                         return NULL;
00431                 }
00432         }
00433         resolve_error_buff[CALL_BUFF_SIZE - 1] = 0;
00434         snprintf (resolve_error_buff, CALL_BUFF_SIZE - 1,
00435                   "Cannot find module '%s'", name);
00436         resolve_error = resolve_error_buff;
00437         cob_set_exception (COB_EC_PROGRAM_NOT_FOUND);
00438         return NULL;
00439 }
00440 
00441 void *
00442 cob_resolve_1 (const char *name)
00443 {
00444         void    *p;
00445 
00446         p = cob_resolve (name);
00447         if (unlikely(!p)) {
00448                 cob_call_error ();
00449         }
00450         return p;
00451 }
00452 
00453 void *
00454 cob_call_resolve (const cob_field *f)
00455 {
00456         char    *buff;
00457 
00458         buff = cob_get_buff (f->size + 1);
00459         cob_field_to_string (f, buff);
00460         return cob_resolve (buff);
00461 }
00462 
00463 void *
00464 cob_call_resolve_1 (const cob_field *f)
00465 {
00466         void    *p;
00467 
00468         p = cob_call_resolve (f);
00469         if (unlikely(!p)) {
00470                 cob_call_error ();
00471         }
00472         return p;
00473 }
00474 
00475 void
00476 cobcancel (const char *name)
00477 {
00478         struct call_hash        *p;
00479         union {
00480                 int     (*cancel_func)(int, ...);
00481                 void    *cancel_void;
00482         } unicanc;
00483 
00484         if (unlikely(!name)) {
00485                 cob_runtime_error ("NULL name parameter passed to 'cobcancel'");
00486                 cob_stop_run (1);
00487         }
00488 #ifdef  COB_ALT_HASH
00489         for (p = call_table; p; p = p->next) {
00490 #else
00491         for (p = call_table[hash ((const unsigned char *)name)]; p; p = p->next) {
00492 #endif
00493                 if (strcmp (name, p->name) == 0) {
00494                         if (p->cancel && !p->flag_is_active) {
00495                                 unicanc.cancel_void = p->cancel;
00496                                 unicanc.cancel_func (-1, NULL, NULL, NULL, NULL,
00497                                                      NULL, NULL, NULL, NULL);
00498                         }
00499                 }
00500         }
00501 }
00502 
00503 void
00504 cob_field_cancel (const cob_field *f)
00505 {
00506         char    *name;
00507 
00508         name = cob_get_buff (f->size + 1);
00509         cob_field_to_string (f, name);
00510         cobcancel (name);
00511 }
00512 
00513 void
00514 cob_init_call (void)
00515 {
00516         char                            *buff;
00517         char                            *s;
00518         char                            *p;
00519         const struct system_table       *psyst;
00520 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00521         lt_dlhandle                     libhandle;
00522 #endif
00523         size_t                          i;
00524         struct stat                     st;
00525 
00526 #ifndef USE_LIBDL
00527         lt_dlinit ();
00528 #endif
00529 
00530         /* big enough for anything from libdl/libltdl */
00531         resolve_error_buff = cob_malloc (CALL_BUFF_SIZE);
00532 
00533 #ifndef COB_ALT_HASH
00534         call_table = cob_malloc (sizeof (struct call_hash *) * HASH_SIZE);
00535 #endif
00536 
00537         call_filename_buff = cob_malloc (CALL_FILEBUFF_SIZE);
00538         call_entry_buff = cob_malloc (COB_SMALL_BUFF);
00539         call_entry2_buff = cob_malloc (COB_SMALL_BUFF);
00540         s = getenv ("COB_LOAD_CASE");
00541         if (s != NULL) {
00542                 if (strcasecmp (s, "LOWER") == 0) {
00543                         name_convert = 1;
00544                 } else if (strcasecmp (s, "UPPER") == 0) {
00545                         name_convert = 2;
00546                 }
00547         }
00548 
00549         buff = cob_malloc (COB_MEDIUM_BUFF);
00550         s = getenv ("COB_LIBRARY_PATH");
00551         if (s == NULL) {
00552                 snprintf (buff, COB_MEDIUM_MAX, ".%s%s",
00553                           PATHSEPS, COB_LIBRARY_PATH);
00554         } else {
00555                 snprintf (buff, COB_MEDIUM_MAX, "%s%s.%s%s",
00556                           s, PATHSEPS, PATHSEPS, COB_LIBRARY_PATH);
00557         }
00558         cob_set_library_path (buff);
00559 
00560 #ifndef COB_BORKED_DLOPEN
00561         mainhandle = lt_dlopen (NULL);
00562 #endif
00563 
00564         s = getenv ("COB_PRE_LOAD");
00565         if (s != NULL) {
00566                 p = cob_strdup (s);
00567                 s = strtok (p, PATHSEPS);
00568                 for (; s; s = strtok (NULL, PATHSEPS)) {
00569                         for (i = 0; i < resolve_size; ++i) {
00570                                 buff[COB_MEDIUM_MAX] = 0;
00571                                 snprintf (buff, COB_MEDIUM_MAX, "%s/%s.%s",
00572                                           resolve_path[i], s, COB_MODULE_EXT);
00573                                 if (stat (buff, &st) == 0) {
00574 #if     defined (_WIN32) || !defined (RTLD_DEFAULT)
00575                                         if ((libhandle = lt_dlopen (buff)) != NULL) {
00576                                                 cache_handle (libhandle);
00577 #else
00578                                         if (lt_dlopen (buff) != NULL) {
00579 #endif
00580                                                 break;
00581                                         }
00582                                 }
00583                         }
00584                 }
00585                 free (p);
00586         }
00587         free (buff);
00588         call_buffer = cob_malloc (CALL_BUFF_SIZE);
00589         call_lastsize = CALL_BUFF_SIZE;
00590         for (psyst = (struct system_table *)&system_tab[0]; psyst->syst_name; ++psyst) {
00591                 insert (psyst->syst_name, psyst->syst_call, NULL);
00592         }
00593 }
00594 
00595 int
00596 cobcall (const char *name, const int argc, void **argv)
00597 {
00598         int     i;
00599         union {
00600                 void    *(*funcptr)();
00601                 int     (*funcint)();
00602                 void    *func_void;
00603         } unifunc;
00604         void    *pargv[16];
00605 
00606         if (unlikely(!cob_initialized)) {
00607                 cob_runtime_error ("'cobcall' - Runtime has not been initialized");
00608                 cob_stop_run (1);
00609         }
00610         if (argc < 0 || argc > 16) {
00611                 cob_runtime_error ("Invalid number of arguments to 'cobcall'");
00612                 cob_stop_run (1);
00613         }
00614         if (unlikely(!name)) {
00615                 cob_runtime_error ("NULL name parameter passed to 'cobcall'");
00616                 cob_stop_run (1);
00617         }
00618         unifunc.func_void = cob_resolve_1 (name);
00619         memset (pargv, 0, sizeof(pargv));
00620         /* Set number of parameters */
00621         cob_call_params = argc;
00622         for (i = 0; i < argc; ++i) {
00623                 pargv[i] = argv[i];
00624         }
00625         return unifunc.funcint (pargv[0], pargv[1], pargv[2], pargv[3],
00626                                 pargv[4], pargv[5], pargv[6], pargv[7],
00627                                 pargv[8], pargv[9], pargv[10], pargv[11],
00628                                 pargv[12], pargv[13], pargv[14], pargv[15]);
00629 }
00630 
00631 int
00632 cobfunc (const char *name, const int argc, void **argv)
00633 {
00634         int     ret;
00635 
00636         if (unlikely(!cob_initialized)) {
00637                 cob_runtime_error ("'cobfunc' - Runtime has not been initialized");
00638                 cob_stop_run (1);
00639         }
00640         ret = cobcall (name, argc, argv);
00641         cobcancel (name);
00642         return ret;
00643 }
00644 
00645 void *
00646 cobsavenv (struct cobjmp_buf *jbuf)
00647 {
00648         if (unlikely(!jbuf)) {
00649                 cob_runtime_error ("NULL name parameter passed to 'cobsavenv'");
00650                 cob_stop_run (1);
00651         }
00652         if (cobjmp_primed) {
00653                 cob_runtime_error ("Multiple call to 'cobsetjmp'");
00654                 cob_stop_run (1);
00655         }
00656         cobjmp_primed = 1;
00657         return jbuf->cbj_jmp_buf;
00658 }
00659 
00660 void *
00661 cobsavenv2 (struct cobjmp_buf *jbuf, const int jsize)
00662 {
00663         int     jtemp;
00664 
00665         /* Shut up compiler */
00666         jtemp = jsize;
00667         return cobsavenv (jbuf);
00668 }
00669 
00670 void
00671 coblongjmp (struct cobjmp_buf *jbuf)
00672 {
00673         if (unlikely(!jbuf)) {
00674                 cob_runtime_error ("NULL name parameter passed to 'coblongjmp'");
00675                 cob_stop_run (1);
00676         }
00677         if (!cobjmp_primed) {
00678                 cob_runtime_error ("Call to 'coblongjmp' with no prior 'cobsetjmp'");
00679                 cob_stop_run (1);
00680         }
00681         cobjmp_primed = 0;
00682         longjmp (jbuf->cbj_jmp_buf, 1);
00683 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines