Start working on Mini-XML v4.0.

master
Michael R Sweet 3 months ago
parent 809204a305
commit f9b9a40494
No known key found for this signature in database
GPG Key ID: BE67C75EC81F3244
  1. 199
      Makefile.in
  2. 2
      NOTICE
  3. 19
      README.md
  4. 65
      config.guess
  5. 118
      config.h.in
  6. 224
      config.sub
  7. 1733
      configure
  8. 425
      configure.ac
  9. 322
      mxml-attr.c
  10. 129
      mxml-entity.c
  11. 1908
      mxml-file.c
  12. 454
      mxml-get.c
  13. 570
      mxml-index.c
  14. 811
      mxml-node.c
  15. 237
      mxml-private.c
  16. 131
      mxml-private.h
  17. 261
      mxml-search.c
  18. 371
      mxml-set.c
  19. 561
      mxml-string.c
  20. 282
      mxml.h
  21. 6
      mxml.pc.in
  22. 484
      testmxml.c

@ -3,63 +3,132 @@
# #
# https://www.msweet.org/mxml # https://www.msweet.org/mxml
# #
# Copyright © 2003-2021 by Michael R Sweet. # Copyright © 2003-2024 by Michael R Sweet.
# #
# Licensed under Apache License v2.0. See the file "LICENSE" for more # Licensed under Apache License v2.0. See the file "LICENSE" for more
# information. # information.
# #
# #
# Compiler tools definitions... # This is a POSIX makefile
#
.POSIX:
#
# Mini-XML version...
#
MXML_VERSION = @MXML_VERSION@
#
# Programs...
# #
AR = @AR@ AR = @AR@
ARFLAGS = @ARFLAGS@
ARCHFLAGS = @ARCHFLAGS@
CC = @CC@ CC = @CC@
CFLAGS = $(OPTIM) $(ARCHFLAGS) @CFLAGS@ $(CPPFLAGS) $(WARNINGS)
CP = @CP@
CPPFLAGS = @CPPFLAGS@
DSO = @DSO@ DSO = @DSO@
DSOFLAGS = @DSOFLAGS@
LDFLAGS = $(OPTIM) $(ARCHFLAGS) @LDFLAGS@
INSTALL = @INSTALL@ INSTALL = @INSTALL@
LIBMXML = @LIBMXML@ LN = @LN@ -sf
LIBS = @LIBS@ MKDIR = @MKDIR@ -p
LN = @LN@ -s
MKDIR = @MKDIR@
OPTIM = @OPTIM@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
RM = @RM@ -f RM = @RM@ -f
RMDIR = @RMDIR@
SHELL = /bin/sh SHELL = /bin/sh
#
# Installation programs...
#
INSTALL_BIN = $(INSTALL) -c -m 755
INSTALL_DATA = $(INSTALL) -c -m 444
INSTALL_DIR = $(INSTALL) -d -m 755
INSTALL_LIB = $(INSTALL) -c -m 755
INSTALL_MAN = $(INSTALL) -c -m 444
#
# Libraries...
#
LIBMXML = @LIBMXML@
LIBMXML_STATIC = @LIBMXML_STATIC@
#
# Install static libraries?
#
INSTALL_STATIC = @INSTALL_STATIC@
#
# Code signing...
#
CODE_SIGN = @CODE_SIGN@
CODESIGN_IDENTITY = -
CSFLAGS = -s "$(CODESIGN_IDENTITY)" @CSFLAGS@ --timestamp
#
# Library archiver...
#
ARFLAGS = @ARFLAGS@
#
# C compiler and preprocessor...
#
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
WARNINGS = @WARNINGS@ WARNINGS = @WARNINGS@
# #
# Configured directories... # Linker options...
#
DSOFLAGS = @DSOFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ -lm
#
# Optimization and architecture options for both the compiler and linker.
#
OPTIM = @OPTIM@
#
# Directories...
# #
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@ bindir = @bindir@
datadir = @datadir@
datarootdir = @datarootdir@ datarootdir = @datarootdir@
exec_prefix = @exec_prefix@
includedir = @includedir@ includedir = @includedir@
infodir = @infodir@
libdir = @libdir@ libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@ mandir = @mandir@
docdir = @docdir@ oldincludedir = @oldincludedir@
BUILDROOT = $(DSTROOT) prefix = @prefix@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
# srcdir = @srcdir@
# Install commands... sysconfdir = @sysconfdir@
# top_srcdir = @top_srcdir@
INSTALL_BIN = $(INSTALL) -m 755 BUILDROOT = $(DSTROOT)$(DESTDIR)
INSTALL_DATA = $(INSTALL) -m 644
INSTALL_DIR = $(INSTALL) -d
INSTALL_LIB = $(INSTALL) -m 755
INSTALL_MAN = $(INSTALL) -m 644
INSTALL_SCRIPT = $(INSTALL) -m 755
# #
@ -81,7 +150,7 @@ DOCFILES = doc/mxml.epub doc/mxml.html doc/mxml-cover.png \
CHANGES.md LICENSE NOTICE README.md CHANGES.md LICENSE NOTICE README.md
PUBLIBOBJS = mxml-attr.o mxml-entity.o mxml-file.o mxml-get.o \ 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 mxml-index.o mxml-node.o mxml-search.o mxml-set.o
LIBOBJS = $(PUBLIBOBJS) mxml-private.o mxml-string.o LIBOBJS = $(PUBLIBOBJS) mxml-private.o
OBJS = testmxml.o $(LIBOBJS) OBJS = testmxml.o $(LIBOBJS)
ALLTARGETS = $(LIBMXML) testmxml ALLTARGETS = $(LIBMXML) testmxml
CROSSTARGETS = $(LIBMXML) CROSSTARGETS = $(LIBMXML)
@ -102,13 +171,12 @@ all: $(TARGETS)
clean: clean:
echo Cleaning build files... echo Cleaning build files...
$(RM) $(OBJS) $(ALLTARGETS) $(RM) $(OBJS) $(ALLTARGETS)
$(RM) mxml1.dll $(RM) mxml2.dll
$(RM) mxml1.lib $(RM) mxml2.lib
$(RM) libmxml.a $(RM) libmxml.a
$(RM) libmxml.so $(RM) libmxml.so
$(RM) libmxml.so.1 $(RM) libmxml.so.2
$(RM) libmxml.so.1.6 $(RM) libmxml.2.dylib
$(RM) libmxml.1.dylib
$(RM) libmxml.dylib $(RM) libmxml.dylib
@ -132,7 +200,7 @@ distclean: clean
# Install everything... # Install everything...
# #
install: $(TARGETS) install-$(LIBMXML) install-libmxml.a install: $(TARGETS) install-$(LIBMXML) @INSTALL_STATIC@
echo Installing documentation in $(BUILDROOT)$(docdir)... echo Installing documentation in $(BUILDROOT)$(docdir)...
$(INSTALL_DIR) $(BUILDROOT)$(docdir) $(INSTALL_DIR) $(BUILDROOT)$(docdir)
for file in $(DOCFILES); do \ for file in $(DOCFILES); do \
@ -154,29 +222,27 @@ install-libmxml.a: libmxml.a
$(INSTALL_LIB) libmxml.a $(BUILDROOT)$(libdir) $(INSTALL_LIB) libmxml.a $(BUILDROOT)$(libdir)
$(RANLIB) $(BUILDROOT)$(libdir)/libmxml.a $(RANLIB) $(BUILDROOT)$(libdir)/libmxml.a
install-libmxml.so.1.6: libmxml.so.1.6 install-libmxml.so.2: libmxml.so.2
echo Installing libmxml.so to $(BUILDROOT)$(libdir)... echo Installing libmxml.so to $(BUILDROOT)$(libdir)...
$(INSTALL_DIR) $(BUILDROOT)$(libdir) $(INSTALL_DIR) $(BUILDROOT)$(libdir)
$(INSTALL_LIB) libmxml.so.1.6 $(BUILDROOT)$(libdir) $(INSTALL_LIB) libmxml.so.2 $(BUILDROOT)$(libdir)
$(RM) $(BUILDROOT)$(libdir)/libmxml.so $(RM) $(BUILDROOT)$(libdir)/libmxml.so
$(LN) libmxml.so.1.6 $(BUILDROOT)$(libdir)/libmxml.so $(LN) libmxml.so.2 $(BUILDROOT)$(libdir)/libmxml.so
$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1
$(LN) libmxml.so.1.6 $(BUILDROOT)$(libdir)/libmxml.so.1
$(LDCONFIG) $(LDCONFIG)
install-libmxml.1.dylib: libmxml.1.dylib install-libmxml.2.dylib: libmxml.2.dylib
echo Installing libmxml.dylib to $(BUILDROOT)$(libdir)... echo Installing libmxml.dylib to $(BUILDROOT)$(libdir)...
$(INSTALL_DIR) $(BUILDROOT)$(libdir) $(INSTALL_DIR) $(BUILDROOT)$(libdir)
$(INSTALL_LIB) libmxml.1.dylib $(BUILDROOT)$(libdir) $(INSTALL_LIB) libmxml.2.dylib $(BUILDROOT)$(libdir)
$(RM) $(BUILDROOT)$(libdir)/libmxml.dylib $(RM) $(BUILDROOT)$(libdir)/libmxml.dylib
$(LN) libmxml.1.dylib $(BUILDROOT)$(libdir)/libmxml.dylib $(LN) libmxml.2.dylib $(BUILDROOT)$(libdir)/libmxml.dylib
# #
# Uninstall everything... # Uninstall everything...
# #
uninstall: uninstall-$(LIBMXML) uninstall-libmxml.a uninstall: uninstall-$(LIBMXML) @UNINSTALL_STATIC@
echo Uninstalling documentation from $(BUILDROOT)$(docdir)... echo Uninstalling documentation from $(BUILDROOT)$(docdir)...
$(RM) -r $(BUILDROOT)$(docdir) $(RM) -r $(BUILDROOT)$(docdir)
echo Uninstalling headers from $(BUILDROOT)$(includedir)... echo Uninstalling headers from $(BUILDROOT)$(includedir)...
@ -190,17 +256,16 @@ uninstall-libmxml.a:
echo Uninstalling libmxml.a from $(BUILDROOT)$(libdir)... echo Uninstalling libmxml.a from $(BUILDROOT)$(libdir)...
$(RM) $(BUILDROOT)$(libdir)/libmxml.a $(RM) $(BUILDROOT)$(libdir)/libmxml.a
uninstall-libmxml.so.1.6: uninstall-libmxml.so.2:
echo Uninstalling libmxml.so from $(BUILDROOT)$(libdir)... echo Uninstalling libmxml.so from $(BUILDROOT)$(libdir)...
$(RM) $(BUILDROOT)$(libdir)/libmxml.so $(RM) $(BUILDROOT)$(libdir)/libmxml.so
$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1 $(RM) $(BUILDROOT)$(libdir)/libmxml.so.2
$(RM) $(BUILDROOT)$(libdir)/libmxml.so.1.6
$(LDCONFIG) $(LDCONFIG)
uninstall-libmxml.1.dylib: uninstall-libmxml.2.dylib:
echo Uninstalling libmxml.dylib from $(BUILDROOT)$(libdir)... echo Uninstalling libmxml.dylib from $(BUILDROOT)$(libdir)...
$(RM) $(BUILDROOT)$(libdir)/libmxml.dylib $(RM) $(BUILDROOT)$(libdir)/libmxml.dylib
$(RM) $(BUILDROOT)$(libdir)/libmxml.1.dylib $(RM) $(BUILDROOT)$(libdir)/libmxml.2.dylib
# #
@ -253,44 +318,42 @@ libmxml.a: $(LIBOBJS)
$(AR) $(ARFLAGS) $@ $(LIBOBJS) $(AR) $(ARFLAGS) $@ $(LIBOBJS)
$(RANLIB) $@ $(RANLIB) $@
$(LIBOBJS): mxml.h $(LIBOBJS): mxml.h mxml-private.h
mxml-entity.o mxml-file.o mxml-private.o: mxml-private.h
# #
# mxml1.dll # libmxml2.dll
# #
mxml1.dll: $(LIBOBJS) libmxml2.dll: $(LIBOBJS)
echo Creating $@... echo Creating $@...
$(DSO) $(DSOFLAGS) $(LDFLAGS) -o $@ $(LIBOBJS) $(LIBS) $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBS)
# #
# libmxml.so.1.6 # libmxml.so.2
# #
libmxml.so.1.6: $(LIBOBJS) libmxml.so.2: $(LIBOBJS)
echo Creating $@... echo Creating $@...
$(DSO) $(DSOFLAGS) $(LDFLAGS) -o libmxml.so.1.6 $(LIBOBJS) $(LIBS) $(DSO) $(DSOFLAGS) -o libmxml.so.2 $(LIBOBJS) $(LIBS)
$(RM) libmxml.so libmxml.so.1 $(RM) libmxml.so
$(LN) libmxml.so.1.6 libmxml.so $(LN) libmxml.so.2 libmxml.so
$(LN) libmxml.so.1.6 libmxml.so.1
# #
# libmxml.1.dylib # libmxml.2.dylib
# #
libmxml.1.dylib: $(LIBOBJS) libmxml.2.dylib: $(LIBOBJS)
echo Creating $@... echo Creating $@...
$(DSO) $(DSOFLAGS) $(LDFLAGS) -o libmxml.1.dylib \ $(DSO) $(DSOFLAGS) -o libmxml.2.dylib \
-install_name $(libdir)/libmxml.dylib \ -install_name $(libdir)/libmxml.dylib \
-current_version 1.6.0 \ -current_version 2.0.0 \
-compatibility_version 1.0.0 \ -compatibility_version 2.0.0 \
$(LIBOBJS) $(LIBS) $(LIBOBJS) $(LIBS)
$(RM) libmxml.dylib $(RM) libmxml.dylib
$(LN) libmxml.1.dylib libmxml.dylib $(LN) libmxml.2.dylib libmxml.dylib
# #

@ -1,6 +1,6 @@
Mini-XML Mini-XML
Copyright © 2003-2022 by Michael R Sweet Copyright © 2003-2024 by Michael R Sweet
(Optional) Exceptions to the Apache 2.0 License: (Optional) Exceptions to the Apache 2.0 License:

