Prechádzať zdrojové kódy

Updated to mxml 3.3.1

Brucey 2 rokov pred
rodič
commit
f315b1ff1c
53 zmenil súbory, kde vykonal 8458 pridanie a 2348 odobranie
  1. 20 0
      mxml.mod/mxml/.cppcheck
  2. 39 0
      mxml.mod/mxml/CHANGES.md
  3. 13 0
      mxml.mod/mxml/CODE_OF_CONDUCT.md
  4. 69 44
      mxml.mod/mxml/Makefile.in
  5. 3 3
      mxml.mod/mxml/NOTICE
  6. 44 20
      mxml.mod/mxml/README.md
  7. 121 0
      mxml.mod/mxml/SECURITY.md
  8. 388 311
      mxml.mod/mxml/config.guess
  9. 2 2
      mxml.mod/mxml/config.h.in
  10. 1016 1033
      mxml.mod/mxml/config.sub
  11. 240 333
      mxml.mod/mxml/configure
  12. 295 270
      mxml.mod/mxml/configure.ac
  13. 173 0
      mxml.mod/mxml/doc/body.man
  14. 1134 0
      mxml.mod/mxml/doc/body.md
  15. 4 0
      mxml.mod/mxml/doc/footer.man
  16. BIN
      mxml.mod/mxml/doc/mxml-128.png
  17. BIN
      mxml.mod/mxml/doc/mxml-cover.opacity
  18. BIN
      mxml.mod/mxml/doc/mxml-cover.png
  19. 1364 0
      mxml.mod/mxml/doc/mxml.3
  20. BIN
      mxml.mod/mxml/doc/mxml.epub
  21. 2637 0
      mxml.mod/mxml/doc/mxml.html
  22. BIN
      mxml.mod/mxml/doc/mxml.opacity
  23. BIN
      mxml.mod/mxml/doc/mxml.png
  24. 12 8
      mxml.mod/mxml/install-sh
  25. 75 51
      mxml.mod/mxml/mxml-file.c
  26. 13 14
      mxml.mod/mxml/mxml-index.c
  27. 6 11
      mxml.mod/mxml/mxml-node.c
  28. 8 14
      mxml.mod/mxml/mxml-private.c
  29. 7 2
      mxml.mod/mxml/mxml-private.h
  30. 121 25
      mxml.mod/mxml/mxml-set.c
  31. 8 6
      mxml.mod/mxml/mxml-string.c
  32. 7 3
      mxml.mod/mxml/mxml.h
  33. 2 2
      mxml.mod/mxml/mxml.pc.in
  34. 1 1
      mxml.mod/mxml/mxml.spec
  35. 84 0
      mxml.mod/mxml/test/class.cxx
  36. 47 0
      mxml.mod/mxml/test/dotest.sh
  37. 17 0
      mxml.mod/mxml/test/enum.cxx
  38. 107 0
      mxml.mod/mxml/test/function.cxx
  39. 1 0
      mxml.mod/mxml/test/functype.cxx
  40. 55 0
      mxml.mod/mxml/test/struct.cxx
  41. 3 0
      mxml.mod/mxml/test/type.cxx
  42. 28 26
      mxml.mod/mxml/testmxml.c
  43. 8 3
      mxml.mod/mxml/vcnet/config.h
  44. 30 0
      mxml.mod/mxml/vcnet/libmxml1_native.nuspec
  45. 11 0
      mxml.mod/mxml/vcnet/libmxml1_native.props
  46. 25 0
      mxml.mod/mxml/vcnet/libmxml1_native.redist.nuspec
  47. 8 35
      mxml.mod/mxml/vcnet/mxml.sln
  48. 80 80
      mxml.mod/mxml/vcnet/mxml1.def
  49. 17 17
      mxml.mod/mxml/vcnet/mxml1.vcxproj
  50. 13 13
      mxml.mod/mxml/vcnet/mxmlstat.vcxproj
  51. 17 17
      mxml.mod/mxml/vcnet/testmxml.vcxproj
  52. 74 0
      mxml.mod/mxml/xcode/config.h
  53. 11 4
      mxml.mod/mxml/xcode/mxml.xcodeproj/project.pbxproj

+ 20 - 0
mxml.mod/mxml/.cppcheck

@@ -0,0 +1,20 @@
+// Bad CERT recommendation: C memory layout not determined by variable locations
+cert-API01-C
+
+// Cppcheck doesn't know enough about variables to know whether they are 
+// uninitialized...
+uninitvar
+
+// Don't report non-const casts.  Inline suppression comments are not working,
+// otherwise we'd be more selective...
+cert-EXP05-C
+
+// Not handling "(unsigned)~CONSTANT" properly...
+cert-INT31-c
+
+// fopen_s is NOT supported on POSIX platforms and DOES NOT APPLY for reading
+// of files!
+cert-MSC24-C
+
+// Not sure why this is a thing...
+preprocessorErrorDirective

+ 39 - 0
mxml.mod/mxml/CHANGES.md

@@ -1,3 +1,42 @@
+# Changes in Mini-XML 3.3.2
+
+- Updated the autoconf `config.guess` and `config.sub` scripts to support cross
+  compilation for newer platforms (Issue #296)
+
+
+# Changes in Mini-XML 3.3.1
+
+- Fixed POSIX thread cleanup bugs (Issue #293)
+
+
+# Changes in Mini-XML 3.3
+
+- Cleaned up usage of `free` throughout the library (Issue #276)
+- Added more error handling to the library (Issue #277)
+- Fixed potential memory leak in `mxmlLoad*` functions (Issue #278, Issue #279)
+- Fixed `mxmlSaveString` with a buffer size of 0 (Issue #284)
+- Fixed `MXML_MINOR_VERSION` value in "mxml.h" (Issue #285)
+- Fixed POSIX threading support for MingW (Issue #287)
+- Fixed some minor memory leaks found by Coverity.
+
+
+# Changes in Mini-XML 3.2
+
+- Added support for shared libraries on Haiku (Issue #262)
+- Fixed handling of unquoted attribute values that start with a Unicode
+  character (Issue #264)
+- Fixed handling of elements that start with a Unicode character (Issue #267)
+- Fixed some minor issues identified by the LGTM security scanner.
+
+
+# Changes in Mini-XML 3.1
+
+- The `mxmlLoad*` functions now print an error when the XML does not start with
+  `<` and no parent node is supplied (Issue #256, Issue #259)
+- Fixed an issue with "make install" trying to install old files (Issue #257)
+- Fixed some DSO installation issues on Linux.
+
+
 # Changes in Mini-XML 3.0
 
 - Changed the license to Apache 2.0 with exceptions (Issue #239)

+ 13 - 0
mxml.mod/mxml/CODE_OF_CONDUCT.md

@@ -0,0 +1,13 @@
+Code of Conduct
+===============
+
+My goal is to provide quality open source software that everyone can use.
+While I may not be able to address every request or accept every contribution
+to this project, I will do my best to develop and maintain it for the common
+good.  As part of the open source community, I expect everyone to:
+
+- Be friendly and patient.
+- Be respectful, even if we disagree.
+- Be honest.
+- Be accepting of all people.
+- Fully explain your concerns, issues, or ideas.

+ 69 - 44
mxml.mod/mxml/Makefile.in

@@ -3,7 +3,7 @@
 #
 # https://www.msweet.org/mxml
 #
-# Copyright © 2003-2019 by Michael R Sweet.
+# Copyright © 2003-2021 by Michael R Sweet.
 #
 # Licensed under Apache License v2.0.  See the file "LICENSE" for more
 # information.
@@ -17,20 +17,22 @@ AR		=	@AR@
 ARFLAGS		=	@ARFLAGS@
 ARCHFLAGS	=	@ARCHFLAGS@
 CC		=	@CC@
-CFLAGS		=	$(OPTIM) $(ARCHFLAGS) @CFLAGS@ @CPPFLAGS@ @PTHREAD_FLAGS@
+CFLAGS		=	$(OPTIM) $(ARCHFLAGS) @CFLAGS@ $(CPPFLAGS) $(WARNINGS)
 CP		=	@CP@
+CPPFLAGS	=	@CPPFLAGS@
 DSO		=	@DSO@
 DSOFLAGS	=	@DSOFLAGS@
 LDFLAGS		=	$(OPTIM) $(ARCHFLAGS) @LDFLAGS@
 INSTALL		=	@INSTALL@
 LIBMXML		=	@LIBMXML@
-LIBS		=	@LIBS@ @PTHREAD_LIBS@
+LIBS		=	@LIBS@
 LN		=	@LN@ -s
 MKDIR		=	@MKDIR@
 OPTIM		=	@OPTIM@
 RANLIB		=	@RANLIB@
 RM		=	@RM@ -f
 SHELL		=	/bin/sh
+WARNINGS	=	@WARNINGS@
 
 
 #
@@ -52,10 +54,10 @@ BUILDROOT	=	$(DSTROOT)
 # Install commands...
 #
 
-INSTALL_BIN	=	$(LIBTOOL) $(INSTALL) -m 755
+INSTALL_BIN	=	$(INSTALL) -m 755
 INSTALL_DATA	=	$(INSTALL) -m 644
 INSTALL_DIR	=	$(INSTALL) -d
-INSTALL_LIB	=	$(LIBTOOL) $(INSTALL) -m 755
+INSTALL_LIB	=	$(INSTALL) -m 755
 INSTALL_MAN	=	$(INSTALL) -m 644
 INSTALL_SCRIPT	=	$(INSTALL) -m 755
 
@@ -75,7 +77,8 @@ INSTALL_SCRIPT	=	$(INSTALL) -m 755
 # Targets...
 #
 
-DOCFILES	=	doc/mxml.html doc/mxmldoc.xsd README.md COPYING CHANGES.md
+DOCFILES	=	doc/mxml.epub doc/mxml.html doc/mxml-cover.png \
+			CHANGES.md LICENSE NOTICE README.md
 PUBLIBOBJS	=	mxml-attr.o mxml-entity.o mxml-file.o mxml-get.o \
 			mxml-index.o mxml-node.o mxml-search.o mxml-set.o
 LIBOBJS		=	$(PUBLIBOBJS) mxml-private.o mxml-string.o
@@ -100,10 +103,13 @@ clean:
 	echo Cleaning build files...
 	$(RM) $(OBJS) $(ALLTARGETS)
 	$(RM) mxml1.dll
+	$(RM) mxml1.lib
 	$(RM) libmxml.a
+	$(RM) libmxml.so
+	$(RM) libmxml.so.1
 	$(RM) libmxml.so.1.6
-	$(RM) libmxml.sl.1
 	$(RM) libmxml.1.dylib
+	$(RM) libmxml.dylib
 
 
 #
@@ -113,26 +119,15 @@ clean:
 distclean:	clean
 	echo Cleaning distribution files...
 	$(RM) config.cache config.log config.status
-	$(RM) Makefile config.h
+	$(RM) Makefile config.h mxml.pc
+	$(RM) test.xmlfd
+	$(RM) temp1.xml temp1.xmlfd temp1s.xml
+	$(RM) temp2.xml temp2s.xml
 	$(RM) -r autom4te*.cache
 	$(RM) *.bck *.bak
 	$(RM) -r clang
 
 
-#
-# Run the clang.llvm.org static code analysis tool on the C sources.
-#
-
-.PHONY: clang clang-changes
-clang:
-	echo Doing static code analysis of all code using CLANG...
-	$(RM) -r clang
-	scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) clean all
-clang-changes:
-	echo Doing static code analysis of changed code using CLANG...
-	scan-build -V -k -o `pwd`/clang $(MAKE) $(MFLAGS) all
-
-
 #
 # Install everything...
 #
@@ -167,6 +162,7 @@ install-libmxml.so.1.6:	libmxml.so.1.6
 	$(LN) libmxml.so.1.6 $(BUILDROOT)$(libdir)/libmxml.so
 	$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1
 	$(LN) libmxml.so.1.6 $(BUILDROOT)$(libdir)/libmxml.so.1
+	$(LDCONFIG)
 
 install-libmxml.1.dylib: libmxml.1.dylib
 	echo Installing libmxml.dylib to $(BUILDROOT)$(libdir)...
@@ -198,7 +194,8 @@ uninstall-libmxml.so.1.6:
 	echo Uninstalling libmxml.so from $(BUILDROOT)$(libdir)...
 	$(RM) $(BUILDROOT)$(libdir)/libmxml.so
 	$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1
-	$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1.4
+	$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1.6
+	$(LDCONFIG)
 
 uninstall-libmxml.1.dylib:
 	echo Uninstalling libmxml.dylib from $(BUILDROOT)$(libdir)...
@@ -206,6 +203,34 @@ uninstall-libmxml.1.dylib:
 	$(RM) $(BUILDROOT)$(libdir)/libmxml.1.dylib
 
 
+#
+# Test everything...
+#
+
+test:	testmxml
+	@echo Testing library...
+	./testmxml test.xml temp1s.xml >temp1.xml
+	./testmxml temp1.xml temp2s.xml >temp2.xml
+	@if cmp temp1.xml temp2.xml; then \
+		echo Stdio file test passed!; \
+		$(RM) temp2.xml temp2s.xml; \
+	else \
+		echo Stdio file test failed!; \
+	fi
+	@if cmp temp1.xml temp1s.xml; then \
+		echo String test passed!; \
+		$(RM) temp1.xml temp1s.xml; \
+	else \
+		echo String test failed!; \
+	fi
+	@if cmp test.xml test.xmlfd; then \
+		echo File descriptor test passed!; \
+		$(RM) test.xmlfd temp1.xmlfd; \
+	else \
+		echo File descriptor test failed!; \
+	fi
+
+
 #
 # Figure out lines-of-code...
 #
@@ -275,27 +300,6 @@ libmxml.1.dylib:	$(LIBOBJS)
 testmxml:	libmxml.a testmxml.o
 	echo Linking $@...
 	$(CC) $(LDFLAGS) -o $@ testmxml.o libmxml.a $(LIBS)
-	@echo Testing library...
-	./testmxml test.xml temp1s.xml >temp1.xml
-	./testmxml temp1.xml temp2s.xml >temp2.xml
-	@if cmp temp1.xml temp2.xml; then \
-		echo Stdio file test passed!; \
-		$(RM) temp2.xml temp2s.xml; \
-	else \
-		echo Stdio file test failed!; \
-	fi
-	@if cmp temp1.xml temp1s.xml; then \
-		echo String test passed!; \
-		$(RM) temp1.xml temp1s.xml; \
-	else \
-		echo String test failed!; \
-	fi
-	@if cmp test.xml test.xmlfd; then \
-		echo File descriptor test passed!; \
-		$(RM) test.xmlfd; \
-	else \
-		echo File descriptor test failed!; \
-	fi
 
 testmxml-vg:	$(LIBOBJS) testmxml.o
 	echo Linking $@...
@@ -304,6 +308,27 @@ testmxml-vg:	$(LIBOBJS) testmxml.o
 testmxml.o:	mxml.h
 
 
+#
+# Analyze code with the Clang static analyzer <https://clang-analyzer.llvm.org>
+#
+
+.PHONY: clang
+clang:
+	clang $(CPPFLAGS) --analyze $(OBJS:.o=.c) 2>clang.log
+	rm -rf $(OBJS:.o=.plist)
+	test -s clang.log && (echo "$(GHA_ERROR)Clang detected issues."; echo ""; cat clang.log; exit 1) || exit 0
+
+
+#
+# Analyze code using Cppcheck <http://cppcheck.sourceforge.net>
+#
+
+.PHONY: cppcheck
+cppcheck:
+	cppcheck $(CPPFLAGS) --template=gcc --addon=cert.py --suppressions-list=.cppcheck $(OBJS:.o=.c) 2>cppcheck.log
+	test -s cppcheck.log && (echo "$(GHA_ERROR)Cppcheck detected issues."; echo ""; cat cppcheck.log; exit 1) || exit 0
+
+
 #
 # Documentation (depends on separate codedoc utility)
 #

+ 3 - 3
mxml.mod/mxml/NOTICE

@@ -1,10 +1,10 @@
 Mini-XML
 
-Copyright © 2003-2019 by Michael R Sweet
+Copyright © 2003-2022 by Michael R Sweet
 
 
-Exceptions to the Apache 2.0 License:
-=====================================
+(Optional) Exceptions to the Apache 2.0 License:
+================================================
 
 In addition, if you combine or link compiled forms of this Software with
 software that is licensed under the GPLv2 or LGPLv2 (“Combined Software”) and if

+ 44 - 20
mxml.mod/mxml/README.md

@@ -1,4 +1,12 @@
-# Mini-XML Version 3.0
+Mini-XML - Tiny XML Parsing Library
+===================================
+
+![Version](https://img.shields.io/github/v/release/michaelrsweet/mxml?include_prereleases)
+![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/mxml)
+![Build](https://github.com/michaelrsweet/mxml/workflows/Build/badge.svg)
+[![Coverity Scan Status](https://img.shields.io/coverity/scan/23959.svg)](https://scan.coverity.com/projects/michaelrsweet-mxml)
+[![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/michaelrsweet/mxml)](https://lgtm.com/projects/g/michaelrsweet/mxml/context:cpp)
+[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/michaelrsweet/mxml)](https://lgtm.com/projects/g/michaelrsweet/mxml/)
 
 Mini-XML is a small XML parsing library that you can use to read XML data files
 or strings in your application without requiring large non-standard libraries.
@@ -21,8 +29,13 @@ Mini-XML provides the following functionality:
 Mini-XML doesn't do validation or other types of processing on the data
 based upon schema files or other sources of definition information.
 
+> Note: Version 3.0 hides the definition of the `mxml_node_t` structure,
+> requiring the use of the various accessor functions that were introduced in
+> version 2.0.
+
 
-## Building Mini-XML
+Building Mini-XML
+-----------------
 
 Mini-XML comes with an autoconf-based configure script; just type the
 following command to get things going:
@@ -59,22 +72,23 @@ Once you have installed it, use the `-lmxml` option to link your application
 against it.
 
 
-## Documentation
+Documentation
+-------------
 
 The documentation is available in the `doc` subdirectory in the files
-`mxml.html` (HTML) and `mxml.pdf` (PDF). You can also look at the
-`testmxml.c` and `mxmldoc.c` source files for examples of using Mini-XML.
+`mxml.html` (HTML) and `mxml.epub` (EPUB).  You can also look at the
+`testmxml.c` source file for examples of using Mini-XML.
 
 Mini-XML provides a single header file which you include:
 
     #include <mxml.h>
 
-Nodes are defined by the `mxml_node_t` structure; the `type` member defines the
-node type (`element`, `integer`, `opaque`, `real`, or `text`) which determines
-which value you want to look at in the `value` union.  New nodes can be created
-using the `mxmlNewElement()`, `mxmlNewInteger()`, `mxmlNewOpaque()`,
-`mxmlNewReal()`, and `mxmlNewText()` functions.  Only elements can have child
-nodes, and the top node must be an element, usually "?xml".
+Nodes (elements, comments, processing directives, integers, opaque strings, real
+numbers, and text strings) are represented by `mxml_node_t` objects.  New nodes
+can be created using the `mxmlNewElement()`, `mxmlNewInteger()`,
+`mxmlNewOpaque()`, `mxmlNewReal()`, and `mxmlNewText()` functions.  Only
+elements can have child nodes, and the top node must be the "?xml" processing
+directive.
 
 You load an XML file using the `mxmlLoadFile()` function:
 
@@ -155,7 +169,7 @@ element using an XPath:
     mxml_node_t *value = mxmlFindPath(tree, "path/to/*/foo/bar");
 
 The `mxmlGetInteger()`, `mxmlGetOpaque()`, `mxmlGetReal()`, and
-`mxmlGetText()` functions retrieve the value from a node:
+`mxmlGetText()` functions retrieve the corresponding value from a node:
 
     mxml_node_t *node;
 
@@ -175,17 +189,27 @@ or the entire tree:
     mxmlDelete(tree);
 
 
-## Getting Help And Reporting Problems
-
-The Mini-XML project page provides access to the Github issue tracking page:
+Getting Help And Reporting Problems
+-----------------------------------
 
-    https://www.msweet.org/mxml
+The [Mini-XML project page](https://www.msweet.org/mxml) provides access to the
+current version of this software, documentation, and Github issue tracking page.
 
 
-## Legal Stuff
+Legal Stuff
+-----------
 
-Copyright © 2003-2019 by Michael R Sweet
+Copyright © 2003-2022 by Michael R Sweet
 
 The Mini-XML library is licensed under the Apache License Version 2.0 with an
-exception to allow linking against GPL2/LGPL2-only software.  See the files
-"LICENSE" and "NOTICE" for more information.
+*optional* exception to allow linking against GPL2/LGPL2-only software.  See the
+files "LICENSE" and "NOTICE" for more information.
+
+> Note: The exception listed in the NOTICE file only applies when linking
+> against GPL2/LGPL2-only software.  Some Apache License purists have objected
+> to linking Apache Licensed code against Mini-XML with these exceptions on the
+> grounds that it makes Mini-XML somehow incompatible with the Apache License.
+> For that reason, people wishing to retain their Apache License purity may
+> omit the exception from their copy of Mini-XML.
+
+> Note 2: IANAL, but I am beginning to dislike them!

+ 121 - 0
mxml.mod/mxml/SECURITY.md

@@ -0,0 +1,121 @@
+Security Policy
+===============
+
+This file describes how security issues are reported and handled, and what the
+expectations are for security issues reported to this project.
+
+
+Responsible Disclosure
+----------------------
+
+With *responsible disclosure*, a security issue (and its fix) is disclosed only
+after a mutually-agreed period of time (the "embargo date").  The issue and fix
+are shared amongst and reviewed by the key stakeholders (Linux distributions,
+OS vendors, etc.) and the CERT/CC.  Fixes are released to the public on the
+agreed-upon date.
+
+> Responsible disclosure applies only to production releases.  A security
+> vulnerability that only affects unreleased code can be fixed immediately
+> without coordination.  Vendors *should not* package and release unstable
+> snapshots, beta releases, or release candidates of this software.
+
+
+Supported Versions
+------------------
+
+All production releases of this software are subject to this security policy.  A
+production release is tagged and given a semantic version number of the form:
+
+    MAJOR.MINOR.PATCH
+
+where "MAJOR" is an integer starting at 1 and "MINOR" and "PATCH" are integers
+starting at 0.  A feature release has a "PATCH" value of 0, for example:
+
+    1.0.0
+    1.1.0
+    2.0.0
+
+Beta releases and release candidates are *not* prodution releases and use
+semantic version numbers of the form:
+
+    MAJOR.MINORbNUMBER
+    MAJOR.MINORrcNUMBER
+
+where "MAJOR" and "MINOR" identify the new feature release version number and
+"NUMBER" identifies a beta or release candidate number starting at 1, for
+example:
+
+    1.0b1
+    1.0b2
+    1.0rc1
+
+
+Reporting a Vulnerability
+-------------------------
+
+Report all security issues to "security AT msweet.org".  Expect a response
+within 5 business days.  Any proposed embargo date should be at least 30 days
+and no more than 90 days in the future.
+
+
+PGP Public Key
+--------------
+
+The following PGP public key can be used for signing security messages.
+
+```
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: GPGTools - https://gpgtools.org
+
+mQINBF6L0RgBEAC8FTqc/1Al+pWW+ULE0OB2qdbiA2NBjEm0X0WhvpjkqihS1Oih
+ij3fzFxKJ+DgutQyDb4QFD8tCFL0f0rtNL1Iz8TtiAJjvlhL4kG5cdq5HYEchO10
+qFeZ1DqvnHXB4pbKouEQ7Q/FqB1PG+m6y2q1ntgW+VPKm/nFUWBCmhTQicY3FOEG
+q9r90enc8vhQGOX4p01KR0+izI/g+97pWgMMj5N4zHuXV/GrPhlVgo3Wn1OfEuX4
+9vmv7GX4G17Me3E3LOo0c6fmPHJsrRG5oifLpvEJXVZW/RhJR3/pKMPSI5gW8Sal
+lKAkNeV7aZG3U0DCiIVL6E4FrqXP4PPj1KBixtxOHqzQW8EJwuqbszNN3vp9w6jM
+GvGtl8w5Qrw/BwnGC6Dmw+Qv04p9JRY2lygzZYcKuwZbLzBdC2CYy7P2shoKiymX
+ARv+i+bUl6OmtDe2aYaqRkNDgJkpuVInBlMHwOyLP6fN2o7ETXQZ+0a1vQsgjmD+
+Mngkc44HRnzsIJ3Ga4WwW8ggnAwUzJ/DgJFYOSbRUF/djBT4/EFoU+/kjXRqq8/d
+c8HjZtz2L27njmMw68/bYmY1TliLp50PXGzJA/KeY90stwKtTI0ufwAyi9i9BaYq
+cGbdq5jnfSNMDdKW2kLCNTQeUWSSytMTsdU0Av3Jrv5KQF8x5GaXcpCOTwARAQAB
+tExNaWNoYWVsIFN3ZWV0IChzZWN1cml0eUBtc3dlZXQub3JnKSAoU2VjdXJpdHkg
+UEdQIEtleSkgPHNlY3VyaXR5QG1zd2VldC5vcmc+iQJUBBMBCgA+FiEEOElfSXYU
+h91AF0sBpZiItz2feQIFAl6L0RgCGwMFCQeGH4AFCwkIBwMFFQoJCAsFFgIDAQAC
+HgECF4AACgkQpZiItz2feQIhjhAAqZHuQJkPBsAKUvJtPiyunpR6JENTUIDxnVXG
+nue+Zev+B7PzQ7C4CAx7vXwuWTt/BXoyQFKRUrm+YGiBTvLYQ8fPqudDnycSaf/A
+n01Ushdlhyg1wmCBGHTgt29IkEZphNj6BebRd675RTOSD5y14jrqUb+gxRNuNDa5
+ZiZBlBE4A8TV6nvlCyLP5oXyTvKQRFCh4dEiL5ZvpoxnhNvJpSe1ohL8iJ9aeAd5
+JdakOKi8MmidRPYC5IldXwduW7VC7dtqSiPqT5aSN0GJ8nIhSpn/ZkOEAPHAtxxa
+0VgjltXwUDktu74MUUghdg2vC1df2Z+PqHLsGEqOmxoBIJYXroIqSEpO3Ma7hz0r
+Xg1AWHMR/xxiLXLxgaZRvTp7AlaNjbqww8JDG8g+nDIeGsgIwWN/6uPczledvDQa
+HtlMfN97i+rt6sCu13UMZHpBKOGg7eAGRhgpOwpUqmlW1b+ojRHGkmZ8oJSE7sFT
+gzSGNkmfVgA1ILl0mi8OBVZ4jlUg6EgVsiPlzolH92iscK7g50PdjzpQe0m3gmcL
+dpOmSL8Fti05dPfamJzIvJd28kMZ6yMnACKj9rq/VpfgYBLK8dbNUjEOQ2oq7PyR
+Ye/LE1OmAJwfZQkyQNI8yAFXoRJ8u3/bRb3SPvGGWquGBDKHv2K1XiCW65uyLe5B
+RNJWmme5Ag0EXovRGAEQAJZMFeIMt/ocLskrp89ZyBTTiavFKn9+QW7C2Mb36A73
+J2g9vRFBSRizb+t8lSzP/T1GbKS0cEmfEpQppWImTbOMV6ZgxrM0IUy1Yd7Kyc0K
+oNMZvykRYwVMzxB5hiQ88kCLfqTNCveIvu1xcB9pWkf+cuDmGCxA3I+yc3Eh/SOP
+urDsHObt7fyEmJpSxCXlMFHRCuWyGXhMNvhR186t9mANW0PyxKJ8efr+2Vhm1+pA
+Vk9JESac/lREvx9PVFmlPdqgqRkQ0TQB5+ROo9Wy77cxQr5+rvSZZff630I1YgZf
+Ph6xOV1/q6vJ3RBNA2nPSTjPeeWQ7pTn7PZGJwCjIUjhMbO+EJVKUJNOAEg033mG
+tLfbFUYdhA/dRgFuKz90loCMfsnf3e4o/TFydSHUuwBUtOWkL1BBWEbk95M/Zr00
+w5fD9knas1u5Lc4ogXzTFPnvJ6hM1RAFJEd+FYzJZIvzwrIx4Ag1DOKViVBpeLTu
+HWj+xckEgvxEBglplALzfSIJ0CLQSNL8iMFbzCnPeUoQfPkqu37KHrB9syAA06Tb
+qw1Ax0qBqKInGIgBd0w6dFLF3s04xVcPAXWyJ0w4I7h2bs+aD6YwwK6xxCtXxtN5
+Q1LQM8s3tKNXER3mZ8zfwgwjsdLVwhXhysFi6Dlkvk/Vrbn1QDfJnzq+F9LsGRGb
+ABEBAAGJAjwEGAEKACYWIQQ4SV9JdhSH3UAXSwGlmIi3PZ95AgUCXovRGAIbDAUJ
+B4YfgAAKCRClmIi3PZ95AhDZD/40fShzDS/smZZL0oXN4GgZ62FrXWBdLjontkXo
+d8hDh1wJZwqsLVbtO2Gu0CPeH9GclQ3bYsR19sGMM4FDgjMu57O/TU6GZl2Ywcjh
+ayhRTHyAq/BKZn71AM0N7LS8MdNTaLbTbzEu5oGbAmOVv5f0SUnQoGxbeF8ih5bo
+hR3ZcORujWMgnymL3+cerNyIDQAtfMAUTfpVcwem4CvquA9Wjtur8YN1t+N7I3o2
+eMTNSyNUL9Yx3NxbyJ0yrrMvASo+ZVRaPW5+ET9Iqd68ILSY04Gnar3URJssggX8
++cuyEbP9bAG8qYqcr2aSC2dW84mL/RnZGR//1dfS0Ugk6Osj0LSF5i+mz0CbIjYQ
+PKgLlgpycuGZBC5kG3RWWfanM0HxPDx10a7vEWA1A5Q+csx4yi3CW/giC1zAdhUO
+cJ1l4Uj/oxpGeLN7BnT/2NzU/px2fpbaG+xU4HlwjzFM2cIOUIohHFhdvFZbFIIA
+mePqTBnEB3HtXYRTgMoYDXLWhlOXjyVnMR45WDfvEA3KqbAz6sNMtaOJ6rHBWnR1
+1YbpvDWUeaGSLXBoGyo3RgTrN9jON8lE/oUxFobnEdfZGD+uwIniylc5rw3+VkBU
++QGZDfgPgxjSmKsWq1cK6rNfBacGYrdyqf90VemEsvR8r0Ump0RPzBMlAAq0Xkup
+WkiKlA==
+=0GzT
+-----END PGP PUBLIC KEY BLOCK-----
+```

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 388 - 311
mxml.mod/mxml/config.guess


+ 2 - 2
mxml.mod/mxml/config.h.in

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2020 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -38,7 +38,7 @@
  * Long long support...
  */
 
-#undef HAVE_LONG_LONG
+#undef HAVE_LONG_LONG_INT
 
 
 /*

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1016 - 1033
mxml.mod/mxml/config.sub


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 240 - 333
mxml.mod/mxml/configure


+ 295 - 270
mxml.mod/mxml/configure.ac

@@ -1,346 +1,371 @@
 dnl
-dnl Configuration script for Mini-XML, a small XML-like file parsing library.
+dnl Configuration script for Mini-XML, a small XML file parsing library.
 dnl
 dnl https://www.msweet.org/mxml
 dnl
-dnl Copyright © 2003-2019 by Michael R Sweet.
+dnl Copyright © 2003-2022 by Michael R Sweet.
 dnl
 dnl Licensed under Apache License v2.0.  See the file "LICENSE" for more
 dnl information.
 dnl
 
+dnl We need at least autoconf 2.70 for --runstatedir...
+AC_PREREQ([2.70])
+
+
 dnl Package name and version...
-AC_INIT([Mini-XML], [3.0], [https://github.com/michaelrsweet/mxml/issues], [mxml], [https://michaelrsweet.github.io/mxml])
+AC_INIT([Mini-XML], [3.3.1], [https://github.com/michaelrsweet/mxml/issues], [mxml], [https://www.msweet.org/mxml])
+
 
 dnl This line is provided to ensure that you don't run the autoheader program
 dnl against this project.  Doing so is completely unsupported and WILL cause
 dnl problems!
 AH_TOP([#error "Somebody ran autoheader on this project which is unsupported and WILL cause problems."])
 
+
 dnl Get the build and host platforms and split the host_os value
 AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
 
 [host_os_name=`echo $host_os | sed -e '1,$s/[0-9.]*$//g'`]
-[host_os_version=`echo $host_os | sed -e '1,$s/^[^0-9.]*//g'`]
+[host_os_version="$(echo $host_os | sed -e '1,$s/^[^0-9.]*//g' | awk -F. '{print $1 $2}')"]
+# Linux often does not yield an OS version we can use...
+AS_IF([test "x$host_os_version" = x], [
+    host_os_version="0"
+])
+
 
 dnl Set the name of the config header file...
-AC_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS([config.h])
+
 
 dnl Version number...
 VERSION="AC_PACKAGE_VERSION"
 AC_SUBST(VERSION)
 AC_DEFINE_UNQUOTED(MXML_VERSION, "Mini-XML v$VERSION")
 
+
 dnl Clear default debugging options and set normal optimization by
 dnl default unless the user asks for debugging specifically.
 CFLAGS="${CFLAGS:=}"
-CXXFLAGS="${CXXFLAGS:=}"
+CPPFLAGS="${CPPFLAGS:=}"
 LDFLAGS="${LDFLAGS:=}"
-AC_SUBST(LDFLAGS)
-
-AC_ARG_WITH(ansi, [  --with-ansi             set full ANSI C mode, default=no],
-	use_ansi="$withval",
-	use_ansi="no")
-
-AC_ARG_WITH(archflags, [  --with-archflags        set additional architecture flags, default=none],
-	ARCHFLAGS="$withval",
-	ARCHFLAGS="")
-AC_SUBST(ARCHFLAGS)
-
-AC_ARG_WITH(optim,   [  --with-optim            set additional optimization flags, default=none],
-	OPTIM="$withval",
-	OPTIM="")
-AC_SUBST(OPTIM)
-
-AC_ARG_ENABLE(debug, [  --enable-debug          turn on debugging, default=no],
-if eval "test x$enable_debug = xyes"; then
- 	OPTIM="$OPTIM -g"
-fi)
-
-AC_ARG_WITH(docdir, [  --with-docdir           set directory for documentation, default=${prefix}/share/doc/mxml],
-	docdir="$withval",
-	docdir="NONE")
-
+AC_SUBST([LDFLAGS])
+LIBS="${LIBS:=}"
+
+
+dnl Options...
+AC_ARG_WITH([ansi], AS_HELP_STRING([--with-ansi], [set full ANSI C mode, default=no]), [
+    use_ansi="$withval"
+], [
+    use_ansi="no"
+])
+
+AC_ARG_WITH([archflags], AS_HELP_STRING([--with-archflags], [set additional architecture flags, default=none]), [
+    ARCHFLAGS="$withval"
+], [
+    AS_CASE(["$host_os_name"], [darwin*], [
+        AS_IF([test "$host_os_version" -ge 200 -a x$enable_debug != xyes], [
+            # macOS 11.0 and higher support the Apple Silicon (arm64) CPUs
+	    ARCHFLAGS="-mmacosx-version-min=10.14 -arch x86_64 -arch arm64"
+	], [test x$enable_debug != xyes], [
+	    ARCHFLAGS="-mmacosx-version-min=10.14 -arch x86_64"
+	])
+    ], [*], [
+	ARCHFLAGS=""
+    ])
+])
+AC_SUBST([ARCHFLAGS])
+
+AC_ARG_WITH([optim], AS_HELP_STRING([--with-optim], [set additional optimization flags, default=none]), [
+    OPTIM="$withval"
+], [
+    OPTIM=""
+])
+AC_SUBST([OPTIM])
+
+AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [turn on debugging, default=no]))
+AC_ARG_ENABLE([maintainer], AS_HELP_STRING([--enable-maintainer], [turn on maintainer mode, default=no]))
+AC_ARG_ENABLE([sanitizer], AS_HELP_STRING([--enable-sanitizer], [build with AddressSanitizer, default=no]))
+
+AC_ARG_WITH([docdir], AS_HELP_STRING([--with-docdir], [set directory for documentation, default=${prefix}/share/doc/mxml]), [
+    docdir="$withval"
+], [
+    docdir="NONE"
+])
 AC_SUBST(docdir)
 
-AC_ARG_WITH(vsnprintf, [  --with-vsnprintf        use vsnprintf emulation functions, default=auto],
-	use_vsnprintf="$withval",
-	use_vsnprintf="no")
+AC_ARG_WITH([vsnprintf], AS_HELP_STRING([--with-vsnprintf], [use vsnprintf emulation functions, default=auto]), [
+    use_vsnprintf="$withval"
+], [
+    use_vsnprintf="no"
+])
+
 
 dnl Checks for programs...
 AC_PROG_CC
 AC_PROG_CXX
 AC_PROG_INSTALL
-if test "$INSTALL" = "$ac_install_sh"; then
-	# Use full path to install-sh script...
-	INSTALL="`pwd`/install-sh -c"
-fi
+AS_IF([test "$INSTALL" = "$ac_install_sh"], [
+    # Use full path to install-sh script...
+    INSTALL="`pwd`/install-sh -c"
+])
 AC_PROG_RANLIB
 AC_CHECK_TOOL(AR,ar)
 AC_PATH_PROG(CP,cp)
+AC_PATH_PROGS(LDCONFIG,ldconfig false)
 AC_PATH_PROG(LN,ln)
 AC_PATH_PROG(MKDIR,mkdir)
 AC_PATH_PROG(RM,rm)
 
-dnl Flags for "ar" command...
-case "$host_os_name" in
-        darwin* | *bsd)
-                ARFLAGS="-rcv"
-                ;;
-        *)
-                ARFLAGS="crvs"
-                ;;
-esac
 
+dnl Flags for "ar" command...
+AS_CASE(["$host_os_name"], [darwin* | *bsd], [
+    ARFLAGS="-rcv"
+], [*], [
+    ARFLAGS="crvs"
+])
 AC_SUBST(ARFLAGS)
 
+
 dnl Inline functions...
 AC_C_INLINE
 
+
 dnl Checks for string functions.
-if test "x$use_ansi" != xyes; then
-	AC_CHECK_FUNCS(strdup strlcat strlcpy)
-fi
+AS_IF([test "x$use_ansi" != xyes], [
+    AC_CHECK_FUNCS([strdup strlcat strlcpy])
+])
+
+AS_IF([test "x$use_vsnprintf" != xyes], [
+    AC_CHECK_FUNCS([snprintf vasprintf vsnprintf])
+])
 
-if test "x$use_vsnprintf" != xyes; then
-	AC_CHECK_FUNCS(snprintf vasprintf vsnprintf)
-fi
 
 dnl Check for "long long" support...
-AC_CACHE_CHECK(for long long int, ac_cv_c_long_long,
-	[if test "$GCC" = yes; then
-		ac_cv_c_long_long=yes
-	else
-		AC_TRY_COMPILE(,[long long int i;],
-			ac_cv_c_long_long=yes,
-			ac_cv_c_long_long=no)
-	fi])
-
-if test $ac_cv_c_long_long = yes; then
-	AC_DEFINE(HAVE_LONG_LONG)
-fi
+AC_TYPE_LONG_LONG_INT
+
 
 dnl Threading support
-AC_ARG_ENABLE(threads, [  --enable-threads        enable multi-threading support])
+AC_ARG_ENABLE([threads], AS_HELP_STRING([--disable-threads], [disable multi-threading support, default=no]))
 
 have_pthread=no
-PTHREAD_FLAGS=""
-PTHREAD_LIBS=""
-
-if test "x$enable_threads" != xno; then
-	AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H))
-
-	if test x$ac_cv_header_pthread_h = xyes; then
-		dnl Check various threading options for the platforms we support
-		for flag in -lpthreads -lpthread -pthread; do
-        		AC_MSG_CHECKING([for pthread_create using $flag])
-			SAVELIBS="$LIBS"
-			LIBS="$flag $LIBS"
-        		AC_TRY_LINK([#include <pthread.h>],
-				[pthread_create(0, 0, 0, 0);],
-        			have_pthread=yes)
-        		AC_MSG_RESULT([$have_pthread])
-			LIBS="$SAVELIBS"
-
-			if test $have_pthread = yes; then
-				PTHREAD_FLAGS="-D_THREAD_SAFE -D_REENTRANT"
-				PTHREAD_LIBS="$flag"
-
-				# Solaris requires -D_POSIX_PTHREAD_SEMANTICS to
-				# be POSIX-compliant... :(
-				case "$host_os_name" in
-					sunos)
-					PTHREAD_FLAGS="$PTHREAD_FLAGS -D_POSIX_PTHREAD_SEMANTICS"
-					;;
-				esac
-				break
-			fi
-		done
-	fi
-fi
-
-AC_SUBST(PTHREAD_FLAGS)
-AC_SUBST(PTHREAD_LIBS)
+AS_IF([test "x$enable_threads" != xno], [
+    AC_CHECK_HEADER([pthread.h], [
+        AC_DEFINE([HAVE_PTHREAD_H], [Have <pthread.h>?])
+    ])
+
+    AS_IF([test x$ac_cv_header_pthread_h = xyes], [
+	dnl Check various threading options for the platforms we support
+	for flag in -lpthreads -lpthread -pthread; do
+	    AC_MSG_CHECKING([for pthread_create using $flag])
+	    SAVELIBS="$LIBS"
+	    LIBS="$flag $LIBS"
+	    AC_LANG([C])
+	    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],[pthread_create(0, 0, 0, 0);])], [
+		have_pthread=yes
+	    ], [
+		LIBS="$SAVELIBS"
+	    ])
+
+	    AS_IF([test x$have_pthread = xyes], [
+		AC_MSG_RESULT([yes])
+		CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE -D_REENTRANT"
+		break
+	    ], [
+		AC_MSG_RESULT([no])
+	    ])
+	done
+    ])
+])
+
 
 dnl Shared library support...
 DSO="${DSO:=:}"
 DSOFLAGS="${DSOFLAGS:=}"
 
-AC_ARG_ENABLE(shared, [  --enable-shared         turn on shared libraries, default=no])
-
-if test x$enable_shared != xno; then
-	AC_MSG_CHECKING(for shared library support)
-	PICFLAG=1
-
-	case "$host_os_name" in
-		sunos | unix_s)
-			AC_MSG_RESULT(yes)
-			LIBMXML="libmxml.so.1.6"
-			DSO="\$(CC)"
-			DSOFLAGS="$DSOFLAGS -Wl,-h,libmxml.so.1 -G -R\$(libdir) \$(OPTIM)"
-			LDFLAGS="$LDFLAGS -R\$(libdir)"
-                	;;
-
-		linux*)
-			AC_MSG_RESULT(yes)
-			LIBMXML="libmxml.so.1.6"
-			DSO="\$(CC)"
-			DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1 -shared \$(OPTIM)"
-			;;
-
-		osf | gnu)
-			AC_MSG_RESULT(yes)
-			LIBMXML="libmxml.so.1.6"
-			DSO="\$(CC)"
-			DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-rpath,\$(libdir) -shared \$(OPTIM)"
-                        LDFLAGS="$LDFLAGS -Wl,-rpath,\$(libdir)"
-			;;
-
-		*bsd)
-			AC_MSG_RESULT(yes)
-			LIBMXML="libmxml.so.1.6"
-			DSO="\$(CC)"
-			DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-R\$(libdir) -shared \$(OPTIM)"
-			LDFLAGS="$LDFLAGS -Wl,-R\$(libdir)"
-                        ;;
-
-		darwin)
-			AC_MSG_RESULT(yes)
-			LIBMXML="libmxml.1.dylib"
-			DSO="\$(CC)"
-			DSOFLAGS="$DSOFLAGS \$(RC_CFLAGS) -dynamiclib -lc"
-			;;
-
-                mingw)
-                        AC_MSG_RESULT(yes)
-                        LIBMXML="mxml1.dll"
-                        DSO="\$(CC)"
-                        DSOFLAGS="$DSOFLAGS -shared -Wl,--out-implib,libmxml1.a,--no-undefined,--enable-runtime-pseudo-reloc"
-                        ;;
-
-		*)
-			AC_MSG_RESULT(no)
-			AC_MSG_WARN(shared libraries not supported on this platform.)
-			PICFLAG=0
-			LIBMXML="libmxml.a"
-			;;
-	esac
-else
+AC_ARG_ENABLE([shared], AS_HELP_STRING([--disable-shared], [turn off shared libraries, default=no]))
+
+AS_IF([test x$enable_shared != xno], [
+    AC_MSG_CHECKING([for shared library support])
+    PICFLAG=1
+
+    AS_CASE(["$host_os_name"], [sunos | unix_s], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="libmxml.so.1.6"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS -Wl,-h,libmxml.so.1 -G -R\$(libdir) \$(OPTIM)"
+	LDFLAGS="$LDFLAGS -R\$(libdir)"
+    ], [linux*], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="libmxml.so.1.6"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1 -shared \$(OPTIM)"
+    ], [osf | gnu], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="libmxml.so.1.6"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-rpath,\$(libdir) -shared \$(OPTIM)"
+	LDFLAGS="$LDFLAGS -Wl,-rpath,\$(libdir)"
+    ], [*bsd | haiku*], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="libmxml.so.1.6"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-R\$(libdir) -shared \$(OPTIM)"
+	LDFLAGS="$LDFLAGS -Wl,-R\$(libdir)"
+    ], [darwin], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="libmxml.1.dylib"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS \$(RC_CFLAGS) -dynamiclib -lc"
+    ], [mingw], [
+	AC_MSG_RESULT([yes])
+	LIBMXML="mxml1.dll"
+	DSO="\$(CC)"
+	DSOFLAGS="$DSOFLAGS -shared -Wl,--out-implib,libmxml1.a,--no-undefined,--enable-runtime-pseudo-reloc"
+    ], [*], [
+	AC_MSG_RESULT([no])
+	AC_MSG_WARN([shared libraries not supported on this platform.])
 	PICFLAG=0
 	LIBMXML="libmxml.a"
-fi
-
-AC_SUBST(DSO)
-AC_SUBST(DSOFLAGS)
-AC_SUBST(LIBMXML)
-AC_SUBST(PICFLAG)
-
-dnl Add -Wall for GCC...
-if test -n "$GCC"; then
-	CFLAGS="-Wall -D_GNU_SOURCE $CFLAGS"
-
-	if test "x$OPTIM" = x; then
-		OPTIM="-Os -g"
-	fi
-
-	if test "x$use_ansi" = xyes; then
-		CFLAGS="-ansi -pedantic $CFLAGS"
-	fi
-
-	if test $PICFLAG = 1 -a "$host_os_name" != aix; then
-    		OPTIM="-fPIC $OPTIM"
-	fi
-else
-	case "$host_os_name" in
-		hp-ux)
-			CFLAGS="-Ae $CFLAGS"
-
-			if test "x$OPTIM" = x; then
-				OPTIM="-O"
-			fi
-
-			OPTIM="+DAportable $OPTIM"
-
-			if test $PICFLAG = 1; then
-				OPTIM="+z $OPTIM"
-			fi
-			;;
-
-		unix_svr | sunos)
-			if test "x$OPTIM" = x; then
-				OPTIM="-O"
-			fi
-
-			if test $PICFLAG = 1; then
-				OPTIM="-KPIC $OPTIM"
-			fi
-			;;
-
-		*)
-			if test "x$OPTIM" = x; then
-				OPTIM="-O"
-			fi
-			;;
-	esac
-fi
+    ])
+], [
+    PICFLAG=0
+    LIBMXML="libmxml.a"
+])
+
+AC_SUBST([DSO])
+AC_SUBST([DSOFLAGS])
+AC_SUBST([LIBMXML])
+AC_SUBST([PICFLAG])
+
+
+dnl Compiler options...
+WARNINGS=""
+AC_SUBST([WARNINGS])
+
+AS_IF([test -n "$GCC"], [
+    CFLAGS="-D_GNU_SOURCE $CFLAGS"
+
+    AS_IF([test "x$OPTIM" = x], [
+	AS_IF([test x$enable_debug = xyes], [
+	    OPTIM="-g"
+	], [
+	    OPTIM="-g -Os"
+	])
+    ], [test x$enable_debug = xyes], [
+	OPTIM="$OPTIM -g"
+    ])
+
+    AS_IF([test x$enable_sanitizer = xyes], [
+	# Use -fsanitize=address with debugging...
+	OPTIM="$OPTIM -fsanitize=address"
+    ], [
+	# Otherwise use the Fortify enhancements to catch any unbounded
+	# string operations...
+	CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2"
+    ])
+
+    AS_IF([test "x$use_ansi" = xyes], [
+	CFLAGS="-ansi -pedantic $CFLAGS"
+    ])
+
+    dnl Show all standard warnings + unused variables when compiling...
+    WARNINGS="-Wall -Wunused"
+
+    dnl Drop some not-useful/unreliable warnings...
+    for warning in char-subscripts format-truncation format-y2k switch unused-result; do
+	AC_MSG_CHECKING([whether compiler supports -Wno-$warning])
+
+	OLDCFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -Wno-$warning -Werror"
+
+	AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [
+	    AC_MSG_RESULT(yes)
+	    WARNINGS="$WARNINGS -Wno-$warning"
+        ], [
+	    AC_MSG_RESULT(no)
+	])
+
+	CFLAGS="$OLDCFLAGS"
+    done
+
+    dnl Maintainer mode enables -Werror...
+    AS_IF([test x$enable_maintainer = xyes], [
+	WARNINGS="$WARNINGS -Werror"
+    ])
+
+    AS_IF([test $PICFLAG = 1 -a "$host_os_name" != aix], [
+	OPTIM="-fPIC $OPTIM"
+    ])
+], [
+    AS_IF([test "x$OPTIM" = x], [
+	AS_IF([test x$enable_debug = xyes], [
+	    OPTIM="-g"
+	], [
+	    OPTIM="-O"
+	])
+    ])
+
+    AS_CASE(["$host_os_name"], [hp-ux], [
+	CFLAGS="-Ae $CFLAGS"
+
+	OPTIM="+DAportable $OPTIM"
+
+	AS_IF([test $PICFLAG = 1], [
+	    OPTIM="+z $OPTIM"
+	])
+    ], [unix_svr | sunos], [
+	AS_IF([test $PICFLAG = 1], [
+	    OPTIM="-KPIC $OPTIM"
+	])
+    ])
+])
+
 
 dnl Determine whether we are cross-compiling...
