added the 'usual' setup.py to allow building a libxml2-python module based

* python/README python/generator.py python/libxml.c python/setup.py:
  added the 'usual' setup.py to allow building a libxml2-python
  module based on the same code. The initialization is however
  different the 2 .so files fo libxml2 and libxslt are identical and
  they entry point initialize both libraries. this is done to avoid
  some possible nasty problem since the Python don't merge the maps
  of all shared modules.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 6d80326..a4e84f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Fri Feb 22 23:44:57 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+	* python/README python/generator.py python/libxml.c python/setup.py:
+	  added the 'usual' setup.py to allow building a libxml2-python
+	  module based on the same code. The initialization is however
+	  different the 2 .so files fo libxml2 and libxslt are identical and
+	  they entry point initialize both libraries. this is done to avoid
+	  some possible nasty problem since the Python don't merge the maps
+	  of all shared modules.
+
 Wed Feb 20 23:16:08 CET 2002 Daniel Veillard <daniel@veillard.com>
 
 	* parser.c: fixed a push/encoding bug reported by Michael
diff --git a/python/README b/python/README
new file mode 100644
index 0000000..b46eee4
--- /dev/null
+++ b/python/README
@@ -0,0 +1,34 @@
+		Module libxml2-python
+		=====================
+
+This is the libxml2 python module, providing access to the
+libxml2 and libxslt (if available) libraries. For general
+informationss on those XML and XSLT libraries check their 
+web pages at :
+    http://xmlsoft.org/
+    and
+    http://xmlsoft.org/XSLT/
+
+The latest version of the sources for this module and the
+associated libraries can be found at:
+    ftp://xmlsoft.org/
+
+Binaries packages of the libxml2 and libxslt libraries can
+be found either on the FTP site for Linux, from external
+sources linked from the web pages, or as part of your set of
+packages provided with your operating system.
+
+NOTE:
+this module distribution is not the primary distribution
+of the libxml2 and libxslt Python binding code, but as 
+the Python way of packaging those for non-Linux systems.
+The main sources are the libxml2 and libxslt tar.gz found on
+the site. One side effect is that the official RPM packages for
+those modules are not generated from the libxml2-python
+distributions but as part of the normal RPM packaging of
+those two libraries.
+The RPM packages can be found at:
+    http://rpmfind.net/linux/rpm2html/search.php?query=libxml2-python
+    http://rpmfind.net/linux/rpm2html/search.php?query=libxslt-python
+
+Daniel Veillard
diff --git a/python/generator.py b/python/generator.py
index 09009a2..7a575c5 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -5,6 +5,7 @@
 
 functions = {}
 
+import sys
 import string
 
 #######################################################################
@@ -408,65 +409,78 @@
     output.write("}\n\n")
     return 1
 
-try:
-    f = open("../doc/libxml2-api.xml")
-    data = f.read()
-    (parser, target)  = getparser()
-    parser.feed(data)
-    parser.close()
-except IOError, msg:
-    print file, ":", msg
+def buildStubs():
+    global py_types
+    global py_return_types
+    global unknown_types
 
-n = len(functions.keys())
-print "Found %d functions in libxml2-api.xml" % (n)
+    try:
+	f = open("libxml2-api.xml")
+	data = f.read()
+	(parser, target)  = getparser()
+	parser.feed(data)
+	parser.close()
+    except IOError, msg:
+	try:
+	    f = open("../doc/libxml2-api.xml")
+	    data = f.read()
+	    (parser, target)  = getparser()
+	    parser.feed(data)
+	    parser.close()
+	except IOError, msg:
+	    print file, ":", msg
+	    sys.exit(1)
 
-py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
-try:
-    f = open("libxml2-python-api.xml")
-    data = f.read()
-    (parser, target)  = getparser()
-    parser.feed(data)
-    parser.close()
-except IOError, msg:
-    print file, ":", msg
+    n = len(functions.keys())
+    print "Found %d functions in libxml2-api.xml" % (n)
+
+    py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
+    try:
+	f = open("libxml2-python-api.xml")
+	data = f.read()
+	(parser, target)  = getparser()
+	parser.feed(data)
+	parser.close()
+    except IOError, msg:
+	print file, ":", msg
 
 
-print "Found %d functions in libxml2-python-api.xml" % (
-      len(functions.keys()) - n)
-nb_wrap = 0
-failed = 0
-skipped = 0
+    print "Found %d functions in libxml2-python-api.xml" % (
+	  len(functions.keys()) - n)
+    nb_wrap = 0
+    failed = 0
+    skipped = 0
 