@ -5,8 +5,12 @@ Mini-XML - Tiny XML Parsing Library
![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/mxml) ![Apache 2.0](https://img.shields.io/github/license/michaelrsweet/mxml)
![Build](https://github.com/michaelrsweet/mxml/workflows/Build/badge.svg) ![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) [![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/) > Note: The master branch contains what will become Mini-XML v4.0. See the
> v3.x branch for the Mini-XML v3.x source code. Version 4.0 is not 100% source
> compatible with earlier versions of Mini-XML. Changes will be documented in
> the near future...
Mini-XML is a small XML parsing library that you can use to read XML data files 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. or strings in your application without requiring large non-standard libraries.
@ -29,10 +33,6 @@ Mini-XML provides the following functionality:
Mini-XML doesn't do validation or other types of processing on the 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. 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
----------------- -----------------
@ -61,12 +61,13 @@ included project files in the `vcnet` subdirectory to build the library
instead. Note: The static library on Windows is NOT thread-safe. instead. Note: The static library on Windows is NOT thread-safe.
## Installing Mini-XML Installing Mini-XML
-------------------
The `install` target will install Mini-XML in the lib and include The `install` target will install Mini-XML in the lib and include
directories: directories:
make install sudo make install
Once you have installed it, use the `-lmxml` option to link your application Once you have installed it, use the `-lmxml` option to link your application
against it. against it.
@ -199,7 +200,7 @@ current version of this software, documentation, and Github issue tracking page.
Legal Stuff Legal Stuff
----------- -----------
Copyright © 2003-2022 by Michael R Sweet Copyright © 2003-2024 by Michael R Sweet
The Mini-XML library is licensed under the Apache License Version 2.0 with an The Mini-XML library is licensed under the Apache License Version 2.0 with an
*optional* exception to allow linking against GPL2/LGPL2-only software. See the *optional* exception to allow linking against GPL2/LGPL2-only software. See the

65
config.guess vendored

@ -1,10 +1,10 @@
#! /bin/sh #! /bin/sh
# Attempt to guess a canonical system name. # Attempt to guess a canonical system name.
# Copyright 1992-2022 Free Software Foundation, Inc. # Copyright 1992-2023 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale # shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2022-05-25' timestamp='2023-08-22'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
usage="\ usage="\
Usage: $0 [OPTION] Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on. Output the configuration name of the system '$me' is run on.
Options: Options:
-h, --help print this help, then exit -h, --help print this help, then exit
@ -60,13 +60,13 @@ version="\
GNU config.guess ($timestamp) GNU config.guess ($timestamp)
Originally written by Per Bothner. Originally written by Per Bothner.
Copyright 1992-2022 Free Software Foundation, Inc. Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help=" help="
Try \`$me --help' for more information." Try '$me --help' for more information."
# Parse command line # Parse command line
while test $# -gt 0 ; do while test $# -gt 0 ; do
@ -102,8 +102,8 @@ GUESS=
# temporary files to be created and, as you can see below, it is a # temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion. # headache to deal with in a portable fashion.
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated. # use 'HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team. # Portable tmp directory creation inspired by the Autoconf team.
@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
set_cc_for_build set_cc_for_build
cat <<-EOF > "$dummy.c" cat <<-EOF > "$dummy.c"
#if defined(__ANDROID__)
LIBC=android
#else
#include <features.h> #include <features.h>
#if defined(__UCLIBC__) #if defined(__UCLIBC__)
LIBC=uclibc LIBC=uclibc
@ -169,6 +172,7 @@ Linux|GNU|GNU/*)
LIBC=musl LIBC=musl
#endif #endif
#endif #endif
#endif
EOF EOF
cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
eval "$cc_set_libc" eval "$cc_set_libc"
@ -459,7 +463,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
UNAME_RELEASE=`uname -v` UNAME_RELEASE=`uname -v`
;; ;;
esac esac
# Japanese Language versions have a version number like `4.1.3-JL'. # Japanese Language versions have a version number like '4.1.3-JL'.
SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
GUESS=sparc-sun-sunos$SUN_REL GUESS=sparc-sun-sunos$SUN_REL
;; ;;
@ -904,7 +908,7 @@ EOF
fi fi
;; ;;
*:FreeBSD:*:*) *:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p` UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in case $UNAME_PROCESSOR in
amd64) amd64)
UNAME_PROCESSOR=x86_64 ;; UNAME_PROCESSOR=x86_64 ;;
@ -966,11 +970,37 @@ EOF
GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
;; ;;
x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
;;
*:[Mm]anagarm:*:*)
GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
;;
*:Minix:*:*) *:Minix:*:*)
GUESS=$UNAME_MACHINE-unknown-minix GUESS=$UNAME_MACHINE-unknown-minix
;; ;;
aarch64:Linux:*:*) aarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC set_cc_for_build
CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
ABI=64
sed 's/^ //' << EOF > "$dummy.c"
#ifdef __ARM_EABI__
#ifdef __ARM_PCS_VFP
ABI=eabihf
#else
ABI=eabi
#endif
#endif
EOF
cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
eval "$cc_set_abi"
case $ABI in
eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
esac
fi
GUESS=$CPU-unknown-linux-$LIBCABI
;; ;;
aarch64_be:Linux:*:*) aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be UNAME_MACHINE=aarch64_be
@ -1036,7 +1066,16 @@ EOF
k1om:Linux:*:*) k1om:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;; ;;
loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) kvx:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;;
kvx:cos:*:*)
GUESS=$UNAME_MACHINE-unknown-cos
;;
kvx:mbr:*:*)
GUESS=$UNAME_MACHINE-unknown-mbr
;;
loongarch32:Linux:*:* | loongarch64:Linux:*:*)
GUESS=$UNAME_MACHINE-unknown-linux-$LIBC GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
;; ;;
m32r*:Linux:*:*) m32r*:Linux:*:*)
@ -1191,7 +1230,7 @@ EOF
GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
;; ;;
i*86:OS/2:*:*) i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility # If we were able to find 'uname', then EMX Unix compatibility
# is probably installed. # is probably installed.
GUESS=$UNAME_MACHINE-pc-os2-emx GUESS=$UNAME_MACHINE-pc-os2-emx
;; ;;
@ -1332,7 +1371,7 @@ EOF
GUESS=ns32k-sni-sysv GUESS=ns32k-sni-sysv
fi fi
;; ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV> # says <Richard.M.Bartel@ccMail.Census.GOV>
GUESS=i586-unisys-sysv4 GUESS=i586-unisys-sysv4
;; ;;

@ -1,99 +1,49 @@
/* //
* Configuration file for Mini-XML, a small XML file parsing library. // Configuration file for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2020 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/* #ifndef MXML_CONFIG_H
* Include necessary headers... # define MXML_CONFIG_H
*/ # include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <stdarg.h>
# include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
//
// Version number
//
/* # define MXML_VERSION ""
* Version number...
*/
#define MXML_VERSION ""
//
// Inline function support
//
/* # define inline
* Inline function support...
*/
#define inline
//
// Long long support
//
/* # undef HAVE_LONG_LONG_INT
* Long long support...
*/
#undef HAVE_LONG_LONG_INT
//
// Have <pthread.h>?
//
/* # undef HAVE_PTHREAD_H
* Do we have the *printf() functions?
*/
#undef HAVE_SNPRINTF
#undef HAVE_VASPRINTF
#undef HAVE_VSNPRINTF
#endif // !MXML_CONFIG_H
/*
* Do we have the strXXX() functions?
*/
#undef HAVE_STRDUP
#undef HAVE_STRLCAT
#undef HAVE_STRLCPY
/*
* Do we have threading support?
*/
#undef HAVE_PTHREAD_H
/*
* Define prototypes for string functions as needed...
*/
# ifndef HAVE_STRDUP
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
# endif /* !HAVE_STRLCPY */
extern char *_mxml_strdupf(const char *, ...);
extern char *_mxml_vstrdupf(const char *, va_list);
# ifndef HAVE_SNPRINTF
extern int _mxml_snprintf(char *, size_t, const char *, ...);
# define snprintf _mxml_snprintf
# endif /* !HAVE_SNPRINTF */
# ifndef HAVE_VSNPRINTF
extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
# define vsnprintf _mxml_vsnprintf
# endif /* !HAVE_VSNPRINTF */

224
config.sub vendored

@ -1,10 +1,10 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright 1992-2022 Free Software Foundation, Inc. # Copyright 1992-2023 Free Software Foundation, Inc.
# shellcheck disable=SC2006,SC2268 # see below for rationale # shellcheck disable=SC2006,SC2268 # see below for rationale
timestamp='2022-01-03' timestamp='2023-09-19'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -76,13 +76,13 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\ version="\
GNU config.sub ($timestamp) GNU config.sub ($timestamp)
Copyright 1992-2022 Free Software Foundation, Inc. Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help=" help="
Try \`$me --help' for more information." Try '$me --help' for more information."
# Parse command line # Parse command line
while test $# -gt 0 ; do while test $# -gt 0 ; do
@ -130,7 +130,7 @@ IFS=$saved_IFS
# Separate into logical components for further validation # Separate into logical components for further validation
case $1 in case $1 in
*-*-*-*-*) *-*-*-*-*)
echo Invalid configuration \`"$1"\': more than four components >&2 echo "Invalid configuration '$1': more than four components" >&2
exit 1 exit 1
;; ;;
*-*-*-*) *-*-*-*)
@ -145,7 +145,8 @@ case $1 in
nto-qnx* | linux-* | uclinux-uclibc* \ nto-qnx* | linux-* | uclinux-uclibc* \
| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
| storm-chaos* | os2-emx* | rtmk-nova*) | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
| windows-* )
basic_machine=$field1 basic_machine=$field1
basic_os=$maybe_os basic_os=$maybe_os
;; ;;
@ -943,7 +944,7 @@ $basic_machine
EOF EOF
IFS=$saved_IFS IFS=$saved_IFS
;; ;;
# We use `pc' rather than `unknown' # We use 'pc' rather than 'unknown'
# because (1) that's what they normally are, and # because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users. # (2) the word "unknown" tends to confuse beginning users.
i*86 | x86_64) i*86 | x86_64)
@ -1075,7 +1076,7 @@ case $cpu-$vendor in
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586 cpu=i586
;; ;;
pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
cpu=i686 cpu=i686
;; ;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@ -1180,7 +1181,7 @@ case $cpu-$vendor in
case $cpu in case $cpu in
1750a | 580 \ 1750a | 580 \
| a29k \ | a29k \
| aarch64 | aarch64_be \ | aarch64 | aarch64_be | aarch64c | arm64ec \
| abacus \ | abacus \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
@ -1199,45 +1200,23 @@ case $cpu-$vendor in
| d10v | d30v | dlx | dsp16xx \ | d10v | d30v | dlx | dsp16xx \
| e2k | elxsi | epiphany \ | e2k | elxsi | epiphany \
| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
| javascript \
| h8300 | h8500 \ | h8300 | h8500 \
| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \ | hexagon \
| i370 | i*86 | i860 | i960 | ia16 | ia64 \ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
| ip2k | iq2000 \ | ip2k | iq2000 \
| k1om \ | k1om \
| kvx \
| le32 | le64 \ | le32 | le64 \
| lm32 \ | lm32 \
| loongarch32 | loongarch64 | loongarchx32 \ | loongarch32 | loongarch64 \
| m32c | m32r | m32rle \ | m32c | m32r | m32rle \
| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
| m88110 | m88k | maxq | mb | mcore | mep | metag \ | m88110 | m88k | maxq | mb | mcore | mep | metag \
| microblaze | microblazeel \ | microblaze | microblazeel \
| mips | mipsbe | mipseb | mipsel | mipsle \ | mips* \
| mips16 \
| mips64 | mips64eb | mips64el \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa32r3 | mipsisa32r3el \
| mipsisa32r5 | mipsisa32r5el \
| mipsisa32r6 | mipsisa32r6el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64r3 | mipsisa64r3el \
| mipsisa64r5 | mipsisa64r5el \
| mipsisa64r6 | mipsisa64r6el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mmix \ | mmix \
| mn10200 | mn10300 \ | mn10200 | mn10300 \
| moxie \ | moxie \
@ -1285,7 +1264,7 @@ case $cpu-$vendor in
;; ;;
*) *)
echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
exit 1 exit 1
;; ;;
esac esac
@ -1306,11 +1285,12 @@ esac
# Decode manufacturer-specific aliases for certain operating systems. # Decode manufacturer-specific aliases for certain operating systems.
if test x$basic_os != x if test x"$basic_os" != x
then then
# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# set os. # set os.
obj=
case $basic_os in case $basic_os in
gnu/linux*) gnu/linux*)
kernel=linux kernel=linux
@ -1341,6 +1321,10 @@ EOF
kernel=linux kernel=linux
os=`echo "$basic_os" | sed -e 's|linux|gnu|'` os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
;; ;;
managarm*)
kernel=managarm
os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
;;
*) *)
kernel= kernel=
os=$basic_os os=$basic_os
@ -1506,10 +1490,16 @@ case $os in
os=eabi os=eabi
;; ;;
*) *)
os=elf os=
obj=elf
;; ;;
esac esac
;; ;;
aout* | coff* | elf* | pe*)
# These are machine code file formats, not OSes
obj=$os
os=
;;
*) *)
# No normalization, but not necessarily accepted, that comes below. # No normalization, but not necessarily accepted, that comes below.
;; ;;
@ -1528,12 +1518,15 @@ else
# system, and we'll never get to this point. # system, and we'll never get to this point.
kernel= kernel=
obj=
case $cpu-$vendor in case $cpu-$vendor in
score-*) score-*)
os=elf os=
obj=elf
;; ;;
spu-*) spu-*)
os=elf os=
obj=elf
;; ;;
*-acorn) *-acorn)
os=riscix1.2 os=riscix1.2
@ -1543,28 +1536,35 @@ case $cpu-$vendor in
os=gnu os=gnu
;; ;;
arm*-semi) arm*-semi)
os=aout os=
obj=aout
;; ;;
c4x-* | tic4x-*) c4x-* | tic4x-*)
os=coff os=
obj=coff
;; ;;
c8051-*) c8051-*)
os=elf os=
obj=elf
;; ;;
clipper-intergraph) clipper-intergraph)
os=clix os=clix
;; ;;
hexagon-*) hexagon-*)
os=elf os=
obj=elf
;; ;;
tic54x-*) tic54x-*)
os=coff os=
obj=coff
;; ;;
tic55x-*) tic55x-*)
os=coff os=
obj=coff
;; ;;
tic6x-*) tic6x-*)
os=coff os=
obj=coff
;; ;;
# This must come before the *-dec entry. # This must come before the *-dec entry.
pdp10-*) pdp10-*)
@ -1586,19 +1586,24 @@ case $cpu-$vendor in
os=sunos3 os=sunos3
;; ;;
m68*-cisco) m68*-cisco)
os=aout os=
obj=aout
;; ;;
mep-*) mep-*)
os=elf os=
obj=elf
;; ;;
mips*-cisco) mips*-cisco)
os=elf os=
obj=elf
;; ;;
mips*-*) mips*-*)
os=elf os=
obj=elf
;; ;;
or32-*) or32-*)
os=coff os=
obj=coff
;; ;;
*-tti) # must be before sparc entry or we get the wrong os. *-tti) # must be before sparc entry or we get the wrong os.
os=sysv3 os=sysv3
@ -1607,7 +1612,8 @@ case $cpu-$vendor in
os=sunos4.1.1 os=sunos4.1.1
;; ;;
pru-*) pru-*)
os=elf os=
obj=elf
;; ;;
*-be) *-be)
os=beos os=beos
@ -1688,10 +1694,12 @@ case $cpu-$vendor in
os=uxpv os=uxpv
;; ;;
*-rom68k) *-rom68k)
os=coff os=
obj=coff
;; ;;
*-*bug) *-*bug)
os=coff os=
obj=coff
;; ;;
*-apple) *-apple)
os=macos os=macos
@ -1709,7 +1717,8 @@ esac
fi fi
# Now, validate our (potentially fixed-up) OS. # Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
case $os in case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes. # Sometimes we do "kernel-libc", so those need to count as OSes.
musl* | newlib* | relibc* | uclibc*) musl* | newlib* | relibc* | uclibc*)
@ -1720,6 +1729,9 @@ case $os in
# VxWorks passes extra cpu info in the 4th filed. # VxWorks passes extra cpu info in the 4th filed.
simlinux | simwindows | spe) simlinux | simwindows | spe)
;; ;;
# See `case $cpu-$os` validation below
ghcjs)
;;
# Now accept the basic system types. # Now accept the basic system types.
# The portable systems comes first. # The portable systems comes first.
# Each alternative MUST end in a * to match a version number. # Each alternative MUST end in a * to match a version number.
@ -1728,7 +1740,7 @@ case $os in
| hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
| sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
| hiux* | abug | nacl* | netware* | windows* \ | hiux* | abug | nacl* | netware* | windows* \
| os9* | macos* | osx* | ios* \ | os9* | macos* | osx* | ios* | tvos* | watchos* \
| mpw* | magic* | mmixware* | mon960* | lnews* \ | mpw* | magic* | mmixware* | mon960* | lnews* \
| amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
| aos* | aros* | cloudabi* | sortix* | twizzler* \ | aos* | aros* | cloudabi* | sortix* | twizzler* \
@ -1737,11 +1749,11 @@ case $os in
| mirbsd* | netbsd* | dicos* | openedition* | ose* \ | mirbsd* | netbsd* | dicos* | openedition* | ose* \
| bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
| ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
| bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ | bosx* | nextstep* | cxux* | oabi* \
| ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ | ptx* | ecoff* | winnt* | domain* | vsta* \
| udi* | lites* | ieee* | go32* | aux* | hcos* \ | udi* | lites* | ieee* | go32* | aux* | hcos* \
| chorusrdb* | cegcc* | glidix* | serenity* \ | chorusrdb* | cegcc* | glidix* | serenity* \
| cygwin* | msys* | pe* | moss* | proelf* | rtems* \ | cygwin* | msys* | moss* | proelf* | rtems* \
| midipix* | mingw32* | mingw64* | mint* \ | midipix* | mingw32* | mingw64* | mint* \
| uxpv* | beos* | mpeix* | udk* | moxiebox* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
| interix* | uwin* | mks* | rhapsody* | darwin* \ | interix* | uwin* | mks* | rhapsody* | darwin* \
@ -1754,7 +1766,7 @@ case $os in
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
| nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
| fiwix* ) | fiwix* | mlibc* | cos* | mbr* )
;; ;;
# This one is extra strict with allowed versions # This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*) sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@ -1762,41 +1774,99 @@ case $os in
;; ;;
none) none)
;; ;;
kernel* | msvc* )
# Restricted further below
;;
'')
if test x"$obj" = x
then
echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
fi
;;
*)
echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
exit 1
;;
esac
case $obj in
aout* | coff* | elf* | pe*)
;;
'')
# empty is fine
;;
*) *)
echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
exit 1
;;
esac
# Here we handle the constraint that a (synthetic) cpu and os are
# valid only in combination with each other and nowhere else.
case $cpu-$os in
# The "javascript-unknown-ghcjs" triple is used by GHC; we
# accept it here in order to tolerate that, but reject any
# variations.
javascript-ghcjs)
;;
javascript-* | *-ghcjs)
echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
exit 1 exit 1
;; ;;
esac esac
# As a final step for OS-related things, validate the OS-kernel combination # As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel. # (given a valid OS), if there is a kernel.
case $kernel-$os in case $kernel-$os-$obj in
linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \
| linux-musl* | linux-relibc* | linux-uclibc* ) | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- )
;;
uclinux-uclibc*- )
;; ;;
uclinux-uclibc* ) managarm-mlibc*- | managarm-kernel*- )
;; ;;
-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) windows*-msvc*-)
;;
-dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- )
# These are just libc implementations, not actual OSes, and thus # These are just libc implementations, not actual OSes, and thus
# require a kernel. # require a kernel.
echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
exit 1 exit 1
;; ;;
kfreebsd*-gnu* | kopensolaris*-gnu*) -kernel*- )
echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
exit 1
;; ;;
vxworks-simlinux | vxworks-simwindows | vxworks-spe) *-kernel*- )
echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
exit 1
;; ;;
nto-qnx*) *-msvc*- )
echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
exit 1
;; ;;
os2-emx) kfreebsd*-gnu*- | kopensolaris*-gnu*-)
;; ;;
*-eabi* | *-gnueabi*) vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
;; ;;
-*) nto-qnx*-)
;;
os2-emx-)
;;
*-eabi*- | *-gnueabi*-)
;;
none--*)
# None (no kernel, i.e. freestanding / bare metal),
# can be paired with an machine code file format
;;
-*-)
# Blank kernel with real OS is always fine. # Blank kernel with real OS is always fine.
;; ;;
*-*) --*)
echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 # Blank kernel and OS with real machine code file format is always fine.
;;
*-*-*)
echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
exit 1 exit 1
;; ;;
esac esac
@ -1879,7 +1949,7 @@ case $vendor in
;; ;;
esac esac
echo "$cpu-$vendor-${kernel:+$kernel-}$os" echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit exit
# Local variables: # Local variables:

1733
configure vendored

File diff suppressed because it is too large Load Diff

