legacy: Add stubs for disabled modules

When legacy support is requested, always enable stubs for FTP and
XPointer location modules which were removed from the standard
configuration. Going forward, the --with-legacy configuration option
should be used to provide maximum ABI compatibility.

Fixes #433.
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 66c06a3..eea841e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,6 +20,14 @@
     BASE_CONFIG: "--with-minimum"
     CFLAGS: "-O2"
 
+gcc:legacy:
+  extends: .test
+  only:
+    - schedules
+  variables:
+    BASE_CONFIG: "--with-legacy"
+    CFLAGS: "-O2"
+
 gcc:python3:
   extends: .test
   variables:
diff --git a/include/libxml/nanoftp.h b/include/libxml/nanoftp.h
index 87a22aa..f68a786 100644
--- a/include/libxml/nanoftp.h
+++ b/include/libxml/nanoftp.h
@@ -14,7 +14,7 @@
 
 #include <libxml/xmlversion.h>
 
-#ifdef LIBXML_FTP_ENABLED
+#if defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
 
 /* Needed for portability to Windows 64 bits */
 #if defined(_WIN32)
@@ -182,5 +182,5 @@
 #ifdef __cplusplus
 }
 #endif
-#endif /* LIBXML_FTP_ENABLED */
+#endif /* defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */
 #endif /* __NANO_FTP_H__ */
diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h
index 55d25ed..dc1620a 100644
--- a/include/libxml/xmlIO.h
+++ b/include/libxml/xmlIO.h
@@ -349,7 +349,7 @@
 /**
  * Default 'ftp://' protocol callbacks
  */
-#ifdef LIBXML_FTP_ENABLED
+#if defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
 XMLPUBFUN int
 	xmlIOFTPMatch			(const char *filename);
 XMLPUBFUN void *
@@ -360,7 +360,7 @@
 					 int len);
 XMLPUBFUN int
 	xmlIOFTPClose			(void * context);
-#endif /* LIBXML_FTP_ENABLED */
+#endif /* defined(LIBXML_FTP_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */
 
 #ifdef __cplusplus
 }
diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h
index 12ce9ed..d03e527 100644
--- a/include/libxml/xpointer.h
+++ b/include/libxml/xpointer.h
@@ -28,7 +28,7 @@
 extern "C" {
 #endif
 
-#ifdef LIBXML_XPTR_LOCS_ENABLED
+#if defined(LIBXML_XPTR_LOCS_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
 /*
  * A Location Set
  */
@@ -105,7 +105,7 @@
 XMLPUBFUN void
 		    xmlXPtrLocationSetRemove	(xmlLocationSetPtr cur,
 						 int val);
-#endif /* LIBXML_XPTR_LOCS_ENABLED */
+#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */
 
 /*
  * Functions.
@@ -117,7 +117,8 @@
 XMLPUBFUN xmlXPathObjectPtr
 		    xmlXPtrEval			(const xmlChar *str,
 						 xmlXPathContextPtr ctx);
-#ifdef LIBXML_XPTR_LOCS_ENABLED
+
+#if defined(LIBXML_XPTR_LOCS_ENABLED) || defined(LIBXML_LEGACY_ENABLED)
 XML_DEPRECATED
 XMLPUBFUN void
 		    xmlXPtrRangeToFunction	(xmlXPathParserContextPtr ctxt,
@@ -128,7 +129,7 @@
 XML_DEPRECATED
 XMLPUBFUN void
 		    xmlXPtrEvalRangePredicate	(xmlXPathParserContextPtr ctxt);
-#endif /* LIBXML_XPTR_LOCS_ENABLED */
+#endif /* defined(LIBXML_XPTR_LOCS_ENABLED) || defined(LIBXML_LEGACY_ENABLED) */
 #ifdef __cplusplus
 }
 #endif
diff --git a/legacy.c b/legacy.c
index bde3854..3e3c7ef 100644
--- a/legacy.c
+++ b/legacy.c
@@ -1338,5 +1338,266 @@
         xmlSAX2CDataBlock(ctx, value, len);
 }
 