-include = open("libxml2-py.h", "w")
-include.write("/* Generated */\n\n")
-export = open("libxml2-export.c", "w")
-export.write("/* Generated */\n\n")
-wrapper = open("libxml2-py.c", "w")
-wrapper.write("/* Generated */\n\n")
-wrapper.write("#include <Python.h>\n")
-wrapper.write("#include <libxml/tree.h>\n")
-wrapper.write("#include \"libxml_wrap.h\"\n")
-wrapper.write("#include \"libxml2-py.h\"\n\n")
-for function in functions.keys():
-    ret = print_function_wrapper(function, wrapper, export, include)
-    if ret < 0:
-        failed = failed + 1
-        del functions[function]
-    if ret == 0:
-        skipped = skipped + 1
-        del functions[function]
-    if ret == 1:
-        nb_wrap = nb_wrap + 1
-include.close()
-export.close()
-wrapper.close()
+    include = open("libxml2-py.h", "w")
+    include.write("/* Generated */\n\n")
+    export = open("libxml2-export.c", "w")
+    export.write("/* Generated */\n\n")
+    wrapper = open("libxml2-py.c", "w")
+    wrapper.write("/* Generated */\n\n")
+    wrapper.write("#include <Python.h>\n")
+    wrapper.write("#include <libxml/tree.h>\n")
+    wrapper.write("#include \"libxml_wrap.h\"\n")
+    wrapper.write("#include \"libxml2-py.h\"\n\n")
+    for function in functions.keys():
+	ret = print_function_wrapper(function, wrapper, export, include)
+	if ret < 0:
+	    failed = failed + 1
+	    del functions[function]
+	if ret == 0:
+	    skipped = skipped + 1
+	    del functions[function]
+	if ret == 1:
+	    nb_wrap = nb_wrap + 1
+    include.close()
+    export.close()
+    wrapper.close()
 
-print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
-                                                          failed, skipped);
-print "Missing type converters: "
-for type in unknown_types.keys():
-    print "%s:%d " % (type, len(unknown_types[type])),
-print
+    print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
+							      failed, skipped);
+    print "Missing type converters: "
+    for type in unknown_types.keys():
+	print "%s:%d " % (type, len(unknown_types[type])),
+    print
 
 #######################################################################
 #
@@ -531,36 +545,8 @@
 function_classes = {}
 
 function_classes["None"] = []
-for type in classes_type.keys():
-    function_classes[classes_type[type][2]] = []
-    
-#
-# Build the list of C types to look for ordered to start with primary classes
-#
-ctypes = []
-classes_list = []
-ctypes_processed = {}
-classes_processed = {}
-for classe in primary_classes:
-    classes_list.append(classe)
-    classes_processed[classe] = ()
-    for type in classes_type.keys():
-        tinfo = classes_type[type]
-        if tinfo[2] == classe:
-            ctypes.append(type)
-            ctypes_processed[type] = ()
-for type in classes_type.keys():
-    if ctypes_processed.has_key(type):
-        continue
-    tinfo = classes_type[type]
-    if not classes_processed.has_key(tinfo[2]):
-        classes_list.append(tinfo[2])
-        classes_processed[tinfo[2]] = ()
-        
-    ctypes.append(type)
-    ctypes_processed[type] = ()
 
-def nameFixup(function, classe, type, file):
+def nameFixup(name, classe, type, file):
     listname = classe + "List"
     ll = len(listname)
     l = len(classe)
@@ -613,49 +599,6 @@
         func = "UTF8" + func[4:]
     return func
 
-for name in functions.keys():
-    found = 0;
-    (desc, ret, args, file) = functions[name]
-    for type in ctypes:
-        classe = classes_type[type][2]
-
-        if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
-            found = 1
-            func = nameFixup(name, classe, type, file)
-            info = (0, func, name, ret, args, file)
-            function_classes[classe].append(info)
-        elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type:
-            found = 1
-            func = nameFixup(name, classe, type, file)
-            info = (1, func, name, ret, args, file)
-            function_classes[classe].append(info)
-        elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
-            found = 1
-            func = nameFixup(name, classe, type, file)
-            info = (0, func, name, ret, args, file)
-            function_classes[classe].append(info)
-        elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type:
-            found = 1
-            func = nameFixup(name, classe, type, file)
-            info = (1, func, name, ret, args, file)
-            function_classes[classe].append(info)
-        if found == 1:
-            break
-    if found == 1:
-        continue
-    if name[0:8] == "xmlXPath":
-        continue
-    if name[0:6] == "xmlStr":
-        continue
-    if name[0:10] == "xmlCharStr":
-        continue
-    func = nameFixup(name, "None", file, file)
-    info = (0, func, name, ret, args, file)
-    function_classes['None'].append(info)
-
-classes = open("libxml2class.py", "w")
-txt = open("libxml2class.txt", "w")
-txt.write("          Generated Classes for libxml2-python\n\n")
 
 def functionCompare(info1, info2):
     (index1, func1, name1, ret1, args1, file1) = info1
@@ -695,157 +638,253 @@
      output.write(val);
      output.write('"""\n')
 
-txt.write("#\n# Global functions of the module\n#\n\n")
-if function_classes.has_key("None"):
-    flist = function_classes["None"]
-    flist.sort(functionCompare)
-    oldfile = ""
-    for info in flist:
-        (index, func, name, ret, args, file) = info
-        if file != oldfile:
-            classes.write("#\n# Functions from module %s\n#\n\n" % file)
-            txt.write("\n# functions from module %s\n" % file)
-            oldfile = file
-        classes.write("def %s(" % func)
-        txt.write("%s()\n" % func);
-        n = 0
-        for arg in args:
-            if n != 0:
-                classes.write(", ")
-            classes.write("%s" % arg[0])
-            n = n + 1
-        classes.write("):\n")
-        writeDoc(name, args, '    ', classes);
+def buildWrappers():
+    global ctypes
+    global py_types
+    global py_return_types
+    global unknown_types
+    global functions
+    global function_classes
+    global classes_type
+    global classes_list
+    global converter_type
+    global primary_classes
+    global converter_type
+    global classes_ancestor
+    global converter_type
+    global primary_classes
+    global classes_ancestor
+    global classes_destructors
 
-        for arg in args:
-            if classes_type.has_key(arg[1]):
-                classes.write("    if %s == None: %s__o = None\n" %
-                              (arg[0], arg[0]))
-                classes.write("    else: %s__o = %s%s\n" %
-                              (arg[0], arg[0], classes_type[arg[1]][0]))
-        if ret[0] != "void":
-            classes.write("    ret = ");
-        else:
-            classes.write("    ");
-        classes.write("libxml2mod.%s(" % name)
-        n = 0
-        for arg in args:
-            if n != 0:
-                classes.write(", ");
-            classes.write("%s" % arg[0])
-            if classes_type.has_key(arg[1]):
-                classes.write("__o");
-            n = n + 1
-        classes.write(")\n");
-        if ret[0] != "void":
-            if classes_type.has_key(ret[0]):
-                classes.write("    if ret == None: return None\n");
-                classes.write("    return ");
-                classes.write(classes_type[ret[0]][1] % ("ret"));
-                classes.write("\n");
-            else:
-                classes.write("    return ret\n");
-        classes.write("\n");
+    for type in classes_type.keys():
+	function_classes[classes_type[type][2]] = []
 
-txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
-for classname in classes_list:
-    if classname == "None":
-        pass
-    else:
-        if classes_ancestor.has_key(classname):
-            txt.write("\n\nClass %s(%s)\n" % (classname,
-                      classes_ancestor[classname]))
-            classes.write("class %s(%s):\n" % (classname,
-                          classes_ancestor[classname]))
-            classes.write("    def __init__(self, _obj=None):\n")
-            classes.write("        self._o = None\n")
-            classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
-                          classes_ancestor[classname]))
-            if classes_ancestor[classname] == "xmlCore" or \
-               classes_ancestor[classname] == "xmlNode":
-                classes.write("    def __repr__(self):\n")
-                format = "%s:%%s" % (classname)
-                classes.write("        return \"%s\" %% (self.name)\n\n" % (
-                              format))
-        else:
-            txt.write("Class %s()\n" % (classname))
-            classes.write("class %s:\n" % (classname))
-            classes.write("    def __init__(self, _obj=None):\n")
-            classes.write("        if _obj != None:self._o = _obj;return\n")
-            classes.write("        self._o = None\n\n");
-        if classes_destructors.has_key(classname):
-            classes.write("    def __del__(self):\n")
-            classes.write("        if self._o != None:\n")
-            classes.write("            libxml2mod.%s(self._o)\n" %
-                          classes_destructors[classname]);
-            classes.write("        self._o = None\n\n");
-        flist = function_classes[classname]
-        flist.sort(functionCompare)
-        oldfile = ""
-        for info in flist:
-            (index, func, name, ret, args, file) = info
-            if file != oldfile:
-                if file == "python_accessor":
-                    classes.write("    # accessors for %s\n" % (classname))
-                    txt.write("    # accessors\n")
-                else:
-                    classes.write("    #\n")
-                    classes.write("    # %s functions from module %s\n" % (
-                                  classname, file))
-                    txt.write("\n    # functions from module %s\n" % file)
-                    classes.write("    #\n\n")
-            oldfile = file
-            classes.write("    def %s(self" % func)
-            txt.write("    %s()\n" % func);
-            n = 0
-            for arg in args:
-                if n != index:
-                    classes.write(", %s" % arg[0])
-                n = n + 1
-            classes.write("):\n")
-            writeDoc(name, args, '        ', classes);
-            n = 0
-            for arg in args:
-                if classes_type.has_key(arg[1]):
-                    if n != index:
-                        classes.write("        if %s == None: %s__o = None\n" %
-                                      (arg[0], arg[0]))
-                        classes.write("        else: %s__o = %s%s\n" %
-                                      (arg[0], arg[0], classes_type[arg[1]][0]))
-                n = n + 1
-            if ret[0] != "void":
-                classes.write("        ret = ");
-            else:
-                classes.write("        ");
-            classes.write("libxml2mod.%s(" % name)
-            n = 0
-            for arg in args:
-                if n != 0:
-                    classes.write(", ");
-                if n != index:
-                    classes.write("%s" % arg[0])
-                    if classes_type.has_key(arg[1]):
-                        classes.write("__o");
-                else:
-                    classes.write("self");
-                    if classes_type.has_key(arg[1]):
-                        classes.write(classes_type[arg[1]][0])
-                n = n + 1
-            classes.write(")\n");
-            if ret[0] != "void":
-                if classes_type.has_key(ret[0]):
-                    classes.write("        if ret == None: return None\n");
-                    classes.write("        return ");
-                    classes.write(classes_type[ret[0]][1] % ("ret"));
-                    classes.write("\n");
-                elif converter_type.has_key(ret[0]):
-                    classes.write("        if ret == None: return None\n");
-                    classes.write("        return ");
-                    classes.write(converter_type[ret[0]] % ("ret"));
-                    classes.write("\n");
-                else:
-                    classes.write("        return ret\n");
-            classes.write("\n");
+    #
+    # Build the list of C types to look for ordered to start
+    # with primary classes
+    #
+    ctypes = []
+    classes_list = []
+    ctypes_processed = {}
+    classes_processed = {}
+    for classe in primary_classes:
+	classes_list.append(classe)
+	classes_processed[classe] = ()
+	for type in classes_type.keys():
+	    tinfo = classes_type[type]
+	    if tinfo[2] == classe:
+		ctypes.append(type)
+		ctypes_processed[type] = ()
+    for type in classes_type.keys():
+	if ctypes_processed.has_key(type):
+	    continue
+	tinfo = classes_type[type]
+	if not classes_processed.has_key(tinfo[2]):
+	    classes_list.append(tinfo[2])
+	    classes_processed[tinfo[2]] = ()
+	    
+	ctypes.append(type)
+	ctypes_processed[type] = ()
 
