[xslt] [PATCH] xslt extensions as modules, take 2



Patch Changes
--------------------------------------------------
1) we getenv("LIBXSLT_PLUGINS_PATH") to find out where plugins
   should be loaded from.
2) libexslt is no longer a bunch of plugins to maintain binary
   abi
3) the modules are actually closed on cleanup instead of being
   left in the process address space 

Implementation Notes
--------------------------------------------------
On a plugin enabled libxslt, when a function, top-level, or element
can't be found in the appropriate standard hashes, we attempt
to find a plugin like this:

Given an extension URI like "http://exslt.org/regular-expressions";
we take the last slash delimited string ("regular-expressions"),
and try to load it. The filename will look like:

a) sprintf("%s/%s", getenv("LIBXSLT_PLUGINS_PATH"), "regular-expressions")

or on *nix, if LIBXSLT_PLUGINS_PATH=NULL

b) sprintf("%s/%s", LIBXSLT_DEFAULT_PLUGINS_PATH(), "regular-expressions")

where LIBXSLT_DEFAULT_PLUGINS_PATH() = "/usr/local/lib/libxslt/1.1/"
for example.

Only open question i have is should plugin support default to on or off?

jr
? libxslt/cscope.out
? python/tests/foo
? tests/exslt/regexp
? tests/exslt/date/.memdump
? tests/keys/.memdump
Index: configure.in
===================================================================
RCS file: /cvs/gnome/libxslt/configure.in,v
retrieving revision 1.163
diff -w -u -r1.163 configure.in
--- configure.in	29 Oct 2004 15:07:14 -0000	1.163
+++ configure.in	2 Jan 2005 22:23:44 -0000
@@ -435,6 +435,35 @@
 AC_SUBST(CPPFLAGS)
 AC_SUBST(LDFLAGS)
 
+AC_ARG_WITH(plugins,
+[  --with-plugins          Add plugin extension support (off)])
+if test "$with_plugins" = ""
+then
+    with_plugins=no
+fi
+
+if test "$with_plugins" = "yes" ; then
+  AC_MSG_CHECKING([libxml2 module support])
+  WITH_MODULES="`$XML_CONFIG --modules`"
+  if test "${WITH_MODULES}" = "1"; then
+    AC_MSG_RESULT(yes)
+  else
+    AC_MSG_RESULT(no)
+  fi
+else
+  WITH_MODULES="0"
+fi
+
+AC_SUBST(WITH_MODULES)
+
+dnl
+dnl setup default module path
+dnl
+module_prefix=$prefix
+test "x$module_prefix" = xNONE && module_prefix=$ac_default_prefix
+LIBXSLT_DEFAULT_PLUGINS_PATH="\"$module_prefix/lib/libxslt/$LIBXSLT_MAJOR_VERSION.$LIBXSLT_MINOR_VERSION/\""
+AC_SUBST(LIBXSLT_DEFAULT_PLUGINS_PATH)
+
 dnl
 dnl In build tree I use a static version with memory debug enabled
 dnl
@@ -502,7 +531,6 @@
 $LN_S Copyright COPYING
 )
 