+/*
+ * nanoftp.h
+ */
+
+#ifndef LIBXML_FTP_ENABLED
+
+#include <libxml/nanoftp.h>
+
+void
+xmlNanoFTPInit(void) {
+}
+
+void
+xmlNanoFTPCleanup(void) {
+}
+
+void
+xmlNanoFTPProxy(const char *host ATTRIBUTE_UNUSED, int port ATTRIBUTE_UNUSED,
+                const char *user ATTRIBUTE_UNUSED,
+	        const char *passwd ATTRIBUTE_UNUSED, int type ATTRIBUTE_UNUSED) {
+}
+
+int
+xmlNanoFTPUpdateURL(void *ctx ATTRIBUTE_UNUSED,
+                    const char *URL ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+void
+xmlNanoFTPScanProxy(const char *URL ATTRIBUTE_UNUSED) {
+}
+
+void*
+xmlNanoFTPNewCtxt(const char *URL ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+void
+xmlNanoFTPFreeCtxt(void * ctx ATTRIBUTE_UNUSED) {
+}
+
+int
+xmlNanoFTPGetResponse(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPCheckResponse(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPQuit(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPConnect(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+void*
+xmlNanoFTPConnectTo(const char *server ATTRIBUTE_UNUSED,
+                    int port ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+int
+xmlNanoFTPCwd(void *ctx ATTRIBUTE_UNUSED,
+              const char *directory ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPDele(void *ctx ATTRIBUTE_UNUSED, const char *file ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+SOCKET
+xmlNanoFTPGetConnection(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPCloseConnection(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPList(void *ctx ATTRIBUTE_UNUSED,
+               ftpListCallback callback ATTRIBUTE_UNUSED,
+               void *userData ATTRIBUTE_UNUSED,
+	       const char *filename ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+SOCKET
+xmlNanoFTPGetSocket(void *ctx ATTRIBUTE_UNUSED,
+                    const char *filename ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPGet(void *ctx ATTRIBUTE_UNUSED,
+              ftpDataCallback callback ATTRIBUTE_UNUSED,
+              void *userData ATTRIBUTE_UNUSED,
+	      const char *filename ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlNanoFTPRead(void *ctx ATTRIBUTE_UNUSED, void *dest ATTRIBUTE_UNUSED,
+               int len ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+void*
+xmlNanoFTPOpen(const char *URL ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+int
+xmlNanoFTPClose(void *ctx ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlIOFTPMatch(const char *filename ATTRIBUTE_UNUSED) {
+    return(0);
+}
+
+void *
+xmlIOFTPOpen(const char *filename ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+int
+xmlIOFTPRead(void *context ATTRIBUTE_UNUSED, char *buffer ATTRIBUTE_UNUSED,
+             int len ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+int
+xmlIOFTPClose(void *context ATTRIBUTE_UNUSED) {
+    return(-1);
+}
+
+#endif /* #ifndef LIBXML_FTP_ENABLED */
+
+/*
+ * xpointer.h
+ */
+
+#ifndef LIBXML_XPTR_LOCS_ENABLED
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/xpointer.h>
+
+xmlXPathObjectPtr
+xmlXPtrNewRange(xmlNodePtr start ATTRIBUTE_UNUSED,
+                int startindex ATTRIBUTE_UNUSED,
+                xmlNodePtr end ATTRIBUTE_UNUSED,
+                int endindex ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewRangePoints(xmlXPathObjectPtr start ATTRIBUTE_UNUSED,
+                      xmlXPathObjectPtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewRangePointNode(xmlXPathObjectPtr start ATTRIBUTE_UNUSED,
+                         xmlNodePtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodePoint(xmlNodePtr start ATTRIBUTE_UNUSED,
+                         xmlXPathObjectPtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodes(xmlNodePtr start ATTRIBUTE_UNUSED,
+                     xmlNodePtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewCollapsedRange(xmlNodePtr start ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodeObject(xmlNodePtr start ATTRIBUTE_UNUSED,
+                          xmlXPathObjectPtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlLocationSetPtr
+xmlXPtrLocationSetCreate(xmlXPathObjectPtr val ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+void
+xmlXPtrLocationSetAdd(xmlLocationSetPtr cur ATTRIBUTE_UNUSED,
+                      xmlXPathObjectPtr val ATTRIBUTE_UNUSED) {
+}
+
+xmlLocationSetPtr
+xmlXPtrLocationSetMerge(xmlLocationSetPtr val1 ATTRIBUTE_UNUSED,
+                        xmlLocationSetPtr val2 ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+void
+xmlXPtrLocationSetDel(xmlLocationSetPtr cur ATTRIBUTE_UNUSED,
+                      xmlXPathObjectPtr val ATTRIBUTE_UNUSED) {
+}
+
+void
+xmlXPtrLocationSetRemove(xmlLocationSetPtr cur ATTRIBUTE_UNUSED,
+                         int val ATTRIBUTE_UNUSED) {
+}
+
+void
+xmlXPtrFreeLocationSet(xmlLocationSetPtr obj ATTRIBUTE_UNUSED) {
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewLocationSetNodes(xmlNodePtr start ATTRIBUTE_UNUSED,
+                           xmlNodePtr end ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlXPathObjectPtr
+xmlXPtrWrapLocationSet(xmlLocationSetPtr val ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+xmlNodePtr
+xmlXPtrBuildNodeList(xmlXPathObjectPtr obj ATTRIBUTE_UNUSED) {
+    return(NULL);
+}
+
+void
+xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt,
+                       int nargs ATTRIBUTE_UNUSED) {
+    XP_ERROR(XPATH_EXPR_ERROR);
+}
+
+#endif /* #ifndef LIBXML_XPTR_LOCS_ENABLED */
+
 #endif /* LIBXML_LEGACY_ENABLED */