/* * Pure Data Packet source file. PF plugin system. * Copyright (c) by Tom Schouten * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include typedef struct { pf_header_t super; void *lib; pf_packet_t name; } module_t; /* note: this is a nice example of non-ortogonality :) we have a little zoo of atom types * scalars * lists * packets * c extension pointers only pointers use reference count management, the other ones do not. so why not implement c extension pointers as packets (dictionaries?) because even then, a c extension type is still necessary, unless all the object oriented c code is rewritten to use dictionaries.. */ /* PLUGIN SIDE */ /* NEW API no more juggling with namespaces: all functions are to be loaded in the current namespace. it is the responsability of the object loader to load the plugin library into the desired namespace (dictionary). */ static pf_list_t *ext = 0; static void register_void(pf_word_type_t type, pf_symbol_t *name){ if (!ext) ext = pf_list_new(); pf_list_t *l = pf_list_new(); pf_list_push_symbol(l, name); pf_list_push_int(l, type); pf_list_push_list(ext, l); } static pf_word_type_t next_void_id = a_extension; pf_word_type_t pf_plugin_new_void(pf_symbol_t *name){ pf_word_type_t t = next_void_id++; register_void(t, name); return t; } pf_symbol_t *pf_plugin_void_name(pf_word_type_t type){ if (!ext) return pf_symbol("unknown.void.not.initialized"); pf_atom_t *a; for (a=ext->first;a;a=a->next){ if (a->w.w_list->first->w.w_int == type) return a->w.w_list->first->next->w.w_symbol; } return pf_symbol("unknown"); } void pf_plugin_add_function(pf_vm_t *vm, pf_function_t f, char *c_name, char *forth_name, char *docstring){ // pf_post("registering %s : %p", c_name, f); /* register unique name */ PF_ASSERT(forth_name); pf_list_t *link = pf_vm_add_primitive(vm, pf_symbol(forth_name), (pf_forth_primitive_t)f); if (docstring) { pf_atom_t *comment = PF_LINK_TO_COMMENT(link); PF_ASSERT(comment->t == a_list); pf_list_push_packet(PF_LINK_TO_COMMENT(link)->w.w_list, pf_packet_stringf("%s", docstring)); } } /* HOST SIDE */ #ifdef HAVE_LIBDL #include #endif #ifdef PF_STATIC /* defined elsewhere */ PF_PRIMITIVE(pf_loadplugin); #else /* load an extension module */ PF_PRIMITIVE(pf_loadplugin) { #ifdef HAVE_LIBDL CHECKN(1); pf_atom_t *arg0; char *filename = STRING(ARG0); pf_forth_primitive_t init_plugin = 0; int name_packet = 0; //pf_error_t e = e_bug; /* create plugin object */ module_t *m = PUSH_NEW("plugin"); //pf_packet_t modp = pf_factory_newpacket(pf_symbol("plugin")); //PUSH_PACKET(modp); //PF_ASSERT(modp); //module_t *m = pf_packet_subheader(modp); m->name = pf_packet_stringf("%s", filename); /* open library */ if (!(m->lib = dlopen(filename, RTLD_NOW))){ THROW(e_inval, "can't load plugin: %s: %s", filename, dlerror()); } /* try to find a setup function */ if ((init_plugin = dlsym(m->lib, "pf_plugin_setup"))) goto gotinit; if ((init_plugin = dlsym(m->lib, "_pf_plugin_setup"))) goto gotinit; // needed on darwin THROW(e_inval, "%s not a valid libpf plugin : %s", filename, dlerror()); gotinit: /* execute it */ arg0 = ARG0; CALL(init_plugin); if (arg0 != ARG0){ // since we pass data upstream, let's check this THROW(e_inval, "plugin setup function does not have zero stack effect"); } /* cleanup, leave plugin packet */ NIP1; EXIT; #else THROW(e_internal, "object loading not supported"); #endif } #endif pf_class_t *module_class = 0; static void module_init(module_t *m){ m->name = 0; m->lib = 0; } static void module_sleep(module_t *m){ if (m->lib) { // pf_post("not closing %s", pf_packet_string_data(m->name)); dlclose(m->lib); } pf_packet_unregister(m->name); module_init(m); } static void module_report(module_t *m, pf_string_t *string){ pf_string_printf(string, "#", pf_packet_string_data(m->name)); } static pf_packet_t module_factory(pf_list_t *type){ module_t *m = (module_t *)pf_packet_create(sizeof(module_t), 0); m->super.type = module_class; module_init(m); return (pf_packet_t)m; } static pf_symbol_t *module_desc(void) { return pf_symbol("plugin"); } PF_PRIMITIVE(pf_forth_plugin_setup){ module_class = pf_class_new(pf_symbol("plugin"), module_factory); pf_class_set_sleep(module_class, (pf_method_t)module_sleep); pf_class_set_report(module_class, (pf_method_string_t)module_report); pf_class_set_desc(module_class, (pf_method_to_desc_t)module_desc); PF_REGISTER_FUNCTION(pf_loadplugin, "loadplugin", "( string -- )\tLoad a binary extension module."); EXIT; }