aboutsummaryrefslogtreecommitdiff
path: root/desiredata/src/s_loader.c
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
commit4d84d14ac1aa13958eaa2971b03f7f929a519105 (patch)
tree6579d3f2cea5410a10c4baac8d0f372fb0dff372 /desiredata/src/s_loader.c
parentb334d38aefbd8e0e159d7af6c20d63c5d2b64859 (diff)
reorganized
svn path=/trunk/; revision=9400
Diffstat (limited to 'desiredata/src/s_loader.c')
-rw-r--r--desiredata/src/s_loader.c196
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;
+}