-
 AC_OUTPUT([
 Makefile
 libxslt.pc
Index: libxslt/extensions.c
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/extensions.c,v
retrieving revision 1.35
diff -w -u -r1.35 extensions.c
--- libxslt/extensions.c	1 Dec 2004 14:44:56 -0000	1.35
+++ libxslt/extensions.c	2 Jan 2005 22:23:45 -0000
@@ -13,6 +13,7 @@
 #include "libxslt.h"
 
 #include <string.h>
+#include <limits.h>
 
 #include <libxml/xmlmemory.h>
 #include <libxml/tree.h>
@@ -20,12 +21,20 @@
 #include <libxml/xmlerror.h>
 #include <libxml/parserInternals.h>
 #include <libxml/xpathInternals.h>
+#include <libxml/xmlmodule.h>
+#include <libxml/list.h>
+#include <libxml/xmlIO.h>
 #include "xslt.h"
 #include "xsltInternals.h"
 #include "xsltutils.h"
 #include "imports.h"
 #include "extensions.h"
 
+#ifdef _WIN32
+#include <stdlib.h> /* for _MAX_PATH */
+#define PATH_MAX _MAX_PATH
+#endif
+
 #ifdef WITH_XSLT_DEBUG
 #define WITH_XSLT_DEBUG_EXTENSIONS
 #endif
@@ -72,6 +81,7 @@
 static xmlHashTablePtr xsltFunctionsHash = NULL;
 static xmlHashTablePtr xsltElementsHash = NULL;
 static xmlHashTablePtr xsltTopLevelsHash = NULL;
+static xmlHashTablePtr xsltModuleHash = NULL;
 
 /************************************************************************
  * 									*
@@ -269,6 +279,80 @@
 }
 
 
+/**
+ * xsltExtModuleRegisterDynamic:
+ * @URI:  the function or element namespace URI
+ *
+ * Looks up an extension module to dynamically load
+ * based on the namespace URI
+ *
+ * Returns 0 if successful, -1 in case of error. 
+ */
+
+#ifdef WITH_MODULES
+typedef void (*exsltRegisterFunction) (void);
+
+int
+static xsltExtModuleRegisterDynamic (const xmlChar *URI) {
+
+  xmlModulePtr m;
+  exsltRegisterFunction regfunc;
+  xmlChar module_filename[PATH_MAX];
+  const xmlChar *extNameBegin = NULL;
+  const xmlChar *extDirectory = NULL;
+  int i, seen_before;
+
+  /* check for bad inputs */
+  if (URI == NULL)
+    return(-1);
+
+  if (NULL == xsltModuleHash) {
+    xsltModuleHash = xmlHashCreate(5);
+    if (xsltModuleHash == NULL)
+      return(-1);
+  }
+
+  /* have we attempted to register this module already? */
+  seen_before = (int)xmlHashLookup(xsltModuleHash, URI);
+  if (0 != seen_before) {
+    return(-1);
+  }
+
+  for (i = xmlStrlen(URI); i != 0 && extNameBegin == NULL; --i)
+    {
+      if (URI[i-1] == '/') extNameBegin = URI + i;
+    }
+
+  if (extNameBegin == NULL || *extNameBegin == '\0') 
+    return(-1);
+
+  /* determine module directory */
+  extDirectory = getenv("LIBXSLT_PLUGINS_PATH");
+  if (NULL == extDirectory) 
+    extDirectory = LIBXSLT_DEFAULT_PLUGINS_PATH();
+  if (NULL == extDirectory) 
+    return(-1);
+
+  /* build the module filename and open it*/
+  xmlStrPrintf(module_filename, sizeof(module_filename), "%s%s", extDirectory, extNameBegin);
+  m = xmlModuleOpen(module_filename);
+  if (NULL == m) 
+    return(-1);
+                   
+  regfunc = (exsltRegisterFunction) xmlModuleSymbol(m, "exsltRegisterModule");
+  if (NULL != regfunc) {
+    (*regfunc)();
+  }
+
+  /* register this module in our hash */
+  xmlHashAddEntry(xsltModuleHash, URI, (void*)m);
+
+  return (NULL == regfunc)? -1 : 0;
+}
+#else
+#define xsltExtModuleRegisterDynamic(b) -1
+#endif
+
 /************************************************************************
  * 									*
  * 		The stylesheet extension prefixes handling		*
@@ -330,10 +414,17 @@
 	xsltExtModulePtr module;
 
 	module = xmlHashLookup(xsltExtensionsHash, URI);
+  if (NULL == module) {
+    if (!xsltExtModuleRegisterDynamic(URI)) {
+      module = xmlHashLookup(xsltExtensionsHash, URI);
+    }
+  }
+
 	if (module != NULL) {
 	    xsltStyleGetExtData(style, URI);
 	}
     }
+
     return(0);
 }
 
@@ -959,6 +1050,14 @@
 	return(NULL);
 
     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI);
+      }
+    }
+
     return ret;
 }
 
@@ -1160,6 +1259,14 @@
 
     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
 
+    /* if function lookup fails, attempt a dynamic load on supported platforms */
+    ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+    if (NULL == ext) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+      }
+    }
+
     if (ext == NULL)
 	return(NULL);
     return(ext->transform);
