From 00d48b08f218699bd2d27c41374e30ecdb10bfb9 Mon Sep 17 00:00:00 2001 From: ellson Date: Sat, 2 Apr 2005 23:55:21 +0000 Subject: [PATCH] various bits for on-demand plugin loading - currently disabled --- configure.ac | 11 +++++-- graphviz.spec.in | 2 +- lib/common/emit.c | 5 ++- lib/common/input.c | 12 ++----- lib/gvc/Makefile.am | 6 ++-- lib/gvc/gvc.h | 2 +- lib/gvc/gvconfig.c | 71 +++++++++++++++++++++++++++++++++++------- lib/gvc/gvplugin.c | 46 +++++++++++++++++++++++---- tclpkg/gv/gv.cpp | 6 ++-- tclpkg/tcldot/tcldot.c | 6 ++-- 10 files changed, 122 insertions(+), 45 deletions(-) diff --git a/configure.ac b/configure.ac index b395fafed..4b2c5ce9e 100644 --- a/configure.ac +++ b/configure.ac @@ -3,11 +3,16 @@ AC_INIT(graphviz, 2.3) AC_CONFIG_SRCDIR(configure.ac) AC_CONFIG_AUX_DIR(config) -# AC_CONFIG_SUBDIRS(libltdl) +#AC_CONFIG_SUBDIRS(libltdl) #AC_LIBTOOL_DLOPEN #AC_LIBLTDL_CONVENIENCE -#AC_SUBST(INCLTDL) -#AC_SUBST(LIBLTDL) + +HAVE_LTDL=0 + +AC_SUBST(INCLTDL) +AC_SUBST(LIBLTDL) +AC_DEFINE_UNQUOTED(HAVE_LTDL,$HAVE_LTDL,Define if to use libltdl dynamic loading of plugins.) +AM_CONDITIONAL(ENABLE_LTDL, [test "x$HAVE_LTDL" = "x1"]) # Checks for system type AC_CANONICAL_TARGET diff --git a/graphviz.spec.in b/graphviz.spec.in index 9558782af..4bc46d53b 100644 --- a/graphviz.spec.in +++ b/graphviz.spec.in @@ -51,7 +51,7 @@ of graphs (as in nodes and edges, not as in barcharts). %{_libdir}/%{name}/*.pm %{_libdir}/%{name}/*.py %{_libdir}/%{name}/*.java -%{_libdir}/%{name}/*.cs +#%{_libdir}/%{name}/*.cs %{_mandir}/man1/*.1* %dir %{_datadir}/%{name} %{_datadir}/%{name}/lefty diff --git a/lib/common/emit.c b/lib/common/emit.c index 16b095126..9eeb9f0a5 100644 --- a/lib/common/emit.c +++ b/lib/common/emit.c @@ -1624,7 +1624,10 @@ void emit_jobs (GVC_t * gvc, graph_t * g) } } job->output_lang = gvrender_select(gvc, job->output_langname); - assert(job->output_lang != NO_SUPPORT); /* should have been verified already */ + if (job->output_lang == NO_SUPPORT) { + fprintf(stderr,"renderer for %s is unavailable\n", job->output_langname); + return; + } if (strcmp(job->output_langname,prev_langname) != 0) { prev_langname = job->output_langname; gvrender_initialize(gvc); diff --git a/lib/common/input.c b/lib/common/input.c index 41375e2a3..f5e12441a 100644 --- a/lib/common/input.c +++ b/lib/common/input.c @@ -29,12 +29,6 @@ codegen_t *Output_codegen; #endif -#if 0 -static char *CONFIG = "cairo {renderer {svg svgz x11 png ps}}"; -#else -static char *CONFIG = ""; -#endif - char *Gvfilepath; static char *usageFmt = @@ -152,10 +146,8 @@ void dotneato_initialize(GVC_t * gvc, int argc, char **argv) /* establish Gvfilepath, if any */ Gvfilepath = getenv("GV_FILE_PATH"); - /* configure codegens */ - config_codegen_builtins(gvc); - gvplugin_builtins(gvc); - gvconfig(gvc, CONFIG); + /* configure for available plugins and codegens */ + gvconfig(gvc); CmdName = basename(argv[0]); i = gvlayout_select(gvc, CmdName); diff --git a/lib/gvc/Makefile.am b/lib/gvc/Makefile.am index 2e226af08..a9168c0f5 100644 --- a/lib/gvc/Makefile.am +++ b/lib/gvc/Makefile.am @@ -5,11 +5,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib/common \ -I$(top_srcdir)/lib/pathplan \ -I$(top_srcdir)/lib/graph \ - -I$(top_srcdir)/lib/cdt + -I$(top_srcdir)/lib/cdt $(INCLTDL) -#@INCLTDL@ - -#LIBS = @LIBLTDL@ +LIBS = $(LIBLTDL) pkginclude_HEADERS = gvc.h gvcint.h gvplugin.h \ gvplugin_render.h gvplugin_layout.h gvplugin_text.h diff --git a/lib/gvc/gvc.h b/lib/gvc/gvc.h index 0802303b7..ccf6b3241 100644 --- a/lib/gvc/gvc.h +++ b/lib/gvc/gvc.h @@ -33,7 +33,7 @@ extern "C" { /* configuration */ - extern void gvconfig(GVC_t * gvc, char *config); + extern void gvconfig(GVC_t * gvc); /* plugins */ diff --git a/lib/gvc/gvconfig.c b/lib/gvc/gvconfig.c index a879c4483..611e81a87 100644 --- a/lib/gvc/gvconfig.c +++ b/lib/gvc/gvconfig.c @@ -23,9 +23,14 @@ #include "macros.h" #include "gvc.h" +#ifndef DISABLE_CODEGENS +extern void config_codegen_builtins(GVC_t *gvc); +#endif + /* A config for gvrender is a text file containing a - tcl-like-syntax list of plugins and their capabilities. + list of plugins and their capabilities using a tcl-like + syntax Lines beginning with '#' are ignored as comments @@ -119,33 +124,77 @@ static char *token(int *nest, char **tokens) /* gvconfig - parse a config file and install the identified plugins */ -void gvconfig(GVC_t * gvc, char *config) +void gvconfig(GVC_t * gvc) { char *s, *path, *api, *type; + api_t gv_api; int quality; int nest = 0; + int sz, rc; + FILE *f; + char *config_path, *home, *config; + char *dot_graphviz_config = "/.graphviz/config"; + +#define SZ_CONFIG 1000 + +#ifndef DISABLE_CODEGENS + config_codegen_builtins(gvc); +#endif + gvplugin_builtins(gvc); + + home = getenv ("HOME"); + if (!home) { + return; + } - s = strdup(config); - /* this copy is never free'd because the config uses pointers - into it for string values */ + config_path = malloc(strlen(home) + strlen(dot_graphviz_config) + 1); + strcpy(config_path, home); + strcat(config_path, dot_graphviz_config); + f = fopen(config_path,"r"); + if (!f) { /* if we fail to open it then it probably doesn't exists + so just fail silently, clean up and return */ + free(config_path); + return; + } + config = malloc(SZ_CONFIG); + config[0] = '\0'; + sz = fread(config, 1, SZ_CONFIG, f); + if (sz == 0) { + fprintf(stderr,"%s is zero sized, or other read error.\n", config_path); + free(config_path); + free(config); + return; + } + if (sz == SZ_CONFIG) { + fprintf(stderr,"%s is bigger than I can handle.\n", config_path); + free(config_path); + free(config); + return; + } + fclose(f); + free(config_path); /* not needed now that we've slurped in the contents */ + + s = config; separator(&nest, &s); while (*s) { path = token(&nest, &s); do { api = token(&nest, &s); + gv_api = gvplugin_api(api); + if (gv_api == -1) { + fprintf(stderr, "invalid api in config: %s %s\n", path, api); + return; + } do { type = token(&nest, &s); if (nest == 2) quality = atoi(token(&nest, &s)); else quality = 0; - if (! - (gvplugin_install - (gvc, gvplugin_api(api), type, quality, path, - NULL))) { - fprintf(stderr, "config error: %s %s %s\n", api, type, - path); + rc = gvplugin_install (gvc, gv_api, type, quality, path, NULL); + if (!rc) { + fprintf(stderr, "config error: %s %s %s\n", path, api, type); return; } } while (nest == 2); diff --git a/lib/gvc/gvplugin.c b/lib/gvc/gvplugin.c index 69550818b..7a93ec03b 100644 --- a/lib/gvc/gvplugin.c +++ b/lib/gvc/gvplugin.c @@ -17,13 +17,16 @@ #include #include #include -#include #include "config.h" #include "types.h" #include "macros.h" #include "gvc.h" +#if HAVE_LTDL +#include +#endif + /* * Define an apis array of name strings using an enumerated api_t as index. * The enumerated type is defined gvplugin.h. The apis array is @@ -109,10 +112,41 @@ gv_plugin_t *gvplugin_load(GVC_t * gvc, api_t api, char *str) } pnext = &((*pnext)->next); } - if ((*pnext)->typeptr == NULL) { - /* FIXME - load dll here */ - } free(s); + if ((*pnext) && (*pnext)->typeptr == NULL) { + +#if HAVE_LTDL + /* dynamically load required plugin library */ + + lt_dlhandle hndl; + lt_ptr ptr; + + if (lt_dlinit()) { + fprintf(stderr,"failed to init libltdl\n"); + return NULL; + } + hndl = lt_dlopen ((*pnext)->path); + if (!hndl) { + fprintf(stderr,"failed to dlopen %s\n", (*pnext)->path); + return NULL; + } + ptr = lt_dlsym (hndl, "gvplugin_cairo_LTX_plugin"); + if (!ptr) { + fprintf(stderr,"failed to resolve %s in %s\n", "gvplugin_cairo_LTX_plugin", (*pnext)->path); + return NULL; + } +#if 0 + /* FIXME */ + (*pnext)->typeptr = +#else + fprintf(stderr,"dynamic loading not implemented\n"); + return NULL; +#endif +#else + fprintf(stderr,"dynamic loading not available\n"); + return NULL; +#endif + } return (gvc->api[api] = *pnext); } @@ -159,8 +193,8 @@ const char *gvplugin_list(GVC_t * gvc, api_t api, char *str) /* point to the beginning of the linked list of plugins for this api */ plugin = &(gvc->apis[api]); - if (p) { /* if str contains a ':', and if we find a match for the type, - then just list teh alternative paths for the plugin */ + if (p) { /* if str contains a ':', and if we find a match for the type, + then just list teh alternative paths for the plugin */ pnext = plugin; while (*pnext) { /* list only the matching type */ diff --git a/tclpkg/gv/gv.cpp b/tclpkg/gv/gv.cpp index 82ea05034..553121568 100644 --- a/tclpkg/gv/gv.cpp +++ b/tclpkg/gv/gv.cpp @@ -30,10 +30,8 @@ static void gvinit() agnodeattr(NULL, "label", NODENAME_ESC); gvc = gvNEWcontext(Info, username()); - /* configure codegens */ - config_codegen_builtins(gvc); - gvplugin_builtins(gvc); -// gvconfig(gvc, CONFIG); + /* configure for available plugins and codegens */ + gvconfig(gvc); } Agraph_t *digraph(char *name) diff --git a/tclpkg/tcldot/tcldot.c b/tclpkg/tcldot/tcldot.c index 58fa7daa9..0129c948a 100644 --- a/tclpkg/tcldot/tcldot.c +++ b/tclpkg/tcldot/tcldot.c @@ -1647,14 +1647,12 @@ int Tcldot_Init(Tcl_Interp * interp) /* create a GraphViz Context and pass a pointer to it in clientdata */ gvc = gvNEWcontext(Info, username()); - /* configure codegens */ - config_codegen_builtins(gvc); + /* configure for available plugins and codegens */ + gvconfig(gvc); /* additional codegens */ for (p = cg; p->name; ++p) gvplugin_install(gvc, API_render, p->name, 0, "cg", (gvplugin_type_t *) p); - gvplugin_builtins(gvc); -// gvconfig(gvc, CONFIG); #ifndef TCLOBJ Tcl_CreateCommand(interp, "dotnew", dotnew, -- 2.40.0