-txt.close()
-classes.close()
+    for name in functions.keys():
+	found = 0;
+	(desc, ret, args, file) = functions[name]
+	for type in ctypes:
+	    classe = classes_type[type][2]
+
+	    if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
+		found = 1
+		func = nameFixup(name, classe, type, file)
+		info = (0, func, name, ret, args, file)
+		function_classes[classe].append(info)
+	    elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type:
+		found = 1
+		func = nameFixup(name, classe, type, file)
+		info = (1, func, name, ret, args, file)
+		function_classes[classe].append(info)
+	    elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
+		found = 1
+		func = nameFixup(name, classe, type, file)
+		info = (0, func, name, ret, args, file)
+		function_classes[classe].append(info)
+	    elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type:
+		found = 1
+		func = nameFixup(name, classe, type, file)
+		info = (1, func, name, ret, args, file)
+		function_classes[classe].append(info)
+	    if found == 1:
+		break
+	if found == 1:
+	    continue
+	if name[0:8] == "xmlXPath":
+	    continue
+	if name[0:6] == "xmlStr":
+	    continue
+	if name[0:10] == "xmlCharStr":
+	    continue
+	func = nameFixup(name, "None", file, file)
+	info = (0, func, name, ret, args, file)
+	function_classes['None'].append(info)
+   
+    classes = open("libxml2class.py", "w")
+    txt = open("libxml2class.txt", "w")
+    txt.write("          Generated Classes for libxml2-python\n\n")
+
+    txt.write("#\n# Global functions of the module\n#\n\n")
+    if function_classes.has_key("None"):
+	flist = function_classes["None"]
+	flist.sort(functionCompare)
+	oldfile = ""
+	for info in flist:
+	    (index, func, name, ret, args, file) = info
+	    if file != oldfile:
+		classes.write("#\n# Functions from module %s\n#\n\n" % file)
+		txt.write("\n# functions from module %s\n" % file)
+		oldfile = file
+	    classes.write("def %s(" % func)
+	    txt.write("%s()\n" % func);
+	    n = 0
+	    for arg in args:
+		if n != 0:
+		    classes.write(", ")
+		classes.write("%s" % arg[0])
+		n = n + 1
+	    classes.write("):\n")
+	    writeDoc(name, args, '    ', classes);
+
+	    for arg in args:
+		if classes_type.has_key(arg[1]):
+		    classes.write("    if %s == None: %s__o = None\n" %
+				  (arg[0], arg[0]))
+		    classes.write("    else: %s__o = %s%s\n" %
+				  (arg[0], arg[0], classes_type[arg[1]][0]))
+	    if ret[0] != "void":
+		classes.write("    ret = ");
+	    else:
+		classes.write("    ");
+	    classes.write("libxml2mod.%s(" % name)
+	    n = 0
+	    for arg in args:
+		if n != 0:
+		    classes.write(", ");
+		classes.write("%s" % arg[0])
+		if classes_type.has_key(arg[1]):
+		    classes.write("__o");
+		n = n + 1
+	    classes.write(")\n");
+	    if ret[0] != "void":
+		if classes_type.has_key(ret[0]):
+		    classes.write("    if ret == None: return None\n");
+		    classes.write("    return ");
+		    classes.write(classes_type[ret[0]][1] % ("ret"));
+		    classes.write("\n");
+		else:
+		    classes.write("    return ret\n");
+	    classes.write("\n");
+
+    txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
+    for classname in classes_list:
+	if classname == "None":
+	    pass
+	else:
+	    if classes_ancestor.has_key(classname):
+		txt.write("\n\nClass %s(%s)\n" % (classname,
+			  classes_ancestor[classname]))
+		classes.write("class %s(%s):\n" % (classname,
+			      classes_ancestor[classname]))
+		classes.write("    def __init__(self, _obj=None):\n")
+		classes.write("        self._o = None\n")
+		classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
+			      classes_ancestor[classname]))
+		if classes_ancestor[classname] == "xmlCore" or \
+		   classes_ancestor[classname] == "xmlNode":
+		    classes.write("    def __repr__(self):\n")
+		    format = "%s:%%s" % (classname)
+		    classes.write("        return \"%s\" %% (self.name)\n\n" % (
+				  format))
+	    else:
+		txt.write("Class %s()\n" % (classname))
+		classes.write("class %s:\n" % (classname))
+		classes.write("    def __init__(self, _obj=None):\n")
+		classes.write("        if _obj != None:self._o = _obj;return\n")
+		classes.write("        self._o = None\n\n");
+	    if classes_destructors.has_key(classname):
+		classes.write("    def __del__(self):\n")
+		classes.write("        if self._o != None:\n")
+		classes.write("            libxml2mod.%s(self._o)\n" %
+			      classes_destructors[classname]);
+		classes.write("        self._o = None\n\n");
+	    flist = function_classes[classname]
+	    flist.sort(functionCompare)
+	    oldfile = ""
+	    for info in flist:
+		(index, func, name, ret, args, file) = info
+		if file != oldfile:
+		    if file == "python_accessor":
+			classes.write("    # accessors for %s\n" % (classname))
+			txt.write("    # accessors\n")
+		    else:
+			classes.write("    #\n")
+			classes.write("    # %s functions from module %s\n" % (
+				      classname, file))
+			txt.write("\n    # functions from module %s\n" % file)
+			classes.write("    #\n\n")
+		oldfile = file
+		classes.write("    def %s(self" % func)
+		txt.write("    %s()\n" % func);
+		n = 0
+		for arg in args:
+		    if n != index:
+			classes.write(", %s" % arg[0])
+		    n = n + 1
+		classes.write("):\n")
+		writeDoc(name, args, '        ', classes);
+		n = 0
+		for arg in args:
+		    if classes_type.has_key(arg[1]):
+			if n != index:
+			    classes.write("        if %s == None: %s__o = None\n" %
+					  (arg[0], arg[0]))
+			    classes.write("        else: %s__o = %s%s\n" %
+					  (arg[0], arg[0], classes_type[arg[1]][0]))
+		    n = n + 1
+		if ret[0] != "void":
+		    classes.write("        ret = ");
+		else:
+		    classes.write("        ");
+		classes.write("libxml2mod.%s(" % name)
+		n = 0
+		for arg in args:
+		    if n != 0:
+			classes.write(", ");
+		    if n != index:
+			classes.write("%s" % arg[0])
+			if classes_type.has_key(arg[1]):
+			    classes.write("__o");
+		    else:
+			classes.write("self");
+			if classes_type.has_key(arg[1]):
+			    classes.write(classes_type[arg[1]][0])
+		    n = n + 1
+		classes.write(")\n");
+		if ret[0] != "void":
+		    if classes_type.has_key(ret[0]):
+			classes.write("        if ret == None: return None\n");
+			classes.write("        return ");
+			classes.write(classes_type[ret[0]][1] % ("ret"));
+			classes.write("\n");
+		    elif converter_type.has_key(ret[0]):
+			classes.write("        if ret == None: return None\n");
+			classes.write("        return ");
+			classes.write(converter_type[ret[0]] % ("ret"));
+			classes.write("\n");
+		    else:
+			classes.write("        return ret\n");
+		classes.write("\n");
+
+    txt.close()
+    classes.close()
+
+
+buildStubs()
+buildWrappers()
diff --git a/python/libxml.c b/python/libxml.c
index 1a21279..e6a9eb8 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -4,6 +4,9 @@
  *           entry points where an automatically generated stub is either
  *           unpractical or would not match cleanly the Python model.
  *