-if test "$build" = "$host"; then
-	TARGETS="ALLTARGETS"
-else
-	TARGETS="CROSSTARGETS"
-fi
-AC_SUBST(TARGETS)
-
-dnl Fix "prefix" variable if it hasn't been specified...
-if test "$prefix" = "NONE"; then
-	prefix="/usr/local"
-fi
-
-dnl Fix "exec_prefix" variable if it hasn't been specified...
-if test "$exec_prefix" = "NONE"; then
-	exec_prefix="$prefix"
-fi
-
-dnl Fix "docdir" variable if it hasn't been specified...
-if test "$docdir" = "NONE"; then
-	docdir="$datadir/doc/mxml"
-fi
-
-dnl Fix "mandir" variable if it hasn't been specified...
-if test "$mandir" = "\${prefix}/man" -a "$prefix" = "/usr"; then
-	case "$host_os_name" in
-        	*bsd | darwin | linux*)
-        		# *BSD, Darwin (macOS), and Linux
-        		mandir="/usr/share/man"
-        		;;
-        	irix)
-        		# SGI IRIX
-        		mandir="/usr/share/catman/u_man"
-        		;;
-        	*)
-        		# All others
-        		mandir="/usr/man"
-        		;;
-	esac
-fi
+AS_IF([test "$build" = "$host"], [
+    TARGETS="ALLTARGETS"
+], [
+    TARGETS="CROSSTARGETS"
+])
+AC_SUBST([TARGETS])
+
+
+dnl Fix installation directories...
+AS_IF([test "$prefix" = "NONE"], [
+    prefix="/usr/local"
+])
+
+AS_IF([test "$exec_prefix" = "NONE"], [
+    exec_prefix="$prefix"
+])
+
+AS_IF([test "$docdir" = "NONE"], [
+    docdir="$datadir/doc/mxml"
+])
+
+AS_IF([test "$mandir" = "\${prefix}/man" -a "$prefix" = "/usr"], [
+    mandir="/usr/share/man"
+])
+
 
 dnl pkg-config stuff...
-if test "$includedir" != /usr/include; then
-	PC_CFLAGS="-I$includedir"
-else
-	PC_CFLAGS=""
-fi
+AS_IF([test "$includedir" != /usr/include], [
+    PC_CFLAGS="-I$includedir"
+], [
+    PC_CFLAGS=""
+])
+AC_SUBST([PC_CFLAGS])
 
-if test "$libdir" != /usr/lib; then
-	PC_LIBS="-L$libdir -lmxml"
-else
-	PC_LIBS="-lmxml"
-fi
+AS_IF([test "$libdir" != /usr/lib], [
+    PC_LIBS="-L$libdir -lmxml"
+], [
+    PC_LIBS="-lmxml"
+])
+AC_SUBST([PC_LIBS])
 
-AC_SUBST(PC_CFLAGS)
-AC_SUBST(PC_LIBS)
 
 dnl Output the makefile, etc...
-AC_OUTPUT(Makefile mxml.pc)
+AC_CONFIG_FILES([Makefile mxml.pc])
+AC_OUTPUT

+ 173 - 0
mxml.mod/mxml/doc/body.man

