// This file is part of SmallBASIC // // external C-Lib support // // This program is distributed under the terms of the GPL v2.0 or later // Download the GNU Public License (GPL) from www.gnu.org // // Copyright(C) 2000 Nicholas Christopoulos #include "common/sys.h" /** * @defgroup clib C-Libraries manager */ #if USE_CLIB #define MAX_CLIBS 256 typedef struct { void *handle; } clib_cnode; static clib_node table[MAX_CLIBS]; // table of library nodes, the first // element allocated for system purposes static int clib_count;// number of loaded libs #endif /** * @ingroup clib * * initializes the C-library manager * * @return 0 for success; -1 for error (actually: 'not supported' error) */ int clib_init() { #if USE_CLIB clib_count = 1; // handle 0 is reserved table[0].handle = NULL; return 0; #else return -1; #endif } /** * @ingroup clib * * de-initializes the C-library manager (closes all open handles) * * @return 0 for success; -1 for error (actually: 'not supported' error) */ int clib_restore() { #if USE_CLIB int i; for (i = 1; i < clib_count; i++) clib_unloadlib(i); return 0; #else return -1; #endif } /** * @ingroup clib * * loads a C-library * * @param libname the filename * @return > 0 the library handle; -1 for error; 0 means static-linked (example: OS API) */ int clib_loadlib(const char *libname) { #if USE_CLIB #if defined(_UnixOS) table[clib_count].handle = dlopen(libname, RTLD_LAZY); if (table[clib_count].handle == NULL) { rt_raise("CALL: CANNOT LOAD LIBRARY '%s'\nSystem reports: %s", libname, dlerror()); return -1; } clib_count++; return clib_count - 1; #elif defined(_Win32) table[clib_count].handle = (void *)LoadLibrary(libname); if (table[clib_count].handle == NULL) { rt_raise("CALL: CANNOT LOAD LIBRARY '%s'", libname); return -1; } clib_count++; return clib_count - 1; #endif #else rt_raise("SUBSYSTEM NOT SUPPORTED"); return -1; // not supported #endif } /** * @ingroup clib * * unloads a C-library * * @param handle the lib-handle */ void clib_unloadlib(int handle) { #if USE_CLIB if (handle > 0 && handle < clib_count) { if (table[handle].handle) { #if defined(_UnixOS) dlclose(table[handle].handle); #elif defined(_Win32) FreeLibrary((HMODULE) table[handle].handle); #endif table[handle].handle = NULL; } } #else rt_raise("SUBSYSTEM NOT SUPPORTED"); #endif } /** * @ingroup clib * * call a C-function * * @param handle the lib-handle * @param name the function name * @return depented on function */ void *clib_call_func(int handle, const char *name, ...) { // NDC information // // It is valid for C to call a function with parameters // even if it is declared without parameters. // // the ... operator works like all others, but there is // a problem because compiler requires one parameters to be // declared // // The compiler pushes the arguments on the stack with reverse order // and after the call it is removes the allocated size from the stack // // Example: // // f(a,b,c) produces // // push c // push b // push a // call f // add sp, size(a)+size(b)+size(c) // ; that means substract from stack pointer the correct size // // now, the push statement (at least on compilers output that I have // study) uses default CPU's words (1 CPU word = 1 int). // Real numbers or any bigest value uses 2 or more words. Smallest // values (like 1 byte) are also uses 1 word. That is depented on // CPU architecture, and it is correct. Unfortunately I don't know // if there is a different way. // // The problem is the returned value. The default is to returned on // accumulator, but that is not the rule (in any case there are no // rules). For example the linux's gcc returns a 'int' the value on // the stack. Turbo C uses AX (DX:AX for long ints). // // I had to found a cross-compiled code to call a C function, so, // that is the idea. // // a) we will convert the parameters to CPU words (ptable, pcount) // b) we will use the C function-pointer (f) without declaring the parameters // c) we will call that function based on number of the parameters that we // have // d) we got the return value as int. // // Problems: // We can't get a 'double' return value #if USE_CLIB void *(f) (); void *proc_ptr; int ptable[256]; int pcount; if (handle > 0 && handle < clib_count) { if (table[handle].handle) { #if defined(_UnixOS) proc_ptr = dlsym(table[handle].handle, name); #elif defined(_Win32) proc_ptr = GetProcAddress((HMODULE) table[handle].handle, name); #endif if (proc_ptr == NULL) rt_raise("CALL: FUNCTION '%s' DOES NOT EXISTS", name); else { f = proc_ptr; } } } #else rt_raise("SUBSYSTEM NOT SUPPORTED"); return NULL; #endif } void clib_call_proc(int handle, const char *name, ...) { } /* --- Glue with SB ------------------------------------------------------------------------------------------------------- */ /** * @ingroup clib * * loads a C-library (SB-RTL glue) * * SB Syntax: handle = LOADLIB(filename) */ void blib_loadlib() { } /** * @ingroup clib * * unloads a C-library (SB-RTL glue) * * SB Syntax: UNLOADLIB handle */ void blib_unloadlib() { } /** * @ingroup clib * * Calls a C function (SB-RTL glue) * * SB Syntax: r = CALL(handle, func_name, ...) */ void blib_call_cfunc() { } /** * @ingroup clib * * Calls a C procedure (SB-RTL glue) * * SB Syntax: CALL handle, proc_name, ... */ void blib_call_cproc() { }