swig/Source/Swig/module.c
Dave Beazley 3ee7a76ef0 Added dynamic module loading
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@914 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-10-04 03:37:52 +00:00

210 lines
6 KiB
C

/* -----------------------------------------------------------------------------
* module.c
*
* This file implements the SWIG module system. Modules are simply
* pieces of code that manipulate tree objects. Each module is defined
* by 4 quantities:
*
* - Module name (used to select the module on the command line)
* - init function (called with the SWIG command line options).
* - start function (called to launch the module)
* - start tag (starting tag expected by the module)
*
* Currently modules must be statically linked with SWIG. However, it
* is anticipated that the module system may eventually support
* dynamic loading.
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 1999-2000. The University of Chicago
* See the file LICENSE for information on usage and redistribution.
* ----------------------------------------------------------------------------- */
#include "swig.h"
#ifdef DYNAMIC_MODULES
#include <dlfcn.h>
#endif
static char cvsroot[] = "$Header$";
struct Module {
String *modname;
int (*initfunc)(int argc, char **argv);
DOH *(*startfunc)(DOH *);
String *starttag;
struct Module *next;
};
static Module *Modules = 0;
static Hash *LoadedModules = 0;
/* -----------------------------------------------------------------------------
* Swig_register_module()
*
* Register a new module with the system
* ----------------------------------------------------------------------------- */
void
Swig_register_module(const String_or_char *modname, const String_or_char *starttag,
int (*initfunc)(int argc, char **argv),
DOH *(*startfunc)(DOH *))
{
Module *m;
m = (Module *) malloc(sizeof(Module));
m->modname = NewString(modname);
m->starttag = NewString(starttag);
m->initfunc = initfunc;
m->startfunc = startfunc;
m->next = Modules;
Modules = m;
}
/* -----------------------------------------------------------------------------
* Swig_load_module()
*
* Load a module. Returns the module object.
* ----------------------------------------------------------------------------- */
Module *
Swig_load_module(const String_or_char *modname) {
Module *m;
static int dlcheck = 0;
m = Modules;
while (m) {
if (Cmp(m->modname, modname) == 0) {
/* Create a new entry in the loaded modules table */
List *ml;
if (!LoadedModules) LoadedModules = NewHash();
ml = Getattr(LoadedModules,m->starttag);
if (!ml) {
ml = NewList();
Setattr(LoadedModules,m->starttag,ml);
}
Append(ml,NewVoid(m,0));
return m;
}
m = m->next;
}
/* Module is not a built-in module. See if we can dynamically load it */
#ifdef DYNAMIC_MODULES
if (dlcheck) return 0;
{
DOH *filename;
void *handle;
void (*init)(void) = 0;
char initfunc[256];
FILE *f;
filename = NewStringf("./swig%s.so", modname);
f = Swig_open(filename);
if (!f) return 0;
fclose(f);
Clear(filename);
Append(filename,Swig_last_file());
sprintf(initfunc,"%smodule",Char(modname));
handle = dlopen(Char(filename), RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
Printf(stdout,"%s\n", dlerror());
return 0;
}
init = (void (*)(void)) dlsym(handle,initfunc);
if (!init) {
Printf(stdout,"Dynamic module %s doesn't define %s()\n", initfunc);
return 0;
}
(*init)(); /* Register function */
dlcheck = 1;
m = Swig_load_module(modname);
dlcheck = 0;
return m;
}
#else
return 0;
#endif
}
/* -----------------------------------------------------------------------------
* Swig_init_module()
*
* Initialize a module
* ----------------------------------------------------------------------------- */
int Swig_init_module(Module *m, int argc, char **argv) {
return (*m->initfunc)(argc,argv);
}
/* -----------------------------------------------------------------------------
* Swig_start_module()
*
* Start a module
* ----------------------------------------------------------------------------- */
DOH *
Swig_start_module(Module *m, DOH *obj) {
return (*m->startfunc)(obj);
}
/* -----------------------------------------------------------------------------
* Swig_run_modules()
*
* Given a tree node. This function tries to run it through all of the loaded
* modules. This works by looking at the "tag" attribute of the node and
* searching for a loaded module that can handle that tag. If no module can be
* found, processing stops and an error is generated.
*
* If more than one module can work on a given tag, those modules will be
* executed one after the other. Caveat: if one of those modules outputs
* a different type of tree, processing immediately stops.
* ----------------------------------------------------------------------------- */
DOH *Swig_run_modules(DOH *node) {
String *tag;
List *ml;
DOH *newnode;
String *newtag;
int i;
tag = Getattr(node,"tag");
if (!tag) {
Printf(stderr,"Whoa. No tag attribute on node passed to Swig_module_run.\n");
exit(EXIT_FAILURE);
}
/* Get the set of modules that can respond to this node */
while (node) {
if (!LoadedModules) {
Printf(stderr,"No modules loaded.\n");
return 0;
}
ml = Getattr(LoadedModules,tag);
if ((!ml) || (Len(ml) == 0)) {
Printf(stderr,"No module for object '%s'\n", tag);
return 0;
}
newnode = 0;
newtag = 0;
for (i = 0; i < Len(ml); i++) {
Module *m;
m = (Module *) Data(Getitem(ml,i));
assert(m);
newnode = (*m->startfunc)(node);
if (!newnode) return 0; /* Done */
newtag = Getattr(newnode,"tag");
if (!newtag) {
Printf(stderr,"Fatal error. Module '%s' returns untagged object.\n", m->modname);
exit(EXIT_FAILURE);
}
if (Cmp(newtag,tag)) break; /* Tag is different. Oh well */
}
if (Cmp(newtag,tag) == 0) break; /* Hmmm. The tag is the same but we already did everything */
node = newnode;
tag = newtag;
}
return 0;
}