diff options
author | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2008-02-08 13:00:32 +0000 |
---|---|---|
committer | IOhannes m zmölnig <zmoelnig@users.sourceforge.net> | 2008-02-08 13:00:32 +0000 |
commit | 4d84d14ac1aa13958eaa2971b03f7f929a519105 (patch) | |
tree | 6579d3f2cea5410a10c4baac8d0f372fb0dff372 /desiredata/src/s_loader.c | |
parent | b334d38aefbd8e0e159d7af6c20d63c5d2b64859 (diff) |
reorganized
svn path=/trunk/; revision=9400
Diffstat (limited to 'desiredata/src/s_loader.c')
-rw-r--r-- | desiredata/src/s_loader.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/desiredata/src/s_loader.c b/desiredata/src/s_loader.c new file mode 100644 index 00000000..aa4d81a0 --- /dev/null +++ b/desiredata/src/s_loader.c @@ -0,0 +1,196 @@ +/* Copyright (c) 1997-1999 Miller Puckette. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#ifdef DL_OPEN +#include <dlfcn.h> +#endif +#ifdef UNISTD +#include <stdlib.h> +#include <unistd.h> +#endif +#ifdef MSW +#include <io.h> +#include <windows.h> +#endif +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif +#include <string.h> +#define PD_PLUSPLUS_FACE +#include "desire.h" +#include "s_stuff.h" +#include <stdio.h> +#include <sstream> +using namespace std; + +typedef void (*t_xxx)(); + +/* naming convention for externs. The names are kept distinct for those +who wich to make "fat" externs compiled for many platforms. Less specific +fallbacks are provided, primarily for back-compatibility; these suffice if +you are building a package which will run with a single set of compiled +objects. The specific name is the letter b, l, d, or m for BSD, linux, +darwin, or microsoft, followed by a more specific string, either "fat" for +a fat binary or an indication of the instruction set. */ + +#ifdef __FreeBSD__ +static char sys_dllextent[] = ".b_i386", sys_dllextent2[] = ".pd_freebsd"; +#endif +#ifdef __linux__ +#ifdef __ia64__ +static char sys_dllextent[] = ".l_ia64", sys_dllextent2[] = ".pd_linux"; +#else +static char sys_dllextent[] = ".l_i386", sys_dllextent2[] = ".pd_linux"; +#endif +#endif +#ifdef __APPLE__ +#ifndef MACOSX3 +static char sys_dllextent[] = ".d_fat", sys_dllextent2[] = ".pd_darwin"; +#else +static char sys_dllextent[] = ".d_ppc", sys_dllextent2[] = ".pd_darwin"; +#endif +#endif +#ifdef MSW +static char sys_dllextent[] = ".m_i386", sys_dllextent2[] = ".dll"; +#endif + +/* maintain list of loaded modules to avoid repeating loads */ +struct t_loadlist { + t_loadlist *ll_next; + t_symbol *ll_name; +}; + +static t_loadlist *sys_loaded; +/* return true if already loaded */ +int sys_onloadlist(char *classname) { + t_symbol *s = gensym(classname); + t_loadlist *ll; + for (ll = sys_loaded; ll; ll = ll->ll_next) + if (ll->ll_name == s) + return 1; + return 0; +} + +/* add to list of loaded modules */ +void sys_putonloadlist(char *classname) { + t_loadlist *ll = (t_loadlist *)getbytes(sizeof(*ll)); + ll->ll_name = gensym(classname); + ll->ll_next = sys_loaded; + sys_loaded = ll; + /* post("put on list %s", classname); */ +} + +static char *make_setup_name(const char *s) { + bool hexmunge=0; + ostringstream buf; + for (; *s; s++) { + char c = *s; + if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z' )|| c == '_') { + buf << c; + } else if (c=='~' && s[1]==0) { /* trailing tilde becomes "_tilde" */ + buf << "_tilde"; + } else { /* anything you can't put in a C symbol is sprintf'ed in hex */ + // load_object: symbol "setup_0xbf861ee4" not found + oprintf(buf,"0x%02x",c); + hexmunge = 1; + } + } + char *r; + if (hexmunge) asprintf(&r,"setup_%s",buf.str().data()); + else asprintf(&r,"%s_setup",buf.str().data()); + return r; +} + +static int sys_do_load_lib(t_canvas *canvas, char *objectname) { + char *filename=0, *dirbuf, *classname, *nameptr; + t_xxx makeout = NULL; + int fd; + if ((classname = strrchr(objectname, '/'))) classname++; + else classname = objectname; + if (sys_onloadlist(objectname)) { + post("%s: already loaded", objectname); + return 1; + } + char *symname = make_setup_name(classname); + /* try looking in the path for (objectname).(sys_dllextent) ... */ + if ((fd = canvas_open2(canvas, objectname, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone; + /* same, with the more generic sys_dllextent2 */ + if ((fd = canvas_open2(canvas, objectname, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone; + /* next try (objectname)/(classname).(sys_dllextent) ... */ + asprintf(&filename,"%s/%s",objectname,classname); + if ((fd = canvas_open2(canvas, filename, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone; + if ((fd = canvas_open2(canvas, filename, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone; + return 0; +gotone: + close(fd); + class_set_extern_dir(gensym(dirbuf)); + /* rebuild the absolute pathname */ + free(filename); + /* extra nulls are a workaround for a dlopen bug */ + asprintf(&filename,"%s/%s%c%c%c%c",dirbuf,nameptr,0,0,0,0); +// filename = realloc(filename,); +#ifdef DL_OPEN + void *dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); + if (!dlobj) { + post("%s: %s", filename, dlerror()); + goto forgetit; + } + makeout = (t_xxx)dlsym(dlobj, symname); +#endif +#ifdef MSW + sys_bashfilename(filename, filename); + HINSTANCE ntdll = LoadLibrary(filename); + if (!ntdll) { + post("%s: couldn't load", filename); + goto forgetit; + } + makeout = (t_xxx)GetProcAddress(ntdll); +#endif + if (!makeout) { + post("%s: can't find symbol '%s' in library", filename, symname); + goto forgetit; + } + makeout(); + class_set_extern_dir(&s_); + sys_putonloadlist(objectname); + free(filename); free(symname); + return 1; +forgetit: + class_set_extern_dir(&s_); + free(filename); free(symname); free(dirbuf); + return 0; +} + +/* callback type definition */ +typedef int (*t_loader)(t_canvas *canvas, char *classname); + +/* linked list of loaders */ +typedef struct t_loader_queue { + t_loader loader; + t_loader_queue *next; +}; + +static t_loader_queue loaders = {sys_do_load_lib, NULL}; + +/* register class loader function */ +void sys_register_loader(t_loader loader) { + t_loader_queue *q = &loaders; + while (1) { + if (q->next) q = q->next; + else { + q->next = (t_loader_queue *)getbytes(sizeof(t_loader_queue)); + q->next->loader = loader; + q->next->next = NULL; + break; + } + } +} + +int sys_load_lib(t_canvas *canvas, char *classname) { + int dspstate = canvas_suspend_dsp(); + int ok = 0; + for(t_loader_queue *q = &loaders; q; q = q->next) if ((ok = q->loader(canvas, classname))) break; + canvas_resume_dsp(dspstate); + return ok; +} |