@@ -1184,6 +1291,12 @@
 
     ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
 
+    if (ext == NULL) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI);
+      }
+    }
+
     if (ext == NULL)
 	return(NULL);
     return(ext->precomp);
@@ -1262,6 +1375,14 @@
 	return(NULL);
 
     XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+
+    /* if lookup fails, attempt a dynamic load on supported platforms */
+    if (NULL == ret) {
+      if (!xsltExtModuleRegisterDynamic(URI)) {
+        XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI);
+      }
+    }
+
     return(ret);
 }
 
@@ -1599,6 +1720,12 @@
 				 xsltExtElementTest);
 }
 
+static void
+xsltHashScannerModuleFree(void * payload, void * data, xmlChar * name)
+{
+  xmlModuleClose(payload); 
+}
+
 /**
  * xsltCleanupGlobals:
  *
@@ -1611,6 +1738,14 @@
     xsltUnregisterAllExtModuleFunction();
     xsltUnregisterAllExtModuleElement();
     xsltUnregisterAllExtModuleTopLevel();
+
+    /* cleanup dynamic module hash */
+    if (NULL != xsltModuleHash)
+      {
+        xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0);
+        xmlHashFree(xsltModuleHash, NULL);
+        xsltModuleHash = NULL;
+      }
 }
 
 static void
Index: libxslt/xsltconfig.h.in
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltconfig.h.in,v
retrieving revision 1.22
diff -w -u -r1.22 xsltconfig.h.in
--- libxslt/xsltconfig.h.in	18 Aug 2004 21:27:08 -0000	1.22
+++ libxslt/xsltconfig.h.in	2 Jan 2005 22:23:48 -0000
@@ -107,6 +107,19 @@
 #endif
 
 /**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ * Note: no default module path for win32 platforms
+ */
+#if @WITH_MODULES@
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define LIBXSLT_DEFAULT_PLUGINS_PATH() @LIBXSLT_DEFAULT_PLUGINS_PATH@
+#endif
+
+/**
  * ATTRIBUTE_UNUSED:
  *
  * This macro is used to flag unused function parameters to GCC
Index: libxslt/xsltwin32config.h
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltwin32config.h,v
retrieving revision 1.71
diff -w -u -r1.71 xsltwin32config.h
--- libxslt/xsltwin32config.h	23 Dec 2004 08:08:11 -0000	1.71
+++ libxslt/xsltwin32config.h	2 Jan 2005 22:23:48 -0000
@@ -57,6 +57,18 @@
 #define WITH_XSLT_DEBUG
 #endif
 
+/**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ */
+#if 1
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define LIBXSLT_PLUGINS_PATH() getenv("LIBXSLT_PLUGINS_PATH")
+#endif
+
 #if 0
 /**
  * DEBUG_MEMORY:
Index: libxslt/xsltwin32config.h.in
===================================================================
RCS file: /cvs/gnome/libxslt/libxslt/xsltwin32config.h.in,v
retrieving revision 1.7
diff -w -u -r1.7 xsltwin32config.h.in
--- libxslt/xsltwin32config.h.in	18 Aug 2004 21:27:08 -0000	1.7
+++ libxslt/xsltwin32config.h.in	2 Jan 2005 22:23:48 -0000
@@ -57,6 +57,18 @@
 #define WITH_XSLT_DEBUG
 #endif
 
+/**
+ * WITH_MODULES:
+ *
+ * Whether module support is configured into libxslt
+ */
+#if @WITH_MODULES@
+#ifndef WITH_MODULES
+#define WITH_MODULES
+#endif
+#define LIBXSLT_PLUGINS_PATH() getenv("LIBXSLT_PLUGINS_PATH")
+#endif
+
 #if 0
 /**
  * DEBUG_MEMORY:
Index: win32/configure.js
===================================================================
RCS file: /cvs/gnome/libxslt/win32/configure.js,v
retrieving revision 1.15
diff -w -u -r1.15 configure.js
--- win32/configure.js	24 Aug 2004 14:43:44 -0000	1.15
+++ win32/configure.js	2 Jan 2005 22:23:52 -0000
@@ -48,6 +48,7 @@
 var withIconv = true;
 var withZlib = false;
 var withCrypto = true;
+var withModules = false;
 /* Win32 build options. */
 var dirSep = "\\";
 var compiler = "msvc";