@ -3,7 +3,7 @@ dnl Configuration script for Mini-XML, a small XML file parsing library.
dnl dnl
dnl https://www.msweet.org/mxml dnl https://www.msweet.org/mxml
dnl dnl
dnl Copyright © 2003-2022 by Michael R Sweet. dnl Copyright © 2003-2024 by Michael R Sweet.
dnl dnl
dnl Licensed under Apache License v2.0. See the file "LICENSE" for more dnl Licensed under Apache License v2.0. See the file "LICENSE" for more
dnl information. dnl information.
@ -14,8 +14,12 @@ AC_PREREQ([2.70])
dnl Package name and version... dnl Package name and version...
AC_INIT([Mini-XML], [3.3.1], [https://github.com/michaelrsweet/mxml/issues], [mxml], [https://www.msweet.org/mxml]) AC_INIT([Mini-XML], [4.0b1], [https://github.com/michaelrsweet/mxml/issues], [mxml], [https://www.msweet.org/mxml])
AC_CONFIG_HEADERS([config.h])
MXML_VERSION="AC_PACKAGE_VERSION"
AC_SUBST([MXML_VERSION])
AC_DEFINE_UNQUOTED([MXML_VERSION], "Mini-XML v$MXML_VERSION", [Version number])
dnl This line is provided to ensure that you don't run the autoheader program 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 against this project. Doing so is completely unsupported and WILL cause
@ -35,113 +39,50 @@ AS_IF([test "x$host_os_version" = x], [
]) ])
dnl Set the name of the config header file... dnl Compiler options...
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:=}" CFLAGS="${CFLAGS:=}"
CPPFLAGS="${CPPFLAGS:=}" CPPFLAGS="${CPPFLAGS:=}"
DSO=""
DSOFLAGS="${DSOFLAGS:=}"
LDFLAGS="${LDFLAGS:=}" LDFLAGS="${LDFLAGS:=}"
AC_SUBST([LDFLAGS])
LIBS="${LIBS:=}" LIBS="${LIBS:=}"
OPTIM="${OPTIM:=}"
AC_SUBST([DSO])
dnl Options... AC_SUBST([DSOFLAGS])
AC_ARG_WITH([ansi], AS_HELP_STRING([--with-ansi], [set full ANSI C mode, default=no]), [ AC_SUBST([LDFLAGS])
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_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]), [ dnl Standard programs...
docdir="$withval"
], [
docdir="NONE"
])
AC_SUBST(docdir)
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_CC
AC_PROG_CXX
AC_PROG_INSTALL
AS_IF([test "$INSTALL" = "$ac_install_sh"], [
# Use full path to install-sh script...
INSTALL="`pwd`/install-sh -c"
])
AC_PROG_RANLIB AC_PROG_RANLIB
AC_CHECK_TOOL(AR,ar) AC_PATH_PROG([AR], [ar])
AC_PATH_PROG(CP,cp) AC_PATH_PROGS([CODE_SIGN], [codesign true])
AC_PATH_PROGS(LDCONFIG,ldconfig false) AC_MSG_CHECKING([for install-sh script])
AC_PATH_PROG(LN,ln) INSTALL="`pwd`/install-sh"
AC_PATH_PROG(MKDIR,mkdir) AC_SUBST([INSTALL])
AC_PATH_PROG(RM,rm) AC_MSG_RESULT([using $INSTALL])
AC_PATH_PROGS([LDCONFIG],ldconfig true)
AC_PATH_PROG([MKDIR], [mkdir])
dnl Flags for "ar" command... AC_PATH_PROG([RM], [rm])
AS_CASE(["$host_os_name"], [darwin* | *bsd], [ AC_PATH_PROG([RMDIR], [rmdir])
ARFLAGS="-rcv" AC_PATH_PROG([LN], [ln])
], [*], [
ARFLAGS="crvs"
dnl Figure out the correct "ar" command flags...
AS_IF([test "$ac_cv_prog_ranlib" = ":"], [
ARFLAGS="crs"
], [
ARFLAGS="cr"
]) ])
AC_SUBST(ARFLAGS) AC_SUBST([ARFLAGS])
dnl Inline functions... dnl Inline functions...
AC_C_INLINE AC_C_INLINE
dnl Checks for string functions.
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])
])
dnl Check for "long long" support... dnl Check for "long long" support...
AC_TYPE_LONG_LONG_INT AC_TYPE_LONG_LONG_INT
@ -180,111 +121,113 @@ AS_IF([test "x$enable_threads" != xno], [
]) ])
dnl Shared library support... dnl Library targets...
DSO="${DSO:=:}" AC_ARG_ENABLE([static], AS_HELP_STRING([--disable-static], [do not install static library]))
DSOFLAGS="${DSOFLAGS:=}" AC_ARG_ENABLE([shared], AS_HELP_STRING([--disable-shared], [do not install shared library]))
AC_ARG_ENABLE([shared], AS_HELP_STRING([--disable-shared], [turn off shared libraries, default=no]))
LIBMXML_STATIC="libmxml.a"
AS_IF([test x$enable_shared != xno], [ AS_IF([test x$enable_shared != xno], [
AC_MSG_CHECKING([for shared library support]) AS_CASE(["$host_os_name"], [linux* | gnu*], [
PICFLAG=1 LIBMXML="libmxml.so.2"
AS_CASE(["$host_os_name"], [sunos | unix_s], [
AC_MSG_RESULT([yes])
LIBMXML="libmxml.so.1.6"
DSO="\$(CC)" DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS -Wl,-h,libmxml.so.1 -G -R\$(libdir) \$(OPTIM)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared"
LDFLAGS="$LDFLAGS -R\$(libdir)" ], [*bsd*], [
], [linux*], [ LIBMXML="libmxml.so.2"
AC_MSG_RESULT([yes])
LIBMXML="libmxml.so.1.6"
DSO="\$(CC)" DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1 -shared \$(OPTIM)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared -lc"
], [osf | gnu], [ ], [darwin*], [
AC_MSG_RESULT([yes]) LIBMXML="libmxml.2.dylib"
LIBMXML="libmxml.so.1.6"
DSO="\$(CC)" DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-rpath,\$(libdir) -shared \$(OPTIM)" DSOFLAGS="$DSOFLAGS -Wl,-no_warn_inits -dynamiclib -lc"
LDFLAGS="$LDFLAGS -Wl,-rpath,\$(libdir)" ], [sunos*], [
], [*bsd | haiku*], [ LIBMXML="libmxml.so.2"
AC_MSG_RESULT([yes])
LIBMXML="libmxml.so.1.6"
DSO="\$(CC)" DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS -Wl,-soname,libmxml.so.1,-R\$(libdir) -shared \$(OPTIM)" DSOFLAGS="$DSOFLAGS -Wl,-h,\`basename \$@\` -G"
LDFLAGS="$LDFLAGS -Wl,-R\$(libdir)"
], [darwin], [
AC_MSG_RESULT([yes])
LIBMXML="libmxml.1.dylib"
DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS \$(RC_CFLAGS) -dynamiclib -lc"
], [mingw], [ ], [mingw], [
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
LIBMXML="mxml1.dll" LIBMXML="libmxml2.dll"
DSO="\$(CC)" DSO="\$(CC)"
DSOFLAGS="$DSOFLAGS -shared -Wl,--out-implib,libmxml1.a,--no-undefined,--enable-runtime-pseudo-reloc" DSOFLAGS="$DSOFLAGS -shared -Wl,--out-implib,libmxml2.a,--no-undefined,--enable-runtime-pseudo-reloc"
], [*], [ ], [*], [
AC_MSG_RESULT([no]) AC_MSG_NOTICE([Warning: Shared libraries may not work, trying -shared option.])
AC_MSG_WARN([shared libraries not supported on this platform.]) LIBMXML="libmxml.so.2"
PICFLAG=0 DSO="\$(CC)"
LIBMXML="libmxml.a" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared"
])
AS_IF([test x$enable_static != xno], [
AC_MSG_NOTICE([Installing static libraries...])
INSTALL_STATIC="install-libmxml.a"
UNINSTALL_STATIC="uninstall-libmxml.a"
], [
INSTALL_STATIC=""
UNINSTALL_STATIC=""
]) ])
], [ ], [
PICFLAG=0 INSTALL_STATIC=""
LIBMXML="libmxml.a" LIBMXML="libmxml.a"
UNINSTALL_STATIC=""
]) ])
AC_SUBST([DSO]) AC_SUBST([INSTALL_STATIC])
AC_SUBST([DSOFLAGS])
AC_SUBST([LIBMXML]) AC_SUBST([LIBMXML])
AC_SUBST([PICFLAG]) AC_SUBST([LIBMXML_STATIC])
AC_SUBST([UNINSTALL_STATIC])
dnl Compiler options... dnl Extra compiler options...
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_WITH([sanitizer], AS_HELP_STRING([--with-sanitizer], [build with address, leak, memory, thread, or undefined sanitizer, default=no]), [], [with_sanitizer=no])
AS_IF([test "x$with_sanitizer" = xyes], [
with_sanitizer="address"
], [test "$with_sanitizer" != address -a "$with_sanitizer" != leak -a "$with_sanitizer" != memory -a "$with_sanitizer" != no -a "$with_sanitizer" != thread -a "$with_sanitizer" != undefined], [
AC_MSG_ERROR([Unsupported --with-sanitizer value "$with_sanitizer" specified.])
])
AS_IF([test x$enable_debug = xyes], [
CSFLAGS=""
OPTIM="$OPTIM -g"
OPTIONS="-DDEBUG -DDEBUG_GUARDS"
], [
CSFLAGS="-o runtime"
OPTIM="$OPTIM -g -Os"
OPTIONS=""
])
AC_SUBST([CSFLAGS])
AC_SUBST([OPTIONS])
WARNINGS="" WARNINGS=""
AC_SUBST([WARNINGS]) AC_SUBST([WARNINGS])
AS_IF([test -n "$GCC"], [ AS_IF([test -n "$GCC"], [
CFLAGS="-D_GNU_SOURCE $CFLAGS" AS_IF([test x$with_sanitizer != xno], [
# Use -fsanitize=FOO with debugging...
AS_IF([test "x$OPTIM" = x], [ OPTIM="$OPTIM -fsanitize=$with_sanitizer"
AS_IF([test x$enable_debug = xyes], [ ], [echo "$CPPFLAGS $CFLAGS" | grep -q _FORTIFY_SOURCE], [
OPTIM="-g" # Don't add _FORTIFY_SOURCE if it is already there
], [
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 # Otherwise use the Fortify enhancements to catch any unbounded
# string operations... # string operations...
CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=3"
])
AS_IF([test "x$use_ansi" = xyes], [
CFLAGS="-ansi -pedantic $CFLAGS"
]) ])
dnl Show all standard warnings + unused variables when compiling... dnl Show all standard warnings + unused variables when compiling...
WARNINGS="-Wall -Wunused" WARNINGS="-Wall -Wunused"
dnl Drop some not-useful/unreliable warnings... dnl Drop some not-useful/unreliable warnings...
for warning in char-subscripts format-truncation format-y2k switch unused-result; do for warning in char-subscripts deprecated-declarations format-truncation format-y2k switch unused-result; do
AC_MSG_CHECKING([whether compiler supports -Wno-$warning]) AC_MSG_CHECKING([whether compiler supports -Wno-$warning])
OLDCFLAGS="$CFLAGS" OLDCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wno-$warning -Werror" CFLAGS="$CFLAGS -Wno-$warning -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [
AC_MSG_RESULT(yes) AC_MSG_RESULT([yes])
WARNINGS="$WARNINGS -Wno-$warning" WARNINGS="$WARNINGS -Wno-$warning"
], [ ], [
AC_MSG_RESULT(no) AC_MSG_RESULT([no])
]) ])
CFLAGS="$OLDCFLAGS" CFLAGS="$OLDCFLAGS"
@ -295,32 +238,111 @@ AS_IF([test -n "$GCC"], [
WARNINGS="$WARNINGS -Werror" WARNINGS="$WARNINGS -Werror"
]) ])
AS_IF([test $PICFLAG = 1 -a "$host_os_name" != aix], [ dnl See if PIE options are supported...
OPTIM="-fPIC $OPTIM" AC_MSG_CHECKING(whether compiler supports -fPIE)
OLDCFLAGS="$CFLAGS"
AS_CASE(["$host_os_name"],
[darwin*], [
CFLAGS="$CFLAGS -fPIC -fPIE -Wl,-pie"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[
OLDCFLAGS="-fPIC $OLDCFLAGS"
LDFLAGS="-fPIE -Wl,-pie $LDFLAGS"
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
])
], [*], [
CFLAGS="$CFLAGS -fPIC -fPIE -pie"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[
OLDCFLAGS="-fPIC $OLDCFLAGS"
LDFLAGS="-fPIE -pie $LDFLAGS"
AC_MSG_RESULT([yes])
],[
AC_MSG_RESULT([no])
])
]) ])
], [ CFLAGS="$OLDCFLAGS"
AS_IF([test "x$OPTIM" = x], [
AS_IF([test x$enable_debug = xyes], [ dnl OS-specific compiler options...
OPTIM="-g" AC_MSG_CHECKING([for OS-specific compiler options])
AS_CASE(["$host_os_name"], [linux*], [
# Make sure we get the full set of Linux APIs from the headers...
CPPFLAGS="$CPPFLAGS -D__USE_MISC -D_GNU_SOURCE"
# Mark read-only sections as relocatable to random addresses...
LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now"
AC_MSG_RESULT([-D__USE_MISC -D_GNU_SOURCE -Wl,-z,relro,-z,now])
], [darwin*], [
# When not building for debug, target macOS 11 or later, "universal"
# binaries when possible...
AS_IF([echo "$CPPFLAGS $CFLAGS $LDFLAGS $OPTIM" | grep -q "\\-arch "], [
# Don't add architecture/min-version flags if they are already present
AC_MSG_RESULT([none])
], [echo "$CPPFLAGS $CFLAGS $LDFLAGS $OPTIM" | grep -q "\\-mmacosx-version-"], [
# Don't add architecture/min-version flags if they are already present
AC_MSG_RESULT([none])
], [test "$host_os_version" -ge 200 -a x$enable_debug != xyes], [
# macOS 11.0 and higher support the Apple Silicon (arm64) CPUs
OPTIM="$OPTIM -mmacosx-version-min=11.0 -arch x86_64 -arch arm64"
AC_MSG_RESULT([-mmacosx-version-min=11.0 -arch x86_64 -arch arm64])
], [ ], [
OPTIM="-O" # Don't add architecture/min-version flags if debug enabled
AC_MSG_RESULT([none])
]) ])
], [*], [
AC_MSG_RESULT([none])
]) ])
])
AS_CASE(["$host_os_name"], [hp-ux], [
CFLAGS="-Ae $CFLAGS"
OPTIM="+DAportable $OPTIM" dnl Extra linker options...
AC_ARG_WITH([dsoflags], AS_HELP_STRING([--with-dsoflags=...], [Specify additional DSOFLAGS]), [
DSOFLAGS="$withval $DSOFLAGS"
])
AC_ARG_WITH([ldflags], AS_HELP_STRING([--with-ldflags=...], [Specify additional LDFLAGS]), [
LDFLAGS="$withval $LDFLAGS"
])
AS_IF([test $PICFLAG = 1], [
OPTIM="+z $OPTIM" dnl Directories...
]) AC_ARG_WITH([docdir], AS_HELP_STRING([--with-docdir], [set directory for documentation, default=${prefix}/share/doc/mxml]), [
], [unix_svr | sunos], [ docdir="$withval"
AS_IF([test $PICFLAG = 1], [ ], [
OPTIM="-KPIC $OPTIM" docdir="NONE"
])
])
]) ])
AC_SUBST(docdir)
dnl Determine whether we are cross-compiling... dnl Determine whether we are cross-compiling...
@ -333,39 +355,44 @@ AC_SUBST([TARGETS])
dnl Fix installation directories... dnl Fix installation directories...
AS_IF([test "$prefix" = "NONE"], [ AS_IF([test "$prefix" = NONE], [
prefix="/usr/local" # Default prefix isn't bound until AC_OUTPUT...
]) realprefix="/usr/local"
], [
AS_IF([test "$exec_prefix" = "NONE"], [ realprefix="$prefix"
exec_prefix="$prefix"
]) ])
AS_IF([test "$docdir" = "NONE"], [ AS_IF([test "$datarootdir" = "\${prefix}/share"], [
docdir="$datadir/doc/mxml" AS_IF([test "$prefix" = "/"], [
datarootdir="/usr/share"
], [
datarootdir="$realprefix/share"
])
]) ])
AS_IF([test "$mandir" = "\${prefix}/man" -a "$prefix" = "/usr"], [ AS_IF([test "$datadir" = "\${prefix}/share"], [
mandir="/usr/share/man" AS_IF([test "$prefix" = "/"], [
datadir="/usr/share"
], [
datadir="$realprefix/share"
])
], [test "$datadir" = "\${datarootdir}"], [
datadir="$datarootdir"
]) ])
dnl pkg-config stuff... dnl pkg-config flags...
AS_IF([test "$includedir" != /usr/include], [ PKGCONFIG_CFLAGS=""
PC_CFLAGS="-I$includedir" PKGCONFIG_LIBS="-lmxml"
], [ AS_IF([test "$realprefix" != "/usr" -a "$realprefix" != "/usr/local"], [
PC_CFLAGS="" PKGCONFIG_CFLAGS="-I\${includedir}"
PKGCONFIG_LIBS="-L\${libdir} $PKGCONFIG_LIBS"
]) ])
AC_SUBST([PC_CFLAGS])
AS_IF([test "$libdir" != /usr/lib], [ AC_SUBST([PKGCONFIG_CFLAGS])
PC_LIBS="-L$libdir -lmxml" AC_SUBST([PKGCONFIG_LIBS])
], [
PC_LIBS="-lmxml"
])
AC_SUBST([PC_LIBS])
dnl Output the makefile, etc... dnl Output generated files...
AC_CONFIG_FILES([Makefile mxml.pc]) AC_CONFIG_FILES([Makefile mxml.pc])
AC_OUTPUT AC_OUTPUT

@ -1,73 +1,50 @@
/* //
* Attribute support code for Mini-XML, a small XML file parsing library. // Attribute support code for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2021 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
/* //
* Local functions... // Local functions...
*/ //
static int mxml_set_attr(mxml_node_t *node, const char *name, char *value); static int mxml_set_attr(mxml_node_t *node, const char *name, char *value);
/* //
* 'mxmlElementDeleteAttr()' - Delete an attribute. // 'mxmlElementDeleteAttr()' - Delete an attribute.
* //
* @since Mini-XML 2.4@
*/
void void
mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */ mxmlElementDeleteAttr(mxml_node_t *node,// I - Element
const char *name)/* I - Attribute name */ const char *name)// I - Attribute name
{ {
int i; /* Looping var */ int i; // Looping var
_mxml_attr_t *attr; /* Cirrent attribute */ _mxml_attr_t *attr; // Cirrent attribute
#ifdef DEBUG
fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
node, name ? name : "(null)");
#endif /* DEBUG */
/* MXML_DEBUG("mxmlElementDeleteAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)");
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name) // Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT || !name)
return; return;
/* // Look for the attribute...
* Look for the attribute... for (i = node->value.element.num_attrs, attr = node->value.element.attrs; i > 0; i --, attr ++)
*/
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
{ {
#ifdef DEBUG MXML_DEBUG("mxmlElementDeleteAttr: %s=\"%s\"\n", attr->name, attr->value);
printf(" %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */
if (!strcmp(attr->name, name)) if (!strcmp(attr->name, name))
{ {
/* // Delete this attribute...
* Delete this attribute...
*/
free(attr->name); free(attr->name);
free(attr->value); free(attr->value);
@ -85,82 +62,60 @@ mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
} }
/* //
* 'mxmlElementGetAttr()' - Get an attribute. // 'mxmlElementGetAttr()' - Get an attribute.
* //
* This function returns @code NULL@ if the node is not an element or the // This function returns @code NULL@ if the node is not an element or the
* named attribute does not exist. // named attribute does not exist.
*/ //
const char * /* O - Attribute value or @code NULL@ */ const char * // O - Attribute value or @code NULL@
mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */ mxmlElementGetAttr(mxml_node_t *node, // I - Element node
const char *name) /* I - Name of attribute */ const char *name) // I - Name of attribute
{ {
int i; /* Looping var */ int i; // Looping var
_mxml_attr_t *attr; /* Cirrent attribute */ _mxml_attr_t *attr; // Cirrent attribute
#ifdef DEBUG
fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
node, name ? name : "(null)");
#endif /* DEBUG */
/* MXML_DEBUG("mxmlElementGetAttr(node=%p, name=\"%s\")\n", node, name ? name : "(null)");
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name) // Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT || !name)
return (NULL); return (NULL);
/* // Look for the attribute...
* Look for the attribute... for (i = node->value.element.num_attrs, attr = node->value.element.attrs; i > 0; i --, attr ++)
*/
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
{ {
#ifdef DEBUG MXML_DEBUG("mxmlElementGetAttr: %s=\"%s\"\n", attr->name, attr->value);
printf(" %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */
if (!strcmp(attr->name, name)) if (!strcmp(attr->name, name))
{ {
#ifdef DEBUG MXML_DEBUG("mxmlElementGetAttr: Returning \"%s\".\n", attr->value);
printf(" Returning \"%s\"!\n", attr->value);
#endif /* DEBUG */
return (attr->value); return (attr->value);
} }
} }
/* // Didn't find attribute, so return NULL...
* Didn't find attribute, so return NULL... MXML_DEBUG("mxmlElementGetAttr: Returning NULL.\n");
*/
#ifdef DEBUG
puts(" Returning NULL!\n");
#endif /* DEBUG */
return (NULL); return (NULL);
} }
/* //
* 'mxmlElementGetAttrByIndex()' - Get an element attribute by index. // 'mxmlElementGetAttrByIndex()' - Get an element attribute by index.
* //
* The index ("idx") is 0-based. @code NULL@ is returned if the specified index // The index ("idx") is 0-based. @code NULL@ is returned if the specified index
* is out of range. // is out of range.
* //
* @since Mini-XML 2.11@
*/
const char * /* O - Attribute value */ const char * // O - Attribute value
mxmlElementGetAttrByIndex( mxmlElementGetAttrByIndex(
mxml_node_t *node, /* I - Node */ mxml_node_t *node, // I - Node
int idx, /* I - Attribute index, starting at 0 */ int idx, // I - Attribute index, starting at 0
const char **name) /* O - Attribute name */ const char **name) // O - Attribute name
{ {
if (!node || node->type != MXML_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs) if (!node || node->type != MXML_TYPE_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs)
return (NULL); return (NULL);
if (name) if (name)
@ -170,50 +125,42 @@ mxmlElementGetAttrByIndex(
} }
/* //
* 'mxmlElementGetAttrCount()' - Get the number of element attributes. // 'mxmlElementGetAttrCount()' - Get the number of element attributes.
* //
* @since Mini-XML 2.11@
*/
int /* O - Number of attributes */ int // O - Number of attributes
mxmlElementGetAttrCount( mxmlElementGetAttrCount(
mxml_node_t *node) /* I - Node */ mxml_node_t *node) // I - Node
{ {
if (node && node->type == MXML_ELEMENT) if (node && node->type == MXML_TYPE_ELEMENT)
return (node->value.element.num_attrs); return (node->value.element.num_attrs);
else else
return (0); return (0);
} }
/* //
* 'mxmlElementSetAttr()' - Set an attribute. // 'mxmlElementSetAttr()' - Set an attribute.
* //
* If the named attribute already exists, the value of the attribute // If the named attribute already exists, the value of the attribute
* is replaced by the new string value. The string value is copied // is replaced by the new string value. The string value is copied
* into the element node. This function does nothing if the node is // into the element node. This function does nothing if the node is
* not an element. // not an element.
*/ //
void void
mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */ mxmlElementSetAttr(mxml_node_t *node, // I - Element node
const char *name, /* I - Name of attribute */ const char *name, // I - Name of attribute
const char *value) /* I - Attribute value */ const char *value) // I - Attribute value
{ {
char *valuec; /* Copy of value */ char *valuec; // Copy of value
#ifdef DEBUG MXML_DEBUG("mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n", node, name ? name : "(null)", value ? value : "(null)");
fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
node, name ? name : "(null)", value ? value : "(null)");
#endif /* DEBUG */
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT || !name)
*/
if (!node || node->type != MXML_ELEMENT || !name)
return; return;
if (value) if (value)
@ -225,109 +172,85 @@ mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
} }
} }
else else
{
valuec = NULL; valuec = NULL;
}
if (mxml_set_attr(node, name, valuec)) if (mxml_set_attr(node, name, valuec))
free(valuec); free(valuec);
} }
/* //
* 'mxmlElementSetAttrf()' - Set an attribute with a formatted value. // 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
* //
* If the named attribute already exists, the value of the attribute // If the named attribute already exists, the value of the attribute
* is replaced by the new formatted string. The formatted string value is // is replaced by the new formatted string. The formatted string value is
* copied into the element node. This function does nothing if the node // copied into the element node. This function does nothing if the node
* is not an element. // is not an element.
* //
* @since Mini-XML 2.3@
*/
void void
mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */ mxmlElementSetAttrf(mxml_node_t *node, // I - Element node
const char *name, /* I - Name of attribute */ const char *name, // I - Name of attribute
const char *format,/* I - Printf-style attribute value */ const char *format,// I - Printf-style attribute value
...) /* I - Additional arguments as needed */ ...) // I - Additional arguments as needed
{ {
va_list ap; /* Argument pointer */ va_list ap; // Argument pointer
char *value; /* Value */ char buffer[16384]; // Format buffer
char *value; // Value
#ifdef DEBUG
fprintf(stderr,
"mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
node, name ? name : "(null)", format ? format : "(null)");
#endif /* DEBUG */
/* MXML_DEBUG("mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n", node, name ? name : "(null)", format ? format : "(null)");
* Range check input...
*/
if (!node || node->type != MXML_ELEMENT || !name || !format) // Range check input...
if (!node || node->type != MXML_TYPE_ELEMENT || !name || !format)
return; return;
/* // Format the value...
* Format the value...
*/
va_start(ap, format); va_start(ap, format);
value = _mxml_vstrdupf(format, ap); vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap); va_end(ap);
if (!value) if ((value = strdup(buffer)) == 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);
name, node->value.element.name);
else if (mxml_set_attr(node, name, value)) else if (mxml_set_attr(node, name, value))
free(value); free(value);
} }
/* //
* 'mxml_set_attr()' - Set or add an attribute name/value pair. // 'mxml_set_attr()' - Set or add an attribute name/value pair.
*/ //
static int /* O - 0 on success, -1 on failure */ static int // O - 0 on success, -1 on failure
mxml_set_attr(mxml_node_t *node, /* I - Element node */ mxml_set_attr(mxml_node_t *node, // I - Element node
const char *name, /* I - Attribute name */ const char *name, // I - Attribute name
char *value) /* I - Attribute value */ char *value) // I - Attribute value
{ {
int i; /* Looping var */ int i; // Looping var
_mxml_attr_t *attr; /* New attribute */ _mxml_attr_t *attr; // New attribute
/* // Look for the attribute...
* Look for the attribute... for (i = node->value.element.num_attrs, attr = node->value.element.attrs; i > 0; i --, attr ++)
*/ {
for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
i > 0;
i --, attr ++)
if (!strcmp(attr->name, name)) if (!strcmp(attr->name, name))
{ {
/* // Free the old value as needed...
* Free the old value as needed...
*/
free(attr->value); free(attr->value);
attr->value = value; attr->value = value;
return (0); return (0);
} }
}
/* // Add a new attribute...
* Add a new attribute... attr = realloc(node->value.element.attrs, (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
*/
if (node->value.element.num_attrs == 0)
attr = malloc(sizeof(_mxml_attr_t));
else
attr = realloc(node->value.element.attrs,
(node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
if (!attr) 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);
name, node->value.element.name);
return (-1); return (-1);
} }
@ -336,8 +259,7 @@ mxml_set_attr(mxml_node_t *node, /* I - Element node */
if ((attr->name = strdup(name)) == NULL) 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);
name, node->value.element.name);
return (-1); return (-1);
} }

@ -1,31 +1,27 @@
/* //
* Character entity support code for Mini-XML, a small XML file parsing library. // Character entity support code for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2019 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "mxml-private.h" #include "mxml-private.h"
/* //
* 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode. // 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlEntityAddCallback( mxmlEntityAddCallback(
mxml_entity_cb_t cb) /* I - Callback function to add */ mxml_entity_cb_t cb) // I - Callback function to add
{ {
_mxml_global_t *global = _mxml_global(); _mxml_global_t *global = _mxml_global();
/* Global data */ // Global data
if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0]))) if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
@ -44,14 +40,14 @@ mxmlEntityAddCallback(
} }
/* //
* 'mxmlEntityGetName()' - Get the name that corresponds to the character value. // 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
* //
* If val does not need to be represented by a named entity, @code NULL@ is returned. // If val does not need to be represented by a named entity, @code NULL@ is returned.
*/ //
const char * /* O - Entity name or @code NULL@ */ const char * // O - Entity name or @code NULL@
mxmlEntityGetName(int val) /* I - Character value */ mxmlEntityGetName(int val) // I - Character value
{ {
switch (val) switch (val)
{ {
@ -73,76 +69,76 @@ mxmlEntityGetName(int val) /* I - Character value */
} }
/* //
* 'mxmlEntityGetValue()' - Get the character corresponding to a named entity. // 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.
* //
* The entity name can also be a numeric constant. -1 is returned if the // The entity name can also be a numeric constant. -1 is returned if the
* name is not known. // name is not known.
*/ //
int /* O - Character value or -1 on error */ int // O - Character value or -1 on error
mxmlEntityGetValue(const char *name) /* I - Entity name */ mxmlEntityGetValue(const char *name) // I - Entity name
{ {
int i; /* Looping var */ int i; // Looping var
int ch; /* Character value */ int ch; // Character value
_mxml_global_t *global = _mxml_global(); _mxml_global_t *global = _mxml_global();
/* Global data */ // Global data
for (i = 0; i < global->num_entity_cbs; i ++) for (i = 0; i < global->num_entity_cbs; i ++)
{
if ((ch = (global->entity_cbs[i])(name)) >= 0) if ((ch = (global->entity_cbs[i])(name)) >= 0)
return (ch); return (ch);
}
return (-1); return (-1);
} }
/* //
* 'mxmlEntityRemoveCallback()' - Remove a callback. // 'mxmlEntityRemoveCallback()' - Remove a callback.
*/ //
void void
mxmlEntityRemoveCallback( mxmlEntityRemoveCallback(
mxml_entity_cb_t cb) /* I - Callback function to remove */ mxml_entity_cb_t cb) // I - Callback function to remove
{ {
int i; /* Looping var */ int i; // Looping var
_mxml_global_t *global = _mxml_global(); _mxml_global_t *global = _mxml_global();
/* Global data */ // Global data
for (i = 0; i < global->num_entity_cbs; i ++) for (i = 0; i < global->num_entity_cbs; i ++)
{
if (cb == global->entity_cbs[i]) if (cb == global->entity_cbs[i])
{ {
/* // Remove the callback...
* Remove the callback...
*/
global->num_entity_cbs --; global->num_entity_cbs --;
if (i < global->num_entity_cbs) if (i < global->num_entity_cbs)
memmove(global->entity_cbs + i, global->entity_cbs + i + 1, memmove(global->entity_cbs + i, global->entity_cbs + i + 1, (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
(global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
return; return;
} }
}
} }
/* //
* '_mxml_entity_cb()' - Lookup standard (X)HTML entities. // '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
*/ //
int /* O - Unicode value or -1 */ int // O - Unicode value or -1
_mxml_entity_cb(const char *name) /* I - Entity name */ _mxml_entity_cb(const char *name) // I - Entity name
{ {
int diff, /* Difference between names */ int diff, // Difference between names
current, /* Current entity in search */ current, // Current entity in search
first, /* First entity in search */ first, // First entity in search
last; /* Last entity in search */ last; // Last entity in search
static const struct static const struct
{ {
const char *name; /* Entity name */ const char *name; // Entity name
int val; /* Character value */ int val; // Character value
} entities[] = } entities[] =
{ {
{ "AElig", 198 }, { "AElig", 198 },
@ -405,10 +401,7 @@ _mxml_entity_cb(const char *name) /* I - Entity name */
}; };
/* // Do a binary search for the named entity...
* Do a binary search for the named entity...
*/
first = 0; first = 0;
last = (int)(sizeof(entities) / sizeof(entities[0]) - 1); last = (int)(sizeof(entities) / sizeof(entities[0]) - 1);
@ -424,11 +417,7 @@ _mxml_entity_cb(const char *name) /* I - Entity name */
first = current; first = current;
} }
/* // If we get here, there is a small chance that there is still a match; check first and last...
* If we get here, there is a small chance that there is still
* a match; check first and last...
*/
if (!strcmp(name, entities[first].name)) if (!strcmp(name, entities[first].name))
return (entities[first].val); return (entities[first].val);
else if (!strcmp(name, entities[last].name)) else if (!strcmp(name, entities[last].name))

File diff suppressed because it is too large Load Diff

@ -1,365 +1,258 @@
/* //
* Node get functions for Mini-XML, a small XML file parsing library. // Node get functions for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2014-2019 by Michael R Sweet. // Copyright © 2014-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
/* //
* 'mxmlGetCDATA()' - Get the value for a CDATA node. // 'mxmlGetCDATA()' - Get the value for a CDATA node.
* //
* @code NULL@ is returned if the node is not a CDATA element. // `NULL` is returned if the node is not a CDATA element.
* //
* @since Mini-XML 2.7@
*/
const char * /* O - CDATA value or @code NULL@ */ const char * // O - CDATA value or `NULL`
mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */ mxmlGetCDATA(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT || strncmp(node->value.element.name, "![CDATA[", 8))
*/
if (!node || node->type != MXML_ELEMENT ||
strncmp(node->value.element.name, "![CDATA[", 8))
return (NULL); return (NULL);
/* // Return the text following the CDATA declaration...
* Return the text following the CDATA declaration...
*/
return (node->value.element.name + 8); return (node->value.element.name + 8);
} }
/* //
* 'mxmlGetCustom()' - Get the value for a custom node. // 'mxmlGetCustom()' - Get the value for a custom node.
* //
* @code NULL@ is returned if the node (or its first child) is not a custom // `NULL` is returned if the node (or its first child) is not a custom
* value node. // value node.
* //
* @since Mini-XML 2.7@
*/
const void * /* O - Custom value or @code NULL@ */ const void * // O - Custom value or `NULL`
mxmlGetCustom(mxml_node_t *node) /* I - Node to get */ mxmlGetCustom(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the custom value...
* Return the integer value... if (node->type == MXML_TYPE_CUSTOM)
*/
if (node->type == MXML_CUSTOM)
return (node->value.custom.data); return (node->value.custom.data);
else if (node->type == MXML_ELEMENT && else if (node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_CUSTOM)
node->child &&
node->child->type == MXML_CUSTOM)
return (node->child->value.custom.data); return (node->child->value.custom.data);
else else
return (NULL); return (NULL);
} }
/* //
* 'mxmlGetElement()' - Get the name for an element node. // 'mxmlGetElement()' - Get the name for an element node.
* //
* @code NULL@ is returned if the node is not an element node. // `NULL` is returned if the node is not an element node.
* //
* @since Mini-XML 2.7@
*/
const char * /* O - Element name or @code NULL@ */ const char * // O - Element name or `NULL`
mxmlGetElement(mxml_node_t *node) /* I - Node to get */ mxmlGetElement(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT)
*/
if (!node || node->type != MXML_ELEMENT)
return (NULL); return (NULL);
/* // Return the element name...
* Return the element name...
*/
return (node->value.element.name); return (node->value.element.name);
} }
/* //
* 'mxmlGetFirstChild()' - Get the first child of an element node. // 'mxmlGetFirstChild()' - Get the first child of an element node.
* //
* @code NULL@ is returned if the node is not an element node or if the node // `NULL` is returned if the node is not an element node or if the node
* has no children. // has no children.
* //
* @since Mini-XML 2.7@
*/
mxml_node_t * /* O - First child or @code NULL@ */ mxml_node_t * // O - First child or `NULL`
mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */ mxmlGetFirstChild(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT)
*/
if (!node || node->type != MXML_ELEMENT)
return (NULL); return (NULL);
/* // Return the first child node...
* Return the first child node...
*/
return (node->child); return (node->child);
} }
/* //
* 'mxmlGetInteger()' - Get the integer value from the specified node or its // 'mxmlGetInteger()' - Get the integer value from the specified node or its
* first child. // first child.
* //
* 0 is returned if the node (or its first child) is not an integer value node. // 0 is returned if the node (or its first child) is not an integer value node.
* //
* @since Mini-XML 2.7@
*/
int /* O - Integer value or 0 */ int // O - Integer value or 0
mxmlGetInteger(mxml_node_t *node) /* I - Node to get */ mxmlGetInteger(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (0); return (0);
/* // Return the integer value...
* Return the integer value... if (node->type == MXML_TYPE_INTEGER)
*/
if (node->type == MXML_INTEGER)
return (node->value.integer); return (node->value.integer);
else if (node->type == MXML_ELEMENT && else if (node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_INTEGER)
node->child &&
node->child->type == MXML_INTEGER)
return (node->child->value.integer); return (node->child->value.integer);
else else
return (0); return (0);
} }
/* //
* 'mxmlGetLastChild()' - Get the last child of an element node. // 'mxmlGetLastChild()' - Get the last child of an element node.
* //
* @code NULL@ is returned if the node is not an element node or if the node // `NULL` is returned if the node is not an element node or if the node
* has no children. // has no children.
* //
* @since Mini-XML 2.7@
*/
mxml_node_t * /* O - Last child or @code NULL@ */ mxml_node_t * // O - Last child or `NULL`
mxmlGetLastChild(mxml_node_t *node) /* I - Node to get */ mxmlGetLastChild(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT)
*/
if (!node || node->type != MXML_ELEMENT)
return (NULL); return (NULL);
/* // Return the last child node...
* Return the node type...
*/
return (node->last_child); return (node->last_child);
} }
/* //
* 'mxmlGetNextSibling()' - Get the next node for the current parent. // 'mxmlGetNextSibling()' - Get the next node for the current parent.
* //
* @code NULL@ is returned if this is the last child for the current parent. // `NULL` is returned if this is the last child for the current parent.
* //
* @since Mini-XML 2.7@
*/
mxml_node_t * mxml_node_t *
mxmlGetNextSibling(mxml_node_t *node) /* I - Node to get */ mxmlGetNextSibling(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the next sibling node...
* Return the node type...
*/
return (node->next); return (node->next);
} }
/* //
* 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child. // 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child.
* //
* @code NULL@ is returned if the node (or its first child) is not an opaque // `NULL` is returned if the node (or its first child) is not an opaque
* value node. // value node.
* //
* @since Mini-XML 2.7@
*/
const char * /* O - Opaque string or @code NULL@ */ const char * // O - Opaque string or `NULL`
mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */ mxmlGetOpaque(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the opaque value...
* Return the integer value... if (node->type == MXML_TYPE_OPAQUE)
*/
if (node->type == MXML_OPAQUE)
return (node->value.opaque); return (node->value.opaque);
else if (node->type == MXML_ELEMENT && else if (node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_OPAQUE)
node->child &&
node->child->type == MXML_OPAQUE)
return (node->child->value.opaque); return (node->child->value.opaque);
else else
return (NULL); return (NULL);
} }
/* //
* 'mxmlGetParent()' - Get the parent node. // 'mxmlGetParent()' - Get the parent node.
* //
* @code NULL@ is returned for a root node. // `NULL` is returned for a root node.
* //
* @since Mini-XML 2.7@
*/
mxml_node_t * /* O - Parent node or @code NULL@ */ mxml_node_t * // O - Parent node or `NULL`
mxmlGetParent(mxml_node_t *node) /* I - Node to get */ mxmlGetParent(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the parent node...
* Return the node type...
*/
return (node->parent); return (node->parent);
} }
/* //
* 'mxmlGetPrevSibling()' - Get the previous node for the current parent. // 'mxmlGetPrevSibling()' - Get the previous node for the current parent.
* //
* @code NULL@ is returned if this is the first child for the current parent. // `NULL` is returned if this is the first child for the current parent.
* //
* @since Mini-XML 2.7@
*/
mxml_node_t * /* O - Previous node or @code NULL@ */ mxml_node_t * // O - Previous node or `NULL`
mxmlGetPrevSibling(mxml_node_t *node) /* I - Node to get */ mxmlGetPrevSibling(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the previous sibling node...
* Return the node type...
*/
return (node->prev); return (node->prev);
} }
/* //
* 'mxmlGetReal()' - Get the real value for a node or its first child. // 'mxmlGetReal()' - Get the real value for a node or its first child.
* //
* 0.0 is returned if the node (or its first child) is not a real value node. // 0.0 is returned if the node (or its first child) is not a real value node.
* //
* @since Mini-XML 2.7@
*/
double /* O - Real value or 0.0 */ double // O - Real value or 0.0
mxmlGetReal(mxml_node_t *node) /* I - Node to get */ mxmlGetReal(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (0.0); return (0.0);
/* // Return the real value...
* Return the integer value... if (node->type == MXML_TYPE_REAL)
*/
if (node->type == MXML_REAL)
return (node->value.real); return (node->value.real);
else if (node->type == MXML_ELEMENT && else if (node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_REAL)
node->child &&
node->child->type == MXML_REAL)
return (node->child->value.real); return (node->child->value.real);
else else
return (0.0); return (0.0);
} }
/* //
* 'mxmlGetText()' - Get the text value for a node or its first child. // 'mxmlGetText()' - Get the text value for a node or its first child.
* //
* @code NULL@ is returned if the node (or its first child) is not a text node. // `NULL` is returned if the node (or its first child) is not a text node.
* The "whitespace" argument can be @code NULL@. // The "whitespace" argument can be `NULL`.
* //
* Note: Text nodes consist of whitespace-delimited words. You will only get // 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@ nodes. // single words of text when reading an XML file with `MXML_TYPE_TEXT` nodes.
* If you want the entire string between elements in the XML file, you MUST read // If you want the entire string between elements in the XML file, you MUST read
* the XML file with @code MXML_OPAQUE@ nodes and get the resulting strings // the XML file with `MXML_TYPE_OPAQUE` nodes and get the resulting strings
* using the @link mxmlGetOpaque@ function instead. // using the @link mxmlGetOpaque@ function instead.
* //
* @since Mini-XML 2.7@
*/ const char * // O - Text string or `NULL`
mxmlGetText(mxml_node_t *node, // I - Node to get
const char * /* O - Text string or @code NULL@ */ int *whitespace) // O - 1 if string is preceded by whitespace, 0 otherwise
mxmlGetText(mxml_node_t *node, /* I - Node to get */
int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
{ {
if (whitespace) if (whitespace)
@ -368,20 +261,15 @@ mxmlGetText(mxml_node_t *node, /* I - Node to get */
return (NULL); return (NULL);
} }
/* // Return the integer value...
* Return the integer value... if (node->type == MXML_TYPE_TEXT)
*/
if (node->type == MXML_TEXT)
{ {
if (whitespace) if (whitespace)
*whitespace = node->value.text.whitespace; *whitespace = node->value.text.whitespace;
return (node->value.text.string); return (node->value.text.string);
} }
else if (node->type == MXML_ELEMENT && else if (node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_TEXT)
node->child &&
node->child->type == MXML_TEXT)
{ {
if (whitespace) if (whitespace)
*whitespace = node->child->value.text.whitespace; *whitespace = node->child->value.text.whitespace;
@ -398,51 +286,35 @@ mxmlGetText(mxml_node_t *node, /* I - Node to get */
} }
/* //
* 'mxmlGetType()' - Get the node type. // 'mxmlGetType()' - Get the node type.
* //
* @code MXML_IGNORE@ is returned if "node" is @code NULL@. // `MXML_TYPE_IGNORE` is returned if "node" is `NULL`.
* //
* @since Mini-XML 2.7@
*/
mxml_type_t /* O - Type of node */ mxml_type_t // O - Type of node
mxmlGetType(mxml_node_t *node) /* I - Node to get */ mxmlGetType(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (MXML_IGNORE); return (MXML_TYPE_IGNORE);
/*
* Return the node type...
*/
// Return the node type...
return (node->type); return (node->type);
} }
/* //
* 'mxmlGetUserData()' - Get the user data pointer for a node. // 'mxmlGetUserData()' - Get the user data pointer for a node.
* //
* @since Mini-XML 2.7@
*/
void * /* O - User data pointer */ void * // O - User data pointer
mxmlGetUserData(mxml_node_t *node) /* I - Node to get */ mxmlGetUserData(mxml_node_t *node) // I - Node to get
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (NULL); return (NULL);
/* // Return the user data pointer...
* Return the user data pointer...
*/
return (node->user_data); return (node->user_data);
} }

@ -1,79 +1,60 @@
/* //
* Index support code for Mini-XML, a small XML file parsing library. // Index support code for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2021 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
/* //
* Sort functions... // Local functions...
*/ //
static int index_compare(mxml_index_t *ind, mxml_node_t *first, static int index_compare(mxml_index_t *ind, mxml_node_t *first, mxml_node_t *second);
mxml_node_t *second); static int index_find(mxml_index_t *ind, const char *element, const char *value, mxml_node_t *node);
static int index_find(mxml_index_t *ind, const char *element,
const char *value, mxml_node_t *node);
static void index_sort(mxml_index_t *ind, int left, int right); static void index_sort(mxml_index_t *ind, int left, int right);
/* //
* 'mxmlIndexDelete()' - Delete an index. // 'mxmlIndexDelete()' - Delete an index.
*/ //
void void
mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */ mxmlIndexDelete(mxml_index_t *ind) // I - Index to delete
{ {
/* // Range check input..
* Range check input..
*/
if (!ind) if (!ind)
return; return;
/* // Free memory...
* Free memory...
*/
free(ind->attr); free(ind->attr);
free(ind->nodes); free(ind->nodes);
free(ind); free(ind);
} }
/* //
* 'mxmlIndexEnum()' - Return the next node in the index. // 'mxmlIndexEnum()' - Return the next node in the index.
* //
* You should call @link mxmlIndexReset@ prior to using this function to get // You should call @link mxmlIndexReset@ prior to using this function to get
* the first node in the index. Nodes are returned in the sorted order of the // the first node in the index. Nodes are returned in the sorted order of the
* index. // index.
*/ //
mxml_node_t * /* O - Next node or @code NULL@ if there is none */ mxml_node_t * // O - Next node or `NULL` if there is none
mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */ mxmlIndexEnum(mxml_index_t *ind) // I - Index to enumerate
{ {
/* // Range check input...
* Range check input...
*/
if (!ind) if (!ind)
return (NULL); return (NULL);
/* // Return the next node...
* Return the next node...
*/
if (ind->cur_node < ind->num_nodes) if (ind->cur_node < ind->num_nodes)
return (ind->nodes[ind->cur_node ++]); return (ind->nodes[ind->cur_node ++]);
else else
@ -81,249 +62,164 @@ mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */
} }
/* //
* 'mxmlIndexFind()' - Find the next matching node. // 'mxmlIndexFind()' - Find the next matching node.
* //
* You should call @link mxmlIndexReset@ prior to using this function for // You should call @link mxmlIndexReset@ prior to using this function for
* the first time with a particular set of "element" and "value" // the first time with a particular set of "element" and "value"
* strings. Passing @code NULL@ for both "element" and "value" is equivalent // strings. Passing `NULL` for both "element" and "value" is equivalent
* to calling @link mxmlIndexEnum@. // to calling @link mxmlIndexEnum@.
*/ //
mxml_node_t * /* O - Node or @code NULL@ if none found */ mxml_node_t * // O - Node or `NULL` if none found
mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */ mxmlIndexFind(mxml_index_t *ind, // I - Index to search
const char *element, /* I - Element name to find, if any */ const char *element, // I - Element name to find, if any
const char *value) /* I - Attribute value, if any */ const char *value) // I - Attribute value, if any
{ {
int diff, /* Difference between names */ int diff, // Difference between names
current, /* Current entity in search */ current, // Current entity in search
first, /* First entity in search */ first, // First entity in search
last; /* Last entity in search */ last; // Last entity in search
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n", ind, element ? element : "(null)", value ? value : "(null)");
printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
ind, element ? element : "(null)", value ? value : "(null)");
#endif /* DEBUG */
/*
* Range check input...
*/
// Range check input...
if (!ind || (!ind->attr && value)) if (!ind || (!ind->attr && value))
{ {
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: Returning NULL, ind->attr=\"%s\"...\n", ind && ind->attr ? ind->attr : "(null)");
puts(" returning NULL...");
if (ind)
printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
#endif /* DEBUG */
return (NULL); return (NULL);
} }
/* // If both element and value are NULL, just enumerate the nodes in the index...
* If both element and value are NULL, just enumerate the nodes in the
* index...
*/
if (!element && !value) if (!element && !value)
return (mxmlIndexEnum(ind)); return (mxmlIndexEnum(ind));
/* // If there are no nodes in the index, return NULL...
* If there are no nodes in the index, return NULL...
*/
if (!ind->num_nodes) if (!ind->num_nodes)
{ {
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: Returning NULL, no nodes...\n");
puts(" returning NULL...");
puts(" no nodes!");
#endif /* DEBUG */
return (NULL); return (NULL);
} }
/* // If cur_node == 0, then find the first matching node...
* If cur_node == 0, then find the first matching node...
*/
if (ind->cur_node == 0) if (ind->cur_node == 0)
{ {
/* // Find the first node using a modified binary search algorithm...
* Find the first node using a modified binary search algorithm...
*/
first = 0; first = 0;
last = ind->num_nodes - 1; last = ind->num_nodes - 1;
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: Find first time, num_nodes=%d...\n", ind->num_nodes);
printf(" find first time, num_nodes=%d...\n", ind->num_nodes);
#endif /* DEBUG */
while ((last - first) > 1) while ((last - first) > 1)
{ {
current = (first + last) / 2; current = (first + last) / 2;
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: first=%d, last=%d, current=%d\n", first, last, current);
printf(" first=%d, last=%d, current=%d\n", first, last, current);
#endif /* DEBUG */
if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0) if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
{ {
/* // Found a match, move back to find the first...
* Found a match, move back to find the first... MXML_DEBUG("mxmlIndexFind: match.\n");
*/
#ifdef DEBUG
puts(" match!");
#endif /* DEBUG */
while (current > 0 && while (current > 0 && !index_find(ind, element, value, ind->nodes[current - 1]))
!index_find(ind, element, value, ind->nodes[current - 1]))
current --; current --;
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: Returning first match=%d\n", current);
printf(" returning first match=%d\n", current);
#endif /* DEBUG */
/*
* Return the first match and save the index to the next...
*/
// Return the first match and save the index to the next...
ind->cur_node = current + 1; ind->cur_node = current + 1;
return (ind->nodes[current]); return (ind->nodes[current]);
} }
else if (diff < 0) else if (diff < 0)
{
last = current; last = current;
}
else else
{
first = current; first = current;
}
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: diff=%d\n", diff);
printf(" diff=%d\n", diff);
#endif /* DEBUG */
} }
/* // If we get this far, then we found exactly 0 or 1 matches...
* If we get this far, then we found exactly 0 or 1 matches...
*/
for (current = first; current <= last; current ++) for (current = first; current <= last; current ++)
{
if (!index_find(ind, element, value, ind->nodes[current])) if (!index_find(ind, element, value, ind->nodes[current]))
{ {
/* // Found exactly one (or possibly two) match...
* Found exactly one (or possibly two) match... MXML_DEBUG("mxmlIndexFind: Returning only match %d...\n", current);
*/
#ifdef DEBUG
printf(" returning only match %d...\n", current);
#endif /* DEBUG */
ind->cur_node = current + 1; ind->cur_node = current + 1;
return (ind->nodes[current]); return (ind->nodes[current]);
} }
}
/* // No matches...
* No matches...
*/
ind->cur_node = ind->num_nodes; ind->cur_node = ind->num_nodes;
MXML_DEBUG("mxmlIndexFind: Returning NULL...\n");
#ifdef DEBUG
puts(" returning NULL...");
#endif /* DEBUG */
return (NULL); return (NULL);
} }
else if (ind->cur_node < ind->num_nodes && else if (ind->cur_node < ind->num_nodes && !index_find(ind, element, value, ind->nodes[ind->cur_node]))
!index_find(ind, element, value, ind->nodes[ind->cur_node]))
{ {
/* // Return the next matching node...
* Return the next matching node... MXML_DEBUG("mxmlIndexFind: Returning next match %d...\n", ind->cur_node);
*/
#ifdef DEBUG
printf(" returning next match %d...\n", ind->cur_node);
#endif /* DEBUG */
return (ind->nodes[ind->cur_node ++]); return (ind->nodes[ind->cur_node ++]);
} }
/* // If we get this far, then we have no matches...
* If we get this far, then we have no matches...
*/
ind->cur_node = ind->num_nodes; ind->cur_node = ind->num_nodes;
#ifdef DEBUG MXML_DEBUG("mxmlIndexFind: Returning NULL...\n");
puts(" returning NULL...");
#endif /* DEBUG */
return (NULL); return (NULL);
} }
/* //
* 'mxmlIndexGetCount()' - Get the number of nodes in an index. // 'mxmlIndexGetCount()' - Get the number of nodes in an index.
* //
* @since Mini-XML 2.7@
*/
int /* I - Number of nodes in index */ int // I - Number of nodes in index
mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */ mxmlIndexGetCount(mxml_index_t *ind) // I - Index of nodes
{ {
/* // Range check input...
* Range check input...
*/
if (!ind) if (!ind)
return (0); return (0);
/* // Return the number of nodes in the index...
* Return the number of nodes in the index...
*/
return (ind->num_nodes); return (ind->num_nodes);
} }
/* //
* 'mxmlIndexNew()' - Create a new index. // 'mxmlIndexNew()' - Create a new index.
* //
* The index will contain all nodes that contain the named element and/or // The index will contain all nodes that contain the named element and/or
* attribute. If both "element" and "attr" are @code NULL@, then the index will // attribute. If both "element" and "attr" are `NULL`, then the index will
* contain a sorted list of the elements in the node tree. Nodes are // 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" // sorted by element name and optionally by attribute value if the "attr"
* argument is not NULL. // argument is not NULL.
*/ //
mxml_index_t * /* O - New index */ mxml_index_t * // O - New index
mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */ mxmlIndexNew(mxml_node_t *node, // I - XML node tree
const char *element, /* I - Element to index or @code NULL@ for all */ const char *element, // I - Element to index or `NULL` for all
const char *attr) /* I - Attribute to index or @code NULL@ for none */ const char *attr) // I - Attribute to index or `NULL` for none
{ {
mxml_index_t *ind; /* New index */ mxml_index_t *ind; // New index
mxml_node_t *current, /* Current node in index */ mxml_node_t *current, // Current node in index
**temp; /* Temporary node pointer array */ **temp; // Temporary node pointer array
/*
* Range check input...
*/
#ifdef DEBUG // Range check input...
printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n", MXML_DEBUG("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n", node, element ? element : "(null)", attr ? attr : "(null)");
node, element ? element : "(null)", attr ? attr : "(null)");
#endif /* DEBUG */
if (!node) if (!node)
return (NULL); return (NULL);
/* // Create a new index...
* Create a new index...
*/
if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL) if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
{ {
mxml_error("Unable to allocate memory for index."); mxml_error("Unable to allocate memory for index.");
@ -356,10 +252,7 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
if (!temp) if (!temp)
{ {
/* // Unable to allocate memory for the index, so abort...
* Unable to allocate memory for the index, so abort...
*/
mxml_error("Unable to allocate memory for index nodes."); mxml_error("Unable to allocate memory for index nodes.");
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
return (NULL); return (NULL);
@ -374,115 +267,36 @@ mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND); current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
} }
/* // Sort nodes based upon the search criteria...
* Sort nodes based upon the search criteria...
*/
#ifdef DEBUG
{
int i; /* Looping var */
printf("%d node(s) in index.\n\n", ind->num_nodes);
if (attr)
{
printf("Node Address Element %s\n", attr);
puts("-------- -------- -------------- ------------------------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name,
mxmlElementGetAttr(ind->nodes[i], attr));
}
else
{
puts("Node Address Element");
puts("-------- -------- --------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name);
}
putchar('\n');
}
#endif /* DEBUG */
if (ind->num_nodes > 1) if (ind->num_nodes > 1)
index_sort(ind, 0, ind->num_nodes - 1); index_sort(ind, 0, ind->num_nodes - 1);
#ifdef DEBUG // Return the new index...
{
int i; /* Looping var */
puts("After sorting:\n");
if (attr)
{
printf("Node Address Element %s\n", attr);
puts("-------- -------- -------------- ------------------------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name,
mxmlElementGetAttr(ind->nodes[i], attr));
}
else
{
puts("Node Address Element");
puts("-------- -------- --------------");
for (i = 0; i < ind->num_nodes; i ++)
printf("%8d %-8p %s\n", i, ind->nodes[i],
ind->nodes[i]->value.element.name);
}
putchar('\n');
}
#endif /* DEBUG */
/*
* Return the new index...
*/
return (ind); return (ind);
} }
/* //
* 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and // 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and
* return the first node in the index. // return the first node in the index.
* //
* This function should be called prior to using @link mxmlIndexEnum@ or // This function should be called prior to using @link mxmlIndexEnum@ or
* @link mxmlIndexFind@ for the first time. // @link mxmlIndexFind@ for the first time.
*/ //
mxml_node_t * /* O - First node or @code NULL@ if there is none */ mxml_node_t * // O - First node or `NULL` if there is none
mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */ mxmlIndexReset(mxml_index_t *ind) // I - Index to reset
{ {
#ifdef DEBUG MXML_DEBUG("mxmlIndexReset(ind=%p)\n", ind);
printf("mxmlIndexReset(ind=%p)\n", ind);
#endif /* DEBUG */
/*
* Range check input...
*/
// Range check input...
if (!ind) if (!ind)
return (NULL); return (NULL);
/* // Set the index to the first element...
* Set the index to the first element...
*/
ind->cur_node = 0; ind->cur_node = 0;
/* // Return the first node...
* Return the first node...
*/
if (ind->num_nodes) if (ind->num_nodes)
return (ind->nodes[0]); return (ind->nodes[0]);
else else
@ -490,137 +304,100 @@ mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */
} }
/* //
* 'index_compare()' - Compare two nodes. // 'index_compare()' - Compare two nodes.
*/ //
static int /* O - Result of comparison */ static int // O - Result of comparison
index_compare(mxml_index_t *ind, /* I - Index */ index_compare(mxml_index_t *ind, // I - Index
mxml_node_t *first, /* I - First node */ mxml_node_t *first, // I - First node
mxml_node_t *second) /* I - Second node */ mxml_node_t *second) // I - Second node
{ {
int diff; /* Difference */ int diff; // Difference
/*
* Check the element name...
*/
if ((diff = strcmp(first->value.element.name, // Check the element name...
second->value.element.name)) != 0) if ((diff = strcmp(first->value.element.name, second->value.element.name)) != 0)
return (diff); return (diff);
/* // Check the attribute value...
* Check the attribute value...
*/
if (ind->attr) if (ind->attr)
{ {
if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr), if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr), mxmlElementGetAttr(second, ind->attr))) != 0)
mxmlElementGetAttr(second, ind->attr))) != 0)
return (diff); return (diff);
} }
/* // No difference, return 0...
* No difference, return 0...
*/
return (0); return (0);
} }
/* //
* 'index_find()' - Compare a node with index values. // 'index_find()' - Compare a node with index values.
*/ //
static int /* O - Result of comparison */ static int // O - Result of comparison
index_find(mxml_index_t *ind, /* I - Index */ index_find(mxml_index_t *ind, // I - Index
const char *element, /* I - Element name or @code NULL@ */ const char *element, // I - Element name or `NULL`
const char *value, /* I - Attribute value or @code NULL@ */ const char *value, // I - Attribute value or `NULL`
mxml_node_t *node) /* I - Node */ mxml_node_t *node) // I - Node
{ {
int diff; /* Difference */ int diff; // Difference
/*
* Check the element name...
*/
// Check the element name...
if (element) if (element)
{ {
if ((diff = strcmp(element, node->value.element.name)) != 0) if ((diff = strcmp(element, node->value.element.name)) != 0)
return (diff); return (diff);
} }
/* // Check the attribute value...
* Check the attribute value...
*/
if (value) if (value)
{ {
if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0) if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
return (diff); return (diff);
} }
/* // No difference, return 0...
* No difference, return 0...
*/
return (0); return (0);
} }
/* //
* 'index_sort()' - Sort the nodes in the index... // 'index_sort()' - Sort the nodes in the index...
* //
* This function implements the classic quicksort algorithm... // This function implements the classic quicksort algorithm...
*/ //
static void static void
index_sort(mxml_index_t *ind, /* I - Index to sort */ index_sort(mxml_index_t *ind, // I - Index to sort
int left, /* I - Left node in partition */ int left, // I - Left node in partition
int right) /* I - Right node in partition */ int right) // I - Right node in partition
{ {
mxml_node_t *pivot, /* Pivot node */ mxml_node_t *pivot, // Pivot node
*temp; /* Swap node */ *temp; // Swap node
int templ, /* Temporary left node */ int templ, // Temporary left node
tempr; /* Temporary right node */ tempr; // Temporary right node
/*
* Loop until we have sorted all the way to the right...
*/
// Loop until we have sorted all the way to the right...
do do
{ {
/* // Sort the pivot in the current partition...
* Sort the pivot in the current partition...
*/
pivot = ind->nodes[left]; pivot = ind->nodes[left];
for (templ = left, tempr = right; templ < tempr;) for (templ = left, tempr = right; templ < tempr;)
{ {
/* // Move left while left node <= pivot node...
* Move left while left node <= pivot node... while ((templ < right) && index_compare(ind, ind->nodes[templ], pivot) <= 0)
*/
while ((templ < right) &&
index_compare(ind, ind->nodes[templ], pivot) <= 0)
templ ++; templ ++;
/* // Move right while right node > pivot node...
* Move right while right node > pivot node... while ((tempr > left) && index_compare(ind, ind->nodes[tempr], pivot) > 0)
*/
while ((tempr > left) &&
index_compare(ind, ind->nodes[tempr], pivot) > 0)
tempr --; tempr --;
/* // Swap nodes if needed...
* Swap nodes if needed...
*/
if (templ < tempr) if (templ < tempr)
{ {
temp = ind->nodes[templ]; temp = ind->nodes[templ];
@ -629,21 +406,14 @@ index_sort(mxml_index_t *ind, /* I - Index to sort */
} }
} }
/* // When we get here, the right (tempr) node is the new position for the pivot node...
* When we get here, the right (tempr) node is the new position for the
* pivot node...
*/
if (index_compare(ind, pivot, ind->nodes[tempr]) > 0) if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
{ {
ind->nodes[left] = ind->nodes[tempr]; ind->nodes[left] = ind->nodes[tempr];
ind->nodes[tempr] = pivot; ind->nodes[tempr] = pivot;
} }
/* // Recursively sort the left partition as needed...
* Recursively sort the left partition as needed...
*/
if (left < (tempr - 1)) if (left < (tempr - 1))
index_sort(ind, left, tempr - 1); index_sort(ind, left, tempr - 1);
} }

File diff suppressed because it is too large Load Diff

@ -1,34 +1,30 @@
/* //
* Private functions for Mini-XML, a small XML file parsing library. // Private functions for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2022 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "mxml-private.h" #include "mxml-private.h"
/* //
* Some crazy people think that unloading a shared object is a good or safe // Some crazy people think that unloading a shared object is a good or safe
* thing to do. Unfortunately, most objects are simply *not* safe to unload // thing to do. Unfortunately, most objects are simply *not* safe to unload
* and bad things *will* happen. // and bad things *will* happen.
* //
* The following mess of conditional code allows us to provide a destructor // The following mess of conditional code allows us to provide a destructor
* function in Mini-XML for our thread-global storage so that it can possibly // function in Mini-XML for our thread-global storage so that it can possibly
* be unloaded safely, although since there is no standard way to do so I // 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. // can't even provide any guarantees that you can do it safely on all platforms.
* //
* This code currently supports AIX, HP-UX, Linux, macOS, 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. // Windows. It might work on the BSDs and IRIX, but I haven't tested that.
*/ //
#if defined(__sun) || defined(_AIX) #if defined(__sun) || defined(_AIX)
# pragma fini(_mxml_fini) # pragma fini(_mxml_fini)
@ -36,133 +32,122 @@
#elif defined(__hpux) #elif defined(__hpux)
# pragma FINI _mxml_fini # pragma FINI _mxml_fini
# define _MXML_FINI _mxml_fini # define _MXML_FINI _mxml_fini
#elif defined(__GNUC__) /* Linux and macOS */ #elif defined(__GNUC__) // Linux and macOS
# define _MXML_FINI __attribute((destructor)) _mxml_fini # define _MXML_FINI __attribute((destructor)) _mxml_fini
#else #else
# define _MXML_FINI _fini # define _MXML_FINI _fini
#endif /* __sun */ #endif // __sun
/* //
* 'mxml_error()' - Display an error message. // 'mxml_error()' - Display an error message.
*/ //
void void
mxml_error(const char *format, /* I - Printf-style format string */ mxml_error(const char *format, // I - Printf-style format string
...) /* I - Additional arguments as needed */ ...) // I - Additional arguments as needed
{ {
va_list ap; /* Pointer to arguments */ va_list ap; // Pointer to arguments
char s[1024]; /* Message string */ char s[1024]; // Message string
_mxml_global_t *global = _mxml_global(); _mxml_global_t *global = _mxml_global();
/* Global data */ // Global data
/* // Range check input...
* Range check input...
*/
if (!format) if (!format)
return; return;
/* // Format the error message string...
* Format the error message string...
*/
va_start(ap, format); va_start(ap, format);
vsnprintf(s, sizeof(s), format, ap); vsnprintf(s, sizeof(s), format, ap);
va_end(ap); va_end(ap);
/* // And then display the error message...
* And then display the error message...
*/
if (global->error_cb) if (global->error_cb)
(*global->error_cb)(s); (*global->error_cb)(s);
else else
fprintf(stderr, "mxml: %s\n", s); fprintf(stderr, "%s\n", s);
} }
/* //
* 'mxml_ignore_cb()' - Default callback for ignored values. // 'mxml_ignore_cb()' - Default callback for ignored values.
*/ //
mxml_type_t /* O - Node type */ mxml_type_t // O - Node type
mxml_ignore_cb(mxml_node_t *node) /* I - Current node */ mxml_ignore_cb(mxml_node_t *node) // I - Current node
{ {
(void)node; (void)node;
return (MXML_IGNORE); return (MXML_TYPE_IGNORE);
} }
/* //
* 'mxml_integer_cb()' - Default callback for integer values. // 'mxml_integer_cb()' - Default callback for integer values.
*/ //
mxml_type_t /* O - Node type */ mxml_type_t // O - Node type
mxml_integer_cb(mxml_node_t *node) /* I - Current node */ mxml_integer_cb(mxml_node_t *node) // I - Current node
{ {
(void)node; (void)node;
return (MXML_INTEGER); return (MXML_TYPE_INTEGER);
} }
/* //
* 'mxml_opaque_cb()' - Default callback for opaque values. // 'mxml_opaque_cb()' - Default callback for opaque values.
*/ //
mxml_type_t /* O - Node type */ mxml_type_t // O - Node type
mxml_opaque_cb(mxml_node_t *node) /* I - Current node */ mxml_opaque_cb(mxml_node_t *node) // I - Current node
{ {
(void)node; (void)node;
return (MXML_OPAQUE); return (MXML_TYPE_OPAQUE);
} }
/* //
* 'mxml_real_cb()' - Default callback for real number values. // 'mxml_real_cb()' - Default callback for real number values.
*/ //
mxml_type_t /* O - Node type */ mxml_type_t // O - Node type
mxml_real_cb(mxml_node_t *node) /* I - Current node */ mxml_real_cb(mxml_node_t *node) // I - Current node
{ {
(void)node; (void)node;
return (MXML_REAL); return (MXML_TYPE_REAL);
} }
#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/ #ifdef HAVE_PTHREAD_H // POSIX threading
# include <pthread.h> # include <pthread.h>
static int _mxml_initialized = 0; static int _mxml_initialized = 0;
/* Have we been initialized? */ // Have we been initialized?
static pthread_key_t _mxml_key; /* Thread local storage key */ static pthread_key_t _mxml_key; // Thread local storage key
static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT; static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
/* One-time initialization object */ // One-time initialization object
static void _mxml_init(void); static void _mxml_init(void);
static void _mxml_destructor(void *g); static void _mxml_destructor(void *g);
/* //
* '_mxml_destructor()' - Free memory used for globals... // '_mxml_destructor()' - Free memory used for globals...
*/ //
static void static void
_mxml_destructor(void *g) /* I - Global data */ _mxml_destructor(void *g) // I - Global data
{ {
free(g); free(g);
} }
/* //
* '_mxml_fini()' - Clean up when unloaded. // '_mxml_fini()' - Clean up when unloaded.
*/ //
static void static void
_MXML_FINI(void) _MXML_FINI(void)
@ -172,14 +157,14 @@ _MXML_FINI(void)
} }
/* //
* '_mxml_global()' - Get global data. // '_mxml_global()' - Get global data.
*/ //
_mxml_global_t * /* O - Global data */ _mxml_global_t * // O - Global data
_mxml_global(void) _mxml_global(void)
{ {
_mxml_global_t *global; /* Global data */ _mxml_global_t *global; // Global data
pthread_once(&_mxml_key_once, _mxml_init); pthread_once(&_mxml_key_once, _mxml_init);
@ -198,9 +183,9 @@ _mxml_global(void)
} }
/* //
* '_mxml_init()' - Initialize global data... // '_mxml_init()' - Initialize global data...
*/ //
static void static void
_mxml_init(void) _mxml_init(void)
@ -210,22 +195,22 @@ _mxml_init(void)
} }
#elif defined(_WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/ #elif defined(_WIN32) && defined(MXML1_EXPORTS) // WIN32 threading
# include <windows.h> # include <windows.h>
static DWORD _mxml_tls_index; /* Index for global storage */ static DWORD _mxml_tls_index; // Index for global storage
/* //
* 'DllMain()' - Main entry for library. // 'DllMain()' - Main entry for library.
*/ //
BOOL WINAPI /* O - Success/failure */ BOOL WINAPI // O - Success/failure
DllMain(HINSTANCE hinst, /* I - DLL module handle */ DllMain(HINSTANCE hinst, // I - DLL module handle
DWORD reason, /* I - Reason */ DWORD reason, // I - Reason
LPVOID reserved) /* I - Unused */ LPVOID reserved) // I - Unused
{ {
_mxml_global_t *global; /* Global data */ _mxml_global_t *global; // Global data
(void)hinst; (void)hinst;
@ -233,17 +218,17 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */
switch (reason) switch (reason)
{ {
case DLL_PROCESS_ATTACH : /* Called on library initialization */ case DLL_PROCESS_ATTACH : // Called on library initialization
if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return (FALSE); return (FALSE);
break; break;
case DLL_THREAD_DETACH : /* Called when a thread terminates */ case DLL_THREAD_DETACH : // Called when a thread terminates
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL) if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global); free(global);
break; break;
case DLL_PROCESS_DETACH : /* Called when library is unloaded */ case DLL_PROCESS_DETACH : // Called when library is unloaded
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL) if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
free(global); free(global);
@ -258,14 +243,14 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */
} }
/* //
* '_mxml_global()' - Get global data. // '_mxml_global()' - Get global data.
*/ //
_mxml_global_t * /* O - Global data */ _mxml_global_t * // O - Global data
_mxml_global(void) _mxml_global(void)
{ {
_mxml_global_t *global; /* Global data */ _mxml_global_t *global; // Global data
if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL) if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
@ -283,25 +268,25 @@ _mxml_global(void)
} }
#else /**** No threading ****/ #else // No threading
/* //
* '_mxml_global()' - Get global data. // '_mxml_global()' - Get global data.
*/ //
_mxml_global_t * /* O - Global data */ _mxml_global_t * // O - Global data
_mxml_global(void) _mxml_global(void)
{ {
static _mxml_global_t global = /* Global data */ static _mxml_global_t global = // Global data
{ {
NULL, /* error_cb */ NULL, // error_cb
1, /* num_entity_cbs */ 1, // num_entity_cbs
{ _mxml_entity_cb }, /* entity_cbs */ { _mxml_entity_cb }, // entity_cbs
72, /* wrap */ 72, // wrap
NULL, /* custom_load_cb */ NULL, // custom_load_cb
NULL /* custom_save_cb */ NULL // custom_save_cb
}; };
return (&global); return (&global);
} }
#endif /* HAVE_PTHREAD_H */ #endif // HAVE_PTHREAD_H

@ -1,87 +1,93 @@
/* //
* Private definitions for Mini-XML, a small XML file parsing library. // Private definitions for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2019 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
#ifndef _mxml_private_h_ #ifndef MXML_PRIVATE_H
# define _mxml_private_h_ # define MXML_PRIVATE_H
/*
* Include necessary headers...
*/
# include "config.h" # include "config.h"
# include "mxml.h" # include "mxml.h"
/* //
* Private structures... // Private macros...
*/ //
# ifdef DEBUG
# define MXML_DEBUG(...) fprintf(stderr, __VA_ARGS__)
# else
# define MXML_DEBUG(...)
# endif // DEBUG
typedef struct _mxml_attr_s /**** An XML element attribute value. ****/ //
// Private structures...
//
typedef struct _mxml_attr_s // An XML element attribute value.
{ {
char *name; /* Attribute name */ char *name; // Attribute name
char *value; /* Attribute value */ char *value; // Attribute value
} _mxml_attr_t; } _mxml_attr_t;
typedef struct _mxml_element_s /**** An XML element value. ****/ typedef struct _mxml_element_s // An XML element value.
{ {
char *name; /* Name of element */ char *name; // Name of element
int num_attrs; /* Number of attributes */ int num_attrs; // Number of attributes
_mxml_attr_t *attrs; /* Attributes */ _mxml_attr_t *attrs; // Attributes
} _mxml_element_t; } _mxml_element_t;
typedef struct _mxml_text_s /**** An XML text value. ****/ typedef struct _mxml_text_s // An XML text value.
{ {
int whitespace; /* Leading whitespace? */ int whitespace; // Leading whitespace?
char *string; /* Fragment string */ char *string; // Fragment string
} _mxml_text_t; } _mxml_text_t;
typedef struct _mxml_custom_s /**** An XML custom value. ****/ typedef struct _mxml_custom_s // An XML custom value.
{ {
void *data; /* Pointer to (allocated) custom data */ void *data; // Pointer to (allocated) custom data
mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */ mxml_custom_destroy_cb_t destroy; // Pointer to destructor function
} _mxml_custom_t; } _mxml_custom_t;
typedef union _mxml_value_u /**** An XML node value. ****/ typedef union _mxml_value_u // An XML node value.
{ {
_mxml_element_t element; /* Element */ _mxml_element_t element; // Element
int integer; /* Integer number */ int integer; // Integer number
char *opaque; /* Opaque string */ char *opaque; // Opaque string
double real; /* Real number */ double real; // Real number
_mxml_text_t text; /* Text fragment */ _mxml_text_t text; // Text fragment
_mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */ _mxml_custom_t custom; // Custom data @since Mini-XML 2.1@
} _mxml_value_t; } _mxml_value_t;
struct _mxml_node_s /**** An XML node. ****/ struct _mxml_node_s // An XML node.
{ {
mxml_type_t type; /* Node type */ mxml_type_t type; // Node type
struct _mxml_node_s *next; /* Next node under same parent */ struct _mxml_node_s *next; // Next node under same parent
struct _mxml_node_s *prev; /* Previous node under same parent */ struct _mxml_node_s *prev; // Previous node under same parent
struct _mxml_node_s *parent; /* Parent node */ struct _mxml_node_s *parent; // Parent node
struct _mxml_node_s *child; /* First child node */ struct _mxml_node_s *child; // First child node
struct _mxml_node_s *last_child; /* Last child node */ struct _mxml_node_s *last_child; // Last child node
_mxml_value_t value; /* Node value */ _mxml_value_t value; // Node value
int ref_count; /* Use count */ int ref_count; // Use count
void *user_data; /* User data */ void *user_data; // User data
}; };
struct _mxml_index_s /**** An XML node index. ****/ struct _mxml_index_s // An XML node index.
{ {
char *attr; /* Attribute used for indexing or NULL */ char *attr; // Attribute used for indexing or NULL
int num_nodes; /* Number of nodes in index */ int num_nodes; // Number of nodes in index
int alloc_nodes; /* Allocated nodes in index */ int alloc_nodes; // Allocated nodes in index
int cur_node; /* Current node */ int cur_node; // Current node
mxml_node_t **nodes; /* Node array */ mxml_node_t **nodes; // Node array
}; };
typedef struct _mxml_global_s /**** Global, per-thread data ****/ typedef struct _mxml_global_s // Global, per-thread data
{ {
void (*error_cb)(const char *); void (*error_cb)(const char *);
@ -93,11 +99,12 @@ typedef struct _mxml_global_s /**** Global, per-thread data ****/
} _mxml_global_t; } _mxml_global_t;
/* //
* Functions... // Private functions...
*/ //
extern _mxml_global_t *_mxml_global(void); extern _mxml_global_t *_mxml_global(void);
extern int _mxml_entity_cb(const char *name); extern int _mxml_entity_cb(const char *name);
#endif /* !_mxml_private_h_ */
#endif // !MXML_PRIVATE_H

@ -1,99 +1,68 @@
/* //
* Search/navigation functions for Mini-XML, a small XML file parsing library. // Search/navigation functions for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2019 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
/* //
* 'mxmlFindElement()' - Find the named element. // 'mxmlFindElement()' - Find the named element.
* //
* The search is constrained by the name, attribute name, and value; any // The search is constrained by the name, attribute name, and value; any
* @code NULL@ names or values are treated as wildcards, so different kinds of // `NULL` names or values are treated as wildcards, so different kinds of
* searches can be implemented by looking for all elements of a given name // searches can be implemented by looking for all elements of a given name
* or all elements with a specific attribute. The descend argument determines // or all elements with a specific attribute. The descend argument determines
* whether the search descends into child nodes; normally you will use // whether the search descends into child nodes; normally you will use
* @code MXML_DESCEND_FIRST@ for the initial search and @code MXML_NO_DESCEND@ // `MXML_DESCEND_FIRST` for the initial search and `MXML_NO_DESCEND`
* to find additional direct descendents of the node. The top node argument // to find additional direct descendents of the node. The top node argument
* constrains the search to a particular node's children. // constrains the search to a particular node's children.
*/ //
mxml_node_t * /* O - Element node or @code NULL@ */ mxml_node_t * // O - Element node or `NULL`
mxmlFindElement(mxml_node_t *node, /* I - Current node */ mxmlFindElement(mxml_node_t *node, // I - Current node
mxml_node_t *top, /* I - Top node */ mxml_node_t *top, // I - Top node
const char *element, /* I - Element name or @code NULL@ for any */ const char *element, // I - Element name or `NULL` for any
const char *attr, /* I - Attribute name, or @code NULL@ for none */ const char *attr, // I - Attribute name, or `NULL` for none
const char *value, /* I - Attribute value, or @code NULL@ for any */ const char *value, // I - Attribute value, or `NULL` for any
int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ int descend) // I - Descend into tree - `MXML_DESCEND`, `MXML_NO_DESCEND`, or `MXML_DESCEND_FIRST`
{ {
const char *temp; /* Current attribute value */ const char *temp; // Current attribute value
/*
* Range check input...
*/
// Range check input...
if (!node || !top || (!attr && value)) if (!node || !top || (!attr && value))
return (NULL); return (NULL);
/* // Start with the next node...
* Start with the next node...
*/
node = mxmlWalkNext(node, top, descend); node = mxmlWalkNext(node, top, descend);
/* // Loop until we find a matching element...
* Loop until we find a matching element...
*/
while (node != NULL) while (node != NULL)
{ {
/* // See if this node matches...
* See if this node matches... if (node->type == MXML_TYPE_ELEMENT && node->value.element.name && (!element || !strcmp(node->value.element.name, element)))
*/
if (node->type == MXML_ELEMENT &&
node->value.element.name &&
(!element || !strcmp(node->value.element.name, element)))
{ {
/* // See if we need to check for an attribute...
* See if we need to check for an attribute...
*/
if (!attr) if (!attr)
return (node); /* No attribute search, return it... */ return (node); // No attribute search, return it...
/*
* Check for the attribute...
*/
// Check for the attribute...
if ((temp = mxmlElementGetAttr(node, attr)) != NULL) if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
{ {
/* // OK, we have the attribute, does it match?
* OK, we have the attribute, does it match?
*/
if (!value || !strcmp(value, temp)) if (!value || !strcmp(value, temp))
return (node); /* Yes, return it... */ return (node); // Yes, return it...
} }
} }
/* // No match, move on to the next node...
* No match, move on to the next node...
*/
if (descend == MXML_DESCEND) if (descend == MXML_DESCEND)
node = mxmlWalkNext(node, top, MXML_DESCEND); node = mxmlWalkNext(node, top, MXML_DESCEND);
else else
@ -104,59 +73,47 @@ mxmlFindElement(mxml_node_t *node, /* I - Current node */
} }
/* //
* 'mxmlFindPath()' - Find a node with the given path. // 'mxmlFindPath()' - Find a node with the given path.
* //
* The "path" is a slash-separated list of element names. The name "*" is // The "path" is a slash-separated list of element names. The name "*" is
* considered a wildcard for one or more levels of elements. For example, // considered a wildcard for one or more levels of elements. For example,
* "foo/one/two", "bar/two/one", "*\/one", and so forth. // "foo/one/two", "bar/two/one", "*\/one", and so forth.
* //
* The first child node of the found node is returned if the given node has // The first child node of the found node is returned if the given node has
* children and the first child is a value node. // children and the first child is a value node.
* //
* @since Mini-XML 2.7@
*/ mxml_node_t * // O - Found node or `NULL`
mxmlFindPath(mxml_node_t *top, // I - Top node
mxml_node_t * /* O - Found node or @code NULL@ */ const char *path) // I - Path to element
mxmlFindPath(mxml_node_t *top, /* I - Top node */
const char *path) /* I - Path to element */
{ {
mxml_node_t *node; /* Current node */ mxml_node_t *node; // Current node
char element[256]; /* Current element name */ char element[256]; // Current element name
const char *pathsep; /* Separator in path */ const char *pathsep; // Separator in path
int descend; /* mxmlFindElement option */ int descend; // mxmlFindElement option
/*
* Range check input...
*/
// Range check input...
if (!top || !path || !*path) if (!top || !path || !*path)
return (NULL); return (NULL);
/* // Search each element in the path...
* Search each element in the path...
*/
node = top; node = top;
while (*path) while (*path)
{ {
/* // Handle wildcards...
* Handle wildcards...
*/
if (!strncmp(path, "*/", 2)) if (!strncmp(path, "*/", 2))
{ {
path += 2; path += 2;
descend = MXML_DESCEND; descend = MXML_DESCEND;
} }
else else
{
descend = MXML_DESCEND_FIRST; descend = MXML_DESCEND_FIRST;
}
/* // Get the next element in the path...
* Get the next element in the path...
*/
if ((pathsep = strchr(path, '/')) == NULL) if ((pathsep = strchr(path, '/')) == NULL)
pathsep = path + strlen(path); pathsep = path + strlen(path);
@ -171,87 +128,91 @@ mxmlFindPath(mxml_node_t *top, /* I - Top node */
else else
path = pathsep; path = pathsep;
/* // Search for the element...
* Search for the element... if ((node = mxmlFindElement(node, node, element, NULL, NULL, descend)) == NULL)
*/
if ((node = mxmlFindElement(node, node, element, NULL, NULL,
descend)) == NULL)
return (NULL); return (NULL);
} }
/* // If we get this far, return the node or its first child...
* If we get this far, return the node or its first child... if (node->child && node->child->type != MXML_TYPE_ELEMENT)
*/
if (node->child && node->child->type != MXML_ELEMENT)
return (node->child); return (node->child);
else else
return (node); return (node);
} }
/* //
* 'mxmlWalkNext()' - Walk to the next logical node in the tree. // 'mxmlWalkNext()' - Walk to the next logical node in the tree.
* //
* The descend argument controls whether the first child is considered // The descend argument controls whether the first child is considered
* to be the next node. The top node argument constrains the walk to // to be the next node. The top node argument constrains the walk to
* the node's children. // the node's children.
*/ //
mxml_node_t * /* O - Next node or @code NULL@ */ mxml_node_t * // O - Next node or `NULL`
mxmlWalkNext(mxml_node_t *node, /* I - Current node */ mxmlWalkNext(mxml_node_t *node, // I - Current node
mxml_node_t *top, /* I - Top node */ mxml_node_t *top, // I - Top node
int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ int descend) // I - Descend into tree - `MXML_DESCEND`, `MXML_NO_DESCEND`, or `MXML_DESCEND_FIRST`
{ {
if (!node) if (!node)
{
return (NULL); return (NULL);
}
else if (node->child && descend) else if (node->child && descend)
{
return (node->child); return (node->child);
}
else if (node == top) else if (node == top)
{
return (NULL); return (NULL);
}
else if (node->next) else if (node->next)
{
return (node->next); return (node->next);
}
else if (node->parent && node->parent != top) else if (node->parent && node->parent != top)
{ {
node = node->parent; node = node->parent;
while (!node->next) while (!node->next)
{
if (node->parent == top || !node->parent) if (node->parent == top || !node->parent)
return (NULL); return (NULL);
else else
node = node->parent; node = node->parent;
}
return (node->next); return (node->next);
} }
else else
{
return (NULL); return (NULL);
}
} }
/* //
* 'mxmlWalkPrev()' - Walk to the previous logical node in the tree. // 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
* //
* The descend argument controls whether the previous node's last child // The descend argument controls whether the previous node's last child
* is considered to be the previous node. The top node argument constrains // is considered to be the previous node. The top node argument constrains
* the walk to the node's children. // the walk to the node's children.
*/ //
mxml_node_t * /* O - Previous node or @code NULL@ */ mxml_node_t * // O - Previous node or `NULL`
mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ mxmlWalkPrev(mxml_node_t *node, // I - Current node
mxml_node_t *top, /* I - Top node */ mxml_node_t *top, // I - Top node
int descend) /* I - Descend into tree - @code MXML_DESCEND@, @code MXML_NO_DESCEND@, or @code MXML_DESCEND_FIRST@ */ int descend) // I - Descend into tree - `MXML_DESCEND`, `MXML_NO_DESCEND`, or `MXML_DESCEND_FIRST`
{ {
if (!node || node == top) if (!node || node == top)
{
return (NULL); return (NULL);
}
else if (node->prev) else if (node->prev)
{ {
if (node->prev->last_child && descend) if (node->prev->last_child && descend)
{ {
/* // Find the last child under the previous node...
* Find the last child under the previous node...
*/
node = node->prev->last_child; node = node->prev->last_child;
while (node->last_child) while (node->last_child)
@ -260,10 +221,16 @@ mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
return (node); return (node);
} }
else else
{
return (node->prev); return (node->prev);
}
} }
else if (node->parent != top) else if (node->parent != top)
{
return (node->parent); return (node->parent);
}
else else
{
return (NULL); return (NULL);
}
} }

@ -1,49 +1,36 @@
/* //
* Node set functions for Mini-XML, a small XML file parsing library. // Node set functions for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2021 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
/* //
* 'mxmlSetCDATA()' - Set the element name of a CDATA node. // 'mxmlSetCDATA()' - Set the element name of a CDATA node.
* //
* The node is not changed if it (or its first child) is not a CDATA element node. // The node is not changed if it (or its first child) is not a CDATA element node.
* //
* @since Mini-XML 2.3@
*/
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */ mxmlSetCDATA(mxml_node_t *node, // I - Node to set
const char *data) /* I - New data string */ const char *data) // I - New data string
{ {
char *s; /* New element name */ size_t datalen; // Length of data string
char *s; // New element name
/*
* Range check input...
*/
if (node && node->type == MXML_ELEMENT && // Range check input...
strncmp(node->value.element.name, "![CDATA[", 8) && if (node && node->type == MXML_TYPE_ELEMENT && strncmp(node->value.element.name, "![CDATA[", 8) && node->child && node->child->type == MXML_TYPE_ELEMENT && !strncmp(node->child->value.element.name, "![CDATA[", 8))
node->child && node->child->type == MXML_ELEMENT &&
!strncmp(node->child->value.element.name, "![CDATA[", 8))
node = node->child; node = node->child;
if (!node || node->type != MXML_ELEMENT || if (!node || node->type != MXML_TYPE_ELEMENT || strncmp(node->value.element.name, "![CDATA[", 8))
strncmp(node->value.element.name, "![CDATA[", 8))
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -56,18 +43,14 @@ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
if (data == (node->value.element.name + 8)) if (data == (node->value.element.name + 8))
{ {
/* // Don't change the value...
* Don't change the value...
*/
return (0); return (0);
} }
/* // Allocate the new value, free any old element value, and set the new value...
* Allocate the new value, free any old element value, and set the new value... datalen = strlen(data);
*/
if ((s = _mxml_strdupf("![CDATA[%s", data)) == NULL) if ((s = malloc(datalen + 9)) == NULL)
{ {
mxml_error("Unable to allocate memory for CDATA."); mxml_error("Unable to allocate memory for CDATA.");
return (-1); return (-1);
@ -75,34 +58,29 @@ mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
free(node->value.element.name); free(node->value.element.name);
node->value.element.name = s; node->value.element.name = s;
snprintf(node->value.element.name, datalen + 9, "![CDATA[%s", data);
return (0); return (0);
} }
/* //
* 'mxmlSetCustom()' - Set the data and destructor of a custom data node. // 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
* //
* The node is not changed if it (or its first child) is not a custom node. // The node is not changed if it (or its first child) is not a custom node.
* //
* @since Mini-XML 2.1@
*/
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetCustom( mxmlSetCustom(
mxml_node_t *node, /* I - Node to set */ mxml_node_t *node, // I - Node to set
void *data, /* I - New data pointer */ void *data, // I - New data pointer
mxml_custom_destroy_cb_t destroy) /* I - New destructor function */ mxml_custom_destroy_cb_t destroy) // I - New destructor function
{ {
/* // Range check input...
* Range check input... if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_CUSTOM)
*/
if (node && node->type == MXML_ELEMENT &&
node->child && node->child->type == MXML_CUSTOM)
node = node->child; node = node->child;
if (!node || node->type != MXML_CUSTOM) if (!node || node->type != MXML_TYPE_CUSTOM)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -114,10 +92,7 @@ mxmlSetCustom(
return (0); return (0);
} }
/* // Free any old element value and set the new value...
* Free any old element value and set the new value...
*/
if (node->value.custom.data && node->value.custom.destroy) if (node->value.custom.data && node->value.custom.destroy)
(*(node->value.custom.destroy))(node->value.custom.data); (*(node->value.custom.destroy))(node->value.custom.data);
@ -128,24 +103,21 @@ mxmlSetCustom(
} }
/* //
* 'mxmlSetElement()' - Set the name of an element node. // 'mxmlSetElement()' - Set the name of an element node.
* //
* The node is not changed if it is not an element node. // The node is not changed if it is not an element node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetElement(mxml_node_t *node, /* I - Node to set */ mxmlSetElement(mxml_node_t *node, // I - Node to set
const char *name) /* I - New name string */ const char *name) // I - New name string
{ {
char *s; /* New name string */ char *s; // New name string
/* // Range check input...
* Range check input... if (!node || node->type != MXML_TYPE_ELEMENT)
*/
if (!node || node->type != MXML_ELEMENT)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -159,10 +131,7 @@ mxmlSetElement(mxml_node_t *node, /* I - Node to set */
if (name == node->value.element.name) if (name == node->value.element.name)
return (0); return (0);
/* // Free any old element value and set the new value...
* Free any old element value and set the new value...
*/
if ((s = strdup(name)) == NULL) if ((s = strdup(name)) == NULL)
{ {
mxml_error("Unable to allocate memory for element name."); mxml_error("Unable to allocate memory for element name.");
@ -176,62 +145,51 @@ mxmlSetElement(mxml_node_t *node, /* I - Node to set */
} }
/* //
* 'mxmlSetInteger()' - Set the value of an integer node. // 'mxmlSetInteger()' - Set the value of an integer node.
* //
* The node is not changed if it (or its first child) is not an integer node. // The node is not changed if it (or its first child) is not an integer node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetInteger(mxml_node_t *node, /* I - Node to set */ mxmlSetInteger(mxml_node_t *node, // I - Node to set
int integer) /* I - Integer value */ int integer) // I - Integer value
{ {
/* // Range check input...
* Range check input... if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_INTEGER)
*/
if (node && node->type == MXML_ELEMENT &&
node->child && node->child->type == MXML_INTEGER)
node = node->child; node = node->child;
if (!node || node->type != MXML_INTEGER) if (!node || node->type != MXML_TYPE_INTEGER)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
} }
/* // Set the new value and return...
* Set the new value and return...
*/
node->value.integer = integer; node->value.integer = integer;
return (0); return (0);
} }
/* //
* 'mxmlSetOpaque()' - Set the value of an opaque node. // 'mxmlSetOpaque()' - Set the value of an opaque node.
* //
* The node is not changed if it (or its first child) is not an opaque node. // The node is not changed if it (or its first child) is not an opaque node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */ mxmlSetOpaque(mxml_node_t *node, // I - Node to set
const char *opaque) /* I - Opaque string */ const char *opaque) // I - Opaque string
{ {
char *s; /* New opaque string */ char *s; // New opaque string
/* // Range check input...
* Range check input... if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_OPAQUE)
*/
if (node && node->type == MXML_ELEMENT &&
node->child && node->child->type == MXML_OPAQUE)
node = node->child; node = node->child;
if (!node || node->type != MXML_OPAQUE) if (!node || node->type != MXML_TYPE_OPAQUE)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -245,10 +203,7 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
if (node->value.opaque == opaque) if (node->value.opaque == opaque)
return (0); return (0);
/* // Free any old opaque value and set the new value...
* Free any old opaque value and set the new value...
*/
if ((s = strdup(opaque)) == NULL) if ((s = strdup(opaque)) == NULL)
{ {
mxml_error("Unable to allocate memory for opaque string."); mxml_error("Unable to allocate memory for opaque string.");
@ -262,32 +217,27 @@ mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
} }
/* //
* 'mxmlSetOpaquef()' - Set the value of an opaque string node to a formatted string. // 'mxmlSetOpaquef()' - Set the value of an opaque string node to a formatted string.
* //
* The node is not changed if it (or its first child) is not an opaque node. // The node is not changed if it (or its first child) is not an opaque node.
* //
* @since Mini-XML 2.11@
*/
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */ mxmlSetOpaquef(mxml_node_t *node, // I - Node to set
const char *format, /* I - Printf-style format string */ const char *format, // I - Printf-style format string
...) /* I - Additional arguments as needed */ ...) // I - Additional arguments as needed
{ {
va_list ap; /* Pointer to arguments */ va_list ap; // Pointer to arguments
char *s; /* Temporary string */ char buffer[16384]; // Format buffer
char *s; // Temporary string
/*
* Range check input...
*/
if (node && node->type == MXML_ELEMENT && // Range check input...
node->child && node->child->type == MXML_OPAQUE) if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_OPAQUE)
node = node->child; node = node->child;
if (!node || node->type != MXML_OPAQUE) if (!node || node->type != MXML_TYPE_OPAQUE)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -298,15 +248,12 @@ mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */
return (-1); return (-1);
} }
/* // Format the new string, free any old string value, and set the new value...
* Format the new string, free any old string value, and set the new value...
*/
va_start(ap, format); va_start(ap, format);
s = _mxml_vstrdupf(format, ap); vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap); va_end(ap);
if (!s) if ((s = strdup(buffer)) == NULL)
{ {
mxml_error("Unable to allocate memory for opaque string."); mxml_error("Unable to allocate memory for opaque string.");
return (-1); return (-1);
@ -319,63 +266,55 @@ mxmlSetOpaquef(mxml_node_t *node, /* I - Node to set */
} }
/* //
* 'mxmlSetReal()' - Set the value of a real number node. // 'mxmlSetReal()' - Set the value of a real number node.
* //
* The node is not changed if it (or its first child) is not a real number node. // The node is not changed if it (or its first child) is not a real number node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetReal(mxml_node_t *node, /* I - Node to set */ mxmlSetReal(mxml_node_t *node, // I - Node to set
double real) /* I - Real number value */ double real) // I - Real number value
{ {
/* /*
* Range check input... * Range check input...
*/ */
if (node && node->type == MXML_ELEMENT && if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_REAL)
node->child && node->child->type == MXML_REAL)
node = node->child; node = node->child;
if (!node || node->type != MXML_REAL) if (!node || node->type != MXML_TYPE_REAL)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
} }
/* // Set the new value and return...
* Set the new value and return...
*/
node->value.real = real; node->value.real = real;
return (0); return (0);
} }
/* //
* 'mxmlSetText()' - Set the value of a text node. // 'mxmlSetText()' - Set the value of a text node.
* //
* The node is not changed if it (or its first child) is not a text node. // The node is not changed if it (or its first child) is not a text node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetText(mxml_node_t *node, /* I - Node to set */ mxmlSetText(mxml_node_t *node, // I - Node to set
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ int whitespace, // I - 1 = leading whitespace, 0 = no whitespace
const char *string) /* I - String */ const char *string) // I - String
{ {
char *s; /* New string */ char *s; // New string
/*
* Range check input...
*/
if (node && node->type == MXML_ELEMENT && // Range check input...
node->child && node->child->type == MXML_TEXT) if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_TEXT)
node = node->child; node = node->child;
if (!node || node->type != MXML_TEXT) if (!node || node->type != MXML_TYPE_TEXT)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -392,10 +331,7 @@ mxmlSetText(mxml_node_t *node, /* I - Node to set */
return (0); return (0);
} }
/* // Free any old string value and set the new value...
* Free any old string value and set the new value...
*/
if ((s = strdup(string)) == NULL) if ((s = strdup(string)) == NULL)
{ {
mxml_error("Unable to allocate memory for text string."); mxml_error("Unable to allocate memory for text string.");
@ -411,31 +347,28 @@ mxmlSetText(mxml_node_t *node, /* I - Node to set */
} }
/* //
* 'mxmlSetTextf()' - Set the value of a text node to a formatted string. // 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
* //
* The node is not changed if it (or its first child) is not a text node. // The node is not changed if it (or its first child) is not a text node.
*/ //
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetTextf(mxml_node_t *node, /* I - Node to set */ mxmlSetTextf(mxml_node_t *node, // I - Node to set
int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ int whitespace, // I - 1 = leading whitespace, 0 = no whitespace
const char *format, /* I - Printf-style format string */ const char *format, // I - Printf-style format string
...) /* I - Additional arguments as needed */ ...) // I - Additional arguments as needed
{ {
va_list ap; /* Pointer to arguments */ va_list ap; // Pointer to arguments
char *s; /* Temporary string */ char buffer[16384]; // Format buffer
char *s; // Temporary string
/*
* Range check input...
*/
if (node && node->type == MXML_ELEMENT && // Range check input...
node->child && node->child->type == MXML_TEXT) if (node && node->type == MXML_TYPE_ELEMENT && node->child && node->child->type == MXML_TYPE_TEXT)
node = node->child; node = node->child;
if (!node || node->type != MXML_TEXT) if (!node || node->type != MXML_TYPE_TEXT)
{ {
mxml_error("Wrong node type."); mxml_error("Wrong node type.");
return (-1); return (-1);
@ -451,10 +384,10 @@ mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
*/ */
va_start(ap, format); va_start(ap, format);
s = _mxml_vstrdupf(format, ap); vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap); va_end(ap);
if (!s) if ((s = strdup(buffer)) == NULL)
{ {
mxml_error("Unable to allocate memory for text string."); mxml_error("Unable to allocate memory for text string.");
return (-1); return (-1);
@ -469,27 +402,19 @@ mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
} }
/* //
* 'mxmlSetUserData()' - Set the user data pointer for a node. // 'mxmlSetUserData()' - Set the user data pointer for a node.
* //
* @since Mini-XML 2.7@
*/
int /* O - 0 on success, -1 on failure */ int // O - 0 on success, -1 on failure
mxmlSetUserData(mxml_node_t *node, /* I - Node to set */ mxmlSetUserData(mxml_node_t *node, // I - Node to set
void *data) /* I - User data pointer */ void *data) // I - User data pointer
{ {
/* // Range check input...
* Range check input...
*/
if (!node) if (!node)
return (-1); return (-1);
/* // Set the user data pointer and return...
* Set the user data pointer and return...
*/
node->user_data = data; node->user_data = data;
return (0); return (0);
} }

@ -1,561 +0,0 @@
/*
* String functions for Mini-XML, a small XML file parsing library.
*
* https://www.msweet.org/mxml
*
* Copyright © 2003-2019 by Michael R Sweet.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
* information.
*/
/*
* Include necessary headers...
*/
#include "config.h"
/*
* The va_copy macro is part of C99, but many compilers don't implement it.
* Provide a "direct assignment" implmentation when va_copy isn't defined...
*/
#ifndef va_copy
# ifdef __va_copy
# define va_copy(dst,src) __va_copy(dst,src)
# else
# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
# endif /* __va_copy */
#endif /* va_copy */
#ifndef HAVE_SNPRINTF
/*
* '_mxml_snprintf()' - Format a string.
*/
int /* O - Number of bytes formatted */
_mxml_snprintf(char *buffer, /* I - Output buffer */
size_t bufsize, /* I - Size of output buffer */
const char *format, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Argument list */
int bytes; /* Number of bytes formatted */
va_start(ap, format);
bytes = vsnprintf(buffer, bufsize, format, ap);
va_end(ap);
return (bytes);
}
#endif /* !HAVE_SNPRINTF */
/*
* '_mxml_strdup()' - Duplicate a string.
*/
#ifndef HAVE_STRDUP
char * /* O - New string pointer */
_mxml_strdup(const char *s) /* I - String to duplicate */
{
char *t; /* New string pointer */
if (s == NULL)
return (NULL);
if ((t = malloc(strlen(s) + 1)) == NULL)
return (NULL);
return (strcpy(t, s));
}
#endif /* !HAVE_STRDUP */
/*
* '_mxml_strdupf()' - Format and duplicate a string.
*/
char * /* O - New string pointer */
_mxml_strdupf(const char *format, /* I - Printf-style format string */
...) /* I - Additional arguments as needed */
{
va_list ap; /* Pointer to additional arguments */
char *s; /* Pointer to formatted string */
/*
* Get a pointer to the additional arguments, format the string,
* and return it...
*/
va_start(ap, format);
#ifdef HAVE_VASPRINTF
if (vasprintf(&s, format, ap) < 0)
s = NULL;
#else
s = _mxml_vstrdupf(format, ap);
#endif /* HAVE_VASPRINTF */
va_end(ap);
return (s);
}
#ifndef HAVE_STRLCAT
/*
* '_mxml_strlcat()' - Safely concatenate a 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 destination buffer */
{
size_t srclen; /* Length of source string */
size_t dstlen; /* Length of destination string */
/*
* Figure out how much room is left...
*/
dstlen = strlen(dst);
if (dstsize <= (dstlen + 1))
return (dstlen); /* No room, return immediately... */
dstsize -= dstlen + 1;
/*
* Figure out how much room is needed...
*/
srclen = strlen(src);
/*
* Copy the appropriate amount...
*/
if (srclen > dstsize)
srclen = dstsize;
memmove(dst + dstlen, src, srclen);
dst[dstlen + srclen] = '\0';
return (dstlen + srclen);
}
#endif /* !HAVE_STRLCAT */
#ifndef HAVE_STRLCPY
/*
* '_mxml_strlcpy()' - Safely copy a string.
*/
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 destination buffer */
{
size_t srclen; /* Length of source string */
/*
* Figure out how much room is needed...
*/
dstsize --;
srclen = strlen(src);
/*
* Copy the appropriate amount...
*/
if (srclen > dstsize)
srclen = dstsize;
memmove(dst, src, srclen);
dst[srclen] = '\0';
return (srclen);
}
#endif /* !HAVE_STRLCPY */
#ifndef HAVE_VSNPRINTF
/*
* '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
*/
int /* O - Number of bytes formatted */
_mxml_vsnprintf(char *buffer, /* O - Output buffer */
size_t bufsize, /* O - Size of output buffer */
const char *format, /* I - Printf-style format string */
va_list ap) /* I - Pointer to additional arguments */
{
char *bufptr, /* Pointer to position in buffer */
*bufend, /* Pointer to end of buffer */
sign, /* Sign of format width */
size, /* Size character (h, l, L) */
type; /* Format type character */
int width, /* Width of field */
prec; /* Number of characters of precision */
char tformat[100], /* Temporary format string for sprintf() */
*tptr, /* Pointer into temporary format */
temp[1024]; /* Buffer for formatted numbers */
char *s; /* Pointer to string */
int slen; /* Length of string */
int bytes; /* Total number of bytes needed */
/*
* Loop through the format string, formatting as needed...
*/
bufptr = buffer;
bufend = buffer + bufsize - 1;
bytes = 0;
while (*format)
{
if (*format == '%')
{
tptr = tformat;
*tptr++ = *format++;
if (*format == '%')
{
if (bufptr && bufptr < bufend)
*bufptr++ = *format;
bytes ++;
format ++;
continue;
}
else if (strchr(" -+#\'", *format))
{
*tptr++ = *format;
sign = *format++;
}
else
sign = 0;
if (*format == '*')
{
/*
* Get width from argument...
*/
format ++;
width = va_arg(ap, int);
snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
tptr += strlen(tptr);
}
else
{
width = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
width = width * 10 + *format++ - '0';
}
}
if (*format == '.')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
format ++;
if (*format == '*')
{
/*
* Get precision from argument...
*/
format ++;
prec = va_arg(ap, int);
snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
tptr += strlen(tptr);
}
else
{
prec = 0;
while (isdigit(*format & 255))
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
prec = prec * 10 + *format++ - '0';
}
}
}
else
prec = -1;
if (*format == 'l' && format[1] == 'l')
{
size = 'L';
if (tptr < (tformat + sizeof(tformat) - 2))
{
*tptr++ = 'l';
*tptr++ = 'l';
}
format += 2;
}
else if (*format == 'h' || *format == 'l' || *format == 'L')
{
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
size = *format++;
}
if (!*format)
break;
if (tptr < (tformat + sizeof(tformat) - 1))
*tptr++ = *format;
type = *format++;
*tptr = '\0';
switch (type)
{
case 'E' : /* Floating point formats */
case 'G' :
case 'e' :
case 'f' :
case 'g' :
if ((width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, double));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'B' : /* Integer formats */
case 'X' :
case 'b' :
case 'd' :
case 'i' :
case 'o' :
case 'u' :
case 'x' :
if ((width + 2) > sizeof(temp))
break;
#ifdef HAVE_LONG_LONG_INT
if (size == 'L')
sprintf(temp, tformat, va_arg(ap, long long));
else
#endif /* HAVE_LONG_LONG_INT */
sprintf(temp, tformat, va_arg(ap, int));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'p' : /* Pointer value */
if ((width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, void *));
bytes += strlen(temp);
if (bufptr)
{
if ((bufptr + strlen(temp)) > bufend)
{
strncpy(bufptr, temp, (size_t)(bufend - bufptr));
bufptr = bufend;
}
else
{
strcpy(bufptr, temp);
bufptr += strlen(temp);
}
}
break;
case 'c' : /* Character or character array */
bytes += width;
if (bufptr)
{
if (width <= 1)
*bufptr++ = va_arg(ap, int);
else
{
if ((bufptr + width) > bufend)
width = bufend - bufptr;
memcpy(bufptr, va_arg(ap, char *), (size_t)width);
bufptr += width;
}
}
break;
case 's' : /* String */
if ((s = va_arg(ap, char *)) == NULL)
s = "(null)";
slen = strlen(s);
if (slen > width && prec != width)
width = slen;
bytes += width;
if (bufptr)
{
if ((bufptr + width) > bufend)
width = bufend - bufptr;
if (slen > width)
slen = width;
if (sign == '-')
{
strncpy(bufptr, s, (size_t)slen);
memset(bufptr + slen, ' ', (size_t)(width - slen));
}
else
{
memset(bufptr, ' ', (size_t)(width - slen));
strncpy(bufptr + width - slen, s, (size_t)slen);
}
bufptr += width;
}
break;
case 'n' : /* Output number of chars so far */
*(va_arg(ap, int *)) = bytes;
break;
}
}
else
{
bytes ++;
if (bufptr && bufptr < bufend)
*bufptr++ = *format;
format ++;
}
}
/*
* Nul-terminate the string and return the number of characters needed.
*/
*bufptr = '\0';
return (bytes);
}
#endif /* !HAVE_VSNPRINTF */
/*
* '_mxml_vstrdupf()' - Format and duplicate a string.
*/
char * /* O - New string pointer */
_mxml_vstrdupf(const char *format, /* I - Printf-style format string */
va_list ap) /* I - Pointer to additional arguments */
{
#ifdef HAVE_VASPRINTF
char *s; /* String */
if (vasprintf(&s, format, ap) < 0)
s = NULL;
return (s);
#else
int bytes; /* Number of bytes required */
char *buffer; /* String buffer */
# ifndef _WIN32
char temp[256]; /* Small buffer for first vsnprintf */
# endif /* !_WIN32 */
/*
* First format with a tiny buffer; this will tell us how many bytes are
* needed...
*/
# ifdef _WIN32
bytes = _vscprintf(format, ap);
# else
va_list apcopy; /* Copy of argument list */
va_copy(apcopy, ap);
if ((bytes = vsnprintf(temp, sizeof(temp), format, apcopy)) < sizeof(temp))
{
/*
* Hey, the formatted string fits in the tiny buffer, so just dup that...
*/
return (strdup(temp));
}
# endif /* _WIN32 */
/*
* Allocate memory for the whole thing and reformat to the new buffer...
*/
if ((buffer = calloc(1, bytes + 1)) != NULL)
vsnprintf(buffer, bytes + 1, format, ap);
/*
* Return the new string...
*/
return (buffer);
#endif /* HAVE_VASPRINTF */
}

282
mxml.h

@ -1,158 +1,140 @@
/* //
* Header file for Mini-XML, a small XML file parsing library. // Header file for Mini-XML, a small XML file parsing library.
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2021 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/* #ifndef MXML_H
* Prevent multiple inclusion... # define MXML_H
*/
#ifndef _mxml_h_
# define _mxml_h_
/*
* Include necessary headers...
*/
# include <stdio.h> # include <stdio.h>
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
# include <ctype.h> # include <ctype.h>
# include <errno.h> # include <errno.h>
# ifdef __cplusplus
extern "C" {
# endif // __cplusplus
/* //
* Constants... // Constants...
*/ //
# define MXML_MAJOR_VERSION 3 /* Major version number */ # define MXML_MAJOR_VERSION 4 // Major version number
# define MXML_MINOR_VERSION 2 /* Minor version number */ # define MXML_MINOR_VERSION 0 // Minor version number
# define MXML_TAB 8 /* Tabs every N columns */ # ifdef __GNUC__
# define MXML_FORMAT(a,b) __attribute__ ((__format__ (__printf__, a, b)))
# else
# define MXML_FORMAT(a,b)
# endif // __GNUC__
# define MXML_NO_CALLBACK 0 /* Don't use a type callback */ # define MXML_TAB 8 // Tabs every N columns
# define MXML_NO_CALLBACK 0 // Don't use a type callback
# define MXML_INTEGER_CALLBACK mxml_integer_cb # define MXML_INTEGER_CALLBACK mxml_integer_cb
/* Treat all data as integers */ // Treat all data as integers
# define MXML_OPAQUE_CALLBACK mxml_opaque_cb # define MXML_OPAQUE_CALLBACK mxml_opaque_cb
/* Treat all data as opaque */ // Treat all data as opaque
# define MXML_REAL_CALLBACK mxml_real_cb # define MXML_REAL_CALLBACK mxml_real_cb
/* Treat all data as real numbers */ // Treat all data as real numbers
# define MXML_TEXT_CALLBACK 0 /* Treat all data as text */ # define MXML_TEXT_CALLBACK 0 // Treat all data as text
# define MXML_IGNORE_CALLBACK mxml_ignore_cb # define MXML_IGNORE_CALLBACK mxml_ignore_cb
/* Ignore all non-element content */ // Ignore all non-element content
# define MXML_NO_PARENT 0 /* No parent for the node */ # define MXML_NO_PARENT 0 // No parent for the node
# define MXML_DESCEND 1 /* Descend when finding/walking */ # define MXML_DESCEND 1 // Descend when finding/walking
# define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */ # define MXML_NO_DESCEND 0 // Don't descend when finding/walking
# define MXML_DESCEND_FIRST -1 /* Descend for first find */ # define MXML_DESCEND_FIRST -1 // Descend for first find
# define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */ # define MXML_WS_BEFORE_OPEN 0 // Callback for before open tag
# define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */ # define MXML_WS_AFTER_OPEN 1 // Callback for after open tag
# define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */ # define MXML_WS_BEFORE_CLOSE 2 // Callback for before close tag
# define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */ # define MXML_WS_AFTER_CLOSE 3 // Callback for after close tag
# define MXML_ADD_BEFORE 0 /* Add node before specified node */ # define MXML_ADD_BEFORE 0 // Add node before specified node
# define MXML_ADD_AFTER 1 /* Add node after specified node */ # define MXML_ADD_AFTER 1 // Add node after specified node
# define MXML_ADD_TO_PARENT NULL /* Add node relative to parent */ # define MXML_ADD_TO_PARENT NULL // Add node relative to parent
/* //
* Data types... // Data types...
*/ //
typedef enum mxml_sax_event_e /**** SAX event type. ****/ typedef enum mxml_sax_event_e // SAX event type.
{ {
MXML_SAX_CDATA, /* CDATA node */ MXML_SAX_EVENT_CDATA, // CDATA node
MXML_SAX_COMMENT, /* Comment node */ MXML_SAX_EVENT_COMMENT, // Comment node
MXML_SAX_DATA, /* Data node */ MXML_SAX_EVENT_DATA, // Data node
MXML_SAX_DIRECTIVE, /* Processing directive node */ MXML_SAX_EVENT_DIRECTIVE, // Processing directive node
MXML_SAX_ELEMENT_CLOSE, /* Element closed */ MXML_SAX_EVENT_ELEMENT_CLOSE, // Element closed
MXML_SAX_ELEMENT_OPEN /* Element opened */ MXML_SAX_EVENT_ELEMENT_OPEN // Element opened
} mxml_sax_event_t; } mxml_sax_event_t;
typedef enum mxml_type_e /**** The XML node type. ****/ typedef enum mxml_type_e // The XML node type.
{ {
MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */ MXML_TYPE_IGNORE = -1, // Ignore/throw away node
MXML_ELEMENT, /* XML element with attributes */ MXML_TYPE_ELEMENT, // XML element with attributes
MXML_INTEGER, /* Integer value */ MXML_TYPE_INTEGER, // Integer value
MXML_OPAQUE, /* Opaque string */ MXML_TYPE_OPAQUE, // Opaque string
MXML_REAL, /* Real value */ MXML_TYPE_REAL, // Real value
MXML_TEXT, /* Text fragment */ MXML_TYPE_TEXT, // Text fragment
MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */ MXML_TYPE_CUSTOM // Custom data
} mxml_type_t; } mxml_type_t;
typedef void (*mxml_custom_destroy_cb_t)(void *); typedef void (*mxml_custom_destroy_cb_t)(void *);
/**** Custom data destructor ****/ // Custom data destructor
typedef void (*mxml_error_cb_t)(const char *); typedef void (*mxml_error_cb_t)(const char *);
/**** Error callback function ****/ // Error callback function
typedef struct _mxml_node_s mxml_node_t; /**** An XML node. ****/ typedef struct _mxml_node_s mxml_node_t;// An XML node.
typedef struct _mxml_index_s mxml_index_t; typedef struct _mxml_index_s mxml_index_t;
/**** An XML node index. ****/ // An XML node index.
typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *); typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
/**** Custom data load callback function ****/ // Custom data load callback function
typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *); typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
/**** Custom data save callback function ****/ // Custom data save callback function
typedef int (*mxml_entity_cb_t)(const char *); typedef int (*mxml_entity_cb_t)(const char *);
/**** Entity callback function */ // Entity callback function
typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *); typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
/**** Load callback function ****/ // Load callback function
typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int); typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
/**** Save callback function ****/ // Save callback function
typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *); typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
/**** SAX callback function ****/ // SAX callback function
/* //
* C++ support... // Prototypes...
*/ //
# ifdef __cplusplus extern void mxmlAdd(mxml_node_t *parent, int where, mxml_node_t *child, mxml_node_t *node);
extern "C" {
# endif /* __cplusplus */
/*
* Prototypes...
*/
extern void mxmlAdd(mxml_node_t *parent, int where,
mxml_node_t *child, mxml_node_t *node);
extern void mxmlDelete(mxml_node_t *node); extern void mxmlDelete(mxml_node_t *node);
extern void mxmlElementDeleteAttr(mxml_node_t *node, extern void mxmlElementDeleteAttr(mxml_node_t *node, const char *name);
const char *name);
extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name); extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name);
extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name); extern const char *mxmlElementGetAttrByIndex(mxml_node_t *node, int idx, const char **name);
extern int mxmlElementGetAttrCount(mxml_node_t *node); extern int mxmlElementGetAttrCount(mxml_node_t *node);
extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, extern void mxmlElementSetAttr(mxml_node_t *node, const char *name, const char *value);
const char *value); extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name, const char *format, ...) MXML_FORMAT(3,4);
extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name,
const char *format, ...)
# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 3, 4)))
# endif /* __GNUC__ */
;
extern int mxmlEntityAddCallback(mxml_entity_cb_t cb); extern int mxmlEntityAddCallback(mxml_entity_cb_t cb);
extern const char *mxmlEntityGetName(int val); extern const char *mxmlEntityGetName(int val);
extern int mxmlEntityGetValue(const char *name); extern int mxmlEntityGetValue(const char *name);
extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb); extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top, const char *element, const char *attr, const char *value, int descend);
const char *element, const char *attr,
const char *value, int descend);
extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path); extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path);
extern const char *mxmlGetCDATA(mxml_node_t *node); extern const char *mxmlGetCDATA(mxml_node_t *node);
extern const void *mxmlGetCustom(mxml_node_t *node); extern const void *mxmlGetCustom(mxml_node_t *node);
@ -171,109 +153,61 @@ extern mxml_type_t mxmlGetType(mxml_node_t *node);
extern void *mxmlGetUserData(mxml_node_t *node); extern void *mxmlGetUserData(mxml_node_t *node);
extern void mxmlIndexDelete(mxml_index_t *ind); extern void mxmlIndexDelete(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind); extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind);
extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind, const char *element, const char *value);
const char *element,
const char *value);
extern int mxmlIndexGetCount(mxml_index_t *ind); extern int mxmlIndexGetCount(mxml_index_t *ind);
extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element, const char *attr);
const char *attr);
extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind); extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t cb); extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t cb);
mxml_type_t (*cb)(mxml_node_t *)); extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t cb);
extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp,
mxml_type_t (*cb)(mxml_node_t *));
extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s,
mxml_type_t (*cb)(mxml_node_t *));
extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string); extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data, mxml_custom_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy);
extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name); extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name);
extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer); extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer);
extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque); extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
extern mxml_node_t *mxmlNewOpaquef(mxml_node_t *parent, const char *format, ...) extern mxml_node_t *mxmlNewOpaquef(mxml_node_t *parent, const char *format, ...) MXML_FORMAT(2,3);
# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 2, 3)))
# endif /* __GNUC__ */
;
extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real); extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real);
extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, const char *string); extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, const char *string);
extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace, const char *format, ...) extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace, const char *format, ...) MXML_FORMAT(3,4);
# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 3, 4)))
# endif /* __GNUC__ */
;
extern mxml_node_t *mxmlNewXML(const char *version); extern mxml_node_t *mxmlNewXML(const char *version);
extern int mxmlRelease(mxml_node_t *node); extern int mxmlRelease(mxml_node_t *node);
extern void mxmlRemove(mxml_node_t *node); extern void mxmlRemove(mxml_node_t *node);
extern int mxmlRetain(mxml_node_t *node); extern int mxmlRetain(mxml_node_t *node);
extern char *mxmlSaveAllocString(mxml_node_t *node, extern char *mxmlSaveAllocString(mxml_node_t *node, mxml_save_cb_t cb);
mxml_save_cb_t cb); extern int mxmlSaveFd(mxml_node_t *node, int fd, mxml_save_cb_t cb);
extern int mxmlSaveFd(mxml_node_t *node, int fd, extern int mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t cb);
mxml_save_cb_t cb); extern int mxmlSaveString(mxml_node_t *node, char *buffer, int bufsize, mxml_save_cb_t cb);
extern int mxmlSaveFile(mxml_node_t *node, FILE *fp, extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
mxml_save_cb_t cb); extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
extern int mxmlSaveString(mxml_node_t *node, char *buffer, extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s, mxml_load_cb_t cb, mxml_sax_cb_t sax, void *sax_data);
int bufsize, mxml_save_cb_t cb);
extern 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);
extern 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);
extern 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);
extern int mxmlSetCDATA(mxml_node_t *node, const char *data); extern int mxmlSetCDATA(mxml_node_t *node, const char *data);
extern int mxmlSetCustom(mxml_node_t *node, void *data, extern int mxmlSetCustom(mxml_node_t *node, void *data, mxml_custom_destroy_cb_t destroy);
mxml_custom_destroy_cb_t destroy); extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load, mxml_custom_save_cb_t save);
extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
mxml_custom_save_cb_t save);
extern int mxmlSetElement(mxml_node_t *node, const char *name); extern int mxmlSetElement(mxml_node_t *node, const char *name);
extern void mxmlSetErrorCallback(mxml_error_cb_t cb); extern void mxmlSetErrorCallback(mxml_error_cb_t cb);
extern int mxmlSetInteger(mxml_node_t *node, int integer); extern int mxmlSetInteger(mxml_node_t *node, int integer);
extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque); extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque);
extern int mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) extern int mxmlSetOpaquef(mxml_node_t *node, const char *format, ...) MXML_FORMAT(2,3);
# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 2, 3)))
# endif /* __GNUC__ */
;
extern int mxmlSetReal(mxml_node_t *node, double real); extern int mxmlSetReal(mxml_node_t *node, double real);
extern int mxmlSetText(mxml_node_t *node, int whitespace, extern int mxmlSetText(mxml_node_t *node, int whitespace, const char *string);
const char *string); extern int mxmlSetTextf(mxml_node_t *node, int whitespace, const char *format, ...) MXML_FORMAT(3,4);
extern int mxmlSetTextf(mxml_node_t *node, int whitespace,
const char *format, ...)
# ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 3, 4)))
# endif /* __GNUC__ */
;
extern int mxmlSetUserData(mxml_node_t *node, void *data); extern int mxmlSetUserData(mxml_node_t *node, void *data);
extern void mxmlSetWrapMargin(int column); extern void mxmlSetWrapMargin(int column);
extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top, int descend);
int descend); extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top, int descend);
extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
int descend);
/* //
* Semi-private functions... // Semi-private functions...
*/ //
extern void mxml_error(const char *format, ...) extern void mxml_error(const char *format, ...) MXML_FORMAT(1,2);
# 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_ignore_cb(mxml_node_t *node);
extern mxml_type_t mxml_integer_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); extern mxml_type_t mxml_opaque_cb(mxml_node_t *node);
extern mxml_type_t mxml_real_cb(mxml_node_t *node); extern mxml_type_t mxml_real_cb(mxml_node_t *node);
/*
* C++ support...
*/
# ifdef __cplusplus # ifdef __cplusplus
} }
# endif /* __cplusplus */ # endif // __cplusplus
#endif /* !_mxml_h_ */ #endif // !MXML_H

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

@ -1,90 +1,79 @@
/* //
* Test program for Mini-XML, a small XML file parsing library. // Test program for Mini-XML, a small XML file parsing library.
* //
* Usage: // Usage:
* //
* ./testmxml input.xml [string-output.xml] >stdio-output.xml // ./testmxml input.xml [string-output.xml] >stdio-output.xml
* ./testmxml "<?xml ..." [string-output.xml] >stdio-output.xml // ./testmxml "<?xml ..." [string-output.xml] >stdio-output.xml
* //
* https://www.msweet.org/mxml // https://www.msweet.org/mxml
* //
* Copyright © 2003-2019 by Michael R Sweet. // Copyright © 2003-2024 by Michael R Sweet.
* //
* Licensed under Apache License v2.0. See the file "LICENSE" for more // Licensed under Apache License v2.0. See the file "LICENSE" for more
* information. // information.
*/ //
/*
* Include necessary headers...
*/
#include "config.h"
#include "mxml-private.h" #include "mxml-private.h"
#ifndef _WIN32 #ifndef _WIN32
# include <unistd.h> # include <unistd.h>
#endif /* !_WIN32 */ #endif // !_WIN32
#include <fcntl.h> #include <fcntl.h>
#ifndef O_BINARY #ifndef O_BINARY
# define O_BINARY 0 # define O_BINARY 0
#endif /* !O_BINARY */ #endif // !O_BINARY
/* //
* Globals... // Globals...
*/ //
int event_counts[6]; int event_counts[6];
/* //
* Local functions... // Local functions...
*/ //
void sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *data); void sax_cb(mxml_node_t *node, mxml_sax_event_t event, void *data);
mxml_type_t type_cb(mxml_node_t *node); mxml_type_t type_cb(mxml_node_t *node);
const char *whitespace_cb(mxml_node_t *node, int where); const char *whitespace_cb(mxml_node_t *node, int where);
/* //
* 'main()' - Main entry for test program. // 'main()' - Main entry for test program.
*/ //
int /* O - Exit status */ int // O - Exit status
main(int argc, /* I - Number of command-line args */ main(int argc, // I - Number of command-line args
char *argv[]) /* I - Command-line args */ char *argv[]) // I - Command-line args
{ {
int i; /* Looping var */ int i; // Looping var
FILE *fp; /* File to read */ FILE *fp; // File to read
int fd; /* File descriptor */ int fd; // File descriptor
mxml_node_t *xml, /* <?xml ...?> node */ mxml_node_t *xml, // <?xml ...?> node
*tree, /* Element tree */ *tree, // Element tree
*node; /* Node which should be in test.xml */ *node; // Node which should be in test.xml
mxml_index_t *ind; /* XML index */ mxml_index_t *ind; // XML index
char buffer[16384]; /* Save string */ char buffer[16384]; // Save string
static const char *types[] = /* Strings for node types */ static const char *types[] = // Strings for node types
{ {
"MXML_ELEMENT", "MXML_TYPE_ELEMENT",
"MXML_INTEGER", "MXML_TYPE_INTEGER",
"MXML_OPAQUE", "MXML_TYPE_OPAQUE",
"MXML_REAL", "MXML_TYPE_REAL",
"MXML_TEXT" "MXML_TYPE_TEXT"
}; };
/* // Check arguments...
* Check arguments...
*/
if (argc != 2 && argc != 3) if (argc != 2 && argc != 3)
{ {
fputs("Usage: testmxml filename.xml [string-output.xml]\n", stderr); fputs("Usage: testmxml filename.xml [string-output.xml]\n", stderr);
return (1); return (1);
} }
/* // Test the basic functionality...
* Test the basic functionality...
*/
xml = mxmlNewXML("1.0"); xml = mxmlNewXML("1.0");
tree = mxmlNewElement(xml, "element"); tree = mxmlNewElement(xml, "element");
@ -94,19 +83,16 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (tree->type != MXML_ELEMENT) if (tree->type != MXML_TYPE_ELEMENT)
{ {
fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT.\n", fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_TYPE_ELEMENT.\n", tree->type < MXML_TYPE_ELEMENT || tree->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[tree->type], tree->type);
tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ?
"UNKNOWN" : types[tree->type], tree->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (strcmp(tree->value.element.name, "element")) if (strcmp(tree->value.element.name, "element"))
{ {
fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\".\n", fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\".\n", tree->value.element.name);
tree->value.element.name);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -116,18 +102,12 @@ main(int argc, /* I - Number of command-line args */
mxmlNewReal(tree, 123.4f); mxmlNewReal(tree, 123.4f);
mxmlNewText(tree, 1, "text"); mxmlNewText(tree, 1, "text");
mxmlLoadString(tree, "<group type='string'>string string string</group>", mxmlLoadString(tree, "<group type='string'>string string string</group>", MXML_NO_CALLBACK);
MXML_NO_CALLBACK); mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", MXML_INTEGER_CALLBACK);
mxmlLoadString(tree, "<group type='integer'>1 2 3</group>", mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>", MXML_REAL_CALLBACK);
MXML_INTEGER_CALLBACK); mxmlLoadString(tree, "<group>opaque opaque opaque</group>", MXML_OPAQUE_CALLBACK);
mxmlLoadString(tree, "<group type='real'>1.0 2.0 3.0</group>", mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one></bar></foo>", MXML_OPAQUE_CALLBACK);
MXML_REAL_CALLBACK); mxmlNewCDATA(tree, "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
mxmlLoadString(tree, "<group>opaque opaque opaque</group>",
MXML_OPAQUE_CALLBACK);
mxmlLoadString(tree, "<foo><bar><one><two>value<two>value2</two></two></one>"
"</bar></foo>", MXML_OPAQUE_CALLBACK);
mxmlNewCDATA(tree,
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n");
mxmlNewCDATA(tree, mxmlNewCDATA(tree,
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n" "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"
@ -152,19 +132,16 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_INTEGER) if (node->type != MXML_TYPE_INTEGER)
{ {
fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER.\n", fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_TYPE_INTEGER.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->value.integer != 123) if (node->value.integer != 123)
{ {
fprintf(stderr, "ERROR: First child value is %d, expected 123.\n", fprintf(stderr, "ERROR: First child value is %d, expected 123.\n", node->value.integer);
node->value.integer);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -178,19 +155,16 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_OPAQUE) if (node->type != MXML_TYPE_OPAQUE)
{ {
fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE.\n", fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_TYPE_OPAQUE.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (!node->value.opaque || strcmp(node->value.opaque, "opaque")) if (!node->value.opaque || strcmp(node->value.opaque, "opaque"))
{ {
fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\".\n", fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\".\n", node->value.opaque ? node->value.opaque : "(null)");
node->value.opaque ? node->value.opaque : "(null)");
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -204,19 +178,16 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_REAL) if (node->type != MXML_TYPE_REAL)
{ {
fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL.\n", fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_TYPE_REAL.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (node->value.real != 123.4f) if (node->value.real != 123.4f)
{ {
fprintf(stderr, "ERROR: Third child value is %f, expected 123.4.\n", fprintf(stderr, "ERROR: Third child value is %f, expected 123.4.\n", node->value.real);
node->value.real);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -230,21 +201,16 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_TEXT) if (node->type != MXML_TYPE_TEXT)
{ {
fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT.\n", fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TYPE_TEXT.\n", node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
if (!node->value.text.whitespace || if (!node->value.text.whitespace || !node->value.text.string || strcmp(node->value.text.string, "text"))
!node->value.text.string || strcmp(node->value.text.string, "text"))
{ {
fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\".\n", fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\".\n", node->value.text.whitespace, node->value.text.string ? node->value.text.string : "(null)");
node->value.text.whitespace,
node->value.text.string ? node->value.text.string : "(null)");
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -260,20 +226,15 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_ELEMENT) if (node->type != MXML_TYPE_ELEMENT)
{ {
fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_ELEMENT.\n", fprintf(stderr, "ERROR: Group child #%d has type %s (%d), expected MXML_TYPE_ELEMENT.\n", i + 1, node->type < MXML_TYPE_ELEMENT || node->type > MXML_TYPE_TEXT ? "UNKNOWN" : types[node->type], node->type);
i + 1, node->type < MXML_ELEMENT || node->type > MXML_TEXT ?
"UNKNOWN" : types[node->type], node->type);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
} }
/* // Test mxmlFindPath...
* Test mxmlFindPath...
*/
node = mxmlFindPath(tree, "*/two"); node = mxmlFindPath(tree, "*/two");
if (!node) if (!node)
{ {
@ -281,7 +242,7 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value")) else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
{ {
fputs("ERROR: Bad value for \"*/two\".\n", stderr); fputs("ERROR: Bad value for \"*/two\".\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
@ -295,7 +256,7 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value")) else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
{ {
fputs("ERROR: Bad value for \"foo/*/two\".\n", stderr); fputs("ERROR: Bad value for \"foo/*/two\".\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
@ -309,17 +270,14 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
else if (node->type != MXML_OPAQUE || strcmp(node->value.opaque, "value")) else if (node->type != MXML_TYPE_OPAQUE || strcmp(node->value.opaque, "value"))
{ {
fputs("ERROR: Bad value for \"foo/bar/one/two\".\n", stderr); fputs("ERROR: Bad value for \"foo/bar/one/two\".\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
/* // Test indices...
* Test indices...
*/
ind = mxmlIndexNew(tree, NULL, NULL); ind = mxmlIndexNew(tree, NULL, NULL);
if (!ind) if (!ind)
{ {
@ -330,8 +288,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 13) if (ind->num_nodes != 13)
{ {
fprintf(stderr, "ERROR: Index of all nodes contains %d " fprintf(stderr, "ERROR: Index of all nodes contains %d nodes; expected 13.\n", ind->num_nodes);
"nodes; expected 13.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -358,8 +315,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 4) if (ind->num_nodes != 4)
{ {
fprintf(stderr, "ERROR: Index of groups contains %d " fprintf(stderr, "ERROR: Index of groups contains %d nodes; expected 4.\n", ind->num_nodes);
"nodes; expected 4.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -386,8 +342,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 3) if (ind->num_nodes != 3)
{ {
fprintf(stderr, "ERROR: Index of type attributes contains %d " fprintf(stderr, "ERROR: Index of type attributes contains %d nodes; expected 3.\n", ind->num_nodes);
"nodes; expected 3.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -414,8 +369,7 @@ main(int argc, /* I - Number of command-line args */
if (ind->num_nodes != 3) if (ind->num_nodes != 3)
{ {
fprintf(stderr, "ERROR: Index of elements and attributes contains %d " fprintf(stderr, "ERROR: Index of elements and attributes contains %d nodes; expected 3.\n", ind->num_nodes);
"nodes; expected 3.\n", ind->num_nodes);
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
@ -432,18 +386,16 @@ main(int argc, /* I - Number of command-line args */
mxmlIndexDelete(ind); mxmlIndexDelete(ind);
/* // Check the mxmlDelete() works properly...
* Check the mxmlDelete() works properly...
*/
for (i = 0; i < 12; i ++) for (i = 0; i < 12; i ++)
{ {
if (tree->child) if (tree->child)
{
mxmlDelete(tree->child); mxmlDelete(tree->child);
}
else else
{ {
fprintf(stderr, "ERROR: Child pointer prematurely NULL on child #%d\n", fprintf(stderr, "ERROR: Child pointer prematurely NULL on child #%d\n", i + 1);
i + 1);
mxmlDelete(tree); mxmlDelete(tree);
return (1); return (1);
} }
@ -463,12 +415,11 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(xml); mxmlDelete(xml);
/* // Open the file/string using the default (MXML_NO_CALLBACK) callback...
* Open the file/string using the default (MXML_NO_CALLBACK) callback...
*/
if (argv[1][0] == '<') if (argv[1][0] == '<')
{
xml = mxmlLoadString(NULL, argv[1], MXML_NO_CALLBACK); xml = mxmlLoadString(NULL, argv[1], MXML_NO_CALLBACK);
}
else if ((fp = fopen(argv[1], "rb")) == NULL) else if ((fp = fopen(argv[1], "rb")) == NULL)
{ {
perror(argv[1]); perror(argv[1]);
@ -476,10 +427,7 @@ main(int argc, /* I - Number of command-line args */
} }
else else
{ {
/* // Read the file...
* Read the file...
*/
xml = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK); xml = mxmlLoadFile(NULL, fp, MXML_NO_CALLBACK);
fclose(fp); fclose(fp);
@ -493,13 +441,9 @@ main(int argc, /* I - Number of command-line args */
if (!strcmp(argv[1], "test.xml")) if (!strcmp(argv[1], "test.xml"))
{ {
const char *text; /* Text value */ const char *text; // Text value
/*
* Verify that mxmlFindElement() and indirectly mxmlWalkNext() work
* properly...
*/
// Verify that mxmlFindElement() and indirectly mxmlWalkNext() work properly...
if ((node = mxmlFindPath(xml, "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); fputs("Unable to find group/option/keyword element in XML tree.\n", stderr);
@ -507,7 +451,7 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
if (node->type != MXML_TEXT) if (node->type != MXML_TYPE_TEXT)
{ {
fputs("No child node of group/option/keyword.\n", stderr); fputs("No child node of group/option/keyword.\n", stderr);
mxmlSaveFile(xml, stderr, MXML_NO_CALLBACK); mxmlSaveFile(xml, stderr, MXML_NO_CALLBACK);
@ -525,12 +469,11 @@ main(int argc, /* I - Number of command-line args */
mxmlDelete(xml); mxmlDelete(xml);
/* // Open the file...
* Open the file...
*/
if (argv[1][0] == '<') if (argv[1][0] == '<')
{
xml = mxmlLoadString(NULL, argv[1], type_cb); xml = mxmlLoadString(NULL, argv[1], type_cb);
}
else if ((fp = fopen(argv[1], "rb")) == NULL) else if ((fp = fopen(argv[1], "rb")) == NULL)
{ {
perror(argv[1]); perror(argv[1]);
@ -538,10 +481,7 @@ main(int argc, /* I - Number of command-line args */
} }
else else
{ {
/* // Read the file...
* Read the file...
*/
xml = mxmlLoadFile(NULL, fp, type_cb); xml = mxmlLoadFile(NULL, fp, type_cb);
fclose(fp); fclose(fp);
@ -555,13 +495,8 @@ main(int argc, /* I - Number of command-line args */
if (!strcmp(argv[1], "test.xml")) if (!strcmp(argv[1], "test.xml"))
{ {
/* // Verify that mxmlFindElement() and indirectly mxmlWalkNext() work properly...
* Verify that mxmlFindElement() and indirectly mxmlWalkNext() work if ((node = mxmlFindElement(xml, xml, "choice", NULL, NULL, MXML_DESCEND)) == NULL)
* properly...
*/
if ((node = mxmlFindElement(xml, xml, "choice", NULL, NULL,
MXML_DESCEND)) == NULL)
{ {
fputs("Unable to find first <choice> element in XML tree.\n", stderr); fputs("Unable to find first <choice> element in XML tree.\n", stderr);
mxmlDelete(tree); mxmlDelete(tree);
@ -576,16 +511,10 @@ main(int argc, /* I - Number of command-line args */
} }
} }
/* // Print the XML tree...
* Print the XML tree...
*/
mxmlSaveFile(xml, stdout, whitespace_cb); mxmlSaveFile(xml, stdout, whitespace_cb);
/* // Save the XML tree to a string and print it...
* Save the XML tree to a string and print it...
*/
if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb) > 0) if (mxmlSaveString(xml, buffer, sizeof(buffer), whitespace_cb) > 0)
{ {
if (argc == 3) if (argc == 3)
@ -596,40 +525,25 @@ main(int argc, /* I - Number of command-line args */
} }
} }
/* // Delete the tree...
* Delete the tree...
*/
mxmlDelete(xml); mxmlDelete(xml);
/* // Read from/write to file descriptors...
* Read from/write to file descriptors...
*/
if (argv[1][0] != '<') if (argv[1][0] != '<')
{ {
/* // Open the file again...
* Open the file again...
*/
if ((fd = open(argv[1], O_RDONLY | O_BINARY)) < 0) if ((fd = open(argv[1], O_RDONLY | O_BINARY)) < 0)
{ {
perror(argv[1]); perror(argv[1]);
return (1); return (1);
} }
/* // Read the file...
* Read the file...
*/
xml = mxmlLoadFd(NULL, fd, type_cb); xml = mxmlLoadFd(NULL, fd, type_cb);
close(fd); close(fd);
/* // Create filename.xmlfd...
* Create filename.xmlfd...
*/
snprintf(buffer, sizeof(buffer), "%sfd", argv[1]); snprintf(buffer, sizeof(buffer), "%sfd", argv[1]);
if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0) if ((fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0)
@ -639,29 +553,22 @@ main(int argc, /* I - Number of command-line args */
return (1); return (1);
} }
/* // Write the file...
* Write the file...
*/
mxmlSaveFd(xml, fd, whitespace_cb); mxmlSaveFd(xml, fd, whitespace_cb);
close(fd); close(fd);
/* // Delete the tree...
* Delete the tree...
*/
mxmlDelete(xml); mxmlDelete(xml);
} }
/* // Test SAX methods...
* Test SAX methods...
*/
memset(event_counts, 0, sizeof(event_counts)); memset(event_counts, 0, sizeof(event_counts));
if (argv[1][0] == '<') if (argv[1][0] == '<')
{
mxmlRelease(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) else if ((fp = fopen(argv[1], "rb")) == NULL)
{ {
perror(argv[1]); perror(argv[1]);
@ -669,10 +576,7 @@ main(int argc, /* I - Number of command-line args */
} }
else else
{ {
/* // Read the file...
* Read the file...
*/
mxmlRelease(mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL)); mxmlRelease(mxmlSAXLoadFile(NULL, fp, type_cb, sax_cb, NULL));
fclose(fp); fclose(fp);
@ -680,56 +584,48 @@ main(int argc, /* I - Number of command-line args */
if (!strcmp(argv[1], "test.xml")) if (!strcmp(argv[1], "test.xml"))
{ {
if (event_counts[MXML_SAX_CDATA] != 1) if (event_counts[MXML_SAX_EVENT_CDATA] != 1)
{ {
fprintf(stderr, "MXML_SAX_CDATA seen %d times, expected 1 times.\n", fprintf(stderr, "MXML_SAX_EVENT_CDATA seen %d times, expected 1 times.\n", event_counts[MXML_SAX_EVENT_CDATA]);
event_counts[MXML_SAX_CDATA]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_COMMENT] != 1) if (event_counts[MXML_SAX_EVENT_COMMENT] != 1)
{ {
fprintf(stderr, "MXML_SAX_COMMENT seen %d times, expected 1 times.\n", fprintf(stderr, "MXML_SAX_EVENT_COMMENT seen %d times, expected 1 times.\n", event_counts[MXML_SAX_EVENT_COMMENT]);
event_counts[MXML_SAX_COMMENT]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_DATA] != 61) if (event_counts[MXML_SAX_EVENT_DATA] != 61)
{ {
fprintf(stderr, "MXML_SAX_DATA seen %d times, expected 61 times.\n", fprintf(stderr, "MXML_SAX_EVENT_DATA seen %d times, expected 61 times.\n", event_counts[MXML_SAX_EVENT_DATA]);
event_counts[MXML_SAX_DATA]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_DIRECTIVE] != 1) if (event_counts[MXML_SAX_EVENT_DIRECTIVE] != 1)
{ {
fprintf(stderr, "MXML_SAX_DIRECTIVE seen %d times, expected 1 times.\n", fprintf(stderr, "MXML_SAX_EVENT_DIRECTIVE seen %d times, expected 1 times.\n", event_counts[MXML_SAX_EVENT_DIRECTIVE]);
event_counts[MXML_SAX_DIRECTIVE]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_ELEMENT_CLOSE] != 20) if (event_counts[MXML_SAX_EVENT_ELEMENT_CLOSE] != 20)
{ {
fprintf(stderr, "MXML_SAX_ELEMENT_CLOSE seen %d times, expected 20 times.\n", fprintf(stderr, "MXML_SAX_EVENT_ELEMENT_CLOSE seen %d times, expected 20 times.\n", event_counts[MXML_SAX_EVENT_ELEMENT_CLOSE]);
event_counts[MXML_SAX_ELEMENT_CLOSE]);
return (1); return (1);
} }
if (event_counts[MXML_SAX_ELEMENT_OPEN] != 20) if (event_counts[MXML_SAX_EVENT_ELEMENT_OPEN] != 20)
{ {
fprintf(stderr, "MXML_SAX_ELEMENT_OPEN seen %d times, expected 20 times.\n", fprintf(stderr, "MXML_SAX_EVENT_ELEMENT_OPEN seen %d times, expected 20 times.\n", event_counts[MXML_SAX_EVENT_ELEMENT_OPEN]);
event_counts[MXML_SAX_ELEMENT_OPEN]);
return (1); return (1);
} }
} }
#ifndef _WIN32 #ifndef _WIN32
/* // Debug hooks...
* Debug hooks...
*/
if (getenv("TEST_DELAY") != NULL) if (getenv("TEST_DELAY") != NULL)
sleep(atoi(getenv("TEST_DELAY"))); sleep(atoi(getenv("TEST_DELAY")));
# ifdef __APPLE__ # ifdef __APPLE__
if (getenv("TEST_LEAKS") != NULL) if (getenv("TEST_LEAKS") != NULL)
{ {
@ -739,43 +635,37 @@ main(int argc, /* I - Number of command-line args */
if (system(command)) if (system(command))
puts("Unable to check for leaks."); puts("Unable to check for leaks.");
} }
# endif /* __APPLE__ */ # endif // __APPLE__
#endif /* !_WIN32 */ #endif // !_WIN32
/*
* Return...
*/
// Return...
return (0); return (0);
} }
/* //
* 'sax_cb()' - Process nodes via SAX. // 'sax_cb()' - Process nodes via SAX.
*/ //
void void
sax_cb(mxml_node_t *node, /* I - Current node */ sax_cb(mxml_node_t *node, // I - Current node
mxml_sax_event_t event, /* I - SAX event */ mxml_sax_event_t event, // I - SAX event
void *data) /* I - SAX user data */ void *data) // I - SAX user data
{ {
static const char * const events[] = /* Events */ static const char * const events[] = // Events
{ {
"MXML_SAX_CDATA", /* CDATA node */ "MXML_SAX_EVENT_CDATA", // CDATA node
"MXML_SAX_COMMENT", /* Comment node */ "MXML_SAX_EVENT_COMMENT", // Comment node
"MXML_SAX_DATA", /* Data node */ "MXML_SAX_EVENT_DATA", // Data node
"MXML_SAX_DIRECTIVE", /* Processing directive node */ "MXML_SAX_EVENT_DIRECTIVE", // Processing directive node
"MXML_SAX_ELEMENT_CLOSE", /* Element closed */ "MXML_SAX_EVENT_ELEMENT_CLOSE", // Element closed
"MXML_SAX_ELEMENT_OPEN" /* Element opened */ "MXML_SAX_EVENT_ELEMENT_OPEN" // Element opened
}; };
(void)data; (void)data;
/* // This SAX callback just counts the different events.
* This SAX callback just counts the different events.
*/
if (!node) if (!node)
fprintf(stderr, "ERROR: SAX callback for event %s has NULL node.\n", events[event]); fprintf(stderr, "ERROR: SAX callback for event %s has NULL node.\n", events[event]);
@ -783,83 +673,65 @@ sax_cb(mxml_node_t *node, /* I - Current node */
} }
/* //
* 'type_cb()' - XML data type callback for mxmlLoadFile()... // 'type_cb()' - XML data type callback for mxmlLoadFile()...
*/ //
mxml_type_t /* O - Data type */ mxml_type_t // O - Data type
type_cb(mxml_node_t *node) /* I - Element node */ type_cb(mxml_node_t *node) // I - Element node
{ {
const char *type; /* Type string */ const char *type; // Type string
/*
* You can lookup attributes and/or use the element name, hierarchy, etc...
*/
// You can lookup attributes and/or use the element name, hierarchy, etc...
if ((type = mxmlElementGetAttr(node, "type")) == NULL) if ((type = mxmlElementGetAttr(node, "type")) == NULL)
type = node->value.element.name; type = node->value.element.name;
if (!strcmp(type, "integer")) if (!strcmp(type, "integer"))
return (MXML_INTEGER); return (MXML_TYPE_INTEGER);
else if (!strcmp(type, "opaque") || !strcmp(type, "pre")) else if (!strcmp(type, "opaque") || !strcmp(type, "pre"))
return (MXML_OPAQUE); return (MXML_TYPE_OPAQUE);
else if (!strcmp(type, "real")) else if (!strcmp(type, "real"))
return (MXML_REAL); return (MXML_TYPE_REAL);
else else
return (MXML_TEXT); return (MXML_TYPE_TEXT);
} }
/* //
* 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert // 'whitespace_cb()' - Let the mxmlSaveFile() function know when to insert
* newlines and tabs... // newlines and tabs...
*/ //
const char * /* O - Whitespace string or NULL */ const char * // O - Whitespace string or NULL
whitespace_cb(mxml_node_t *node, /* I - Element node */ whitespace_cb(mxml_node_t *node, // I - Element node
int where) /* I - Open or close tag? */ int where) // I - Open or close tag?
{ {
mxml_node_t *parent; /* Parent node */ mxml_node_t *parent; // Parent node
int level; /* Indentation level */ int level; // Indentation level
const char *name; /* Name of element */ const char *name; // Name of element
static const char *tabs = "\t\t\t\t\t\t\t\t"; static const char *tabs = "\t\t\t\t\t\t\t\t";
/* Tabs for indentation */ // Tabs for indentation
/* // We can conditionally break to a new line before or after any element.
* We can conditionally break to a new line before or after any element. // These are just common HTML elements...
* These are just common HTML elements...
*/
name = node->value.element.name; name = node->value.element.name;
if (!strcmp(name, "html") || !strcmp(name, "head") || !strcmp(name, "body") || if (!strcmp(name, "html") || !strcmp(name, "head") || !strcmp(name, "body") || !strcmp(name, "pre") || !strcmp(name, "p") || !strcmp(name, "h1") || !strcmp(name, "h2") || !strcmp(name, "h3") || !strcmp(name, "h4") || !strcmp(name, "h5") || !strcmp(name, "h6"))
!strcmp(name, "pre") || !strcmp(name, "p") ||
!strcmp(name, "h1") || !strcmp(name, "h2") || !strcmp(name, "h3") ||
!strcmp(name, "h4") || !strcmp(name, "h5") || !strcmp(name, "h6"))
{ {
/* // Newlines before open and after close...
* Newlines before open and after close...
*/
if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_AFTER_CLOSE) if (where == MXML_WS_BEFORE_OPEN || where == MXML_WS_AFTER_CLOSE)
return ("\n"); return ("\n");
} }
else if (!strcmp(name, "dl") || !strcmp(name, "ol") || !strcmp(name, "ul")) else if (!strcmp(name, "dl") || !strcmp(name, "ol") || !strcmp(name, "ul"))
{ {
/* // Put a newline before and after list elements...
* Put a newline before and after list elements...
*/
return ("\n"); return ("\n");
} }
else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li")) else if (!strcmp(name, "dd") || !strcmp(name, "dt") || !strcmp(name, "li"))
{ {
/* // Put a tab before <li>'s, <dd>'s, and <dt>'s, and a newline after them...
* Put a tab before <li>'s, <dd>'s, and <dt>'s, and a newline after them...
*/
if (where == MXML_WS_BEFORE_OPEN) if (where == MXML_WS_BEFORE_OPEN)
return ("\t"); return ("\t");
else if (where == MXML_WS_AFTER_CLOSE) else if (where == MXML_WS_AFTER_CLOSE)
@ -872,13 +744,9 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
else else
return (NULL); return (NULL);
} }
else if (where == MXML_WS_BEFORE_OPEN || else if (where == MXML_WS_BEFORE_OPEN || ((!strcmp(name, "choice") || !strcmp(name, "option")) && where == MXML_WS_BEFORE_CLOSE))
((!strcmp(name, "choice") || !strcmp(name, "option")) &&
where == MXML_WS_BEFORE_CLOSE))
{ {
for (level = -1, parent = node->parent; for (level = -1, parent = node->parent; parent; level ++, parent = parent->parent);
parent;
level ++, parent = parent->parent);
if (level > 8) if (level > 8)
level = 8; level = 8;
@ -887,17 +755,11 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */
return (tabs + 8 - level); return (tabs + 8 - level);
} }
else if (where == MXML_WS_AFTER_CLOSE || else if (where == MXML_WS_AFTER_CLOSE || ((!strcmp(name, "group") || !strcmp(name, "option") || !strcmp(name, "choice")) && where == MXML_WS_AFTER_OPEN))
((!strcmp(name, "group") || !strcmp(name, "option") ||
!strcmp(name, "choice")) &&
where == MXML_WS_AFTER_OPEN))
return ("\n"); return ("\n");
else if (where == MXML_WS_AFTER_OPEN && !node->child) else if (where == MXML_WS_AFTER_OPEN && !node->child)
return ("\n"); return ("\n");
/* // Return NULL for no added whitespace...
* Return NULL for no added whitespace...
*/
return (NULL); return (NULL);
} }

Loading…
Cancel
Save