aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gl/Makefile.am93
-rw-r--r--gl/alloca_.h52
-rw-r--r--gl/allocsa.c139
-rw-r--r--gl/allocsa.h113
-rw-r--r--gl/allocsa.valgrind7
-rw-r--r--gl/asnprintf.c37
-rw-r--r--gl/asprintf.c37
-rw-r--r--gl/m4/alloca.m442
-rw-r--r--gl/m4/allocsa.m415
-rw-r--r--gl/m4/eealloc.m432
-rw-r--r--gl/m4/eoverflow.m464
-rw-r--r--gl/m4/gnulib.m446
-rw-r--r--gl/m4/intmax_t.m461
-rw-r--r--gl/m4/inttypes_h.m426
-rw-r--r--gl/m4/longdouble.m428
-rw-r--r--gl/m4/longlong.m423
-rw-r--r--gl/m4/mkdtemp.m423
-rw-r--r--gl/m4/onceonly_2_57.m486
-rw-r--r--gl/m4/setenv.m470
-rw-r--r--gl/m4/signed.m417
-rw-r--r--gl/m4/size_max.m459
-rw-r--r--gl/m4/stdint_h.m426
-rw-r--r--gl/m4/strpbrk.m416
-rw-r--r--gl/m4/strsep.m417
-rw-r--r--gl/m4/uintmax_t.m430
-rw-r--r--gl/m4/ulonglong.m423
-rw-r--r--gl/m4/vasnprintf.m458
-rw-r--r--gl/m4/vasprintf.m425
-rw-r--r--gl/m4/wchar_t.m420
-rw-r--r--gl/m4/wint_t.m420
-rw-r--r--gl/m4/xsize.m413
-rw-r--r--gl/mkdtemp.c203
-rw-r--r--gl/mkdtemp.h32
-rw-r--r--gl/printf-args.c118
-rw-r--r--gl/printf-args.h136
-rw-r--r--gl/printf-parse.c536
-rw-r--r--gl/printf-parse.h74
-rw-r--r--gl/setenv.c328
-rw-r--r--gl/setenv.h54
-rw-r--r--gl/strpbrk.c42
-rw-r--r--gl/strpbrk.h28
-rw-r--r--gl/strsep.c55
-rw-r--r--gl/strsep.h52
-rw-r--r--gl/unsetenv.c99
-rw-r--r--gl/vasnprintf.c901
-rw-r--r--gl/vasnprintf.h77
-rw-r--r--gl/vasprintf.c42
-rw-r--r--gl/vasprintf.h63
-rw-r--r--gl/xsize.h108
49 files changed, 4266 insertions, 0 deletions
diff --git a/gl/Makefile.am b/gl/Makefile.am
new file mode 100644
index 000000000..be8e6a5b6
--- /dev/null
+++ b/gl/Makefile.am
@@ -0,0 +1,93 @@
+## Process this file with automake to produce Makefile.in.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+#
+# This file is free software, distributed under the terms of the GNU
+# General Public License. As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Automake, under
+# the same distribution terms as the rest of that program.
+#
+# Generated by gnulib-tool.
+# Invoked as: gnulib-tool --import
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --aux-dir=scripts alloca-opt allocsa mkdtemp setenv strpbrk strsep vasnprintf vasprintf xsize
+
+AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies
+
+noinst_LIBRARIES = libgnu.a
+
+libgnu_a_SOURCES =
+libgnu_a_LIBADD = @LIBOBJS@
+EXTRA_DIST =
+BUILT_SOURCES =
+SUFFIXES =
+MOSTLYCLEANFILES =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
+
+## begin gnulib module alloca-opt
+
+BUILT_SOURCES += $(ALLOCA_H)
+EXTRA_DIST += alloca_.h
+
+# We need the following in order to create an <alloca.h> when the system
+# doesn't have one that works with the given compiler.
+all-local $(libgnu_a_OBJECTS): $(ALLOCA_H)
+alloca.h: alloca_.h
+ cp $(srcdir)/alloca_.h $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += alloca.h alloca.h-t
+
+## end gnulib module alloca-opt
+
+## begin gnulib module allocsa
+
+libgnu_a_SOURCES += allocsa.h allocsa.c
+EXTRA_DIST += allocsa.valgrind
+
+## end gnulib module allocsa
+
+## begin gnulib module mkdtemp
+
+libgnu_a_SOURCES += mkdtemp.h
+
+## end gnulib module mkdtemp
+
+## begin gnulib module setenv
+
+libgnu_a_SOURCES += setenv.h
+
+## end gnulib module setenv
+
+## begin gnulib module strpbrk
+
+libgnu_a_SOURCES += strpbrk.h
+
+## end gnulib module strpbrk
+
+## begin gnulib module strsep
+
+libgnu_a_SOURCES += strsep.h
+
+## end gnulib module strsep
+
+## begin gnulib module vasnprintf
+
+libgnu_a_SOURCES += printf-args.h printf-parse.h vasnprintf.h
+
+## end gnulib module vasnprintf
+
+## begin gnulib module vasprintf
+
+libgnu_a_SOURCES += vasprintf.h
+
+## end gnulib module vasprintf
+
+## begin gnulib module xsize
+
+libgnu_a_SOURCES += xsize.h
+
+## end gnulib module xsize
+
+
+# Makefile.am ends here
diff --git a/gl/alloca_.h b/gl/alloca_.h
new file mode 100644
index 000000000..3e3fdf43f
--- /dev/null
+++ b/gl/alloca_.h
@@ -0,0 +1,52 @@
+/* Memory allocation on the stack.
+
+ Copyright (C) 1995, 1999, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
+ means there is a real alloca function. */
+#ifndef _GNULIB_ALLOCA_H
+# define _GNULIB_ALLOCA_H
+
+/* alloca (N) returns a pointer to N bytes of memory
+ allocated on the stack, which will last until the function returns.
+ Use of alloca should be avoided:
+ - inside arguments of function calls - undefined behaviour,
+ - in inline functions - the allocation may actually last until the
+ calling function returns,
+ - for huge N (say, N >= 65536) - you never know how large (or small)
+ the stack is, and when the stack cannot fulfill the memory allocation
+ request, the program just crashes.
+ */
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#endif /* _GNULIB_ALLOCA_H */
diff --git a/gl/allocsa.c b/gl/allocsa.c
new file mode 100644
index 000000000..a54e2d0ca
--- /dev/null
+++ b/gl/allocsa.c
@@ -0,0 +1,139 @@
+/* Safe automatic memory allocation.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Written by Bruno Haible <[email protected]>, 2003.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "allocsa.h"
+
+/* The speed critical point in this file is freesa() applied to an alloca()
+ result: it must be fast, to match the speed of alloca(). The speed of
+ mallocsa() and freesa() in the other case are not critical, because they
+ are only invoked for big memory sizes. */
+
+#if HAVE_ALLOCA
+
+/* Store the mallocsa() results in a hash table. This is needed to reliably
+ distinguish a mallocsa() result and an alloca() result.
+
+ Although it is possible that the same pointer is returned by alloca() and
+ by mallocsa() at different times in the same application, it does not lead
+ to a bug in freesa(), because:
+ - Before a pointer returned by alloca() can point into malloc()ed memory,
+ the function must return, and once this has happened the programmer must
+ not call freesa() on it anyway.
+ - Before a pointer returned by mallocsa() can point into the stack, it
+ must be freed. The only function that can free it is freesa(), and
+ when freesa() frees it, it also removes it from the hash table. */
+
+#define MAGIC_NUMBER 0x1415fb4a
+#define MAGIC_SIZE sizeof (int)
+/* This is how the header info would look like without any alignment
+ considerations. */
+struct preliminary_header { void *next; char room[MAGIC_SIZE]; };
+/* But the header's size must be a multiple of sa_alignment_max. */
+#define HEADER_SIZE \
+ (((sizeof (struct preliminary_header) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max)
+struct header { void *next; char room[HEADER_SIZE - sizeof (struct preliminary_header) + MAGIC_SIZE]; };
+/* Verify that HEADER_SIZE == sizeof (struct header). */
+typedef int verify1[2 * (HEADER_SIZE == sizeof (struct header)) - 1];
+/* We make the hash table quite big, so that during lookups the probability
+ of empty hash buckets is quite high. There is no need to make the hash
+ table resizable, because when the hash table gets filled so much that the
+ lookup becomes slow, it means that the application has memory leaks. */
+#define HASH_TABLE_SIZE 257
+static void * mallocsa_results[HASH_TABLE_SIZE];
+
+#endif
+
+void *
+mallocsa (size_t n)
+{
+#if HAVE_ALLOCA
+ /* Allocate one more word, that serves as an indicator for malloc()ed
+ memory, so that freesa() of an alloca() result is fast. */
+ size_t nplus = n + HEADER_SIZE;
+
+ if (nplus >= n)
+ {
+ char *p = (char *) malloc (nplus);
+
+ if (p != NULL)
+ {
+ size_t slot;
+
+ p += HEADER_SIZE;
+
+ /* Put a magic number into the indicator word. */
+ ((int *) p)[-1] = MAGIC_NUMBER;
+
+ /* Enter p into the hash table. */
+ slot = (unsigned long) p % HASH_TABLE_SIZE;
+ ((struct header *) (p - HEADER_SIZE))->next = mallocsa_results[slot];
+ mallocsa_results[slot] = p;
+
+ return p;
+ }
+ }
+ /* Out of memory. */
+ return NULL;
+#else
+# if !MALLOC_0_IS_NONNULL
+ if (n == 0)
+ n = 1;
+# endif
+ return malloc (n);
+#endif
+}
+
+#if HAVE_ALLOCA
+void
+freesa (void *p)
+{
+ /* mallocsa() may have returned NULL. */
+ if (p != NULL)
+ {
+ /* Attempt to quickly distinguish the mallocsa() result - which has
+ a magic indicator word - and the alloca() result - which has an
+ uninitialized indicator word. It is for this test that sa_increment
+ additional bytes are allocated in the alloca() case. */
+ if (((int *) p)[-1] == MAGIC_NUMBER)
+ {
+ /* Looks like a mallocsa() result. To see whether it really is one,
+ perform a lookup in the hash table. */
+ size_t slot = (unsigned long) p % HASH_TABLE_SIZE;
+ void **chain = &mallocsa_results[slot];
+ for (; *chain != NULL;)
+ {
+ if (*chain == p)
+ {
+ /* Found it. Remove it from the hash table and free it. */
+ char *p_begin = (char *) p - HEADER_SIZE;
+ *chain = ((struct header *) p_begin)->next;
+ free (p_begin);
+ return;
+ }
+ chain = &((struct header *) ((char *) *chain - HEADER_SIZE))->next;
+ }
+ }
+ /* At this point, we know it was not a mallocsa() result. */
+ }
+}
+#endif
diff --git a/gl/allocsa.h b/gl/allocsa.h
new file mode 100644
index 000000000..cb6893ad1
--- /dev/null
+++ b/gl/allocsa.h
@@ -0,0 +1,113 @@
+/* Safe automatic memory allocation.
+ Copyright (C) 2003-2004 Free Software Foundation, Inc.
+ Written by Bruno Haible <[email protected]>, 2003.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _ALLOCSA_H
+#define _ALLOCSA_H
+
+#include <alloca.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/* safe_alloca(N) is equivalent to alloca(N) when it is safe to call
+ alloca(N); otherwise it returns NULL. It either returns N bytes of
+ memory allocated on the stack, that lasts until the function returns,
+ or NULL.
+ Use of safe_alloca should be avoided:
+ - inside arguments of function calls - undefined behaviour,
+ - in inline functions - the allocation may actually last until the
+ calling function returns.
+*/
+#if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots.
+ This must be a macro, not an inline function. */
+# define safe_alloca(N) ((N) < 4032 ? alloca (N) : NULL)
+#else
+# define safe_alloca(N) ((N), NULL)
+#endif
+
+/* allocsa(N) is a safe variant of alloca(N). It allocates N bytes of
+ memory allocated on the stack, that must be freed using freesa() before
+ the function returns. Upon failure, it returns NULL. */
+#if HAVE_ALLOCA
+# define allocsa(N) \
+ ((N) < 4032 - sa_increment \
+ ? (void *) ((char *) alloca ((N) + sa_increment) + sa_increment) \
+ : mallocsa (N))
+#else
+# define allocsa(N) \
+ mallocsa (N)
+#endif
+extern void * mallocsa (size_t n);
+
+/* Free a block of memory allocated through allocsa(). */
+#if HAVE_ALLOCA
+extern void freesa (void *p);
+#else
+# define freesa free
+#endif
+
+/* Maybe we should also define a variant
+ nallocsa (size_t n, size_t s) - behaves like allocsa (n * s)
+ If this would be useful in your application. please speak up. */
+
+
+/* ------------------- Auxiliary, non-public definitions ------------------- */
+
+/* Determine the alignment of a type at compile time. */
+#if defined __GNUC__
+# define sa_alignof __alignof__
+#elif defined __cplusplus
+ template <class type> struct sa_alignof_helper { char __slot1; type __slot2; };
+# define sa_alignof(type) offsetof (sa_alignof_helper<type>, __slot2)
+#elif defined __hpux
+ /* Work around a HP-UX 10.20 cc bug with enums constants defined as offsetof
+ values. */
+# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
+#else
+# define sa_alignof(type) offsetof (struct { char __slot1; type __slot2; }, __slot2)
+#endif
+
+enum
+{
+/* The desired alignment of memory allocations is the maximum alignment
+ among all elementary types. */
+ sa_alignment_long = sa_alignof (long),
+ sa_alignment_double = sa_alignof (double),
+#ifdef HAVE_LONG_LONG
+ sa_alignment_longlong = sa_alignof (long long),
+#endif
+#ifdef HAVE_LONG_DOUBLE
+ sa_alignment_longdouble = sa_alignof (long double),
+#endif
+ sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1)
+#ifdef HAVE_LONG_LONG
+ | (sa_alignment_longlong - 1)
+#endif
+#ifdef HAVE_LONG_DOUBLE
+ | (sa_alignment_longdouble - 1)
+#endif
+ ) + 1,
+/* The increment that guarantees room for a magic word must be >= sizeof (int)
+ and a multiple of sa_alignment_max. */
+ sa_increment = ((sizeof (int) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max
+};
+
+#endif /* _ALLOCSA_H */
diff --git a/gl/allocsa.valgrind b/gl/allocsa.valgrind
new file mode 100644
index 000000000..f4c77d686
--- /dev/null
+++ b/gl/allocsa.valgrind
@@ -0,0 +1,7 @@
+# Suppress a valgrind message about use of uninitialized memory in freesa().
+# This use is OK because it provides only a speedup.
+{
+ freesa
+ Memcheck:Cond
+ fun:freesa
+}
diff --git a/gl/asnprintf.c b/gl/asnprintf.c
new file mode 100644
index 000000000..1b7f4ba39
--- /dev/null
+++ b/gl/asnprintf.c
@@ -0,0 +1,37 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasnprintf.h"
+
+#include <stdarg.h>
+
+char *
+asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+{
+ va_list args;
+ char *result;
+
+ va_start (args, format);
+ result = vasnprintf (resultbuf, lengthp, format, args);
+ va_end (args);
+ return result;
+}
diff --git a/gl/asprintf.c b/gl/asprintf.c
new file mode 100644
index 000000000..7c4e64a24
--- /dev/null
+++ b/gl/asprintf.c
@@ -0,0 +1,37 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasprintf.h"
+
+#include <stdarg.h>
+
+int
+asprintf (char **resultp, const char *format, ...)
+{
+ va_list args;
+ int result;
+
+ va_start (args, format);
+ result = vasprintf (resultp, format, args);
+ va_end (args);
+ return result;
+}
diff --git a/gl/m4/alloca.m4 b/gl/m4/alloca.m4
new file mode 100644
index 000000000..a9e3f452c
--- /dev/null
+++ b/gl/m4/alloca.m4
@@ -0,0 +1,42 @@
+# alloca.m4 serial 5
+dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_ALLOCA],
+[
+ dnl Work around a bug of AC_EGREP_CPP in autoconf-2.57.
+ AC_REQUIRE([AC_PROG_CPP])
+ AC_REQUIRE([AC_PROG_EGREP])
+
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ if test $ac_cv_func_alloca_works = no; then
+ gl_PREREQ_ALLOCA
+ fi
+
+ # Define an additional variable used in the Makefile substitution.
+ if test $ac_cv_working_alloca_h = yes; then
+ AC_EGREP_CPP([Need own alloca], [
+#if defined __GNUC__ || defined _AIX || defined _MSC_VER
+ Need own alloca
+#endif
+ ],
+ [AC_DEFINE(HAVE_ALLOCA, 1,
+ [Define to 1 if you have `alloca' after including <alloca.h>,
+ a header that may be supplied by this distribution.])
+ ALLOCA_H=alloca.h],
+ [ALLOCA_H=])
+ else
+ ALLOCA_H=alloca.h
+ fi
+ AC_SUBST([ALLOCA_H])
+
+ AC_DEFINE(HAVE_ALLOCA_H, 1,
+ [Define HAVE_ALLOCA_H for backward compatibility with older code
+ that includes <alloca.h> only if HAVE_ALLOCA_H is defined.])
+])
+
+# Prerequisites of lib/alloca.c.
+# STACK_DIRECTION is already handled by AC_FUNC_ALLOCA.
+AC_DEFUN([gl_PREREQ_ALLOCA], [:])
diff --git a/gl/m4/allocsa.m4 b/gl/m4/allocsa.m4
new file mode 100644
index 000000000..474862fe3
--- /dev/null
+++ b/gl/m4/allocsa.m4
@@ -0,0 +1,15 @@
+# allocsa.m4 serial 3
+dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_ALLOCSA],
+[
+ dnl Use the autoconf tests for alloca(), but not the AC_SUBSTed variables
+ dnl @ALLOCA@ and @LTALLOCA@.
+ AC_REQUIRE([gl_FUNC_ALLOCA])
+ AC_REQUIRE([gl_EEMALLOC])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+])
diff --git a/gl/m4/eealloc.m4 b/gl/m4/eealloc.m4
new file mode 100644
index 000000000..adcfd06c9
--- /dev/null
+++ b/gl/m4/eealloc.m4
@@ -0,0 +1,32 @@
+# eealloc.m4 serial 1
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_EEALLOC],
+[
+ AC_REQUIRE([gl_EEMALLOC])
+ AC_REQUIRE([gl_EEREALLOC])
+ AC_REQUIRE([AC_C_INLINE])
+])
+
+AC_DEFUN([gl_EEMALLOC],
+[
+ _AC_FUNC_MALLOC_IF(
+ [gl_cv_func_malloc_0_nonnull=1],
+ [gl_cv_func_malloc_0_nonnull=0])
+ AC_DEFINE_UNQUOTED([MALLOC_0_IS_NONNULL], $gl_cv_func_malloc_0_nonnull,
+ [If malloc(0) is != NULL, define this to 1. Otherwise define this
+ to 0.])
+])
+
+AC_DEFUN([gl_EEREALLOC],
+[
+ _AC_FUNC_REALLOC_IF(
+ [gl_cv_func_realloc_0_nonnull=1],
+ [gl_cv_func_realloc_0_nonnull=0])
+ AC_DEFINE_UNQUOTED([REALLOC_0_IS_NONNULL], $gl_cv_func_realloc_0_nonnull,
+ [If realloc(NULL,0) is != NULL, define this to 1. Otherwise define this
+ to 0.])
+])
diff --git a/gl/m4/eoverflow.m4 b/gl/m4/eoverflow.m4
new file mode 100644
index 000000000..8c28ca305
--- /dev/null
+++ b/gl/m4/eoverflow.m4
@@ -0,0 +1,64 @@
+# eoverflow.m4 serial 1
+dnl Copyright (C) 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+# The EOVERFLOW errno value ought to be defined in <errno.h>, according to
+# POSIX. But some systems (like AIX 3) don't define it, and some systems
+# (like OSF/1) define it when _XOPEN_SOURCE_EXTENDED is defined.
+
+# Define EOVERFLOW as a C macro and as a substituted macro in such a way that
+# 1. on all systems, after inclusion of <errno.h>, EOVERFLOW is usable,
+# 2. on systems where EOVERFLOW is defined elsewhere, we use the same numeric
+# value.
+
+AC_DEFUN([gl_EOVERFLOW],
+[
+ AC_REQUIRE([AC_PROG_CC])dnl
+
+ AC_CACHE_CHECK([for EOVERFLOW], ac_cv_decl_EOVERFLOW, [
+ AC_EGREP_CPP(yes,[
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+ ], have_eoverflow=1)
+ if test -n "$have_eoverflow"; then
+ dnl EOVERFLOW exists in <errno.h>. Don't need to define EOVERFLOW ourselves.
+ ac_cv_decl_EOVERFLOW=yes
+ else
+ AC_EGREP_CPP(yes,[
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+#ifdef EOVERFLOW
+yes
+#endif
+ ], have_eoverflow=1)
+ if test -n "$have_eoverflow"; then
+ dnl EOVERFLOW exists but is hidden.
+ dnl Define it to the same value.
+ _AC_COMPUTE_INT([EOVERFLOW], ac_cv_decl_EOVERFLOW, [
+#define _XOPEN_SOURCE_EXTENDED 1
+#include <errno.h>
+/* The following two lines are a workaround against an autoconf-2.52 bug. */
+#include <stdio.h>
+#include <stdlib.h>
+])
+ else
+ dnl EOVERFLOW isn't defined by the system. Define EOVERFLOW ourselves, but
+ dnl don't define it as EINVAL, because snprintf() callers want to
+ dnl distinguish EINVAL and EOVERFLOW.
+ ac_cv_decl_EOVERFLOW=E2BIG
+ fi
+ fi
+ ])
+ if test "$ac_cv_decl_EOVERFLOW" != yes; then
+ AC_DEFINE_UNQUOTED([EOVERFLOW], [$ac_cv_decl_EOVERFLOW],
+ [Define as good substitute value for EOVERFLOW.])
+ EOVERFLOW="$ac_cv_decl_EOVERFLOW"
+ AC_SUBST(EOVERFLOW)
+ fi
+])
diff --git a/gl/m4/gnulib.m4 b/gl/m4/gnulib.m4
new file mode 100644
index 000000000..46d5e338b
--- /dev/null
+++ b/gl/m4/gnulib.m4
@@ -0,0 +1,46 @@
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# This file is free software, distributed under the terms of the GNU
+# General Public License. As a special exception to the GNU General
+# Public License, this file may be distributed as part of a program
+# that contains a configuration script generated by Autoconf, under
+# the same distribution terms as the rest of that program.
+#
+# Generated by gnulib-tool.
+#
+# Invoked as: gnulib-tool --import
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --aux-dir=scripts alloca-opt allocsa mkdtemp setenv strpbrk strsep vasnprintf vasprintf xsize
+
+AC_DEFUN([gl_EARLY],
+[
+ AC_GNU_SOURCE
+])
+
+AC_DEFUN([gl_INIT],
+[
+ gl_FUNC_ALLOCA
+ gl_ALLOCSA
+ gt_FUNC_MKDTEMP
+ gt_FUNC_SETENV
+ gl_FUNC_STRPBRK
+ gl_FUNC_STRSEP
+ gl_FUNC_VASNPRINTF
+ gl_FUNC_VASPRINTF
+ gl_XSIZE
+])
+
+dnl Usage: gl_MODULES(module1 module2 ...)
+AC_DEFUN([gl_MODULES], [])
+
+dnl Usage: gl_SOURCE_BASE(DIR)
+AC_DEFUN([gl_SOURCE_BASE], [])
+
+dnl Usage: gl_M4_BASE(DIR)
+AC_DEFUN([gl_M4_BASE], [])
+
+dnl Usage: gl_LIB(LIBNAME)
+AC_DEFUN([gl_LIB], [])
+
+dnl Usage: gl_LGPL
+AC_DEFUN([gl_LGPL], [])
+
+# gnulib.m4 ends here
diff --git a/gl/m4/intmax_t.m4 b/gl/m4/intmax_t.m4
new file mode 100644
index 000000000..44b16523c
--- /dev/null
+++ b/gl/m4/intmax_t.m4
@@ -0,0 +1,61 @@
+# intmax_t.m4 serial 4
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ(2.13)
+
+# Define intmax_t to 'long' or 'long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_INTMAX_T],
+[
+ dnl For simplicity, we assume that a header file defines 'intmax_t' if and
+ dnl only if it defines 'uintmax_t'.
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+ AC_DEFINE_UNQUOTED(intmax_t, $ac_type,
+ [Define to long or long long if <inttypes.h> and <stdint.h> don't define.])
+ else
+ AC_DEFINE(HAVE_INTMAX_T, 1,
+ [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+ fi
+])
+
+dnl An alternative would be to explicitly test for 'intmax_t'.
+
+AC_DEFUN([gt_AC_TYPE_INTMAX_T],
+[
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t,
+ [AC_TRY_COMPILE([
+#include <stddef.h>
+#include <stdlib.h>
+#if HAVE_STDINT_H_WITH_UINTMAX
+#include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+#include <inttypes.h>
+#endif
+], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)])
+ if test $gt_cv_c_intmax_t = yes; then
+ AC_DEFINE(HAVE_INTMAX_T, 1,
+ [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.])
+ else
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ test $ac_cv_type_long_long = yes \
+ && ac_type='long long' \
+ || ac_type='long'
+ AC_DEFINE_UNQUOTED(intmax_t, $ac_type,
+ [Define to long or long long if <stdint.h> and <inttypes.h> don't define.])
+ fi
+])
diff --git a/gl/m4/inttypes_h.m4 b/gl/m4/inttypes_h.m4
new file mode 100644
index 000000000..a5d075d96
--- /dev/null
+++ b/gl/m4/inttypes_h.m4
@@ -0,0 +1,26 @@
+# inttypes_h.m4 serial 6
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_INTTYPES_H_WITH_UINTMAX if <inttypes.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_INTTYPES_H],
+[
+ AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h,
+ [AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <inttypes.h>],
+ [uintmax_t i = (uintmax_t) -1;],
+ gl_cv_header_inttypes_h=yes,
+ gl_cv_header_inttypes_h=no)])
+ if test $gl_cv_header_inttypes_h = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1,
+ [Define if <inttypes.h> exists, doesn't clash with <sys/types.h>,
+ and declares uintmax_t. ])
+ fi
+])
diff --git a/gl/m4/longdouble.m4 b/gl/m4/longdouble.m4
new file mode 100644
index 000000000..40cd7ce02
--- /dev/null
+++ b/gl/m4/longdouble.m4
@@ -0,0 +1,28 @@
+# longdouble.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether the compiler supports the 'long double' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_LONGDOUBLE],
+[
+ AC_CACHE_CHECK([for long double], gt_cv_c_long_double,
+ [if test "$GCC" = yes; then
+ gt_cv_c_long_double=yes
+ else
+ AC_TRY_COMPILE([
+ /* The Stardent Vistra knows sizeof(long double), but does not support it. */
+ long double foo = 0.0;
+ /* On Ultrix 4.3 cc, long double is 4 and double is 8. */
+ int array [2*(sizeof(long double) >= sizeof(double)) - 1];
+ ], ,
+ gt_cv_c_long_double=yes, gt_cv_c_long_double=no)
+ fi])
+ if test $gt_cv_c_long_double = yes; then
+ AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.])
+ fi
+])
diff --git a/gl/m4/longlong.m4 b/gl/m4/longlong.m4
new file mode 100644
index 000000000..7b399e012
--- /dev/null
+++ b/gl/m4/longlong.m4
@@ -0,0 +1,23 @@
+# longlong.m4 serial 5
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_LONG_LONG if 'long long' works.
+
+AC_DEFUN([gl_AC_TYPE_LONG_LONG],
+[
+ AC_CACHE_CHECK([for long long], ac_cv_type_long_long,
+ [AC_TRY_LINK([long long ll = 1LL; int i = 63;],
+ [long long llmax = (long long) -1;
+ return ll << i | ll >> i | llmax / ll | llmax % ll;],
+ ac_cv_type_long_long=yes,
+ ac_cv_type_long_long=no)])
+ if test $ac_cv_type_long_long = yes; then
+ AC_DEFINE(HAVE_LONG_LONG, 1,
+ [Define if you have the 'long long' type.])
+ fi
+])
diff --git a/gl/m4/mkdtemp.m4 b/gl/m4/mkdtemp.m4
new file mode 100644
index 000000000..e02c8256c
--- /dev/null
+++ b/gl/m4/mkdtemp.m4
@@ -0,0 +1,23 @@
+# mkdtemp.m4 serial 3
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gt_FUNC_MKDTEMP],
+[
+ AC_REPLACE_FUNCS(mkdtemp)
+ if test $ac_cv_func_mkdtemp = no; then
+ gl_PREREQ_MKDTEMP
+ fi
+])
+
+# Prerequisites of lib/mkdtemp.c
+AC_DEFUN([gl_PREREQ_MKDTEMP],
+[
+ AC_REQUIRE([AC_HEADER_STAT])
+ AC_CHECK_HEADERS_ONCE(sys/time.h unistd.h)
+ AC_CHECK_HEADERS(time.h)
+ AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])
+ AC_CHECK_FUNCS(gettimeofday)
+])
diff --git a/gl/m4/onceonly_2_57.m4 b/gl/m4/onceonly_2_57.m4
new file mode 100644
index 000000000..9fc510e06
--- /dev/null
+++ b/gl/m4/onceonly_2_57.m4
@@ -0,0 +1,86 @@
+# onceonly_2_57.m4 serial 3
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl This file defines some "once only" variants of standard autoconf macros.
+dnl AC_CHECK_HEADERS_ONCE like AC_CHECK_HEADERS
+dnl AC_CHECK_FUNCS_ONCE like AC_CHECK_FUNCS
+dnl AC_CHECK_DECLS_ONCE like AC_CHECK_DECLS
+dnl AC_REQUIRE([AC_HEADER_STDC]) like AC_HEADER_STDC
+dnl The advantage is that the check for each of the headers/functions/decls
+dnl will be put only once into the 'configure' file. It keeps the size of
+dnl the 'configure' file down, and avoids redundant output when 'configure'
+dnl is run.
+dnl The drawback is that the checks cannot be conditionalized. If you write
+dnl if some_condition; then gl_CHECK_HEADERS(stdlib.h); fi
+dnl inside an AC_DEFUNed function, the gl_CHECK_HEADERS macro call expands to
+dnl empty, and the check will be inserted before the body of the AC_DEFUNed
+dnl function.
+
+dnl This is like onceonly.m4, except that it uses diversions to named sections
+dnl DEFAULTS and INIT_PREPARE in order to check all requested headers at once,
+dnl thus reducing the size of 'configure'. Works with autoconf-2.57. The
+dnl size reduction is ca. 9%.
+
+dnl Autoconf version 2.57 or newer is recommended.
+AC_PREREQ(2.54)
+
+# AC_CHECK_HEADERS_ONCE(HEADER1 HEADER2 ...) is a once-only variant of
+# AC_CHECK_HEADERS(HEADER1 HEADER2 ...).
+AC_DEFUN([AC_CHECK_HEADERS_ONCE], [
+ :
+ AC_FOREACH([gl_HEADER_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME,
+ [./-], [___])), [
+ m4_divert_text([INIT_PREPARE],
+ [gl_header_list="$gl_header_list gl_HEADER_NAME"])
+ gl_HEADERS_EXPANSION
+ AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_HEADER_NAME])),
+ [Define to 1 if you have the <]m4_defn([gl_HEADER_NAME])[> header file.])
+ ])
+ AC_REQUIRE([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME,
+ [./-], [___])))
+ ])
+])
+m4_define([gl_HEADERS_EXPANSION], [
+ m4_divert_text([DEFAULTS], [gl_header_list=])
+ AC_CHECK_HEADERS([$gl_header_list])
+ m4_define([gl_HEADERS_EXPANSION], [])
+])
+
+# AC_CHECK_FUNCS_ONCE(FUNC1 FUNC2 ...) is a once-only variant of
+# AC_CHECK_FUNCS(FUNC1 FUNC2 ...).
+AC_DEFUN([AC_CHECK_FUNCS_ONCE], [
+ :
+ AC_FOREACH([gl_FUNC_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME]), [
+ m4_divert_text([INIT_PREPARE],
+ [gl_func_list="$gl_func_list gl_FUNC_NAME"])
+ gl_FUNCS_EXPANSION
+ AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_FUNC_NAME])),
+ [Define to 1 if you have the `]m4_defn([gl_FUNC_NAME])[' function.])
+ ])
+ AC_REQUIRE([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME]))
+ ])
+])
+m4_define([gl_FUNCS_EXPANSION], [
+ m4_divert_text([DEFAULTS], [gl_func_list=])
+ AC_CHECK_FUNCS([$gl_func_list])
+ m4_define([gl_FUNCS_EXPANSION], [])
+])
+
+# AC_CHECK_DECLS_ONCE(DECL1 DECL2 ...) is a once-only variant of
+# AC_CHECK_DECLS(DECL1, DECL2, ...).
+AC_DEFUN([AC_CHECK_DECLS_ONCE], [
+ :
+ AC_FOREACH([gl_DECL_NAME], [$1], [
+ AC_DEFUN([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME]), [
+ AC_CHECK_DECLS(m4_defn([gl_DECL_NAME]))
+ ])
+ AC_REQUIRE([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME]))
+ ])
+])
diff --git a/gl/m4/setenv.m4 b/gl/m4/setenv.m4
new file mode 100644
index 000000000..4c76be1ff
--- /dev/null
+++ b/gl/m4/setenv.m4
@@ -0,0 +1,70 @@
+# setenv.m4 serial 5
+dnl Copyright (C) 2001-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gt_FUNC_SETENV],
+[
+ AC_REPLACE_FUNCS(setenv unsetenv)
+ if test $ac_cv_func_setenv = no; then
+ gl_PREREQ_SETENV
+ fi
+ if test $ac_cv_func_unsetenv = no; then
+ gl_PREREQ_UNSETENV
+ else
+ AC_CACHE_CHECK([for unsetenv() return type], gt_cv_func_unsetenv_ret,
+ [AC_TRY_COMPILE([#include <stdlib.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+int unsetenv (const char *name);
+#else
+int unsetenv();
+#endif
+], , gt_cv_func_unsetenv_ret='int', gt_cv_func_unsetenv_ret='void')])
+ if test $gt_cv_func_unsetenv_ret = 'void'; then
+ AC_DEFINE(VOID_UNSETENV, 1, [Define if unsetenv() returns void, not int.])
+ fi
+ fi
+])
+
+# Check if a variable is properly declared.
+# gt_CHECK_VAR_DECL(includes,variable)
+AC_DEFUN([gt_CHECK_VAR_DECL],
+[
+ define([gt_cv_var], [gt_cv_var_]$2[_declaration])
+ AC_MSG_CHECKING([if $2 is properly declared])
+ AC_CACHE_VAL(gt_cv_var, [
+ AC_TRY_COMPILE([$1
+ extern struct { int foo; } $2;],
+ [$2.foo = 1;],
+ gt_cv_var=no,
+ gt_cv_var=yes)])
+ AC_MSG_RESULT($gt_cv_var)
+ if test $gt_cv_var = yes; then
+ AC_DEFINE([HAVE_]translit($2, [a-z], [A-Z])[_DECL], 1,
+ [Define if you have the declaration of $2.])
+ fi
+])
+
+# Prerequisites of lib/setenv.c.
+AC_DEFUN([gl_PREREQ_SETENV],
+[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ AC_CHECK_HEADERS(search.h)
+ AC_CHECK_FUNCS(tsearch)
+ gt_CHECK_VAR_DECL([#include <errno.h>], errno)
+ gt_CHECK_VAR_DECL([#include <unistd.h>], environ)
+])
+
+# Prerequisites of lib/unsetenv.c.
+AC_DEFUN([gl_PREREQ_UNSETENV],
+[
+ AC_CHECK_HEADERS_ONCE(unistd.h)
+ gt_CHECK_VAR_DECL([#include <errno.h>], errno)
+ gt_CHECK_VAR_DECL([#include <unistd.h>], environ)
+])
diff --git a/gl/m4/signed.m4 b/gl/m4/signed.m4
new file mode 100644
index 000000000..048f59369
--- /dev/null
+++ b/gl/m4/signed.m4
@@ -0,0 +1,17 @@
+# signed.m4 serial 1 (gettext-0.10.40)
+dnl Copyright (C) 2001-2002 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([bh_C_SIGNED],
+[
+ AC_CACHE_CHECK([for signed], bh_cv_c_signed,
+ [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)])
+ if test $bh_cv_c_signed = no; then
+ AC_DEFINE(signed, ,
+ [Define to empty if the C compiler doesn't support this keyword.])
+ fi
+])
diff --git a/gl/m4/size_max.m4 b/gl/m4/size_max.m4
new file mode 100644
index 000000000..4fe81c7b0
--- /dev/null
+++ b/gl/m4/size_max.m4
@@ -0,0 +1,59 @@
+# size_max.m4 serial 2
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([gl_SIZE_MAX],
+[
+ AC_CHECK_HEADERS(stdint.h)
+ dnl First test whether the system already has SIZE_MAX.
+ AC_MSG_CHECKING([for SIZE_MAX])
+ result=
+ AC_EGREP_CPP([Found it], [
+#include <limits.h>
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef SIZE_MAX
+Found it
+#endif
+], result=yes)
+ if test -z "$result"; then
+ dnl Define it ourselves. Here we assume that the type 'size_t' is not wider
+ dnl than the type 'unsigned long'.
+ dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr',
+ dnl which is guaranteed to work from LONG_MIN to LONG_MAX.
+ _AC_COMPUTE_INT([~(size_t)0 / 10], res_hi,
+ [#include <stddef.h>], result=?)
+ _AC_COMPUTE_INT([~(size_t)0 % 10], res_lo,
+ [#include <stddef.h>], result=?)
+ _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint,
+ [#include <stddef.h>], result=?)
+ if test "$fits_in_uint" = 1; then
+ dnl Even though SIZE_MAX fits in an unsigned int, it must be of type
+ dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'.
+ AC_TRY_COMPILE([#include <stddef.h>
+ extern size_t foo;
+ extern unsigned long foo;
+ ], [], fits_in_uint=0)
+ fi
+ if test -z "$result"; then
+ if test "$fits_in_uint" = 1; then
+ result="$res_hi$res_lo"U
+ else
+ result="$res_hi$res_lo"UL
+ fi
+ else
+ dnl Shouldn't happen, but who knows...
+ result='~(size_t)0'
+ fi
+ fi
+ AC_MSG_RESULT([$result])
+ if test "$result" != yes; then
+ AC_DEFINE_UNQUOTED([SIZE_MAX], [$result],
+ [Define as the maximum value of type 'size_t', if the system doesn't define it.])
+ fi
+])
diff --git a/gl/m4/stdint_h.m4 b/gl/m4/stdint_h.m4
new file mode 100644
index 000000000..3355f35aa
--- /dev/null
+++ b/gl/m4/stdint_h.m4
@@ -0,0 +1,26 @@
+# stdint_h.m4 serial 5
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_STDINT_H_WITH_UINTMAX if <stdint.h> exists,
+# doesn't clash with <sys/types.h>, and declares uintmax_t.
+
+AC_DEFUN([gl_AC_HEADER_STDINT_H],
+[
+ AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h,
+ [AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <stdint.h>],
+ [uintmax_t i = (uintmax_t) -1;],
+ gl_cv_header_stdint_h=yes,
+ gl_cv_header_stdint_h=no)])
+ if test $gl_cv_header_stdint_h = yes; then
+ AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1,
+ [Define if <stdint.h> exists, doesn't clash with <sys/types.h>,
+ and declares uintmax_t. ])
+ fi
+])
diff --git a/gl/m4/strpbrk.m4 b/gl/m4/strpbrk.m4
new file mode 100644
index 000000000..68360684e
--- /dev/null
+++ b/gl/m4/strpbrk.m4
@@ -0,0 +1,16 @@
+# strpbrk.m4 serial 2
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRPBRK],
+[
+ AC_REPLACE_FUNCS(strpbrk)
+ if test $ac_cv_func_strpbrk = no; then
+ gl_PREREQ_STRPBRK
+ fi
+])
+
+# Prerequisites of lib/strpbrk.c.
+AC_DEFUN([gl_PREREQ_STRPBRK], [:])
diff --git a/gl/m4/strsep.m4 b/gl/m4/strsep.m4
new file mode 100644
index 000000000..40a087b3d
--- /dev/null
+++ b/gl/m4/strsep.m4
@@ -0,0 +1,17 @@
+# strsep.m4 serial 3
+dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRSEP],
+[
+ dnl Persuade glibc <string.h> to declare strsep().
+ AC_REQUIRE([AC_GNU_SOURCE])
+
+ AC_REPLACE_FUNCS(strsep)
+ gl_PREREQ_STRSEP
+])
+
+# Prerequisites of lib/strsep.c.
+AC_DEFUN([gl_PREREQ_STRSEP], [:])
diff --git a/gl/m4/uintmax_t.m4 b/gl/m4/uintmax_t.m4
new file mode 100644
index 000000000..bf83ed746
--- /dev/null
+++ b/gl/m4/uintmax_t.m4
@@ -0,0 +1,30 @@
+# uintmax_t.m4 serial 9
+dnl Copyright (C) 1997-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+AC_PREREQ(2.13)
+
+# Define uintmax_t to 'unsigned long' or 'unsigned long long'
+# if it is not already defined in <stdint.h> or <inttypes.h>.
+
+AC_DEFUN([gl_AC_TYPE_UINTMAX_T],
+[
+ AC_REQUIRE([gl_AC_HEADER_INTTYPES_H])
+ AC_REQUIRE([gl_AC_HEADER_STDINT_H])
+ if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then
+ AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG])
+ test $ac_cv_type_unsigned_long_long = yes \
+ && ac_type='unsigned long long' \
+ || ac_type='unsigned long'
+ AC_DEFINE_UNQUOTED(uintmax_t, $ac_type,
+ [Define to unsigned long or unsigned long long
+ if <stdint.h> and <inttypes.h> don't define.])
+ else
+ AC_DEFINE(HAVE_UINTMAX_T, 1,
+ [Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>.])
+ fi
+])
diff --git a/gl/m4/ulonglong.m4 b/gl/m4/ulonglong.m4
new file mode 100644
index 000000000..dee10ccc3
--- /dev/null
+++ b/gl/m4/ulonglong.m4
@@ -0,0 +1,23 @@
+# ulonglong.m4 serial 4
+dnl Copyright (C) 1999-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works.
+
+AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG],
+[
+ AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long,
+ [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;],
+ [unsigned long long ullmax = (unsigned long long) -1;
+ return ull << i | ull >> i | ullmax / ull | ullmax % ull;],
+ ac_cv_type_unsigned_long_long=yes,
+ ac_cv_type_unsigned_long_long=no)])
+ if test $ac_cv_type_unsigned_long_long = yes; then
+ AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1,
+ [Define if you have the 'unsigned long long' type.])
+ fi
+])
diff --git a/gl/m4/vasnprintf.m4 b/gl/m4/vasnprintf.m4
new file mode 100644
index 000000000..7ff343035
--- /dev/null
+++ b/gl/m4/vasnprintf.m4
@@ -0,0 +1,58 @@
+# vasnprintf.m4 serial 5
+dnl Copyright (C) 2002-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_VASNPRINTF],
+[
+ AC_REQUIRE([gl_EOVERFLOW])
+ AC_REPLACE_FUNCS(vasnprintf)
+ if test $ac_cv_func_vasnprintf = no; then
+ AC_LIBOBJ(printf-args)
+ AC_LIBOBJ(printf-parse)
+ AC_LIBOBJ(asnprintf)
+ gl_PREREQ_PRINTF_ARGS
+ gl_PREREQ_PRINTF_PARSE
+ gl_PREREQ_VASNPRINTF
+ gl_PREREQ_ASNPRINTF
+ fi
+])
+
+# Prequisites of lib/printf-args.h, lib/printf-args.c.
+AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
+[
+ AC_REQUIRE([bh_C_SIGNED])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+])
+
+# Prequisites of lib/printf-parse.h, lib/printf-parse.c.
+AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
+[
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+ AC_REQUIRE([AC_TYPE_SIZE_T])
+ AC_CHECK_TYPES(ptrdiff_t)
+ AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
+])
+
+# Prerequisites of lib/vasnprintf.c.
+AC_DEFUN([gl_PREREQ_VASNPRINTF],
+[
+ AC_REQUIRE([AC_FUNC_ALLOCA])
+ AC_REQUIRE([gl_AC_TYPE_LONG_LONG])
+ AC_REQUIRE([gt_TYPE_LONGDOUBLE])
+ AC_REQUIRE([gt_TYPE_WCHAR_T])
+ AC_REQUIRE([gt_TYPE_WINT_T])
+ AC_CHECK_FUNCS(snprintf wcslen)
+])
+
+# Prerequisites of lib/asnprintf.c.
+AC_DEFUN([gl_PREREQ_ASNPRINTF],
+[
+])
diff --git a/gl/m4/vasprintf.m4 b/gl/m4/vasprintf.m4
new file mode 100644
index 000000000..385e92edd
--- /dev/null
+++ b/gl/m4/vasprintf.m4
@@ -0,0 +1,25 @@
+# vasprintf.m4 serial 1
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_VASPRINTF],
+[
+ AC_REPLACE_FUNCS(vasprintf)
+ if test $ac_cv_func_vasprintf = no; then
+ AC_LIBOBJ(asprintf)
+ gl_PREREQ_VASPRINTF
+ gl_PREREQ_ASPRINTF
+ fi
+])
+
+# Prerequisites of lib/vasprintf.c.
+AC_DEFUN([gl_PREREQ_VASPRINTF],
+[
+])
+
+# Prerequisites of lib/asprintf.c.
+AC_DEFUN([gl_PREREQ_ASPRINTF],
+[
+])
diff --git a/gl/m4/wchar_t.m4 b/gl/m4/wchar_t.m4
new file mode 100644
index 000000000..cde2129a9
--- /dev/null
+++ b/gl/m4/wchar_t.m4
@@ -0,0 +1,20 @@
+# wchar_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <stddef.h> has the 'wchar_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WCHAR_T],
+[
+ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t,
+ [AC_TRY_COMPILE([#include <stddef.h>
+ wchar_t foo = (wchar_t)'\0';], ,
+ gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)])
+ if test $gt_cv_c_wchar_t = yes; then
+ AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.])
+ fi
+])
diff --git a/gl/m4/wint_t.m4 b/gl/m4/wint_t.m4
new file mode 100644
index 000000000..b8fff9c86
--- /dev/null
+++ b/gl/m4/wint_t.m4
@@ -0,0 +1,20 @@
+# wint_t.m4 serial 1 (gettext-0.12)
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+dnl Test whether <wchar.h> has the 'wint_t' type.
+dnl Prerequisite: AC_PROG_CC
+
+AC_DEFUN([gt_TYPE_WINT_T],
+[
+ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t,
+ [AC_TRY_COMPILE([#include <wchar.h>
+ wint_t foo = (wchar_t)'\0';], ,
+ gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)])
+ if test $gt_cv_c_wint_t = yes; then
+ AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.])
+ fi
+])
diff --git a/gl/m4/xsize.m4 b/gl/m4/xsize.m4
new file mode 100644
index 000000000..85bb721e4
--- /dev/null
+++ b/gl/m4/xsize.m4
@@ -0,0 +1,13 @@
+# xsize.m4 serial 3
+dnl Copyright (C) 2003-2004 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XSIZE],
+[
+ dnl Prerequisites of lib/xsize.h.
+ AC_REQUIRE([gl_SIZE_MAX])
+ AC_REQUIRE([AC_C_INLINE])
+ AC_CHECK_HEADERS(stdint.h)
+])
diff --git a/gl/mkdtemp.c b/gl/mkdtemp.c
new file mode 100644
index 000000000..469cf4718
--- /dev/null
+++ b/gl/mkdtemp.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 1999, 2001-2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+/* Extracted from misc/mkdtemp.c and sysdeps/posix/tempname.c. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Specification. */
+#include "mkdtemp.h"
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stdio.h>
+#ifndef TMP_MAX
+# define TMP_MAX 238328
+#endif
+
+#if HAVE_STDINT_H || _LIBC
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#if HAVE_UNISTD_H || _LIBC
+# include <unistd.h>
+#endif
+
+#if HAVE_GETTIMEOFDAY || _LIBC
+# if HAVE_SYS_TIME_H || _LIBC
+# include <sys/time.h>
+# endif
+#else
+# if HAVE_TIME_H || _LIBC
+# include <time.h>
+# endif
+#endif
+
+#include <sys/stat.h>
+#if STAT_MACROS_BROKEN
+# undef S_ISDIR
+#endif
+#if !defined S_ISDIR && defined S_IFDIR
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !S_IRUSR && S_IREAD
+# define S_IRUSR S_IREAD
+#endif
+#if !S_IRUSR
+# define S_IRUSR 00400
+#endif
+#if !S_IWUSR && S_IWRITE
+# define S_IWUSR S_IWRITE
+#endif
+#if !S_IWUSR
+# define S_IWUSR 00200
+#endif
+#if !S_IXUSR && S_IEXEC
+# define S_IXUSR S_IEXEC
+#endif
+#if !S_IXUSR
+# define S_IXUSR 00100
+#endif
+
+#ifdef __MINGW32__
+/* mingw's mkdir() function has 1 argument, but we pass 2 arguments.
+ Therefore we have to disable the argument count checking. */
+# define mkdir ((int (*)()) mkdir)
+#endif
+
+#if !_LIBC
+# define __getpid getpid
+# define __gettimeofday gettimeofday
+# define __mkdir mkdir
+#endif
+
+/* Use the widest available unsigned type if uint64_t is not
+ available. The algorithm below extracts a number less than 62**6
+ (approximately 2**35.725) from uint64_t, so ancient hosts where
+ uintmax_t is only 32 bits lose about 3.725 bits of randomness,
+ which is better than not having mkstemp at all. */
+#if !defined UINT64_MAX && !defined uint64_t
+# define uint64_t uintmax_t
+#endif
+
+/* These are the characters used in temporary filenames. */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL. TMPL must match the
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ does not exist at the time of the call to __gen_tempname. TMPL is
+ overwritten with the result.
+
+ KIND is:
+ __GT_DIR: create a directory, which will be mode 0700.
+
+ We use a clever algorithm to get hard-to-predict names. */
+static int
+gen_tempname (char *tmpl)
+{
+ int len;
+ char *XXXXXX;
+ static uint64_t value;
+ uint64_t random_time_bits;
+ int count, fd = -1;
+ int save_errno = errno;
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get some more or less random data. */
+#ifdef RANDOM_BITS
+ RANDOM_BITS (random_time_bits);
+#else
+# if HAVE_GETTIMEOFDAY || _LIBC
+ {
+ struct timeval tv;
+ __gettimeofday (&tv, NULL);
+ random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+ }
+# else
+ random_time_bits = time (NULL);
+# endif
+#endif
+ value += random_time_bits ^ __getpid ();
+
+ for (count = 0; count < TMP_MAX; value += 7777, ++count)
+ {
+ uint64_t v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+
+ if (fd >= 0)
+ {
+ __set_errno (save_errno);
+ return fd;
+ }
+ else if (errno != EEXIST)
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ __set_errno (EEXIST);
+ return -1;
+}
+
+/* Generate a unique temporary directory from TEMPLATE.
+ The last six characters of TEMPLATE must be "XXXXXX";
+ they are replaced with a string that makes the filename unique.
+ The directory is created, mode 700, and its name is returned.
+ (This function comes from OpenBSD.) */
+char *
+mkdtemp (char *template)
+{
+ if (gen_tempname (template))
+ return NULL;
+ else
+ return template;
+}
diff --git a/gl/mkdtemp.h b/gl/mkdtemp.h
new file mode 100644
index 000000000..617604801
--- /dev/null
+++ b/gl/mkdtemp.h
@@ -0,0 +1,32 @@
+/* Creating a private temporary directory.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#if HAVE_MKDTEMP
+
+/* Get mkdtemp() declaration. */
+#include <stdlib.h>
+
+#else
+
+/* Create a unique temporary directory from TEMPLATE.
+ The last six characters of TEMPLATE must be "XXXXXX";
+ they are replaced with a string that makes the directory name unique.
+ Returns TEMPLATE, or a null pointer if it cannot get a unique name.
+ The directory is created mode 700. */
+extern char * mkdtemp (char *template);
+
+#endif
diff --git a/gl/printf-args.c b/gl/printf-args.c
new file mode 100644
index 000000000..0ed1acbb8
--- /dev/null
+++ b/gl/printf-args.c
@@ -0,0 +1,118 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "printf-args.h"
+
+#ifdef STATIC
+STATIC
+#endif
+int
+printf_fetchargs (va_list args, arguments *a)
+{
+ size_t i;
+ argument *ap;
+
+ for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
+ switch (ap->type)
+ {
+ case TYPE_SCHAR:
+ ap->a.a_schar = va_arg (args, /*signed char*/ int);
+ break;
+ case TYPE_UCHAR:
+ ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
+ break;
+ case TYPE_SHORT:
+ ap->a.a_short = va_arg (args, /*short*/ int);
+ break;
+ case TYPE_USHORT:
+ ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
+ break;
+ case TYPE_INT:
+ ap->a.a_int = va_arg (args, int);
+ break;
+ case TYPE_UINT:
+ ap->a.a_uint = va_arg (args, unsigned int);
+ break;
+ case TYPE_LONGINT:
+ ap->a.a_longint = va_arg (args, long int);
+ break;
+ case TYPE_ULONGINT:
+ ap->a.a_ulongint = va_arg (args, unsigned long int);
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ ap->a.a_longlongint = va_arg (args, long long int);
+ break;
+ case TYPE_ULONGLONGINT:
+ ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
+ break;
+#endif
+ case TYPE_DOUBLE:
+ ap->a.a_double = va_arg (args, double);
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ ap->a.a_longdouble = va_arg (args, long double);
+ break;
+#endif
+ case TYPE_CHAR:
+ ap->a.a_char = va_arg (args, int);
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ ap->a.a_wide_char = va_arg (args, wint_t);
+ break;
+#endif
+ case TYPE_STRING:
+ ap->a.a_string = va_arg (args, const char *);
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ ap->a.a_wide_string = va_arg (args, const wchar_t *);
+ break;
+#endif
+ case TYPE_POINTER:
+ ap->a.a_pointer = va_arg (args, void *);
+ break;
+ case TYPE_COUNT_SCHAR_POINTER:
+ ap->a.a_count_schar_pointer = va_arg (args, signed char *);
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ ap->a.a_count_short_pointer = va_arg (args, short *);
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ ap->a.a_count_int_pointer = va_arg (args, int *);
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ ap->a.a_count_longint_pointer = va_arg (args, long int *);
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
+ break;
+#endif
+ default:
+ /* Unknown type. */
+ return -1;
+ }
+ return 0;
+}
diff --git a/gl/printf-args.h b/gl/printf-args.h
new file mode 100644
index 000000000..cec1cc6c2
--- /dev/null
+++ b/gl/printf-args.h
@@ -0,0 +1,136 @@
+/* Decomposed printf argument list.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _PRINTF_ARGS_H
+#define _PRINTF_ARGS_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get wchar_t. */
+#ifdef HAVE_WCHAR_T
+# include <stddef.h>
+#endif
+
+/* Get wint_t. */
+#ifdef HAVE_WINT_T
+# include <wchar.h>
+#endif
+
+/* Get va_list. */
+#include <stdarg.h>
+
+
+/* Argument types */
+typedef enum
+{
+ TYPE_NONE,
+ TYPE_SCHAR,
+ TYPE_UCHAR,
+ TYPE_SHORT,
+ TYPE_USHORT,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_LONGINT,
+ TYPE_ULONGINT,
+#ifdef HAVE_LONG_LONG
+ TYPE_LONGLONGINT,
+ TYPE_ULONGLONGINT,
+#endif
+ TYPE_DOUBLE,
+#ifdef HAVE_LONG_DOUBLE
+ TYPE_LONGDOUBLE,
+#endif
+ TYPE_CHAR,
+#ifdef HAVE_WINT_T
+ TYPE_WIDE_CHAR,
+#endif
+ TYPE_STRING,
+#ifdef HAVE_WCHAR_T
+ TYPE_WIDE_STRING,
+#endif
+ TYPE_POINTER,
+ TYPE_COUNT_SCHAR_POINTER,
+ TYPE_COUNT_SHORT_POINTER,
+ TYPE_COUNT_INT_POINTER,
+ TYPE_COUNT_LONGINT_POINTER
+#ifdef HAVE_LONG_LONG
+, TYPE_COUNT_LONGLONGINT_POINTER
+#endif
+} arg_type;
+
+/* Polymorphic argument */
+typedef struct
+{
+ arg_type type;
+ union
+ {
+ signed char a_schar;
+ unsigned char a_uchar;
+ short a_short;
+ unsigned short a_ushort;
+ int a_int;
+ unsigned int a_uint;
+ long int a_longint;
+ unsigned long int a_ulongint;
+#ifdef HAVE_LONG_LONG
+ long long int a_longlongint;
+ unsigned long long int a_ulonglongint;
+#endif
+ float a_float;
+ double a_double;
+#ifdef HAVE_LONG_DOUBLE
+ long double a_longdouble;
+#endif
+ int a_char;
+#ifdef HAVE_WINT_T
+ wint_t a_wide_char;
+#endif
+ const char* a_string;
+#ifdef HAVE_WCHAR_T
+ const wchar_t* a_wide_string;
+#endif
+ void* a_pointer;
+ signed char * a_count_schar_pointer;
+ short * a_count_short_pointer;
+ int * a_count_int_pointer;
+ long int * a_count_longint_pointer;
+#ifdef HAVE_LONG_LONG
+ long long int * a_count_longlongint_pointer;
+#endif
+ }
+ a;
+}
+argument;
+
+typedef struct
+{
+ size_t count;
+ argument *arg;
+}
+arguments;
+
+
+/* Fetch the arguments, putting them into a. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_fetchargs (va_list args, arguments *a);
+
+#endif /* _PRINTF_ARGS_H */
diff --git a/gl/printf-parse.c b/gl/printf-parse.c
new file mode 100644
index 000000000..3d2fb175f
--- /dev/null
+++ b/gl/printf-parse.c
@@ -0,0 +1,536 @@
+/* Formatted output to strings.
+ Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Get size_t, NULL. */
+#include <stddef.h>
+
+/* Get intmax_t. */
+#if HAVE_STDINT_H_WITH_UINTMAX
+# include <stdint.h>
+#endif
+#if HAVE_INTTYPES_H_WITH_UINTMAX
+# include <inttypes.h>
+#endif
+
+/* malloc(), realloc(), free(). */
+#include <stdlib.h>
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+#if WIDE_CHAR_VERSION
+# define PRINTF_PARSE wprintf_parse
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+#else
+# define PRINTF_PARSE printf_parse
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+#endif
+
+#ifdef STATIC
+STATIC
+#endif
+int
+PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
+{
+ const CHAR_T *cp = format; /* pointer into format */
+ size_t arg_posn = 0; /* number of regular arguments consumed */
+ size_t d_allocated; /* allocated elements of d->dir */
+ size_t a_allocated; /* allocated elements of a->arg */
+ size_t max_width_length = 0;
+ size_t max_precision_length = 0;
+
+ d->count = 0;
+ d_allocated = 1;
+ d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
+ if (d->dir == NULL)
+ /* Out of memory. */
+ return -1;
+
+ a->count = 0;
+ a_allocated = 0;
+ a->arg = NULL;
+
+#define REGISTER_ARG(_index_,_type_) \
+ { \
+ size_t n = (_index_); \
+ if (n >= a_allocated) \
+ { \
+ size_t memory_size; \
+ argument *memory; \
+ \
+ a_allocated = xtimes (a_allocated, 2); \
+ if (a_allocated <= n) \
+ a_allocated = xsum (n, 1); \
+ memory_size = xtimes (a_allocated, sizeof (argument)); \
+ if (size_overflow_p (memory_size)) \
+ /* Overflow, would lead to out of memory. */ \
+ goto error; \
+ memory = (a->arg \
+ ? realloc (a->arg, memory_size) \
+ : malloc (memory_size)); \
+ if (memory == NULL) \
+ /* Out of memory. */ \
+ goto error; \
+ a->arg = memory; \
+ } \
+ while (a->count <= n) \
+ a->arg[a->count++].type = TYPE_NONE; \
+ if (a->arg[n].type == TYPE_NONE) \
+ a->arg[n].type = (_type_); \
+ else if (a->arg[n].type != (_type_)) \
+ /* Ambiguous type for positional argument. */ \
+ goto error; \
+ }
+
+ while (*cp != '\0')
+ {
+ CHAR_T c = *cp++;
+ if (c == '%')
+ {
+ size_t arg_index = ARG_NONE;
+ DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
+
+ /* Initialize the next directive. */
+ dp->dir_start = cp - 1;
+ dp->flags = 0;
+ dp->width_start = NULL;
+ dp->width_end = NULL;
+ dp->width_arg_index = ARG_NONE;
+ dp->precision_start = NULL;
+ dp->precision_end = NULL;
+ dp->precision_arg_index = ARG_NONE;
+ dp->arg_index = ARG_NONE;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+
+ /* Read the flags. */
+ for (;;)
+ {
+ if (*cp == '\'')
+ {
+ dp->flags |= FLAG_GROUP;
+ cp++;
+ }
+ else if (*cp == '-')
+ {
+ dp->flags |= FLAG_LEFT;
+ cp++;
+ }
+ else if (*cp == '+')
+ {
+ dp->flags |= FLAG_SHOWSIGN;
+ cp++;
+ }
+ else if (*cp == ' ')
+ {
+ dp->flags |= FLAG_SPACE;
+ cp++;
+ }
+ else if (*cp == '#')
+ {
+ dp->flags |= FLAG_ALT;
+ cp++;
+ }
+ else if (*cp == '0')
+ {
+ dp->flags |= FLAG_ZERO;
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Parse the field width. */
+ if (*cp == '*')
+ {
+ dp->width_start = cp;
+ cp++;
+ dp->width_end = cp;
+ if (max_width_length < 1)
+ max_width_length = 1;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory later. */
+ goto error;
+ dp->width_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->width_arg_index == ARG_NONE)
+ {
+ dp->width_arg_index = arg_posn++;
+ if (dp->width_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->width_arg_index, TYPE_INT);
+ }
+ else if (*cp >= '0' && *cp <= '9')
+ {
+ size_t width_length;
+
+ dp->width_start = cp;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->width_end = cp;
+ width_length = dp->width_end - dp->width_start;
+ if (max_width_length < width_length)
+ max_width_length = width_length;
+ }
+
+ /* Parse the precision. */
+ if (*cp == '.')
+ {
+ cp++;
+ if (*cp == '*')
+ {
+ dp->precision_start = cp - 1;
+ cp++;
+ dp->precision_end = cp;
+ if (max_precision_length < 2)
+ max_precision_length = 2;
+
+ /* Test for positional argument. */
+ if (*cp >= '0' && *cp <= '9')
+ {
+ const CHAR_T *np;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ ;
+ if (*np == '$')
+ {
+ size_t n = 0;
+
+ for (np = cp; *np >= '0' && *np <= '9'; np++)
+ n = xsum (xtimes (n, 10), *np - '0');
+ if (n == 0)
+ /* Positional argument 0. */
+ goto error;
+ if (size_overflow_p (n))
+ /* n too large, would lead to out of memory
+ later. */
+ goto error;
+ dp->precision_arg_index = n - 1;
+ cp = np + 1;
+ }
+ }
+ if (dp->precision_arg_index == ARG_NONE)
+ {
+ dp->precision_arg_index = arg_posn++;
+ if (dp->precision_arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
+ }
+ else
+ {
+ size_t precision_length;
+
+ dp->precision_start = cp - 1;
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ dp->precision_end = cp;
+ precision_length = dp->precision_end - dp->precision_start;
+ if (max_precision_length < precision_length)
+ max_precision_length = precision_length;
+ }
+ }
+
+ {
+ arg_type type;
+
+ /* Parse argument type/size specifiers. */
+ {
+ int flags = 0;
+
+ for (;;)
+ {
+ if (*cp == 'h')
+ {
+ flags |= (1 << (flags & 1));
+ cp++;
+ }
+ else if (*cp == 'L')
+ {
+ flags |= 4;
+ cp++;
+ }
+ else if (*cp == 'l')
+ {
+ flags += 8;
+ cp++;
+ }
+#ifdef HAVE_INTMAX_T
+ else if (*cp == 'j')
+ {
+ if (sizeof (intmax_t) > sizeof (long))
+ {
+ /* intmax_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (intmax_t) > sizeof (int))
+ {
+ /* intmax_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+#endif
+ else if (*cp == 'z' || *cp == 'Z')
+ {
+ /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
+ because the warning facility in gcc-2.95.2 understands
+ only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
+ if (sizeof (size_t) > sizeof (long))
+ {
+ /* size_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (size_t) > sizeof (int))
+ {
+ /* size_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else if (*cp == 't')
+ {
+ if (sizeof (ptrdiff_t) > sizeof (long))
+ {
+ /* ptrdiff_t = long long */
+ flags += 16;
+ }
+ else if (sizeof (ptrdiff_t) > sizeof (int))
+ {
+ /* ptrdiff_t = long */
+ flags += 8;
+ }
+ cp++;
+ }
+ else
+ break;
+ }
+
+ /* Read the conversion character. */
+ c = *cp++;
+ switch (c)
+ {
+ case 'd': case 'i':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGLONGINT;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_LONGINT;
+ else if (flags & 2)
+ type = TYPE_SCHAR;
+ else if (flags & 1)
+ type = TYPE_SHORT;
+ else
+ type = TYPE_INT;
+ break;
+ case 'o': case 'u': case 'x': case 'X':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_ULONGLONGINT;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_ULONGINT;
+ else if (flags & 2)
+ type = TYPE_UCHAR;
+ else if (flags & 1)
+ type = TYPE_USHORT;
+ else
+ type = TYPE_UINT;
+ break;
+ case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+#ifdef HAVE_LONG_DOUBLE
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_LONGDOUBLE;
+ else
+#endif
+ type = TYPE_DOUBLE;
+ break;
+ case 'c':
+ if (flags >= 8)
+#ifdef HAVE_WINT_T
+ type = TYPE_WIDE_CHAR;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_CHAR;
+ break;
+#ifdef HAVE_WINT_T
+ case 'C':
+ type = TYPE_WIDE_CHAR;
+ c = 'c';
+ break;
+#endif
+ case 's':
+ if (flags >= 8)
+#ifdef HAVE_WCHAR_T
+ type = TYPE_WIDE_STRING;
+#else
+ goto error;
+#endif
+ else
+ type = TYPE_STRING;
+ break;
+#ifdef HAVE_WCHAR_T
+ case 'S':
+ type = TYPE_WIDE_STRING;
+ c = 's';
+ break;
+#endif
+ case 'p':
+ type = TYPE_POINTER;
+ break;
+ case 'n':
+#ifdef HAVE_LONG_LONG
+ if (flags >= 16 || (flags & 4))
+ type = TYPE_COUNT_LONGLONGINT_POINTER;
+ else
+#endif
+ if (flags >= 8)
+ type = TYPE_COUNT_LONGINT_POINTER;
+ else if (flags & 2)
+ type = TYPE_COUNT_SCHAR_POINTER;
+ else if (flags & 1)
+ type = TYPE_COUNT_SHORT_POINTER;
+ else
+ type = TYPE_COUNT_INT_POINTER;
+ break;
+ case '%':
+ type = TYPE_NONE;
+ break;
+ default:
+ /* Unknown conversion character. */
+ goto error;
+ }
+ }
+
+ if (type != TYPE_NONE)
+ {
+ dp->arg_index = arg_index;
+ if (dp->arg_index == ARG_NONE)
+ {
+ dp->arg_index = arg_posn++;
+ if (dp->arg_index == ARG_NONE)
+ /* arg_posn wrapped around. */
+ goto error;
+ }
+ REGISTER_ARG (dp->arg_index, type);
+ }
+ dp->conversion = c;
+ dp->dir_end = cp;
+ }
+
+ d->count++;
+ if (d->count >= d_allocated)
+ {
+ size_t memory_size;
+ DIRECTIVE *memory;
+
+ d_allocated = xtimes (d_allocated, 2);
+ memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
+ if (size_overflow_p (memory_size))
+ /* Overflow, would lead to out of memory. */
+ goto error;
+ memory = realloc (d->dir, memory_size);
+ if (memory == NULL)
+ /* Out of memory. */
+ goto error;
+ d->dir = memory;
+ }
+ }
+ }
+ d->dir[d->count].dir_start = cp;
+
+ d->max_width_length = max_width_length;
+ d->max_precision_length = max_precision_length;
+ return 0;
+
+error:
+ if (a->arg)
+ free (a->arg);
+ if (d->dir)
+ free (d->dir);
+ return -1;
+}
+
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef PRINTF_PARSE
diff --git a/gl/printf-parse.h b/gl/printf-parse.h
new file mode 100644
index 000000000..82a0d37cd
--- /dev/null
+++ b/gl/printf-parse.h
@@ -0,0 +1,74 @@
+/* Parse printf format string.
+ Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _PRINTF_PARSE_H
+#define _PRINTF_PARSE_H
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP 1 /* ' flag */
+#define FLAG_LEFT 2 /* - flag */
+#define FLAG_SHOWSIGN 4 /* + flag */
+#define FLAG_SPACE 8 /* space flag */
+#define FLAG_ALT 16 /* # flag */
+#define FLAG_ZERO 32
+
+/* arg_index value indicating that no argument is consumed. */
+#define ARG_NONE (~(size_t)0)
+
+/* A parsed directive. */
+typedef struct
+{
+ const char* dir_start;
+ const char* dir_end;
+ int flags;
+ const char* width_start;
+ const char* width_end;
+ size_t width_arg_index;
+ const char* precision_start;
+ const char* precision_end;
+ size_t precision_arg_index;
+ char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
+ size_t arg_index;
+}
+char_directive;
+
+/* A parsed format string. */
+typedef struct
+{
+ size_t count;
+ char_directive *dir;
+ size_t max_width_length;
+ size_t max_precision_length;
+}
+char_directives;
+
+
+/* Parses the format string. Fills in the number N of directives, and fills
+ in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+ to the end of the format string. Also fills in the arg_type fields of the
+ arguments and the needed count of arguments. */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int printf_parse (const char *format, char_directives *d, arguments *a);
+
+#endif /* _PRINTF_PARSE_H */
diff --git a/gl/setenv.c b/gl/setenv.c
new file mode 100644
index 000000000..33dbeb7a3
--- /dev/null
+++ b/gl/setenv.c
@@ -0,0 +1,328 @@
+/* Copyright (C) 1992,1995-1999,2000-2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <alloca.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#if _LIBC || HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !_LIBC
+# include "allocsa.h"
+#endif
+
+#if !_LIBC
+# define __environ environ
+# ifndef HAVE_ENVIRON_DECL
+extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define setenv __setenv
+# define clearenv __clearenv
+# define tfind __tfind
+# define tsearch __tsearch
+#endif
+
+/* In the GNU C library implementation we try to be more clever and
+ allow arbitrarily many changes of the environment given that the used
+ values are from a small set. Outside glibc this will eat up all
+ memory after a while. */
+#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
+ && defined __GNUC__)
+# define USE_TSEARCH 1
+# include <search.h>
+typedef int (*compar_fn_t) (const void *, const void *);
+
+/* This is a pointer to the root of the search tree with the known
+ values. */
+static void *known_values;
+
+# define KNOWN_VALUE(Str) \
+ ({ \
+ void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
+ value != NULL ? *(char **) value : NULL; \
+ })
+# define STORE_VALUE(Str) \
+ tsearch (Str, &known_values, (compar_fn_t) strcmp)
+
+#else
+# undef USE_TSEARCH
+
+# define KNOWN_VALUE(Str) NULL
+# define STORE_VALUE(Str) do { } while (0)
+
+#endif
+
+
+/* If this variable is not a null pointer we allocated the current
+ environment. */
+static char **last_environ;
+
+
+/* This function is used by `setenv' and `putenv'. The difference between
+ the two functions is that for the former must create a new string which
+ is then placed in the environment, while the argument of `putenv'
+ must be used directly. This is all complicated by the fact that we try
+ to reuse values once generated for a `setenv' call since we can never
+ free the strings. */
+int
+__add_to_environ (const char *name, const char *value, const char *combined,
+ int replace)
+{
+ register char **ep;
+ register size_t size;
+ const size_t namelen = strlen (name);
+ const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
+
+ LOCK;
+
+ /* We have to get the pointer now that we have the lock and not earlier
+ since another thread might have created a new environment. */
+ ep = __environ;
+
+ size = 0;
+ if (ep != NULL)
+ {
+ for (; *ep != NULL; ++ep)
+ if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
+ break;
+ else
+ ++size;
+ }
+
+ if (ep == NULL || *ep == NULL)
+ {
+ char **new_environ;
+#ifdef USE_TSEARCH
+ char *new_value;
+#endif
+
+ /* We allocated this space; we can extend it. */
+ new_environ =
+ (char **) (last_environ == NULL
+ ? malloc ((size + 2) * sizeof (char *))
+ : realloc (last_environ, (size + 2) * sizeof (char *)));
+ if (new_environ == NULL)
+ {
+ UNLOCK;
+ return -1;
+ }
+
+ /* If the whole entry is given add it. */
+ if (combined != NULL)
+ /* We must not add the string to the search tree since it belongs
+ to the user. */
+ new_environ[size] = (char *) combined;
+ else
+ {
+ /* See whether the value is already known. */
+#ifdef USE_TSEARCH
+# ifdef _LIBC
+ new_value = (char *) alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = (char *) allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ new_environ[size] = KNOWN_VALUE (new_value);
+ if (new_environ[size] == NULL)
+#endif
+ {
+ new_environ[size] = (char *) malloc (namelen + 1 + vallen);
+ if (new_environ[size] == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (new_environ[size], new_value, namelen + 1 + vallen);
+#else
+ memcpy (new_environ[size], name, namelen);
+ new_environ[size][namelen] = '=';
+ memcpy (&new_environ[size][namelen + 1], value, vallen);
+#endif
+ /* And save the value now. We cannot do this when we remove
+ the string since then we cannot decide whether it is a
+ user string or not. */
+ STORE_VALUE (new_environ[size]);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ }
+
+ if (__environ != last_environ)
+ memcpy ((char *) new_environ, (char *) __environ,
+ size * sizeof (char *));
+
+ new_environ[size + 1] = NULL;
+
+ last_environ = __environ = new_environ;
+ }
+ else if (replace)
+ {
+ char *np;
+
+ /* Use the user string if given. */
+ if (combined != NULL)
+ np = (char *) combined;
+ else
+ {
+#ifdef USE_TSEARCH
+ char *new_value;
+# ifdef _LIBC
+ new_value = alloca (namelen + 1 + vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
+# else
+ new_value = allocsa (namelen + 1 + vallen);
+ if (new_value == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
+# endif
+
+ np = KNOWN_VALUE (new_value);
+ if (np == NULL)
+#endif
+ {
+ np = malloc (namelen + 1 + vallen);
+ if (np == NULL)
+ {
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
+
+#ifdef USE_TSEARCH
+ memcpy (np, new_value, namelen + 1 + vallen);
+#else
+ memcpy (np, name, namelen);
+ np[namelen] = '=';
+ memcpy (&np[namelen + 1], value, vallen);
+#endif
+ /* And remember the value. */
+ STORE_VALUE (np);
+ }
+#if defined USE_TSEARCH && !defined _LIBC
+ freesa (new_value);
+#endif
+ }
+
+ *ep = np;
+ }
+
+ UNLOCK;
+
+ return 0;
+}
+
+int
+setenv (const char *name, const char *value, int replace)
+{
+ return __add_to_environ (name, value, NULL, replace);
+}
+
+/* The `clearenv' was planned to be added to POSIX.1 but probably
+ never made it. Nevertheless the POSIX.9 standard (POSIX bindings
+ for Fortran 77) requires this function. */
+int
+clearenv (void)
+{
+ LOCK;
+
+ if (__environ == last_environ && __environ != NULL)
+ {
+ /* We allocated this environment so we can free it. */
+ free (__environ);
+ last_environ = NULL;
+ }
+
+ /* Clear the environment pointer removes the whole environment. */
+ __environ = NULL;
+
+ UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+static void
+free_mem (void)
+{
+ /* Remove all traces. */
+ clearenv ();
+
+ /* Now remove the search tree. */
+ __tdestroy (known_values, free);
+ known_values = NULL;
+}
+text_set_element (__libc_subfreeres, free_mem);
+
+
+# undef setenv
+# undef clearenv
+weak_alias (__setenv, setenv)
+weak_alias (__clearenv, clearenv)
+#endif
diff --git a/gl/setenv.h b/gl/setenv.h
new file mode 100644
index 000000000..c89e7da4d
--- /dev/null
+++ b/gl/setenv.h
@@ -0,0 +1,54 @@
+/* Setting environment variables.
+ Copyright (C) 2001-2004 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#if HAVE_SETENV || HAVE_UNSETENV
+
+/* Get setenv(), unsetenv() declarations. */
+# include <stdlib.h>
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !HAVE_SETENV
+
+/* Set NAME to VALUE in the environment.
+ If REPLACE is nonzero, overwrite an existing value. */
+extern int setenv (const char *name, const char *value, int replace);
+
+#endif
+
+#if HAVE_UNSETENV
+
+# if VOID_UNSETENV
+/* On some systems, unsetenv() returns void.
+ This is the case for FreeBSD 4.8, NetBSD 1.6, OpenBSD 3.4. */
+# define unsetenv(name) ((unsetenv)(name), 0)
+# endif
+
+#else
+
+/* Remove the variable NAME from the environment. */
+extern int unsetenv (const char *name);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gl/strpbrk.c b/gl/strpbrk.c
new file mode 100644
index 000000000..9152440b1
--- /dev/null
+++ b/gl/strpbrk.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1994, 2000, 2002-2003 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to [email protected].
+
+ This program 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, or (at your option) any
+ later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+
+#undef strpbrk
+
+/* Find the first occurrence in S of any character in ACCEPT. */
+char *
+strpbrk (const char *s, const char *accept)
+{
+ while (*s != '\0')
+ {
+ const char *a = accept;
+ while (*a != '\0')
+ if (*a++ == *s)
+ return (char *) s;
+ ++s;
+ }
+
+ return NULL;
+}
diff --git a/gl/strpbrk.h b/gl/strpbrk.h
new file mode 100644
index 000000000..acc8d358b
--- /dev/null
+++ b/gl/strpbrk.h
@@ -0,0 +1,28 @@
+/* Searching in a string.
+ Copyright (C) 2001-2002 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#if HAVE_STRPBRK
+
+/* Get strpbrk() declaration. */
+#include <string.h>
+
+#else
+
+/* Find the first occurrence in S of any character in ACCEPT. */
+extern char *strpbrk (const char *s, const char *accept);
+
+#endif
diff --git a/gl/strsep.c b/gl/strsep.c
new file mode 100644
index 000000000..40c2939c8
--- /dev/null
+++ b/gl/strsep.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+
+ Written by Yoann Vandoorselaere <[email protected]>.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Specification. */
+#include "strsep.h"
+
+#include <string.h>
+
+#include "strpbrk.h"
+
+char *
+strsep (char **stringp, const char *delim)
+{
+ char *start = *stringp;
+ char *ptr;
+
+ if (!start)
+ return NULL;
+
+ if (!*delim)
+ ptr = start + strlen (start);
+ else
+ {
+ ptr = strpbrk (start, delim);
+ if (!ptr)
+ {
+ *stringp = NULL;
+ return start;
+ }
+ }
+
+ *ptr = '\0';
+ *stringp = ptr + 1;
+
+ return start;
+}
diff --git a/gl/strsep.h b/gl/strsep.h
new file mode 100644
index 000000000..ca28a2ffe
--- /dev/null
+++ b/gl/strsep.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+
+ Written by Yoann Vandoorselaere <[email protected]>.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef GNULIB_STRSEP_H_
+#define GNULIB_STRSEP_H_
+
+#if HAVE_STRSEP
+
+/*
+ * Get strsep() declaration.
+ */
+#include <string.h>
+
+#else
+
+/* Searches the next delimiter (char listed in DELIM) starting at *STRINGP.
+ If one is found, it is overwritten with a NUL, and *STRINGP is advanced
+ to point to the next char after it. Otherwise, *STRINGP is set to NULL.
+ If *STRINGP was already NULL, nothing happens.
+ Returns the old value of *STRINGP.
+
+ This is a variant of strtok() that is multithread-safe and supports
+ empty fields.
+
+ Caveat: It modifies the original string.
+ Caveat: These functions cannot be used on constant strings.
+ Caveat: The identity of the delimiting character is lost.
+ Caveat: It doesn't work with multibyte strings unless all of the delimiter
+ characters are ASCII characters < 0x30.
+
+ See also strtok_r(). */
+
+extern char *strsep (char **stringp, const char *delim);
+
+#endif
+
+#endif /* GNULIB_STRSEP_H_ */
diff --git a/gl/unsetenv.c b/gl/unsetenv.c
new file mode 100644
index 000000000..4b53fc9c8
--- /dev/null
+++ b/gl/unsetenv.c
@@ -0,0 +1,99 @@
+/* Copyright (C) 1992,1995-1999,2000-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#if !_LIBC
+# if !defined errno && !defined HAVE_ERRNO_DECL
+extern int errno;
+# endif
+# define __set_errno(ev) ((errno) = (ev))
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#if _LIBC || HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if !_LIBC
+# define __environ environ
+# ifndef HAVE_ENVIRON_DECL
+extern char **environ;
+# endif
+#endif
+
+#if _LIBC
+/* This lock protects against simultaneous modifications of `environ'. */
+# include <bits/libc-lock.h>
+__libc_lock_define_initialized (static, envlock)
+# define LOCK __libc_lock_lock (envlock)
+# define UNLOCK __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+/* In the GNU C library we must keep the namespace clean. */
+#ifdef _LIBC
+# define unsetenv __unsetenv
+#endif
+
+
+int
+unsetenv (const char *name)
+{
+ size_t len;
+ char **ep;
+
+ if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ len = strlen (name);
+
+ LOCK;
+
+ ep = __environ;
+ while (*ep != NULL)
+ if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones back. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+
+ UNLOCK;
+
+ return 0;
+}
+
+#ifdef _LIBC
+# undef unsetenv
+weak_alias (__unsetenv, unsetenv)
+#endif
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
new file mode 100644
index 000000000..324d62ecd
--- /dev/null
+++ b/gl/vasnprintf.c
@@ -0,0 +1,901 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 1999, 2002-2005 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
+ This must come before <config.h> because <config.h> may include
+ <features.h>, and once <features.h> has been included, it's too late. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#ifndef IN_LIBINTL
+# include <alloca.h>
+#endif
+
+/* Specification. */
+#if WIDE_CHAR_VERSION
+# include "vasnwprintf.h"
+#else
+# include "vasnprintf.h"
+#endif
+
+#include <stdio.h> /* snprintf(), sprintf() */
+#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
+#include <string.h> /* memcpy(), strlen() */
+#include <errno.h> /* errno */
+#include <limits.h> /* CHAR_BIT, INT_MAX */
+#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
+#if WIDE_CHAR_VERSION
+# include "wprintf-parse.h"
+#else
+# include "printf-parse.h"
+#endif
+
+/* Checked size_t computations. */
+#include "xsize.h"
+
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
+#endif
+
+#ifdef HAVE_WCHAR_T
+# ifdef HAVE_WCSLEN
+# define local_wcslen wcslen
+# else
+ /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid
+ a dependency towards this library, here is a local substitute.
+ Define this substitute only once, even if this file is included
+ twice in the same compilation unit. */
+# ifndef local_wcslen_defined
+# define local_wcslen_defined 1
+static size_t
+local_wcslen (const wchar_t *s)
+{
+ const wchar_t *ptr;
+
+ for (ptr = s; *ptr != (wchar_t) 0; ptr++)
+ ;
+ return ptr - s;
+}
+# endif
+# endif
+#endif
+
+#if WIDE_CHAR_VERSION
+# define VASNPRINTF vasnwprintf
+# define CHAR_T wchar_t
+# define DIRECTIVE wchar_t_directive
+# define DIRECTIVES wchar_t_directives
+# define PRINTF_PARSE wprintf_parse
+# define USE_SNPRINTF 1
+# if HAVE_DECL__SNWPRINTF
+ /* On Windows, the function swprintf() has a different signature than
+ on Unix; we use the _snwprintf() function instead. */
+# define SNPRINTF _snwprintf
+# else
+ /* Unix. */
+# define SNPRINTF swprintf
+# endif
+#else
+# define VASNPRINTF vasnprintf
+# define CHAR_T char
+# define DIRECTIVE char_directive
+# define DIRECTIVES char_directives
+# define PRINTF_PARSE printf_parse
+# define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF)
+# if HAVE_DECL__SNPRINTF
+ /* Windows. */
+# define SNPRINTF _snprintf
+# else
+ /* Unix. */
+# define SNPRINTF snprintf
+# endif
+#endif
+
+CHAR_T *
+VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args)
+{
+ DIRECTIVES d;
+ arguments a;
+
+ if (PRINTF_PARSE (format, &d, &a) < 0)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+#define CLEANUP() \
+ free (d.dir); \
+ if (a.arg) \
+ free (a.arg);
+
+ if (printf_fetchargs (args, &a) < 0)
+ {
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+ {
+ size_t buf_neededlength;
+ CHAR_T *buf;
+ CHAR_T *buf_malloced;
+ const CHAR_T *cp;
+ size_t i;
+ DIRECTIVE *dp;
+ /* Output string accumulator. */
+ CHAR_T *result;
+ size_t allocated;
+ size_t length;
+
+ /* Allocate a small buffer that will hold a directive passed to
+ sprintf or snprintf. */
+ buf_neededlength =
+ xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+#if HAVE_ALLOCA
+ if (buf_neededlength < 4000 / sizeof (CHAR_T))
+ {
+ buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
+ buf_malloced = NULL;
+ }
+ else
+#endif
+ {
+ size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
+ if (size_overflow_p (buf_memsize))
+ goto out_of_memory_1;
+ buf = (CHAR_T *) malloc (buf_memsize);
+ if (buf == NULL)
+ goto out_of_memory_1;
+ buf_malloced = buf;
+ }
+
+ if (resultbuf != NULL)
+ {
+ result = resultbuf;
+ allocated = *lengthp;
+ }
+ else
+ {
+ result = NULL;
+ allocated = 0;
+ }
+ length = 0;
+ /* Invariants:
+ result is either == resultbuf or == NULL or malloc-allocated.
+ If length > 0, then result != NULL. */
+
+ /* Ensures that allocated >= needed. Aborts through a jump to
+ out_of_memory if needed is SIZE_MAX or otherwise too big. */
+#define ENSURE_ALLOCATION(needed) \
+ if ((needed) > allocated) \
+ { \
+ size_t memory_size; \
+ CHAR_T *memory; \
+ \
+ allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
+ if ((needed) > allocated) \
+ allocated = (needed); \
+ memory_size = xtimes (allocated, sizeof (CHAR_T)); \
+ if (size_overflow_p (memory_size)) \
+ goto out_of_memory; \
+ if (result == resultbuf || result == NULL) \
+ memory = (CHAR_T *) malloc (memory_size); \
+ else \
+ memory = (CHAR_T *) realloc (result, memory_size); \
+ if (memory == NULL) \
+ goto out_of_memory; \
+ if (result == resultbuf && length > 0) \
+ memcpy (memory, result, length * sizeof (CHAR_T)); \
+ result = memory; \
+ }
+
+ for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
+ {
+ if (cp != dp->dir_start)
+ {
+ size_t n = dp->dir_start - cp;
+ size_t augmented_length = xsum (length, n);
+
+ ENSURE_ALLOCATION (augmented_length);
+ memcpy (result + length, cp, n * sizeof (CHAR_T));
+ length = augmented_length;
+ }
+ if (i == d.count)
+ break;
+
+ /* Execute a single directive. */
+ if (dp->conversion == '%')
+ {
+ size_t augmented_length;
+
+ if (!(dp->arg_index == ARG_NONE))
+ abort ();
+ augmented_length = xsum (length, 1);
+ ENSURE_ALLOCATION (augmented_length);
+ result[length] = '%';
+ length = augmented_length;
+ }
+ else
+ {
+ if (!(dp->arg_index != ARG_NONE))
+ abort ();
+
+ if (dp->conversion == 'n')
+ {
+ switch (a.arg[dp->arg_index].type)
+ {
+ case TYPE_COUNT_SCHAR_POINTER:
+ *a.arg[dp->arg_index].a.a_count_schar_pointer = length;
+ break;
+ case TYPE_COUNT_SHORT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_short_pointer = length;
+ break;
+ case TYPE_COUNT_INT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_pointer = length;
+ break;
+ case TYPE_COUNT_LONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_COUNT_LONGLONGINT_POINTER:
+ *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
+ break;
+#endif
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ arg_type type = a.arg[dp->arg_index].type;
+ CHAR_T *p;
+ unsigned int prefix_count;
+ int prefixes[2];
+#if !USE_SNPRINTF
+ size_t tmp_length;
+ CHAR_T tmpbuf[700];
+ CHAR_T *tmp;
+
+ /* Allocate a temporary buffer of sufficient size for calling
+ sprintf. */
+ {
+ size_t width;
+ size_t precision;
+
+ width = 0;
+ if (dp->width_start != dp->width_end)
+ {
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->width_arg_index].a.a_int;
+ width = (arg < 0 ? (unsigned int) (-arg) : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ precision = 6;
+ if (dp->precision_start != dp->precision_end)
+ {
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ int arg;
+
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ arg = a.arg[dp->precision_arg_index].a.a_int;
+ precision = (arg < 0 ? 0 : arg);
+ }
+ else
+ {
+ const CHAR_T *digitp = dp->precision_start + 1;
+
+ precision = 0;
+ while (digitp != dp->precision_end)
+ precision = xsum (xtimes (precision, 10), *digitp++ - '0');
+ }
+ }
+
+ switch (dp->conversion)
+ {
+
+ case 'd': case 'i': case 'u':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ break;
+
+ case 'o':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1 /* turn floor into ceil */
+ + 1; /* account for leading sign */
+ break;
+
+ case 'x': case 'X':
+# ifdef HAVE_LONG_LONG
+ if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ else
+# endif
+ if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ else
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading sign or alternate form */
+ break;
+
+ case 'f': case 'F':
+# ifdef HAVE_LONG_DOUBLE
+ if (type == TYPE_LONGDOUBLE)
+ tmp_length =
+ (unsigned int) (LDBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ else
+# endif
+ tmp_length =
+ (unsigned int) (DBL_MAX_EXP
+ * 0.30103 /* binary -> decimal */
+ * 2 /* estimate for FLAG_GROUP */
+ )
+ + 1 /* turn floor into ceil */
+ + 10; /* sign, decimal point etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'e': case 'E': case 'g': case 'G':
+ case 'a': case 'A':
+ tmp_length =
+ 12; /* sign, decimal point, exponent etc. */
+ tmp_length = xsum (tmp_length, precision);
+ break;
+
+ case 'c':
+# if defined HAVE_WINT_T && !WIDE_CHAR_VERSION
+ if (type == TYPE_WIDE_CHAR)
+ tmp_length = MB_CUR_MAX;
+ else
+# endif
+ tmp_length = 1;
+ break;
+
+ case 's':
+# ifdef HAVE_WCHAR_T
+ if (type == TYPE_WIDE_STRING)
+ {
+ tmp_length =
+ local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
+
+# if !WIDE_CHAR_VERSION
+ tmp_length = xtimes (tmp_length, MB_CUR_MAX);
+# endif
+ }
+ else
+# endif
+ tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
+ break;
+
+ case 'p':
+ tmp_length =
+ (unsigned int) (sizeof (void *) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1 /* turn floor into ceil */
+ + 2; /* account for leading 0x */
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (tmp_length < width)
+ tmp_length = width;
+
+ tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
+ }
+
+ if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
+ tmp = tmpbuf;
+ else
+ {
+ size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
+
+ if (size_overflow_p (tmp_memsize))
+ /* Overflow, would lead to out of memory. */
+ goto out_of_memory;
+ tmp = (CHAR_T *) malloc (tmp_memsize);
+ if (tmp == NULL)
+ /* Out of memory. */
+ goto out_of_memory;
+ }
+#endif
+
+ /* Construct the format string for calling snprintf or
+ sprintf. */
+ p = buf;
+ *p++ = '%';
+ if (dp->flags & FLAG_GROUP)
+ *p++ = '\'';
+ if (dp->flags & FLAG_LEFT)
+ *p++ = '-';
+ if (dp->flags & FLAG_SHOWSIGN)
+ *p++ = '+';
+ if (dp->flags & FLAG_SPACE)
+ *p++ = ' ';
+ if (dp->flags & FLAG_ALT)
+ *p++ = '#';
+ if (dp->flags & FLAG_ZERO)
+ *p++ = '0';
+ if (dp->width_start != dp->width_end)
+ {
+ size_t n = dp->width_end - dp->width_start;
+ memcpy (p, dp->width_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+ if (dp->precision_start != dp->precision_end)
+ {
+ size_t n = dp->precision_end - dp->precision_start;
+ memcpy (p, dp->precision_start, n * sizeof (CHAR_T));
+ p += n;
+ }
+
+ switch (type)
+ {
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ case TYPE_ULONGLONGINT:
+ *p++ = 'l';
+ /*FALLTHROUGH*/
+#endif
+ case TYPE_LONGINT:
+ case TYPE_ULONGINT:
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+#endif
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+#endif
+ *p++ = 'l';
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ *p++ = 'L';
+ break;
+#endif
+ default:
+ break;
+ }
+ *p = dp->conversion;
+#if USE_SNPRINTF
+ p[1] = '%';
+ p[2] = 'n';
+ p[3] = '\0';
+#else
+ p[1] = '\0';
+#endif
+
+ /* Construct the arguments for calling snprintf or sprintf. */
+ prefix_count = 0;
+ if (dp->width_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
+ }
+ if (dp->precision_arg_index != ARG_NONE)
+ {
+ if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
+ abort ();
+ prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int;
+ }
+
+#if USE_SNPRINTF
+ /* Prepare checking whether snprintf returns the count
+ via %n. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+#endif
+
+ for (;;)
+ {
+ size_t maxlen;
+ int count;
+ int retcount;
+
+ maxlen = allocated - length;
+ count = -1;
+ retcount = 0;
+
+#if USE_SNPRINTF
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ arg, &count); \
+ break; \
+ case 1: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], arg, &count); \
+ break; \
+ case 2: \
+ retcount = SNPRINTF (result + length, maxlen, buf, \
+ prefixes[0], prefixes[1], arg, \
+ &count); \
+ break; \
+ default: \
+ abort (); \
+ }
+#else
+# define SNPRINTF_BUF(arg) \
+ switch (prefix_count) \
+ { \
+ case 0: \
+ count = sprintf (tmp, buf, arg); \
+ break; \
+ case 1: \
+ count = sprintf (tmp, buf, prefixes[0], arg); \
+ break; \
+ case 2: \
+ count = sprintf (tmp, buf, prefixes[0], prefixes[1],\
+ arg); \
+ break; \
+ default: \
+ abort (); \
+ }
+#endif
+
+ switch (type)
+ {
+ case TYPE_SCHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_schar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UCHAR:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uchar;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_SHORT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_short;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_USHORT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_ushort;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT:
+ {
+ int arg = a.arg[dp->arg_index].a.a_int;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT:
+ {
+ unsigned int arg = a.arg[dp->arg_index].a.a_uint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_LONGINT:
+ {
+ long int arg = a.arg[dp->arg_index].a.a_longint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGINT:
+ {
+ unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_LONG
+ case TYPE_LONGLONGINT:
+ {
+ long long int arg = a.arg[dp->arg_index].a.a_longlongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_ULONGLONGINT:
+ {
+ unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_DOUBLE:
+ {
+ double arg = a.arg[dp->arg_index].a.a_double;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case TYPE_LONGDOUBLE:
+ {
+ long double arg = a.arg[dp->arg_index].a.a_longdouble;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_CHAR:
+ {
+ int arg = a.arg[dp->arg_index].a.a_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WINT_T
+ case TYPE_WIDE_CHAR:
+ {
+ wint_t arg = a.arg[dp->arg_index].a.a_wide_char;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_STRING:
+ {
+ const char *arg = a.arg[dp->arg_index].a.a_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#ifdef HAVE_WCHAR_T
+ case TYPE_WIDE_STRING:
+ {
+ const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+#endif
+ case TYPE_POINTER:
+ {
+ void *arg = a.arg[dp->arg_index].a.a_pointer;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ default:
+ abort ();
+ }
+
+#if USE_SNPRINTF
+ /* Portability: Not all implementations of snprintf()
+ are ISO C 99 compliant. Determine the number of
+ bytes that snprintf() has produced or would have
+ produced. */
+ if (count >= 0)
+ {
+ /* Verify that snprintf() has NUL-terminated its
+ result. */
+ if (count < maxlen && result[length + count] != '\0')
+ abort ();
+ /* Portability hack. */
+ if (retcount > count)
+ count = retcount;
+ }
+ else
+ {
+ /* snprintf() doesn't understand the '%n'
+ directive. */
+ if (p[1] != '\0')
+ {
+ /* Don't use the '%n' directive; instead, look
+ at the snprintf() return value. */
+ p[1] = '\0';
+ continue;
+ }
+ else
+ {
+ /* Look at the snprintf() return value. */
+ if (retcount < 0)
+ {
+ /* HP-UX 10.20 snprintf() is doubly deficient:
+ It doesn't understand the '%n' directive,
+ *and* it returns -1 (rather than the length
+ that would have been required) when the
+ buffer is too small. */
+ size_t bigger_need =
+ xsum (xtimes (allocated, 2), 12);
+ ENSURE_ALLOCATION (bigger_need);
+ continue;
+ }
+ else
+ count = retcount;
+ }
+ }
+#endif
+
+ /* Attempt to handle failure. */
+ if (count < 0)
+ {
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ errno = EINVAL;
+ return NULL;
+ }
+
+#if !USE_SNPRINTF
+ if (count >= tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
+#endif
+
+ /* Make room for the result. */
+ if (count >= maxlen)
+ {
+ /* Need at least count bytes. But allocate
+ proportionally, to avoid looping eternally if
+ snprintf() reports a too small count. */
+ size_t n =
+ xmax (xsum (length, count), xtimes (allocated, 2));
+
+ ENSURE_ALLOCATION (n);
+#if USE_SNPRINTF
+ continue;
+#endif
+ }
+
+#if USE_SNPRINTF
+ /* The snprintf() result did fit. */
+#else
+ /* Append the sprintf() result. */
+ memcpy (result + length, tmp, count * sizeof (CHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+#endif
+
+ length += count;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Add the final NUL. */
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length] = '\0';
+
+ if (result != resultbuf && length + 1 < allocated)
+ {
+ /* Shrink the allocated memory if possible. */
+ CHAR_T *memory;
+
+ memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T));
+ if (memory != NULL)
+ result = memory;
+ }
+
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ CLEANUP ();
+ *lengthp = length;
+ if (length > INT_MAX)
+ goto length_overflow;
+ return result;
+
+ length_overflow:
+ /* We could produce such a big string, but its length doesn't fit into
+ an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in
+ this case. */
+ if (result != resultbuf)
+ free (result);
+ errno = EOVERFLOW;
+ return NULL;
+
+ out_of_memory:
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ out_of_memory_1:
+ CLEANUP ();
+ errno = ENOMEM;
+ return NULL;
+ }
+}
+
+#undef SNPRINTF
+#undef USE_SNPRINTF
+#undef PRINTF_PARSE
+#undef DIRECTIVES
+#undef DIRECTIVE
+#undef CHAR_T
+#undef VASNPRINTF
diff --git a/gl/vasnprintf.h b/gl/vasnprintf.h
new file mode 100644
index 000000000..894008cae
--- /dev/null
+++ b/gl/vasnprintf.h
@@ -0,0 +1,77 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 2002-2004 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _VASNPRINTF_H
+#define _VASNPRINTF_H
+
+/* Get va_list. */
+#include <stdarg.h>
+
+/* Get size_t. */
+#include <stddef.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ You can pass a preallocated buffer for the result in RESULTBUF and its
+ size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+ If successful, return the address of the string (this may be = RESULTBUF
+ if no dynamic memory allocation was necessary) and set *LENGTHP to the
+ number of resulting bytes, excluding the trailing NUL. Upon error, set
+ errno and return NULL.
+
+ When dynamic memory allocation occurs, the preallocated buffer is left
+ alone (with possibly modified contents). This makes it possible to use
+ a statically allocated or stack-allocated buffer, like this:
+
+ char buf[100];
+ size_t len = sizeof (buf);
+ char *output = vasnprintf (buf, &len, format, args);
+ if (output == NULL)
+ ... error handling ...;
+ else
+ {
+ ... use the output string ...;
+ if (output != buf)
+ free (output);
+ }
+ */
+extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
+ __attribute__ ((__format__ (__printf__, 3, 0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VASNPRINTF_H */
diff --git a/gl/vasprintf.c b/gl/vasprintf.c
new file mode 100644
index 000000000..149c29242
--- /dev/null
+++ b/gl/vasprintf.c
@@ -0,0 +1,42 @@
+/* Formatted output to strings.
+ Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification. */
+#include "vasprintf.h"
+
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+int
+vasprintf (char **resultp, const char *format, va_list args)
+{
+ size_t length;
+ char *result = vasnprintf (NULL, &length, format, args);
+ if (result == NULL)
+ return -1;
+
+ *resultp = result;
+ /* Return the number of resulting bytes, excluding the trailing NUL.
+ If it wouldn't fit in an 'int', vasnprintf() would have returned NULL
+ and set errno to EOVERFLOW. */
+ return length;
+}
diff --git a/gl/vasprintf.h b/gl/vasprintf.h
new file mode 100644
index 000000000..d02f15451
--- /dev/null
+++ b/gl/vasprintf.h
@@ -0,0 +1,63 @@
+/* vsprintf with automatic memory allocation.
+ Copyright (C) 2002-2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _VASPRINTF_H
+#define _VASPRINTF_H
+
+#if HAVE_VASPRINTF
+
+/* Get asprintf(), vasprintf() declarations. */
+#include <stdio.h>
+
+#else
+
+/* Get va_list. */
+#include <stdarg.h>
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+ If the memory allocation succeeds, store the address of the string in
+ *RESULT and return the number of resulting bytes, excluding the trailing
+ NUL. Upon memory allocation error, or some other error, return -1. */
+extern int asprintf (char **result, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+extern int vasprintf (char **result, const char *format, va_list args)
+ __attribute__ ((__format__ (__printf__, 2, 0)));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /* _VASPRINTF_H */
diff --git a/gl/xsize.h b/gl/xsize.h
new file mode 100644
index 000000000..341fb16ca
--- /dev/null
+++ b/gl/xsize.h
@@ -0,0 +1,108 @@
+/* xsize.h -- Checked size_t computations.
+
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+ This program 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, or (at your option)
+ any later version.
+
+ This 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. */
+
+#ifndef _XSIZE_H
+#define _XSIZE_H
+
+/* Get size_t. */
+#include <stddef.h>
+
+/* Get SIZE_MAX. */
+#include <limits.h>
+#if HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+/* The size of memory objects is often computed through expressions of
+ type size_t. Example:
+ void* p = malloc (header_size + n * element_size).
+ These computations can lead to overflow. When this happens, malloc()
+ returns a piece of memory that is way too small, and the program then
+ crashes while attempting to fill the memory.
+ To avoid this, the functions and macros in this file check for overflow.
+ The convention is that SIZE_MAX represents overflow.
+ malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
+ implementation that uses mmap --, it's recommended to use size_overflow_p()
+ or size_in_bounds_p() before invoking malloc().
+ The example thus becomes:
+ size_t size = xsum (header_size, xtimes (n, element_size));
+ void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
+*/
+
+/* Convert an arbitrary value >= 0 to type size_t. */
+#define xcast_size_t(N) \
+ ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
+
+/* Sum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum (size_t size1, size_t size2)
+{
+ size_t sum = size1 + size2;
+ return (sum >= size1 ? sum : SIZE_MAX);
+}
+
+/* Sum of three sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum3 (size_t size1, size_t size2, size_t size3)
+{
+ return xsum (xsum (size1, size2), size3);
+}
+
+/* Sum of four sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
+{
+ return xsum (xsum (xsum (size1, size2), size3), size4);
+}
+
+/* Maximum of two sizes, with overflow check. */
+static inline size_t
+#if __GNUC__ >= 3
+__attribute__ ((__pure__))
+#endif
+xmax (size_t size1, size_t size2)
+{
+ /* No explicit check is needed here, because for any n:
+ max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
+ return (size1 >= size2 ? size1 : size2);
+}
+
+/* Multiplication of a count with an element size, with overflow check.
+ The count must be >= 0 and the element size must be > 0.
+ This is a macro, not an inline function, so that it works correctly even
+ when N is of a wider tupe and N > SIZE_MAX. */
+#define xtimes(N, ELSIZE) \
+ ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
+
+/* Check for overflow. */
+#define size_overflow_p(SIZE) \
+ ((SIZE) == SIZE_MAX)
+/* Check against overflow. */
+#define size_in_bounds_p(SIZE) \
+ ((SIZE) != SIZE_MAX)
+
+#endif /* _XSIZE_H */