Merge from emacs-24; up to 2012-12-06T01:39:03Z!monnier@iro.umontreal.ca
[bpt/emacs.git] / src / xml.c
index 0b39f3e..5939c58 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -1,5 +1,5 @@
 /* Interface to libxml2.
-   Copyright (C) 2010-2011 Free Software Foundation, Inc.
+   Copyright (C) 2010-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -20,14 +20,105 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_LIBXML2
 
-#include <setjmp.h>
 #include <libxml/tree.h>
 #include <libxml/parser.h>
 #include <libxml/HTMLparser.h>
 
 #include "lisp.h"
+#include "character.h"
 #include "buffer.h"
 
+\f
+static Lisp_Object Qlibxml2_dll;
+
+#ifdef WINDOWSNT
+
+#include <windows.h>
+#include "w32.h"
+
+/* Macro for defining functions that will be loaded from the libxml2 DLL.  */
+#define DEF_XML2_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
+
+/* Macro for loading libxml2 functions from the library.  */
+#define LOAD_XML2_FN(lib,func) {                                       \
+    fn_##func = (void *) GetProcAddress (lib, #func);                  \
+    if (!fn_##func) goto bad_library;                                  \
+  }
+
+DEF_XML2_FN (htmlDocPtr, htmlReadMemory,
+            (const char *, int, const char *, const char *, int));
+DEF_XML2_FN (xmlDocPtr, xmlReadMemory,
+            (const char *, int, const char *, const char *, int));
+DEF_XML2_FN (xmlNodePtr, xmlDocGetRootElement, (xmlDocPtr));
+DEF_XML2_FN (void, xmlFreeDoc, (xmlDocPtr));
+DEF_XML2_FN (void, xmlCleanupParser, (void));
+DEF_XML2_FN (void, xmlCheckVersion, (int));
+
+static int
+libxml2_loaded_p (void)
+{
+  Lisp_Object found = Fassq (Qlibxml2_dll, Vlibrary_cache);
+
+  if (CONSP (found))
+    return EQ (XCDR (found), Qt) ? 1 : 0;
+  return 0;
+}
+
+#else  /* !WINDOWSNT */
+
+#define fn_htmlReadMemory       htmlReadMemory
+#define fn_xmlReadMemory        xmlReadMemory
+#define fn_xmlDocGetRootElement xmlDocGetRootElement
+#define fn_xmlFreeDoc           xmlFreeDoc
+#define fn_xmlCleanupParser     xmlCleanupParser
+#define fn_xmlCheckVersion      xmlCheckVersion
+
+static int
+libxml2_loaded_p (void)
+{
+  return 1;
+}
+
+#endif /* !WINDOWSNT */
+
+static int
+init_libxml2_functions (void)
+{
+#ifdef WINDOWSNT
+  if (libxml2_loaded_p ())
+    return 1;
+  else
+    {
+      HMODULE library;
+
+      if (!(library = w32_delayed_load (Qlibxml2_dll)))
+       {
+         message ("%s", "libxml2 library not found");
+         return 0;
+       }
+
+      /* LOAD_XML2_FN jumps to bad_library if it fails to find the
+        named function.  */
+      LOAD_XML2_FN (library, htmlReadMemory);
+      LOAD_XML2_FN (library, xmlReadMemory);
+      LOAD_XML2_FN (library, xmlDocGetRootElement);
+      LOAD_XML2_FN (library, xmlFreeDoc);
+      LOAD_XML2_FN (library, xmlCleanupParser);
+      LOAD_XML2_FN (library, xmlCheckVersion);
+
+      Vlibrary_cache = Fcons (Fcons (Qlibxml2_dll, Qt), Vlibrary_cache);
+      return 1;
+    }
+
+ bad_library:
+  Vlibrary_cache = Fcons (Fcons (Qlibxml2_dll, Qnil), Vlibrary_cache);
+
+  return 0;
+#else  /* !WINDOWSNT */
+  return 1;
+#endif /* !WINDOWSNT */
+}
+
 static Lisp_Object
 make_dom (xmlNode *node)
 {
@@ -92,7 +183,7 @@ parse_region (Lisp_Object start, Lisp_Object end, Lisp_Object base_url, int html
   ptrdiff_t bytes;
   ptrdiff_t istart, iend;
 
-  LIBXML_TEST_VERSION;
+  fn_xmlCheckVersion (LIBXML_VERSION);
 
   validate_region (&start, &end);
 
@@ -111,16 +202,16 @@ parse_region (Lisp_Object start, Lisp_Object end, Lisp_Object base_url, int html
   bytes = CHAR_TO_BYTE (iend) - CHAR_TO_BYTE (istart);
 
   if (htmlp)
-    doc = htmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
-                         bytes, burl, "utf-8",
-                         HTML_PARSE_RECOVER|HTML_PARSE_NONET|
-                         HTML_PARSE_NOWARNING|HTML_PARSE_NOERROR|
-                         HTML_PARSE_NOBLANKS);
+    doc = fn_htmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
+                            bytes, burl, "utf-8",
+                            HTML_PARSE_RECOVER|HTML_PARSE_NONET|
+                            HTML_PARSE_NOWARNING|HTML_PARSE_NOERROR|
+                            HTML_PARSE_NOBLANKS);
   else
-    doc = xmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
-                        bytes, burl, "utf-8",
-                        XML_PARSE_NONET|XML_PARSE_NOWARNING|
-                        XML_PARSE_NOBLANKS |XML_PARSE_NOERROR);
+    doc = fn_xmlReadMemory ((char *) BYTE_POS_ADDR (CHAR_TO_BYTE (istart)),
+                           bytes, burl, "utf-8",
+                           XML_PARSE_NONET|XML_PARSE_NOWARNING|
+                           XML_PARSE_NOBLANKS |XML_PARSE_NOERROR);
 
   if (doc != NULL)
     {
@@ -139,19 +230,26 @@ parse_region (Lisp_Object start, Lisp_Object end, Lisp_Object base_url, int html
       if (NILP (result)) {
        /* The document isn't just comments, so get the tree the
           proper way. */
-       xmlNode *node = xmlDocGetRootElement (doc);
+       xmlNode *node = fn_xmlDocGetRootElement (doc);
        if (node != NULL)
          result = make_dom (node);
       } else
        result = Fcons (intern ("top"),
                        Fcons (Qnil, Fnreverse (Fcons (r, result))));
 
-      xmlFreeDoc (doc);
+      fn_xmlFreeDoc (doc);
     }
 
   return result;
 }
 
