OpenCOBOL 1.1pre-rel
|
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 }