+ * If compiled with MERGED_MODULES, the entry point will be used to
+ * initialize both the libxml2 and the libxslt wrappers
+ *
  * See Copyright for the status of this software.
  *
  * daniel@veillard.com
@@ -1418,9 +1421,16 @@
     { NULL }
 };
 
+#ifdef MERGED_MODULES
+extern void initlibxml2mod(void);
+#endif
+
 void initlibxml2mod(void) {
     PyObject *m;
     m = Py_InitModule("libxml2mod", libxmlMethods);
     libxml_xmlErrorInitialize();
+#ifdef MERGED_MODULES
+    initlibxsltmod();
+#endif
 }
 
diff --git a/python/setup.py b/python/setup.py
new file mode 100755
index 0000000..57a890a
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,120 @@
+#!/usr/bin/python -u
+#
+# Setup script for libxml2 and libxslt if found
+#
+import sys, os
+from distutils.core import setup, Extension
+
+
+def missing(file):
+    if os.access(file, os.R_OK) == 0:
+        return 1
+    return 0
+
+xml_files = ["libxml2-api.xml", "libxml2-python-api.xml",
+             "libxml.c", "libxml.py", "libxml_wrap.h", "types.c",
+	     "xmlgenerator.py", "README", "TODO"]
+
+xslt_files = ["libxslt-api.xml", "libxslt-python-api.xml",
+             "libxslt.c", "libxsl.py", "libxslt_wrap.h",
+	     "xsltgenerator.py"]
+
+if missing("libxml2-py.c") or missing("libxml2.py"):
+    try:
+	try:
+	    import xmlgenerator
+	except:
+	    import generator
+    except:
+	print "failed to find and generate stubs for libxml2, aborting ..."
+	print sys.exc_type, sys.exc_value
+	sys.exit(1)
+
+    head = open("libxml.py", "r")
+    generated = open("libxml2class.py", "r")
+    result = open("libxml2.py", "w")
+    for line in head.readlines():
+	result.write(line)
+    for line in generated.readlines():
+	result.write(line)
+    head.close()
+    generated.close()
+    result.close()
+
+with_xslt=0
+if missing("libxslt-py.c") or missing("libxslt.py"):
+    if missing("xsltgenerator.py") or missing("libxslt-api.xml"):
+        print "libxslt stub generator not found, libxslt not built"
+    else:
+	try:
+	    import xsltgenerator
+	except:
+	    print "failed to generate stubs for libxslt, aborting ..."
+	    print sys.exc_type, sys.exc_value
+	else:
+	    head = open("libxsl.py", "r")
+	    generated = open("libxsltclass.py", "r")
+	    result = open("libxslt.py", "w")
+	    for line in head.readlines():
+		result.write(line)
+	    for line in generated.readlines():
+		result.write(line)
+	    head.close()
+	    generated.close()
+	    result.close()
+	    with_xslt=1
+else:
+    with_xslt=1
+
+
+descr = "libxml2 package"
+modules = [ 'libxml2' ]
+c_files = ['libxml2-py.c', 'libxml.c', 'types.c' ]
+includes= ["/usr/include/libxml2"]
+libs    = ["xml2", "m", "z"]
+macros  = []
+if with_xslt == 1:
+    descr = "libxml2 and libxslt package"
+    #
+    # We are gonna build 2 identical shared libs with merge initializing
+    # both libxml2mod and libxsltmod
+    #
+    c_files = c_files + ['libxslt-py.c', 'libxslt.c']
+    libs.insert(0, 'xslt')
+    includes.append("/usr/include/libxslt")
+    modules.append('libxslt')
+    macros.append(('MERGED_MODULES', '1'))
+
+
+extens=[Extension('libxml2mod', c_files, include_dirs=includes,
+                  libraries=libs, define_macros=macros)] 
+if with_xslt == 1:
+    extens.append(Extension('libxsltmod', c_files, include_dirs=includes,
+			    libraries=libs))
+
+if missing("MANIFEST"):
+    global xml_files
+
+    manifest = open("MANIFEST", "w")
+    manifest.write("setup.py\n")
+    for file in xml_files:
+        manifest.write(file + "\n")
+    if with_xslt == 1:
+	for file in xslt_files:
+	    manifest.write(file + "\n")
+    manifest.close()
+
+setup (name = "libxml2-python",
+       version = "2.4.16",
+       description = descr,
+       author = "Daniel Veillard",
+       author_email = "veillard@redhat.com",
+       url = "http://xmlsoft.org/python.html",
+       licence="MIT Licence",
+
+       py_modules=modules,
+       ext_modules=extens,
+       )
+
+sys.exit(0)
+