+void
+xml_cleanup_parser (void)
+{
+  if (libxml2_loaded_p ())
+    fn_xmlCleanupParser ();
+}
+
 DEFUN ("libxml-parse-html-region", Flibxml_parse_html_region,
        Slibxml_parse_html_region,
        2, 3, 0,
@@ -159,7 +257,9 @@ DEFUN ("libxml-parse-html-region", Flibxml_parse_html_region,
 If BASE-URL is non-nil, it is used to expand relative URLs.  */)
   (Lisp_Object start, Lisp_Object end, Lisp_Object base_url)
 {
-  return parse_region (start, end, base_url, 1);
+  if (init_libxml2_functions ())
+    return parse_region (start, end, base_url, 1);
+  return Qnil;
 }
 
 DEFUN ("libxml-parse-xml-region", Flibxml_parse_xml_region,
@@ -169,7 +269,9 @@ DEFUN ("libxml-parse-xml-region", Flibxml_parse_xml_region,
 If BASE-URL is non-nil, it is used to expand relative URLs.  */)
   (Lisp_Object start, Lisp_Object end, Lisp_Object base_url)
 {
-  return parse_region (start, end, base_url, 0);
+  if (init_libxml2_functions ())
+    return parse_region (start, end, base_url, 0);
+  return Qnil;
 }
 
 \f
@@ -181,6 +283,8 @@ syms_of_xml (void)
 {
   defsubr (&Slibxml_parse_html_region);
   defsubr (&Slibxml_parse_xml_region);
+
+  DEFSYM (Qlibxml2_dll, "libxml2");
 }
 
 #endif /* HAVE_LIBXML2 */