/* 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 #endif #ifdef UNISTD #include #include #endif #ifdef MSW #include #include #endif #ifdef __APPLE__ #include #endif #include #define PD_PLUSPLUS_FACE #include "desire.h" #include "s_stuff.h" #include #include 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; }