@@ -0,0 +1,173 @@
+.SH INCLUDE FILE
+#include <mxml.h>
+.SH LIBRARY
+\-lmxml
+.SH DESCRIPTION
+Mini-XML is a small XML parsing library that you can use to
+read XML and XML-like data files in your application without
+requiring large non-standard libraries.  Mini-XML only
+requires an ANSI C compatible compiler (GCC works, as do
+most vendors' ANSI C compilers) and a "make" program.
+.PP
+Mini-XML provides the following functionality:
+.IP \(bu 4
+Reading of UTF-8 and UTF-16 and writing of UTF-8 encoded XML files and strings.
+.IP \(bu 4
+Data is stored in a linked-list tree structure,
+preserving the XML data hierarchy.
+.IP \(bu 4
+Supports arbitrary element names, attributes, and attribute
+values with no preset limits, just available memory.
+.IP \(bu 4
+Supports integer, real, opaque ("CDATA"), and text data types in
+"leaf" nodes.
+.IP \(bu 4
+Functions for creating, indexing, and managing trees of data.
+.IP \(bu 4
+"Find" and "walk" functions for easily locating and navigating
+trees of data.
+.PP
+Mini-XML doesn't do validation or other types of processing
+on the data based upon schema files or other sources of
+definition information, nor does it support character
+entities other than those required by the XML
+specification.
+.SH USING MINI-XML
+Mini-XML provides a single header file which you include:
+.nf
+
+    #include <mxml.h>
+.fi
+.PP
+Nodes are defined by the "mxml_node_t" structure; the "type"
+member defines the node type (element, integer, opaque,
+real, or text) which determines which value you want to look
+at in the "value" union.  New nodes can be created using the
+"mxmlNewElement()", "mxmlNewInteger()", "mxmlNewOpaque()",
+"mxmlNewReal()", and "mxmlNewText()" functions.  Only
+elements can have child nodes, and the top node must be an
+element, usually "?xml".
+.PP
+You load an XML file using the "mxmlLoadFile()" function:
+.nf
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "r");
+    tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
+    fclose(fp);
+.fi
+.PP
+Similarly, you save an XML file using the "mxmlSaveFile()"
+function:
+.nf
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "w");
+    mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
+    fclose(fp);
+.fi
+.PP
+The "mxmlLoadString()", "mxmlSaveAllocString()", and
+"mxmlSaveString()" functions load XML node trees from and save
+XML node trees to strings:
+.nf
+
+    char buffer[8192];
+    char *ptr;
+    mxml_node_t *tree;
+
+    ...
+    tree = mxmlLoadString(NULL, buffer, MXML_NO_CALLBACK);
+
+    ...
+    mxmlSaveString(tree, buffer, sizeof(buffer),
+                   MXML_NO_CALLBACK);
+
+    ...
+    ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
+.fi
+.PP
+You can find a named element/node using the "mxmlFindElement()"
+function:
+.nf
+
+    mxml_node_t *node = mxmlFindElement(tree, tree, "name",
+                                        "attr", "value",
+                                        MXML_DESCEND);
+.fi
+.PP
+The "name", "attr", and "value" arguments can be passed as
+NULL to act as wildcards, e.g.:
+.nf
+
+    /* Find the first "a" element */
+    node = mxmlFindElement(tree, tree, "a", NULL, NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" attribute */
+    node = mxmlFindElement(tree, tree, "a", "href", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" to a URL */
+    node = mxmlFindElement(tree, tree, "a", "href",
+                           "http://www.easysw.com/~mike/mxml/",
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" attribute*/
+    node = mxmlFindElement(tree, tree, NULL, "src", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" = "foo.jpg" */
+    node = mxmlFindElement(tree, tree, NULL, "src",
+                           "foo.jpg", MXML_DESCEND);
+.fi
+.PP
+You can also iterate with the same function:
+.nf
+
+    mxml_node_t *node;
+
+    for (node = mxmlFindElement(tree, tree, "name", NULL,
+                                NULL, MXML_DESCEND);
+         node != NULL;
+         node = mxmlFindElement(node, tree, "name", NULL,
+                                NULL, MXML_DESCEND))
+    {
+      ... do something ...
+    }
+.fi
+.PP
+To find the value of a specific node in the tree, use the "mxmlFindPath()"
+function:
+.nf
+
+    mxml_node_t *value = mxmlFindPath(tree, "path/to/*/foo/bar");
+.fi
+.PP
+The "mxmlGetInteger()", "mxmlGetOpaque()", "mxmlGetReal()", and "mxmlGetText()"
+functions retrieve the value from a node:
+.nf
+
+    mxml_node_t *node;
+
+    int intvalue = mxmlGetInteger(node);
+
+    const char *opaquevalue = mxmlGetOpaque(node);
+
+    double realvalue = mxmlGetReal(node);
+
+    int whitespacevalue;
+    const char *textvalue = mxmlGetText(node, &whitespacevalue);
+.fi
+.PP
+Finally, once you are done with the XML data, use the
+"mxmlDelete()" function to recursively free the memory that
+is used for a particular node or the entire tree:
+.nf
+
+    mxmlDelete(tree);
+.fi

+ 1134 - 0
mxml.mod/mxml/doc/body.md

@@ -0,0 +1,1134 @@
+---
+title: Mini-XML 3.3 Programming Manual
+author: Michael R Sweet
+copyright: Copyright © 2003-2022, All Rights Reserved.
+version: 3.3
+...
+
+# Introduction
+
+Mini-XML is a small XML parsing library that you can use to read XML data files
+or strings in your application without requiring large non-standard libraries.
+Mini-XML provides the following functionality:
+
+- Reading of UTF-8 and UTF-16 and writing of UTF-8 encoded XML files and
+  strings.
+- Data is stored in a linked-list tree structure, preserving the XML data
+  hierarchy.
+- SAX (streamed) reading of XML files and strings to minimize memory usage.
+- Supports arbitrary element names, attributes, and attribute values with no
+  preset limits, just available memory.
+- Supports integer, real, opaque ("cdata"), and text data types in "leaf"
+  nodes.
+- Functions for creating and managing trees of data.
+- "Find" and "walk" functions for easily locating and navigating trees of
+  data.
+
+Mini-XML doesn't do validation or other types of processing on the data based
+upon schema files or other sources of definition information.
+
+
+## History
+
+Mini-XML was initially developed for the [Gutenprint](http://gutenprint.sf.net/)
+project to replace the rather large and unwieldy `libxml2` library with
+something substantially smaller and easier-to-use.  It all began one morning in
+June of 2003 when Robert posted the following sentence to the developer's list:
+
+> It's bad enough that we require libxml2, but rolling our own XML parser is a
+> bit more than we can handle.
+
+I then replied with:
+
+> Given the limited scope of what you use in XML, it should be trivial to code a
+> mini-XML API in a few hundred lines of code.
+
+I took my own challenge and coded furiously for two days to produced the initial
+public release of Mini-XML, total lines of code: 696.  Robert promptly
+integrated Mini-XML into Gutenprint and removed libxml2.
+
+Thanks to lots of feedback and support from various developers, Mini-XML has
+evolved since then to provide a more complete XML implementation and now stands
+at a whopping 4,300 lines of code, compared to 196,141 lines of code for libxml2
+version 2.9.9.
+
+
+## Resources
+
+The Mini-XML home page can be found at <https://www.msweet.org/mxml>.  From
+there you can download the current version of Mini-XML, access the issue
+tracker, and find other resources.
+
+
+## Legal Stuff
+
+The Mini-XML library is copyright © 2003-2021 by Michael R Sweet and is provided
+under the Apache License Version 2.0 with an exception to allow linking against
+GPL2/LGPL2-only software.  See the files "LICENSE" and "NOTICE" for more
+information.
+
+
+# Using Mini-XML
+
+Mini-XML provides a single header file which you include:
+
+    #include <mxml.h>
+
+The Mini-XML library is included with your program using the `-lmxml` option:
+
+    gcc -o myprogram myprogram.c -lmxml
+
+If you have the `pkg-config` software installed, you can use it to determine the
+proper compiler and linker options for your installation:
+
+    gcc `pkg-config --cflags mxml` -o myprogram myprogram.c `pkg-config --libs mxml`
+
+
+## Loading an XML File
+
+You load an XML file using the `mxmlLoadFile` function:
+
+    mxml_node_t *
+    mxmlLoadFile(mxml_node_t *top, FILE *fp,
+                 mxml_type_t (*cb)(mxml_node_t *));
+
+The `cb` argument specifies a function that assigns child (value) node types for
+each element in the document.  The callback can be a function you provide or one
+of the standard functions provided with Mini-XML.  For example, to load the XML
+file "filename.xml" containing text strings you can use the
+`MXML_OPAQUE_CALLBACK` function:
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "r");
+    tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
+    fclose(fp);
+
+Mini-XML also provides functions to load from a file descriptor or string:
+
+    mxml_node_t *
+    mxmlLoadFd(mxml_node_t *top, int fd,
+               mxml_type_t (*cb)(mxml_node_t *));
+
+    mxml_node_t *
+    mxmlLoadString(mxml_node_t *top, const char *s,
+                   mxml_type_t (*cb)(mxml_node_t *));
+
+
+### Load Callbacks
+
+The last argument to the `mxmlLoad` functions is a callback function which is
+used to determine the value type of each data node in an XML document.  Mini-XML
+defines several standard callbacks for simple XML data files:
+
+- `MXML_INTEGER_CALLBACK`: All data nodes contain whitespace-separated integers.
+- `MXML_OPAQUE_CALLBACK`: All data nodes contain opaque strings with whitespace preserved.
+- `MXML_REAL_CALLBACK` - All data nodes contain whitespace-separated floating-point numbers.
+- `MXML_TEXT_CALLBACK` - All data nodes contain whitespace-separated strings.
+
+You can provide your own callback functions for more complex XML documents.
+Your callback function will receive a pointer to the current element node and
+must return the value type of the immediate children for that element node:
+`MXML_CUSTOM`, `MXML_INTEGER`, `MXML_OPAQUE`, `MXML_REAL`, or `MXML_TEXT`.  The
+function is called *after* the element and its attributes have been read, so you
+can look at the element name, attributes, and attribute values to determine the
+proper value type to return.
+
+The following callback function looks for an attribute named "type" or the
+element name to determine the value type for its child nodes:
+
+    mxml_type_t
+    type_cb(mxml_node_t *node)
+    {
+      const char *type;
+
+     /*
+      * You can lookup attributes and/or use the element name,
+      * hierarchy, etc...
+      */
+
+      type = mxmlElementGetAttr(node, "type");
+      if (type == NULL)
+        type = mxmlGetElement(node);
+
+      if (!strcmp(type, "integer"))
+        return (MXML_INTEGER);
+      else if (!strcmp(type, "opaque"))
+        return (MXML_OPAQUE);
+      else if (!strcmp(type, "real"))
+        return (MXML_REAL);
+      else
+        return (MXML_TEXT);
+    }
+
+To use this callback function, simply use the name when you call any of the load
+functions:
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "r");
+    tree = mxmlLoadFile(NULL, fp, type_cb);
+    fclose(fp);
+
+
+## Nodes
+
+Every piece of information in an XML file is stored in memory in "nodes".  Nodes
+are defined by the `mxml_node_t` structure.  Each node has a typed value,
+optional user data, a parent node, sibling nodes (previous and next), and
+potentially child nodes.
+
+For example, if you have an XML file like the following:
+
+    <?xml version="1.0" encoding="utf-8"?>
+    <data>
+        <node>val1</node>
+        <node>val2</node>
+        <node>val3</node>
+        <group>
+            <node>val4</node>
+            <node>val5</node>
+            <node>val6</node>
+        </group>
+        <node>val7</node>
+        <node>val8</node>
+    </data>
+
+the node tree for the file would look like the following in memory:
+
+    ?xml version="1.0" encoding="utf-8"?
+      |
+    data
+      |
+    node - node - node - group - node - node
+      |      |      |      |       |      |
+    val1   val2   val3     |     val7   val8
+                           |
+                         node - node - node
+                           |      |      |
+                         val4   val5   val6
+
+where "-" is a pointer to the sibling node and "|" is a pointer to the first
+child or parent node.
+
+The `mxmlGetType` function gets the type of a node:
+
+    mxml_type_t
+    mxmlGetType(mxml_node_t *node);
+
+- `MXML_CUSTOM` : A custom value defined by your application,
+- `MXML_ELEMENT` : An XML element, CDATA, comment, or processing instruction,
+- `MXML_INTEGER` : A whitespace-delimited integer value,
+- `MXML_OPAQUE` : An opaque string value that preserves all whitespace,
+- `MXML_REAL` : A whitespace-delimited floating point value, or
+- `MXML_TEXT` : A whitespace-delimited text (fragment) value.
+
+> Note: CDATA, comment, and processing directive nodes are currently stored in
+> memory as special elements.  This will be changed in a future major release of
+> Mini-XML.
+
+The parent and sibling nodes are accessed using the `mxmlGetParent`,
+`mxmlGetNextSibling`, and `mxmlGetPreviousSibling` functions, while the children
+of an element node are accessed using the `mxmlGetFirstChild` or
+`mxmlGetLastChild` functions:
+
+    mxml_node_t *
+    mxmlGetFirstChild(mxml_node_t *node);
+
+    mxml_node_t *
+    mxmlGetLastChild(mxml_node_t *node);
+
+    mxml_node_t *
+    mxmlGetNextSibling(mxml_node_t *node);
+
+    mxml_node_t *
+    mxmlGetParent(mxml_node_t *node);
+
+    mxml_node_t *
+    mxmlGetPrevSibling(mxml_node_t *node);
+
+The `mxmlGetUserData` function gets any user (application) data associated with
+the node:
+
+    void *
+    mxmlGetUserData(mxml_node_t *node);
+
+
+## Creating XML Documents
+
+You can create and update XML documents in memory using the various `mxmlNew`
+functions. The following code will create the XML document described in the
+previous section:
+
+    mxml_node_t *xml;    /* <?xml ... ?> */
+    mxml_node_t *data;   /* <data> */
+    mxml_node_t *node;   /* <node> */
+    mxml_node_t *group;  /* <group> */
+
+    xml = mxmlNewXML("1.0");
+
+    data = mxmlNewElement(xml, "data");
+
+        node = mxmlNewElement(data, "node");
+        mxmlNewText(node, 0, "val1");
+        node = mxmlNewElement(data, "node");
+        mxmlNewText(node, 0, "val2");
+        node = mxmlNewElement(data, "node");
+        mxmlNewText(node, 0, "val3");
+
+        group = mxmlNewElement(data, "group");
+
+            node = mxmlNewElement(group, "node");
+            mxmlNewText(node, 0, "val4");
+            node = mxmlNewElement(group, "node");
+            mxmlNewText(node, 0, "val5");
+            node = mxmlNewElement(group, "node");
+            mxmlNewText(node, 0, "val6");
+
+        node = mxmlNewElement(data, "node");
+        mxmlNewText(node, 0, "val7");
+        node = mxmlNewElement(data, "node");
+        mxmlNewText(node, 0, "val8");
+
+We start by creating the declaration node common to all XML files using the
+`mxmlNewXML` function:
+
+    xml = mxmlNewXML("1.0");
+
+We then create the `<data>` node used for this document using the
+`mxmlNewElement` function.  The first argument specifies the parent node
+\(`xml`) while the second specifies the element name \(`data`):
+
+    data = mxmlNewElement(xml, "data");
+
+Each `<node>...</node>` in the file is created using the `mxmlNewElement` and
+`mxmlNewText` functions.  The first argument of `mxmlNewText` specifies the
+parent node \(`node`).  The second argument specifies whether whitespace appears
+before the text - 0 or false in this case.  The last argument specifies the
+actual text to add:
+
+    node = mxmlNewElement(data, "node");
+    mxmlNewText(node, 0, "val1");
+
+The resulting in-memory XML document can then be saved or processed just like
+one loaded from disk or a string.
+
+
+## Saving an XML File
+
+You save an XML file using the `mxmlSaveFile` function:
+
+    int
+    mxmlSaveFile(mxml_node_t *node, FILE *fp,
+                 mxml_save_cb_t cb);
+
+The `cb` argument specifies a function that returns the whitespace (if any) that
+is inserted before and after each element node.  The `MXML_NO_CALLBACK` constant
+tells Mini-XML to not include any extra whitespace.  For example, so save an XML
+file to the file "filename.xml" with no extra whitespace:
+
+    FILE *fp;
+
+    fp = fopen("filename.xml", "w");
+    mxmlSaveFile(xml, fp, MXML_NO_CALLBACK);
+    fclose(fp);
+
+Mini-XML also provides functions to save to a file descriptor or strings:
+
+    char *
+    mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t cb);
+
+    int
+    mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t cb);
+
+    int
+    mxmlSaveString(mxml_node_t *node, char *buffer, int bufsize,
+                   mxml_save_cb_t cb);
+
+
+### Controlling Line Wrapping
+
+When saving XML documents, Mini-XML normally wraps output lines at column 75 so
+that the text is readable in terminal windows.  The `mxmlSetWrapMargin` function
+overrides the default wrap margin for the current thread:
+
+    void mxmlSetWrapMargin(int column);
+
+For example, the following code sets the margin to 132 columns:
+
+    mxmlSetWrapMargin(132);
+
+while the following code disables wrapping by setting the margin to 0:
+
+    mxmlSetWrapMargin(0);
+
+
+### Save Callbacks
+
+The last argument to the `mxmlSave` functions is a callback function which is
+used to automatically insert whitespace in an XML document.  Your callback
+function will be called up to four times for each element node with a pointer to
+the node and a "where" value of `MXML_WS_BEFORE_OPEN`, `MXML_WS_AFTER_OPEN`,
+`MXML_WS_BEFORE_CLOSE`, or `MXML_WS_AFTER_CLOSE`.  The callback function should
+return `NULL` if no whitespace should be added or the string to insert (spaces,
+tabs, carriage returns, and newlines) otherwise.
+
+The following whitespace callback can be used to add whitespace to XHTML output
+to make it more readable in a standard text editor:
+
+    const char *
+    whitespace_cb(mxml_node_t *node, int where)
+    {
+      const char *element;
+
+     /*
+      * We can conditionally break to a new line before or after
+      * any element.  These are just common HTML elements...
+      */
+
+      element = mxmlGetElement(node);
+
+      if (!strcmp(element, "html") ||
+          !strcmp(element, "head") ||
+          !strcmp(element, "body") ||
+          !strcmp(element, "pre") ||
+          !strcmp(element, "p") ||
+          !strcmp(element, "h1") ||
+          !strcmp(element, "h2") ||
+          !strcmp(element, "h3") ||
+          !strcmp(element, "h4") ||
+          !strcmp(element, "h5") ||
+          !strcmp(element, "h6"))
+      {
+       /*
+        * Newlines before open and after close...
+        */
+
+        if (where == MXML_WS_BEFORE_OPEN ||
+            where == MXML_WS_AFTER_CLOSE)
+          return ("\n");
+      }
+      else if (!strcmp(element, "dl") ||
+               !strcmp(element, "ol") ||
+               !strcmp(element, "ul"))
+      {
+       /*
+        * Put a newline before and after list elements...
+        */
+
+        return ("\n");
+      }
+      else if (!strcmp(element, "dd") ||
+               !strcmp(element, "dt") ||
+               !strcmp(element, "li"))
+      {
+       /*
+        * Put a tab before <li>'s, <dd>'s, and <dt>'s, and a
+        * newline after them...
+        */
+
+        if (where == MXML_WS_BEFORE_OPEN)
+          return ("\t");
+        else if (where == MXML_WS_AFTER_CLOSE)
+          return ("\n");
+      }
+
+     /*
+      * Otherwise return NULL for no added whitespace...
+      */
+
+      return (NULL);
+    }
+
+To use this callback function, simply use the name when you call any of the save
+functions:
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "w");
+    mxmlSaveFile(tree, fp, whitespace_cb);
+    fclose(fp);
+
+
+## Memory Management
+
+Once you are done with the XML data, use the `mxmlDelete` function to
+recursively free the memory that is used for a particular node or the entire
+tree:
+
+    void
+    mxmlDelete(mxml_node_t *tree);
+
+You can also use reference counting to manage memory usage.  The `mxmlRetain`
+and `mxmlRelease` functions increment and decrement a node's use count,
+respectively.  When the use count goes to zero, `mxmlRelease` automatically
+calls `mxmlDelete` to actually free the memory used by the node tree.  New nodes
+start with a use count of 1.
+
+
+# More About Nodes
+
+## Element Nodes
+
+Element \(`MXML_ELEMENT`) nodes are created using the `mxmlNewElement` function.
+Element attributes are set using the `mxmlElementSetAttr` and
+`mxmlElementSetAttrf` functions and cleared using the `mxmlElementDeleteAttr`
+function:
+
+    mxml_node_t *
+    mxmlNewElement(mxml_node_t *parent, const char *name);
+
+    void
+    mxmlElementDeleteAttr(mxml_node_t *node, const char *name);
+
+    void
+    mxmlElementSetAttr(mxml_node_t *node, const char *name,
+                       const char *value);
+
+    void
+    mxmlElementSetAttrf(mxml_node_t *node, const char *name,
+                        const char *format, ...);
+
+Child nodes are added using the various `mxmlNew` functions.  The top (root)
+node must be an element, usually created by the `mxmlNewXML` function:
+
+    mxml_node_t *
+    mxmlNewXML(const char *version);
+
+The `mxmlGetElement` function retrieves the element name, the
+`mxmlElementGetAttr` function retrieves the value string for a named attribute
+associated with the element.  The `mxmlElementGetAttrByIndex` and
+`mxmlElementGetAttrCount` functions retrieve attributes by index:
+
+    const char *
+    mxmlGetElement(mxml_node_t *node);
+
+    const char *
+    mxmlElementGetAttr(mxml_node_t *node, const char *name);
+
+    const char *
+    mxmlElementGetAttrByIndex(mxml_node_t *node, int idx,
+                              const char **name);
+
+    int
+    mxmlElementGetAttrCount(mxml_node_t *node);
+
+
+## CDATA Nodes
+
+CDATA \(`MXML_ELEMENT`) nodes are created using the `mxmlNewCDATA` function:
+
+    mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
+
+The `mxmlGetCDATA` function retrieves the CDATA string pointer for a node:
+
+    const char *mxmlGetCDATA(mxml_node_t *node);
+
+
+## Comment Nodes
+
+Because comments are currently stored as element nodes, comment
+\(`MXML_ELEMENT`) nodes are created using the `mxmlNewElement` function by
+including the surrounding "!--" and "--" characters in the element name, for
+example:
+
+    mxml_node_t *node = mxmlNewElement("!-- This is a comment --");
+
+Similarly, the `mxmlGetElement` function retrieves the comment string pointer
+for a node, which includes the surrounding "!--" and "--" characters.
+
+    const char *comment = mxmlGetElement(node);
+    /* returns "!-- This is a comment --" */
+
+
+## Processing Instruction Nodes
+
+Because processing instructions are currently stored as element nodes,
+processing instruction \(`MXML_ELEMENT`) nodes are created using the
+`mxmlNewElement` function including the surrounding "?" characters:
+
+    mxml_node_t *node = mxmlNewElement("?xml-stylesheet type=\"text/css\" href=\"style.css\"?");
+
+The `mxmlGetElement` function retrieves the processing instruction string for a
+node, including the surrounding "?" characters:
+
+    const char *instr = mxmlGetElement(node);
+    /* returned "?xml-stylesheet type=\"text/css\" href=\"style.css\"?" */
+
+
+## Integer Nodes
+
+Integer \(`MXML_INTEGER`) nodes are created using the `mxmlNewInteger` function:
+
+    mxml_node_t *
+    mxmlNewInteger(mxml_node_t *parent, int integer);
+
+The `mxmlGetInteger` function retrieves the integer value for a node:
+
+    int
+    mxmlGetInteger(mxml_node_t *node);
+
+
+## Opaque String Nodes
+
+Opaque string \(`MXML_OPAQUE`) nodes are created using the `mxmlNewOpaque`
+function:
+
+    mxml_node_t *
+    mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
+
+The `mxmlGetOpaque` function retrieves the opaque string pointer for a node:
+
+    const char *
+    mxmlGetOpaque(mxml_node_t *node);
+
+
+## Text Nodes
+
+Whitespace-delimited text string \(`MXML_TEXT`) nodes are created using the
+`mxmlNewText` and `mxmlNewTextf` functions.  Each text node consists of a text
+string and (leading) whitespace flag value.
+
+    mxml_node_t *
+    mxmlNewText(mxml_node_t *parent, int whitespace,
+                const char *string);
+
+    mxml_node_t *
+    mxmlNewTextf(mxml_node_t *parent, int whitespace,
+                 const char *format, ...);
+
+The `mxmlGetText` function retrieves the text string pointer and whitespace
+flag value for a node:
+
+     const char *
+     mxmlGetText(mxml_node_t *node, int *whitespace);
+
+
+## Real Number Nodes
+
+Real number \(`MXML_REAL`) nodes are created using the `mxmlNewReal` function:
+
+    mxml_node_t *
+    mxmlNewReal(mxml_node_t *parent, double real);
+
+The `mxmlGetReal` function retrieves the real number for a node:
+
+    double
+    mxmlGetReal(mxml_node_t *node);
+
+
+# Locating Data in an XML Document
+
+Mini-XML provides many functions for enumerating, searching, and indexing XML
+documents.
+
+
+## Finding Nodes
+
+The `mxmlFindPath` function finds the (first) value node under a specific
+element using a "path":
+
+    mxml_node_t *
+    mxmlFindPath(mxml_node_t *node, const char *path);
+
+The `path` string can contain the "*" wildcard to match a single element node in
+the hierarchy.  For example, the following code will find the first "node"
+element under the "group" element, first using an explicit path and then using a
+wildcard:
+
+    mxml_node_t *value = mxmlFindPath(xml, "data/group/node");
+
+    mxml_node_t *value = mxmlFindPath(xml, "data/*/node");
+
+The `mxmlFindElement` function can be used to find a named element, optionally
+matching an attribute and value:
+
+    mxml_node_t *
+    mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
+                    const char *element, const char *attr,
+                    const char *value, int descend);
+
+The "element", "attr", and "value" arguments can be passed as `NULL` to act as
+wildcards, e.g.:
+
+    /* Find the first "a" element */
+    node = mxmlFindElement(tree, tree, "a", NULL, NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" attribute */
+    node = mxmlFindElement(tree, tree, "a", "href", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" to a URL */
+    node = mxmlFindElement(tree, tree, "a", "href",
+                           "http://michaelrsweet.github.io/",
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" attribute*/
+    node = mxmlFindElement(tree, tree, NULL, "src", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" = "foo.jpg" */
+    node = mxmlFindElement(tree, tree, NULL, "src", "foo.jpg",
+                           MXML_DESCEND);
+
+You can also iterate with the same function:
+
+    mxml_node_t *node;
+
+    for (node = mxmlFindElement(tree, tree, "element", NULL,
+                                NULL, MXML_DESCEND);
+         node != NULL;
+         node = mxmlFindElement(node, tree, "element", NULL,
+                                NULL, MXML_DESCEND))
+    {
+      ... do something ...
+    }
+
+The `descend` argument \(`MXML_DESCEND` in the examples above) can be one of
+three constants:
+
+- `MXML_NO_DESCEND`: ignore child nodes in the element hierarchy, instead using
+  siblings (same level) or parent nodes (above) until the top (root) node is
+  reached.
+
+- `MXML_DESCEND_FIRST`: start the search with the first child of the node, and
+  then search siblings.  You'll normally use this when iterating through direct
+  children of a parent node, e.g. all of the "node" and "group" elements under
+  the "?xml" parent node in the previous example.
+
+- `MXML_DESCEND`: search child nodes first, then sibling nodes, and then parent
+  nodes.
+
+
+## Iterating Nodes
+
+While the `mxmlFindNode` and `mxmlFindPath` functions will find a particular
+element node, sometimes you need to iterate over all nodes.  The `mxmlWalkNext`
+and `mxmlWalkPrev` functions can be used to iterate through the XML node
+tree:
+
+    mxml_node_t *
+    mxmlWalkNext(mxml_node_t *node, mxml_node_t *top,
+                 int descend);
+
+    mxml_node_t *
+    mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
+                 int descend);
+
+Depending on the value of the `descend` argument, these functions will
+automatically traverse child, sibling, and parent nodes until the `top` node is
+reached.  For example, the following code will iterate over all of the nodes in
+the sample XML document in the previous section:
+
+    mxml_node_t *node;
+
+    for (node = xml;
+         node != NULL;
+         node = mxmlWalkNext(node, xml, MXML_DESCEND))
+    {
+      ... do something ...
+    }
+
+The nodes will be returned in the following order:
+
+    <?xml version="1.0" encoding="utf-8"?>
+    <data>
+    <node>
+    val1
+    <node>
+    val2
+    <node>
+    val3
+    <group>
+    <node>
+    val4
+    <node>
+    val5
+    <node>
+    val6
+    <node>
+    val7
+    <node>
+    val8
+
+
+## Indexing
+
+The `mxmlIndexNew` function allows you to create an index of nodes for faster
+searching and enumeration:
+
+    mxml_index_t *
+    mxmlIndexNew(mxml_node_t *node, const char *element,
+                 const char *attr);
+
+The `element` and `attr` arguments control which elements are included in the
+index.  If `element` is not `NULL` then only elements with the specified name
+are added to the index.  Similarly, if `attr` is not `NULL` then only elements
+containing the specified attribute are added to the index.  The nodes are sorted
+in the index.
+
+For example, the following code creates an index of all "id" values in an XML
+document:
+
+    mxml_index_t *ind = mxmlIndexNew(xml, NULL, "id");
+
+Once the index is created, the `mxmlIndexFind` function can be used to find a
+matching node:
+
+    mxml_node_t *
+    mxmlIndexFind(mxml_index_t *ind, const char *element,
+                  const char *value);
+
+For example, the following code will find the element whose "id" string is "42":
+
+    mxml_node_t *node = mxmlIndexFind(ind, NULL, "42");
+
+Alternately, the `mxmlIndexReset` and `mxmlIndexEnum` functions can be used to
+enumerate the nodes in the index:
+
+    mxml_node_t *
+    mxmlIndexReset(mxml_index_t *ind);
+
+    mxml_node_t *
+    mxmlIndexEnum(mxml_index_t *ind);
+
+Typically these functions will be used in a `for` loop:
+
+    mxml_node_t *node;
+
+    for (node = mxmlIndexReset(ind);
+         node != NULL;
+         node = mxmlIndexEnum(ind))
+    {
+      ... do something ...
+    }
+
+The `mxmlIndexCount` function returns the number of nodes in the index:
+
+    int
+    mxmlIndexGetCount(mxml_index_t *ind);
+
+Finally, the `mxmlIndexDelete` function frees all memory associated with the
+index:
+
+    void
+    mxmlIndexDelete(mxml_index_t *ind);
+
+
+# Custom Data Types
+
+Mini-XML supports custom data types via per-thread load and save callbacks.
+Only a single set of callbacks can be active at any time for the current thread,
+however your callbacks can store additional information in order to support
+multiple custom data types as needed.  The `MXML_CUSTOM` node type identifies
+custom data nodes.
+
+The `mxmlGetCustom` function retrieves the custom value pointer for a node.
+
+    const void *
+    mxmlGetCustom(mxml_node_t *node);
+
+Custom \(`MXML_CUSTOM`) nodes are created using the `mxmlNewCustom` function or
+using a custom per-thread load callbacks specified using the
+`mxmlSetCustomHandlers` function:
+
+    typedef void (*mxml_custom_destroy_cb_t)(void *);
+    typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
+    typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
+
+    mxml_node_t *
+    mxmlNewCustom(mxml_node_t *parent, void *data,
+                  mxml_custom_destroy_cb_t destroy);
+
+    int
+    mxmlSetCustom(mxml_node_t *node, void *data,
+                  mxml_custom_destroy_cb_t destroy);
+
+    void
+    mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
+                          mxml_custom_save_cb_t save);
+
+The load callback receives a pointer to the current data node and a string of
+opaque character data from the XML source with character entities converted to
+the corresponding UTF-8 characters.  For example, if we wanted to support a
+custom date/time type whose value is encoded as "yyyy-mm-ddThh:mm:ssZ" (ISO
+format), the load callback would look like the following:
+
+    typedef struct
+    {
+      unsigned year,    /* Year */
+               month,   /* Month */
+               day,     /* Day */
+               hour,    /* Hour */
+               minute,  /* Minute */
+               second;  /* Second */
+      time_t   unix;    /* UNIX time */
+    } iso_date_time_t;
+
+    int
+    load_custom(mxml_node_t *node, const char *data)
+    {
+      iso_date_time_t *dt;
+      struct tm tmdata;
+
+     /*
+      * Allocate data structure...
+      */
+
+      dt = calloc(1, sizeof(iso_date_time_t));
+
+     /*
+      * Try reading 6 unsigned integers from the data string...
+      */
+
+      if (sscanf(data, "%u-%u-%uT%u:%u:%uZ", &(dt->year),
+                 &(dt->month), &(dt->day), &(dt->hour),
+                 &(dt->minute), &(dt->second)) != 6)
+      {
+       /*
+        * Unable to read numbers, free the data structure and
+        * return an error...
+        */
+
+        free(dt);
+
+        return (-1);
+      }
+
+     /*
+      * Range check values...
+      */
+
+      if (dt->month < 1 || dt->month > 12 ||
+          dt->day < 1 || dt->day > 31 ||
+          dt->hour < 0 || dt->hour > 23 ||
+          dt->minute < 0 || dt->minute > 59 ||
+          dt->second < 0 || dt->second > 60)
+      {
+       /*
+        * Date information is out of range...
+        */
+
+        free(dt);
+
+        return (-1);
+      }
+
+     /*
+      * Convert ISO time to UNIX time in seconds...
+      */
+
+      tmdata.tm_year = dt->year - 1900;
+      tmdata.tm_mon  = dt->month - 1;
+      tmdata.tm_day  = dt->day;
+      tmdata.tm_hour = dt->hour;
+      tmdata.tm_min  = dt->minute;
+      tmdata.tm_sec  = dt->second;
+
+      dt->unix = gmtime(&tmdata);
+
+     /*
+      * Assign custom node data and destroy (free) function
+      * pointers...
+      */
+
+      mxmlSetCustom(node, data, free);
+
+     /*
+      * Return with no errors...
+      */
+
+      return (0);
+    }
+
+The function itself can return 0 on success or -1 if it is unable to decode the
+custom data or the data contains an error.  Custom data nodes contain a `void`
+pointer to the allocated custom data for the node and a pointer to a destructor
+function which will free the custom data when the node is deleted.  In this
+example, we use the standard `free` function since everything is contained in a
+single calloc'd block.
+
+The save callback receives the node pointer and returns an allocated string
+containing the custom data value.  The following save callback could be used for
+our ISO date/time type:
+
+    char *
+    save_custom(mxml_node_t *node)
+    {
+      char data[255];
+      iso_date_time_t *dt;
+
+
+      dt = (iso_date_time_t *)mxmlGetCustom(node);
+
+      snprintf(data, sizeof(data),
+               "%04u-%02u-%02uT%02u:%02u:%02uZ",
+               dt->year, dt->month, dt->day, dt->hour,
+               dt->minute, dt->second);
+
+      return (strdup(data));
+    }
+
+You register the callback functions using the `mxmlSetCustomHandlers` function:
+
+    mxmlSetCustomHandlers(load_custom, save_custom);
+
+
+# SAX (Stream) Loading of Documents
+
+Mini-XML supports an implementation of the Simple API for XML (SAX) which allows
+you to load and process an XML document as a stream of nodes.  Aside from
+allowing you to process XML documents of any size, the Mini-XML implementation
+also allows you to retain portions of the document in memory for later
+processing.
+
+The `mxmlSAXLoadFd`, `mxmlSAXLoadFile`, and `mxmlSAXLoadString` functions
+provide the SAX loading APIs:
+
+    mxml_node_t *
+    mxmlSAXLoadFd(mxml_node_t *top, int fd,
+                  mxml_type_t (*cb)(mxml_node_t *),
+                  mxml_sax_cb_t sax, void *sax_data);
+
+    mxml_node_t *
+    mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
+                    mxml_type_t (*cb)(mxml_node_t *),
+                    mxml_sax_cb_t sax, void *sax_data);
+
+    mxml_node_t *
+    mxmlSAXLoadString(mxml_node_t *top, const char *s,
+                      mxml_type_t (*cb)(mxml_node_t *),
+                      mxml_sax_cb_t sax, void *sax_data);
+
+Each function works like the corresponding `mxmlLoad` function but uses a
+callback to process each node as it is read.  The callback function receives the
+node, an event code, and a user data pointer you supply:
+
+    void
+    sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+           void *data)
+    {
+      ... do something ...
+    }
+
+The event will be one of the following:
+
+- `MXML_SAX_CDATA`: CDATA was just read.
+- `MXML_SAX_COMMENT`: A comment was just read.
+- `MXML_SAX_DATA`: Data (custom, integer, opaque, real, or text) was just read.
+- `MXML_SAX_DIRECTIVE`: A processing directive/instruction was just read.
+- `MXML_SAX_ELEMENT_CLOSE` - A close element was just read \(`</element>`)
+- `MXML_SAX_ELEMENT_OPEN` - An open element was just read \(`<element>`)
+
+Elements are *released* after the close element is processed.  All other nodes
+are released after they are processed.  The SAX callback can *retain* the node
+using the `mxmlRetain` function.  For example, the following SAX callback will
+retain all nodes, effectively simulating a normal in-memory load:
+
+    void
+    sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+           void *data)
+    {
+      if (event != MXML_SAX_ELEMENT_CLOSE)
+        mxmlRetain(node);
+    }
+
+More typically the SAX callback will only retain a small portion of the document
+that is needed for post-processing.  For example, the following SAX callback
+will retain the title and headings in an XHTML file.  It also retains the (parent) elements like `<html>`, `<head>`, and `<body>`, and processing
+directives like  `<?xml ... ?>` and  `<!DOCTYPE ... >`:
+
+    void
+    sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+           void *data)
+    {
+      if (event == MXML_SAX_ELEMENT_OPEN)
+      {
+       /*
+        * Retain headings and titles...
+        */
+
+        const char *element = mxmlGetElement(node);
+
+        if (!strcmp(element, "html") ||
+            !strcmp(element, "head") ||
+            !strcmp(element, "title") ||
+            !strcmp(element, "body") ||
+            !strcmp(element, "h1") ||
+            !strcmp(element, "h2") ||
+            !strcmp(element, "h3") ||
+            !strcmp(element, "h4") ||
+            !strcmp(element, "h5") ||
+            !strcmp(element, "h6"))
+          mxmlRetain(node);
+      }
+      else if (event == MXML_SAX_DIRECTIVE)
+        mxmlRetain(node);
+      else if (event == MXML_SAX_DATA)
+      {
+        if (mxmlGetRefCount(mxmlGetParent(node)) > 1)
+        {
+         /*
+          * If the parent was retained, then retain this data
+          * node as well.
+          */
+
+          mxmlRetain(node);
+        }
+      }
+    }
+
+The resulting skeleton document tree can then be searched just like one loaded
+using the `mxmlLoad` functions.  For example, a filter that reads an XHTML
+document from stdin and then shows the title and headings in the document would
+look like:
+
+    mxml_node_t *doc, *title, *body, *heading;
+
+    doc = mxmlSAXLoadFd(NULL, 0, MXML_TEXT_CALLBACK, sax_cb,
+                        NULL);
+
+    title = mxmlFindElement(doc, doc, "title", NULL, NULL,
+                            MXML_DESCEND);
+
+    if (title)
+      print_children(title);
+
+    body = mxmlFindElement(doc, doc, "body", NULL, NULL,
+                           MXML_DESCEND);
+
+    if (body)
+    {
+      for (heading = mxmlGetFirstChild(body);
+           heading;
+           heading = mxmlGetNextSibling(heading))
+        print_children(heading);
+    }
+
+The `print_children` function is:
+
+    void
+    print_children(mxml_node_t *parent)
+    {
+      mxml_node_t *node;
+      const char *text;
+      int whitespace;
+
+      for (node = mxmlGetFirstChild(parent);
+           node != NULL;
+           node = mxmlGetNextSibling(node))
+      {
+        text = mxmlGetText(node, &whitespace);
+
+        if (whitespace)
+          putchar(' ');
+
+        fputs(text, stdout);
+      }
+
+      putchar('\n');
+    }

+ 4 - 0
mxml.mod/mxml/doc/footer.man

@@ -0,0 +1,4 @@
+.SH SEE ALSO
+Mini-XML Programmers Manual, https://www.msweet.org/mxml
+.SH COPYRIGHT
+Copyright \[co] 2003-2021 by Michael R Sweet.

BIN
mxml.mod/mxml/doc/mxml-128.png


BIN
mxml.mod/mxml/doc/mxml-cover.opacity


BIN
mxml.mod/mxml/doc/mxml-cover.png


+ 1364 - 0
mxml.mod/mxml/doc/mxml.3

@@ -0,0 +1,1364 @@
+.TH mxml 3 "Mini-XML API" "2022-07-25" "Mini-XML API"
+.SH NAME
+mxml \- Mini-XML API
+.SH INCLUDE FILE
+#include <mxml.h>
+.SH LIBRARY
+\-lmxml
+.SH DESCRIPTION
+Mini-XML is a small XML parsing library that you can use to
+read XML and XML-like data files in your application without
+requiring large non-standard libraries.  Mini-XML only
+requires an ANSI C compatible compiler (GCC works, as do
+most vendors' ANSI C compilers) and a "make" program.
+.PP
+Mini-XML provides the following functionality:
+.IP \(bu 4
+Reading of UTF-8 and UTF-16 and writing of UTF-8 encoded XML files and strings.
+.IP \(bu 4
+Data is stored in a linked-list tree structure,
+preserving the XML data hierarchy.
+.IP \(bu 4
+Supports arbitrary element names, attributes, and attribute
+values with no preset limits, just available memory.
+.IP \(bu 4
+Supports integer, real, opaque ("CDATA"), and text data types in
+"leaf" nodes.
+.IP \(bu 4
+Functions for creating, indexing, and managing trees of data.
+.IP \(bu 4
+"Find" and "walk" functions for easily locating and navigating
+trees of data.
+.PP
+Mini-XML doesn't do validation or other types of processing
+on the data based upon schema files or other sources of
+definition information, nor does it support character
+entities other than those required by the XML
+specification.
+.SH USING MINI-XML
+Mini-XML provides a single header file which you include:
+.nf
+
+    #include <mxml.h>
+.fi
+.PP
+Nodes are defined by the "mxml_node_t" structure; the "type"
+member defines the node type (element, integer, opaque,
+real, or text) which determines which value you want to look
+at in the "value" union.  New nodes can be created using the
+"mxmlNewElement()", "mxmlNewInteger()", "mxmlNewOpaque()",
+"mxmlNewReal()", and "mxmlNewText()" functions.  Only
+elements can have child nodes, and the top node must be an
+element, usually "?xml".
+.PP
+You load an XML file using the "mxmlLoadFile()" function:
+.nf
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "r");
+    tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
+    fclose(fp);
+.fi
+.PP
+Similarly, you save an XML file using the "mxmlSaveFile()"
+function:
+.nf
+
+    FILE *fp;
+    mxml_node_t *tree;
+
+    fp = fopen("filename.xml", "w");
+    mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
+    fclose(fp);
+.fi
+.PP
+The "mxmlLoadString()", "mxmlSaveAllocString()", and
+"mxmlSaveString()" functions load XML node trees from and save
+XML node trees to strings:
+.nf
+
+    char buffer[8192];
+    char *ptr;
+    mxml_node_t *tree;
+
+    ...
+    tree = mxmlLoadString(NULL, buffer, MXML_NO_CALLBACK);
+
+    ...
+    mxmlSaveString(tree, buffer, sizeof(buffer),
+                   MXML_NO_CALLBACK);
+
+    ...
+    ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);
+.fi
+.PP
+You can find a named element/node using the "mxmlFindElement()"
+function:
+.nf
+
+    mxml_node_t *node = mxmlFindElement(tree, tree, "name",
+                                        "attr", "value",
+                                        MXML_DESCEND);
+.fi
+.PP
+The "name", "attr", and "value" arguments can be passed as
+NULL to act as wildcards, e.g.:
+.nf
+
+    /* Find the first "a" element */
+    node = mxmlFindElement(tree, tree, "a", NULL, NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" attribute */
+    node = mxmlFindElement(tree, tree, "a", "href", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first "a" element with "href" to a URL */
+    node = mxmlFindElement(tree, tree, "a", "href",
+                           "http://www.easysw.com/~mike/mxml/",
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" attribute*/
+    node = mxmlFindElement(tree, tree, NULL, "src", NULL,
+                           MXML_DESCEND);
+
+    /* Find the first element with a "src" = "foo.jpg" */
+    node = mxmlFindElement(tree, tree, NULL, "src",
+                           "foo.jpg", MXML_DESCEND);
+.fi
+.PP
+You can also iterate with the same function:
+.nf
+
+    mxml_node_t *node;
+
+    for (node = mxmlFindElement(tree, tree, "name", NULL,
+                                NULL, MXML_DESCEND);
+         node != NULL;
+         node = mxmlFindElement(node, tree, "name", NULL,
+                                NULL, MXML_DESCEND))
+    {
+      ... do something ...
+    }
+.fi
+.PP
+To find the value of a specific node in the tree, use the "mxmlFindPath()"
+function:
+.nf
+
+    mxml_node_t *value = mxmlFindPath(tree, "path/to/*/foo/bar");
+.fi
+.PP
+The "mxmlGetInteger()", "mxmlGetOpaque()", "mxmlGetReal()", and "mxmlGetText()"
+functions retrieve the value from a node:
+.nf
+
+    mxml_node_t *node;
+
+    int intvalue = mxmlGetInteger(node);
+
+    const char *opaquevalue = mxmlGetOpaque(node);
+
+    double realvalue = mxmlGetReal(node);
+
+    int whitespacevalue;
+    const char *textvalue = mxmlGetText(node, &whitespacevalue);
+.fi
+.PP
+Finally, once you are done with the XML data, use the
+"mxmlDelete()" function to recursively free the memory that
+is used for a particular node or the entire tree:
+.nf
+
+    mxmlDelete(tree);
+.fi
+.SH ENUMERATIONS
+.SS mxml_sax_event_e
+SAX event type.
+.TP 5
+MXML_SAX_CDATA
+.br
+CDATA node
+.TP 5
+MXML_SAX_COMMENT
+.br
+Comment node
+.TP 5
+MXML_SAX_DATA
+.br
+Data node
+.TP 5
+MXML_SAX_DIRECTIVE
+.br
+Processing directive node
+.TP 5
+MXML_SAX_ELEMENT_CLOSE
+.br
+Element closed
+.TP 5
+MXML_SAX_ELEMENT_OPEN
+.br
+Element opened
+.SS mxml_type_e
+The XML node type.
+.TP 5
+MXML_CUSTOM
+.br
+Custom data 
+.TP 5
+MXML_ELEMENT
+.br
+XML element with attributes
+.TP 5
+MXML_IGNORE
+.br
+Ignore/throw away node 
+.TP 5
+MXML_INTEGER
+.br
+Integer value
+.TP 5
+MXML_OPAQUE
+.br
+Opaque string
+.TP 5
+MXML_REAL
+.br
+Real value
+.TP 5
+MXML_TEXT
+.br
+Text fragment
+.SH FUNCTIONS
+.SS mxmlAdd
+Add a node to a tree.
+.PP
+.nf
+void mxmlAdd (
+    mxml_node_t *parent,
+    int where,
+    mxml_node_t *child,
+    mxml_node_t *node
+);
+.fi
+.PP
+Adds the specified node to the parent.  If the child argument is not
+\fBNULL\fR, puts the new node before or after the specified child depending
+on the value of the where argument.  If the child argument is \fBNULL\fR,
+puts the new node at the beginning of the child list (\fBMXML_ADD_BEFORE\fR)
+or at the end of the child list (\fBMXML_ADD_AFTER\fR).  The constant
+\fBMXML_ADD_TO_PARENT\fR can be used to specify a \fBNULL\fR child pointer.
+.SS mxmlDelete
+Delete a node and all of its children.
+.PP
+.nf
+void mxmlDelete (
+    mxml_node_t *node
+);
+.fi
+.PP
+If the specified node has a parent, this function first removes the
+node from its parent using the \fImxmlRemove\fR function.
+.SS mxmlElementDeleteAttr
+Delete an attribute.
+.PP
+.nf
+void mxmlElementDeleteAttr (
+    mxml_node_t *node,
+    const char *name
+);
+.fi
+.PP
+
+.SS mxmlElementGetAttr
+Get an attribute.
+.PP
+.nf
+const char * mxmlElementGetAttr (
+    mxml_node_t *node,
+    const char *name
+);
+.fi
+.PP
+This function returns \fBNULL\fR if the node is not an element or the
+named attribute does not exist.
+.SS mxmlElementGetAttrByIndex
+Get an element attribute by index.
+.PP
+.nf
+const char * mxmlElementGetAttrByIndex (
+    mxml_node_t *node,
+    int idx,
+    const char **name
+);
+.fi
+.PP
+The index ("idx") is 0-based.  \fBNULL\fR is returned if the specified index
+is out of range.
+
+
+.SS mxmlElementGetAttrCount
+Get the number of element attributes.
+.PP
+.nf
+int  mxmlElementGetAttrCount (
+    mxml_node_t *node
+);
+.fi
+.PP
+
+.SS mxmlElementSetAttr
+Set an attribute.
+.PP
+.nf
+void mxmlElementSetAttr (
+    mxml_node_t *node,
+    const char *name,
+    const char *value
+);
+.fi
+.PP
+If the named attribute already exists, the value of the attribute
+is replaced by the new string value. The string value is copied
+into the element node. This function does nothing if the node is
+not an element.
+.SS mxmlElementSetAttrf
+Set an attribute with a formatted value.
+.PP
+.nf
+void mxmlElementSetAttrf (
+    mxml_node_t *node,
+    const char *name,
+    const char *format,
+    ...
+);
+.fi
+.PP
+If the named attribute already exists, the value of the attribute
+is replaced by the new formatted string. The formatted string value is
+copied into the element node. This function does nothing if the node
+is not an element.
+
+
+.SS mxmlEntityAddCallback
+Add a callback to convert entities to Unicode.
+.PP
+.nf
+int  mxmlEntityAddCallback (
+    mxml_entity_cb_t cb
+);
+.fi
+.SS mxmlEntityGetName
+Get the name that corresponds to the character value.
+.PP
+.nf
+const char * mxmlEntityGetName (
+    int val
+);
+.fi
+.PP
+If val does not need to be represented by a named entity, \fBNULL\fR is returned.
+.SS mxmlEntityGetValue
+Get the character corresponding to a named entity.
+.PP
+.nf
+int  mxmlEntityGetValue (
+    const char *name
+);
+.fi
+.PP
+The entity name can also be a numeric constant. -1 is returned if the
+name is not known.
+.SS mxmlEntityRemoveCallback
+Remove a callback.
+.PP
+.nf
+void mxmlEntityRemoveCallback (
+    mxml_entity_cb_t cb
+);
+.fi
+.SS mxmlFindElement
+Find the named element.
+.PP
+.nf
+mxml_node_t * mxmlFindElement (
+    mxml_node_t *node,
+    mxml_node_t *top,
+    const char *element,
+    const char *attr,
+    const char *value,
+    int descend
+);
+.fi
+.PP
+The search is constrained by the name, attribute name, and value; any
+\fBNULL\fR names or values are treated as wildcards, so different kinds of
+searches can be implemented by looking for all elements of a given name
+or all elements with a specific attribute. The descend argument determines
+whether the search descends into child nodes; normally you will use
+\fBMXML_DESCEND_FIRST\fR for the initial search and \fBMXML_NO_DESCEND\fR
+to find additional direct descendents of the node. The top node argument
+constrains the search to a particular node's children.
+.SS mxmlFindPath
+Find a node with the given path.
+.PP
+.nf
+mxml_node_t * mxmlFindPath (
+    mxml_node_t *top,
+    const char *path
+);
+.fi
+.PP
+The "path" is a slash-separated list of element names. The name "\fI" is
+considered a wildcard for one or more levels of elements.  For example,
+"foo/one/two", "bar/two/one", "\fR/one", and so forth.
+.PP
+The first child node of the found node is returned if the given node has
+children and the first child is a value node.
+
+
+.SS mxmlGetCDATA
+Get the value for a CDATA node.
+.PP
+.nf
+const char * mxmlGetCDATA (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node is not a CDATA element.
+
+
+.SS mxmlGetCustom
+Get the value for a custom node.
+.PP
+.nf
+const void * mxmlGetCustom (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node (or its first child) is not a custom
+value node.
+
+
+.SS mxmlGetElement
+Get the name for an element node.
+.PP
+.nf
+const char * mxmlGetElement (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node is not an element node.
+
+
+.SS mxmlGetFirstChild
+Get the first child of an element node.
+.PP
+.nf
+mxml_node_t * mxmlGetFirstChild (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node is not an element node or if the node
+has no children.
+
+
+.SS mxmlGetInteger
+Get the integer value from the specified node or its
+first child.
+.PP
+.nf
+int  mxmlGetInteger (
+    mxml_node_t *node
+);
+.fi
+.PP
+0 is returned if the node (or its first child) is not an integer value node.
+
+
+.SS mxmlGetLastChild
+Get the last child of an element node.
+.PP
+.nf
+mxml_node_t * mxmlGetLastChild (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node is not an element node or if the node
+has no children.
+
+
+.SS mxmlGetNextSibling
+
+.PP
+.nf
+mxml_node_t * mxmlGetNextSibling (
+    mxml_node_t *node
+);
+.fi
+.SS mxmlGetOpaque
+Get an opaque string value for a node or its first child.
+.PP
+.nf
+const char * mxmlGetOpaque (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node (or its first child) is not an opaque
+value node.
+
+
+.SS mxmlGetParent
+Get the parent node.
+.PP
+.nf
+mxml_node_t * mxmlGetParent (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned for a root node.
+
+
+.SS mxmlGetPrevSibling
+Get the previous node for the current parent.
+.PP
+.nf
+mxml_node_t * mxmlGetPrevSibling (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBNULL\fR is returned if this is the first child for the current parent.
+
+
+.SS mxmlGetReal
+Get the real value for a node or its first child.
+.PP
+.nf
+double  mxmlGetReal (
+    mxml_node_t *node
+);
+.fi
+.PP
+0.0 is returned if the node (or its first child) is not a real value node.
+
+
+.SS mxmlGetRefCount
+Get the current reference (use) count for a node.
+.PP
+.nf
+int  mxmlGetRefCount (
+    mxml_node_t *node
+);
+.fi
+.PP
+The initial reference count of new nodes is 1. Use the \fImxmlRetain\fR
+and \fImxmlRelease\fR functions to increment and decrement a node's
+reference count.
+
+\.
+.SS mxmlGetText
+Get the text value for a node or its first child.
+.PP
+.nf
+const char * mxmlGetText (
+    mxml_node_t *node,
+    int *whitespace
+);
+.fi
+.PP
+\fBNULL\fR is returned if the node (or its first child) is not a text node.
+The "whitespace" argument can be \fBNULL\fR.
+.PP
+Note: Text nodes consist of whitespace-delimited words. You will only get
+single words of text when reading an XML file with \fBMXML_TEXT\fR nodes.
+If you want the entire string between elements in the XML file, you MUST read
+the XML file with \fBMXML_OPAQUE\fR nodes and get the resulting strings
+using the \fImxmlGetOpaque\fR function instead.
+
+
+.SS mxmlGetType
+Get the node type.
+.PP
+.nf
+mxml_type_t  mxmlGetType (
+    mxml_node_t *node
+);
+.fi
+.PP
+\fBMXML_IGNORE\fR is returned if "node" is \fBNULL\fR.
+
+
+.SS mxmlGetUserData
+Get the user data pointer for a node.
+.PP
+.nf
+void * mxmlGetUserData (
+    mxml_node_t *node
+);
+.fi
+.PP
+
+.SS mxmlIndexDelete
+Delete an index.
+.PP
+.nf
+void mxmlIndexDelete (
+    mxml_index_t *ind
+);
+.fi
+.SS mxmlIndexEnum
+Return the next node in the index.
+.PP
+.nf
+mxml_node_t * mxmlIndexEnum (
+    mxml_index_t *ind
+);
+.fi
+.PP
+You should call \fImxmlIndexReset\fR prior to using this function to get
+the first node in the index.  Nodes are returned in the sorted order of the
+index.
+.SS mxmlIndexFind
+Find the next matching node.
+.PP
+.nf
+mxml_node_t * mxmlIndexFind (
+    mxml_index_t *ind,
+    const char *element,
+    const char *value
+);
+.fi
+.PP
+You should call \fImxmlIndexReset\fR prior to using this function for
+the first time with a particular set of "element" and "value"
+strings. Passing \fBNULL\fR for both "element" and "value" is equivalent
+to calling \fImxmlIndexEnum\fR.
+.SS mxmlIndexGetCount
+Get the number of nodes in an index.
+.PP
+.nf
+int  mxmlIndexGetCount (
+    mxml_index_t *ind
+);
+.fi
+.PP
+
+.SS mxmlIndexNew
+Create a new index.
+.PP
+.nf
+mxml_index_t * mxmlIndexNew (
+    mxml_node_t *node,
+    const char *element,
+    const char *attr
+);
+.fi
+.PP
+The index will contain all nodes that contain the named element and/or
+attribute.  If both "element" and "attr" are \fBNULL\fR, then the index will
+contain a sorted list of the elements in the node tree.  Nodes are
+sorted by element name and optionally by attribute value if the "attr"
+argument is not NULL.
+.SS mxmlIndexReset
+Reset the enumeration/find pointer in the index and
+return the first node in the index.
+.PP
+.nf
+mxml_node_t * mxmlIndexReset (
+    mxml_index_t *ind
+);
+.fi
+.PP
+This function should be called prior to using \fImxmlIndexEnum\fR or
+\fImxmlIndexFind\fR for the first time.
+.SS mxmlLoadFd
+Load a file descriptor into an XML node tree.
+.PP
+.nf
+mxml_node_t * mxmlLoadFd (
+    mxml_node_t *top,
+    int fd,
+    mxml_load_cb_t cb
+);
+.fi
+.PP
+The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child (data) nodes of the specified type.
+.PP
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
+(including whitespace).
+.SS mxmlLoadFile
+Load a file into an XML node tree.
+.PP
+.nf
+mxml_node_t * mxmlLoadFile (
+    mxml_node_t *top,
+    FILE *fp,
+    mxml_load_cb_t cb
+);
+.fi
+.PP
+The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child (data) nodes of the specified type.
+.PP
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
+(including whitespace).
+.SS mxmlLoadString
+Load a string into an XML node tree.
+.PP
+.nf
+mxml_node_t * mxmlLoadString (
+    mxml_node_t *top,
+    const char *s,
+    mxml_load_cb_t cb
+);
+.fi
+.PP
+The nodes in the specified string are added to the specified top node.
+If no top node is provided, the XML string MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire string. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child (data) nodes of the specified type.
+.PP
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the \fBMXML_TEXT_CALLBACK\fR, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+\fBMXML_OPAQUE_CALLBACK\fR which returns the inline text as a single string
+(including whitespace).
+.SS mxmlNewCDATA
+Create a new CDATA node.
+.PP
+.nf
+mxml_node_t * mxmlNewCDATA (
+    mxml_node_t *parent,
+    const char *data
+);
+.fi
+.PP
+The new CDATA node is added to the end of the specified parent's child
+list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+CDATA node has no parent.  The data string must be nul-terminated and
+is copied into the new node.  CDATA nodes currently use the
+\fBMXML_ELEMENT\fR type.
+
+
+.SS mxmlNewCustom
+Create a new custom data node.
+.PP
+.nf
+mxml_node_t * mxmlNewCustom (
+    mxml_node_t *parent,
+    void *data,
+    mxml_custom_destroy_cb_t destroy
+);
+.fi
+.PP
+The new custom node is added to the end of the specified parent's child
+list. The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+element node has no parent. \fBNULL\fR can be passed when the data in the
+node is not dynamically allocated or is separately managed.
+
+
+.SS mxmlNewElement
+Create a new element node.
+.PP
+.nf
+mxml_node_t * mxmlNewElement (
+    mxml_node_t *parent,
+    const char *name
+);
+.fi
+.PP
+The new element node is added to the end of the specified parent's child
+list. The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+element node has no parent.
+.SS mxmlNewInteger
+Create a new integer node.
+.PP
+.nf
+mxml_node_t * mxmlNewInteger (
+    mxml_node_t *parent,
+    int integer
+);
+.fi
+.PP
+The new integer node is added to the end of the specified parent's child
+list. The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+integer node has no parent.
+.SS mxmlNewOpaque
+Create a new opaque string.
+.PP
+.nf
+mxml_node_t * mxmlNewOpaque (
+    mxml_node_t *parent,
+    const char *opaque
+);
+.fi
+.PP
+The new opaque string node is added to the end of the specified parent's
+child list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that
+the new opaque string node has no parent.  The opaque string must be nul-
+terminated and is copied into the new node.
+.SS mxmlNewOpaquef
+Create a new formatted opaque string node.
+.PP
+.nf
+mxml_node_t * mxmlNewOpaquef (
+    mxml_node_t *parent,
+    const char *format,
+    ...
+);
+.fi
+.PP
+The new opaque string node is added to the end of the specified parent's
+child list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that
+the new opaque string node has no parent.  The format string must be
+nul-terminated and is formatted into the new node.
+.SS mxmlNewReal
+Create a new real number node.
+.PP
+.nf
+mxml_node_t * mxmlNewReal (
+    mxml_node_t *parent,
+    double real
+);
+.fi
+.PP
+The new real number node is added to the end of the specified parent's
+child list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that
+the new real number node has no parent.
+.SS mxmlNewText
+Create a new text fragment node.
+.PP
+.nf
+mxml_node_t * mxmlNewText (
+    mxml_node_t *parent,
+    int whitespace,
+    const char *string
+);
+.fi
+.PP
+The new text node is added to the end of the specified parent's child
+list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+text node has no parent.  The whitespace parameter is used to specify
+whether leading whitespace is present before the node.  The text
+string must be nul-terminated and is copied into the new node.
+.SS mxmlNewTextf
+Create a new formatted text fragment node.
+.PP
+.nf
+mxml_node_t * mxmlNewTextf (
+    mxml_node_t *parent,
+    int whitespace,
+    const char *format,
+    ...
+);
+.fi
+.PP
+The new text node is added to the end of the specified parent's child
+list.  The constant \fBMXML_NO_PARENT\fR can be used to specify that the new
+text node has no parent.  The whitespace parameter is used to specify
+whether leading whitespace is present before the node.  The format
+string must be nul-terminated and is formatted into the new node.
+.SS mxmlNewXML
+Create a new XML document tree.
+.PP
+.nf
+mxml_node_t * mxmlNewXML (
+    const char *version
+);
+.fi
+.PP
+The "version" argument specifies the version number to put in the
+?xml element node. If \fBNULL\fR, version "1.0" is assumed.
+
+
+.SS mxmlRelease
+Release a node.
+.PP
+.nf
+int  mxmlRelease (
+    mxml_node_t *node
+);
+.fi
+.PP
+When the reference count reaches zero, the node (and any children)
+is deleted via \fImxmlDelete\fR.
+
+
+.SS mxmlRemove
+Remove a node from its parent.
+.PP
+.nf
+void mxmlRemove (
+    mxml_node_t *node
+);
+.fi
+.PP
+This function does not free memory used by the node - use \fImxmlDelete\fR
+for that.  This function does nothing if the node has no parent.
+.SS mxmlRetain
+Retain a node.
+.PP
+.nf
+int  mxmlRetain (
+    mxml_node_t *node
+);
+.fi
+.PP
+
+.SS mxmlSAXLoadFd
+Load a file descriptor into an XML node tree
+using a SAX callback.
+.PP
+.nf
+mxml_node_t * mxmlSAXLoadFd (
+    mxml_node_t *top,
+    int fd,
+    mxml_load_cb_t cb,
+    mxml_sax_cb_t sax_cb,
+    void *sax_data
+);
+.fi
+.PP
+The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child nodes of the specified type.
+.PP
+The SAX callback must call \fImxmlRetain\fR for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+
+.SS mxmlSAXLoadFile
+Load a file into an XML node tree
+using a SAX callback.
+.PP
+.nf
+mxml_node_t * mxmlSAXLoadFile (
+    mxml_node_t *top,
+    FILE *fp,
+    mxml_load_cb_t cb,
+    mxml_sax_cb_t sax_cb,
+    void *sax_data
+);
+.fi
+.PP
+The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child nodes of the specified type.
+.PP
+The SAX callback must call \fImxmlRetain\fR for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+
+.SS mxmlSAXLoadString
+Load a string into an XML node tree
+using a SAX callback.
+.PP
+.nf
+mxml_node_t * mxmlSAXLoadString (
+    mxml_node_t *top,
+    const char *s,
+    mxml_load_cb_t cb,
+    mxml_sax_cb_t sax_cb,
+    void *sax_data
+);
+.fi
+.PP
+The nodes in the specified string are added to the specified top node.
+If no top node is provided, the XML string MUST be well-formed with a
+single parent node like 
+.URL ?xml ?xml
+ for the entire string. The callback
+function returns the value type that should be used for child nodes.
+The constants \fBMXML_INTEGER_CALLBACK\fR, \fBMXML_OPAQUE_CALLBACK\fR,
+\fBMXML_REAL_CALLBACK\fR, and \fBMXML_TEXT_CALLBACK\fR are defined for
+loading child nodes of the specified type.
+.PP
+The SAX callback must call \fImxmlRetain\fR for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+
+.SS mxmlSaveAllocString
+Save an XML tree to an allocated string.
+.PP
+.nf
+char * mxmlSaveAllocString (
+    mxml_node_t *node,
+    mxml_save_cb_t cb
+);
+.fi
+.PP
+This function returns a pointer to a string containing the textual
+representation of the XML node tree.  The string should be freed
+using \fBfree()\fR when you are done with it.  \fBNULL\fR is returned if the node
+would produce an empty string or if the string cannot be allocated.
+.PP
+The callback argument specifies a function that returns a whitespace
+string or \fBNULL\fR before and after each element.  If \fBMXML_NO_CALLBACK\fR
+is specified, whitespace will only be added before \fBMXML_TEXT\fR nodes
+with leading whitespace and before attribute names inside opening
+element tags.
+.SS mxmlSaveFd
+Save an XML tree to a file descriptor.
+.PP
+.nf
+int  mxmlSaveFd (
+    mxml_node_t *node,
+    int fd,
+    mxml_save_cb_t cb
+);
+.fi
+.PP
+The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If \fBMXML_NO_CALLBACK\fR
+is specified, whitespace will only be added before \fBMXML_TEXT\fR nodes
+with leading whitespace and before attribute names inside opening
+element tags.
+.SS mxmlSaveFile
+Save an XML tree to a file.
+.PP
+.nf
+int  mxmlSaveFile (
+    mxml_node_t *node,
+    FILE *fp,
+    mxml_save_cb_t cb
+);
+.fi
+.PP
+The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If \fBMXML_NO_CALLBACK\fR
+is specified, whitespace will only be added before \fBMXML_TEXT\fR nodes
+with leading whitespace and before attribute names inside opening
+element tags.
+.SS mxmlSaveString
+Save an XML node tree to a string.
+.PP
+.nf
+int  mxmlSaveString (
+    mxml_node_t *node,
+    char *buffer,
+    int bufsize,
+    mxml_save_cb_t cb
+);
+.fi
+.PP
+This function returns the total number of bytes that would be
+required for the string but only copies (bufsize - 1) characters
+into the specified buffer.
+.PP
+The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If \fBMXML_NO_CALLBACK\fR
+is specified, whitespace will only be added before \fBMXML_TEXT\fR nodes
+with leading whitespace and before attribute names inside opening
+element tags.
+.SS mxmlSetCDATA
+Set the element name of a CDATA node.
+.PP
+.nf
+int  mxmlSetCDATA (
+    mxml_node_t *node,
+    const char *data
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not a CDATA element node.
+
+
+.SS mxmlSetCustom
+Set the data and destructor of a custom data node.
+.PP
+.nf
+int  mxmlSetCustom (
+    mxml_node_t *node,
+    void *data,
+    mxml_custom_destroy_cb_t destroy
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not a custom node.
+
+
+.SS mxmlSetCustomHandlers
+Set the handling functions for custom data.
+.PP
+.nf
+void mxmlSetCustomHandlers (
+    mxml_custom_load_cb_t load,
+    mxml_custom_save_cb_t save
+);
+.fi
+.PP
+The load function accepts a node pointer and a data string and must
+return 0 on success and non-zero on error.
+.PP
+The save function accepts a node pointer and must return a malloc'd
+string on success and \fBNULL\fR on error.
+.SS mxmlSetElement
+Set the name of an element node.
+.PP
+.nf
+int  mxmlSetElement (
+    mxml_node_t *node,
+    const char *name
+);
+.fi
+.PP
+The node is not changed if it is not an element node.
+.SS mxmlSetErrorCallback
+Set the error message callback.
+.PP
+.nf
+void mxmlSetErrorCallback (
+    mxml_error_cb_t cb
+);
+.fi
+.SS mxmlSetInteger
+Set the value of an integer node.
+.PP
+.nf
+int  mxmlSetInteger (
+    mxml_node_t *node,
+    int integer
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not an integer node.
+.SS mxmlSetOpaque
+Set the value of an opaque node.
+.PP
+.nf
+int  mxmlSetOpaque (
+    mxml_node_t *node,
+    const char *opaque
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not an opaque node.
+.SS mxmlSetOpaquef
+Set the value of an opaque string node to a formatted string.
+.PP
+.nf
+int  mxmlSetOpaquef (
+    mxml_node_t *node,
+    const char *format,
+    ...
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not an opaque node.
+
+
+.SS mxmlSetReal
+Set the value of a real number node.
+.PP
+.nf
+int  mxmlSetReal (
+    mxml_node_t *node,
+    double real
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not a real number node.
+.SS mxmlSetText
+Set the value of a text node.
+.PP
+.nf
+int  mxmlSetText (
+    mxml_node_t *node,
+    int whitespace,
+    const char *string
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not a text node.
+.SS mxmlSetTextf
+Set the value of a text node to a formatted string.
+.PP
+.nf
+int  mxmlSetTextf (
+    mxml_node_t *node,
+    int whitespace,
+    const char *format,
+    ...
+);
+.fi
+.PP
+The node is not changed if it (or its first child) is not a text node.
+.SS mxmlSetUserData
+Set the user data pointer for a node.
+.PP
+.nf
+int  mxmlSetUserData (
+    mxml_node_t *node,
+    void *data
+);
+.fi
+.PP
+
+.SS mxmlSetWrapMargin
+Set the wrap margin when saving XML data.
+.PP
+.nf
+void mxmlSetWrapMargin (
+    int column
+);
+.fi
+.PP
+Wrapping is disabled when "column" is 0.
+
+
+.SS mxmlWalkNext
+Walk to the next logical node in the tree.
+.PP
+.nf
+mxml_node_t * mxmlWalkNext (
+    mxml_node_t *node,
+    mxml_node_t *top,
+    int descend
+);
+.fi
+.PP
+The descend argument controls whether the first child is considered
+to be the next node.  The top node argument constrains the walk to
+the node's children.
+.SS mxmlWalkPrev
+Walk to the previous logical node in the tree.
+.PP
+.nf
+mxml_node_t * mxmlWalkPrev (
+    mxml_node_t *node,
+    mxml_node_t *top,
+    int descend
+);
+.fi
+.PP
+The descend argument controls whether the previous node's last child
+is considered to be the previous node.  The top node argument constrains
+the walk to the node's children.
+.SH TYPES
+.SS mxml_custom_destroy_cb_t
+Custom data destructor
+.PP
+.nf
+typedef void(*)(void *) mxml_custom_destroy_cb_t;
+.fi
+.SS mxml_custom_load_cb_t
+Custom data load callback function
+.PP
+.nf
+typedef int(*)(mxml_node_t *, const char *) mxml_custom_load_cb_t;
+.fi
+.SS mxml_custom_save_cb_t
+Custom data save callback function
+.PP
+.nf
+typedef char *(*)(mxml_node_t *) mxml_custom_save_cb_t;
+.fi
+.SS mxml_entity_cb_t
+Entity callback function
+.PP
+.nf
+typedef int(*)(const char *) mxml_entity_cb_t;
+.fi
+.SS mxml_error_cb_t
+Error callback function
+.PP
+.nf
+typedef void(*)(const char *) mxml_error_cb_t;
+.fi
+.SS mxml_index_t
+An XML node index.
+.PP
+.nf
+typedef struct _mxml_index_s mxml_index_t;
+.fi
+.SS mxml_load_cb_t
+Load callback function
+.PP
+.nf
+typedef mxml_type_t(*)(mxml_node_t *) mxml_load_cb_t;
+.fi
+.SS mxml_node_t
+An XML node.
+.PP
+.nf
+typedef struct _mxml_node_s mxml_node_t;
+.fi
+.SS mxml_save_cb_t
+Save callback function
+.PP
+.nf
+typedef const char *(*)(mxml_node_t *, int) mxml_save_cb_t;
+.fi
+.SS mxml_sax_cb_t
+SAX callback function
+.PP
+.nf
+typedef void(*)(mxml_node_t *, mxml_sax_event_t, void *) mxml_sax_cb_t;
+.fi
+.SS mxml_sax_event_t
+SAX event type.
+.PP
+.nf
+typedef enum mxml_sax_event_e mxml_sax_event_t;
+.fi
+.SS mxml_type_t
+The XML node type.
+.PP
+.nf
+typedef enum mxml_type_e mxml_type_t;
+.fi
+.SH SEE ALSO
+Mini-XML Programmers Manual, https://www.msweet.org/mxml
+.SH COPYRIGHT
+Copyright \[co] 2003-2021 by Michael R Sweet.

BIN
mxml.mod/mxml/doc/mxml.epub


+ 2637 - 0
mxml.mod/mxml/doc/mxml.html

@@ -0,0 +1,2637 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+<title>Mini-XML 3.3 Programming Manual</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+<meta name="generator" content="codedoc v3.7">
+<meta name="author" content="Michael R Sweet">
+<meta name="language" content="en-US">
+<meta name="copyright" content="Copyright © 2003-2022, All Rights Reserved.">
+<meta name="version" content="3.3">
+<style type="text/css"><!--
+body {
+  background: white;
+  color: black;
+  font-family: sans-serif;
+  font-size: 12pt;
+}
+a {
+  color: black;
+}
+a:link, a:visited {
+  color: #00f;
+}
+a:link:hover, a:visited:hover, a:active {
+  color: #c0c;
+}
+body, p, h1, h2, h3, h4, h5, h6 {
+  font-family: sans-serif;
+  line-height: 1.4;
+}
+h1, h2, h3, h4, h5, h6 {
+  font-weight: bold;
+  page-break-inside: avoid;
+}
+h1 {
+  font-size: 250%;
+  margin: 0;
+}
+h2 {
+  font-size: 250%;
+  margin-top: 1.5em;
+}
+h3 {
+  font-size: 200%;
+  margin-bottom: 0.5em;
+  margin-top: 1.5em;
+}
+h4 {
+  font-size: 150%;
+  margin-bottom: 0.5em;
+  margin-top: 1.5em;
+}
+h5 {
+  font-size: 125%;
+  margin-bottom: 0.5em;
+  margin-top: 1.5em;
+}
+h6 {
+  font-size: 110%;
+  margin-bottom: 0.5em;
+  margin-top: 1.5em;
+}
+img.title {
+  width: 256px;
+}
+div.header h1, div.header p {
+  text-align: center;
+}
+div.contents, div.body, div.footer {
+  page-break-before: always;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+  border-bottom: solid 2px gray;
+}
+.description {
+  margin-top: 0.5em;
+}
+.function {
+  margin-bottom: 0;
+}
+blockquote {
+  border: solid thin gray;
+  box-shadow: 3px 3px 5px rgba(127,127,127,0.25);
+  margin: 1em 0;
+  padding: 10px;
+  page-break-inside: avoid;
+}
+p code, li code, p.code, pre, ul.code li {
+  font-family: monospace;
+  hyphens: manual;
+  -webkit-hyphens: manual;
+}
+p.code, pre, ul.code li {
+  background: rgba(127,127,127,0.25);
+  border: thin dotted gray;
+  padding: 10px;
+  page-break-inside: avoid;
+}
+pre {
+  white-space: pre-wrap;
+}
+a:link, a:visited {
+  text-decoration: none;
+}
+span.info {
+  background: black;
+  border: solid thin black;
+  color: white;
+  font-size: 80%;
+  font-style: italic;
+  font-weight: bold;
+  white-space: nowrap;
+}
+h1 span.info, h2 span.info, h3 span.info, h4 span.info {
+  border-top-left-radius: 10px;
+  border-top-right-radius: 10px;
+  float: right;
+  padding: 3px 6px;
+}
+ul.code, ul.contents, ul.subcontents {
+  list-style-type: none;
+  margin: 0;
+  padding-left: 0;
+}
+ul.code li {
+  margin: 0;
+}
+ul.contents > li {
+  margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+  padding-left: 2em;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+td {
+  border: solid 1px gray;
+  padding: 5px 10px;
+  vertical-align: top;
+}
+td.left {
+  text-align: left;
+}
+td.center {
+  text-align: center;
+}
+td.right {
+  text-align: right;
+}
+th {
+  border-bottom: solid 2px gray;
+  padding: 1px 5px;
+  text-align: center;
+  vertical-align: bottom;
+}
+tr:nth-child(even) {
+  background: rgba(127,127,127,0.25);
+}
+table.list {
+  border-collapse: collapse;
+  width: 100%;
+}
+table.list th {
+  border-bottom: none;
+  border-right: 2px solid gray;
+  font-family: monospace;
+  font-weight: normal;
+  padding: 5px 10px 5px 2px;
+  text-align: right;
+  vertical-align: top;
+}
+table.list td {
+  border: none;
+  padding: 5px 2px 5px 10px;
+  text-align: left;
+  vertical-align: top;
+}
+h2.title, h3.title {
+  border-bottom: solid 2px gray;
+}
+/* Syntax highlighting */
+span.comment {
+  color: darkgreen;
+}
+span.directive {
+  color: purple;
+}
+span.number {
+  color: brown;
+}
+span.reserved {
+  color: darkcyan;
+}
+span.string {
+  color: magenta;
+}
+/* Dark mode overrides */
+@media (prefers-color-scheme: dark) {
+  body {
+    background: black;
+    color: #ccc;
+  }
+  a {
+    color: #ccc;
+  }
+  a:link, a:visited {
+    color: #66f;
+  }
+  a:link:hover, a:visited:hover, a:active {
+    color: #f06;
+  }
+}
+/* Show contents on left side in web browser */
+@media screen and (min-width: 800px) {
+  div.contents {
+    border-right: solid thin gray;
+    bottom: 0px;
+    box-shadow: 3px 3px 5px rgba(127,127,127,0.5);
+    font-size: 10pt;
+    left: 0px;
+    overflow: scroll;
+    padding: 1%;
+    position: fixed;
+    top: 0px;
+    width: 18%;
+  }
+  div.contents h2.title {
+    margin-top: 0px;
+  }
+  div.header, div.body, div.footer {
+    margin-left: 20%;
+    padding: 1% 2%;
+  }
+}
+/* Center title page content vertically */
+@media print {
+  div.header {
+    padding-top: 33%;
+  }
+}
+--></style>
+</head>
+<body>
+<div class="header">
+<p><img class="title" src="mxml-cover.png"></p>
+<h1 class="title">Mini-XML 3.3 Programming Manual</h1>
+<p>Michael R Sweet</p>
+<p>Copyright © 2003-2022, All Rights Reserved.</p>
+</div>
+<div class="contents">
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<li><a href="#introduction">Introduction</a><ul class="subcontents">
+<li><a href="#history">History</a></li>
+<li><a href="#resources">Resources</a></li>
+<li><a href="#legal-stuff">Legal Stuff</a></li>
+</ul></li>
+<li><a href="#using-mini-xml">Using Mini-XML</a><ul class="subcontents">
+<li><a href="#loading-an-xml-file">Loading an XML File</a></li>
+<li><a href="#nodes">Nodes</a></li>
+<li><a href="#creating-xml-documents">Creating XML Documents</a></li>
+<li><a href="#saving-an-xml-file">Saving an XML File</a></li>
+<li><a href="#memory-management">Memory Management</a></li>
+</ul></li>
+<li><a href="#more-about-nodes">More About Nodes</a><ul class="subcontents">
+<li><a href="#element-nodes">Element Nodes</a></li>
+<li><a href="#cdata-nodes">CDATA Nodes</a></li>
+<li><a href="#comment-nodes">Comment Nodes</a></li>
+<li><a href="#processing-instruction-nodes">Processing Instruction Nodes</a></li>
+<li><a href="#integer-nodes">Integer Nodes</a></li>
+<li><a href="#opaque-string-nodes">Opaque String Nodes</a></li>
+<li><a href="#text-nodes">Text Nodes</a></li>
+<li><a href="#real-number-nodes">Real Number Nodes</a></li>
+</ul></li>
+<li><a href="#locating-data-in-an-xml-document">Locating Data in an XML Document</a><ul class="subcontents">
+<li><a href="#finding-nodes">Finding Nodes</a></li>
+<li><a href="#iterating-nodes">Iterating Nodes</a></li>
+<li><a href="#indexing">Indexing</a></li>
+</ul></li>
+<li><a href="#custom-data-types">Custom Data Types</a></li>
+<li><a href="#sax-stream-loading-of-documents">SAX (Stream) Loading of Documents</a></li>
+<li><a href="#FUNCTIONS">Functions</a><ul class="subcontents">
+<li><a href="#mxmlAdd">mxmlAdd</a></li>
+<li><a href="#mxmlDelete">mxmlDelete</a></li>
+<li><a href="#mxmlElementDeleteAttr">mxmlElementDeleteAttr</a></li>
+<li><a href="#mxmlElementGetAttr">mxmlElementGetAttr</a></li>
+<li><a href="#mxmlElementGetAttrByIndex">mxmlElementGetAttrByIndex</a></li>
+<li><a href="#mxmlElementGetAttrCount">mxmlElementGetAttrCount</a></li>
+<li><a href="#mxmlElementSetAttr">mxmlElementSetAttr</a></li>
+<li><a href="#mxmlElementSetAttrf">mxmlElementSetAttrf</a></li>
+<li><a href="#mxmlEntityAddCallback">mxmlEntityAddCallback</a></li>
+<li><a href="#mxmlEntityGetName">mxmlEntityGetName</a></li>
+<li><a href="#mxmlEntityGetValue">mxmlEntityGetValue</a></li>
+<li><a href="#mxmlEntityRemoveCallback">mxmlEntityRemoveCallback</a></li>
+<li><a href="#mxmlFindElement">mxmlFindElement</a></li>
+<li><a href="#mxmlFindPath">mxmlFindPath</a></li>
+<li><a href="#mxmlGetCDATA">mxmlGetCDATA</a></li>
+<li><a href="#mxmlGetCustom">mxmlGetCustom</a></li>
+<li><a href="#mxmlGetElement">mxmlGetElement</a></li>
+<li><a href="#mxmlGetFirstChild">mxmlGetFirstChild</a></li>
+<li><a href="#mxmlGetInteger">mxmlGetInteger</a></li>
+<li><a href="#mxmlGetLastChild">mxmlGetLastChild</a></li>
+<li><a href="#mxmlGetNextSibling">mxmlGetNextSibling</a></li>
+<li><a href="#mxmlGetOpaque">mxmlGetOpaque</a></li>
+<li><a href="#mxmlGetParent">mxmlGetParent</a></li>
+<li><a href="#mxmlGetPrevSibling">mxmlGetPrevSibling</a></li>
+<li><a href="#mxmlGetReal">mxmlGetReal</a></li>
+<li><a href="#mxmlGetRefCount">mxmlGetRefCount</a></li>
+<li><a href="#mxmlGetText">mxmlGetText</a></li>
+<li><a href="#mxmlGetType">mxmlGetType</a></li>
+<li><a href="#mxmlGetUserData">mxmlGetUserData</a></li>
+<li><a href="#mxmlIndexDelete">mxmlIndexDelete</a></li>
+<li><a href="#mxmlIndexEnum">mxmlIndexEnum</a></li>
+<li><a href="#mxmlIndexFind">mxmlIndexFind</a></li>
+<li><a href="#mxmlIndexGetCount">mxmlIndexGetCount</a></li>
+<li><a href="#mxmlIndexNew">mxmlIndexNew</a></li>
+<li><a href="#mxmlIndexReset">mxmlIndexReset</a></li>
+<li><a href="#mxmlLoadFd">mxmlLoadFd</a></li>
+<li><a href="#mxmlLoadFile">mxmlLoadFile</a></li>
+<li><a href="#mxmlLoadString">mxmlLoadString</a></li>
+<li><a href="#mxmlNewCDATA">mxmlNewCDATA</a></li>
+<li><a href="#mxmlNewCustom">mxmlNewCustom</a></li>
+<li><a href="#mxmlNewElement">mxmlNewElement</a></li>
+<li><a href="#mxmlNewInteger">mxmlNewInteger</a></li>
+<li><a href="#mxmlNewOpaque">mxmlNewOpaque</a></li>
+<li><a href="#mxmlNewOpaquef">mxmlNewOpaquef</a></li>
+<li><a href="#mxmlNewReal">mxmlNewReal</a></li>
+<li><a href="#mxmlNewText">mxmlNewText</a></li>
+<li><a href="#mxmlNewTextf">mxmlNewTextf</a></li>
+<li><a href="#mxmlNewXML">mxmlNewXML</a></li>
+<li><a href="#mxmlRelease">mxmlRelease</a></li>
+<li><a href="#mxmlRemove">mxmlRemove</a></li>
+<li><a href="#mxmlRetain">mxmlRetain</a></li>
+<li><a href="#mxmlSAXLoadFd">mxmlSAXLoadFd</a></li>
+<li><a href="#mxmlSAXLoadFile">mxmlSAXLoadFile</a></li>
+<li><a href="#mxmlSAXLoadString">mxmlSAXLoadString</a></li>
+<li><a href="#mxmlSaveAllocString">mxmlSaveAllocString</a></li>
+<li><a href="#mxmlSaveFd">mxmlSaveFd</a></li>
+<li><a href="#mxmlSaveFile">mxmlSaveFile</a></li>
+<li><a href="#mxmlSaveString">mxmlSaveString</a></li>
+<li><a href="#mxmlSetCDATA">mxmlSetCDATA</a></li>
+<li><a href="#mxmlSetCustom">mxmlSetCustom</a></li>
+<li><a href="#mxmlSetCustomHandlers">mxmlSetCustomHandlers</a></li>
+<li><a href="#mxmlSetElement">mxmlSetElement</a></li>
+<li><a href="#mxmlSetErrorCallback">mxmlSetErrorCallback</a></li>
+<li><a href="#mxmlSetInteger">mxmlSetInteger</a></li>
+<li><a href="#mxmlSetOpaque">mxmlSetOpaque</a></li>
+<li><a href="#mxmlSetOpaquef">mxmlSetOpaquef</a></li>
+<li><a href="#mxmlSetReal">mxmlSetReal</a></li>
+<li><a href="#mxmlSetText">mxmlSetText</a></li>
+<li><a href="#mxmlSetTextf">mxmlSetTextf</a></li>
+<li><a href="#mxmlSetUserData">mxmlSetUserData</a></li>
+<li><a href="#mxmlSetWrapMargin">mxmlSetWrapMargin</a></li>
+<li><a href="#mxmlWalkNext">mxmlWalkNext</a></li>
+<li><a href="#mxmlWalkPrev">mxmlWalkPrev</a></li>
+</ul></li>
+<li><a href="#TYPES">Data Types</a><ul class="subcontents">
+<li><a href="#mxml_custom_destroy_cb_t">mxml_custom_destroy_cb_t</a></li>
+<li><a href="#mxml_custom_load_cb_t">mxml_custom_load_cb_t</a></li>
+<li><a href="#mxml_custom_save_cb_t">mxml_custom_save_cb_t</a></li>
+<li><a href="#mxml_entity_cb_t">mxml_entity_cb_t</a></li>
+<li><a href="#mxml_error_cb_t">mxml_error_cb_t</a></li>
+<li><a href="#mxml_index_t">mxml_index_t</a></li>
+<li><a href="#mxml_load_cb_t">mxml_load_cb_t</a></li>
+<li><a href="#mxml_node_t">mxml_node_t</a></li>
+<li><a href="#mxml_save_cb_t">mxml_save_cb_t</a></li>
+<li><a href="#mxml_sax_cb_t">mxml_sax_cb_t</a></li>
+<li><a href="#mxml_sax_event_t">mxml_sax_event_t</a></li>
+<li><a href="#mxml_type_t">mxml_type_t</a></li>
+</ul></li>
+<li><a href="#ENUMERATIONS">Enumerations</a><ul class="subcontents">
+<li><a href="#mxml_sax_event_e">mxml_sax_event_e</a></li>
+<li><a href="#mxml_type_e">mxml_type_e</a></li>
+</ul></li>
+</ul>
+</div>
+<div class="body">
+<h2 class="title" id="introduction">Introduction</h2>
+<p>Mini-XML is a small XML parsing library that you can use to read XML data files or strings in your application without requiring large non-standard libraries. Mini-XML provides the following functionality:</p>
+<ul>
+<li><p>Reading of UTF-8 and UTF-16 and writing of UTF-8 encoded XML files and strings.</p>
+</li>
+<li><p>Data is stored in a linked-list tree structure, preserving the XML data hierarchy.</p>
+</li>
+<li><p>SAX (streamed) reading of XML files and strings to minimize memory usage.</p>
+</li>
+<li><p>Supports arbitrary element names, attributes, and attribute values with no preset limits, just available memory.</p>
+</li>
+<li><p>Supports integer, real, opaque (&quot;cdata&quot;), and text data types in &quot;leaf&quot; nodes.</p>
+</li>
+<li><p>Functions for creating and managing trees of data.</p>
+</li>
+<li><p>&quot;Find&quot; and &quot;walk&quot; functions for easily locating and navigating trees of data.</p>
+</li>
+</ul>
+<p>Mini-XML doesn't do validation or other types of processing on the data based upon schema files or other sources of definition information.</p>
+<h3 class="title" id="history">History</h3>
+<p>Mini-XML was initially developed for the <a href="http://gutenprint.sf.net/">Gutenprint</a> project to replace the rather large and unwieldy <code>libxml2</code> library with something substantially smaller and easier-to-use. It all began one morning in June of 2003 when Robert posted the following sentence to the developer's list:</p>
+<blockquote>
+<p>It's bad enough that we require libxml2, but rolling our own XML parser is a bit more than we can handle.</p>
+</blockquote>
+<p>I then replied with:</p>
+<blockquote>
+<p>Given the limited scope of what you use in XML, it should be trivial to code a mini-XML API in a few hundred lines of code.</p>
+</blockquote>
+<p>I took my own challenge and coded furiously for two days to produced the initial public release of Mini-XML, total lines of code: 696. Robert promptly integrated Mini-XML into Gutenprint and removed libxml2.</p>
+<p>Thanks to lots of feedback and support from various developers, Mini-XML has evolved since then to provide a more complete XML implementation and now stands at a whopping 4,300 lines of code, compared to 196,141 lines of code for libxml2 version 2.9.9.</p>
+<h3 class="title" id="resources">Resources</h3>
+<p>The Mini-XML home page can be found at <a href="https://www.msweet.org/mxml">https://www.msweet.org/mxml</a>. From there you can download the current version of Mini-XML, access the issue tracker, and find other resources.</p>
+<h3 class="title" id="legal-stuff">Legal Stuff</h3>
+<p>The Mini-XML library is copyright © 2003-2021 by Michael R Sweet and is provided under the Apache License Version 2.0 with an exception to allow linking against GPL2/LGPL2-only software. See the files &quot;LICENSE&quot; and &quot;NOTICE&quot; for more information.</p>
+<h2 class="title" id="using-mini-xml">Using Mini-XML</h2>
+<p>Mini-XML provides a single header file which you include:</p>
+<pre><code>#include &lt;mxml.h&gt;
+</code></pre>
+<p>The Mini-XML library is included with your program using the <code>-lmxml</code> option:</p>
+<pre><code>gcc -o myprogram myprogram.c -lmxml
+</code></pre>
+<p>If you have the <code>pkg-config</code> software installed, you can use it to determine the proper compiler and linker options for your installation:</p>
+<pre><code>gcc `pkg-config --cflags mxml` -o myprogram myprogram.c `pkg-config --libs mxml`
+</code></pre>
+<h3 class="title" id="loading-an-xml-file">Loading an XML File</h3>
+<p>You load an XML file using the <code>mxmlLoadFile</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlLoadFile(mxml_node_t *top, FILE *fp,
+             mxml_type_t (*cb)(mxml_node_t *));
+</code></pre>
+<p>The <code>cb</code> argument specifies a function that assigns child (value) node types for each element in the document. The callback can be a function you provide or one of the standard functions provided with Mini-XML. For example, to load the XML file &quot;filename.xml&quot; containing text strings you can use the <code>MXML_OPAQUE_CALLBACK</code> function:</p>
+<pre><code>FILE *fp;
+mxml_node_t *tree;
+
+fp = fopen(&quot;filename.xml&quot;, &quot;r&quot;);
+tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
+fclose(fp);
+</code></pre>
+<p>Mini-XML also provides functions to load from a file descriptor or string:</p>
+<pre><code>mxml_node_t *
+mxmlLoadFd(mxml_node_t *top, int fd,
+           mxml_type_t (*cb)(mxml_node_t *));
+
+mxml_node_t *
+mxmlLoadString(mxml_node_t *top, const char *s,
+               mxml_type_t (*cb)(mxml_node_t *));
+</code></pre>
+<h4 id="load-callbacks">Load Callbacks</h4>
+<p>The last argument to the <code>mxmlLoad</code> functions is a callback function which is used to determine the value type of each data node in an XML document. Mini-XML defines several standard callbacks for simple XML data files:</p>
+<ul>
+<li><p><code>MXML_INTEGER_CALLBACK</code>: All data nodes contain whitespace-separated integers.</p>
+</li>
+<li><p><code>MXML_OPAQUE_CALLBACK</code>: All data nodes contain opaque strings with whitespace preserved.</p>
+</li>
+<li><p><code>MXML_REAL_CALLBACK</code> - All data nodes contain whitespace-separated floating-point numbers.</p>
+</li>
+<li><p><code>MXML_TEXT_CALLBACK</code> - All data nodes contain whitespace-separated strings.</p>
+</li>
+</ul>
+<p>You can provide your own callback functions for more complex XML documents. Your callback function will receive a pointer to the current element node and must return the value type of the immediate children for that element node: <code>MXML_CUSTOM</code>, <code>MXML_INTEGER</code>, <code>MXML_OPAQUE</code>, <code>MXML_REAL</code>, or <code>MXML_TEXT</code>. The function is called <em>after</em> the element and its attributes have been read, so you can look at the element name, attributes, and attribute values to determine the proper value type to return.</p>
+<p>The following callback function looks for an attribute named &quot;type&quot; or the element name to determine the value type for its child nodes:</p>
+<pre><code>mxml_type_t
+type_cb(mxml_node_t *node)
+{
+  const char *type;
+
+ /*
+  * You can lookup attributes and/or use the element name,
+  * hierarchy, etc...
+  */
+
+  type = mxmlElementGetAttr(node, &quot;type&quot;);
+  if (type == NULL)
+    type = mxmlGetElement(node);
+
+  if (!strcmp(type, &quot;integer&quot;))
+    return (MXML_INTEGER);
+  else if (!strcmp(type, &quot;opaque&quot;))
+    return (MXML_OPAQUE);
+  else if (!strcmp(type, &quot;real&quot;))
+    return (MXML_REAL);
+  else
+    return (MXML_TEXT);
+}
+</code></pre>
+<p>To use this callback function, simply use the name when you call any of the load functions:</p>
+<pre><code>FILE *fp;
+mxml_node_t *tree;
+
+fp = fopen(&quot;filename.xml&quot;, &quot;r&quot;);
+tree = mxmlLoadFile(NULL, fp, type_cb);
+fclose(fp);
+</code></pre>
+<h3 class="title" id="nodes">Nodes</h3>
+<p>Every piece of information in an XML file is stored in memory in &quot;nodes&quot;. Nodes are defined by the <code>mxml_node_t</code> structure. Each node has a typed value, optional user data, a parent node, sibling nodes (previous and next), and potentially child nodes.</p>
+<p>For example, if you have an XML file like the following:</p>
+<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;data&gt;
+    &lt;node&gt;val1&lt;/node&gt;
+    &lt;node&gt;val2&lt;/node&gt;
+    &lt;node&gt;val3&lt;/node&gt;
+    &lt;group&gt;
+        &lt;node&gt;val4&lt;/node&gt;
+        &lt;node&gt;val5&lt;/node&gt;
+        &lt;node&gt;val6&lt;/node&gt;
+    &lt;/group&gt;
+    &lt;node&gt;val7&lt;/node&gt;
+    &lt;node&gt;val8&lt;/node&gt;
+&lt;/data&gt;
+</code></pre>
+<p>the node tree for the file would look like the following in memory:</p>
+<pre><code>?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?
+  |
+data
+  |
+node - node - node - group - node - node
+  |      |      |      |       |      |
+val1   val2   val3     |     val7   val8
+                       |
+                     node - node - node
+                       |      |      |
+                     val4   val5   val6
+</code></pre>
+<p>where &quot;-&quot; is a pointer to the sibling node and &quot;|&quot; is a pointer to the first child or parent node.</p>
+<p>The <code>mxmlGetType</code> function gets the type of a node:</p>
+<pre><code>mxml_type_t
+mxmlGetType(mxml_node_t *node);
+</code></pre>
+<ul>
+<li><p><code>MXML_CUSTOM</code> : A custom value defined by your application,</p>
+</li>
+<li><p><code>MXML_ELEMENT</code> : An XML element, CDATA, comment, or processing instruction,</p>
+</li>
+<li><p><code>MXML_INTEGER</code> : A whitespace-delimited integer value,</p>
+</li>
+<li><p><code>MXML_OPAQUE</code> : An opaque string value that preserves all whitespace,</p>
+</li>
+<li><p><code>MXML_REAL</code> : A whitespace-delimited floating point value, or</p>
+</li>
+<li><p><code>MXML_TEXT</code> : A whitespace-delimited text (fragment) value.</p>
+</li>
+</ul>
+<blockquote>
+<p>Note: CDATA, comment, and processing directive nodes are currently stored in memory as special elements. This will be changed in a future major release of Mini-XML.</p>
+</blockquote>
+<p>The parent and sibling nodes are accessed using the <code>mxmlGetParent</code>, <code>mxmlGetNextSibling</code>, and <code>mxmlGetPreviousSibling</code> functions, while the children of an element node are accessed using the <code>mxmlGetFirstChild</code> or <code>mxmlGetLastChild</code> functions:</p>
+<pre><code>mxml_node_t *
+mxmlGetFirstChild(mxml_node_t *node);
+
+mxml_node_t *
+mxmlGetLastChild(mxml_node_t *node);
+
+mxml_node_t *
+mxmlGetNextSibling(mxml_node_t *node);
+
+mxml_node_t *
+mxmlGetParent(mxml_node_t *node);
+
+mxml_node_t *
+mxmlGetPrevSibling(mxml_node_t *node);
+</code></pre>
+<p>The <code>mxmlGetUserData</code> function gets any user (application) data associated with the node:</p>
+<pre><code>void *
+mxmlGetUserData(mxml_node_t *node);
+</code></pre>
+<h3 class="title" id="creating-xml-documents">Creating XML Documents</h3>
+<p>You can create and update XML documents in memory using the various <code>mxmlNew</code> functions. The following code will create the XML document described in the previous section:</p>
+<pre><code>mxml_node_t *xml;    /* &lt;?xml ... ?&gt; */
+mxml_node_t *data;   /* &lt;data&gt; */
+mxml_node_t *node;   /* &lt;node&gt; */
+mxml_node_t *group;  /* &lt;group&gt; */
+
+xml = mxmlNewXML(&quot;1.0&quot;);
+
+data = mxmlNewElement(xml, &quot;data&quot;);
+
+    node = mxmlNewElement(data, &quot;node&quot;);
+    mxmlNewText(node, 0, &quot;val1&quot;);
+    node = mxmlNewElement(data, &quot;node&quot;);
+    mxmlNewText(node, 0, &quot;val2&quot;);
+    node = mxmlNewElement(data, &quot;node&quot;);
+    mxmlNewText(node, 0, &quot;val3&quot;);
+
+    group = mxmlNewElement(data, &quot;group&quot;);
+
+        node = mxmlNewElement(group, &quot;node&quot;);
+        mxmlNewText(node, 0, &quot;val4&quot;);
+        node = mxmlNewElement(group, &quot;node&quot;);
+        mxmlNewText(node, 0, &quot;val5&quot;);
+        node = mxmlNewElement(group, &quot;node&quot;);
+        mxmlNewText(node, 0, &quot;val6&quot;);
+
+    node = mxmlNewElement(data, &quot;node&quot;);
+    mxmlNewText(node, 0, &quot;val7&quot;);
+    node = mxmlNewElement(data, &quot;node&quot;);
+    mxmlNewText(node, 0, &quot;val8&quot;);
+</code></pre>
+<p>We start by creating the declaration node common to all XML files using the <code>mxmlNewXML</code> function:</p>
+<pre><code>xml = mxmlNewXML(&quot;1.0&quot;);
+</code></pre>
+<p>We then create the <code>&lt;data&gt;</code> node used for this document using the <code>mxmlNewElement</code> function. The first argument specifies the parent node (<code>xml</code>) while the second specifies the element name (<code>data</code>):</p>
+<pre><code>data = mxmlNewElement(xml, &quot;data&quot;);
+</code></pre>
+<p>Each <code>&lt;node&gt;...&lt;/node&gt;</code> in the file is created using the <code>mxmlNewElement</code> and <code>mxmlNewText</code> functions. The first argument of <code>mxmlNewText</code> specifies the parent node (<code>node</code>). The second argument specifies whether whitespace appears before the text - 0 or false in this case. The last argument specifies the actual text to add:</p>
+<pre><code>node = mxmlNewElement(data, &quot;node&quot;);
+mxmlNewText(node, 0, &quot;val1&quot;);
+</code></pre>
+<p>The resulting in-memory XML document can then be saved or processed just like one loaded from disk or a string.</p>
+<h3 class="title" id="saving-an-xml-file">Saving an XML File</h3>
+<p>You save an XML file using the <code>mxmlSaveFile</code> function:</p>
+<pre><code>int
+mxmlSaveFile(mxml_node_t *node, FILE *fp,
+             mxml_save_cb_t cb);
+</code></pre>
+<p>The <code>cb</code> argument specifies a function that returns the whitespace (if any) that is inserted before and after each element node. The <code>MXML_NO_CALLBACK</code> constant tells Mini-XML to not include any extra whitespace. For example, so save an XML file to the file &quot;filename.xml&quot; with no extra whitespace:</p>
+<pre><code>FILE *fp;
+
+fp = fopen(&quot;filename.xml&quot;, &quot;w&quot;);
+mxmlSaveFile(xml, fp, MXML_NO_CALLBACK);
+fclose(fp);
+</code></pre>
+<p>Mini-XML also provides functions to save to a file descriptor or strings:</p>
+<pre><code>char *
+mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t cb);
+
+int
+mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t cb);
+
+int
+mxmlSaveString(mxml_node_t *node, char *buffer, int bufsize,
+               mxml_save_cb_t cb);
+</code></pre>
+<h4 id="controlling-line-wrapping">Controlling Line Wrapping</h4>
+<p>When saving XML documents, Mini-XML normally wraps output lines at column 75 so that the text is readable in terminal windows. The <code>mxmlSetWrapMargin</code> function overrides the default wrap margin for the current thread:</p>
+<pre><code>void mxmlSetWrapMargin(int column);
+</code></pre>
+<p>For example, the following code sets the margin to 132 columns:</p>
+<pre><code>mxmlSetWrapMargin(132);
+</code></pre>
+<p>while the following code disables wrapping by setting the margin to 0:</p>
+<pre><code>mxmlSetWrapMargin(0);
+</code></pre>
+<h4 id="save-callbacks">Save Callbacks</h4>
+<p>The last argument to the <code>mxmlSave</code> functions is a callback function which is used to automatically insert whitespace in an XML document. Your callback function will be called up to four times for each element node with a pointer to the node and a &quot;where&quot; value of <code>MXML_WS_BEFORE_OPEN</code>, <code>MXML_WS_AFTER_OPEN</code>, <code>MXML_WS_BEFORE_CLOSE</code>, or <code>MXML_WS_AFTER_CLOSE</code>. The callback function should return <code>NULL</code> if no whitespace should be added or the string to insert (spaces, tabs, carriage returns, and newlines) otherwise.</p>
+<p>The following whitespace callback can be used to add whitespace to XHTML output to make it more readable in a standard text editor:</p>
+<pre><code>const char *
+whitespace_cb(mxml_node_t *node, int where)
+{
+  const char *element;
+
+ /*
+  * We can conditionally break to a new line before or after
+  * any element.  These are just common HTML elements...
+  */
+
+  element = mxmlGetElement(node);
+
+  if (!strcmp(element, &quot;html&quot;) ||
+      !strcmp(element, &quot;head&quot;) ||
+      !strcmp(element, &quot;body&quot;) ||
+      !strcmp(element, &quot;pre&quot;) ||
+      !strcmp(element, &quot;p&quot;) ||
+      !strcmp(element, &quot;h1&quot;) ||
+      !strcmp(element, &quot;h2&quot;) ||
+      !strcmp(element, &quot;h3&quot;) ||
+      !strcmp(element, &quot;h4&quot;) ||
+      !strcmp(element, &quot;h5&quot;) ||
+      !strcmp(element, &quot;h6&quot;))
+  {
+   /*
+    * Newlines before open and after close...
+    */
+
+    if (where == MXML_WS_BEFORE_OPEN ||
+        where == MXML_WS_AFTER_CLOSE)
+      return (&quot;\n&quot;);
+  }
+  else if (!strcmp(element, &quot;dl&quot;) ||
+           !strcmp(element, &quot;ol&quot;) ||
+           !strcmp(element, &quot;ul&quot;))
+  {
+   /*
+    * Put a newline before and after list elements...
+    */
+
+    return (&quot;\n&quot;);
+  }
+  else if (!strcmp(element, &quot;dd&quot;) ||
+           !strcmp(element, &quot;dt&quot;) ||
+           !strcmp(element, &quot;li&quot;))
+  {
+   /*
+    * Put a tab before &lt;li&gt;'s, &lt;dd&gt;'s, and &lt;dt&gt;'s, and a
+    * newline after them...
+    */
+
+    if (where == MXML_WS_BEFORE_OPEN)
+      return (&quot;\t&quot;);
+    else if (where == MXML_WS_AFTER_CLOSE)
+      return (&quot;\n&quot;);
+  }
+
+ /*
+  * Otherwise return NULL for no added whitespace...
+  */
+
+  return (NULL);
+}
+</code></pre>
+<p>To use this callback function, simply use the name when you call any of the save functions:</p>
+<pre><code>FILE *fp;
+mxml_node_t *tree;
+
+fp = fopen(&quot;filename.xml&quot;, &quot;w&quot;);
+mxmlSaveFile(tree, fp, whitespace_cb);
+fclose(fp);
+</code></pre>
+<h3 class="title" id="memory-management">Memory Management</h3>
+<p>Once you are done with the XML data, use the <code>mxmlDelete</code> function to recursively free the memory that is used for a particular node or the entire tree:</p>
+<pre><code>void
+mxmlDelete(mxml_node_t *tree);
+</code></pre>
+<p>You can also use reference counting to manage memory usage. The <code>mxmlRetain</code> and <code>mxmlRelease</code> functions increment and decrement a node's use count, respectively. When the use count goes to zero, <code>mxmlRelease</code> automatically calls <code>mxmlDelete</code> to actually free the memory used by the node tree. New nodes start with a use count of 1.</p>
+<h2 class="title" id="more-about-nodes">More About Nodes</h2>
+<h3 class="title" id="element-nodes">Element Nodes</h3>
+<p>Element (<code>MXML_ELEMENT</code>) nodes are created using the <code>mxmlNewElement</code> function. Element attributes are set using the <code>mxmlElementSetAttr</code> and <code>mxmlElementSetAttrf</code> functions and cleared using the <code>mxmlElementDeleteAttr</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlNewElement(mxml_node_t *parent, const char *name);
+
+void
+mxmlElementDeleteAttr(mxml_node_t *node, const char *name);
+
+void
+mxmlElementSetAttr(mxml_node_t *node, const char *name,
+                   const char *value);
+
+void
+mxmlElementSetAttrf(mxml_node_t *node, const char *name,
+                    const char *format, ...);
+</code></pre>
+<p>Child nodes are added using the various <code>mxmlNew</code> functions. The top (root) node must be an element, usually created by the <code>mxmlNewXML</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlNewXML(const char *version);
+</code></pre>
+<p>The <code>mxmlGetElement</code> function retrieves the element name, the <code>mxmlElementGetAttr</code> function retrieves the value string for a named attribute associated with the element. The <code>mxmlElementGetAttrByIndex</code> and <code>mxmlElementGetAttrCount</code> functions retrieve attributes by index:</p>
+<pre><code>const char *
+mxmlGetElement(mxml_node_t *node);
+
+const char *
+mxmlElementGetAttr(mxml_node_t *node, const char *name);
+
+const char *
+mxmlElementGetAttrByIndex(mxml_node_t *node, int idx,
+                          const char **name);
+
+int
+mxmlElementGetAttrCount(mxml_node_t *node);
+</code></pre>
+<h3 class="title" id="cdata-nodes">CDATA Nodes</h3>
+<p>CDATA (<code>MXML_ELEMENT</code>) nodes are created using the <code>mxmlNewCDATA</code> function:</p>
+<pre><code>mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
+</code></pre>
+<p>The <code>mxmlGetCDATA</code> function retrieves the CDATA string pointer for a node:</p>
+<pre><code>const char *mxmlGetCDATA(mxml_node_t *node);
+</code></pre>
+<h3 class="title" id="comment-nodes">Comment Nodes</h3>
+<p>Because comments are currently stored as element nodes, comment (<code>MXML_ELEMENT</code>) nodes are created using the <code>mxmlNewElement</code> function by including the surrounding &quot;!--&quot; and &quot;--&quot; characters in the element name, for example:</p>
+<pre><code>mxml_node_t *node = mxmlNewElement(&quot;!-- This is a comment --&quot;);
+</code></pre>
+<p>Similarly, the <code>mxmlGetElement</code> function retrieves the comment string pointer for a node, which includes the surrounding &quot;!--&quot; and &quot;--&quot; characters.</p>
+<pre><code>const char *comment = mxmlGetElement(node);
+/* returns &quot;!-- This is a comment --&quot; */
+</code></pre>
+<h3 class="title" id="processing-instruction-nodes">Processing Instruction Nodes</h3>
+<p>Because processing instructions are currently stored as element nodes, processing instruction (<code>MXML_ELEMENT</code>) nodes are created using the <code>mxmlNewElement</code> function including the surrounding &quot;?&quot; characters:</p>
+<pre><code>mxml_node_t *node = mxmlNewElement(&quot;?xml-stylesheet type=\&quot;text/css\&quot; href=\&quot;style.css\&quot;?&quot;);
+</code></pre>
+<p>The <code>mxmlGetElement</code> function retrieves the processing instruction string for a node, including the surrounding &quot;?&quot; characters:</p>
+<pre><code>const char *instr = mxmlGetElement(node);
+/* returned &quot;?xml-stylesheet type=\&quot;text/css\&quot; href=\&quot;style.css\&quot;?&quot; */
+</code></pre>
+<h3 class="title" id="integer-nodes">Integer Nodes</h3>
+<p>Integer (<code>MXML_INTEGER</code>) nodes are created using the <code>mxmlNewInteger</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlNewInteger(mxml_node_t *parent, int integer);
+</code></pre>
+<p>The <code>mxmlGetInteger</code> function retrieves the integer value for a node:</p>
+<pre><code>int
+mxmlGetInteger(mxml_node_t *node);
+</code></pre>
+<h3 class="title" id="opaque-string-nodes">Opaque String Nodes</h3>
+<p>Opaque string (<code>MXML_OPAQUE</code>) nodes are created using the <code>mxmlNewOpaque</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
+</code></pre>
+<p>The <code>mxmlGetOpaque</code> function retrieves the opaque string pointer for a node:</p>
+<pre><code>const char *
+mxmlGetOpaque(mxml_node_t *node);
+</code></pre>
+<h3 class="title" id="text-nodes">Text Nodes</h3>
+<p>Whitespace-delimited text string (<code>MXML_TEXT</code>) nodes are created using the <code>mxmlNewText</code> and <code>mxmlNewTextf</code> functions. Each text node consists of a text string and (leading) whitespace flag value.</p>
+<pre><code>mxml_node_t *
+mxmlNewText(mxml_node_t *parent, int whitespace,
+            const char *string);
+
+mxml_node_t *
+mxmlNewTextf(mxml_node_t *parent, int whitespace,
+             const char *format, ...);
+</code></pre>
+<p>The <code>mxmlGetText</code> function retrieves the text string pointer and whitespace flag value for a node:</p>
+<pre><code> const char *
+ mxmlGetText(mxml_node_t *node, int *whitespace);
+</code></pre>
+<h3 class="title" id="real-number-nodes">Real Number Nodes</h3>
+<p>Real number (<code>MXML_REAL</code>) nodes are created using the <code>mxmlNewReal</code> function:</p>
+<pre><code>mxml_node_t *
+mxmlNewReal(mxml_node_t *parent, double real);
+</code></pre>
+<p>The <code>mxmlGetReal</code> function retrieves the real number for a node:</p>
+<pre><code>double
+mxmlGetReal(mxml_node_t *node);
+</code></pre>
+<h2 class="title" id="locating-data-in-an-xml-document">Locating Data in an XML Document</h2>
+<p>Mini-XML provides many functions for enumerating, searching, and indexing XML documents.</p>
+<h3 class="title" id="finding-nodes">Finding Nodes</h3>
+<p>The <code>mxmlFindPath</code> function finds the (first) value node under a specific element using a &quot;path&quot;:</p>
+<pre><code>mxml_node_t *
+mxmlFindPath(mxml_node_t *node, const char *path);
+</code></pre>
+<p>The <code>path</code> string can contain the &quot;*&quot; wildcard to match a single element node in the hierarchy. For example, the following code will find the first &quot;node&quot; element under the &quot;group&quot; element, first using an explicit path and then using a wildcard:</p>
+<pre><code>mxml_node_t *value = mxmlFindPath(xml, &quot;data/group/node&quot;);
+
+mxml_node_t *value = mxmlFindPath(xml, &quot;data/*/node&quot;);
+</code></pre>
+<p>The <code>mxmlFindElement</code> function can be used to find a named element, optionally matching an attribute and value:</p>
+<pre><code>mxml_node_t *
+mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
+                const char *element, const char *attr,
+                const char *value, int descend);
+</code></pre>
+<p>The &quot;element&quot;, &quot;attr&quot;, and &quot;value&quot; arguments can be passed as <code>NULL</code> to act as wildcards, e.g.:</p>
+<pre><code>/* Find the first &quot;a&quot; element */
+node = mxmlFindElement(tree, tree, &quot;a&quot;, NULL, NULL,
+                       MXML_DESCEND);
+
+/* Find the first &quot;a&quot; element with &quot;href&quot; attribute */
+node = mxmlFindElement(tree, tree, &quot;a&quot;, &quot;href&quot;, NULL,
+                       MXML_DESCEND);
+
+/* Find the first &quot;a&quot; element with &quot;href&quot; to a URL */
+node = mxmlFindElement(tree, tree, &quot;a&quot;, &quot;href&quot;,
+                       &quot;http://michaelrsweet.github.io/&quot;,
+                       MXML_DESCEND);
+
+/* Find the first element with a &quot;src&quot; attribute*/
+node = mxmlFindElement(tree, tree, NULL, &quot;src&quot;, NULL,
+                       MXML_DESCEND);
+
+/* Find the first element with a &quot;src&quot; = &quot;foo.jpg&quot; */
+node = mxmlFindElement(tree, tree, NULL, &quot;src&quot;, &quot;foo.jpg&quot;,
+                       MXML_DESCEND);
+</code></pre>
+<p>You can also iterate with the same function:</p>
+<pre><code>mxml_node_t *node;
+
+for (node = mxmlFindElement(tree, tree, &quot;element&quot;, NULL,
+                            NULL, MXML_DESCEND);
+     node != NULL;
+     node = mxmlFindElement(node, tree, &quot;element&quot;, NULL,
+                            NULL, MXML_DESCEND))
+{
+  ... do something ...
+}
+</code></pre>
+<p>The <code>descend</code> argument (<code>MXML_DESCEND</code> in the examples above) can be one of three constants:</p>
+<ul>
+<li><p><code>MXML_NO_DESCEND</code>: ignore child nodes in the element hierarchy, instead using siblings (same level) or parent nodes (above) until the top (root) node is reached.</p>
+</li>
+<li><p><code>MXML_DESCEND_FIRST</code>: start the search with the first child of the node, and then search siblings. You'll normally use this when iterating through direct children of a parent node, e.g. all of the &quot;node&quot; and &quot;group&quot; elements under the &quot;?xml&quot; parent node in the previous example.</p>
+</li>
+<li><p><code>MXML_DESCEND</code>: search child nodes first, then sibling nodes, and then parent nodes.</p>
+</li>
+</ul>
+<h3 class="title" id="iterating-nodes">Iterating Nodes</h3>
+<p>While the <code>mxmlFindNode</code> and <code>mxmlFindPath</code> functions will find a particular element node, sometimes you need to iterate over all nodes. The <code>mxmlWalkNext</code> and <code>mxmlWalkPrev</code> functions can be used to iterate through the XML node tree:</p>
+<pre><code>mxml_node_t *
+mxmlWalkNext(mxml_node_t *node, mxml_node_t *top,
+             int descend);
+
+mxml_node_t *
+mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
+             int descend);
+</code></pre>
+<p>Depending on the value of the <code>descend</code> argument, these functions will automatically traverse child, sibling, and parent nodes until the <code>top</code> node is reached. For example, the following code will iterate over all of the nodes in the sample XML document in the previous section:</p>
+<pre><code>mxml_node_t *node;
+
+for (node = xml;
+     node != NULL;
+     node = mxmlWalkNext(node, xml, MXML_DESCEND))
+{
+  ... do something ...
+}
+</code></pre>
+<p>The nodes will be returned in the following order:</p>
+<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;data&gt;
+&lt;node&gt;
+val1
+&lt;node&gt;
+val2
+&lt;node&gt;
+val3
+&lt;group&gt;
+&lt;node&gt;
+val4
+&lt;node&gt;
+val5
+&lt;node&gt;
+val6
+&lt;node&gt;
+val7
+&lt;node&gt;
+val8
+</code></pre>
+<h3 class="title" id="indexing">Indexing</h3>
+<p>The <code>mxmlIndexNew</code> function allows you to create an index of nodes for faster searching and enumeration:</p>
+<pre><code>mxml_index_t *
+mxmlIndexNew(mxml_node_t *node, const char *element,
+             const char *attr);
+</code></pre>
+<p>The <code>element</code> and <code>attr</code> arguments control which elements are included in the index. If <code>element</code> is not <code>NULL</code> then only elements with the specified name are added to the index. Similarly, if <code>attr</code> is not <code>NULL</code> then only elements containing the specified attribute are added to the index. The nodes are sorted in the index.</p>
+<p>For example, the following code creates an index of all &quot;id&quot; values in an XML document:</p>
+<pre><code>mxml_index_t *ind = mxmlIndexNew(xml, NULL, &quot;id&quot;);
+</code></pre>
+<p>Once the index is created, the <code>mxmlIndexFind</code> function can be used to find a matching node:</p>
+<pre><code>mxml_node_t *
+mxmlIndexFind(mxml_index_t *ind, const char *element,
+              const char *value);
+</code></pre>
+<p>For example, the following code will find the element whose &quot;id&quot; string is &quot;42&quot;:</p>
+<pre><code>mxml_node_t *node = mxmlIndexFind(ind, NULL, &quot;42&quot;);
+</code></pre>
+<p>Alternately, the <code>mxmlIndexReset</code> and <code>mxmlIndexEnum</code> functions can be used to enumerate the nodes in the index:</p>
+<pre><code>mxml_node_t *
+mxmlIndexReset(mxml_index_t *ind);
+
+mxml_node_t *
+mxmlIndexEnum(mxml_index_t *ind);
+</code></pre>
+<p>Typically these functions will be used in a <code>for</code> loop:</p>
+<pre><code>mxml_node_t *node;
+
+for (node = mxmlIndexReset(ind);
+     node != NULL;
+     node = mxmlIndexEnum(ind))
+{
+  ... do something ...
+}
+</code></pre>
+<p>The <code>mxmlIndexCount</code> function returns the number of nodes in the index:</p>
+<pre><code>int
+mxmlIndexGetCount(mxml_index_t *ind);
+</code></pre>
+<p>Finally, the <code>mxmlIndexDelete</code> function frees all memory associated with the index:</p>
+<pre><code>void
+mxmlIndexDelete(mxml_index_t *ind);
+</code></pre>
+<h2 class="title" id="custom-data-types">Custom Data Types</h2>
+<p>Mini-XML supports custom data types via per-thread load and save callbacks. Only a single set of callbacks can be active at any time for the current thread, however your callbacks can store additional information in order to support multiple custom data types as needed. The <code>MXML_CUSTOM</code> node type identifies custom data nodes.</p>
+<p>The <code>mxmlGetCustom</code> function retrieves the custom value pointer for a node.</p>
+<pre><code>const void *
+mxmlGetCustom(mxml_node_t *node);
+</code></pre>
+<p>Custom (<code>MXML_CUSTOM</code>) nodes are created using the <code>mxmlNewCustom</code> function or using a custom per-thread load callbacks specified using the <code>mxmlSetCustomHandlers</code> function:</p>
+<pre><code>typedef void (*mxml_custom_destroy_cb_t)(void *);
+typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
+typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
+
+mxml_node_t *
+mxmlNewCustom(mxml_node_t *parent, void *data,
+              mxml_custom_destroy_cb_t destroy);
+
+int
+mxmlSetCustom(mxml_node_t *node, void *data,
+              mxml_custom_destroy_cb_t destroy);
+
+void
+mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
+                      mxml_custom_save_cb_t save);
+</code></pre>
+<p>The load callback receives a pointer to the current data node and a string of opaque character data from the XML source with character entities converted to the corresponding UTF-8 characters. For example, if we wanted to support a custom date/time type whose value is encoded as &quot;yyyy-mm-ddThh:mm:ssZ&quot; (ISO format), the load callback would look like the following:</p>
+<pre><code>typedef struct
+{
+  unsigned year,    /* Year */
+           month,   /* Month */
+           day,     /* Day */
+           hour,    /* Hour */
+           minute,  /* Minute */
+           second;  /* Second */
+  time_t   unix;    /* UNIX time */
+} iso_date_time_t;
+
+int
+load_custom(mxml_node_t *node, const char *data)
+{
+  iso_date_time_t *dt;
+  struct tm tmdata;
+
+ /*
+  * Allocate data structure...
+  */
+
+  dt = calloc(1, sizeof(iso_date_time_t));
+
+ /*
+  * Try reading 6 unsigned integers from the data string...
+  */
+
+  if (sscanf(data, &quot;%u-%u-%uT%u:%u:%uZ&quot;, &amp;(dt-&gt;year),
+             &amp;(dt-&gt;month), &amp;(dt-&gt;day), &amp;(dt-&gt;hour),
+             &amp;(dt-&gt;minute), &amp;(dt-&gt;second)) != 6)
+  {
+   /*
+    * Unable to read numbers, free the data structure and
+    * return an error...
+    */
+
+    free(dt);
+
+    return (-1);
+  }
+
+ /*
+  * Range check values...
+  */
+
+  if (dt-&gt;month &lt; 1 || dt-&gt;month &gt; 12 ||
+      dt-&gt;day &lt; 1 || dt-&gt;day &gt; 31 ||
+      dt-&gt;hour &lt; 0 || dt-&gt;hour &gt; 23 ||
+      dt-&gt;minute &lt; 0 || dt-&gt;minute &gt; 59 ||
+      dt-&gt;second &lt; 0 || dt-&gt;second &gt; 60)
+  {
+   /*
+    * Date information is out of range...
+    */
+
+    free(dt);
+
+    return (-1);
+  }
+
+ /*
+  * Convert ISO time to UNIX time in seconds...
+  */
+
+  tmdata.tm_year = dt-&gt;year - 1900;
+  tmdata.tm_mon  = dt-&gt;month - 1;
+  tmdata.tm_day  = dt-&gt;day;
+  tmdata.tm_hour = dt-&gt;hour;
+  tmdata.tm_min  = dt-&gt;minute;
+  tmdata.tm_sec  = dt-&gt;second;
+
+  dt-&gt;unix = gmtime(&amp;tmdata);
+
+ /*
+  * Assign custom node data and destroy (free) function
+  * pointers...
+  */
+
+  mxmlSetCustom(node, data, free);
+
+ /*
+  * Return with no errors...
+  */
+
+  return (0);
+}
+</code></pre>
+<p>The function itself can return 0 on success or -1 if it is unable to decode the custom data or the data contains an error. Custom data nodes contain a <code>void</code> pointer to the allocated custom data for the node and a pointer to a destructor function which will free the custom data when the node is deleted. In this example, we use the standard <code>free</code> function since everything is contained in a single calloc'd block.</p>
+<p>The save callback receives the node pointer and returns an allocated string containing the custom data value. The following save callback could be used for our ISO date/time type:</p>
+<pre><code>char *
+save_custom(mxml_node_t *node)
+{
+  char data[255];
+  iso_date_time_t *dt;
+
+
+  dt = (iso_date_time_t *)mxmlGetCustom(node);
+
+  snprintf(data, sizeof(data),
+           &quot;%04u-%02u-%02uT%02u:%02u:%02uZ&quot;,
+           dt-&gt;year, dt-&gt;month, dt-&gt;day, dt-&gt;hour,
+           dt-&gt;minute, dt-&gt;second);
+
+  return (strdup(data));
+}
+</code></pre>
+<p>You register the callback functions using the <code>mxmlSetCustomHandlers</code> function:</p>
+<pre><code>mxmlSetCustomHandlers(load_custom, save_custom);
+</code></pre>
+<h2 class="title" id="sax-stream-loading-of-documents">SAX (Stream) Loading of Documents</h2>
+<p>Mini-XML supports an implementation of the Simple API for XML (SAX) which allows you to load and process an XML document as a stream of nodes. Aside from allowing you to process XML documents of any size, the Mini-XML implementation also allows you to retain portions of the document in memory for later processing.</p>
+<p>The <code>mxmlSAXLoadFd</code>, <code>mxmlSAXLoadFile</code>, and <code>mxmlSAXLoadString</code> functions provide the SAX loading APIs:</p>
+<pre><code>mxml_node_t *
+mxmlSAXLoadFd(mxml_node_t *top, int fd,
+              mxml_type_t (*cb)(mxml_node_t *),
+              mxml_sax_cb_t sax, void *sax_data);
+
+mxml_node_t *
+mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
+                mxml_type_t (*cb)(mxml_node_t *),
+                mxml_sax_cb_t sax, void *sax_data);
+
+mxml_node_t *
+mxmlSAXLoadString(mxml_node_t *top, const char *s,
+                  mxml_type_t (*cb)(mxml_node_t *),
+                  mxml_sax_cb_t sax, void *sax_data);
+</code></pre>
+<p>Each function works like the corresponding <code>mxmlLoad</code> function but uses a callback to process each node as it is read. The callback function receives the node, an event code, and a user data pointer you supply:</p>
+<pre><code>void
+sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+       void *data)
+{
+  ... do something ...
+}
+</code></pre>
+<p>The event will be one of the following:</p>
+<ul>
+<li><p><code>MXML_SAX_CDATA</code>: CDATA was just read.</p>
+</li>
+<li><p><code>MXML_SAX_COMMENT</code>: A comment was just read.</p>
+</li>
+<li><p><code>MXML_SAX_DATA</code>: Data (custom, integer, opaque, real, or text) was just read.</p>
+</li>
+<li><p><code>MXML_SAX_DIRECTIVE</code>: A processing directive/instruction was just read.</p>
+</li>
+<li><p><code>MXML_SAX_ELEMENT_CLOSE</code> - A close element was just read (<code>&lt;/element&gt;</code>)</p>
+</li>
+<li><p><code>MXML_SAX_ELEMENT_OPEN</code> - An open element was just read (<code>&lt;element&gt;</code>)</p>
+</li>
+</ul>
+<p>Elements are <em>released</em> after the close element is processed. All other nodes are released after they are processed. The SAX callback can <em>retain</em> the node using the <code>mxmlRetain</code> function. For example, the following SAX callback will retain all nodes, effectively simulating a normal in-memory load:</p>
+<pre><code>void
+sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+       void *data)
+{
+  if (event != MXML_SAX_ELEMENT_CLOSE)
+    mxmlRetain(node);
+}
+</code></pre>
+<p>More typically the SAX callback will only retain a small portion of the document that is needed for post-processing. For example, the following SAX callback will retain the title and headings in an XHTML file. It also retains the (parent) elements like <code>&lt;html&gt;</code>, <code>&lt;head&gt;</code>, and <code>&lt;body&gt;</code>, and processing directives like <code>&lt;?xml ... ?&gt;</code> and <code>&lt;!DOCTYPE ... &gt;</code>:</p>
+<pre><code>void
+sax_cb(mxml_node_t *node, mxml_sax_event_t event,
+       void *data)
+{
+  if (event == MXML_SAX_ELEMENT_OPEN)
+  {
+   /*
+    * Retain headings and titles...
+    */
+
+    const char *element = mxmlGetElement(node);
+
+    if (!strcmp(element, &quot;html&quot;) ||
+        !strcmp(element, &quot;head&quot;) ||
+        !strcmp(element, &quot;title&quot;) ||
+        !strcmp(element, &quot;body&quot;) ||
+        !strcmp(element, &quot;h1&quot;) ||
+        !strcmp(element, &quot;h2&quot;) ||
+        !strcmp(element, &quot;h3&quot;) ||
+        !strcmp(element, &quot;h4&quot;) ||
+        !strcmp(element, &quot;h5&quot;) ||
+        !strcmp(element, &quot;h6&quot;))
+      mxmlRetain(node);
+  }
+  else if (event == MXML_SAX_DIRECTIVE)
+    mxmlRetain(node);
+  else if (event == MXML_SAX_DATA)
+  {
+    if (mxmlGetRefCount(mxmlGetParent(node)) &gt; 1)
+    {
+     /*
+      * If the parent was retained, then retain this data
+      * node as well.
+      */
+
+      mxmlRetain(node);
+    }
+  }
+}
+</code></pre>
+<p>The resulting skeleton document tree can then be searched just like one loaded using the <code>mxmlLoad</code> functions. For example, a filter that reads an XHTML document from stdin and then shows the title and headings in the document would look like:</p>
+<pre><code>mxml_node_t *doc, *title, *body, *heading;
+
+doc = mxmlSAXLoadFd(NULL, 0, MXML_TEXT_CALLBACK, sax_cb,
+                    NULL);
+
+title = mxmlFindElement(doc, doc, &quot;title&quot;, NULL, NULL,
+                        MXML_DESCEND);
+
+if (title)
+  print_children(title);
+
+body = mxmlFindElement(doc, doc, &quot;body&quot;, NULL, NULL,
+                       MXML_DESCEND);
+
+if (body)
+{
+  for (heading = mxmlGetFirstChild(body);
+       heading;
+       heading = mxmlGetNextSibling(heading))
+    print_children(heading);
+}
+</code></pre>
+<p>The <code>print_children</code> function is:</p>
+<pre><code>void
+print_children(mxml_node_t *parent)
+{
+  mxml_node_t *node;
+  const char *text;
+  int whitespace;
+
+  for (node = mxmlGetFirstChild(parent);
+       node != NULL;
+       node = mxmlGetNextSibling(node))
+  {
+    text = mxmlGetText(node, &amp;whitespace);
+
+    if (whitespace)
+      putchar(' ');
+
+    fputs(text, stdout);
+  }
+
+  putchar('\n');
+}
+</code></pre>
+<h2 class="title"><a id="FUNCTIONS">Functions</a></h2>
+<h3 class="function"><a id="mxmlAdd">mxmlAdd</a></h3>
+<p class="description">Add a node to a tree.</p>
+<p class="code">
+void mxmlAdd(<a href="#mxml_node_t">mxml_node_t</a> *parent, int where, <a href="#mxml_node_t">mxml_node_t</a> *child, <a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node</td></tr>
+<tr><th>where</th>
+<td class="description">Where to add, <code>MXML_ADD_BEFORE</code> or <code>MXML_ADD_AFTER</code></td></tr>
+<tr><th>child</th>
+<td class="description">Child node for where or <code>MXML_ADD_TO_PARENT</code></td></tr>
+<tr><th>node</th>
+<td class="description">Node to add</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Adds the specified node to the parent.  If the child argument is not
+<code>NULL</code>, puts the new node before or after the specified child depending
+on the value of the where argument.  If the child argument is <code>NULL</code>,
+puts the new node at the beginning of the child list (<code>MXML_ADD_BEFORE</code>)
+or at the end of the child list (<code>MXML_ADD_AFTER</code>).  The constant
+<code>MXML_ADD_TO_PARENT</code> can be used to specify a <code>NULL</code> child pointer.</p>
+<h3 class="function"><a id="mxmlDelete">mxmlDelete</a></h3>
+<p class="description">Delete a node and all of its children.</p>
+<p class="code">
+void mxmlDelete(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to delete</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If the specified node has a parent, this function first removes the
+node from its parent using the <a href="#mxmlRemove"><code>mxmlRemove</code></a> function.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.4&#160;</span><a id="mxmlElementDeleteAttr">mxmlElementDeleteAttr</a></h3>
+<p class="description">Delete an attribute.</p>
+<p class="code">
+void mxmlElementDeleteAttr(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Element</td></tr>
+<tr><th>name</th>
+<td class="description">Attribute name</td></tr>
+</tbody></table>
+<h3 class="function"><a id="mxmlElementGetAttr">mxmlElementGetAttr</a></h3>
+<p class="description">Get an attribute.</p>
+<p class="code">
+const char *mxmlElementGetAttr(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Element node</td></tr>
+<tr><th>name</th>
+<td class="description">Name of attribute</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Attribute value or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns <code>NULL</code> if the node is not an element or the
+named attribute does not exist.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.11&#160;</span><a id="mxmlElementGetAttrByIndex">mxmlElementGetAttrByIndex</a></h3>
+<p class="description">Get an element attribute by index.</p>
+<p class="code">
+const char *mxmlElementGetAttrByIndex(<a href="#mxml_node_t">mxml_node_t</a> *node, int idx, const char **name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node</td></tr>
+<tr><th>idx</th>
+<td class="description">Attribute index, starting at 0</td></tr>
+<tr><th>name</th>
+<td class="description">Attribute name</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Attribute value</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The index (&quot;idx&quot;) is 0-based.  <code>NULL</code> is returned if the specified index
+is out of range.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.11&#160;</span><a id="mxmlElementGetAttrCount">mxmlElementGetAttrCount</a></h3>
+<p class="description">Get the number of element attributes.</p>
+<p class="code">
+int mxmlElementGetAttrCount(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of attributes</p>
+<h3 class="function"><a id="mxmlElementSetAttr">mxmlElementSetAttr</a></h3>
+<p class="description">Set an attribute.</p>
+<p class="code">
+void mxmlElementSetAttr(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *name, const char *value);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Element node</td></tr>
+<tr><th>name</th>
+<td class="description">Name of attribute</td></tr>
+<tr><th>value</th>
+<td class="description">Attribute value</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If the named attribute already exists, the value of the attribute
+is replaced by the new string value. The string value is copied
+into the element node. This function does nothing if the node is
+not an element.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlElementSetAttrf">mxmlElementSetAttrf</a></h3>
+<p class="description">Set an attribute with a formatted value.</p>
+<p class="code">
+void mxmlElementSetAttrf(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *name, const char *format, ...);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Element node</td></tr>
+<tr><th>name</th>
+<td class="description">Name of attribute</td></tr>
+<tr><th>format</th>
+<td class="description">Printf-style attribute value</td></tr>
+<tr><th>...</th>
+<td class="description">Additional arguments as needed</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If the named attribute already exists, the value of the attribute
+is replaced by the new formatted string. The formatted string value is
+copied into the element node. This function does nothing if the node
+is not an element.
+
+</p>
+<h3 class="function"><a id="mxmlEntityAddCallback">mxmlEntityAddCallback</a></h3>
+<p class="description">Add a callback to convert entities to Unicode.</p>
+<p class="code">
+int mxmlEntityAddCallback(<a href="#mxml_entity_cb_t">mxml_entity_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>cb</th>
+<td class="description">Callback function to add</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><a id="mxmlEntityGetName">mxmlEntityGetName</a></h3>
+<p class="description">Get the name that corresponds to the character value.</p>
+<p class="code">
+const char *mxmlEntityGetName(int val);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>val</th>
+<td class="description">Character value</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Entity name or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">If val does not need to be represented by a named entity, <code>NULL</code> is returned.</p>
+<h3 class="function"><a id="mxmlEntityGetValue">mxmlEntityGetValue</a></h3>
+<p class="description">Get the character corresponding to a named entity.</p>
+<p class="code">
+int mxmlEntityGetValue(const char *name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>name</th>
+<td class="description">Entity name</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Character value or -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The entity name can also be a numeric constant. -1 is returned if the
+name is not known.</p>
+<h3 class="function"><a id="mxmlEntityRemoveCallback">mxmlEntityRemoveCallback</a></h3>
+<p class="description">Remove a callback.</p>
+<p class="code">
+void mxmlEntityRemoveCallback(<a href="#mxml_entity_cb_t">mxml_entity_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>cb</th>
+<td class="description">Callback function to remove</td></tr>
+</tbody></table>
+<h3 class="function"><a id="mxmlFindElement">mxmlFindElement</a></h3>
+<p class="description">Find the named element.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlFindElement(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_node_t">mxml_node_t</a> *top, const char *element, const char *attr, const char *value, int descend);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Current node</td></tr>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>element</th>
+<td class="description">Element name or <code>NULL</code> for any</td></tr>
+<tr><th>attr</th>
+<td class="description">Attribute name, or <code>NULL</code> for none</td></tr>
+<tr><th>value</th>
+<td class="description">Attribute value, or <code>NULL</code> for any</td></tr>
+<tr><th>descend</th>
+<td class="description">Descend into tree - <code>MXML_DESCEND</code>, <code>MXML_NO_DESCEND</code>, or <code>MXML_DESCEND_FIRST</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Element node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The search is constrained by the name, attribute name, and value; any
+<code>NULL</code> names or values are treated as wildcards, so different kinds of
+searches can be implemented by looking for all elements of a given name
+or all elements with a specific attribute. The descend argument determines
+whether the search descends into child nodes; normally you will use
+<code>MXML_DESCEND_FIRST</code> for the initial search and <code>MXML_NO_DESCEND</code>
+to find additional direct descendents of the node. The top node argument
+constrains the search to a particular node's children.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlFindPath">mxmlFindPath</a></h3>
+<p class="description">Find a node with the given path.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlFindPath(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *path);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>path</th>
+<td class="description">Path to element</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Found node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;path&quot; is a slash-separated list of element names. The name &quot;<em>" is
+considered a wildcard for one or more levels of elements.  For example,
+"foo/one/two", "bar/two/one", "</em>/one&quot;, and so forth.<br>
+<br>
+The first child node of the found node is returned if the given node has
+children and the first child is a value node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetCDATA">mxmlGetCDATA</a></h3>
+<p class="description">Get the value for a CDATA node.</p>
+<p class="code">
+const char *mxmlGetCDATA(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">CDATA value or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node is not a CDATA element.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetCustom">mxmlGetCustom</a></h3>
+<p class="description">Get the value for a custom node.</p>
+<p class="code">
+const void *mxmlGetCustom(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Custom value or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node (or its first child) is not a custom
+value node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetElement">mxmlGetElement</a></h3>
+<p class="description">Get the name for an element node.</p>
+<p class="code">
+const char *mxmlGetElement(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Element name or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node is not an element node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetFirstChild">mxmlGetFirstChild</a></h3>
+<p class="description">Get the first child of an element node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlGetFirstChild(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First child or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node is not an element node or if the node
+has no children.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetInteger">mxmlGetInteger</a></h3>
+<p class="description">Get the integer value from the specified node or its
+first child.</p>
+<p class="code">
+int mxmlGetInteger(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Integer value or 0</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">0 is returned if the node (or its first child) is not an integer value node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetLastChild">mxmlGetLastChild</a></h3>
+<p class="description">Get the last child of an element node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlGetLastChild(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Last child or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node is not an element node or if the node
+has no children.
+
+</p>
+<h3 class="function"><a id="mxmlGetNextSibling">mxmlGetNextSibling</a></h3>
+<p class="description"></p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlGetNextSibling(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Get the next node for the current parent.</p>
+<p class="discussion"><code>NULL</code> is returned if this is the last child for the current parent.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetOpaque">mxmlGetOpaque</a></h3>
+<p class="description">Get an opaque string value for a node or its first child.</p>
+<p class="code">
+const char *mxmlGetOpaque(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Opaque string or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node (or its first child) is not an opaque
+value node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetParent">mxmlGetParent</a></h3>
+<p class="description">Get the parent node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlGetParent(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Parent node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned for a root node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetPrevSibling">mxmlGetPrevSibling</a></h3>
+<p class="description">Get the previous node for the current parent.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlGetPrevSibling(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Previous node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if this is the first child for the current parent.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetReal">mxmlGetReal</a></h3>
+<p class="description">Get the real value for a node or its first child.</p>
+<p class="code">
+double mxmlGetReal(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Real value or 0.0</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">0.0 is returned if the node (or its first child) is not a real value node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetRefCount">mxmlGetRefCount</a></h3>
+<p class="description">Get the current reference (use) count for a node.</p>
+<p class="code">
+int mxmlGetRefCount(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Reference count</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The initial reference count of new nodes is 1. Use the <a href="#mxmlRetain"><code>mxmlRetain</code></a>
+and <a href="#mxmlRelease"><code>mxmlRelease</code></a> functions to increment and decrement a node's
+reference count.
+
+.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetText">mxmlGetText</a></h3>
+<p class="description">Get the text value for a node or its first child.</p>
+<p class="code">
+const char *mxmlGetText(<a href="#mxml_node_t">mxml_node_t</a> *node, int *whitespace);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+<tr><th>whitespace</th>
+<td class="description">1 if string is preceded by whitespace, 0 otherwise</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Text string or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>NULL</code> is returned if the node (or its first child) is not a text node.
+The &quot;whitespace&quot; argument can be <code>NULL</code>.<br>
+<br>
+Note: Text nodes consist of whitespace-delimited words. You will only get
+single words of text when reading an XML file with <code>MXML_TEXT</code> nodes.
+If you want the entire string between elements in the XML file, you MUST read
+the XML file with <code>MXML_OPAQUE</code> nodes and get the resulting strings
+using the <a href="#mxmlGetOpaque"><code>mxmlGetOpaque</code></a> function instead.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetType">mxmlGetType</a></h3>
+<p class="description">Get the node type.</p>
+<p class="code">
+<a href="#mxml_type_t">mxml_type_t</a> mxmlGetType(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Type of node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion"><code>MXML_IGNORE</code> is returned if &quot;node&quot; is <code>NULL</code>.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlGetUserData">mxmlGetUserData</a></h3>
+<p class="description">Get the user data pointer for a node.</p>
+<p class="code">
+void *mxmlGetUserData(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to get</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">User data pointer</p>
+<h3 class="function"><a id="mxmlIndexDelete">mxmlIndexDelete</a></h3>
+<p class="description">Delete an index.</p>
+<p class="code">
+void mxmlIndexDelete(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>ind</th>
+<td class="description">Index to delete</td></tr>
+</tbody></table>
+<h3 class="function"><a id="mxmlIndexEnum">mxmlIndexEnum</a></h3>
+<p class="description">Return the next node in the index.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlIndexEnum(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>ind</th>
+<td class="description">Index to enumerate</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Next node or <code>NULL</code> if there is none</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">You should call <a href="#mxmlIndexReset"><code>mxmlIndexReset</code></a> prior to using this function to get
+the first node in the index.  Nodes are returned in the sorted order of the
+index.</p>
+<h3 class="function"><a id="mxmlIndexFind">mxmlIndexFind</a></h3>
+<p class="description">Find the next matching node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlIndexFind(<a href="#mxml_index_t">mxml_index_t</a> *ind, const char *element, const char *value);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>ind</th>
+<td class="description">Index to search</td></tr>
+<tr><th>element</th>
+<td class="description">Element name to find, if any</td></tr>
+<tr><th>value</th>
+<td class="description">Attribute value, if any</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Node or <code>NULL</code> if none found</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">You should call <a href="#mxmlIndexReset"><code>mxmlIndexReset</code></a> prior to using this function for
+the first time with a particular set of &quot;element&quot; and &quot;value&quot;
+strings. Passing <code>NULL</code> for both &quot;element&quot; and &quot;value&quot; is equivalent
+to calling <a href="#mxmlIndexEnum"><code>mxmlIndexEnum</code></a>.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlIndexGetCount">mxmlIndexGetCount</a></h3>
+<p class="description">Get the number of nodes in an index.</p>
+<p class="code">
+int mxmlIndexGetCount(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>ind</th>
+<td class="description">Index of nodes</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Number of nodes in index</p>
+<h3 class="function"><a id="mxmlIndexNew">mxmlIndexNew</a></h3>
+<p class="description">Create a new index.</p>
+<p class="code">
+<a href="#mxml_index_t">mxml_index_t</a> *mxmlIndexNew(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *element, const char *attr);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">XML node tree</td></tr>
+<tr><th>element</th>
+<td class="description">Element to index or <code>NULL</code> for all</td></tr>
+<tr><th>attr</th>
+<td class="description">Attribute to index or <code>NULL</code> for none</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New index</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The index will contain all nodes that contain the named element and/or
+attribute.  If both &quot;element&quot; and &quot;attr&quot; are <code>NULL</code>, then the index will
+contain a sorted list of the elements in the node tree.  Nodes are
+sorted by element name and optionally by attribute value if the &quot;attr&quot;
+argument is not NULL.</p>
+<h3 class="function"><a id="mxmlIndexReset">mxmlIndexReset</a></h3>
+<p class="description">Reset the enumeration/find pointer in the index and
+return the first node in the index.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlIndexReset(<a href="#mxml_index_t">mxml_index_t</a> *ind);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>ind</th>
+<td class="description">Index to reset</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if there is none</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function should be called prior to using <a href="#mxmlIndexEnum"><code>mxmlIndexEnum</code></a> or
+<a href="#mxmlIndexFind"><code>mxmlIndexFind</code></a> for the first time.</p>
+<h3 class="function"><a id="mxmlLoadFd">mxmlLoadFd</a></h3>
+<p class="description">Load a file descriptor into an XML node tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFd(<a href="#mxml_node_t">mxml_node_t</a> *top, int fd, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>fd</th>
+<td class="description">File descriptor to read from</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child (data) nodes of the specified type.<br>
+<br>
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
+(including whitespace).</p>
+<h3 class="function"><a id="mxmlLoadFile">mxmlLoadFile</a></h3>
+<p class="description">Load a file into an XML node tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadFile(<a href="#mxml_node_t">mxml_node_t</a> *top, FILE *fp, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>fp</th>
+<td class="description">File to read from</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child (data) nodes of the specified type.<br>
+<br>
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
+(including whitespace).</p>
+<h3 class="function"><a id="mxmlLoadString">mxmlLoadString</a></h3>
+<p class="description">Load a string into an XML node tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlLoadString(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *s, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>s</th>
+<td class="description">String to load</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the string has errors.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified string are added to the specified top node.
+If no top node is provided, the XML string MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire string. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child (data) nodes of the specified type.<br>
+<br>
+Note: The most common programming error when using the Mini-XML library is
+to load an XML file using the <code>MXML_TEXT_CALLBACK</code>, which returns inline
+text as a series of whitespace-delimited words, instead of using the
+<code>MXML_OPAQUE_CALLBACK</code> which returns the inline text as a single string
+(including whitespace).</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlNewCDATA">mxmlNewCDATA</a></h3>
+<p class="description">Create a new CDATA node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewCDATA(<a href="#mxml_node_t">mxml_node_t</a> *parent, const char *data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>data</th>
+<td class="description">Data string</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new CDATA node is added to the end of the specified parent's child
+list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+CDATA node has no parent.  The data string must be nul-terminated and
+is copied into the new node.  CDATA nodes currently use the
+<code>MXML_ELEMENT</code> type.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.1&#160;</span><a id="mxmlNewCustom">mxmlNewCustom</a></h3>
+<p class="description">Create a new custom data node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewCustom(<a href="#mxml_node_t">mxml_node_t</a> *parent, void *data, <a href="#mxml_custom_destroy_cb_t">mxml_custom_destroy_cb_t</a> destroy);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>data</th>
+<td class="description">Pointer to data</td></tr>
+<tr><th>destroy</th>
+<td class="description">Function to destroy data</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new custom node is added to the end of the specified parent's child
+list. The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+element node has no parent. <code>NULL</code> can be passed when the data in the
+node is not dynamically allocated or is separately managed.
+
+</p>
+<h3 class="function"><a id="mxmlNewElement">mxmlNewElement</a></h3>
+<p class="description">Create a new element node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewElement(<a href="#mxml_node_t">mxml_node_t</a> *parent, const char *name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>name</th>
+<td class="description">Name of element</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new element node is added to the end of the specified parent's child
+list. The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+element node has no parent.</p>
+<h3 class="function"><a id="mxmlNewInteger">mxmlNewInteger</a></h3>
+<p class="description">Create a new integer node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewInteger(<a href="#mxml_node_t">mxml_node_t</a> *parent, int integer);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>integer</th>
+<td class="description">Integer value</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new integer node is added to the end of the specified parent's child
+list. The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+integer node has no parent.</p>
+<h3 class="function"><a id="mxmlNewOpaque">mxmlNewOpaque</a></h3>
+<p class="description">Create a new opaque string.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewOpaque(<a href="#mxml_node_t">mxml_node_t</a> *parent, const char *opaque);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>opaque</th>
+<td class="description">Opaque string</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new opaque string node is added to the end of the specified parent's
+child list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that
+the new opaque string node has no parent.  The opaque string must be nul-
+terminated and is copied into the new node.</p>
+<h3 class="function"><a id="mxmlNewOpaquef">mxmlNewOpaquef</a></h3>
+<p class="description">Create a new formatted opaque string node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewOpaquef(<a href="#mxml_node_t">mxml_node_t</a> *parent, const char *format, ...);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>format</th>
+<td class="description">Printf-style format string</td></tr>
+<tr><th>...</th>
+<td class="description">Additional args as needed</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new opaque string node is added to the end of the specified parent's
+child list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that
+the new opaque string node has no parent.  The format string must be
+nul-terminated and is formatted into the new node.</p>
+<h3 class="function"><a id="mxmlNewReal">mxmlNewReal</a></h3>
+<p class="description">Create a new real number node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewReal(<a href="#mxml_node_t">mxml_node_t</a> *parent, double real);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>real</th>
+<td class="description">Real number value</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new real number node is added to the end of the specified parent's
+child list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that
+the new real number node has no parent.</p>
+<h3 class="function"><a id="mxmlNewText">mxmlNewText</a></h3>
+<p class="description">Create a new text fragment node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewText(<a href="#mxml_node_t">mxml_node_t</a> *parent, int whitespace, const char *string);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>whitespace</th>
+<td class="description">1 = leading whitespace, 0 = no whitespace</td></tr>
+<tr><th>string</th>
+<td class="description">String</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new text node is added to the end of the specified parent's child
+list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+text node has no parent.  The whitespace parameter is used to specify
+whether leading whitespace is present before the node.  The text
+string must be nul-terminated and is copied into the new node.</p>
+<h3 class="function"><a id="mxmlNewTextf">mxmlNewTextf</a></h3>
+<p class="description">Create a new formatted text fragment node.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewTextf(<a href="#mxml_node_t">mxml_node_t</a> *parent, int whitespace, const char *format, ...);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>parent</th>
+<td class="description">Parent node or <code>MXML_NO_PARENT</code></td></tr>
+<tr><th>whitespace</th>
+<td class="description">1 = leading whitespace, 0 = no whitespace</td></tr>
+<tr><th>format</th>
+<td class="description">Printf-style format string</td></tr>
+<tr><th>...</th>
+<td class="description">Additional args as needed</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The new text node is added to the end of the specified parent's child
+list.  The constant <code>MXML_NO_PARENT</code> can be used to specify that the new
+text node has no parent.  The whitespace parameter is used to specify
+whether leading whitespace is present before the node.  The format
+string must be nul-terminated and is formatted into the new node.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlNewXML">mxmlNewXML</a></h3>
+<p class="description">Create a new XML document tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlNewXML(const char *version);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>version</th>
+<td class="description">Version number to use</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New ?xml node</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The &quot;version&quot; argument specifies the version number to put in the
+?xml element node. If <code>NULL</code>, version &quot;1.0&quot; is assumed.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlRelease">mxmlRelease</a></h3>
+<p class="description">Release a node.</p>
+<p class="code">
+int mxmlRelease(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New reference count</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">When the reference count reaches zero, the node (and any children)
+is deleted via <a href="#mxmlDelete"><code>mxmlDelete</code></a>.
+
+</p>
+<h3 class="function"><a id="mxmlRemove">mxmlRemove</a></h3>
+<p class="description">Remove a node from its parent.</p>
+<p class="code">
+void mxmlRemove(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to remove</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function does not free memory used by the node - use <a href="#mxmlDelete"><code>mxmlDelete</code></a>
+for that.  This function does nothing if the node has no parent.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlRetain">mxmlRetain</a></h3>
+<p class="description">Retain a node.</p>
+<p class="code">
+int mxmlRetain(<a href="#mxml_node_t">mxml_node_t</a> *node);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">New reference count</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlSAXLoadFd">mxmlSAXLoadFd</a></h3>
+<p class="description">Load a file descriptor into an XML node tree
+using a SAX callback.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadFd(<a href="#mxml_node_t">mxml_node_t</a> *top, int fd, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>fd</th>
+<td class="description">File descriptor to read from</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+<tr><th>sax_cb</th>
+<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
+<tr><th>sax_data</th>
+<td class="description">SAX user data</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child nodes of the specified type.<br>
+<br>
+The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlSAXLoadFile">mxmlSAXLoadFile</a></h3>
+<p class="description">Load a file into an XML node tree
+using a SAX callback.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadFile(<a href="#mxml_node_t">mxml_node_t</a> *top, FILE *fp, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>fp</th>
+<td class="description">File to read from</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+<tr><th>sax_cb</th>
+<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
+<tr><th>sax_data</th>
+<td class="description">SAX user data</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the file could not be read.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified file are added to the specified top node.
+If no top node is provided, the XML file MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire file. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child nodes of the specified type.<br>
+<br>
+The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlSAXLoadString">mxmlSAXLoadString</a></h3>
+<p class="description">Load a string into an XML node tree
+using a SAX callback.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlSAXLoadString(<a href="#mxml_node_t">mxml_node_t</a> *top, const char *s, <a href="#mxml_load_cb_t">mxml_load_cb_t</a> cb, <a href="#mxml_sax_cb_t">mxml_sax_cb_t</a> sax_cb, void *sax_data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>s</th>
+<td class="description">String to load</td></tr>
+<tr><th>cb</th>
+<td class="description">Callback function or constant</td></tr>
+<tr><th>sax_cb</th>
+<td class="description">SAX callback or <code>MXML_NO_CALLBACK</code></td></tr>
+<tr><th>sax_data</th>
+<td class="description">SAX user data</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">First node or <code>NULL</code> if the string has errors.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The nodes in the specified string are added to the specified top node.
+If no top node is provided, the XML string MUST be well-formed with a
+single parent node like <a href="?xml">?xml</a> for the entire string. The callback
+function returns the value type that should be used for child nodes.
+The constants <code>MXML_INTEGER_CALLBACK</code>, <code>MXML_OPAQUE_CALLBACK</code>,
+<code>MXML_REAL_CALLBACK</code>, and <code>MXML_TEXT_CALLBACK</code> are defined for
+loading child nodes of the specified type.<br>
+<br>
+The SAX callback must call <a href="#mxmlRetain"><code>mxmlRetain</code></a> for any nodes that need to
+be kept for later use. Otherwise, nodes are deleted when the parent
+node is closed or after each data, comment, CDATA, or directive node.
+
+</p>
+<h3 class="function"><a id="mxmlSaveAllocString">mxmlSaveAllocString</a></h3>
+<p class="description">Save an XML tree to an allocated string.</p>
+<p class="code">
+char *mxmlSaveAllocString(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to write</td></tr>
+<tr><th>cb</th>
+<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Allocated string or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns a pointer to a string containing the textual
+representation of the XML node tree.  The string should be freed
+using <code>free()</code> when you are done with it.  <code>NULL</code> is returned if the node
+would produce an empty string or if the string cannot be allocated.<br>
+<br>
+The callback argument specifies a function that returns a whitespace
+string or <code>NULL</code> before and after each element.  If <code>MXML_NO_CALLBACK</code>
+is specified, whitespace will only be added before <code>MXML_TEXT</code> nodes
+with leading whitespace and before attribute names inside opening
+element tags.</p>
+<h3 class="function"><a id="mxmlSaveFd">mxmlSaveFd</a></h3>
+<p class="description">Save an XML tree to a file descriptor.</p>
+<p class="code">
+int mxmlSaveFd(<a href="#mxml_node_t">mxml_node_t</a> *node, int fd, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to write</td></tr>
+<tr><th>fd</th>
+<td class="description">File descriptor to write to</td></tr>
+<tr><th>cb</th>
+<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If <code>MXML_NO_CALLBACK</code>
+is specified, whitespace will only be added before <code>MXML_TEXT</code> nodes
+with leading whitespace and before attribute names inside opening
+element tags.</p>
+<h3 class="function"><a id="mxmlSaveFile">mxmlSaveFile</a></h3>
+<p class="description">Save an XML tree to a file.</p>
+<p class="code">
+int mxmlSaveFile(<a href="#mxml_node_t">mxml_node_t</a> *node, FILE *fp, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to write</td></tr>
+<tr><th>fp</th>
+<td class="description">File to write to</td></tr>
+<tr><th>cb</th>
+<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error.</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If <code>MXML_NO_CALLBACK</code>
+is specified, whitespace will only be added before <code>MXML_TEXT</code> nodes
+with leading whitespace and before attribute names inside opening
+element tags.</p>
+<h3 class="function"><a id="mxmlSaveString">mxmlSaveString</a></h3>
+<p class="description">Save an XML node tree to a string.</p>
+<p class="code">
+int mxmlSaveString(<a href="#mxml_node_t">mxml_node_t</a> *node, char *buffer, int bufsize, <a href="#mxml_save_cb_t">mxml_save_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to write</td></tr>
+<tr><th>buffer</th>
+<td class="description">String buffer</td></tr>
+<tr><th>bufsize</th>
+<td class="description">Size of string buffer</td></tr>
+<tr><th>cb</th>
+<td class="description">Whitespace callback or <code>MXML_NO_CALLBACK</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Size of string</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the total number of bytes that would be
+required for the string but only copies (bufsize - 1) characters
+into the specified buffer.<br>
+<br>
+The callback argument specifies a function that returns a whitespace
+string or NULL before and after each element. If <code>MXML_NO_CALLBACK</code>
+is specified, whitespace will only be added before <code>MXML_TEXT</code> nodes
+with leading whitespace and before attribute names inside opening
+element tags.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlSetCDATA">mxmlSetCDATA</a></h3>
+<p class="description">Set the element name of a CDATA node.</p>
+<p class="code">
+int mxmlSetCDATA(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>data</th>
+<td class="description">New data string</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not a CDATA element node.
+
+</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.1&#160;</span><a id="mxmlSetCustom">mxmlSetCustom</a></h3>
+<p class="description">Set the data and destructor of a custom data node.</p>
+<p class="code">
+int mxmlSetCustom(<a href="#mxml_node_t">mxml_node_t</a> *node, void *data, <a href="#mxml_custom_destroy_cb_t">mxml_custom_destroy_cb_t</a> destroy);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>data</th>
+<td class="description">New data pointer</td></tr>
+<tr><th>destroy</th>
+<td class="description">New destructor function</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not a custom node.
+
+</p>
+<h3 class="function"><a id="mxmlSetCustomHandlers">mxmlSetCustomHandlers</a></h3>
+<p class="description">Set the handling functions for custom data.</p>
+<p class="code">
+void mxmlSetCustomHandlers(<a href="#mxml_custom_load_cb_t">mxml_custom_load_cb_t</a> load, <a href="#mxml_custom_save_cb_t">mxml_custom_save_cb_t</a> save);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>load</th>
+<td class="description">Load function</td></tr>
+<tr><th>save</th>
+<td class="description">Save function</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The load function accepts a node pointer and a data string and must
+return 0 on success and non-zero on error.<br>
+<br>
+The save function accepts a node pointer and must return a malloc'd
+string on success and <code>NULL</code> on error.</p>
+<h3 class="function"><a id="mxmlSetElement">mxmlSetElement</a></h3>
+<p class="description">Set the name of an element node.</p>
+<p class="code">
+int mxmlSetElement(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *name);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>name</th>
+<td class="description">New name string</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it is not an element node.</p>
+<h3 class="function"><a id="mxmlSetErrorCallback">mxmlSetErrorCallback</a></h3>
+<p class="description">Set the error message callback.</p>
+<p class="code">
+void mxmlSetErrorCallback(<a href="#mxml_error_cb_t">mxml_error_cb_t</a> cb);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>cb</th>
+<td class="description">Error callback function</td></tr>
+</tbody></table>
+<h3 class="function"><a id="mxmlSetInteger">mxmlSetInteger</a></h3>
+<p class="description">Set the value of an integer node.</p>
+<p class="code">
+int mxmlSetInteger(<a href="#mxml_node_t">mxml_node_t</a> *node, int integer);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>integer</th>
+<td class="description">Integer value</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not an integer node.</p>
+<h3 class="function"><a id="mxmlSetOpaque">mxmlSetOpaque</a></h3>
+<p class="description">Set the value of an opaque node.</p>
+<p class="code">
+int mxmlSetOpaque(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *opaque);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>opaque</th>
+<td class="description">Opaque string</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not an opaque node.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.11&#160;</span><a id="mxmlSetOpaquef">mxmlSetOpaquef</a></h3>
+<p class="description">Set the value of an opaque string node to a formatted string.</p>
+<p class="code">
+int mxmlSetOpaquef(<a href="#mxml_node_t">mxml_node_t</a> *node, const char *format, ...);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>format</th>
+<td class="description">Printf-style format string</td></tr>
+<tr><th>...</th>
+<td class="description">Additional arguments as needed</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not an opaque node.
+
+</p>
+<h3 class="function"><a id="mxmlSetReal">mxmlSetReal</a></h3>
+<p class="description">Set the value of a real number node.</p>
+<p class="code">
+int mxmlSetReal(<a href="#mxml_node_t">mxml_node_t</a> *node, double real);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>real</th>
+<td class="description">Real number value</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not a real number node.</p>
+<h3 class="function"><a id="mxmlSetText">mxmlSetText</a></h3>
+<p class="description">Set the value of a text node.</p>
+<p class="code">
+int mxmlSetText(<a href="#mxml_node_t">mxml_node_t</a> *node, int whitespace, const char *string);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>whitespace</th>
+<td class="description">1 = leading whitespace, 0 = no whitespace</td></tr>
+<tr><th>string</th>
+<td class="description">String</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not a text node.</p>
+<h3 class="function"><a id="mxmlSetTextf">mxmlSetTextf</a></h3>
+<p class="description">Set the value of a text node to a formatted string.</p>
+<p class="code">
+int mxmlSetTextf(<a href="#mxml_node_t">mxml_node_t</a> *node, int whitespace, const char *format, ...);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>whitespace</th>
+<td class="description">1 = leading whitespace, 0 = no whitespace</td></tr>
+<tr><th>format</th>
+<td class="description">Printf-style format string</td></tr>
+<tr><th>...</th>
+<td class="description">Additional arguments as needed</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The node is not changed if it (or its first child) is not a text node.</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.7&#160;</span><a id="mxmlSetUserData">mxmlSetUserData</a></h3>
+<p class="description">Set the user data pointer for a node.</p>
+<p class="code">
+int mxmlSetUserData(<a href="#mxml_node_t">mxml_node_t</a> *node, void *data);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Node to set</td></tr>
+<tr><th>data</th>
+<td class="description">User data pointer</td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on failure</p>
+<h3 class="function"><span class="info">&#160;Mini-XML 2.3&#160;</span><a id="mxmlSetWrapMargin">mxmlSetWrapMargin</a></h3>
+<p class="description">Set the wrap margin when saving XML data.</p>
+<p class="code">
+void mxmlSetWrapMargin(int column);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>column</th>
+<td class="description">Column for wrapping, 0 to disable wrapping</td></tr>
+</tbody></table>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Wrapping is disabled when &quot;column&quot; is 0.
+
+</p>
+<h3 class="function"><a id="mxmlWalkNext">mxmlWalkNext</a></h3>
+<p class="description">Walk to the next logical node in the tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlWalkNext(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_node_t">mxml_node_t</a> *top, int descend);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Current node</td></tr>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>descend</th>
+<td class="description">Descend into tree - <code>MXML_DESCEND</code>, <code>MXML_NO_DESCEND</code>, or <code>MXML_DESCEND_FIRST</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Next node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The descend argument controls whether the first child is considered
+to be the next node.  The top node argument constrains the walk to
+the node's children.</p>
+<h3 class="function"><a id="mxmlWalkPrev">mxmlWalkPrev</a></h3>
+<p class="description">Walk to the previous logical node in the tree.</p>
+<p class="code">
+<a href="#mxml_node_t">mxml_node_t</a> *mxmlWalkPrev(<a href="#mxml_node_t">mxml_node_t</a> *node, <a href="#mxml_node_t">mxml_node_t</a> *top, int descend);</p>
+<h4 class="parameters">Parameters</h4>
+<table class="list"><tbody>
+<tr><th>node</th>
+<td class="description">Current node</td></tr>
+<tr><th>top</th>
+<td class="description">Top node</td></tr>
+<tr><th>descend</th>
+<td class="description">Descend into tree - <code>MXML_DESCEND</code>, <code>MXML_NO_DESCEND</code>, or <code>MXML_DESCEND_FIRST</code></td></tr>
+</tbody></table>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Previous node or <code>NULL</code></p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The descend argument controls whether the previous node's last child
+is considered to be the previous node.  The top node argument constrains
+the walk to the node's children.</p>
+<h2 class="title"><a id="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a id="mxml_custom_destroy_cb_t">mxml_custom_destroy_cb_t</a></h3>
+<p class="description">Custom data destructor</p>
+<p class="code">
+typedef void (*mxml_custom_destroy_cb_t)(void *);
+</p>
+<h3 class="typedef"><a id="mxml_custom_load_cb_t">mxml_custom_load_cb_t</a></h3>
+<p class="description">Custom data load callback function</p>
+<p class="code">
+typedef int (*mxml_custom_load_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, const char *);
+</p>
+<h3 class="typedef"><a id="mxml_custom_save_cb_t">mxml_custom_save_cb_t</a></h3>
+<p class="description">Custom data save callback function</p>
+<p class="code">
+typedef char *(*mxml_custom_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *);
+</p>
+<h3 class="typedef"><a id="mxml_entity_cb_t">mxml_entity_cb_t</a></h3>
+<p class="description">Entity callback function</p>
+<p class="code">
+typedef int (*mxml_entity_cb_t)(const char *);
+</p>
+<h3 class="typedef"><a id="mxml_error_cb_t">mxml_error_cb_t</a></h3>
+<p class="description">Error callback function</p>
+<p class="code">
+typedef void (*mxml_error_cb_t)(const char *);
+</p>
+<h3 class="typedef"><a id="mxml_index_t">mxml_index_t</a></h3>
+<p class="description">An XML node index.</p>
+<p class="code">
+typedef struct _mxml_index_s mxml_index_t;
+</p>
+<h3 class="typedef"><a id="mxml_load_cb_t">mxml_load_cb_t</a></h3>
+<p class="description">Load callback function</p>
+<p class="code">
+typedef <a href="#mxml_type_t">mxml_type_t</a> (*mxml_load_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *);
+</p>
+<h3 class="typedef"><a id="mxml_node_t">mxml_node_t</a></h3>
+<p class="description">An XML node.</p>
+<p class="code">
+typedef struct _mxml_node_s mxml_node_t;
+</p>
+<h3 class="typedef"><a id="mxml_save_cb_t">mxml_save_cb_t</a></h3>
+<p class="description">Save callback function</p>
+<p class="code">
+typedef const char *(*mxml_save_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, int);
+</p>
+<h3 class="typedef"><a id="mxml_sax_cb_t">mxml_sax_cb_t</a></h3>
+<p class="description">SAX callback function</p>
+<p class="code">
+typedef void (*mxml_sax_cb_t)(<a href="#mxml_node_t">mxml_node_t</a> *, mxml_sax_event_t, void *);
+</p>
+<h3 class="typedef"><a id="mxml_sax_event_t">mxml_sax_event_t</a></h3>
+<p class="description">SAX event type.</p>
+<p class="code">
+typedef enum <a href="#mxml_sax_event_e">mxml_sax_event_e</a> mxml_sax_event_t;
+</p>
+<h3 class="typedef"><a id="mxml_type_t">mxml_type_t</a></h3>
+<p class="description">The XML node type.</p>
+<p class="code">
+typedef enum <a href="#mxml_type_e">mxml_type_e</a> mxml_type_t;
+</p>
+<h2 class="title"><a id="ENUMERATIONS">Constants</a></h2>
+<h3 class="enumeration"><a id="mxml_sax_event_e">mxml_sax_event_e</a></h3>
+<p class="description">SAX event type.</p>
+<h4 class="constants">Constants</h4>
+<table class="list"><tbody>
+<tr><th>MXML_SAX_CDATA </th><td class="description">CDATA node</td></tr>
+<tr><th>MXML_SAX_COMMENT </th><td class="description">Comment node</td></tr>
+<tr><th>MXML_SAX_DATA </th><td class="description">Data node</td></tr>
+<tr><th>MXML_SAX_DIRECTIVE </th><td class="description">Processing directive node</td></tr>
+<tr><th>MXML_SAX_ELEMENT_CLOSE </th><td class="description">Element closed</td></tr>
+<tr><th>MXML_SAX_ELEMENT_OPEN </th><td class="description">Element opened</td></tr>
+</tbody></table>
+<h3 class="enumeration"><a id="mxml_type_e">mxml_type_e</a></h3>
+<p class="description">The XML node type.</p>
+<h4 class="constants">Constants</h4>
+<table class="list"><tbody>
+<tr><th>MXML_CUSTOM <span class="info">&#160;Mini-XML 2.1&#160;</span></th><td class="description">Custom data </td></tr>
+<tr><th>MXML_ELEMENT </th><td class="description">XML element with attributes</td></tr>
+<tr><th>MXML_IGNORE <span class="info">&#160;Mini-XML 2.3&#160;</span></th><td class="description">Ignore/throw away node </td></tr>
+<tr><th>MXML_INTEGER </th><td class="description">Integer value</td></tr>
+<tr><th>MXML_OPAQUE </th><td class="description">Opaque string</td></tr>
+<tr><th>MXML_REAL </th><td class="description">Real value</td></tr>
+<tr><th>MXML_TEXT </th><td class="description">Text fragment</td></tr>
+</tbody></table>
+</div>
+</body>
+</html>

BIN
mxml.mod/mxml/doc/mxml.opacity


BIN
mxml.mod/mxml/doc/mxml.png


+ 12 - 8
mxml.mod/mxml/install-sh

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -217,7 +217,13 @@ mxmlElementSetAttr(mxml_node_t *node,	/* I - Element node */
     return;
 
   if (value)
-    valuec = strdup(value);
+  {
+    if ((valuec = strdup(value)) == NULL)
+    {
+      mxml_error("Unable to allocate memory for attribute '%s' in element %s.", name, node->value.element.name);
+      return;
+    }
+  }
   else
     valuec = NULL;
 
@@ -269,7 +275,7 @@ mxmlElementSetAttrf(mxml_node_t *node,	/* I - Element node */
   va_end(ap);
 
   if (!value)
-    mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+    mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
                name, node->value.element.name);
   else if (mxml_set_attr(node, name, value))
     free(value);
@@ -302,9 +308,7 @@ mxml_set_attr(mxml_node_t *node,	/* I - Element node */
       * Free the old value as needed...
       */
 
-      if (attr->value)
-        free(attr->value);
-
+      free(attr->value);
       attr->value = value;
 
       return (0);
@@ -322,7 +326,7 @@ mxml_set_attr(mxml_node_t *node,	/* I - Element node */
 
   if (!attr)
   {
-    mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+    mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
                name, node->value.element.name);
     return (-1);
   }
@@ -332,7 +336,7 @@ mxml_set_attr(mxml_node_t *node,	/* I - Element node */
 
   if ((attr->name = strdup(name)) == NULL)
   {
-    mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
+    mxml_error("Unable to allocate memory for attribute '%s' in element %s.",
                name, node->value.element.name);
     return (-1);
   }

+ 75 - 51
mxml.mod/mxml/mxml-file.c

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -15,8 +15,6 @@
 
 #ifndef _WIN32
 #  include <unistd.h>
-#else
-#include <io.h>
 #endif /* !_WIN32 */
 #include "mxml-private.h"
 
@@ -243,13 +241,12 @@ mxmlLoadStream(mxml_node_t    *top,	/* I - Top node */
  *
  * This function returns a pointer to a string containing the textual
  * representation of the XML node tree.  The string should be freed
- * using the free() function when you are done with it.  @code NULL@ is returned
- * if the node would produce an empty string or if the string cannot be
- * allocated.
+ * using `free()` when you are done with it.  `NULL` is returned if the node
+ * would produce an empty string or if the string cannot be allocated.
  *
  * The callback argument specifies a function that returns a whitespace
- * string or NULL before and after each element.  If @code MXML_NO_CALLBACK@
- * is specified, whitespace will only be added before @code MXML_TEXT@ nodes
+ * string or `NULL` before and after each element.  If `MXML_NO_CALLBACK`
+ * is specified, whitespace will only be added before `MXML_TEXT` nodes
  * with leading whitespace and before attribute names inside opening
  * element tags.
  */
@@ -485,7 +482,10 @@ mxmlSaveString(mxml_node_t    *node,	/* I - Node to write */
   */
 
   if (ptr[0] >= ptr[1])
-    buffer[bufsize - 1] = '\0';
+  {
+    if (bufsize > 0)
+      buffer[bufsize - 1] = '\0';
+  }
   else
     ptr[0][0] = '\0';
 
@@ -697,9 +697,7 @@ mxml_add_char(int  ch,			/* I  - Character to add */
 
     if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
     {
-      free(*buffer);
-
-      mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
+      mxml_error("Unable to expand string buffer to %d bytes.", *bufsize);
 
       return (-1);
     }
@@ -791,7 +789,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
 	  if (mxml_bad_char(ch))
 	  {
-	    mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	    mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	       ch);
 	    return (EOF);
 	  }
@@ -855,7 +853,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
 	  if (ch < 0x80)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 	}
@@ -889,7 +887,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
 	  if (ch < 0x800)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 
@@ -941,7 +939,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
 	  if (ch < 0x10000)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 	}
@@ -964,7 +962,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
 	if (mxml_bad_char(ch))
 	{
-	  mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	  mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	     ch);
 	  return (EOF);
 	}
@@ -1012,7 +1010,7 @@ mxml_fd_getc(void *p,			/* I  - File descriptor buffer */
 
         if (mxml_bad_char(ch))
 	{
-	  mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	  mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	     ch);
 	  return (EOF);
 	}
@@ -1597,7 +1595,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 	{
 	  if (mxml_bad_char(ch))
 	  {
-	    mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	    mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	       ch);
 	    return (EOF);
 	  }
@@ -1649,7 +1647,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 
 	  if (ch < 0x80)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 	}
@@ -1671,7 +1669,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 
 	  if (ch < 0x800)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 
@@ -1705,7 +1703,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 
 	  if (ch < 0x10000)
 	  {
-	    mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	    mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	    return (EOF);
 	  }
 	}
@@ -1722,7 +1720,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 
 	if (mxml_bad_char(ch))
 	{
-	  mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	  mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	     ch);
 	  return (EOF);
 	}
@@ -1751,7 +1749,7 @@ mxml_file_getc(void *p,			/* I  - Pointer to file */
 
         if (mxml_bad_char(ch))
 	{
-	  mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	  mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	     ch);
 	  return (EOF);
 	}
@@ -1869,9 +1867,9 @@ mxml_load_data(
     mxml_sax_cb_t   sax_cb,		/* I - SAX callback or MXML_NO_CALLBACK */
     void            *sax_data)		/* I - SAX user data */
 {
-  mxml_node_t	*node,			/* Current node */
-		*first,			/* First node added */
-		*parent;		/* Current parent node */
+  mxml_node_t	*node = NULL,		/* Current node */
+		*first = NULL,		/* First node added */
+		*parent = NULL;		/* Current parent node */
   int		line = 1,		/* Current line number */
 		ch,			/* Character from file */
 		whitespace;		/* Non-zero if whitespace seen */
@@ -1899,7 +1897,7 @@ mxml_load_data(
 
   if ((buffer = malloc(64)) == NULL)
   {
-    mxml_error("Unable to allocate string buffer!");
+    mxml_error("Unable to allocate string buffer.");
     return (NULL);
   }
 
@@ -1917,7 +1915,19 @@ mxml_load_data(
   else
     type = MXML_IGNORE;
 
-  while ((ch = (*getc_cb)(p, &encoding)) != EOF)
+  if ((ch = (*getc_cb)(p, &encoding)) == EOF)
+  {
+    free(buffer);
+    return (NULL);
+  }
+  else if (ch != '<' && !top)
+  {
+    free(buffer);
+    mxml_error("XML does not start with '<' (saw '%c').", ch);
+    return (NULL);
+  }
+
+  do
   {
     if ((ch == '<' ||
          (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
@@ -2050,7 +2060,7 @@ mxml_load_data(
 	  break;
 	else if (ch == '<')
 	{
-	  mxml_error("Bare < in element!");
+	  mxml_error("Bare < in element.");
 	  goto error;
 	}
 	else if (ch == '&')
@@ -2283,7 +2293,7 @@ mxml_load_data(
         {
           (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
 
-          if (!mxmlRelease(node))
+          if (strncmp(node->value.element.name, "?xml ", 5) && !mxmlRelease(node))
             node = NULL;
         }
 
@@ -2424,8 +2434,13 @@ mxml_load_data(
         {
           (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
 
-          if (!mxmlRelease(node) && first == node)
-	    first = NULL;
+          if (!mxmlRelease(node))
+          {
+            if (first == node)
+	      first = NULL;
+
+	    node = NULL;
+	  }
         }
 
        /*
@@ -2472,6 +2487,7 @@ mxml_load_data(
 	  {
 	    mxml_error("Expected > but got '%c' instead for element <%s/> on line %d.", ch, buffer, line);
             mxmlDelete(node);
+            node = NULL;
             goto error;
 	  }
 
@@ -2504,8 +2520,13 @@ mxml_load_data(
         {
           (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
 
-          if (!mxmlRelease(node) && first == node)
-            first = NULL;
+          if (!mxmlRelease(node))
+          {
+            if (first == node)
+	      first = NULL;
+
+	    node = NULL;
+	  }
         }
       }
 
@@ -2533,6 +2554,7 @@ mxml_load_data(
 	goto error;
     }
   }
+  while ((ch = (*getc_cb)(p, &encoding)) != EOF);
 
  /*
   * Free the string buffer - we don't need it anymore...
@@ -2570,7 +2592,7 @@ mxml_load_data(
   * Common error return...
   */
 
-error:
+  error:
 
   mxmlDelete(first);
 
@@ -2607,7 +2629,7 @@ mxml_parse_element(
 
   if ((name = malloc(64)) == NULL)
   {
-    mxml_error("Unable to allocate memory for name!");
+    mxml_error("Unable to allocate memory for name.");
     return (EOF);
   }
 
@@ -2616,7 +2638,7 @@ mxml_parse_element(
   if ((value = malloc(64)) == NULL)
   {
     free(name);
-    mxml_error("Unable to allocate memory for value!");
+    mxml_error("Unable to allocate memory for value.");
     return (EOF);
   }
 
@@ -2676,8 +2698,9 @@ mxml_parse_element(
     * Read the attribute name...
     */
 
-    name[0] = ch;
-    ptr     = name + 1;
+    ptr = name;
+    if (mxml_add_char(ch, &ptr, &name, &namesize))
+      goto error;
 
     if (ch == '\"' || ch == '\'')
     {
@@ -2730,14 +2753,14 @@ mxml_parse_element(
 	  if (mxml_add_char(ch, &ptr, &name, &namesize))
 	    goto error;
 	}
-    }
+      }
     }
 
     *ptr = '\0';
 
     if (mxmlElementGetAttr(node, name))
     {
-      mxml_error("Duplicate attribute '%s' in element %s on line %d.", name, node->value.element.name, name, *line);
+      mxml_error("Duplicate attribute '%s' in element %s on line %d.", name, node->value.element.name, *line);
       goto error;
     }
 
@@ -2805,8 +2828,9 @@ mxml_parse_element(
         * Read unquoted value...
 	*/
 
-	value[0] = ch;
-	ptr      = value + 1;
+	ptr      = value;
+	if (mxml_add_char(ch, &ptr, &value, &valsize))
+	  goto error;
 
 	while ((ch = (*getc_cb)(p, encoding)) != EOF)
 	{
@@ -2882,7 +2906,7 @@ mxml_parse_element(
   * Common error return point...
   */
 
-error:
+  error:
 
   free(name);
   free(value);
@@ -2924,7 +2948,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
 	    if (mxml_bad_char(ch))
 	    {
-	      mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	      mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         		 ch);
 	      return (EOF);
 	    }
@@ -2974,7 +2998,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
 	    if (ch < 0x80)
 	    {
-	      mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	      mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	      return (EOF);
 	    }
 
@@ -3000,7 +3024,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
 	    if (ch < 0x800)
 	    {
-	      mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	      mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	      return (EOF);
 	    }
 
@@ -3035,7 +3059,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
 	    if (ch < 0x10000)
 	    {
-	      mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
+	      mxml_error("Invalid UTF-8 sequence for character 0x%04x.", ch);
 	      return (EOF);
 	    }
 
@@ -3058,7 +3082,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
           if (mxml_bad_char(ch))
 	  {
-	    mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	    mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	       ch);
 	    return (EOF);
 	  }
@@ -3106,7 +3130,7 @@ mxml_string_getc(void *p,		/* I  - Pointer to file */
 
           if (mxml_bad_char(ch))
 	  {
-	    mxml_error("Bad control character 0x%02x not allowed by XML standard!",
+	    mxml_error("Bad control character 0x%02x not allowed by XML standard.",
         	       ch);
 	    return (EOF);
 	  }

+ 13 - 14
mxml.mod/mxml/mxml-index.c

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -46,12 +46,8 @@ mxmlIndexDelete(mxml_index_t *ind)	/* I - Index to delete */
   * Free memory...
   */
 
-  if (ind->attr)
-    free(ind->attr);
-
-  if (ind->alloc_nodes)
-    free(ind->nodes);
-
+  free(ind->attr);
+  free(ind->nodes);
   free(ind);
 }
 
@@ -330,13 +326,19 @@ mxmlIndexNew(mxml_node_t *node,		/* I - XML node tree */
 
   if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
   {
-    mxml_error("Unable to allocate %d bytes for index - %s",
-               sizeof(mxml_index_t), strerror(errno));
+    mxml_error("Unable to allocate memory for index.");
     return (NULL);
   }
 
   if (attr)
-    ind->attr = strdup(attr);
+  {
+    if ((ind->attr = strdup(attr)) == NULL)
+    {
+      mxml_error("Unable to allocate memory for index attribute.");
+      free(ind);
+      return (NULL);
+    }
+  }
 
   if (!element && !attr)
     current = node;
@@ -358,10 +360,7 @@ mxmlIndexNew(mxml_node_t *node,		/* I - XML node tree */
         * Unable to allocate memory for the index, so abort...
 	*/
 
-        mxml_error("Unable to allocate %d bytes for index: %s",
-	           (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
-		   strerror(errno));
-
+        mxml_error("Unable to allocate memory for index nodes.");
         mxmlIndexDelete(ind);
 	return (NULL);
       }

+ 6 - 11
mxml.mod/mxml/mxml-node.c

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -808,17 +808,14 @@ mxml_free(mxml_node_t *node)		/* I - Node */
   switch (node->type)
   {
     case MXML_ELEMENT :
-        if (node->value.element.name)
-	  free(node->value.element.name);
+	free(node->value.element.name);
 
 	if (node->value.element.num_attrs)
 	{
 	  for (i = 0; i < node->value.element.num_attrs; i ++)
 	  {
-	    if (node->value.element.attrs[i].name)
-	      free(node->value.element.attrs[i].name);
-	    if (node->value.element.attrs[i].value)
-	      free(node->value.element.attrs[i].value);
+	    free(node->value.element.attrs[i].name);
+	    free(node->value.element.attrs[i].value);
 	  }
 
           free(node->value.element.attrs);
@@ -828,15 +825,13 @@ mxml_free(mxml_node_t *node)		/* I - Node */
        /* Nothing to do */
         break;
     case MXML_OPAQUE :
-        if (node->value.opaque)
-	  free(node->value.opaque);
+	free(node->value.opaque);
         break;
     case MXML_REAL :
        /* Nothing to do */
         break;
     case MXML_TEXT :
-        if (node->value.text.string)
-	  free(node->value.text.string);
+	free(node->value.text.string);
         break;
     case MXML_CUSTOM :
         if (node->value.custom.data &&

+ 8 - 14
mxml.mod/mxml/mxml-private.c

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2022 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -26,7 +26,7 @@
  * be unloaded safely, although since there is no standard way to do so I
  * can't even provide any guarantees that you can do it safely on all platforms.
  *
- * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and
+ * This code currently supports AIX, HP-UX, Linux, macOS, Solaris, and
  * Windows.  It might work on the BSDs and IRIX, but I haven't tested that.
  */
 
@@ -36,7 +36,7 @@
 #elif defined(__hpux)
 #  pragma FINI _mxml_fini
 #  define _MXML_FINI _mxml_fini
-#elif defined(__GNUC__) /* Linux and Mac OS X */
+#elif defined(__GNUC__) /* Linux and macOS */
 #  define _MXML_FINI __attribute((destructor)) _mxml_fini
 #else
 #  define _MXML_FINI _fini
@@ -140,7 +140,9 @@ mxml_real_cb(mxml_node_t *node)		/* I - Current node */
 #ifdef HAVE_PTHREAD_H			/**** POSIX threading ****/
 #  include <pthread.h>
 
-static pthread_key_t	_mxml_key = -1;	/* Thread local storage key */
+static int		_mxml_initialized = 0;
+					/* Have we been initialized? */
+static pthread_key_t	_mxml_key;	/* Thread local storage key */
 static pthread_once_t	_mxml_key_once = PTHREAD_ONCE_INIT;
 					/* One-time initialization object */
 static void		_mxml_init(void);
@@ -165,17 +167,8 @@ _mxml_destructor(void *g)		/* I - Global data */
 static void
 _MXML_FINI(void)
 {
-  _mxml_global_t	*global;	/* Global data */
-
-
-  if (_mxml_key != -1)
-  {
-    if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
-      _mxml_destructor(global);
-
+  if (_mxml_initialized)
     pthread_key_delete(_mxml_key);
-    _mxml_key = -1;
-  }
 }
 
 
@@ -212,6 +205,7 @@ _mxml_global(void)
 static void
 _mxml_init(void)
 {
+  _mxml_initialized = 1;
   pthread_key_create(&_mxml_key, _mxml_destructor);
 }
 

+ 7 - 2
mxml.mod/mxml/mxml-private.h

@@ -9,12 +9,15 @@
  * information.
  */
 
+#ifndef _mxml_private_h_
+#  define _mxml_private_h_
+
 /*
  * Include necessary headers...
  */
 
-#include "config.h"
-#include "mxml.h"
+#  include "config.h"
+#  include "mxml.h"
 
 
 /*
@@ -96,3 +99,5 @@ typedef struct _mxml_global_s		/**** Global, per-thread data ****/
 
 extern _mxml_global_t	*_mxml_global(void);
 extern int		_mxml_entity_cb(const char *name);
+
+#endif /* !_mxml_private_h_ */

+ 121 - 25
mxml.mod/mxml/mxml-set.c

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -29,7 +29,7 @@ int					/* O - 0 on success, -1 on failure */
 mxmlSetCDATA(mxml_node_t *node,		/* I - Node to set */
              const char  *data)		/* I - New data string */
 {
-  char	*s;				/* String pointer */
+  char	*s;				/* New element name */
 
 
  /*
@@ -42,22 +42,38 @@ mxmlSetCDATA(mxml_node_t *node,		/* I - Node to set */
       !strncmp(node->child->value.element.name, "![CDATA[", 8))
     node = node->child;
 
-  if (!node || node->type != MXML_ELEMENT || !data ||
+  if (!node || node->type != MXML_ELEMENT ||
       strncmp(node->value.element.name, "![CDATA[", 8))
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
+  else if (!data)
+  {
+    mxml_error("NULL string not allowed.");
+    return (-1);
+  }
 
   if (data == (node->value.element.name + 8))
+  {
+   /*
+    * Don't change the value...
+    */
+
     return (0);
+  }
 
  /*
   * Allocate the new value, free any old element value, and set the new value...
   */
 
-  s = _mxml_strdupf("![CDATA[%s", data);
-
-  if (node->value.element.name)
-    free(node->value.element.name);
+  if ((s = _mxml_strdupf("![CDATA[%s", data)) == NULL)
+  {
+    mxml_error("Unable to allocate memory for CDATA.");
+    return (-1);
+  }
 
+  free(node->value.element.name);
   node->value.element.name = s;
 
   return (0);
@@ -87,7 +103,10 @@ mxmlSetCustom(
     node = node->child;
 
   if (!node || node->type != MXML_CUSTOM)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
 
   if (data == node->value.custom.data)
   {
@@ -119,12 +138,23 @@ int					/* O - 0 on success, -1 on failure */
 mxmlSetElement(mxml_node_t *node,	/* I - Node to set */
                const char  *name)	/* I - New name string */
 {
+  char *s;				/* New name string */
+
+
  /*
   * Range check input...
   */
 
-  if (!node || node->type != MXML_ELEMENT || !name)
+  if (!node || node->type != MXML_ELEMENT)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
+  else if (!name)
+  {
+    mxml_error("NULL string not allowed.");
+    return (-1);
+  }
 
   if (name == node->value.element.name)
     return (0);
@@ -133,10 +163,14 @@ mxmlSetElement(mxml_node_t *node,	/* I - Node to set */
   * Free any old element value and set the new value...
   */
 
-  if (node->value.element.name)
-    free(node->value.element.name);
+  if ((s = strdup(name)) == NULL)
+  {
+    mxml_error("Unable to allocate memory for element name.");
+    return (-1);
+  }
 
-  node->value.element.name = strdup(name);
+  free(node->value.element.name);
+  node->value.element.name = s;
 
   return (0);
 }
@@ -161,7 +195,10 @@ mxmlSetInteger(mxml_node_t *node,	/* I - Node to set */
     node = node->child;
 
   if (!node || node->type != MXML_INTEGER)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
 
  /*
   * Set the new value and return...
@@ -183,6 +220,9 @@ int					/* O - 0 on success, -1 on failure */
 mxmlSetOpaque(mxml_node_t *node,	/* I - Node to set */
               const char  *opaque)	/* I - Opaque string */
 {
+  char *s;				/* New opaque string */
+
+
  /*
   * Range check input...
   */
@@ -191,8 +231,16 @@ mxmlSetOpaque(mxml_node_t *node,	/* I - Node to set */
       node->child && node->child->type == MXML_OPAQUE)
     node = node->child;
 
-  if (!node || node->type != MXML_OPAQUE || !opaque)
+  if (!node || node->type != MXML_OPAQUE)
+  {
+    mxml_error("Wrong node type.");
+    return (-1);
+  }
+  else if (!opaque)
+  {
+    mxml_error("NULL string not allowed.");
     return (-1);
+  }
 
   if (node->value.opaque == opaque)
     return (0);
@@ -201,10 +249,14 @@ mxmlSetOpaque(mxml_node_t *node,	/* I - Node to set */
   * Free any old opaque value and set the new value...
   */
 
-  if (node->value.opaque)
-    free(node->value.opaque);
+  if ((s = strdup(opaque)) == NULL)
+  {
+    mxml_error("Unable to allocate memory for opaque string.");
+    return (-1);
+  }
 
-  node->value.opaque = strdup(opaque);
+  free(node->value.opaque);
+  node->value.opaque = s;
 
   return (0);
 }
@@ -235,8 +287,16 @@ mxmlSetOpaquef(mxml_node_t *node,	/* I - Node to set */
       node->child && node->child->type == MXML_OPAQUE)
     node = node->child;
 
-  if (!node || node->type != MXML_OPAQUE || !format)
+  if (!node || node->type != MXML_OPAQUE)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
+  else if (!format)
+  {
+    mxml_error("NULL string not allowed.");
+    return (-1);
+  }
 
  /*
   * Format the new string, free any old string value, and set the new value...
@@ -246,9 +306,13 @@ mxmlSetOpaquef(mxml_node_t *node,	/* I - Node to set */
   s = _mxml_vstrdupf(format, ap);
   va_end(ap);
 
-  if (node->value.opaque)
-    free(node->value.opaque);
+  if (!s)
+  {
+    mxml_error("Unable to allocate memory for opaque string.");
+    return (-1);
+  }
 
+  free(node->value.opaque);
   node->value.opaque = s;
 
   return (0);
@@ -274,7 +338,10 @@ mxmlSetReal(mxml_node_t *node,		/* I - Node to set */
     node = node->child;
 
   if (!node || node->type != MXML_REAL)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
 
  /*
   * Set the new value and return...
@@ -297,6 +364,9 @@ mxmlSetText(mxml_node_t *node,		/* I - Node to set */
             int         whitespace,	/* I - 1 = leading whitespace, 0 = no whitespace */
 	    const char  *string)	/* I - String */
 {
+  char *s;				/* New string */
+
+
  /*
   * Range check input...
   */
@@ -305,8 +375,16 @@ mxmlSetText(mxml_node_t *node,		/* I - Node to set */
       node->child && node->child->type == MXML_TEXT)
     node = node->child;
 
-  if (!node || node->type != MXML_TEXT || !string)
+  if (!node || node->type != MXML_TEXT)
+  {
+    mxml_error("Wrong node type.");
+    return (-1);
+  }
+  else if (!string)
+  {
+    mxml_error("NULL string not allowed.");
     return (-1);
+  }
 
   if (string == node->value.text.string)
   {
@@ -318,11 +396,16 @@ mxmlSetText(mxml_node_t *node,		/* I - Node to set */
   * Free any old string value and set the new value...
   */
 
-  if (node->value.text.string)
-    free(node->value.text.string);
+  if ((s = strdup(string)) == NULL)
+  {
+    mxml_error("Unable to allocate memory for text string.");
+    return (-1);
+  }
+
+  free(node->value.text.string);
 
   node->value.text.whitespace = whitespace;
-  node->value.text.string     = strdup(string);
+  node->value.text.string     = s;
 
   return (0);
 }
@@ -352,8 +435,16 @@ mxmlSetTextf(mxml_node_t *node,		/* I - Node to set */
       node->child && node->child->type == MXML_TEXT)
     node = node->child;
 
-  if (!node || node->type != MXML_TEXT || !format)
+  if (!node || node->type != MXML_TEXT)
+  {
+    mxml_error("Wrong node type.");
     return (-1);
+  }
+  else if (!format)
+  {
+    mxml_error("NULL string not allowed.");
+    return (-1);
+  }
 
  /*
   * Free any old string value and set the new value...
@@ -363,8 +454,13 @@ mxmlSetTextf(mxml_node_t *node,		/* I - Node to set */
   s = _mxml_vstrdupf(format, ap);
   va_end(ap);
 
-  if (node->value.text.string)
-    free(node->value.text.string);
+  if (!s)
+  {
+    mxml_error("Unable to allocate memory for text string.");
+    return (-1);
+  }
+
+  free(node->value.text.string);
 
   node->value.text.whitespace = whitespace;
   node->value.text.string     = s;

+ 8 - 6
mxml.mod/mxml/mxml-string.c

@@ -114,7 +114,7 @@ _mxml_strdupf(const char *format,	/* I - Printf-style format string */
 size_t					/* O - Number of bytes copied */
 _mxml_strlcat(char       *dst,		/* I - Destination buffer */
               const char *src,		/* I - Source string */
-              size_t     dstsize)	/* I - Size of destinatipon buffer */
+              size_t     dstsize)	/* I - Size of destination buffer */
 {
   size_t	srclen;			/* Length of source string */
   size_t	dstlen;			/* Length of destination string */
@@ -160,7 +160,7 @@ _mxml_strlcat(char       *dst,		/* I - Destination buffer */
 size_t					/* O - Number of bytes copied */
 _mxml_strlcpy(char       *dst,		/* I - Destination buffer */
               const char *src,		/* I - Source string */
-              size_t     dstsize)	/* I - Size of destinatipon buffer */
+              size_t     dstsize)	/* I - Size of destination buffer */
 {
   size_t        srclen;                 /* Length of source string */
 
@@ -374,11 +374,11 @@ _mxml_vsnprintf(char       *buffer,	/* O - Output buffer */
 	    if ((width + 2) > sizeof(temp))
 	      break;
 
-#ifdef HAVE_LONG_LONG
+#ifdef HAVE_LONG_LONG_INT
 	    if (size == 'L')
 	      sprintf(temp, tformat, va_arg(ap, long long));
 	    else
-#endif /* HAVE_LONG_LONG */
+#endif /* HAVE_LONG_LONG_INT */
 	    sprintf(temp, tformat, va_arg(ap, int));
 
             bytes += strlen(temp);
@@ -517,8 +517,10 @@ _mxml_vstrdupf(const char *format,	/* I - Printf-style format string */
 
 #else
   int		bytes;			/* Number of bytes required */
-  char		*buffer,		/* String buffer */
-		temp[256];		/* Small buffer for first vsnprintf */
+  char		*buffer;		/* String buffer */
+#  ifndef _WIN32
+  char		temp[256];		/* Small buffer for first vsnprintf */
+#  endif /* !_WIN32 */
 
 
  /*

+ 7 - 3
mxml.mod/mxml/mxml.h

@@ -3,7 +3,7 @@
  *
  * https://www.msweet.org/mxml
  *
- * Copyright © 2003-2019 by Michael R Sweet.
+ * Copyright © 2003-2021 by Michael R Sweet.
  *
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
  * information.
@@ -32,7 +32,7 @@
  */
 
 #  define MXML_MAJOR_VERSION	3	/* Major version number */
-#  define MXML_MINOR_VERSION	0	/* Minor version number */
+#  define MXML_MINOR_VERSION	2	/* Minor version number */
 
 #  define MXML_TAB		8	/* Tabs every N columns */
 
@@ -267,7 +267,11 @@ extern mxml_node_t	*mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
  * Semi-private functions...
  */
 
-extern void		mxml_error(const char *format, ...);
+extern void		mxml_error(const char *format, ...)
+#    ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 1, 2)))
+#    endif /* __GNUC__ */
+;
 extern mxml_type_t	mxml_ignore_cb(mxml_node_t *node);
 extern mxml_type_t	mxml_integer_cb(mxml_node_t *node);
 extern mxml_type_t	mxml_opaque_cb(mxml_node_t *node);

+ 2 - 2
mxml.mod/mxml/mxml.pc.in

@@ -6,5 +6,5 @@ includedir=@includedir@
 Name: Mini-XML
 Description: Lightweight XML support library
 Version: @VERSION@
-Libs: @PC_LIBS@ @PTHREAD_LIBS@
-Cflags: @PC_CFLAGS@ @PTHREAD_FLAGS@
+Libs: @PC_LIBS@
+Cflags: @PC_CFLAGS@

+ 1 - 1
mxml.mod/mxml/mxml.spec

@@ -11,7 +11,7 @@
 
 Summary: Small XML file parsing library
 Name: mxml
-Version: 3.0
+Version: 3.2
 Release: 1
 License: Apache 2.0
 Group: Development/Libraries

+ 84 - 0
mxml.mod/mxml/test/class.cxx

@@ -0,0 +1,84 @@
+class foo_c : public bar_c		// Foo class derived from bar
+{
+  float	foo;				/* Real number */
+  int	bar;				/* Integer */
+
+  public:
+
+  foo_c(float f, int b);
+  ~foo_c();
+
+  // 'get_bar()' - Get the value of bar.
+  int // O - Value of bar
+  get_bar()
+  {
+    return (bar);
+  }
+
+  // 'get_foo()' - Get the value of foo.
+  float // O - Value of foo
+  get_foo()
+  {
+    return (foo);
+  }
+
+  // 'set_bar()' - Set the value of bar.
+  void
+  set_bar(int b) // I - Value of bar
+  {
+    bar = b;
+  }
+
+  // 'set_foo()' - Set the value of foo.
+  void
+  set_foo(float f) // I - Value of foo
+  {
+    foo = f;
+  }
+
+  // 'set_foobar()' - Set foo and optionally bar (should show default args).
+  void
+  set_foobar(float f, // I - Value of foo
+             int b = 0) // I - Value of bar
+  {
+    foo = f;
+    bar = b;
+  }
+
+  protected:
+
+  static int global;			/* Global integer */
+
+  // 'get_global()' - Get the global integer.
+  int // O - Integer
+  get_global()
+  {
+    return (global);
+  }
+
+  private:
+
+  int barfoo; // Another private integer
+
+  public: 
+
+  // 'get_barfoo()' - Get the barfoo value.
+  int // O - Barfoo value
+  get_barfoo()
+  {
+    return (barfoo);
+  }
+}
+
+// 'foo_c::foo_c()' - Create a foo_c class.
+foo_c::foo_c(float f, // I - Value of foo
+             int b) // I - Value of bar
+{
+  foo = f;
+  bar = b;
+}
+
+// 'foo_c::~foo_c()' - Destroy a foo_c class.
+foo_c::~foo_c()
+{
+}

+ 47 - 0
mxml.mod/mxml/test/dotest.sh

@@ -0,0 +1,47 @@
+#!/bin/sh
+(cd ..; make mxmldoc-static)
+
+files=""
+mode=""
+
+while test $# -gt 0; do
+	arg="$1"
+	shift
+
+	case "$arg" in
+		-f) framed="--framed framed" ;;
+		-g) mode="gdb" ;;
+		-v) mode="valgrind" ;;
+		*.h | *.c | *.cxx) files="$files $arg" ;;
+		*)
+			echo "Usage: ./dotest.sh [-f] [-g] [-v] [files]"
+			exit 1
+			;;
+	esac
+done
+
+if test "$files" = ""; then
+	files=*.cxx
+fi
+
+rm -f test.xml
+
+case "$mode" in
+	gdb)
+		echo "break malloc_error_break" >.gdbcmds
+		echo "set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib" >>.gdbcmds
+		echo "run $framed test.xml $files >test.html 2>test.log" >>.gdbcmds
+		gdb -x .gdbcmds ../mxmldoc-static
+		;;
+
+	valgrind)
+		valgrind --log-fd=3 --leak-check=yes \
+			../mxmldoc-static $framed test.xml $files \
+			>test.html 2>test.log 3>test.valgrind
+		;;
+
+	*)
+		../mxmldoc-static $framed test.xml $files >test.html 2>test.log
+		;;
+esac
+

+ 17 - 0
mxml.mod/mxml/test/enum.cxx

@@ -0,0 +1,17 @@
+typedef enum foo_enum_e			/* Sample enumeration type */
+{
+  FOO_ONE,				/* One fish */
+  FOO_TWO,				/* Two fish */
+  FOO_RED,				/* Red fish */
+  FOO_BLUE,				/* Blue fish */
+  FOO_PRIVATE				/* Private fish @private@ */
+} foo_enum_t;
+
+typedef enum foo_enum2_e		/* Sample enumeration type #2 */
+{
+  FOO2_ONE,				/* One fish #2 */
+  FOO2_TWO,				/* Two fish #2 */
+  FOO2_RED,				/* Red fish #2 */
+  FOO2_BLUE,				/* Blue fish #2 */
+  FOO2_PRIVATE				/* Private fish #2 @private@ */
+} foo_enum2_t;

+ 107 - 0
mxml.mod/mxml/test/function.cxx

@@ -0,0 +1,107 @@
+/*
+ * 'foo_void_function()' - Do foo with bar.
+ *
+ * Use the @link foo_float_function@ or @link foo_int_function@ functions
+ * instead.  Pass @code NULL@ for "three" then there is no string to print.
+ *
+ * @deprecated@
+ */
+
+void
+foo_void_function(int        one,	/* I - Integer */
+                  float      *two,	/* O - Real number */
+                  const char *three)	/* I - String */
+{
+  if (one)
+  {
+    puts("Hello, World!");
+  }
+  else
+    puts(three);
+
+  *two = 2.0f;
+}
+
+
+/*
+ * 'foo_float_function()' - Do foo with bar.
+ *
+ * @since 1.2@
+ */
+
+float					/* O - Real number */
+foo_float_function(int        one,	/* I - Integer */
+                   const char *two)	/* I - String */
+{
+  if (one)
+  {
+    puts("Hello, World!");
+  }
+  else
+    puts(two);
+
+  return (2.0f);
+}
+
+
+/*
+ * 'foo_default_string()' - Do something with a defaulted string arg.
+ */
+
+int					/* O - Integer value */
+foo_default_string(int one,		/* I - Integer */
+                   const char *two = "2")
+					/* I - String */
+{
+  if (one)
+  {
+    puts("Hello, World!");
+  }
+  else
+    puts(two);
+
+  return (2);
+}
+
+
+/*
+ * 'foo_default_int()' - Do something with a defaulted int arg.
+ */
+
+int					/* O - Integer value */
+foo_default_int(int one,		/* I - Integer */
+                int two = 2)		/* I - Integer */
+{
+  if (one)
+  {
+    puts("Hello, World!");
+  }
+  else
+    puts(two);
+
+  return (2);
+}
+
+
+/*
+ * 'foo_void_func()' - Function taking no arguments.
+ */
+
+void
+foo_void_func(void)
+{
+  puts("foo_void_func()");
+}
+
+
+/*
+ * 'foo_private_func()' - Private function.
+ *
+ * @private@
+ */
+
+void
+foo_private_func(void)
+{
+  puts("foo_private_func()");
+}

+ 1 - 0
mxml.mod/mxml/test/functype.cxx

@@ -0,0 +1 @@
+typedef int (*foo_func_t)(void *foo, int bar);	/**** Foo function type ****/

+ 55 - 0
mxml.mod/mxml/test/struct.cxx

@@ -0,0 +1,55 @@
+typedef struct foo_s			/* Foo structure */
+{
+  float	foo;				/* Real number */
+  int	bar;				/* Integer */
+
+  foo_s(float f, int b);
+  ~foo_s();
+
+  // 'get_bar()' - Get the value of bar.
+  int // O - Value of bar
+  get_bar()
+  {
+    return (bar);
+  }
+
+  // 'get_foo()' - Get the value of foo.
+  float // O - Value of foo
+  get_foo()
+  {
+    return (foo);
+  }
+
+  // 'set_bar()' - Set the value of bar.
+  void
+  set_bar(int b) // I - Value of bar
+  {
+    bar = b;
+  }
+
+  // 'set_foo()' - Set the value of foo.
+  void
+  set_foo(float f) // I - Value of foo
+  {
+    foo = f;
+  }
+} foo_t;
+
+// 'foo_s::foo_s()' - Create a foo_s structure.
+foo_s::foo_s(float f, // I - Value of foo
+             int b) // I - Value of bar
+{
+  foo = f;
+  bar = b;
+}
+
+// 'foo_s::~foo_s()' - Destroy a foo_s structure.
+foo_s::~foo_s()
+{
+}
+
+typedef struct foo_private_s		/* @private@ */
+{
+  int	a;				/* Value of "a" */
+  char	b[255];				/* Value of "b" */
+} foo_private_t;

+ 3 - 0
mxml.mod/mxml/test/type.cxx

@@ -0,0 +1,3 @@
+typedef int foo_simple_t;		/* Simple integer type */
+
+typedef int foo_simple_private_t;	/* @private@ */

+ 28 - 26
mxml.mod/mxml/testmxml.c

@@ -56,7 +56,8 @@ main(int  argc,				/* I - Number of command-line args */
   int			i;		/* Looping var */
   FILE			*fp;		/* File to read */
   int			fd;		/* File descriptor */
-  mxml_node_t		*tree,		/* XML tree */
+  mxml_node_t		*xml,		/* <?xml ...?> node */
+			*tree,		/* Element tree */
 			*node;		/* Node which should be in test.xml */
   mxml_index_t		*ind;		/* XML index */
   char			buffer[16384];	/* Save string */
@@ -84,7 +85,8 @@ main(int  argc,				/* I - Number of command-line args */
   * Test the basic functionality...
   */
 
-  tree = mxmlNewElement(MXML_NO_PARENT, "element");
+  xml  = mxmlNewXML("1.0");
+  tree = mxmlNewElement(xml, "element");
 
   if (!tree)
   {
@@ -459,14 +461,14 @@ main(int  argc,				/* I - Number of command-line args */
     return (1);
   }
 
-  mxmlDelete(tree);
+  mxmlDelete(xml);
 
  /*
   * Open the file/string using the default (MXML_NO_CALLBACK) callback...
   */
 
   if (argv[1][0] == '<')
-    tree = mxmlLoadString(NULL, argv[1], MXML_NO_CALLBACK);
+    xml = mxmlLoadString(NULL, argv[1], MXML_NO_CALLBACK);
   else if ((fp = fopen(argv[1], "rb")) == NULL)
   {
     perror(argv[1]);
@@ -478,12 +480,12 @@ main(int  argc,				/* I - Number of command-line args */
     * Read the file...
     */
 
-    tree = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
+    xml = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
 
     fclose(fp);
   }
 
-  if (!tree)
+  if (!xml)
   {
     fputs("Unable to read XML file with default callback.\n", stderr);
     return (1);
@@ -498,7 +500,7 @@ main(int  argc,				/* I - Number of command-line args */
     * properly...
     */
 
-    if ((node = mxmlFindPath(tree, "group/option/keyword")) == NULL)
+    if ((node = mxmlFindPath(xml, "group/option/keyword")) == NULL)
     {
       fputs("Unable to find group/option/keyword element in XML tree.\n", stderr);
       mxmlDelete(tree);
@@ -508,27 +510,27 @@ main(int  argc,				/* I - Number of command-line args */
     if (node->type != MXML_TEXT)
     {
       fputs("No child node of group/option/keyword.\n", stderr);
-      mxmlSaveFile(tree, stderr, MXML_NO_CALLBACK);
-      mxmlDelete(tree);
+      mxmlSaveFile(xml, stderr, MXML_NO_CALLBACK);
+      mxmlDelete(xml);
       return (1);
     }
 
     if ((text = mxmlGetText(node, NULL)) == NULL || strcmp(text, "InputSlot"))
     {
       fprintf(stderr, "Child node of group/option/value has value \"%s\" instead of \"InputSlot\".\n", text ? text : "(null)");
-      mxmlDelete(tree);
+      mxmlDelete(xml);
       return (1);
     }
   }
 
-  mxmlDelete(tree);
+  mxmlDelete(xml);
 
  /*
   * Open the file...
   */
 
   if (argv[1][0] == '<')
-    tree = mxmlLoadString(NULL, argv[1], type_cb);
+    xml = mxmlLoadString(NULL, argv[1], type_cb);
   else if ((fp = fopen(argv[1], "rb")) == NULL)
   {
     perror(argv[1]);
@@ -540,12 +542,12 @@ main(int  argc,				/* I - Number of command-line args */
     * Read the file...
     */
 
-    tree = mxmlLoadFile(NULL, fp, type_cb);
+    xml = mxmlLoadFile(NULL, fp, type_cb);
 
     fclose(fp);
   }
 
-  if (!tree)
+  if (!xml)
   {
     fputs("Unable to read XML file.\n", stderr);
     return (1);
@@ -558,7 +560,7 @@ main(int  argc,				/* I - Number of command-line args */
     * properly...
     */
 
-    if ((node = mxmlFindElement(tree, tree, "choice", NULL, NULL,
+    if ((node = mxmlFindElement(xml, xml, "choice", NULL, NULL,
                                 MXML_DESCEND)) == NULL)
     {
       fputs("Unable to find first <choice> element in XML tree.\n", stderr);
@@ -566,7 +568,7 @@ main(int  argc,				/* I - Number of command-line args */
       return (1);
     }
 
-    if (!mxmlFindElement(node, tree, "choice", NULL, NULL, MXML_NO_DESCEND))
+    if (!mxmlFindElement(node, xml, "choice", NULL, NULL, MXML_NO_DESCEND))
     {
       fputs("Unable to find second <choice> element in XML tree.\n", stderr);
       mxmlDelete(tree);
@@ -578,13 +580,13 @@ main(int  argc,				/* I - Number of command-line args */
   * Print the XML tree...
   */
 
-  mxmlSaveFile(tree, stdout, whitespace_cb);
+  mxmlSaveFile(xml, stdout, whitespace_cb);
 
  /*
   * Save the XML tree to a string and print it...
   */
 
-  if (mxmlSaveString(tree, buffer, sizeof(buffer), whitespace_cb) > 0)
+  if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb) > 0)
   {
     if (argc == 3)
     {
@@ -598,7 +600,7 @@ main(int  argc,				/* I - Number of command-line args */
   * Delete the tree...
   */
 
-  mxmlDelete(tree);
+  mxmlDelete(xml);
 
  /*
   * Read from/write to file descriptors...
@@ -620,7 +622,7 @@ main(int  argc,				/* I - Number of command-line args */
     * Read the file...
     */
 
-    tree = mxmlLoadFd(NULL, fd, type_cb);
+    xml = mxmlLoadFd(NULL, fd, type_cb);
 
     close(fd);
 
@@ -641,7 +643,7 @@ main(int  argc,				/* I - Number of command-line args */
     * Write the file...
     */
 
-    mxmlSaveFd(tree, fd, whitespace_cb);
+    mxmlSaveFd(xml, fd, whitespace_cb);
 
     close(fd);
 
@@ -649,7 +651,7 @@ main(int  argc,				/* I - Number of command-line args */
     * Delete the tree...
     */
 
-    mxmlDelete(tree);
+    mxmlDelete(xml);
   }
 
  /*
@@ -659,7 +661,7 @@ main(int  argc,				/* I - Number of command-line args */
   memset(event_counts, 0, sizeof(event_counts));
 
   if (argv[1][0] == '<')
-    mxmlSAXLoadString(NULL, argv[1], type_cb, sax_cb, NULL);
+    mxmlRelease(mxmlSAXLoadString(NULL, argv[1], type_cb, sax_cb, NULL));
   else if ((fp = fopen(argv[1], "rb")) == NULL)
   {
     perror(argv[1]);
@@ -671,7 +673,7 @@ main(int  argc,				/* I - Number of command-line args */
     * Read the file...
     */
 
-    mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL);
+    mxmlRelease(mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL));
 
     fclose(fp);
   }
@@ -692,9 +694,9 @@ main(int  argc,				/* I - Number of command-line args */
       return (1);
     }
 
-    if (event_counts[MXML_SAX_DATA] != 60)
+    if (event_counts[MXML_SAX_DATA] != 61)
     {
-      fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 60 times.\n",
+      fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 61 times.\n",
               event_counts[MXML_SAX_DATA]);
       return (1);
     }

+ 8 - 3
mxml.mod/mxml/vcnet/config.h

@@ -2,7 +2,7 @@
  * Visual Studio configuration file for Mini-XML, a small XML file parsing
  * library.
  *
- * Copyright 2003-2019 by Michael R Sweet.
+ * Copyright 2003-2021 by Michael R Sweet.
  *
  * These coded instructions, statements, and computer programs are the
  * property of Michael R Sweet and are protected by Federal copyright
@@ -63,7 +63,7 @@
  * Version number...
  */
 
-#define MXML_VERSION "Mini-XML v2.13"
+#define MXML_VERSION "Mini-XML v3.3.1"
 
 
 /*
@@ -77,7 +77,7 @@
  * Long long support...
  */
 
-#define HAVE_LONG_LONG 1
+#define HAVE_LONG_LONG_INT 1
 
 
 /*
@@ -113,6 +113,11 @@ extern char	*_mxml_strdup(const char *);
 #    define strdup _mxml_strdup
 #  endif /* !HAVE_STRDUP */
 
+#  ifndef HAVE_STRLCAT
+extern size_t	_mxml_strlcat(char *, const char *, size_t);
+#    define strlcat _mxml_strlcat
+#  endif /* !HAVE_STRLCAT */
+
 #  ifndef HAVE_STRLCPY
 extern size_t	_mxml_strlcpy(char *, const char *, size_t);
 #    define strlcpy _mxml_strlcpy

+ 30 - 0
mxml.mod/mxml/vcnet/libmxml1_native.nuspec

@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
+    <metadata>
+        <id>libmxml1_native</id>
+        <title>Small XML File Parsing Library for VS2019+</title>
+        <version>3.3.0</version>
+        <authors>Michael R Sweet</authors>
+        <owners>michaelrsweet</owners>
+        <projectUrl>https://github.com/michaelrsweet/mxml</projectUrl>
+        <license type="expression">Apache-2.0</license>
+        <icon>build/native/mxml-128.png</icon>
+	<readme>build/native/README.md</readme>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>Small XML File Parsing Library</description>
+        <summary>Mini-XML is a small XML parsing library that you can use to read XML data files or strings in your application without requiring large non-standard libraries.</summary>
+        <copyright>Copyright © 2003-2021 by Michael R Sweet</copyright>
+        <tags>xml</tags>
+	<dependencies>
+	    <dependency id="libmxml1_native.redist" version="3.3.0" />
+	</dependencies>
+    </metadata>
+    <files>
+        <file src="..\doc\mxml-128.png" target="build\native" />
+        <file src="..\README.md" target="build\native" />
+        <file src="libmxml1_native.props" target="build\native" />
+        <file src="..\mxml.h" target="build\native\include" />
+        <!--<file src="Win32\**\libmxml1.lib" target="build\native\lib\Win32" />-->
+        <file src="x64\**\libmxml1.lib" target="build\native\lib\x64" />
+    </files>
+</package>

+ 11 - 0
mxml.mod/mxml/vcnet/libmxml1_native.props

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>$(MSBuildThisFileDirectory)\lib\$(Platform)\$(Configuration)\libmxml1.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+</Project>

+ 25 - 0
mxml.mod/mxml/vcnet/libmxml1_native.redist.nuspec

@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
+    <metadata>
+        <id>libmxml1_native.redist</id>
+        <title>Small XML File Parsing Library for VS2019+ Redist</title>
+        <version>3.3.0</version>
+        <authors>Michael R Sweet</authors>
+        <owners>michaelrsweet</owners>
+        <projectUrl>https://github.com/michaelrsweet/mxml</projectUrl>
+        <license type="expression">Apache-2.0</license>
+        <icon>build/native/mxml-128.png</icon>
+	<readme>build/native/README.md</readme>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>Redistributable components for package 'libmxml1_native'. This package should only be installed as a dependency.</description>
+        <summary>Mini-XML is a small XML parsing library that you can use to read XML data files or strings in your application without requiring large non-standard libraries. This package provides the redistributable content for Mini-XML.</summary>
+        <copyright>Copyright © 2003-2021 by Michael R Sweet</copyright>
+        <tags>xml</tags>
+    </metadata>
+    <files>
+        <file src="..\doc\mxml-128.png" target="build\native" />
+        <file src="..\README.md" target="build\native" />
+        <!--<file src="Win32\**\libmxml1.dll" target="build\native\bin\Win32" />-->
+        <file src="x64\**\libmxml1.dll" target="build\native\bin\x64" />
+    </files>
+</package>

+ 8 - 35
mxml.mod/mxml/vcnet/mxml.sln

@@ -1,14 +1,9 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28010.2036
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30204.135
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mxml1", "mxml1.vcxproj", "{E5AA9476-9751-4654-8109-B1A2112D5E73}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mxmldoc", "mxmldoc.vcxproj", "{D909892E-520A-4322-9A47-DAEBDA9CC7A7}"
-	ProjectSection(ProjectDependencies) = postProject
-		{E5AA9476-9751-4654-8109-B1A2112D5E73} = {E5AA9476-9751-4654-8109-B1A2112D5E73}
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testmxml", "testmxml.vcxproj", "{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}"
 	ProjectSection(ProjectDependencies) = postProject
 		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958} = {CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}
@@ -18,44 +13,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mxmlstat", "mxmlstat.vcxpro
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Win32 = Debug|Win32
 		Debug|x64 = Debug|x64
-		Release|Win32 = Release|Win32
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Debug|Win32.ActiveCfg = Debug|Win32
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Debug|Win32.Build.0 = Debug|Win32
 		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Debug|x64.ActiveCfg = Debug|Win32
 		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Debug|x64.Build.0 = Debug|Win32
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|Win32.ActiveCfg = Debug|Win32
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|Win32.Build.0 = Debug|Win32
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|x64.ActiveCfg = Debug|Win32
-		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|x64.Build.0 = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Debug|Win32.Build.0 = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Debug|x64.ActiveCfg = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Debug|x64.Build.0 = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Release|Win32.ActiveCfg = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Release|Win32.Build.0 = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Release|x64.ActiveCfg = Debug|Win32
-		{D909892E-520A-4322-9A47-DAEBDA9CC7A7}.Release|x64.Build.0 = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Debug|Win32.ActiveCfg = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Debug|Win32.Build.0 = Debug|Win32
+		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|x64.ActiveCfg = Debug|x64
+		{E5AA9476-9751-4654-8109-B1A2112D5E73}.Release|x64.Build.0 = Debug|x64
 		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Debug|x64.ActiveCfg = Debug|Win32
 		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Debug|x64.Build.0 = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|Win32.ActiveCfg = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|Win32.Build.0 = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|x64.ActiveCfg = Debug|Win32
-		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|x64.Build.0 = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Debug|Win32.ActiveCfg = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Debug|Win32.Build.0 = Debug|Win32
+		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|x64.ActiveCfg = Debug|x64
+		{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}.Release|x64.Build.0 = Debug|x64
 		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Debug|x64.ActiveCfg = Debug|Win32
 		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Debug|x64.Build.0 = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|Win32.ActiveCfg = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|Win32.Build.0 = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|x64.ActiveCfg = Debug|Win32
-		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|x64.Build.0 = Debug|Win32
+		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|x64.ActiveCfg = Debug|x64
+		{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}.Release|x64.Build.0 = Debug|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 80 - 80
mxml.mod/mxml/vcnet/mxml1.def

@@ -1,80 +1,80 @@
-LIBRARY "MXML1"
-EXPORTS
- _mxml_strdupf
- _mxml_strlcpy
- _mxml_vstrdupf
- mxml_ignore_cb
- mxml_integer_cb
- mxml_opaque_cb
- mxml_real_cb
- mxmlAdd
- mxmlDelete
- mxmlElementDeleteAttr
- mxmlElementGetAttrByIndex
- mxmlElementGetAttrCount
- mxmlElementGetAttr
- mxmlElementSetAttr
- mxmlElementSetAttrf
- mxmlEntityAddCallback
- mxmlEntityGetName
- mxmlEntityGetValue
- mxmlEntityRemoveCallback
- mxmlFindElement
- mxmlFindPath
- mxmlGetCDATA
- mxmlGetCustom
- mxmlGetElement
- mxmlGetFirstChild
- mxmlGetInteger
- mxmlGetLastChild
- mxmlGetNextSibling
- mxmlGetOpaque
- mxmlGetParent
- mxmlGetPrevSibling
- mxmlGetReal
- mxmlGetRefCount
- mxmlGetText
- mxmlGetType
- mxmlGetUserData
- mxmlIndexDelete
- mxmlIndexEnum
- mxmlIndexFind
- mxmlIndexGetCount
- mxmlIndexNew
- mxmlIndexReset
- mxmlLoadFd
- mxmlLoadFile
- mxmlLoadString
- mxmlNewCDATA
- mxmlNewCustom
- mxmlNewElement
- mxmlNewInteger
- mxmlNewOpaque
- mxmlNewReal
- mxmlNewText
- mxmlNewTextf
- mxmlNewXML
- mxmlRelease
- mxmlRemove
- mxmlRetain
- mxmlSaveAllocString
- mxmlSaveFd
- mxmlSaveFile
- mxmlSaveString
- mxmlSAXLoadFd
- mxmlSAXLoadFile
- mxmlSAXLoadString
- mxmlSetCDATA
- mxmlSetCustom
- mxmlSetCustomHandlers
- mxmlSetElement
- mxmlSetErrorCallback
- mxmlSetInteger
- mxmlSetOpaque
- mxmlSetReal
- mxmlSetText
- mxmlSetTextf
- mxmlSetUserData
- mxmlSetWrapMargin
- mxmlWalkNext
- mxmlWalkPrev
+LIBRARY "MXML1"
+EXPORTS
+ _mxml_strdupf
+ _mxml_strlcpy
+ _mxml_vstrdupf
+ mxml_ignore_cb
+ mxml_integer_cb
+ mxml_opaque_cb
+ mxml_real_cb
+ mxmlAdd
+ mxmlDelete
+ mxmlElementDeleteAttr
+ mxmlElementGetAttrByIndex
+ mxmlElementGetAttrCount
+ mxmlElementGetAttr
+ mxmlElementSetAttr
+ mxmlElementSetAttrf
+ mxmlEntityAddCallback
+ mxmlEntityGetName
+ mxmlEntityGetValue
+ mxmlEntityRemoveCallback
+ mxmlFindElement
+ mxmlFindPath
+ mxmlGetCDATA
+ mxmlGetCustom
+ mxmlGetElement
+ mxmlGetFirstChild
+ mxmlGetInteger
+ mxmlGetLastChild
+ mxmlGetNextSibling
+ mxmlGetOpaque
+ mxmlGetParent
+ mxmlGetPrevSibling
+ mxmlGetReal
+ mxmlGetRefCount
+ mxmlGetText
+ mxmlGetType
+ mxmlGetUserData
+ mxmlIndexDelete
+ mxmlIndexEnum
+ mxmlIndexFind
+ mxmlIndexGetCount
+ mxmlIndexNew
+ mxmlIndexReset
+ mxmlLoadFd
+ mxmlLoadFile
+ mxmlLoadString
+ mxmlNewCDATA
+ mxmlNewCustom
+ mxmlNewElement
+ mxmlNewInteger
+ mxmlNewOpaque
+ mxmlNewReal
+ mxmlNewText
+ mxmlNewTextf
+ mxmlNewXML
+ mxmlRelease
+ mxmlRemove
+ mxmlRetain
+ mxmlSaveAllocString
+ mxmlSaveFd
+ mxmlSaveFile
+ mxmlSaveString
+ mxmlSAXLoadFd
+ mxmlSAXLoadFile
+ mxmlSAXLoadString
+ mxmlSetCDATA
+ mxmlSetCustom
+ mxmlSetCustomHandlers
+ mxmlSetElement
+ mxmlSetErrorCallback
+ mxmlSetInteger
+ mxmlSetOpaque
+ mxmlSetReal
+ mxmlSetText
+ mxmlSetTextf
+ mxmlSetUserData
+ mxmlSetWrapMargin
+ mxmlWalkNext
+ mxmlWalkPrev

+ 17 - 17
mxml.mod/mxml/vcnet/mxml1.vcxproj

@@ -21,27 +21,27 @@
   <PropertyGroup Label="Globals">
     <ProjectGuid>{E5AA9476-9751-4654-8109-B1A2112D5E73}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -68,23 +68,23 @@
     <_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>true</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>false</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>true</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>false</LinkIncremental>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -100,7 +100,7 @@
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\mxml1.dll</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\mxml1.dll</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ModuleDefinitionFile>.\mxml1.def</ModuleDefinitionFile>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -122,7 +122,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\mxml1.dll</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\mxml1.dll</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ModuleDefinitionFile>.\mxml1.def</ModuleDefinitionFile>
       <GenerateDebugInformation>false</GenerateDebugInformation>
@@ -151,7 +151,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\mxml1.dll</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\mxml1.dll</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ModuleDefinitionFile>.\mxml1.def</ModuleDefinitionFile>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -176,7 +176,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\mxml1.dll</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\mxml1.dll</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <ModuleDefinitionFile>.\mxml1.def</ModuleDefinitionFile>
       <GenerateDebugInformation>false</GenerateDebugInformation>

+ 13 - 13
mxml.mod/mxml/vcnet/mxmlstat.vcxproj

@@ -39,32 +39,32 @@
     <ProjectGuid>{CDEEBB3C-D45B-4CC5-BE9B-0BD415A27958}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
     <RootNamespace>mxmlstat</RootNamespace>
-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
@@ -88,23 +88,23 @@
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <LinkIncremental>true</LinkIncremental>
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <LinkIncremental>true</LinkIncremental>
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <LinkIncremental>false</LinkIncremental>
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <LinkIncremental>false</LinkIncremental>
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>

+ 17 - 17
mxml.mod/mxml/vcnet/testmxml.vcxproj

@@ -21,27 +21,27 @@
   <PropertyGroup Label="Globals">
     <ProjectGuid>{75CAC6C4-A6BC-4935-A3C9-8F0AE0744227}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@@ -68,23 +68,23 @@
     <_ProjectFileVersion>15.0.27924.0</_ProjectFileVersion>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>true</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>false</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>true</LinkIncremental>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <OutDir>$(Configuration)\$(Platform)\$(ProjectName)\</OutDir>
-    <IntDir>$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
+    <OutDir>$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+    <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
     <LinkIncremental>false</LinkIncremental>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -100,7 +100,7 @@
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\testmxml.exe</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\testmxml.exe</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)testmxml.pdb</ProgramDatabaseFile>
@@ -121,7 +121,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\testmxml.exe</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\testmxml.exe</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Console</SubSystem>
@@ -149,7 +149,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\testmxml.exe</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\testmxml.exe</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <ProgramDatabaseFile>$(OutDir)testmxml.pdb</ProgramDatabaseFile>
@@ -173,7 +173,7 @@
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
     </ClCompile>
     <Link>
-      <OutputFile>$(Configuration)\$(Platform)\$(ProductName)\testmxml.exe</OutputFile>
+      <OutputFile>$(Platform)\$(Configuration)\$(ProductName)\testmxml.exe</OutputFile>
       <IgnoreSpecificDefaultLibraries>oldnames.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Console</SubSystem>

+ 74 - 0
mxml.mod/mxml/xcode/config.h

@@ -0,0 +1,74 @@
+/*
+ * Xcode configuration file for Mini-XML, a small XML file parsing library.
+ *
+ * https://www.msweet.org/mxml
+ *
+ * Copyright © 2003-2021 by Michael R Sweet.
+ *
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+
+/*
+ * Version number...
+ */
+
+#define MXML_VERSION "Mini-XML v3.3.1"
+
+
+/*
+ * Inline function support...
+ */
+
+#define inline
+
+
+/*
+ * Long long support...
+ */
+
+#define HAVE_LONG_LONG_INT 1
+
+
+/*
+ * Do we have the *printf() functions?
+ */
+
+#define HAVE_SNPRINTF 1
+#define HAVE_VASPRINTF 1
+#define HAVE_VSNPRINTF 1
+
+
+/*
+ * Do we have the strXXX() functions?
+ */
+
+#define HAVE_STRDUP 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRLCPY 1
+
+
+/*
+ * Do we have threading support?
+ */
+
+#define HAVE_PTHREAD_H 1
+
+
+/*
+ * Define prototypes for string functions as needed...
+ */
+
+extern char	*_mxml_strdupf(const char *, ...);
+extern char	*_mxml_vstrdupf(const char *, va_list);

+ 11 - 4
mxml.mod/mxml/xcode/mxml.xcodeproj/project.pbxproj

@@ -228,7 +228,7 @@
 		272CFFFD1E8C6664007EBCAC /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1010;
+				LastUpgradeCheck = 1310;
 				ORGANIZATIONNAME = "Michael R Sweet";
 				TargetAttributes = {
 					272C00041E8C6664007EBCAC = {
@@ -250,10 +250,11 @@
 			};
 			buildConfigurationList = 272C00001E8C6664007EBCAC /* Build configuration list for PBXProject "mxml" */;
 			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
+			developmentRegion = en;
 			hasScannedForEncodings = 0;
 			knownRegions = (
 				en,
+				Base,
 			);
 			mainGroup = 272CFFFC1E8C6664007EBCAC;
 			productRefGroup = 272C00061E8C6664007EBCAC /* Products */;
@@ -318,6 +319,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
@@ -342,6 +344,7 @@
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -368,7 +371,7 @@
 				GCC_WARN_UNUSED_LABEL = YES;
 				GCC_WARN_UNUSED_PARAMETER = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				RUN_CLANG_STATIC_ANALYZER = YES;
@@ -380,6 +383,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ANALYZER_NONNULL = YES;
 				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 				CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
@@ -404,6 +408,7 @@
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 				CLANG_WARN_STRICT_PROTOTYPES = YES;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -424,7 +429,7 @@
 				GCC_WARN_UNUSED_LABEL = YES;
 				GCC_WARN_UNUSED_PARAMETER = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				RUN_CLANG_STATIC_ANALYZER = YES;
 				SDKROOT = macosx;
@@ -452,6 +457,7 @@
 		272C003E1E8C6AEB007EBCAC /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CODE_SIGN_IDENTITY = "-";
 				DEVELOPMENT_TEAM = RU58A2256H;
 				MACOSX_DEPLOYMENT_TARGET = 10.12;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -461,6 +467,7 @@
 		272C003F1E8C6AEB007EBCAC /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CODE_SIGN_IDENTITY = "-";
 				DEVELOPMENT_TEAM = RU58A2256H;
 				MACOSX_DEPLOYMENT_TARGET = 10.12;
 				PRODUCT_NAME = "$(TARGET_NAME)";

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov