summaryrefslogtreecommitdiff
path: root/snprintfv
diff options
context:
space:
mode:
Diffstat (limited to 'snprintfv')
-rw-r--r--snprintfv/AUTHORS8
-rw-r--r--snprintfv/Makefile.am48
-rw-r--r--snprintfv/Makefile.in590
-rw-r--r--snprintfv/README30
-rw-r--r--snprintfv/THANKS13
-rw-r--r--snprintfv/compat.h315
-rw-r--r--snprintfv/custom.c182
-rw-r--r--snprintfv/filament.c232
-rw-r--r--snprintfv/filament.h257
-rw-r--r--snprintfv/filament.in197
-rw-r--r--snprintfv/filament.stamp0
-rw-r--r--snprintfv/format.c1275
-rw-r--r--snprintfv/mem.c82
-rw-r--r--snprintfv/mem.h120
-rw-r--r--snprintfv/printf.c1568
-rw-r--r--snprintfv/printf.h846
-rw-r--r--snprintfv/printf.in318
-rw-r--r--snprintfv/printf.stamp0
-rw-r--r--snprintfv/stream.c226
-rw-r--r--snprintfv/stream.h192
-rw-r--r--snprintfv/stream.in96
-rw-r--r--snprintfv/stream.stamp0
22 files changed, 6595 insertions, 0 deletions
diff --git a/snprintfv/AUTHORS b/snprintfv/AUTHORS
new file mode 100644
index 0000000..d17456b
--- /dev/null
+++ b/snprintfv/AUTHORS
@@ -0,0 +1,8 @@
+Authors of libsnprintfv. See individual files for their licenses.
+
+Gary V. Vaughan <gary@gnu.org>:
+ Designed, implemented and maintained libsnprintfv up to the 0.98h release.
+
+Paolo Bonzini <bonzini@gnu.org> and
+Bruce Korb <bkorb@gnu.org>:
+ Are currently maintaining libsnprintfv (starting from Summer 2002).
diff --git a/snprintfv/Makefile.am b/snprintfv/Makefile.am
new file mode 100644
index 0000000..a86859a
--- /dev/null
+++ b/snprintfv/Makefile.am
@@ -0,0 +1,48 @@
+## -*- Mode: Makefile -*-
+## ---------------------------------------------------------------------
+## Makefile.am -- process this file with automake to produce Makefile.in
+## Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+## Originally by Gary V. Vaughan, 1998
+## This file is part of Snprintfv
+##
+## Snprintfv is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Snprintfv program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+##
+## As a special exception to the GNU General Public License, if you
+## distribute this file as part of a program that also links with and
+## uses the libopts library from AutoGen, you may include it under
+## the same distribution terms used by the libopts library.
+
+## Code:
+
+INCLUDES = -I$(top_srcdir)
+noinst_HEADERS = mem.h filament.h stream.h printf.h compat.h
+dist_noinst_DATA = filament.stamp stream.stamp printf.stamp
+noinst_LTLIBRARIES = libsnprintfv.la
+libsnprintfv_la_LDFLAGS = -no-undefined
+CSRC = filament.c format.c printf.c mem.c stream.c custom.c
+
+nodist_libsnprintfv_la_SOURCES = snv.c
+
+# These files are the raw sources used to generate similarly named
+# header files after extracting the prototypes from the sources
+#
+EXTRA_DIST = filament.in printf.in stream.in $(CSRC)
+
+snv.c : $(CSRC)
+ for f in $(CSRC) ; do echo "#include \"$$f\"" ; done > $@
+
+.NOTPARALLEL:
+
+# Makefile.am ends here
diff --git a/snprintfv/Makefile.in b/snprintfv/Makefile.in
new file mode 100644
index 0000000..23b6acb
--- /dev/null
+++ b/snprintfv/Makefile.in
@@ -0,0 +1,590 @@
+# Makefile.in generated by automake 1.12.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2012 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = snprintfv
+DIST_COMMON = README $(dist_noinst_DATA) $(noinst_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/config/depcomp AUTHORS THANKS
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/config/ag_macros.m4 \
+ $(top_srcdir)/config/extensions.m4 \
+ $(top_srcdir)/config/libopts.m4 \
+ $(top_srcdir)/config/libtool.m4 \
+ $(top_srcdir)/config/ltoptions.m4 \
+ $(top_srcdir)/config/ltsugar.m4 \
+ $(top_srcdir)/config/ltversion.m4 \
+ $(top_srcdir)/config/lt~obsolete.m4 \
+ $(top_srcdir)/config/onceonly.m4 \
+ $(top_srcdir)/config/snprintfv.m4 \
+ $(top_srcdir)/config/unlocked-io.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libsnprintfv_la_LIBADD =
+nodist_libsnprintfv_la_OBJECTS = snv.lo
+libsnprintfv_la_OBJECTS = $(nodist_libsnprintfv_la_OBJECTS)
+libsnprintfv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libsnprintfv_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(nodist_libsnprintfv_la_SOURCES)
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_noinst_DATA)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AGEN5_TESTS = @AGEN5_TESTS@
+AG_GUILE = @AG_GUILE@
+AG_LDFLAGS = @AG_LDFLAGS@
+AG_MAJOR_VERSION = @AG_MAJOR_VERSION@
+AG_MINOR_VERSION = @AG_MINOR_VERSION@
+AG_TIMEOUT = @AG_TIMEOUT@
+AG_VERSION = @AG_VERSION@
+AG_XML2 = @AG_XML2@
+AGexe = @AGexe@
+AGnam = @AGnam@
+AMTAR = @AMTAR@
+AO_AGE = @AO_AGE@
+AO_CURRENT = @AO_CURRENT@
+AO_REVISION = @AO_REVISION@
+AO_TEMPLATE_VERSION = @AO_TEMPLATE_VERSION@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CLexe = @CLexe@
+CLnam = @CLnam@
+CONFIG_SHELL = @CONFIG_SHELL@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_ENABLED = @DEBUG_ENABLED@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNAMIC_AG = @DYNAMIC_AG@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_STATIC = @ENABLE_STATIC@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GDexe = @GDexe@
+GDnam = @GDnam@
+GO_AGE = @GO_AGE@
+GO_CURRENT = @GO_CURRENT@
+GO_REVISION = @GO_REVISION@
+GREP = @GREP@
+GUILE_VERSION = @GUILE_VERSION@
+INCLIST = @INCLIST@
+INCSNPRINTFV = @INCSNPRINTFV@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBGUILE_CFLAGS = @LIBGUILE_CFLAGS@
+LIBGUILE_LIBS = @LIBGUILE_LIBS@
+LIBGUILE_PATH = @LIBGUILE_PATH@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSNPRINTFV = @LIBSNPRINTFV@
+LIBTOOL = @LIBTOOL@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIBXML2_PATH = @LIBXML2_PATH@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+M4_SRC = @M4_SRC@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPTS_TESTDIR = @OPTS_TESTDIR@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSIX_SHELL = @POSIX_SHELL@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TEXI2HTML = @TEXI2HTML@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_aux_dir = @ac_aux_dir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)
+noinst_HEADERS = mem.h filament.h stream.h printf.h compat.h
+dist_noinst_DATA = filament.stamp stream.stamp printf.stamp
+noinst_LTLIBRARIES = libsnprintfv.la
+libsnprintfv_la_LDFLAGS = -no-undefined
+CSRC = filament.c format.c printf.c mem.c stream.c custom.c
+nodist_libsnprintfv_la_SOURCES = snv.c
+
+# These files are the raw sources used to generate similarly named
+# header files after extracting the prototypes from the sources
+#
+EXTRA_DIST = filament.in printf.in stream.in $(CSRC)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu snprintfv/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu snprintfv/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+libsnprintfv.la: $(libsnprintfv_la_OBJECTS) $(libsnprintfv_la_DEPENDENCIES) $(EXTRA_libsnprintfv_la_DEPENDENCIES)
+ $(libsnprintfv_la_LINK) $(libsnprintfv_la_OBJECTS) $(libsnprintfv_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snv.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+cscopelist: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES cscopelist ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am
+
+
+snv.c : $(CSRC)
+ for f in $(CSRC) ; do echo "#include \"$$f\"" ; done > $@
+
+.NOTPARALLEL:
+
+# Makefile.am ends here
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/snprintfv/README b/snprintfv/README
new file mode 100644
index 0000000..9251106
--- /dev/null
+++ b/snprintfv/README
@@ -0,0 +1,30 @@
+This is libsnprintfv, a portable, extensible reimplementation of the
+POSIX format printing API. libsnprintfv provides all the features
+which should be present in a POSIX format printing implementation,
+but which often are not, such as guaranteed return of number of
+characters printed and support for %n$ format specifiers.
+
+In addition the the POSIX features, libsnprintfv also provides some
+extensions to the API, and a GNU glibc-2 compatible printf custom
+format specifier, all of which you can use with impunity if you link
+with libsnprintfv, rather than worrying about whether the target C
+library provides the extensions. See the info manual for details of
+the API calls available, and an explanation of how to write custom
+specifier handlers.
+
+The latest version of libsnprintfv is available from the author's
+homepage: http://www.oranda.demon.co.uk.
+
+libsnprintfv is written in a very portable K&R compatible style, and
+should build anywhere that provides a reasonable C compiler and runtime.
+See the file INSTALL for instructions on how to build and install
+libsnprintfv.
+
+See the file NEWS for a description of user visible changes to
+libsnprintfv between releases.
+
+See the file TODO for a list of outstanding work.
+
+If you have any suggestions or bug reports, please send email to the
+author at <gary@gnu.org>.
+
diff --git a/snprintfv/THANKS b/snprintfv/THANKS
new file mode 100644
index 0000000..0480bbe
--- /dev/null
+++ b/snprintfv/THANKS
@@ -0,0 +1,13 @@
+libsnprintfv would not be what it is without the invaluable help of
+these people:
+
+Everybody who was kind enough to spend time testing libsnprintfv,
+use it in their packages and report bugs.
+
+The following people made especially gracious contributions of their
+time and energy in helping to track down bugs, port to new systems,
+and generally assist in the maintainership process:
+
+Bruce Korb <bkorb@gnu.org>
+Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+Robert Lipe <robertlipe@usa.net>
diff --git a/snprintfv/compat.h b/snprintfv/compat.h
new file mode 100644
index 0000000..0145b97
--- /dev/null
+++ b/snprintfv/compat.h
@@ -0,0 +1,315 @@
+/* -*- Mode: C -*-
+ * --------------------------------------------------------------------
+ * compat.h.in --- verbose but portable cpp defines for snprintfv
+ * Copyright (C) 1999 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1999
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ *
+ * Code: */
+
+#ifndef SNPRINTFV_COMPAT_H
+#define SNPRINTFV_COMPAT_H 1
+
+#define _GNU_SOURCE 1 /* for strsignal in GNU's libc */
+#define __USE_GNU 1 /* exact same thing as above */
+#define __EXTENSIONS__ 1 /* and another way to call for it */
+
+#ifdef __cplusplus
+extern "C" {
+#define SNV_END_EXTERN_C }
+#else
+#define SNV_END_EXTERN_C
+#endif /* __cplusplus */
+
+#define NO_FLOAT_PRINTING
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+# ifndef errno
+ /* Some sytems #define this! */
+ extern int errno;
+# endif
+#endif
+
+#if defined( HAVE_LIMITS_H )
+# include <limits.h>
+
+#elif defined( HAVE_SYS_LIMITS_H )
+# include <sys/limits.h>
+
+#elif defined( HAVE_VALUES_H )
+# ifndef MAXINT
+# include <values.h>
+# endif /* MAXINT */
+#endif
+
+#if defined( HAVE_STRING_H )
+# include <string.h>
+
+#elif defined( HAVE_STRINGS_H )
+# include <strings.h>
+#endif
+
+#if defined( HAVE_MEMORY_H )
+# include <memory.h>
+#endif
+
+#if defined( HAVE_INTTYPES_H )
+# include <inttypes.h>
+
+#elif defined( HAVE_STDINT_H )
+# include <stdint.h>
+#endif
+
+#ifndef HAVE_UINTMAX_T
+# if defined( HAVE_LONG_LONG )
+ typedef long long intmax_t;
+ typedef unsigned long long uintmax_t;
+# else
+ typedef long intmax_t;
+ typedef unsigned long uintmax_t;
+# endif
+#endif
+
+#if defined( HAVE_STDARG_H )
+# include <stdarg.h>
+# ifndef VA_START
+# define VA_START(a, f) va_start(a, f)
+# define VA_END(a) va_end(a)
+# endif /* VA_START */
+# define SNV_USING_STDARG_H
+#elif defined( HAVE_VARARGS_H )
+# include <varargs.h>
+# ifndef VA_START
+# define VA_START(a, f) va_start(a)
+# define VA_END(a) va_end(a)
+# endif /* VA_START */
+# undef SNV_USING_STDARG_H
+#else
+# include "must-have-stdarg-or-varargs"
+#endif
+
+#if HAVE_RUNETYPE_H
+# include <runetype.h>
+#endif
+
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef HAVE_WCHAR_T
+typedef wchar_t snv_wchar_t;
+#else
+typedef int snv_wchar_t;
+#endif
+
+#ifdef HAVE_WINT_T
+typedef wint_t snv_wint_t;
+#else
+typedef int snv_wint_t;
+#endif
+
+/* inline and const keywords are (mostly) handled by config.h */
+#ifdef __GNUC__
+# ifndef const
+# define const __const
+# endif
+# ifndef inline
+# define inline __inline
+# endif
+# ifndef signed
+# define signed __signed
+# endif
+#else
+# ifndef __STDC__
+# undef signed
+# define signed
+# endif
+#endif
+
+#ifdef __STDC__
+# define _SNV_STR(x) #x
+ typedef void *snv_pointer;
+ typedef const void *snv_constpointer;
+#else
+# define _SNV_STR(x) "x"
+ typedef char *snv_pointer;
+ typedef char *snv_constpointer;
+#endif
+
+#if defined(HAVE_FPUTC_UNLOCKED) && defined(HAVE_FLOCKFILE)
+# define SNV_FPUTC_UNLOCKED fputc_unlocked
+# define SNV_PUTC_UNLOCKED putc_unlocked
+# define SNV_WITH_LOCKED_FP(fp, tmp_var) \
+ for (flockfile (fp), tmp_var = 1; \
+ tmp_var--; funlockfile (fp))
+#else
+# define SNV_FPUTC_UNLOCKED fputc
+# define SNV_PUTC_UNLOCKED putc
+# define SNV_WITH_LOCKED_FP(fp, tmp_var) \
+ for (tmp_var = 1; tmp_var--; )
+#endif
+
+/*
+ * Define macros for storing integers inside pointers.
+ * Be aware that it is only safe to use these macros to store `int'
+ * values in `char*' (or `void*') words, and then extract them later.
+ * Although it will work the other way round on many common
+ * architectures, it is not portable to assume a `char*' can be
+ * stored in an `int' and extracted later without loss of the msb's
+ */
+#define SNV_POINTER_TO_LONG(p) ((long)(p))
+#define SNV_POINTER_TO_ULONG(p) ((unsigned long)(p))
+#define SNV_LONG_TO_POINTER(i) ((snv_pointer)(long)(i))
+#define SNV_ULONG_TO_POINTER(u) ((snv_pointer)(unsigned long)(u))
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#else
+typedef enum {
+ false = 0,
+ true = 1
+} bool;
+#endif
+
+#ifdef __CYGWIN32__
+# ifndef __CYGWIN__
+# define __CYGWIN__
+# endif
+#endif
+#ifdef __CYGWIN__
+# ifndef _WIN32
+# define _WIN32
+# endif
+#endif
+
+#ifndef PARAMS
+# define PARAMS(args) args
+#endif
+
+#undef SNV_STMT_START
+#undef SNV_STMT_END
+#if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
+# define SNV_STMT_START (void)(
+# define SNV_STMT_END )
+
+#elif (defined (sun) || defined (__sun__))
+# define SNV_STMT_START if (1)
+# define SNV_STMT_END else (void)0
+
+#else
+# define SNV_STMT_START do
+# define SNV_STMT_END while (false)
+#endif
+
+#ifdef _WIN32
+# ifdef DLL_EXPORT
+# define SNV_SCOPE extern __declspec(dllexport)
+# else
+# ifdef LIBSNPRINTFV_DLL_IMPORT
+# define SNV_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+#endif
+#ifndef SNV_SCOPE
+# define SNV_SCOPE extern
+#endif
+
+#undef SNV_GNUC_PRINTF
+#undef SNV_GNUC_NORETURN
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+# define SNV_GNUC_PRINTF( args, format_idx, arg_idx ) \
+ args __attribute__((format (printf, format_idx, arg_idx)))
+# define SNV_GNUC_NORETURN \
+ __attribute__((noreturn))
+# define SNV_ASSERT_FCN " (", __PRETTY_FUNCTION__, ")"
+#else /* !__GNUC__ */
+# define SNV_GNUC_PRINTF( args, format_idx, arg_idx ) args
+# define SNV_GNUC_NORETURN
+# define SNV_ASSERT_FCN "", "", ""
+#endif /* !__GNUC__ */
+
+#define SNV_ASSERT_FMT "file %s: line %d%s%s%s: assertion \"%s\" failed.\n"
+
+#define snv_assert(expr) snv_fassert(stderr, expr)
+#define snv_fassert(stream, expr) SNV_STMT_START { \
+ if (!(expr)) { \
+ fprintf (stream, SNV_ASSERT_FMT, __FILE__, __LINE__, \
+ SNV_ASSERT_FCN, _SNV_STR(expr)); \
+ exit(EXIT_FAILURE); \
+ }; } SNV_STMT_END
+
+#define return_if_fail(expr) freturn_if_fail(stderr, expr)
+#define freturn_if_fail(expr) SNV_STMT_START { \
+ if (!(expr)) { \
+ fprintf (stream, SNV_ASSERT_FMT, __FILE__, __LINE__, \
+ SNV_ASSERT_FCN, _SNV_STR(expr)); \
+ return; \
+ }; } SNV_STMT_END
+
+#define return_val_if_fail(expr, val) freturn_val_if_fail(stderr, expr, val)
+#define freturn_val_if_fail(stream, expr, val) SNV_STMT_START { \
+ if (!(expr)) { \
+ fprintf (stream, SNV_ASSERT_FMT, __FILE__, __LINE__, \
+ SNV_ASSERT_FCN, _SNV_STR(expr)); \
+ return val; \
+ }; } SNV_STMT_END
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef ABS
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+typedef SNV_LONG_DOUBLE snv_long_double;
+
+#ifndef HAVE_STRTOUL
+extern unsigned long
+strtoul( const char *nptrm, char **endptr, register int base );
+#endif
+
+SNV_END_EXTERN_C
+#endif /* SNPRINTFV_COMPAT_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/compat.h */
diff --git a/snprintfv/custom.c b/snprintfv/custom.c
new file mode 100644
index 0000000..05793ea
--- /dev/null
+++ b/snprintfv/custom.c
@@ -0,0 +1,182 @@
+/* -*- Mode: C -*- */
+
+/* custom.c --- printf clone for argv arrays
+ * Copyright (C) 2003 Gary V. Vaughan
+ * Originally by Paolo Bonzini, 2002
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include <stddef.h>
+
+#if HAVE_RUNETYPE_H
+# include <runetype.h>
+#endif
+
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#include "printf.h"
+
+
+
+/**
+ * printf_generic_info:
+ * @pinfo: the current state information for the format
+ * string parser.
+ * @n: the number of available slots in the @argtypes array
+ * @argtypes: the pointer to the first slot to be filled by the
+ * function
+ *
+ * An example implementation of a %printf_arginfo_function, which
+ * takes the basic type from the type given in the %spec_entry
+ * and adds flags depending on what was parsed (e.g. %PA_FLAG_SHORT
+ * is %pparser->is_short and so on).
+ *
+ * Return value:
+ * Always 1.
+ */
+int
+printf_generic_info (struct printf_info *const pinfo, size_t n, int *argtypes)
+{
+ int type = pinfo->type;
+
+ if (!n)
+ return 1;
+
+ if ((type & PA_TYPE_MASK) == PA_POINTER)
+ type |= PA_FLAG_UNSIGNED;
+
+ if (pinfo->is_char)
+ type = PA_CHAR;
+
+ if (pinfo->is_short)
+ type |= PA_FLAG_SHORT;
+
+ if (pinfo->is_long)
+ type |= PA_FLAG_LONG;
+
+ if (pinfo->is_long_double)
+ type |= PA_FLAG_LONG_LONG;
+
+ argtypes[0] = type;
+ return 1;
+}
+
+
+/**
+ * printf_generic:
+ * @stream: the stream (possibly a struct printfv_stream appropriately
+ * cast) on which to write output.
+ * @pinfo: the current state information for the format string parser.
+ * @args: the pointer to the first argument to be read by the handler
+ *
+ * An example implementation of a %printf_function, used to provide easy
+ * access to justification, width and precision options.
+ *
+ * Return value:
+ * The number of characters output.
+ **/
+int
+printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ int len = 0, count_or_errorcode = SNV_OK;
+ char *p = NULL;
+
+ /* Used to interface to the custom function. */
+ STREAM *out;
+ Filament *fil;
+ printf_function *user_func = (printf_function *) pinfo->extra;
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Read these now to advance the argument pointer appropriately */
+ if (pinfo->prec == -1)
+ pinfo->prec = 0;
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec <= -1)
+ {
+ PRINTF_ERROR (pinfo, "invalid flags");
+ return -1;
+ }
+
+ /* Print to a stream using a user-supplied function. */
+ fil = filnew (NULL, (size_t)0);
+ out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
+ user_func (out, pinfo, args);
+ stream_delete (out);
+ len = fillen (fil);
+ p = fildelete (fil);
+
+ /* Left pad to the width if the supplied argument is less than
+ the width specifier. */
+ if (p != NULL && pinfo->prec && pinfo->prec < len)
+ len = pinfo->prec;
+
+ if ((len < pinfo->width) && !pinfo->left)
+ {
+ int padwidth = pinfo->width - len;
+ while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+ }
+
+ /* Fill the buffer with as many characters from the format argument
+ * as possible without overflowing or exceeding the precision.
+ */
+ if ((count_or_errorcode >= 0) && (p != NULL))
+ {
+ int mark = count_or_errorcode;
+ while ((count_or_errorcode >= 0) && *p != '\0'
+ && ((pinfo->prec == 0) || (count_or_errorcode - mark < len)))
+ SNV_EMIT (*p++, stream, count_or_errorcode);
+ }
+
+ /* Right pad to the width if we still didn't reach the specified
+ * width and the left justify flag was set.
+ */
+ if ((count_or_errorcode < pinfo->width) && pinfo->left)
+ while ((count_or_errorcode >= 0)
+ && (count_or_errorcode < pinfo->width))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Return the number of characters emitted. */
+ return count_or_errorcode;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/custom.c */
diff --git a/snprintfv/filament.c b/snprintfv/filament.c
new file mode 100644
index 0000000..a4b138f
--- /dev/null
+++ b/snprintfv/filament.c
@@ -0,0 +1,232 @@
+/* -*- Mode: C -*- */
+
+/* filament.c --- a bit like a string, but different =)O|
+ * Copyright (C) 1999 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1999
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Commentary:
+ *
+ * Try to exploit usage patterns to optimise string handling, and
+ * as a happy consequence handle NUL's embedded in strings properly.
+ *
+ * o Since finding the length of a (long) string is time consuming and
+ * requires careful coding to cache the result in local scope: We
+ * keep count of the length of a Filament all the time, so finding the
+ * length is O(1) at the expense of a little bookkeeping while
+ * manipulating the Filament contents.
+ *
+ * o Constantly resizing a block of memory to hold a string is memory
+ * efficient, but slow: Filaments are only ever expanded in size,
+ * doubling at each step to minimise the number of times the block
+ * needs to be reallocated and the contents copied (this problem is
+ * especially poignant for very large strings).
+ *
+ * o Most strings tend to be either relatively small and short-lived,
+ * or else long-lived but growing in asymptotically in size: To
+ * care for the former case, Filaments start off with a modest static
+ * buffer for the string contents to avoid any mallocations (except
+ * the initial one to get the structure!); the latter case is handled
+ * gracefully by the resizing algorithm in the previous point.
+ *
+ * o Extracting a C-style NUL terminated string from the Filament is
+ * an extremely common operation: We ensure there is always a
+ * terminating NUL character after the last character in the string
+ * so that the conversion can be performed quickly.
+ *
+ * In summary, Filaments are good where you need to do a lot of length
+ * calculations with your strings and/or gradually append more text
+ * onto existing strings. Filaments are also an easy way to get 8-bit
+ * clean strings is a more lightweight approach isn't required.
+ *
+ * They probably don't buy much if you need to do insertions and partial
+ * deletions, but optimising for that is a whole other problem!
+ */
+
+/* Code: */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include "mem.h"
+#include "filament.h"
+
+
+
+/**
+ * filnew: constructor
+ * @init: address of the first byte to copy into the new object.
+ * @len: the number of bytes to copy into the new object.
+ *
+ * Create a new Filament object, initialised to hold a copy of the
+ * first @len bytes starting at address @init. If @init is NULL, or
+ * @len is 0 (or less), then the initialised Filament will return the
+ * empty string, "", if its value is queried.
+ *
+ * Return value:
+ * A newly created Filament object is returned.
+ **/
+Filament *
+filnew (const char *const init, size_t len)
+{
+ Filament *new;
+
+ new = snv_new (Filament, 1);
+
+ new->value = new->buffer;
+ new->length = 0;
+ new->size = FILAMENT_BUFSIZ;
+
+ return (init || len) ? filinit (new, init, len) : new;
+}
+
+/**
+ * filinit:
+ * @fil: The Filament object to initialise.
+ * @init: address of the first byte to copy into the new object.
+ * @len: the number of bytes to copy into the new object.
+ *
+ * Initialise a Filament object to hold a copy of the first @len bytes
+ * starting at address @init. If @init is NULL, or @len is 0 (or less),
+ * then the Filament will be reset to hold the empty string, "".
+ *
+ * Return value:
+ * The initialised Filament object is returned.
+ **/
+Filament *
+filinit (Filament *fil, const char *const init, size_t len)
+{
+ if (init == NULL || len < 1)
+ {
+ /* Recycle any dynamic memory assigned to the previous
+ contents of @fil, and point back into the static buffer. */
+ if (fil->value != fil->buffer)
+ snv_delete (fil->value);
+
+ fil->value = fil->buffer;
+ fil->length = 0;
+ fil->size = FILAMENT_BUFSIZ;
+ }
+ else
+ {
+ if (len < FILAMENT_BUFSIZ)
+ {
+ /* We have initialisation data which will easily fit into
+ the static buffer: recycle any memory already assigned
+ and initialise in the static buffer. */
+ if (fil->value != fil->buffer)
+ {
+ snv_delete (fil->value);
+ fil->value = fil->buffer;
+ fil->size = FILAMENT_BUFSIZ;
+ }
+ }
+ else
+ {
+ /* If we get to here then we never try to shrink the already
+ allocated dynamic buffer (if any), we just leave it in
+ place all ready to expand into later... */
+ fil_maybe_extend (fil, len, false);
+ }
+
+ snv_assert (len < fil->size);
+
+ fil->length = len;
+ memcpy (fil->value, init, len);
+ }
+
+ return fil;
+}
+
+/**
+ * fildelete: destructor
+ * @fil: The Filament object for recycling.
+ *
+ * The memory being used by @fil is recycled.
+ *
+ * Return value:
+ * The original contents of @fil are converted to a null terminated
+ * string which is returned, either to be freed itself or else used
+ * as a normal C string. The entire Filament contents are copied into
+ * this string including any embedded nulls.
+ **/
+char *
+fildelete (Filament *fil)
+{
+ char *value;
+
+ if (fil->value == fil->buffer)
+ {
+ value = memcpy (snv_new (char, 1 + fil->length),
+ fil->buffer, 1 + fil->length);
+ value[fil->length] = '\0';
+ }
+ else
+ value = filval (fil);
+
+ snv_delete (fil);
+
+ return value;
+}
+
+/**
+ * _fil_extend:
+ * @fil: The Filament object which may need more string space.
+ * @len: The length of the data to be stored in @fil.
+ * @copy: whether to copy data from the static buffer on reallocation.
+ *
+ * This function will will assign a bigger block of memory to @fil
+ * considering the space left in @fil and @len, the length required
+ * for the prospective contents.
+ */
+void
+_fil_extend (Filament *fil, size_t len, bool copy)
+{
+ /* Usually we will simply double the amount of space previously
+ allocated, but if the extra data is larger than the current
+ size it *still* won't fit, so in that case we allocate enough
+ room plus some we leave the current free space to expand into. */
+ fil->size += MAX (len, fil->size);
+
+ if (fil->value == fil->buffer)
+ {
+ fil->value = snv_new (char, fil->size);
+ if (copy)
+ memcpy (fil->value, fil->buffer, fil->length);
+ }
+ else
+ fil->value = snv_renew (char, fil->value, fil->size);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/filament.c */
diff --git a/snprintfv/filament.h b/snprintfv/filament.h
new file mode 100644
index 0000000..c28be6b
--- /dev/null
+++ b/snprintfv/filament.h
@@ -0,0 +1,257 @@
+/* -*- Mode: C -*- */
+
+/* filament.h --- a bit like a string but different =)O|
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef FILAMENT_H
+#define FILAMENT_H 1
+
+#include <snprintfv/compat.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+/* This brace is so that emacs can still indent properly: */ }
+#endif
+#endif /* __cplusplus */
+
+#define FILAMENT_BUFSIZ (512 - sizeof(char *) - (2 * sizeof(size_t)))
+
+/**
+ * Filament:
+ * Opaque data type used to hold 8-bit clean dynamic strings which know
+ * their own length and resize themselves to avoid buffer overruns.
+ **/
+typedef struct filament Filament;
+
+struct filament
+{
+ char *value; /* pointer to the start of the string */
+ size_t length; /* length of the string */
+ size_t size; /* total memory allocated */
+ char buffer[FILAMENT_BUFSIZ]; /* usually string == &buffer[0] */
+};
+
+/**
+ * filnew: constructor
+ * @init: address of the first byte to copy into the new object.
+ * @len: the number of bytes to copy into the new object.
+ *
+ * Create a new Filament object, initialised to hold a copy of the
+ * first @len bytes starting at address @init. If @init is NULL, or
+ * @len is 0 (or less), then the initialised Filament will return the
+ * empty string, "", if its value is queried.
+ *
+ * Return value:
+ * A newly created Filament object is returned.
+ **/
+extern Filament *
+filnew (const char *const init, size_t len);
+
+/**
+ * filinit:
+ * @fil: The Filament object to initialise.
+ * @init: address of the first byte to copy into the new object.
+ * @len: the number of bytes to copy into the new object.
+ *
+ * Initialise a Filament object to hold a copy of the first @len bytes
+ * starting at address @init. If @init is NULL, or @len is 0 (or less),
+ * then the Filament will be reset to hold the empty string, "".
+ *
+ * Return value:
+ * The initialised Filament object is returned.
+ **/
+extern Filament *
+filinit (Filament *fil, const char *const init, size_t len);
+
+/**
+ * fildelete: destructor
+ * @fil: The Filament object for recycling.
+ *
+ * The memory being used by @fil is recycled.
+ *
+ * Return value:
+ * The original contents of @fil are converted to a null terminated
+ * string which is returned, either to be freed itself or else used
+ * as a normal C string. The entire Filament contents are copied into
+ * this string including any embedded nulls.
+ **/
+extern char *
+fildelete (Filament *fil);
+
+/**
+ * _fil_extend:
+ * @fil: The Filament object which may need more string space.
+ * @len: The length of the data to be stored in @fil.
+ * @copy: whether to copy data from the static buffer on reallocation.
+ *
+ * This function will will assign a bigger block of memory to @fil
+ * considering the space left in @fil and @len, the length required
+ * for the prospective contents.
+ */
+extern void
+_fil_extend (Filament *fil, size_t len, bool copy);
+
+#line 61 "filament.in"
+
+/* Save the overhead of a function call in the great majority of cases. */
+#define fil_maybe_extend(fil, len, copy) \
+ (((len)>=(fil)->size) ? _fil_extend((fil), (len), (copy)) : (void)0)
+
+/**
+ * filval:
+ * @fil: The Filament object being queried.
+ *
+ * Return value:
+ * A pointer to the null terminated string held by the Filament
+ * object is returned. Since the @fil may contain embedded nulls, it
+ * is not entirely safe to use the strfoo() API to examine the contents
+ * of the return value.
+ **/
+SNV_INLINE char *
+filval (Filament *fil)
+{
+ /* Because we have been careful to ensure there is always at least
+ one spare byte of allocated memory, it is safe to set it here. */
+ fil->value[fil->length] = '\0';
+ return (char *) (fil->value);
+}
+
+/**
+ * fillen:
+ * @fil: The Filament object being queried.
+ *
+ * Return value:
+ * The length of @fil, including any embedded nulls, but excluding the
+ * terminating null, is returned.
+ **/
+SNV_INLINE size_t
+fillen (Filament *fil)
+{
+ return fil->length;
+}
+
+/**
+ * filelt:
+ * @fil: The Filament being queried.
+ * @n: A zero based index into @fil.
+ *
+ * This function looks for the @n'th element of @fil.
+ *
+ * Return value:
+ * If @n is an index inside the Filament @fil, then the character stored
+ * at that index cast to an int is returned, otherwise @n is outside
+ * this range and -1 is returned.
+ **/
+SNV_INLINE int
+filelt (Filament *fil, ssize_t n)
+{
+ if ((n >= 0) && (n < (ssize_t)fil->length))
+ return (int) fil->value[n];
+ else
+ return -1;
+}
+
+/**
+ * filncat:
+ * @fil: The destination Filament of the concatenation.
+ * @str: The address of the source bytes for concatenation.
+ * @n: The number of bytes to be copied from @str.
+ *
+ * @n bytes starting with the byte at address @str are destructively
+ * concatenated to @fil. If necessary, @fil is dynamically reallocated
+ * to make room for this operation.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filncat (Filament *fil, const char *str, size_t n)
+{
+ fil_maybe_extend (fil, n + fil->length, true);
+ memcpy (fil->value + fil->length, str, n);
+ fil->length += n;
+ return fil->value;
+}
+
+/**
+ * filcat:
+ * @fil: The destination Filament of the concatenation.
+ * @str: The address of the source bytes for concatenation.
+ *
+ * The bytes starting at address @str upto and including the first null
+ * byte encountered are destructively concatenated to @fil. If
+ * necessary @fil is dynamically reallocated to make room for this
+ * operation.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filcat (Filament *fil, const char *str)
+{
+ size_t length = strlen (str);
+ return filncat (fil, str, length);
+}
+
+/**
+ * filccat:
+ * @fil: The destination Filament of the concatenation.
+ * @c: The character to append to @fil.
+ *
+ * @c is destructively concatenated to @fil. If necessary, @fil is
+ * dynamically reallocated to make room for this operation. When used
+ * repeatedly this function is less efficient than %filncat,
+ * since it must check whether to extend the filament before each
+ * character is appended.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filccat (Filament *fil, int c)
+{
+ fil_maybe_extend (fil, 1 + fil->length, true);
+ fil->value[fil->length++] = c;
+ return fil->value;
+}
+
+#ifdef __cplusplus
+#if 0
+/* This brace is so that emacs can still indent properly: */
+{
+#endif
+}
+#endif /* __cplusplus */
+
+#endif /* FILAMENT_H */
+
+/* filament.h ends here */
diff --git a/snprintfv/filament.in b/snprintfv/filament.in
new file mode 100644
index 0000000..0fb8923
--- /dev/null
+++ b/snprintfv/filament.in
@@ -0,0 +1,197 @@
+/* -*- Mode: C -*- */
+
+/* filament.h --- a bit like a string but different =)O|
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef FILAMENT_H
+#define FILAMENT_H 1
+
+#include <snprintfv/compat.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+/* This brace is so that emacs can still indent properly: */ }
+#endif
+#endif /* __cplusplus */
+
+#define FILAMENT_BUFSIZ (512 - sizeof(char *) - (2 * sizeof(size_t)))
+
+/**
+ * Filament:
+ * Opaque data type used to hold 8-bit clean dynamic strings which know
+ * their own length and resize themselves to avoid buffer overruns.
+ **/
+typedef struct filament Filament;
+
+struct filament
+{
+ char *value; /* pointer to the start of the string */
+ size_t length; /* length of the string */
+ size_t size; /* total memory allocated */
+ char buffer[FILAMENT_BUFSIZ]; /* usually string == &buffer[0] */
+};
+
+@protos filament.c
+
+/* Save the overhead of a function call in the great majority of cases. */
+#define fil_maybe_extend(fil, len, copy) \
+ (((len)>=(fil)->size) ? _fil_extend((fil), (len), (copy)) : (void)0)
+
+/**
+ * filval:
+ * @fil: The Filament object being queried.
+ *
+ * Return value:
+ * A pointer to the null terminated string held by the Filament
+ * object is returned. Since the @fil may contain embedded nulls, it
+ * is not entirely safe to use the strfoo() API to examine the contents
+ * of the return value.
+ **/
+SNV_INLINE char *
+filval (Filament *fil)
+{
+ /* Because we have been careful to ensure there is always at least
+ one spare byte of allocated memory, it is safe to set it here. */
+ fil->value[fil->length] = '\0';
+ return (char *) (fil->value);
+}
+
+/**
+ * fillen:
+ * @fil: The Filament object being queried.
+ *
+ * Return value:
+ * The length of @fil, including any embedded nulls, but excluding the
+ * terminating null, is returned.
+ **/
+SNV_INLINE size_t
+fillen (Filament *fil)
+{
+ return fil->length;
+}
+
+/**
+ * filelt:
+ * @fil: The Filament being queried.
+ * @n: A zero based index into @fil.
+ *
+ * This function looks for the @n'th element of @fil.
+ *
+ * Return value:
+ * If @n is an index inside the Filament @fil, then the character stored
+ * at that index cast to an int is returned, otherwise @n is outside
+ * this range and -1 is returned.
+ **/
+SNV_INLINE int
+filelt (Filament *fil, ssize_t n)
+{
+ if ((n >= 0) && (n < (ssize_t)fil->length))
+ return (int) fil->value[n];
+ else
+ return -1;
+}
+
+/**
+ * filncat:
+ * @fil: The destination Filament of the concatenation.
+ * @str: The address of the source bytes for concatenation.
+ * @n: The number of bytes to be copied from @str.
+ *
+ * @n bytes starting with the byte at address @str are destructively
+ * concatenated to @fil. If necessary, @fil is dynamically reallocated
+ * to make room for this operation.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filncat (Filament *fil, const char *str, size_t n)
+{
+ fil_maybe_extend (fil, n + fil->length, true);
+ memcpy (fil->value + fil->length, str, n);
+ fil->length += n;
+ return fil->value;
+}
+
+/**
+ * filcat:
+ * @fil: The destination Filament of the concatenation.
+ * @str: The address of the source bytes for concatenation.
+ *
+ * The bytes starting at address @str upto and including the first null
+ * byte encountered are destructively concatenated to @fil. If
+ * necessary @fil is dynamically reallocated to make room for this
+ * operation.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filcat (Filament *fil, const char *str)
+{
+ size_t length = strlen (str);
+ return filncat (fil, str, length);
+}
+
+/**
+ * filccat:
+ * @fil: The destination Filament of the concatenation.
+ * @c: The character to append to @fil.
+ *
+ * @c is destructively concatenated to @fil. If necessary, @fil is
+ * dynamically reallocated to make room for this operation. When used
+ * repeatedly this function is less efficient than %filncat,
+ * since it must check whether to extend the filament before each
+ * character is appended.
+ *
+ * Return value:
+ * A pointer to the (not null terminated) string which is the result
+ * of this concatenation is returned.
+ **/
+SNV_INLINE char *
+filccat (Filament *fil, int c)
+{
+ fil_maybe_extend (fil, 1 + fil->length, true);
+ fil->value[fil->length++] = c;
+ return fil->value;
+}
+
+#ifdef __cplusplus
+#if 0
+/* This brace is so that emacs can still indent properly: */
+{
+#endif
+}
+#endif /* __cplusplus */
+
+#endif /* FILAMENT_H */
+
+/* filament.h ends here */
diff --git a/snprintfv/filament.stamp b/snprintfv/filament.stamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/snprintfv/filament.stamp
diff --git a/snprintfv/format.c b/snprintfv/format.c
new file mode 100644
index 0000000..bed8d17
--- /dev/null
+++ b/snprintfv/format.c
@@ -0,0 +1,1275 @@
+/* -*- Mode: C -*- */
+
+/* format.c --- printf clone for argv arrays
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#include "compat.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#include <sys/limits.h>
+#endif
+
+#ifdef WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include <float.h>
+#include <math.h>
+#include <stddef.h>
+
+#if HAVE_RUNETYPE_H
+# include <runetype.h>
+#endif
+
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#include "printf.h"
+
+#ifndef NO_FLOAT_PRINTING
+# ifdef HAVE_LONG_DOUBLE
+# ifndef HAVE_ISNANL
+# define isnanl(x) ((x) != (x))
+# endif
+# ifndef HAVE_ISINFL
+# define isinfl(x) isnanl ((x) - (x))
+# endif
+# ifndef HAVE_MODFL
+static snv_long_double modfl (long double x, long double *exp);
+# endif
+# ifndef HAVE_COPYSIGNL
+static snv_long_double copysignl (long double x, long double y);
+# endif
+# else
+# ifdef HAVE_ISNAN
+# define isnanl isnan
+# else
+# define isnanl(x) ((x) != (x))
+# endif
+# ifdef HAVE_ISINF
+# define isinfl isinf
+# else
+# define isinfl(x) isnanl ((x) - (x))
+# endif
+# ifdef HAVE_COPYSIGN
+# define copysignl copysign
+# else
+# define copysign(x, y) (((x) < 0.0 ^ (y) < 0.0) ? (x) * -1.0 : (x));
+# endif
+# define modfl modf
+# endif
+#endif
+
+
+static uintmax_t
+fetch_uintmax (struct printf_info *pinfo, union printf_arg const *arg)
+{
+ if (pinfo->is_long_double)
+ return (uintmax_t) arg->pa_u_long_long_int;
+
+ if (pinfo->is_long)
+ return (uintmax_t) arg->pa_u_long_int;
+
+ if (pinfo->is_short)
+ return (uintmax_t) arg->pa_u_short_int;
+
+ if (pinfo->is_char)
+ return (uintmax_t) arg->pa_char;
+
+ return (uintmax_t) arg->pa_u_int;
+}
+
+static intmax_t
+fetch_intmax (struct printf_info *pinfo, union printf_arg const *arg)
+{
+ if (pinfo->is_long_double)
+ return (intmax_t) (signed long long) arg->pa_long_long_int;
+
+ if (pinfo->is_long)
+ return (intmax_t) (signed long) arg->pa_long_int;
+
+ if (pinfo->is_short)
+ return (intmax_t) (signed short) arg->pa_short_int;
+
+ if (pinfo->is_char)
+ return (intmax_t) (signed char) arg->pa_char;
+
+ return (intmax_t) (signed int) arg->pa_int;
+}
+
+#ifndef NO_FLOAT_PRINTING
+static snv_long_double
+fetch_double (struct printf_info *pinfo, union printf_arg const *arg)
+{
+ if (pinfo->is_long_double)
+ return (snv_long_double) arg->pa_long_double;
+ else
+ return (snv_long_double) (arg->pa_double);
+}
+#endif
+
+
+#ifndef NO_FLOAT_PRINTING
+
+/* These two routines are cleaned up version of the code in libio 2.95.3
+ (actually I got it from the Attic, not from the released tarball).
+ The changes were mainly to share code between %f and %g (libio did
+ share some code between %e and %g), and to share code between the
+ %e and %f when invoked by %g. Support from infinities and NaNs comes
+ from the old snprintfv code. */
+
+typedef struct {
+ int pfs_prec;
+ int fmtch;
+ int expcnt;
+ int gformat;
+ char * scan_back_pz;
+ char * out_pz;
+ char * start_pz;
+ char * pfs_end;
+ snv_long_double fract;
+ snv_long_double integer;
+ snv_long_double tmp;
+} print_float_status_t;
+
+static char *
+print_float_round (snv_long_double fract, int *exp, char *start, char *end,
+ char ch, int *signp)
+{
+ snv_long_double tmp;
+ if (fract)
+ (void) modfl (fract * 10, &tmp);
+ else
+ tmp = ch - '0';
+
+ if (tmp > 4)
+ for (;; --end)
+ {
+ if (*end == '.')
+ --end;
+ if (end == start)
+ {
+ if (exp) /* e/E; increment exponent */
+ ++end, ++*exp;
+
+ *end = '1';
+ break;
+ }
+ if (++*end <= '9')
+ break;
+ *end = '0';
+ }
+
+ /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
+ else if (*signp == '-')
+ for (;; --end)
+ {
+ if (*end == '.')
+ --end;
+ if (*end != '0')
+ break;
+ if (end == start)
+ *signp = 0;
+ }
+ return (start);
+}
+
+static void
+fiddle_precision (print_float_status_t * pfs)
+{
+ /* %e/%f/%#g add 0's for precision, others trim 0's */
+ if (pfs->gformat && !pinfo->alt)
+ {
+ while (pfs->out_pz > pfs->start_pz && *--pfs->out_pz == '0');
+ if (*pfs->out_pz != '.')
+ ++pfs->out_pz;
+ }
+ else
+ for (; pfs->pfs_prec--; *pfs->out_pz++ = '0');
+}
+
+static void
+do_fformat (print_float_status_t * pfs)
+{
+ /* reverse integer into beginning of buffer */
+ if (pfs->expcnt)
+ for (; ++pfs->scn_bk_pz < pfs->pfs_end; *pfs->out_pz++ = *pfs->scn_bk_pz);
+ else
+ *pfs->out_pz++ = '0';
+
+ /* If precision required or alternate flag set, add in a
+ decimal point. */
+ if (pinfo->prec || pinfo->alt)
+ *pfs->out_pz++ = '.';
+
+ /* if requires more precision and some fraction left */
+ if (pfs->fract)
+ {
+ if (pfs->pfs_prec)
+ {
+ /* For %g, if no integer part, don't count initial
+ zeros as significant digits. */
+ do
+ {
+ pfs->fract = modfl (pfs->fract * 10, &pfs->tmp);
+ *pfs->out_pz++ = '0' + ((int) pfs->tmp);
+ }
+ while (!pfs->tmp && !pfs->expcnt && pfs->gformat);
+
+ while (--pfs->pfs_prec && pfs->fract)
+ {
+ pfs->fract = modfl (pfs->fract * 10, &pfs->tmp);
+ *pfs->out_pz++ = '0' + ((int) pfs->tmp);
+ }
+ }
+
+ if (pfs->fract)
+ pfs->start_pz =
+ print_float_round (pfs->fract, (int *) NULL, pfs->start_pz,
+ pfs->out_pz - 1, (char) 0, signp);
+ }
+
+ fiddle_precision (pfp);
+}
+
+static void
+do_eformat (print_float_status_t * pfs)
+{
+ if (pfs->expcnt)
+ {
+ *pfs->out_pz++ = *++pfs->scn_bk_pz;
+ if (pinfo->prec || pinfo->alt)
+ *pfs->out_pz++ = '.';
+
+ /* if requires more precision and some integer left */
+ for (; pfs->pfs_prec && ++pfs->scn_bk_pz < pfs->pfs_end; --pfs->pfs_prec)
+ *pfs->out_pz++ = *pfs->scn_bk_pz;
+
+ /* if done precision and more of the integer component,
+ round using it; adjust fract so we don'pfs->out_pz re-round
+ later. */
+ if (!pfs->pfs_prec && ++pfs->scn_bk_pz < pfs->pfs_end)
+ {
+ pfs->fract = 0;
+ pfs->start_pz = print_float_round (
+ (snv_long_double) 0, &pfs->expcnt, pfs->start_pz, pfs->out_pz - 1,
+ *pfs->scn_bk_pz, signp);
+ }
+
+ /* adjust expcnt for digit in front of decimal */
+ --pfs->expcnt;
+ }
+
+ /* until first fractional digit, decrement exponent */
+ else if (pfs->fract)
+ {
+ /* adjust expcnt for digit in front of decimal */
+ for (pfs->expcnt = -1;; --pfs->expcnt)
+ {
+ pfs->fract = modfl (pfs->fract * 10, &pfs->tmp);
+ if (pfs->tmp)
+ break;
+ }
+ *pfs->out_pz++ = '0' + ((int) pfs->tmp);
+ if (pinfo->prec || pinfo->alt)
+ *pfs->out_pz++ = '.';
+ }
+
+ else
+ {
+ *pfs->out_pz++ = '0';
+ if (pinfo->prec || pinfo->alt)
+ *pfs->out_pz++ = '.';
+ }
+
+ /* if requires more precision and some fraction left */
+ if (pfs->fract)
+ {
+ if (pfs->pfs_prec)
+ do
+ {
+ pfs->fract = modfl (pfs->fract * 10, &pfs->tmp);
+ *pfs->out_pz++ = '0' + ((int) pfs->tmp);
+ }
+ while (--pfs->pfs_prec && pfs->fract);
+
+ if (pfs->fract)
+ pfs->start_pz = print_float_round (
+ pfs->fract, &pfs->expcnt, pfs->start_pz, pfs->out_pz - 1,
+ (char) 0, signp);
+ }
+
+ fiddle_precision (pfp);
+
+ if (pfs.fmtch != 'e' && pfs.fmtch != 'E')
+ return;
+
+ {
+ char expbuf[10];
+ *pfs.out_pz++ = pfs.fmtch;
+ if (pfs.expcnt < 0)
+ {
+ pfs.expcnt = -pfs.expcnt;
+ *pfs.out_pz++ = '-';
+ }
+ else
+ *pfs.out_pz++ = '+';
+
+ pfs.scn_bk_pz = expbuf;
+ do
+ *pfs.scn_bk_pz++ = '0' + (pfs.expcnt % 10);
+ while ((pfs.expcnt /= 10) > 9);
+ *pfs.scn_bk_pz++ = '0' + pfs.expcnt;
+ while (pfs.scn_bk_pz > expbuf)
+ *pfs.out_pz++ = *--pfs.scn_bk_pz;
+ }
+}
+
+static void
+do_gformat (print_float_status_t * pfs)
+{
+ pfs->gformat = 1;
+
+ /* a precision of 0 is treated as a precision of 1. */
+ if (!pfs->pfs_prec)
+ pinfo->prec = ++pfs->pfs_prec;
+
+ /* ``The style used depends on the value converted; style e
+ will be used only if the exponent resulting from the
+ conversion is less than -4 or greater than the precision.''
+ -- ANSI X3J11 */
+ if ( (pfs->expcnt > pfs->pfs_prec)
+ || (!pfs->expcnt && pfs->fract && pfs->fract < .0001L))
+ {
+ /* g/G format counts "significant digits, not digits of
+ precision; for the e/E format, this just causes an
+ off-by-one problem, i.e. g/G considers the digit
+ before the decimal point significant and e/E doesn't
+ count it as precision. */
+ --pfs->pfs_prec;
+ pfs->fmtch -= 2; /* G->E, g->e */
+ do_eformat (pfs);
+ }
+ else
+ {
+ /* Decrement precision */
+ if (fnum != 0.0L)
+ pfs->pfs_prec -= (pfs->pfs_end - pfs->scn_bk_pz) - 1;
+ else
+ pfs->pfs_prec--;
+
+ do_fformat (pfs);
+ }
+}
+
+static int
+print_float (struct printf_info *pinfo, char *startp, char *endp, int *signp,
+ snv_long_double fnum)
+{
+ print_float_status_t pfs = {
+ .pfs_prec = pinfo->prec,
+ .pfs_end = endp,
+ .fmtch = pinfo->spec,
+ .out_pz = startp,
+ .start_pz = startp,
+ .gformat = 0
+ };
+
+ *signp = 0;
+
+ /* Do the special cases: nans, infinities, zero, and negative numbers. */
+ if (isnanl (fnum))
+ {
+ /* Not-a-numbers are printed as a simple string. */
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'N' : 'n';
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'A' : 'a';
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'N' : 'n';
+ return pfs.out_pz - pfs.start_pz;
+ }
+
+ /* Zero and infinity also can have a sign in front of them. */
+ if (copysignl (1.0, fnum) < 0.0)
+ {
+ fnum = -1.0 * fnum;
+ *signp = '-';
+ }
+
+ if (isinfl (fnum))
+ {
+ /* Infinities are printed as a simple string. */
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'I' : 'i';
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'N' : 'n';
+ *pfs.out_pz++ = pfs.fmtch < 'a' ? 'F' : 'f';
+ goto set_signp;
+ }
+
+ pfs.expcnt = 0;
+ pfs.fract = modfl (fnum, &pfs.integer);
+
+ /* get an extra slot for rounding. */
+ *pfs.out_pz++ = '0';
+
+ /* get integer portion of number; put into the end of the buffer; the
+ .01 is added for modfl (356.0 / 10, &integer) returning .59999999... */
+ for (pfs.scn_bk_pz = pfs.pfs_end - 1;
+ pfs.scn_bk_pz >= pfs.start_pz && pfs.integer;
+ ++pfs.expcnt)
+ {
+ pfs.tmp = modfl (pfs.integer / 10, &pfs.integer);
+ *pfs.scn_bk_pz-- = '0' + ((int) ((pfs.tmp + .01L) * 10));
+ }
+
+ switch (pfs.fmtch)
+ {
+ case 'g':
+ case 'G':
+ do_gformat (&pfs);
+ break;
+
+ case 'f':
+ case 'F':
+ do_fformat (&pfs);
+ break;
+
+ case 'e':
+ case 'E':
+ do_eformat (&pfs);
+ break;
+
+ default:
+ abort ();
+ }
+
+set_signp:
+ if (!*signp)
+ {
+ if (pinfo->showsign)
+ *signp = '+';
+ else if (pinfo->space)
+ *signp = ' ';
+ }
+
+ return (pfs.out_pz - pfs.start_pz);
+}
+#endif
+
+
+static int
+printf_flag_info (struct printf_info *const pinfo, size_t n, int *argtypes)
+{
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+ (void)n;
+ (void)argtypes;
+
+ if (!(pinfo->state & (SNV_STATE_BEGIN | SNV_STATE_FLAG)))
+ {
+ PRINTF_ERROR (pinfo, "invalid specifier");
+ return -1;
+ }
+
+ pinfo->state = SNV_STATE_FLAG;
+
+ while (pinfo->state & SNV_STATE_FLAG)
+ {
+ switch (*pinfo->format)
+ {
+ case '#':
+ pinfo->alt = true;
+ pinfo->format++;
+ break;
+
+ case '0':
+ if (!pinfo->left)
+ pinfo->pad = '0';
+ pinfo->format++;
+ break;
+
+ case '-':
+ pinfo->pad = ' ';
+ pinfo->left = true;
+ pinfo->format++;
+ break;
+
+ case ' ':
+ pinfo->space = true;
+ pinfo->format++;
+ break;
+
+ case '+':
+ pinfo->showsign = true;
+ pinfo->format++;
+ break;
+
+ case '\'':
+ pinfo->group = true;
+ pinfo->format++;
+ break;
+
+ default:
+ pinfo->state = ~(SNV_STATE_BEGIN | SNV_STATE_FLAG);
+ break;
+ }
+ }
+
+ pinfo->format--;
+
+ /* Return the number of characters emitted. */
+ return 0;
+}
+
+/* This function has considerably more freedom than the others in
+ playing with pinfo; in particular, it modifies argindex and can
+ return completely bogus values whose only purpose is to extend
+ the argtypes vector so that it has enough items for the positional
+ parameter of the width (in the *n$ case). It also expects that
+ argtypes = (base of argtypes vector) + pinfo->argindex.
+
+ This is messy, suggestion for simplifying it are gladly accepted. */
+static int
+printf_numeric_param_info (struct printf_info *const pinfo, size_t n, int *argtypes)
+{
+ const char *pEnd = NULL;
+ int found = 0, allowed_states, new_state;
+ int position = 0, skipped_args = 0;
+ long value;
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* If we are looking at a ``.'', then this is a precision parameter. */
+ if (*pinfo->format == '.')
+ {
+ pinfo->format++;
+ found |= 1;
+ }
+
+ /* First we might have a ``*''. */
+ if (*pinfo->format == '*')
+ {
+ pinfo->format++;
+ found |= 2;
+ }
+
+ /* Parse the number. */
+ for (pEnd = pinfo->format, value = 0; *pEnd >= '0' && *pEnd <= '9'; pEnd++)
+ value = value * 10 + (*pEnd - '0');
+
+ if (pEnd > pinfo->format)
+ {
+ pinfo->format = pEnd;
+ found |= 4;
+ }
+
+ if (value > INT_MAX)
+ {
+ PRINTF_ERROR (pinfo, "out of range");
+ return -1;
+ }
+
+ /* And finally a dollar sign. */
+ if (*pinfo->format == '$')
+ {
+ if (value == 0)
+ {
+ PRINTF_ERROR (pinfo, "invalid position specifier");
+ return -1;
+ }
+
+ position = value;
+ pinfo->format++;
+ found |= 8;
+ }
+
+ switch (found & 14)
+ {
+ /* We found a * specification */
+ case 2:
+ if (pinfo->args)
+ value = pinfo->args[pinfo->argindex].pa_int;
+ if (n)
+ argtypes[0] = PA_INT;
+ pinfo->argindex++;
+ skipped_args = 1;
+ found ^= 6;
+ break;
+
+ /* We found a *n$ specification */
+ case 14:
+ if (n + pinfo->argindex > (unsigned)position - 1)
+ argtypes[position - 1 - pinfo->argindex] = PA_INT;
+
+ /* Else there is not enough space, reallocate and retry please...
+ ... but we must say how much to skip. */
+ if (position >= pinfo->argindex)
+ skipped_args = position - pinfo->argindex;
+
+ if (pinfo->args)
+ value = pinfo->args[position - 1].pa_int;
+ found ^= 10;
+ break;
+ }
+
+ switch (found)
+ {
+ /* We must have read a width specification. */
+ case 4:
+ allowed_states = SNV_STATE_BEGIN | SNV_STATE_WIDTH;
+ new_state = ~(SNV_STATE_BEGIN | SNV_STATE_FLAG | SNV_STATE_WIDTH);
+
+ /* How awful... */
+ if (value < 0)
+ {
+ pinfo->pad = ' ';
+ pinfo->left = true;
+ value = -value;
+ }
+
+ pinfo->width = value;
+ break;
+
+ /* We must have read a precision specification. */
+ case 5:
+ allowed_states = SNV_STATE_PRECISION | SNV_STATE_BEGIN;
+ new_state = SNV_STATE_MODIFIER | SNV_STATE_SPECIFIER;
+ pinfo->prec = value;
+ break;
+
+ /* We must have read a position specification. */
+ case 12:
+ allowed_states = SNV_STATE_BEGIN;
+ new_state = ~SNV_STATE_BEGIN;
+ pinfo->dollar = position;
+ break;
+
+ /* We must have read something bogus. */
+ default:
+ PRINTF_ERROR (pinfo, "invalid specifier");
+ return -1;
+ }
+
+ if (!(pinfo->state & allowed_states))
+ {
+ PRINTF_ERROR (pinfo, "invalid specifier");
+ return -1;
+ }
+
+ pinfo->state = new_state;
+ pinfo->format--;
+ return skipped_args;
+}
+
+static int
+printf_modifier_info (struct printf_info *const pinfo, size_t n, int *argtypes)
+{
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+ (void)n;
+ (void)argtypes;
+
+ /* Check for valid pre-state. */
+ if (!(pinfo->state & (SNV_STATE_BEGIN | SNV_STATE_MODIFIER)))
+ {
+ PRINTF_ERROR (pinfo, "out of range");
+ return -1;
+ }
+
+ while (pinfo->state != SNV_STATE_SPECIFIER)
+ {
+ switch (*pinfo->format)
+ {
+ case 'h':
+ if (*++pinfo->format != 'h')
+ {
+ pinfo->is_short = true;
+ break;
+ }
+
+ pinfo->is_char = true;
+ pinfo->format++;
+ break;
+
+ case 'z':
+ if (sizeof (size_t) > sizeof (char *))
+ pinfo->is_long_double = true;
+ else
+ pinfo->is_long = true;
+
+ pinfo->format++;
+ break;
+
+ case 't':
+ if (sizeof (ptrdiff_t) > sizeof (char *))
+ pinfo->is_long_double = true;
+ else
+ pinfo->is_long = true;
+
+ pinfo->format++;
+ break;
+
+ case 'l':
+ if (*++pinfo->format != 'l')
+ {
+ pinfo->is_long = true;
+ break;
+ }
+ /*FALLTHROUGH*/
+
+ case 'j':
+ case 'q':
+ case 'L':
+ pinfo->is_long_double = true;
+ pinfo->format++;
+ break;
+
+ default:
+ pinfo->state = SNV_STATE_SPECIFIER;
+ pinfo->format--;
+ break;
+ }
+ }
+
+ /* Return the number of characters emitted. */
+ return 0;
+}
+
+
+static int
+printf_char (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ int count_or_errorcode = SNV_OK;
+ char ch = '\0';
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec != -1
+ || pinfo->is_char || pinfo->is_short || pinfo->is_long
+ || pinfo->is_long_double || pinfo->pad == '0'
+ || pinfo->alt || pinfo->space || pinfo->showsign)
+ {
+ PRINTF_ERROR (pinfo, "invalid flags");
+ return -1;
+ }
+
+ /* Extract the correct argument from the arg vector. */
+ ch = args->pa_char;
+
+ /* Left pad to the width if the supplied argument is less than
+ the width specifier. */
+ if ((pinfo->width > 1) && !pinfo->left)
+ {
+ int padwidth = pinfo->width - 1;
+
+ while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+ }
+
+ /* Emit the character argument. */
+ SNV_EMIT (ch, stream, count_or_errorcode);
+
+ /* Right pad to the width if we still didn't reach the specified
+ width and the left justify flag was set. */
+ if ((count_or_errorcode < pinfo->width) && pinfo->left)
+ while ((count_or_errorcode >= 0)
+ && (count_or_errorcode < pinfo->width))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Return the number of characters emitted. */
+ return count_or_errorcode;
+}
+
+#ifndef NO_FLOAT_PRINTING
+
+static int
+printf_float (STREAM *stream,
+ struct printf_info *const pinfo,
+ union printf_arg const *args)
+{
+ snv_long_double value = 0.0;
+ int sign, len, count_or_errorcode = SNV_OK;
+#ifdef HAVE_LONG_DOUBLE
+ char buffer[LDBL_MAX_10_EXP * 2 + 20], *p = buffer;
+#else
+ char buffer[DBL_MAX_10_EXP * 2 + 20], *p = buffer;
+#endif
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Check for valid pre-state */
+ if (pinfo->prec == -1)
+ pinfo->prec = SNV_POINTER_TO_LONG (pinfo->extra);
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec <= -1
+ || pinfo->is_char || pinfo->is_short || pinfo->is_long)
+ {
+ PRINTF_ERROR (pinfo, "invalid flags");
+ return -1;
+ }
+
+ /* Extract the correct argument from the arg vector. */
+ value = fetch_double (pinfo, args);
+
+ /* Convert the number into a string. */
+ len = print_float (pinfo, buffer, buffer + sizeof (buffer), &sign, value);
+ if (*buffer == '0')
+ p++, len--;
+
+ /* Compute the size of the padding. */
+ pinfo->width -= len;
+ if (sign)
+ pinfo->width--;
+
+ /* Left pad to the remaining width if the supplied argument is less
+ than the width specifier, and the padding character is ' '. */
+ if (pinfo->pad == ' ' && !pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Display any sign character. */
+ if (count_or_errorcode >= 0 && sign)
+ SNV_EMIT (sign, stream, count_or_errorcode);
+
+ /* Left pad to the remaining width if the supplied argument is less
+ than the width specifier, and the padding character is not ' '. */
+ if (pinfo->pad != ' ' && !pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Fill the stream buffer with as many characters from the number
+ buffer as possible without overflowing. */
+ while ((count_or_errorcode >= 0) && (len-- > 0))
+ SNV_EMIT (*p++, stream, count_or_errorcode);
+
+ /* Right pad to the width if we still didn't reach the specified
+ width and the left justify flag was set. */
+ if (pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Return the number of characters emitted. */
+ return count_or_errorcode;
+}
+#endif
+
+static int
+printf_count (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ (void)stream;
+
+ if (pinfo->is_char)
+ *(char *) (args->pa_pointer) = pinfo->count;
+
+ else if (pinfo->is_short)
+ *(short *) (args->pa_pointer) = pinfo->count;
+
+ else if (pinfo->is_long)
+ *(long *) (args->pa_pointer) = pinfo->count;
+
+ else if (pinfo->is_long_double)
+ *(intmax_t *) (args->pa_pointer) = pinfo->count;
+
+ else
+ *(int *) (args->pa_pointer) = pinfo->count;
+
+ return 0;
+}
+
+static int
+printf_integer (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ static const char digits_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static const char digits_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ const char *digits;
+
+ unsigned base = SNV_POINTER_TO_ULONG (pinfo->extra);
+ uintmax_t value = 0L;
+ int type, count_or_errorcode = SNV_OK;
+ char buffer[256], *p, *end;
+ bool is_negative = false;
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Check for valid pre-state. */
+ if (!(pinfo->state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
+ {
+ PRINTF_ERROR (pinfo, "out of range");
+ return -1;
+ }
+
+ /* Upper or lower-case hex conversion? */
+ digits = ((pinfo->spec >= 'a') && (pinfo->spec <= 'z'))
+ ? digits_lower : digits_upper;
+
+ if (pinfo->prec == -1)
+ pinfo->prec = 0;
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec < 0)
+ {
+ PRINTF_ERROR (pinfo, "invalid precision");
+ return -1;
+ }
+
+ type = pinfo->type;
+
+ /* Extract the correct argument from the arg vector. */
+ if (type & PA_FLAG_UNSIGNED)
+ {
+ value = fetch_uintmax (pinfo, args);
+ is_negative = false;
+ pinfo->showsign = pinfo->space = false;
+ }
+ else
+ {
+ intmax_t svalue = 0L;
+ svalue = fetch_intmax (pinfo, args);
+ is_negative = (svalue < 0);
+ value = (uintmax_t) ABS (svalue);
+ }
+
+ /* Convert the number into a string. */
+ p = end = &buffer[sizeof (buffer) - 1];
+
+ if (value == 0)
+ *p-- = '0';
+
+ else
+ while (value > 0)
+ {
+ *p-- = digits[value % base];
+ value /= base;
+ }
+
+ pinfo->width -= end - p;
+ pinfo->prec -= end - p;
+
+ /* Octal numbers have a leading zero in alterate form. */
+ if (pinfo->alt && base == 8)
+ {
+ *p-- = '0';
+ --pinfo->width;
+ }
+
+ /* Left pad with zeros to make up the precision. */
+ if (pinfo->prec > 0)
+ {
+ pinfo->width -= pinfo->prec;
+ while (pinfo->prec-- > 0)
+ *p-- = '0';
+ }
+
+ /* Reserve room for leading `0x' for hexadecimal. */
+ if (pinfo->alt && base == 16)
+ pinfo->width -= 2;
+
+ /* Reserve room for a sign character. */
+ if (is_negative || pinfo->showsign || pinfo->space)
+ --pinfo->width;
+
+ /* Left pad to the remaining width if the supplied argument is less
+ * than the width specifier, and the padding character is ' '.
+ */
+ if (pinfo->pad == ' ' && !pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Display any sign character. */
+ if (count_or_errorcode >= 0)
+ {
+ if (is_negative)
+ SNV_EMIT ('-', stream, count_or_errorcode);
+ else if (pinfo->showsign)
+ SNV_EMIT ('+', stream, count_or_errorcode);
+ else if (pinfo->space)
+ SNV_EMIT (' ', stream, count_or_errorcode);
+ }
+
+ /* Display `0x' for alternate hexadecimal specifier. */
+ if ((count_or_errorcode >= 0) && (base == 16) && pinfo->alt)
+ {
+ SNV_EMIT ('0', stream, count_or_errorcode);
+ SNV_EMIT (digits['X' - 'A' + 10], stream, count_or_errorcode);
+ }
+
+ /* Left pad to the remaining width if the supplied argument is less
+ * than the width specifier, and the padding character is not ' '.
+ */
+ if (pinfo->pad != ' ' && !pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Fill the stream buffer with as many characters from the number
+ * buffer as possible without overflowing.
+ */
+ while ((count_or_errorcode >= 0) && (++p < &buffer[sizeof (buffer)]))
+ SNV_EMIT (*p, stream, count_or_errorcode);
+
+ /* Right pad to the width if we still didn't reach the specified
+ * width and the left justify flag was set.
+ */
+ if (pinfo->left)
+ while ((count_or_errorcode >= 0) && (pinfo->width-- > 0))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Return the number of characters emitted. */
+ return count_or_errorcode;
+}
+
+static int
+printf_pointer (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ int count_or_errorcode = SNV_OK;
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Read these now to advance the argument pointer appropriately */
+ if (pinfo->prec == -1)
+ pinfo->prec = 0;
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec <= -1
+ || pinfo->is_char || pinfo->is_short || pinfo->is_long
+ || pinfo->is_long_double)
+ {
+ PRINTF_ERROR (pinfo, "invalid flags");
+ return -1;
+ }
+
+ /* Always print 0x. */
+ pinfo->alt = 1;
+ pinfo->is_long = sizeof(long) == sizeof (char *);
+ pinfo->is_long_double = sizeof(intmax_t) == sizeof (char *);
+
+ /* Use the standard routine for numbers for the printing call,
+ if the pointer is not NULL. */
+
+ if (args->pa_pointer != NULL)
+ return printf_integer (stream, pinfo, args);
+
+ /* Print a NULL pointer as (nil), appropriately padded. */
+ if ((pinfo->width > 5) && !pinfo->left)
+ {
+ int padwidth = pinfo->width - 5;
+ while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+ }
+
+ SNV_EMIT ('(', stream, count_or_errorcode);
+ SNV_EMIT ('n', stream, count_or_errorcode);
+ SNV_EMIT ('i', stream, count_or_errorcode);
+ SNV_EMIT ('l', stream, count_or_errorcode);
+ SNV_EMIT (')', stream, count_or_errorcode);
+
+ if ((pinfo->width > 5) && pinfo->left)
+ while ((count_or_errorcode >= 0)
+ && (count_or_errorcode < pinfo->width))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ return count_or_errorcode;
+}
+
+static int
+printf_string (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args)
+{
+ int len = 0, count_or_errorcode = SNV_OK;
+ const char *p = NULL;
+
+ return_val_if_fail (pinfo != NULL, SNV_ERROR);
+
+ /* Read these now to advance the argument pointer appropriately */
+ if (pinfo->prec == -1)
+ pinfo->prec = 0;
+
+ /* Check for valid pre-state. */
+ if (pinfo->prec <= -1
+ || pinfo->is_char || pinfo->is_short || pinfo->is_long
+ || pinfo->is_long_double)
+ {
+ PRINTF_ERROR (pinfo, "invalid flags");
+ return -1;
+ }
+
+ /* Extract the correct argument from the arg vector. */
+ p = args->pa_string;
+
+ /* Left pad to the width if the supplied argument is less than
+ the width specifier. */
+ if (p != NULL)
+ {
+ len = strlen (p);
+ if (pinfo->prec && pinfo->prec < len)
+ len = pinfo->prec;
+ }
+
+ if ((len < pinfo->width) && !pinfo->left)
+ {
+ int padwidth = pinfo->width - len;
+ while ((count_or_errorcode >= 0) && (count_or_errorcode < padwidth))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+ }
+
+ /* Fill the buffer with as many characters from the format argument
+ as possible without overflowing or exceeding the precision. */
+ if ((count_or_errorcode >= 0) && (p != NULL))
+ {
+ int mark = count_or_errorcode;
+ while ((count_or_errorcode >= 0) && *p != '\0'
+ && ((pinfo->prec == 0) || (count_or_errorcode - mark < len)))
+ SNV_EMIT (*p++, stream, count_or_errorcode);
+ }
+
+ /* Right pad to the width if we still didn't reach the specified
+ width and the left justify flag was set. */
+ if ((count_or_errorcode < pinfo->width) && pinfo->left)
+ while ((count_or_errorcode >= 0)
+ && (count_or_errorcode < pinfo->width))
+ SNV_EMIT (pinfo->pad, stream, count_or_errorcode);
+
+ /* Return the number of characters emitted. */
+ return count_or_errorcode;
+}
+
+
+
+/* replacements for modfl and copysignl follow. */
+
+#if !defined NO_FLOAT_PRINTING && defined HAVE_LONG_DOUBLE
+# ifndef HAVE_MODFL
+static long double modfl (long double x, long double *exp)
+{
+ /* To compute the integer part of a positive integer (in this case
+ abs(X)), sum a big enough integer to the absolute value, so that
+ the precision of the floating point number is exactly 1. Then
+ we round towards zero.
+
+ The code in the two branches is the same but it considers -x
+ if x is negative. */
+
+ long double z;
+ if (x < 0.0L)
+ {
+ z = 1.0L / LDBL_EPSILON - x - 1.0 / LDBL_EPSILON;
+ if (z + x > 0.0L)
+ z = z - 1.0L;
+
+ return (*exp = -z) + x;
+ }
+ else
+ {
+ z = 1.0L / LDBL_EPSILON + x - 1.0 / LDBL_EPSILON;
+ if (z > x)
+ z = z - 1.0L;
+
+ return x - (*exp = z);
+ }
+}
+# endif /* !HAVE_MODFL */
+
+# ifndef HAVE_COPYSIGNL
+long double
+copysignl (long double x, long double y)
+{
+# ifdef HAVE_COPYSIGN
+ return x * (long double) copysign (1.0, x * y);
+# else /* !HAVE_COPYSIGN */
+ /* If we do not have copysign, assume zero is unsigned (too risky to
+ assume we have infinities, which would allow to test with
+ (x < 0.0 && 1.0 / x < 0.0). */
+ return (x < 0.0 ^ y < 0.0) ? x * -1.0 : x;
+# endif /* !HAVE_COPYSIGN */
+}
+# endif /* !HAVE_COPYSIGNL */
+#endif /* !NO_FLOAT_PRINTING && HAVE_LONG_DOUBLE) */
+
+
+
+/* This is where the parsing of FORMAT strings is handled:
+
+ Each of these functions should inspect PPARSER for parser
+ state information; update PPARSER as necessary based on
+ the state discovered; possibly put some characters in STREAM, in
+ which case that number of characters must be returned. If the
+ handler detects that parsing (of the current specifier) is complete,
+ then it must set pinfo->state to SNV_STATE_END. The library will then
+ copy characters from the format string to STREAM until another unescaped
+ SNV_CHAR_SPEC is detected when the handlers will be called again. */
+
+spec_entry snv_default_spec_table[] = {
+ /* ch type function */
+ {' ', 0, 0, NULL, printf_flag_info, NULL},
+ {'#', 0, 0, NULL, printf_flag_info, NULL},
+ {'+', 0, 0, NULL, printf_flag_info, NULL},
+ {'-', 0, 0, NULL, printf_flag_info, NULL},
+ {'\'', 0, 0, NULL, printf_flag_info, NULL},
+ {'*', 0, PA_INT, NULL, printf_numeric_param_info, NULL},
+ {'$', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'.', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'0', 0, 0, NULL, printf_flag_info, NULL},
+ {'1', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'2', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'3', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'4', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'5', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'6', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'7', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'8', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'9', 0, 0, NULL, printf_numeric_param_info, NULL},
+ {'c', 0, PA_CHAR, printf_char, NULL, NULL},
+ {'d', 0, PA_INT, printf_integer, printf_generic_info, (snv_pointer) 10},
+#ifndef NO_FLOAT_PRINTING
+ {'e', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+ {'E', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+ {'f', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+ {'F', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+ {'g', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+ {'G', 0, PA_DOUBLE, printf_float, printf_generic_info, (snv_pointer) 6},
+#endif
+ {'h', 0, 0, NULL, printf_modifier_info, NULL},
+ {'i', 0, PA_INT, printf_integer, printf_generic_info, (snv_pointer) 10},
+ {'j', 0, 0, NULL, printf_modifier_info, NULL},
+ {'l', 0, 0, NULL, printf_modifier_info, NULL},
+ {'L', 0, 0, NULL, printf_modifier_info, NULL},
+ {'n', 0, PA_INT | PA_FLAG_PTR, printf_count, printf_generic_info, NULL},
+ {'o', 0, PA_INT | PA_FLAG_UNSIGNED,
+ printf_integer, printf_generic_info, (snv_pointer) 8},
+ {'p', 0, PA_POINTER, printf_pointer, NULL, (snv_pointer) 16},
+ {'q', 0, 0, NULL, printf_modifier_info, NULL},
+ {'s', 0, PA_STRING, printf_string, NULL, NULL},
+ {'t', 0, 0, NULL, printf_modifier_info, NULL},
+ {'u', 0, PA_INT | PA_FLAG_UNSIGNED,
+ printf_integer, printf_generic_info, (snv_pointer) 10},
+ {'x', 0, PA_INT | PA_FLAG_UNSIGNED,
+ printf_integer, printf_generic_info, (snv_pointer) 16},
+ {'X', 0, PA_INT | PA_FLAG_UNSIGNED,
+ printf_integer, printf_generic_info, (snv_pointer) 16},
+ {'z', 0, 0, NULL, printf_modifier_info, NULL},
+ {'\0', 0, PA_LAST, NULL, NULL, NULL}
+};
+
+/* format.c ends here */
diff --git a/snprintfv/mem.c b/snprintfv/mem.c
new file mode 100644
index 0000000..553492f
--- /dev/null
+++ b/snprintfv/mem.c
@@ -0,0 +1,82 @@
+/* -*- Mode: C -*- */
+
+/* mem.c --- memory management routines
+ * Copyright (C) 2002 Gary V. Vaughan
+ * Originally by Paolo Bonzini, 2002
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include "mem.h"
+
+
+/* We deliberately don't prototype the malloc functions; they are cast
+ to match the function pointers we expose to avoid compiler warnings
+ from mismatched prototypes (if we find a host implementation.
+
+ Not also that if this file is compiled -DWITH_DMALLOC, the inclusion
+ in mem.h will cause the malloc references below to be redirected
+ correctly. */
+malloc_proc_t* snv_malloc = (malloc_proc_t*)malloc;
+realloc_proc_t* snv_realloc = (realloc_proc_t*)realloc;
+free_proc_t* snv_free = (free_proc_t*)free;
+
+/* Unportable memory management functions are reimplemented tout court. */
+snv_pointer
+snv_xrealloc (snv_pointer old, size_t count)
+{
+ if (count < 1)
+ {
+ snv_free (old);
+ return NULL;
+ }
+ if (!old)
+ return snv_malloc (count);
+ else
+ return snv_realloc (old, count);
+}
+
+char *
+snv_strdup (const char *str)
+{
+ size_t len = strlen (str);
+ char *result = snv_malloc (len + 1);
+ memcpy (result, str, len + 1);
+ return result;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/mem.c */
diff --git a/snprintfv/mem.h b/snprintfv/mem.h
new file mode 100644
index 0000000..496cf53
--- /dev/null
+++ b/snprintfv/mem.h
@@ -0,0 +1,120 @@
+/* -*- Mode: C -*- */
+
+/* mem.h --- memory handling macros
+ * Copyright (C) 1999 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1999
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef SNPRINTFV_MEM_H
+#define SNPRINTFV_MEM_H 1
+
+#include <snprintfv/compat.h>
+
+#ifdef WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#ifdef _WIN32
+# ifdef DLL_EXPORT
+# define SNV_SCOPE extern __declspec(dllexport)
+# else
+# ifdef LIBSNPRINTFV_DLL_IMPORT
+# define SNV_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+#else
+# define SNV_SCOPE extern
+#endif
+
+/* This is the API we use throughout libsnprintfv. */
+#define snv_new(type, count) \
+ ((type*)snv_malloc((size_t)sizeof(type) * (count)))
+#define snv_renew(type, ptr, count) \
+ ((type*)snv_xrealloc((ptr), (size_t)sizeof(type) * (count)))
+#define snv_delete(old) snv_free(old)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef void* (malloc_proc_t )(size_t);
+typedef void* (realloc_proc_t)(snv_pointer, size_t);
+typedef void* (free_proc_t )(snv_pointer);
+
+/* These function pointers are exposed through the API incase a user
+ of this library needs to map our memory management routines to
+ their own (e.g. xmalloc). */
+
+/**
+ * snv_malloc:
+ * @count: The number of bytes to allocate.
+ *
+ * Allocates a fresh block of memory whose size is @count bytes.
+ *
+ * Return value:
+ * The pointer to the newly-allocated memory area.
+ */
+SNV_SCOPE malloc_proc_t *snv_malloc;
+
+/**
+ * snv_realloc:
+ * @old: The pointer to the block whose size must be changed.
+ * @count: The number of bytes to allocate.
+ *
+ * Reallocates a fresh block of memory pointed to by @old
+ * so that its size becomes @count bytes.
+ *
+ * Return value:
+ * The pointer to the newly-allocated memory area, possibly
+ * the same as @old.
+ */
+SNV_SCOPE realloc_proc_t *snv_realloc;
+
+/**
+ * snv_free:
+ * @old: The pointer to the block that must freed.
+ *
+ * Frees a block of memory pointed to by @old.
+ */
+SNV_SCOPE free_proc_t *snv_free;
+
+/* And these are reimplemented tout court because they are
+ not fully portable. */
+extern realloc_proc_t snv_xrealloc;
+extern char* snv_strdup (const char *str);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SNPRINTFV_MEM_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/mem.h */
diff --git a/snprintfv/printf.c b/snprintfv/printf.c
new file mode 100644
index 0000000..58927a9
--- /dev/null
+++ b/snprintfv/printf.c
@@ -0,0 +1,1568 @@
+/* -*- Mode: C -*- */
+
+/* printf.c --- printf clone for argv arrays
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <unistd.h> /* for the write(2) call */
+
+#ifdef HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(_e)
+#endif
+
+#define COMPILING_PRINTF_C
+#include "printf.h"
+
+#ifdef WITH_DMALLOC
+#include <dmalloc.h>
+#endif
+
+#include "filament.h"
+#include "stream.h"
+#include "mem.h"
+
+#ifdef SNV_LIBRARY_BUILD
+# include "dl.h"
+#else
+
+# ifndef HAVE_STRTOUL
+# include "strtoul.c"
+# endif
+#endif /* SNV_LIBRARY_BUILD */
+
+#define EOS '\0'
+#define SNV_CHAR_SPEC '%'
+#define SNV_ESC_SPEC '\\'
+
+/* Functions to manage mapping of spec chars to handlers. */
+SNV_INLINE unsigned spec_hash (unsigned spec);
+SNV_INLINE void spec_init (void);
+SNV_INLINE spec_entry *spec_lookup (unsigned spec);
+static void spec_insert (spec_entry * pentry);
+static int do_printfv (STREAM *stream, const char *format,
+ union printf_arg const args[]);
+
+/* FIXME: We are assuming an ASCII character set where all the
+ printable characters are between SPACE and DEL. */
+#define ASCII_DEL (int)'\177'
+#define ASCII_SPACE (int)' '
+
+#define IS_MODIFIER(spec) (!((spec)->fmt))
+
+/* TODO: This is not thread-safe. Change the API to pass the spec_table
+ in as the first parameter to the functions which use it? */
+static spec_entry *spec_table[ASCII_DEL - ASCII_SPACE];
+
+/* TODO: This is not thread-safe as well. */
+static char *printf_last_error;
+
+SNV_INLINE unsigned
+spec_hash (unsigned spec)
+{
+ return (spec & ASCII_DEL) - ASCII_SPACE;
+}
+
+/* Register all of the functions in INIT_SPEC_TABLE. */
+static void
+spec_init (void)
+{
+ static bool is_init = false;
+
+ if (!is_init)
+ {
+ extern spec_entry snv_default_spec_table[];
+ unsigned ix;
+
+ memset (spec_table, 0, sizeof (spec_table));
+ for (ix = 0; snv_default_spec_table[ix].spec_key != EOS; ix++)
+ {
+ unsigned hash = spec_hash (snv_default_spec_table[ix].spec_key);
+ spec_table[hash] = snv_default_spec_table + ix;
+ }
+
+ is_init = true;
+ }
+}
+
+/* Insert PENTRY, a new handler, into SPEC_TABLE. */
+SNV_INLINE void
+spec_insert (spec_entry *pentry)
+{
+ unsigned hash = spec_hash (pentry->spec_key);
+ spec_init ();
+ spec_table[hash] = pentry;
+}
+
+/* Lookup and return the SPEC_TABLE entry for SPEC. */
+SNV_INLINE spec_entry *
+spec_lookup (unsigned spec)
+{
+ unsigned hash = spec_hash (spec);
+ spec_init ();
+ return spec_table[hash];
+}
+
+/**
+ * register_printf_function: printf.h
+ * @spec: the character which will trigger @func, cast to an unsigned int.
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments
+ * to the specifier
+ *
+ * Register the pair made of @fmt and @arg, so that it is called
+ * when @spec is encountered in a format string.
+ *
+ * Return value:
+ * Returns %NULL if @func was not successfully registered, a
+ * %spec_entry with the information on the function if it was.
+ **/
+spec_entry *
+register_printf_function (unsigned spec, printf_function *fmt,
+ printf_arginfo_function *arg)
+{
+ spec_entry *new, *old;
+ old = spec_lookup (spec);
+ if (old && IS_MODIFIER (old))
+ return NULL;
+
+ if (!fmt || !spec)
+ return NULL;
+
+ new = snv_new (spec_entry, 1);
+ new->spec_key = spec;
+ new->fmt = fmt;
+ new->arg = arg;
+ new->user = NULL;
+
+ spec_insert (new);
+
+ return new;
+}
+
+static int
+call_argtype_function (
+ struct printf_info *const pinfo,
+ int **argtypes,
+ spec_entry *spec)
+{
+ int n;
+ int argindex = (pinfo->dollar && !IS_MODIFIER (spec))
+ ? pinfo->dollar - 1
+ : pinfo->argindex;
+
+ int save_argindex = pinfo->argindex;
+ int save_state = pinfo->state;
+ char const *save_format = pinfo->format;
+
+ if (!spec->arg)
+ {
+ n = 1;
+ if (pinfo->argc <= argindex)
+ {
+ /*
+ * "argtypes" points to a pointer of an array of int values.
+ * Here, we ensure that there are "argindex + 1" entries in
+ * that array.
+ */
+ *argtypes = snv_renew (int, *argtypes, argindex + 1);
+
+ /*
+ * IF there are more entries that follow the current argument
+ * index, then we will clobber all the entries that follow.
+ * The size of these entries is the size of the array elements,
+ * not the size of the pointer to the array elements.
+ */
+ if (pinfo->argc < argindex)
+ memset(*argtypes + pinfo->argc, PA_UNKNOWN,
+ (argindex - pinfo->argc) * sizeof(**argtypes));
+
+ pinfo->argc = argindex + 1;
+ }
+
+ (*argtypes) [argindex] = spec->type;
+ }
+
+ else
+ {
+ pinfo->spec = (unsigned)*(pinfo->format);
+ pinfo->extra = spec->user;
+ pinfo->type = spec->type;
+
+ if (pinfo->argc > argindex)
+ n = spec->arg(pinfo, (size_t) (pinfo->argc - argindex),
+ *argtypes + argindex);
+ else
+ n = spec->arg(pinfo, (size_t)0, NULL);
+
+ if (n < 0)
+ return n;
+ if (argindex + n > pinfo->argc)
+ {
+ int new_ct = argindex + n;
+ *argtypes = snv_renew (int, *argtypes, new_ct);
+ memset(*argtypes + pinfo->argc, PA_UNKNOWN,
+ (new_ct - pinfo->argc) * sizeof(**argtypes));
+ pinfo->argc = argindex + n;
+ /* Call again... */
+ pinfo->argindex = save_argindex;
+ pinfo->format = save_format;
+ pinfo->state = save_state;
+ pinfo->spec = (unsigned)*(pinfo->format);
+ pinfo->extra = spec->user;
+ pinfo->type = spec->type;
+ n = spec->arg(pinfo, (size_t)n, *argtypes + argindex);
+ }
+ }
+
+ if (!pinfo->dollar || !IS_MODIFIER (spec))
+ pinfo->argindex += n;
+
+ return n;
+}
+
+
+/**
+ * printf_strerror: printf.h
+ *
+ * Communicate information on the last error in a printf
+ * format string.
+ *
+ * Return value:
+ * A string describing the last error which occurred during the
+ * parsing of a printf format string. It is the responsibility
+ * of the caller to free the string.
+ */
+char *
+printf_strerror (void)
+{
+ return snv_strdup(printf_last_error);
+}
+
+/* (re)initialise the memory used by PPARSER. */
+static inline void
+parser_init (
+ struct printf_info *pinfo,
+ const char *format,
+ const union printf_arg *args)
+{
+ memset (pinfo, 0, sizeof (struct printf_info));
+ pinfo->format = format;
+ pinfo->args = args;
+}
+
+static inline struct printf_info *
+parser_reset (struct printf_info *pinfo)
+{
+ pinfo->is_long_double = pinfo->is_char = pinfo->is_short =
+ pinfo->is_long = pinfo->alt = pinfo->space = pinfo->left =
+ pinfo->showsign = pinfo->group = pinfo->wide =
+ pinfo->width = pinfo->spec = 0;
+
+ pinfo->state = SNV_STATE_BEGIN;
+ pinfo->prec = -1;
+ pinfo->dollar = 0;
+ pinfo->pad = ' ';
+
+ return pinfo;
+}
+
+
+/**
+ * printf_error: printf.h
+ * @pinfo: pointer to the current parser state.
+ * @file: file where error was detected.
+ * @line: line where error was detected.
+ * @func1: " (" if function is supplied by compiler.
+ * @func2: function where error was detected, if supplied by compiler.
+ * @func3: ")" if function is supplied by compiler.
+ * @error_message: new error message to append to @pinfo.
+ *
+ * The contents of @error_message are appended to the @pinfo internal
+ * error string, so it is safe to pass static strings or recycle the
+ * original when this function returns.
+ *
+ * Return value:
+ * The address of the full accumulated error message in @pinfo is
+ * returned.
+ **/
+char *
+printf_error (struct printf_info *pinfo, const char *file, int line,
+ const char *func1, const char *func2, const char *func3,
+ const char *error_message)
+{
+ int i;
+ char *result;
+ if (pinfo->error == NULL)
+ pinfo->error = filnew (NULL, (size_t)0);
+ else
+ filccat (pinfo->error, '\n');
+
+ /* Cannot use printf because a bug in it might trigger another
+ printf_error! */
+ result = filcat (pinfo->error, "file ");
+ filcat (pinfo->error, file);
+ filcat (pinfo->error, ": line ");
+ for (i = 10; i <= line; i *= 10);
+ for (i /= 10; i >= 1; i /= 10)
+ filccat (pinfo->error, '0' + (line / i) % 10);
+
+ filcat (pinfo->error, func1);
+ filcat (pinfo->error, func2);
+ filcat (pinfo->error, func3);
+ filcat (pinfo->error, ": ");
+ filcat (pinfo->error, error_message);
+ return result;
+}
+
+
+
+/**
+ * parse_printf_format: printf.h
+ * @format: a % delimited format string.
+ * @n: the size of the @argtypes vector
+ * @argtypes: a vector of ints, to be filled with the argument types from @format
+ *
+ * Returns information about the number and types of
+ * arguments expected by the template string @format.
+ * The argument @n specifies the number of elements in the array
+ * @argtypes. This is the maximum number of elements that
+ * the function will try to write.
+ *
+ * Return value:
+ * The total number of arguments required by @format. If this
+ * number is greater than @n, then the information returned
+ * describes only the first @n arguments. If you want information
+ * about additional arguments, allocate a bigger array and call
+ * this function again. If there is an error, then %SNV_ERROR
+ * is returned instead.
+ **/
+size_t
+parse_printf_format (const char *format, int n, int *argtypes)
+{
+ struct printf_info info;
+
+ return_val_if_fail (format != NULL, (size_t)-1);
+
+ parser_init (&info, format, NULL);
+
+ while (*info.format != EOS)
+ {
+ int ch = (int) *info.format++;
+ spec_entry *spec;
+ int status;
+ int argindex;
+
+ if (ch != SNV_CHAR_SPEC)
+ continue;
+
+ if (*info.format == SNV_CHAR_SPEC)
+ {
+ /* An escaped CHAR_SPEC: ignore it (by falling through). */
+ ++info.format;
+ continue;
+ }
+
+ /* We found the start of a format specifier! */
+ parser_reset (&info);
+ do
+ {
+ /* Until we fill the stream (or get some other
+ exception) or one of the handlers tells us
+ we have reached the end of the specifier... */
+
+ /* ...lookup the handler associated with the char
+ we are looking at in the format string... */
+ spec = spec_lookup ((unsigned)*(info.format));
+ if (spec == NULL)
+ {
+ PRINTF_ERROR (&info, "unregistered specifier");
+ goto error;
+ }
+
+ if (!IS_MODIFIER (spec) &&
+ !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
+ {
+ PRINTF_ERROR (&info, "invalid combination of flags");
+ goto error;
+ }
+
+ argindex = info.dollar && !IS_MODIFIER (spec)
+ ? info.dollar - 1 : info.argindex;
+
+ /* ...and call the relevant handler. */
+ if (spec->arg)
+ {
+ info.spec = (unsigned)*(info.format);
+ info.extra = spec->user;
+ info.type = spec->type;
+ status = (*spec->arg) (&info, (size_t) (n - argindex),
+ argtypes + argindex);
+ }
+ else
+ {
+ status = 1;
+ if (n > argindex)
+ argtypes[argindex] = spec->type;
+ }
+
+ if (status < 0)
+ goto error;
+
+ info.argc = MAX (info.argc, argindex + status);
+ if (!info.dollar || !IS_MODIFIER (spec))
+ info.argindex += status;
+
+ info.format++;
+ }
+ while (IS_MODIFIER (spec));
+
+ continue;
+
+ error:
+ /* Get here on error */
+ info.argc = -1;
+ break;
+ }
+
+ if (printf_last_error)
+ snv_delete (printf_last_error);
+
+ if (info.error)
+ printf_last_error = fildelete (info.error);
+ else
+ printf_last_error = NULL;
+
+ return info.argc;
+}
+
+static int
+do_printfv (STREAM *stream, const char *format, union printf_arg const args[])
+{
+ struct printf_info info;
+
+ /* This is the parser driver.
+
+ Here we scan through the format string and move bytes into the
+ stream and call handlers based on the parser state. */
+
+ parser_init (&info, format, args);
+
+ /* Keep going until the format string runs out! */
+ while (*info.format != EOS)
+ {
+ int ch = (int) *info.format++;
+
+ switch (ch)
+ {
+ case SNV_CHAR_SPEC:
+ if (*info.format != SNV_CHAR_SPEC)
+ {
+ /* We found the start of a format specifier! */
+ spec_entry *spec;
+ int status;
+ int argindex;
+
+ parser_reset (&info);
+ do
+ {
+ /* Until we fill the stream (or get some other
+ exception) or one of the handlers tells us
+ we have reached the end of the specifier... */
+
+ /* ...lookup the handler associated with the char
+ we are looking at in the format string... */
+ spec = spec_lookup ((unsigned)*(info.format));
+ if (spec == NULL)
+ {
+ PRINTF_ERROR (&info, "unregistered specifier");
+ goto error;
+ }
+
+ if (!IS_MODIFIER (spec) &&
+ !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
+ {
+ PRINTF_ERROR (&info, "invalid combination of flags");
+ goto error;
+ }
+
+ /* ...and call the relevant handler. */
+ info.spec = (unsigned)*(info.format);
+ info.extra = spec->user;
+ info.type = spec->type;
+
+ status = spec->arg ? (*spec->arg) (&info, (size_t)0, NULL) : 1;
+
+ if (status < 0)
+ goto error;
+
+ argindex = info.dollar && !IS_MODIFIER (spec)
+ ? info.dollar - 1 : info.argindex;
+
+ info.format++;
+ info.argc = MAX (info.argc, argindex + status);
+ if (!info.dollar && !IS_MODIFIER (spec))
+ info.argindex += status;
+ }
+ while (info.count >= 0 && IS_MODIFIER (spec));
+
+ status = (*spec->fmt) (stream, &info, args + argindex);
+
+ if (status < 0)
+ goto error;
+
+ info.count += status;
+ continue;
+ }
+
+ /* An escaped CHAR_SPEC: ignore it (by falling through). */
+ ++info.format;
+
+ /*FALLTHROUGH*/
+
+ default:
+ /* Just a character: copy it. */
+ SNV_EMIT (ch, stream, info.count);
+ continue;
+ }
+
+ error:
+ /* Get here on error */
+ info.count = -1;
+ break;
+ }
+
+ if (printf_last_error)
+ snv_delete (printf_last_error);
+
+ if (info.error)
+ printf_last_error = fildelete (info.error);
+ else
+ printf_last_error = NULL;
+
+ return info.count;
+}
+
+/**
+ * stream_printfv: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+stream_printfv (STREAM *stream, const char *format, snv_constpointer const *ap)
+{
+ union printf_arg *args;
+ struct printf_info info;
+ int count_or_errorcode;
+ int *argtypes = NULL;
+
+ return_val_if_fail (format != NULL, SNV_ERROR);
+
+ parser_init (&info, format, NULL);
+
+ /* Keep going until the format string runs out! */
+ while (*info.format != EOS)
+ {
+ int ch = (int) *info.format++;
+
+ switch (ch)
+ {
+ case SNV_CHAR_SPEC:
+ if (*info.format != SNV_CHAR_SPEC)
+ {
+ /* We found the start of a format specifier! */
+ spec_entry *spec;
+
+ parser_reset (&info);
+ do
+ {
+ /* Until we fill the stream (or get some other
+ exception) or one of the handlers tells us
+ we have reached the end of the specifier... */
+
+ /* ...lookup the handler associated with the char
+ we are looking at in the format string... */
+ spec = spec_lookup ((unsigned)*(info.format));
+ if (spec == NULL)
+ {
+ PRINTF_ERROR (&info, "unregistered specifier");
+ goto error;
+ }
+
+ if (!IS_MODIFIER (spec) &&
+ !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
+ {
+ PRINTF_ERROR (&info, "invalid combination of flags");
+ goto error;
+ }
+
+ /* ...and call the relevant handler. */
+ if (call_argtype_function (&info, &argtypes, spec) < 0)
+ goto error;
+
+ info.format++;
+ }
+ while (info.count >= 0 && IS_MODIFIER (spec));
+ continue;
+ }
+
+ /* An escaped CHAR_SPEC: ignore it (by falling through). */
+ ++info.format;
+
+ /*FALLTHROUGH*/
+
+ default: /* Just a character: ignore it. */
+ continue;
+ }
+
+ error:
+ /* Get here on error */
+ info.argc = -1;
+ break;
+ }
+
+ if (info.argc == 0)
+ {
+ args = NULL;
+ }
+ else
+ {
+ int idx;
+
+ assert(argtypes != NULL);
+ args = snv_new (union printf_arg, info.argc);
+
+ /* We scanned the format string to find the type of the arguments,
+ so we can now cast it and store it correctly. */
+ for (idx = 0; idx < info.argc; idx++)
+ {
+ int tp = argtypes[idx];
+ if ((tp & PA_TYPE_MASK) == PA_TYPE_MASK)
+ {
+ if (idx + 1 == info.argc)
+ {
+ info.argc--;
+ break;
+ }
+ continue; /* Ignore it. We allow skipping args, but the
+ * user is responsible for ensuring a void* sized
+ * spacer in the argument list.
+ */
+ }
+
+ switch (tp & ~PA_FLAG_UNSIGNED)
+ {
+ case PA_CHAR:
+ args[idx].pa_char = (char) *(const long int *)(ap + idx);
+ break;
+
+ case PA_WCHAR:
+ args[idx].pa_wchar =
+ (snv_wchar_t) *(const long int *)(ap + idx);
+ break;
+
+ case PA_INT|PA_FLAG_SHORT:
+ args[idx].pa_short_int =
+ (short int) *(const long int *)(ap + idx);
+ break;
+
+ case PA_INT:
+ args[idx].pa_int = (int) *(const long int *)(ap + idx);
+ break;
+
+ case PA_INT|PA_FLAG_LONG:
+ args[idx].pa_long_int = *(const long int *)(ap + idx);
+ break;
+
+ case PA_INT|PA_FLAG_LONG_LONG:
+ args[idx].pa_long_long_int = **(const intmax_t **)(ap + idx);
+ break;
+
+ case PA_FLOAT:
+ args[idx].pa_float = **(const float **)(ap + idx);
+ break;
+
+ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
+#ifdef HAVE_LONG_DOUBLE
+ args[idx].pa_long_double = **(const long double **)(ap + idx);
+ break;
+#endif
+ /* else fall through */
+
+ case PA_DOUBLE:
+ args[idx].pa_double = **(const double **)(ap + idx);
+ break;
+
+ /* Note that pointer types are dereferenced just once! */
+ case PA_STRING:
+ args[idx].pa_string = *(const char **)(ap + idx);
+ break;
+
+ case PA_WSTRING:
+ args[idx].pa_wstring = *(const snv_wchar_t **)(ap + idx);
+ break;
+
+ case PA_POINTER:
+ args[idx].pa_pointer = *(snv_constpointer *)(ap + idx);
+ break;
+
+ default:
+ if (argtypes[idx] & PA_FLAG_PTR)
+ args[idx].pa_pointer = *(snv_constpointer *)(ap + idx);
+ else
+ args[idx].pa_long_double = 0.0;
+ break;
+ }
+ }
+ }
+
+ if (printf_last_error)
+ snv_delete (printf_last_error);
+
+ if (info.error)
+ printf_last_error = fildelete (info.error);
+ else
+ printf_last_error = NULL;
+
+ count_or_errorcode = do_printfv (stream, format, args);
+
+ snv_delete (argtypes);
+ if (info.argc > 0)
+ snv_delete (args);
+
+ return count_or_errorcode;
+}
+
+
+/**
+ * stream_vprintf: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+stream_vprintf (STREAM *stream, const char *format, va_list ap)
+{
+ union printf_arg *args = NULL;
+ struct printf_info info;
+ int count_or_errorcode;
+ int *argtypes = NULL;
+
+ return_val_if_fail (format != NULL, SNV_ERROR);
+
+ parser_init (&info, format, NULL);
+
+ /* Keep going until the format string runs out! */
+ while (*info.format != EOS)
+ {
+ int ch = (int) *info.format++;
+
+ switch (ch)
+ {
+ case SNV_CHAR_SPEC:
+ if (*info.format != SNV_CHAR_SPEC)
+ {
+ /* We found the start of a format specifier! */
+ spec_entry *spec;
+
+ parser_reset (&info);
+ do
+ {
+ /* Until we fill the stream (or get some other
+ exception) or one of the handlers tells us
+ we have reached the end of the specifier... */
+ /* ...lookup the handler associated with the char
+ we are looking at in the format string... */
+ spec = spec_lookup ((unsigned)*(info.format));
+ if (spec == NULL)
+ {
+ PRINTF_ERROR (&info, "unregistered specifier");
+ goto error;
+ }
+
+ if (!IS_MODIFIER (spec) &&
+ !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
+ {
+ PRINTF_ERROR (&info, "invalid combination of flags");
+ goto error;
+ }
+
+ /* ...and call the relevant handler. */
+ if (call_argtype_function (&info, &argtypes, spec) < 0)
+ goto error;
+
+ info.format++;
+ }
+ while (info.count >= 0 && IS_MODIFIER (spec));
+ continue;
+ }
+ /* An escaped CHAR_SPEC: ignore it (by falling through). */
+ ++info.format;
+
+ /*FALLTHROUGH*/
+
+ default: /* Just a character: ignore it. */
+ continue;
+ }
+
+ error:
+ /* Get here on error */
+ info.argc = -1;
+ break;
+ }
+
+ if (info.argc > 0)
+ {
+ int idx;
+
+ assert(argtypes != NULL);
+ args = snv_new (union printf_arg, info.argc);
+
+ /* Scan the format string to find the type of the argument
+ so we can cast it and store it correctly.
+
+ Note that according to the ISO C standards, standard
+ type promotion takes place on any variadic arguments as
+ they are aligned on the call stack, and so it is these
+ promoted types that we must extract with the va_arg()
+ macro, or the alignment gets all messed up.
+
+ Thanks to Robert Lipe <robertlipe@usa.net> for explaining all
+ this to me. */
+ for (idx = 0; idx < info.argc; idx++)
+ switch (argtypes[idx] & ~PA_FLAG_UNSIGNED)
+ {
+ case PA_CHAR:
+ args[idx].pa_char = va_arg (ap, int); /* Promoted. */
+ break;
+
+ case PA_WCHAR:
+ args[idx].pa_wchar = va_arg (ap, snv_wint_t); /* Promoted. */
+ break;
+
+ case PA_INT|PA_FLAG_SHORT:
+ args[idx].pa_short_int = va_arg (ap, int); /* Promoted. */
+ break;
+
+ case PA_INT:
+ args[idx].pa_int = va_arg (ap, int);
+ break;
+
+ case PA_INT|PA_FLAG_LONG:
+ args[idx].pa_long_int = va_arg (ap, long int);
+ break;
+
+ case PA_INT|PA_FLAG_LONG_LONG:
+ args[idx].pa_long_long_int = va_arg (ap, intmax_t);
+ break;
+
+ case PA_FLOAT:
+ args[idx].pa_float = va_arg (ap, double); /* Promoted. */
+ break;
+
+ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
+ args[idx].pa_long_double = va_arg (ap, long double);
+ break;
+
+ case PA_DOUBLE:
+ args[idx].pa_double = va_arg (ap, double);
+ break;
+
+ case PA_STRING:
+ args[idx].pa_string = va_arg (ap, const char *);
+ break;
+
+ case PA_WSTRING:
+ args[idx].pa_wstring = va_arg (ap, const snv_wchar_t *);
+ break;
+
+ case PA_POINTER:
+ args[idx].pa_pointer = va_arg (ap, void *);
+ break;
+
+ default:
+ if (argtypes[idx] & PA_FLAG_PTR)
+ args[idx].pa_pointer = va_arg (ap, void *);
+ else
+ args[idx].pa_long_double = 0.0;
+ break;
+ }
+ }
+
+ if (printf_last_error)
+ snv_delete (printf_last_error);
+
+ if (info.error)
+ printf_last_error = fildelete (info.error);
+ else
+ printf_last_error = NULL;
+
+ count_or_errorcode = do_printfv (stream, format, args);
+
+ snv_delete (argtypes);
+ snv_delete (args);
+ return count_or_errorcode;
+}
+
+/**
+ * stream_printf: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+stream_printf (STREAM * stream, const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = stream_vprintf (stream, format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+
+/* Finally... the main API implementation: */
+
+/**
+ * snv_fdputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a file descriptor.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream, or -1 in case of
+ * an error (errno will be set to indicate the type of error).
+ **/
+int
+snv_fdputc (int ch, STREAM *stream)
+{
+ static char buf[1] = { 0 };
+ buf[0] = (char) ch;
+ return
+ write ((int) SNV_POINTER_TO_LONG (stream_details (stream)), buf, (size_t) 1)
+ ? ch : -1;
+}
+
+/**
+ * snv_dprintf: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_dprintf (int fd, const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = snv_vdprintf (fd, format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+/**
+ * snv_vdprintf: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vdprintf (int fd, const char *format, va_list ap)
+{
+ int result;
+ STREAM *out = stream_new (SNV_LONG_TO_POINTER (fd),
+ SNV_UNLIMITED, NULL, snv_fdputc);
+
+ result = stream_vprintf (out, format, ap);
+ stream_delete (out);
+ return result;
+}
+
+/**
+ * snv_dprintfv: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_dprintfv (int fd, const char *format, snv_constpointer const args[])
+{
+ int result;
+ STREAM *out = stream_new (SNV_LONG_TO_POINTER (fd),
+ SNV_UNLIMITED, NULL, snv_fdputc);
+
+ result = stream_printfv (out, format, args);
+ stream_delete (out);
+ return result;
+}
+
+
+/**
+ * snv_fileputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a FILE*.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+int
+snv_fileputc (int ch, STREAM *stream)
+{
+ FILE *fp = (FILE *) stream_details (stream);
+ return putc (ch, fp);
+}
+
+static int
+snv_fileputc_unlocked (int ch, STREAM *stream)
+{
+ FILE *fp = (FILE *) stream_details (stream);
+ return SNV_PUTC_UNLOCKED (ch, fp);
+}
+
+/**
+ * snv_printf: printf.h
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_printf (const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = snv_vprintf (format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+/**
+ * snv_vprintf: printf.h
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vprintf (const char *format, va_list ap)
+{
+ int result;
+ STREAM *out = stream_new (stdout, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
+ int tmp;
+
+ SNV_WITH_LOCKED_FP (stdout, tmp)
+ result = stream_vprintf (out, format, ap);
+
+ stream_delete (out);
+ return result;
+}
+
+/**
+ * snv_printfv: printf.h
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to the string @format,
+ * and write the result to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_printfv (const char *format, snv_constpointer const args[])
+{
+ int result;
+ STREAM *out = stream_new (stdout, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
+ int tmp;
+
+ SNV_WITH_LOCKED_FP (stdout, tmp)
+ result = stream_printfv (out, format, args);
+ stream_delete (out);
+ return result;
+}
+
+/**
+ * snv_fprintf: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the @file stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_fprintf (FILE * file, const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = snv_vfprintf (file, format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+/**
+ * snv_vfprintf: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the @file stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vfprintf (FILE *file, const char *format, va_list ap)
+{
+ int result;
+ STREAM *out = stream_new (file, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
+ int tmp;
+
+ SNV_WITH_LOCKED_FP (file, tmp)
+ result = stream_vprintf (out, format, ap);
+ stream_delete (out);
+ return result;
+}
+
+/**
+ * snv_fprintfv: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to @file.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_fprintfv (FILE *file, const char *format, snv_constpointer const args[])
+{
+ int result;
+ STREAM *out = stream_new (file, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
+ int tmp;
+
+ SNV_WITH_LOCKED_FP (file, tmp)
+ result = stream_printfv (out, format, args);
+
+ stream_delete (out);
+ return result;
+}
+
+
+/**
+ * snv_bufputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a char buffer.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+int
+snv_bufputc (int ch, STREAM * stream)
+{
+ char **ppbuffer = (char **) stream_details (stream);
+ **ppbuffer = (char) ch;
+ (*ppbuffer)++;
+ return ch;
+}
+
+/**
+ * snv_sprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_sprintf (char buffer[], const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = snv_vsprintf (buffer, format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+/**
+ * snv_vsprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vsprintf (char buffer[], const char *format, va_list ap)
+{
+ int count_or_errorcode;
+ STREAM *out = stream_new (&buffer, SNV_UNLIMITED, NULL, snv_bufputc);
+ count_or_errorcode = stream_vprintf (out, format, ap);
+
+ /* Terminate with an EOS without incrementing the counter. */
+ stream_put (EOS, out);
+
+ stream_delete (out);
+ return count_or_errorcode;
+}
+
+/**
+ * snv_sprintfv: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_sprintfv (char buffer[], const char *format, snv_constpointer const args[])
+{
+ int count_or_errorcode;
+ STREAM *out = stream_new (&buffer, SNV_UNLIMITED, NULL, snv_bufputc);
+ count_or_errorcode = stream_printfv (out, format, args);
+
+ /* Terminate with an EOS without incrementing the counter. */
+ stream_put (EOS, out);
+
+ stream_delete (out);
+ return count_or_errorcode;
+}
+
+/**
+ * snv_snprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_snprintf (char buffer[], unsigned long limit, const char *format, ...)
+{
+ int count_or_errorcode;
+ va_list ap;
+
+ va_start (ap, format);
+ count_or_errorcode = snv_vsnprintf (buffer, limit, format, ap);
+ va_end (ap);
+
+ return count_or_errorcode;
+}
+
+/**
+ * snv_vsnprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vsnprintf (char buffer[], unsigned long limit, const char *format, va_list ap)
+{
+ int count_or_errorcode;
+ STREAM *out = stream_new (&buffer, limit - 1, NULL, snv_bufputc);
+ count_or_errorcode = stream_vprintf (out, format, ap);
+ *buffer = EOS;
+
+ stream_delete (out);
+ return count_or_errorcode;
+}
+
+/**
+ * snv_snprintfv: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_snprintfv (char buffer[], unsigned long limit, const char *format,
+ snv_constpointer const args[])
+{
+ int count_or_errorcode;
+ STREAM *out = stream_new (&buffer, limit - 1, NULL, snv_bufputc);
+ count_or_errorcode = stream_printfv (out, format, args);
+ *buffer = EOS;
+
+ stream_delete (out);
+ return count_or_errorcode;
+}
+
+
+/**
+ * snv_filputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a Filament*.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+int
+snv_filputc (int ch, STREAM * stream)
+{
+ return filccat ((Filament *) stream_details (stream), ch), ch;
+}
+
+/**
+ * snv_asprintf: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Yes, this interface is cumbersome and totally useless. It would
+ * have been better to simply return the allocated address, but
+ * it turns out that somebody wasn't thinking much when adding
+ * asprintf to libiberty a few years ago.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_asprintf (char **result, const char *format, ...)
+{
+ int count;
+ va_list ap;
+
+ va_start (ap, format);
+ count = snv_vasprintf (result, format, ap);
+ va_end (ap);
+
+ return count;
+}
+
+/**
+ * snv_vasprintf: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Above moaning for asprintf applies here too.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_vasprintf (char **result, const char *format, va_list ap)
+{
+ int count_or_errorcode;
+ char *base;
+ Filament *fil = filnew (NULL, (size_t)0);
+ STREAM *out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
+ count_or_errorcode = stream_vprintf (out, format, ap);
+
+ base = fildelete (fil);
+ stream_delete (out);
+
+ *result = (count_or_errorcode < 0) ? NULL : base;
+ return count_or_errorcode;
+}
+
+/**
+ * snv_asprintfv: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Above moaning for asprintf applies here too.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+int
+snv_asprintfv (char **result, const char *format, snv_constpointer const args[])
+{
+ int count_or_errorcode;
+ char *base;
+ Filament *fil = filnew (NULL, (size_t)0);
+ STREAM *out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
+ count_or_errorcode = stream_printfv (out, format, args);
+
+ base = fildelete (fil);
+ stream_delete (out);
+
+ *result = (count_or_errorcode < 0) ? NULL : base;
+ return count_or_errorcode;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/printfv.c */
diff --git a/snprintfv/printf.h b/snprintfv/printf.h
new file mode 100644
index 0000000..7e53fd1
--- /dev/null
+++ b/snprintfv/printf.h
@@ -0,0 +1,846 @@
+/* -*- Mode: C -*- */
+
+/* printf.in --- printf clone for argv arrays
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef SNPRINTFV_SNPRINTFV_H
+#define SNPRINTFV_SNPRINTFV_H 1
+
+#include <snprintfv/compat.h>
+#include <snprintfv/filament.h>
+#include <snprintfv/stream.h>
+#include <snprintfv/mem.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* The type of each element in the table of printf specifiers. */
+struct spec_entry;
+
+typedef enum
+{
+ SNV_ERROR = -1,
+ SNV_OK
+}
+snv_status;
+
+/* Basic states required by the parser. On initialisation the parser
+ will be in SNV_STATE_BEGIN, and tokens will be parsed by the registered
+ functions until the parser reached SNV_STATE_END. */
+#define SNV_STATE_BEGIN 1
+#define SNV_STATE_END 0
+
+/* States needed to support:
+ %[<number>$]<flags>[<width>|\*][.<precision>|\*]<modifiers><specifier> */
+#define SNV_STATE_FLAG (1 << 1)
+#define SNV_STATE_WIDTH (1 << 2)
+#define SNV_STATE_PRECISION (1 << 3)
+#define SNV_STATE_MODIFIER (1 << 4)
+#define SNV_STATE_SPECIFIER (1 << 5)
+
+/* First state available to the user */
+#define SNV_STATE_USER_FIRST (1 << 8)
+
+/* Mask for states available to the user */
+#define SNV_STATE_USER_MASK ~(SNV_STATE_USER_FIRST - 1)
+
+typedef struct printf_info
+{
+ int count; /* accumulated count, or SNV_ERROR */
+ int state; /* one of the defines above */
+ Filament *error; /* accumulated error details */
+
+ const char *format; /* pointer to format string */
+ int argc; /* number of arguments used by format */
+ int argindex; /* number of non-dollar arguments used so far */
+
+ int dollar; /* standard parser state, as in glibc */
+ int prec; /* from this field on, as in glibc */
+ int width;
+
+ snv_pointer extra;
+ int type;
+
+ char spec;
+ char pad;
+ unsigned is_long_double:1;
+ unsigned is_char:1;
+ unsigned is_short:1;
+ unsigned is_long:1;
+ unsigned alt:1;
+ unsigned space:1;
+ unsigned left:1;
+ unsigned showsign:1;
+ unsigned group:1;
+ unsigned wide:1;
+
+ const union printf_arg *args;
+} printf_info;
+
+/**
+ * printf_arg:
+ * @pa_char: an unsigned %char
+ * @pa_wchar: a %wchar_t
+ * @pa_short_int: a %short integer
+ * @pa_int: an %int
+ * @pa_long_int: a %long integer
+ * @pa_long_long_int: the widest signed integer type in use on the host
+ * @pa_u_short_int: an unsigned %short integer
+ * @pa_u_int: an unsigned %int
+ * @pa_u_long_int: an unsigned %long integer
+ * @pa_u_long_long_int: the widest unsigned integer type in use on the host
+ * @pa_float: a %float
+ * @pa_double: a %double
+ * @pa_long_double: a long %double, or a simple %double if it is the widest floating-point type in use on the host
+ * @pa_string: a %const pointer to %char
+ * @pa_wstring: a %const pointer to %wchar_t
+ * @pa_pointer: a generic pointer
+ *
+ * The various kinds of arguments that can be passed to printf.
+ */
+typedef union printf_arg
+{
+ unsigned char pa_char;
+ snv_wchar_t pa_wchar;
+ short int pa_short_int;
+ int pa_int;
+ long int pa_long_int;
+ intmax_t pa_long_long_int;
+ unsigned short int pa_u_short_int;
+ unsigned int pa_u_int;
+ unsigned long int pa_u_long_int;
+ uintmax_t pa_u_long_long_int;
+ float pa_float;
+ double pa_double;
+ long double pa_long_double;
+ const char *pa_string;
+ const snv_wchar_t *pa_wstring;
+ snv_constpointer pa_pointer;
+} printf_arg;
+
+/**
+ * PRINTF_ERROR:
+ * @pi: A pointer to the current state for the parser
+ * @str: The error message
+ *
+ * Append an error that will be returned by printf_strerror.
+ */
+#define PRINTF_ERROR(pi, str) \
+ printf_error(pi, __FILE__, __LINE__, SNV_ASSERT_FCN, str);
+
+typedef int printf_function (STREAM *stream, struct printf_info *pparser,
+ union printf_arg const * args);
+
+typedef int printf_arginfo_function (struct printf_info *pparser, size_t n,
+ int *argtypes);
+
+/**
+ * spec_entry:
+ * @spec: the specifier character that was matched
+ * @type: when @arg is NULL, the type of the only argument to the specifier
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments to the specifier
+ * @user: the user data for the specifier, accessible to the handler function
+ *
+ * This is returned by register_printf_function.
+ */
+typedef struct spec_entry
+{
+ unsigned int spec_key;
+ int unused; /* for binary compatibility */
+ int type;
+ printf_function *fmt;
+ printf_arginfo_function *arg;
+ snv_pointer user;
+}
+spec_entry;
+
+/**
+ * register_callback_function: printf.h
+ * @spec: the character which will trigger the functions, cast to an unsigned int.
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments to the specifier
+ *
+ * Register the pair made of @fmt and @arg, so that it is called
+ * when @spec is encountered in a format string. If you create
+ * a shared library with an entry point named
+ * %snv_register_printf_funcs, and put the library in the
+ * search path given by the environment library %LTDL_LIBRARY_PATH,
+ * that entry point will be called when %libsnprintfv is initialized,
+ * passing a pointer to this kind of function (actually, a pointer
+ * to %register_printf_function) to it. This functionality is only
+ * present when the library is installed, not when it is built as
+ * a convenience library.
+ *
+ * Return value:
+ * Returns %NULL if @func was not successfully registered, a
+ * %spec_entry with the information on the function if it was.
+ **/
+typedef spec_entry *register_callback_function (unsigned spec, printf_function *func, printf_arginfo_function *arginfo);
+
+/* Codes to determine basic types.
+
+ These values cover all the standard format specifications.
+ Users can add new values after PA_LAST for their own types. */
+
+enum
+{
+ PA_INT, /* int */
+ PA_CHAR, /* int, cast to char */
+ PA_WCHAR, /* wide char */
+ PA_STRING, /* const char *, a '\0'-terminated string */
+ PA_WSTRING, /* const wchar_t *, wide character string */
+ PA_POINTER, /* void * */
+ PA_FLOAT, /* float */
+ PA_DOUBLE, /* double */
+ PA_LAST,
+ PA_UNKNOWN = -1
+};
+
+/* Flag bits that can be set in a type. */
+#define PA_TYPE_MASK 0x00ff
+#define PA_FLAG_MASK ~SNV_TYPE_MASK
+
+#define PA_FLAG_LONG_LONG (1 << 8)
+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
+#define PA_FLAG_LONG (1 << 9)
+#define PA_FLAG_SHORT (1 << 10)
+#define PA_FLAG_UNSIGNED (1 << 11)
+#define PA_FLAG_CHAR (1 << 12)
+#define PA_FLAG_PTR (1 << 13)
+
+/**
+ * SNV_EMIT:
+ * @ch: the character to be printed
+ * @stream: the stream on which to print
+ * @count: a variable to be updated with the count of printed
+ * characters
+ *
+ * Maintain the count while putting @ch in @stream, also be careful about
+ * handling %NULL stream if the handler is being called purely to count
+ * output size.
+ **/
+#define SNV_EMIT(ch, stream, count) \
+ SNV_STMT_START { \
+ if ((stream)) \
+ { \
+ if ((count) >= 0) \
+ { \
+ int m_status = stream_put((unsigned char) (ch), (stream)); \
+ (count) = m_status < 0 ? m_status : (count) + m_status; \
+ } \
+ } \
+ else \
+ { \
+ (void)(ch); \
+ (count)++; \
+ } \
+ } SNV_STMT_END
+
+#line 267 "printf.in"
+/**
+ * printf_generic_info:
+ * @pinfo: the current state information for the format
+ * string parser.
+ * @n: the number of available slots in the @argtypes array
+ * @argtypes: the pointer to the first slot to be filled by the
+ * function
+ *
+ * An example implementation of a %printf_arginfo_function, which
+ * takes the basic type from the type given in the %spec_entry
+ * and adds flags depending on what was parsed (e.g. %PA_FLAG_SHORT
+ * is %pparser->is_short and so on).
+ *
+ * Return value:
+ * Always 1.
+ */
+extern int
+printf_generic_info (struct printf_info *const pinfo, size_t n, int *argtypes);
+
+/**
+ * printf_generic:
+ * @stream: the stream (possibly a struct printfv_stream appropriately
+ * cast) on which to write output.
+ * @pinfo: the current state information for the format string parser.
+ * @args: the pointer to the first argument to be read by the handler
+ *
+ * An example implementation of a %printf_function, used to provide easy
+ * access to justification, width and precision options.
+ *
+ * Return value:
+ * The number of characters output.
+ **/
+extern int
+printf_generic (STREAM *stream, struct printf_info *const pinfo, union printf_arg const *args);
+
+#line 268 "printf.in"
+/**
+ * register_printf_function: printf.h
+ * @spec: the character which will trigger @func, cast to an unsigned int.
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments
+ * to the specifier
+ *
+ * Register the pair made of @fmt and @arg, so that it is called
+ * when @spec is encountered in a format string.
+ *
+ * Return value:
+ * Returns %NULL if @func was not successfully registered, a
+ * %spec_entry with the information on the function if it was.
+ **/
+extern spec_entry *
+register_printf_function (unsigned spec, printf_function *fmt,
+ printf_arginfo_function *arg);
+
+/**
+ * printf_strerror: printf.h
+ *
+ * Communicate information on the last error in a printf
+ * format string.
+ *
+ * Return value:
+ * A string describing the last error which occurred during the
+ * parsing of a printf format string. It is the responsibility
+ * of the caller to free the string.
+ */
+extern char *
+printf_strerror (void);
+
+/**
+ * printf_error: printf.h
+ * @pinfo: pointer to the current parser state.
+ * @file: file where error was detected.
+ * @line: line where error was detected.
+ * @func1: " (" if function is supplied by compiler.
+ * @func2: function where error was detected, if supplied by compiler.
+ * @func3: ")" if function is supplied by compiler.
+ * @error_message: new error message to append to @pinfo.
+ *
+ * The contents of @error_message are appended to the @pinfo internal
+ * error string, so it is safe to pass static strings or recycle the
+ * original when this function returns.
+ *
+ * Return value:
+ * The address of the full accumulated error message in @pinfo is
+ * returned.
+ **/
+extern char *
+printf_error (struct printf_info *pinfo, const char *file, int line,
+ const char *func1, const char *func2, const char *func3,
+ const char *error_message);
+
+/**
+ * parse_printf_format: printf.h
+ * @format: a % delimited format string.
+ * @n: the size of the @argtypes vector
+ * @argtypes: a vector of ints, to be filled with the argument types from @format
+ *
+ * Returns information about the number and types of
+ * arguments expected by the template string @format.
+ * The argument @n specifies the number of elements in the array
+ * @argtypes. This is the maximum number of elements that
+ * the function will try to write.
+ *
+ * Return value:
+ * The total number of arguments required by @format. If this
+ * number is greater than @n, then the information returned
+ * describes only the first @n arguments. If you want information
+ * about additional arguments, allocate a bigger array and call
+ * this function again. If there is an error, then %SNV_ERROR
+ * is returned instead.
+ **/
+extern size_t
+parse_printf_format (const char *format, int n, int *argtypes);
+
+/**
+ * stream_printfv: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+stream_printfv (STREAM *stream, const char *format, snv_constpointer const *ap);
+
+/**
+ * stream_vprintf: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+stream_vprintf (STREAM *stream, const char *format, va_list ap);
+
+/**
+ * stream_printf: printf.h
+ * @stream: an initialised stream structure.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to @stream. If @stream is %NULL, only count the
+ * number of characters needed to output the format.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+stream_printf (STREAM * stream, const char *format, ...);
+
+/**
+ * snv_fdputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a file descriptor.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream, or -1 in case of
+ * an error (errno will be set to indicate the type of error).
+ **/
+extern int
+snv_fdputc (int ch, STREAM *stream);
+
+/**
+ * snv_dprintf: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_dprintf (int fd, const char *format, ...);
+
+/**
+ * snv_vdprintf: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vdprintf (int fd, const char *format, va_list ap);
+
+/**
+ * snv_dprintfv: printf.h
+ * @fd: an open file descriptor.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to file descriptor @fd.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_dprintfv (int fd, const char *format, snv_constpointer const args[]);
+
+/**
+ * snv_fileputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a FILE*.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+extern int
+snv_fileputc (int ch, STREAM *stream);
+
+/**
+ * snv_printf: printf.h
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_printf (const char *format, ...);
+
+/**
+ * snv_vprintf: printf.h
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vprintf (const char *format, va_list ap);
+
+/**
+ * snv_printfv: printf.h
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to the string @format,
+ * and write the result to the standard output stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_printfv (const char *format, snv_constpointer const args[]);
+
+/**
+ * snv_fprintf: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the @file stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_fprintf (FILE * file, const char *format, ...);
+
+/**
+ * snv_vfprintf: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the @file stream.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vfprintf (FILE *file, const char *format, va_list ap);
+
+/**
+ * snv_fprintfv: printf.h
+ * @file: a stdio.h FILE* stream.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to @file.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_fprintfv (FILE *file, const char *format, snv_constpointer const args[]);
+
+/**
+ * snv_bufputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a char buffer.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+extern int
+snv_bufputc (int ch, STREAM * stream);
+
+/**
+ * snv_sprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_sprintf (char buffer[], const char *format, ...);
+
+/**
+ * snv_vsprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vsprintf (char buffer[], const char *format, va_list ap);
+
+/**
+ * snv_sprintfv: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to the string @buffer.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_sprintfv (char buffer[], const char *format, snv_constpointer const args[]);
+
+/**
+ * snv_snprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_snprintf (char buffer[], unsigned long limit, const char *format, ...);
+
+/**
+ * snv_vsnprintf: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vsnprintf (char buffer[], unsigned long limit, const char *format, va_list ap);
+
+/**
+ * snv_snprintfv: printf.h
+ * @buffer: a preallocated char* buffer.
+ * @limit: the maximum number of characters to write into @buffer.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to the string @buffer, truncating the formatted string
+ * if it reaches @limit characters in length.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_snprintfv (char buffer[], unsigned long limit, const char *format,
+ snv_constpointer const args[]);
+
+/**
+ * snv_filputc: printf.h
+ * @ch: A single character to be added to @stream.
+ * @stream: The stream in which to write @ch.
+ *
+ * A StreamPut function for use in putting characters
+ * into STREAMs holding a Filament*.
+ *
+ * Return value:
+ * The value of @ch that has been put in @stream.
+ **/
+extern int
+snv_filputc (int ch, STREAM * stream);
+
+/**
+ * snv_asprintf: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @va_alist: a varargs/stdargs va_list.
+ *
+ * Format the elements of @va_alist according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Yes, this interface is cumbersome and totally useless. It would
+ * have been better to simply return the allocated address, but
+ * it turns out that somebody wasn't thinking much when adding
+ * asprintf to libiberty a few years ago.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_asprintf (char **result, const char *format, ...);
+
+/**
+ * snv_vasprintf: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @ap: a varargs/stdargs va_list.
+ *
+ * Format the elements of @ap according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Above moaning for asprintf applies here too.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_vasprintf (char **result, const char *format, va_list ap);
+
+/**
+ * snv_asprintfv: printf.h
+ * @result: the address of a char * variable.
+ * @format: a % delimited format string.
+ * @args: a vector of argument addresses to match @format.
+ *
+ * Format the elements of @args according to @format, and write
+ * the results to an internally allocated buffer whose address is
+ * stored in @result (and should be freed by the caller) unless
+ * there is an error.
+ *
+ * Above moaning for asprintf applies here too.
+ *
+ * Return value:
+ * The number of characters written is returned, unless there is
+ * an error, when %SNV_ERROR is returned.
+ **/
+extern int
+snv_asprintfv (char **result, const char *format, snv_constpointer const args[]);
+
+#line 269 "printf.in"
+
+/* If you don't want to use snprintfv functions for *all* of your string
+ formatting API, then define COMPILING_SNPRINTFV_C and use the snv_
+ prefix for the entry points below. */
+#ifndef COMPILING_PRINTF_C
+#undef printf
+#undef vprintf
+#undef dprintf
+#undef vdprintf
+#undef fprintf
+#undef vfprintf
+#undef sprintf
+#undef vsprintf
+#undef snprintf
+#undef vsnprintf
+#undef asprintf
+#undef vasprintf
+#undef asprintfv
+#undef dprintfv
+#undef fprintfv
+#undef sprintfv
+#undef printfv
+#undef snprintfv
+
+#define printf snv_printf
+#define vprintf snv_vprintf
+#define dprintf snv_dprintf
+#define vdprintf snv_vdprintf
+#define fprintf snv_fprintf
+#define vfprintf snv_vfprintf
+#define sprintf snv_sprintf
+#define vsprintf snv_vsprintf
+#define snprintf snv_snprintf
+#define vsnprintf snv_vsnprintf
+#define asprintf snv_asprintf
+#define vasprintf snv_vasprintf
+#define asprintfv snv_asprintfv
+#define dprintfv snv_dprintfv
+#define fprintfv snv_fprintfv
+#define sprintfv snv_sprintfv
+#define printfv snv_printfv
+#define snprintfv snv_snprintfv
+#endif /* !COMPILING_SNPRINTFV_C */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SNPRINTFV_SNPRINTFV_H */
+
+/* snprintfv.h ends here */
diff --git a/snprintfv/printf.in b/snprintfv/printf.in
new file mode 100644
index 0000000..98ba995
--- /dev/null
+++ b/snprintfv/printf.in
@@ -0,0 +1,318 @@
+/* -*- Mode: C -*- */
+
+/* printf.in --- printf clone for argv arrays
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef SNPRINTFV_SNPRINTFV_H
+#define SNPRINTFV_SNPRINTFV_H 1
+
+#include <snprintfv/compat.h>
+#include <snprintfv/filament.h>
+#include <snprintfv/stream.h>
+#include <snprintfv/mem.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* The type of each element in the table of printf specifiers. */
+struct spec_entry;
+
+typedef enum
+{
+ SNV_ERROR = -1,
+ SNV_OK
+}
+snv_status;
+
+/* Basic states required by the parser. On initialisation the parser
+ will be in SNV_STATE_BEGIN, and tokens will be parsed by the registered
+ functions until the parser reached SNV_STATE_END. */
+#define SNV_STATE_BEGIN 1
+#define SNV_STATE_END 0
+
+/* States needed to support:
+ %[<number>$]<flags>[<width>|\*][.<precision>|\*]<modifiers><specifier> */
+#define SNV_STATE_FLAG (1 << 1)
+#define SNV_STATE_WIDTH (1 << 2)
+#define SNV_STATE_PRECISION (1 << 3)
+#define SNV_STATE_MODIFIER (1 << 4)
+#define SNV_STATE_SPECIFIER (1 << 5)
+
+/* First state available to the user */
+#define SNV_STATE_USER_FIRST (1 << 8)
+
+/* Mask for states available to the user */
+#define SNV_STATE_USER_MASK ~(SNV_STATE_USER_FIRST - 1)
+
+typedef struct printf_info
+{
+ int count; /* accumulated count, or SNV_ERROR */
+ int state; /* one of the defines above */
+ Filament *error; /* accumulated error details */
+
+ const char *format; /* pointer to format string */
+ int argc; /* number of arguments used by format */
+ int argindex; /* number of non-dollar arguments used so far */
+
+ int dollar; /* standard parser state, as in glibc */
+ int prec; /* from this field on, as in glibc */
+ int width;
+
+ snv_pointer extra;
+ int type;
+
+ char spec;
+ char pad;
+ unsigned is_long_double:1;
+ unsigned is_char:1;
+ unsigned is_short:1;
+ unsigned is_long:1;
+ unsigned alt:1;
+ unsigned space:1;
+ unsigned left:1;
+ unsigned showsign:1;
+ unsigned group:1;
+ unsigned wide:1;
+
+ const union printf_arg *args;
+} printf_info;
+
+/**
+ * printf_arg:
+ * @pa_char: an unsigned %char
+ * @pa_wchar: a %wchar_t
+ * @pa_short_int: a %short integer
+ * @pa_int: an %int
+ * @pa_long_int: a %long integer
+ * @pa_long_long_int: the widest signed integer type in use on the host
+ * @pa_u_short_int: an unsigned %short integer
+ * @pa_u_int: an unsigned %int
+ * @pa_u_long_int: an unsigned %long integer
+ * @pa_u_long_long_int: the widest unsigned integer type in use on the host
+ * @pa_float: a %float
+ * @pa_double: a %double
+ * @pa_long_double: a long %double, or a simple %double if it is the widest floating-point type in use on the host
+ * @pa_string: a %const pointer to %char
+ * @pa_wstring: a %const pointer to %wchar_t
+ * @pa_pointer: a generic pointer
+ *
+ * The various kinds of arguments that can be passed to printf.
+ */
+typedef union printf_arg
+{
+ unsigned char pa_char;
+ snv_wchar_t pa_wchar;
+ short int pa_short_int;
+ int pa_int;
+ long int pa_long_int;
+ intmax_t pa_long_long_int;
+ unsigned short int pa_u_short_int;
+ unsigned int pa_u_int;
+ unsigned long int pa_u_long_int;
+ uintmax_t pa_u_long_long_int;
+ float pa_float;
+ double pa_double;
+ long double pa_long_double;
+ const char *pa_string;
+ const snv_wchar_t *pa_wstring;
+ snv_constpointer pa_pointer;
+} printf_arg;
+
+/**
+ * PRINTF_ERROR:
+ * @pi: A pointer to the current state for the parser
+ * @str: The error message
+ *
+ * Append an error that will be returned by printf_strerror.
+ */
+#define PRINTF_ERROR(pi, str) \
+ printf_error(pi, __FILE__, __LINE__, SNV_ASSERT_FCN, str);
+
+typedef int printf_function (STREAM *stream, struct printf_info *pparser,
+ union printf_arg const * args);
+
+typedef int printf_arginfo_function (struct printf_info *pparser, size_t n,
+ int *argtypes);
+
+/**
+ * spec_entry:
+ * @spec: the specifier character that was matched
+ * @type: when @arg is NULL, the type of the only argument to the specifier
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments to the specifier
+ * @user: the user data for the specifier, accessible to the handler function
+ *
+ * This is returned by register_printf_function.
+ */
+typedef struct spec_entry
+{
+ unsigned int spec_key;
+ int unused; /* for binary compatibility */
+ int type;
+ printf_function *fmt;
+ printf_arginfo_function *arg;
+ snv_pointer user;
+}
+spec_entry;
+
+/**
+ * register_callback_function: printf.h
+ * @spec: the character which will trigger the functions, cast to an unsigned int.
+ * @fmt: the handler function to actually print the arguments to the specifier
+ * @arg: the handler function to tell %printf about the types of the arguments to the specifier
+ *
+ * Register the pair made of @fmt and @arg, so that it is called
+ * when @spec is encountered in a format string. If you create
+ * a shared library with an entry point named
+ * %snv_register_printf_funcs, and put the library in the
+ * search path given by the environment library %LTDL_LIBRARY_PATH,
+ * that entry point will be called when %libsnprintfv is initialized,
+ * passing a pointer to this kind of function (actually, a pointer
+ * to %register_printf_function) to it. This functionality is only
+ * present when the library is installed, not when it is built as
+ * a convenience library.
+ *
+ * Return value:
+ * Returns %NULL if @func was not successfully registered, a
+ * %spec_entry with the information on the function if it was.
+ **/
+typedef spec_entry *register_callback_function (unsigned spec, printf_function *func, printf_arginfo_function *arginfo);
+
+/* Codes to determine basic types.
+
+ These values cover all the standard format specifications.
+ Users can add new values after PA_LAST for their own types. */
+
+enum
+{
+ PA_INT, /* int */
+ PA_CHAR, /* int, cast to char */
+ PA_WCHAR, /* wide char */
+ PA_STRING, /* const char *, a '\0'-terminated string */
+ PA_WSTRING, /* const wchar_t *, wide character string */
+ PA_POINTER, /* void * */
+ PA_FLOAT, /* float */
+ PA_DOUBLE, /* double */
+ PA_LAST,
+ PA_UNKNOWN = -1
+};
+
+/* Flag bits that can be set in a type. */
+#define PA_TYPE_MASK 0x00ff
+#define PA_FLAG_MASK ~SNV_TYPE_MASK
+
+#define PA_FLAG_LONG_LONG (1 << 8)
+#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG
+#define PA_FLAG_LONG (1 << 9)
+#define PA_FLAG_SHORT (1 << 10)
+#define PA_FLAG_UNSIGNED (1 << 11)
+#define PA_FLAG_CHAR (1 << 12)
+#define PA_FLAG_PTR (1 << 13)
+
+/**
+ * SNV_EMIT:
+ * @ch: the character to be printed
+ * @stream: the stream on which to print
+ * @count: a variable to be updated with the count of printed
+ * characters
+ *
+ * Maintain the count while putting @ch in @stream, also be careful about
+ * handling %NULL stream if the handler is being called purely to count
+ * output size.
+ **/
+#define SNV_EMIT(ch, stream, count) \
+ SNV_STMT_START { \
+ if ((stream)) \
+ { \
+ if ((count) >= 0) \
+ { \
+ int m_status = stream_put((unsigned char) (ch), (stream)); \
+ (count) = m_status < 0 ? m_status : (count) + m_status; \
+ } \
+ } \
+ else \
+ { \
+ (void)(ch); \
+ (count)++; \
+ } \
+ } SNV_STMT_END
+
+@protos format.c
+@protos custom.c
+@protos printf.c
+
+/* If you don't want to use snprintfv functions for *all* of your string
+ formatting API, then define COMPILING_SNPRINTFV_C and use the snv_
+ prefix for the entry points below. */
+#ifndef COMPILING_PRINTF_C
+#undef printf
+#undef vprintf
+#undef dprintf
+#undef vdprintf
+#undef fprintf
+#undef vfprintf
+#undef sprintf
+#undef vsprintf
+#undef snprintf
+#undef vsnprintf
+#undef asprintf
+#undef vasprintf
+#undef asprintfv
+#undef dprintfv
+#undef fprintfv
+#undef sprintfv
+#undef printfv
+#undef snprintfv
+
+#define printf snv_printf
+#define vprintf snv_vprintf
+#define dprintf snv_dprintf
+#define vdprintf snv_vdprintf
+#define fprintf snv_fprintf
+#define vfprintf snv_vfprintf
+#define sprintf snv_sprintf
+#define vsprintf snv_vsprintf
+#define snprintf snv_snprintf
+#define vsnprintf snv_vsnprintf
+#define asprintf snv_asprintf
+#define vasprintf snv_vasprintf
+#define asprintfv snv_asprintfv
+#define dprintfv snv_dprintfv
+#define fprintfv snv_fprintfv
+#define sprintfv snv_sprintfv
+#define printfv snv_printfv
+#define snprintfv snv_snprintfv
+#endif /* !COMPILING_SNPRINTFV_C */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SNPRINTFV_SNPRINTFV_H */
+
+/* snprintfv.h ends here */
diff --git a/snprintfv/printf.stamp b/snprintfv/printf.stamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/snprintfv/printf.stamp
diff --git a/snprintfv/stream.c b/snprintfv/stream.c
new file mode 100644
index 0000000..a979f33
--- /dev/null
+++ b/snprintfv/stream.c
@@ -0,0 +1,226 @@
+/* -*- Mode: C -*- */
+
+/* stream.c --- customizable stream routines
+ * Copyright (C) 1998, 1999, 2000, 2002, 2003 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WITH_DMALLOC
+# include <dmalloc.h>
+#endif
+
+#include "compat.h"
+#include "stream.h"
+#include "mem.h"
+
+struct stream
+{
+ snv_pointer stream;
+ unsigned long limit;
+
+ StreamGet get_func;
+ StreamPut put_func;
+};
+
+static int
+stream_not_readable (STREAM *stream)
+{
+ (void)stream;
+ return -1;
+}
+
+static int
+stream_not_writable (int ch, STREAM *stream)
+{
+ (void)stream;
+ (void)ch;
+ return -1;
+}
+
+/**
+ * stream_new: constructor
+ * @dets: user supplied stream details to be passed into the various funcs.
+ * @limit: the maximum number of consecutive bytes to fit in @dets.
+ * @get_func: function to get a character from @dets stream.
+ * @put_func: function to put a character in @dets stream.
+ *
+ * Allocate and initialize a new %STREAM data type. The @get_func
+ * and @put_func can be NULL if you intend to create a non-readable
+ * or non-writable stream, respectively.
+ *
+ * Return value:
+ * The address of the newly allocated and initialised stream is returned.
+ **/
+STREAM *
+stream_new (snv_pointer dets, unsigned long limit, StreamGet get_func, StreamPut put_func)
+{
+ STREAM *new = snv_new (STREAM, 1);
+
+ new->stream = dets;
+ new->limit = limit;
+
+ new->get_func = get_func ? get_func : stream_not_readable;
+ new->put_func = put_func ? put_func : stream_not_writable;
+
+ return new;
+}
+
+
+/**
+ * stream_delete: destructor
+ * @stream: The stream pending deletion
+ *
+ * The memory associated with @stream is recycled.
+
+ * Return value:
+ * The %dets supplied by the user when the stream was created are
+ * returned for handling by the calling function.
+ **/
+snv_pointer
+stream_delete (STREAM *stream)
+{
+ snv_pointer dets = stream->stream;
+ snv_delete (stream);
+ return dets;
+}
+
+/**
+ * stream_details:
+ * @stream: the stream being queried.
+ *
+ * The finalization function specified when @stream was created (if any)
+ * is called, and then the memory associated with @stream is recycled.
+ * It is the responsibility of the finalization function to recycle, or
+ * otherwise manage, any memory associated with the user supplied %dets.
+ * Return value:
+ * This function returns the stream details associated with @stream
+ * when it was originally created.
+ **/
+snv_pointer
+stream_details (STREAM *stream)
+{
+ return stream ? stream->stream : NULL;
+}
+
+/**
+ * stream_put:
+ * @ch: A single character to be placed in @stream.
+ * @stream: The stream to be written to.
+ *
+ * This function will @ch in @stream if that stream's output limit will
+ * not be exceeded.
+ *
+ * Return value:
+ * If @stream is full, return 1. Otherwise, if any other error occurs,
+ * that error code is returned unchanged. This is of course dependant
+ * on what the handler function uses to indicate an error. If the stream
+ * is not full and the stream's writing function succeeds, 1 (the number of
+ * characters emitted!) is returned.
+ **/
+int
+stream_put (int ch, STREAM *stream)
+{
+ int ch_or_errorcode;
+
+ if (!stream)
+ return -1;
+
+ if (stream->limit < 1)
+ return 1;
+
+ stream->limit -= 1;
+ ch_or_errorcode = (*stream->put_func) ((unsigned char) ch, stream);
+
+ return (ch_or_errorcode < 0) ? ch_or_errorcode : 1;
+}
+
+/**
+ * stream_puts:
+ * @s: A string to be placed in @stream.
+ * @stream: The stream to be written to.
+ *
+ * This function will @ch in @stream if that stream's output limit will
+ * not be exceeded.
+ *
+ * Return value:
+ * If any other error occurs, that error code is returned unchanged.
+ * This is of course dependant on what the handler function uses to
+ * indicate an error. If the stream becomes full, the remaining
+ * characters are not printed. If the stream's writing function
+ * always succeeds, the number of characters emitted or skipped is
+ * returned.
+ **/
+int
+stream_puts (char *s, STREAM *stream)
+{
+ int ch_or_errorcode;
+ int num;
+
+ if (!stream)
+ return -1;
+
+ for (num = 0; *s; num++, s++)
+ {
+ if (stream->limit < 1)
+ return num + strlen (s);
+
+ stream->limit -= 1;
+ ch_or_errorcode = (*stream->put_func) ((unsigned char) *s, stream);
+
+ if (ch_or_errorcode < 0)
+ return ch_or_errorcode;
+ }
+
+ return num;
+}
+
+/**
+ * stream_get:
+ * @stream: The stream to be read from.
+ *
+ * This function will try to read a single character from @stream.
+ *
+ * Return value:
+ * If an error occurs or the end of @stream is reached, -1 is returned.
+ * Under normal circumstances the value if the character read (cast to
+ * an int) is returned.
+ **/
+int
+stream_get (STREAM *stream)
+{
+ return (*stream->get_func) (stream);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "gnu"
+ * indent-tabs-mode: nil
+ * End:
+ * end of snprintfv/stream.c */
diff --git a/snprintfv/stream.h b/snprintfv/stream.h
new file mode 100644
index 0000000..0f47855
--- /dev/null
+++ b/snprintfv/stream.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C -*- */
+
+/* stream.h --- customizable stream routines
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#define STREAM_READABLE (1 << 0)
+#define STREAM_WRITABLE (1 << 1)
+
+/**
+ * SNV_UNLIMITED:
+ * Used to denote that there is no upper limit to the number of characters
+ * that can safely be written to a stream.
+ **/
+#define SNV_UNLIMITED (~0UL)
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+/* This brace is so that emacs can still indent properly: */ }
+#endif
+#endif /* __cplusplus */
+
+/**
+ * STREAM:
+ * Data type used to pass details of streams between functions,
+ * much like stdio's %FILE, but more flexible. A %STREAM can be uni- or
+ * bi-directional depending on how it is initialised.
+ **/
+typedef struct stream STREAM;
+
+/**
+ * StreamPut:
+ * @ch: The character to write to @stream cast to an int.
+ * @stream: The stream being written to.
+ *
+ * Type of the function to put a character in a writeable stream.
+ *
+ * Return value:
+ * The function should return the character written to the
+ * stream, cast to an int if it was written successfully, or
+ * else %EOF, if the write failed.
+ **/
+typedef int (*StreamPut) (int ch, STREAM * stream);
+
+/**
+ * StreamGet:
+ * @stream: The stream being read from.
+ *
+ * Type of the function to get a character from a readable stream.
+ *
+ * Return value:
+ * The function should return the character read from the
+ * stream, cast to an int if it was read successfully, or
+ * else %EOF, if the read failed.
+ **/
+typedef int (*StreamGet) (STREAM * stream);
+
+
+/**
+ * stream_new: constructor
+ * @dets: user supplied stream details to be passed into the various funcs.
+ * @limit: the maximum number of consecutive bytes to fit in @dets.
+ * @get_func: function to get a character from @dets stream.
+ * @put_func: function to put a character in @dets stream.
+ *
+ * Allocate and initialize a new %STREAM data type. The @get_func
+ * and @put_func can be NULL if you intend to create a non-readable
+ * or non-writable stream, respectively.
+ *
+ * Return value:
+ * The address of the newly allocated and initialised stream is returned.
+ **/
+extern STREAM *
+stream_new (snv_pointer dets, unsigned long limit, StreamGet get_func, StreamPut put_func);
+
+/**
+ * stream_delete: destructor
+ * @stream: The stream pending deletion
+ *
+ * The memory associated with @stream is recycled.
+
+ * Return value:
+ * The %dets supplied by the user when the stream was created are
+ * returned for handling by the calling function.
+ **/
+extern snv_pointer
+stream_delete (STREAM *stream);
+
+/**
+ * stream_details:
+ * @stream: the stream being queried.
+ *
+ * The finalization function specified when @stream was created (if any)
+ * is called, and then the memory associated with @stream is recycled.
+ * It is the responsibility of the finalization function to recycle, or
+ * otherwise manage, any memory associated with the user supplied %dets.
+ * Return value:
+ * This function returns the stream details associated with @stream
+ * when it was originally created.
+ **/
+extern snv_pointer
+stream_details (STREAM *stream);
+
+/**
+ * stream_put:
+ * @ch: A single character to be placed in @stream.
+ * @stream: The stream to be written to.
+ *
+ * This function will @ch in @stream if that stream's output limit will
+ * not be exceeded.
+ *
+ * Return value:
+ * If @stream is full, return 1. Otherwise, if any other error occurs,
+ * that error code is returned unchanged. This is of course dependant
+ * on what the handler function uses to indicate an error. If the stream
+ * is not full and the stream's writing function succeeds, 1 (the number of
+ * characters emitted!) is returned.
+ **/
+extern int
+stream_put (int ch, STREAM *stream);
+
+/**
+ * stream_puts:
+ * @s: A string to be placed in @stream.
+ * @stream: The stream to be written to.
+ *
+ * This function will @ch in @stream if that stream's output limit will
+ * not be exceeded.
+ *
+ * Return value:
+ * If any other error occurs, that error code is returned unchanged.
+ * This is of course dependant on what the handler function uses to
+ * indicate an error. If the stream becomes full, the remaining
+ * characters are not printed. If the stream's writing function
+ * always succeeds, the number of characters emitted or skipped is
+ * returned.
+ **/
+extern int
+stream_puts (char *s, STREAM *stream);
+
+/**
+ * stream_get:
+ * @stream: The stream to be read from.
+ *
+ * This function will try to read a single character from @stream.
+ *
+ * Return value:
+ * If an error occurs or the end of @stream is reached, -1 is returned.
+ * Under normal circumstances the value if the character read (cast to
+ * an int) is returned.
+ **/
+extern int
+stream_get (STREAM *stream);
+
+#line 88 "stream.in"
+#ifdef __cplusplus
+#if 0
+/* This brace is so that emacs can still indent properly: */
+{
+#endif
+}
+#endif /* __cplusplus */
+
+#endif /* STREAM_H */
diff --git a/snprintfv/stream.in b/snprintfv/stream.in
new file mode 100644
index 0000000..fbcf431
--- /dev/null
+++ b/snprintfv/stream.in
@@ -0,0 +1,96 @@
+/* -*- Mode: C -*- */
+
+/* stream.h --- customizable stream routines
+ * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
+ * Originally by Gary V. Vaughan, 1998
+ * This file is part of Snprintfv
+ *
+ * Snprintfv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Snprintfv program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * As a special exception to the GNU General Public License, if you
+ * distribute this file as part of a program that also links with and
+ * uses the libopts library from AutoGen, you may include it under
+ * the same distribution terms used by the libopts library.
+ */
+
+/* Code: */
+
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#define STREAM_READABLE (1 << 0)
+#define STREAM_WRITABLE (1 << 1)
+
+/**
+ * SNV_UNLIMITED:
+ * Used to denote that there is no upper limit to the number of characters
+ * that can safely be written to a stream.
+ **/
+#define SNV_UNLIMITED (~0UL)
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+/* This brace is so that emacs can still indent properly: */ }
+#endif
+#endif /* __cplusplus */
+
+/**
+ * STREAM:
+ * Data type used to pass details of streams between functions,
+ * much like stdio's %FILE, but more flexible. A %STREAM can be uni- or
+ * bi-directional depending on how it is initialised.
+ **/
+typedef struct stream STREAM;
+
+/**
+ * StreamPut:
+ * @ch: The character to write to @stream cast to an int.
+ * @stream: The stream being written to.
+ *
+ * Type of the function to put a character in a writeable stream.
+ *
+ * Return value:
+ * The function should return the character written to the
+ * stream, cast to an int if it was written successfully, or
+ * else %EOF, if the write failed.
+ **/
+typedef int (*StreamPut) (int ch, STREAM * stream);
+
+/**
+ * StreamGet:
+ * @stream: The stream being read from.
+ *
+ * Type of the function to get a character from a readable stream.
+ *
+ * Return value:
+ * The function should return the character read from the
+ * stream, cast to an int if it was read successfully, or
+ * else %EOF, if the read failed.
+ **/
+typedef int (*StreamGet) (STREAM * stream);
+
+
+@protos stream.c
+#ifdef __cplusplus
+#if 0
+/* This brace is so that emacs can still indent properly: */
+{
+#endif
+}
+#endif /* __cplusplus */
+
+#endif /* STREAM_H */
diff --git a/snprintfv/stream.stamp b/snprintfv/stream.stamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/snprintfv/stream.stamp