@@ -105,6 +106,7 @@
 	txt += "  iconv:      Use iconv library (" + (withIconv? "yes" : "no")  + ")\n";
 	txt += "  zlib:       Use zlib library (" + (withZlib? "yes" : "no") + ")\n";
 	txt += "  crypto:     Enable Crypto support (" + (withCrypto? "yes" : "no") + ")\n";
+	txt += "  modules:    Enable Module support (" + (withModules? "yes" : "no") + ")\n";
 	txt += "\nWin32 build options, default value given in parentheses:\n\n";
 	txt += "  compiler:   Compiler to be used [msvc|mingw] (" + compiler + ")\n";
 	txt += "  cruntime:   C-runtime compiler option (only msvc) (" + cruntime + ")\n";
@@ -188,6 +190,7 @@
 	vf.WriteLine("WITH_ICONV=" + (withIconv? "1" : "0"));
 	vf.WriteLine("WITH_ZLIB=" + (withZlib? "1" : "0"));
 	vf.WriteLine("WITH_CRYPTO=" + (withCrypto? "1" : "0"));
+	vf.WriteLine("WITH_MODULES=" + (withModules? "1" : "0"));
 	vf.WriteLine("DEBUG=" + (buildDebug? "1" : "0"));
 	vf.WriteLine("STATIC=" + (buildStatic? "1" : "0"));
 	vf.WriteLine("PREFIX=" + buildPrefix);
@@ -233,6 +236,10 @@
 			of.WriteLine(s.replace(/\ WITH_MEM_DEBUG\@/, withMemDebug? "1" : "0"));
 		} else if (s.search(/\ WITH_DEBUGGER\@/) != -1) {
 			of.WriteLine(s.replace(/\ WITH_DEBUGGER\@/, withDebugger? "1" : "0"));
+		} else if (s.search(/\ WITH_MODULES\@/) != -1) {
+			of.WriteLine(s.replace(/\ WITH_MODULES\@/, withModules? "1" : "0"));
+		} else if (s.search(/\ LIBXSLT_DEFAULT_PLUGINS_PATH\@/) != -1) {
+			of.WriteLine(s.replace(/\ LIBXSLT_DEFAULT_PLUGINS_PATH\@/, "NULL"));
 		} else
 			of.WriteLine(ln);
 	}
@@ -262,6 +269,8 @@
 			of.WriteLine(s.replace(/\ LIBEXSLT_VERSION_EXTRA\@/, verCvs));
 		} else if (s.search(/\ WITH_CRYPTO\@/) != -1) {
 			of.WriteLine(s.replace(/\ WITH_CRYPTO\@/, withCrypto? "1" : "0"));
+		} else if (s.search(/\ WITH_MODULES\@/) != -1) {
+			of.WriteLine(s.replace(/\ WITH_MODULES\@/, withModules? "1" : "0"));
 		} else
 			of.WriteLine(ln);
 	}
@@ -332,6 +341,8 @@
 			withZlib  = strToBool(arg.substring(opt.length + 1, arg.length));
 		else if (opt == "crypto")
 			withCrypto = strToBool(arg.substring(opt.length + 1, arg.length));
+		else if (opt == "modules")
+			withModules = strToBool(arg.substring(opt.length + 1, arg.length));
 		else if (opt == "compiler")
 			compiler = arg.substring(opt.length + 1, arg.length);
  		else if (opt == "cruntime")
@@ -446,6 +457,7 @@
 txtOut += "         Use iconv: " + boolToStr(withIconv) + "\n";
 txtOut += "         With zlib: " + boolToStr(withZlib) + "\n";
 txtOut += "            Crypto: " + boolToStr(withCrypto) + "\n";
+txtOut += "           Modules: " + boolToStr(withModules) + "\n";
 txtOut += "\n";
 txtOut += "Win32 build configuration\n";
 txtOut += "-------------------------\n";


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]