aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2018-09-02 15:32:56 +0200
committerMattias Andrée <maandree@kth.se>2018-09-02 15:32:56 +0200
commit47128b7def4954c4cf544924c94f018d88033374 (patch)
treec75e6c76c078a095ff691d42a1f0b2d0ea0f0357
parentAdd malloc function attribute were appropriate (diff)
downloadlibsimple-47128b7def4954c4cf544924c94f018d88033374.tar.gz
libsimple-47128b7def4954c4cf544924c94f018d88033374.tar.bz2
libsimple-47128b7def4954c4cf544924c94f018d88033374.tar.xz
misc
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile52
-rw-r--r--README3
-rw-r--r--aligned_enmemdup.c64
-rw-r--r--aligned_memdup.c40
-rw-r--r--allocn.c118
-rw-r--r--config.mk2
-rw-r--r--enaligned_allocz.c132
-rw-r--r--enaligned_memdup.c64
-rw-r--r--encalloc.c2
-rw-r--r--enmalloc.c2
-rw-r--r--enposix_memalignz.c145
-rw-r--r--enrealloc.c4
-rw-r--r--enstrdup.c6
-rw-r--r--enstrndup.c6
-rw-r--r--envaligned_alloczn.c159
-rw-r--r--envmalloczn.c8
-rw-r--r--envmemalloc.c29
-rw-r--r--envposix_memalignzn.c174
-rw-r--r--envreallocn.c4
-rw-r--r--libsimple.c96
-rw-r--r--libsimple.h1433
-rw-r--r--libsimple/aligned_alloc.h75
-rw-r--r--libsimple/aligned_allocz.h85
-rw-r--r--libsimple/aligned_memdup.h40
-rw-r--r--libsimple/calloc.h74
-rw-r--r--libsimple/definitions.h421
-rw-r--r--libsimple/env.h93
-rw-r--r--libsimple/malloc.h74
-rw-r--r--libsimple/mallocz.h87
-rw-r--r--libsimple/mem.h64
-rw-r--r--libsimple/memalign.h82
-rw-r--r--libsimple/memalignz.h123
-rw-r--r--libsimple/memalloc.h113
-rw-r--r--libsimple/memdup.h33
-rw-r--r--libsimple/posix_memalign.h75
-rw-r--r--libsimple/posix_memalignz.h85
-rw-r--r--libsimple/printf.h122
-rw-r--r--libsimple/pvalloc.h82
-rw-r--r--libsimple/pvallocz.h111
-rw-r--r--libsimple/realloc.h72
-rw-r--r--libsimple/str.h99
-rw-r--r--libsimple/strdup.h27
-rw-r--r--libsimple/strn.h74
-rw-r--r--libsimple/strndup.h38
-rw-r--r--libsimple/time.h149
-rw-r--r--libsimple/valloc.h82
-rw-r--r--libsimple/vallocz.h107
-rw-r--r--strndup.c15
-rw-r--r--test.c131
-rw-r--r--vmemalloc.c232
50 files changed, 3929 insertions, 1479 deletions
diff --git a/Makefile b/Makefile
index 4d22b69..cb3628a 100644
--- a/Makefile
+++ b/Makefile
@@ -3,20 +3,59 @@
CONFIGFILE = config.mk
include $(CONFIGFILE)
+SUBHDR =\
+ libsimple/definitions.h\
+ libsimple/memalloc.h\
+ libsimple/strdup.h\
+ libsimple/strndup.h\
+ libsimple/memdup.h\
+ libsimple/aligned_memdup.h\
+ libsimple/mallocz.h\
+ libsimple/malloc.h\
+ libsimple/calloc.h\
+ libsimple/realloc.h\
+ libsimple/memalignz.h\
+ libsimple/memalign.h\
+ libsimple/vallocz.h\
+ libsimple/valloc.h\
+ libsimple/pvallocz.h\
+ libsimple/pvalloc.h\
+ libsimple/aligned_allocz.h\
+ libsimple/aligned_alloc.h\
+ libsimple/posix_memalignz.h\
+ libsimple/posix_memalign.h\
+ libsimple/env.h\
+ libsimple/time.h\
+ libsimple/printf.h\
+ libsimple/str.h\
+ libsimple/strn.h\
+ libsimple/mem.h
+
+HDR =\
+ $(SUBHDR)\
+ libsimple.h
+
OBJ =\
+ aligned_memdup.o\
allocn.o\
asprintf.o\
difftimespec.o\
difftimeval.o\
doubletotimespec.o\
doubletotimeval.o\
+ enaligned_memdup.o\
+ enaligned_allocz.o\
+ enposix_memalignz.o\
encalloc.o\
enmalloc.o\
enmemdup.o\
enrealloc.o\
enstrdup.o\
enstrndup.o\
+ envaligned_alloczn.o\
envmalloczn.o\
+ envmemalloc.o\
+ envposix_memalignzn.o\
envputenvf.o\
envreallocn.o\
isutf8.o\
@@ -52,6 +91,7 @@ OBJ =\
timespectostr.o\
timevaltostr.o\
vasprintf.o\
+ vmemalloc.o\
vputenvf.o\
vweprintf.o\
libsimple.o
@@ -59,10 +99,10 @@ OBJ =\
TESTS = $(OBJ:.o=.test)
all: libsimple.a $(TESTS)
-$(OBJ): $(@:.o=.c) libsimple.h
+$(OBJ): $(@:.o=.c) $(HDR)
$(TESTS): $(@:=.o) test.o libsimple.a
-$(TESTS:=.o): $(@:.test.o=.c) libsimple.h test.h
-test.o: test.c libsimple.h test.h
+$(TESTS:=.o): $(@:.test.o=.c) $(HDR) test.h
+test.o: test.c $(HDR) test.h
libsimple.a: $(OBJ)
$(AR) rc $@ $?
@@ -72,22 +112,24 @@ libsimple.a: $(OBJ)
$(CC) -o $@ $< test.o libsimple.a $(LDFLAGS)
.c.test.o:
- $(CC) -c -o $@ $< $(CFLAGS) -DTEST
+ $(CC) -c -o $@ $< $(CFLAGS) -DTEST -O0
check: $(TESTS)
@set -e; for t in $(TESTS); do printf '%s\n' "./$$t"; $(CHECK_PREFIX) "./$$t"; done
install: libsimple.a
mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
- mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
+ mkdir -p -- "$(DESTDIR)$(PREFIX)/include/libsimple"
cp -- libsimple.a "$(DESTDIR)$(PREFIX)/lib"
cp -- libsimple.h "$(DESTDIR)$(PREFIX)/include"
cp -- libsimple-arg.h "$(DESTDIR)$(PREFIX)/include"
+ cp -- $(SUBHDR) "$(DESTDIR)$(PREFIX)/include/libsimple"
uninstall:
-rm -f -- "$(DESTDIR)$(PREFIX)/lib/libsimple.a"
-rm -f -- "$(DESTDIR)$(PREFIX)/include/libsimple.h"
-rm -f -- "$(DESTDIR)$(PREFIX)/include/libsimple-arg.h"
+ -rm -rf -- "$(DESTDIR)$(PREFIX)/include/libsimple"
clean:
-rm -rf -- *.o *.su *.a *.so *.so.* *.gch *.gcda *.gcno *.gcov *.lo *.test
diff --git a/README b/README
index 4b2eb25..2866b75 100644
--- a/README
+++ b/README
@@ -5,7 +5,8 @@ values for integer data types.
All functions are namespaced with `libsimple_` and aliased with macro
definitions to unnamespaced names unless there already is a macro with that
-name.
+name. However, the `libsimple_{,e,en}{,v}{mem,array}alloc` functions do
+not have unnamespaced aliases as they are libsimple specific.
Programs using this library should define `char *argv0` and set it to
the 0:th command line argument.
diff --git a/aligned_enmemdup.c b/aligned_enmemdup.c
new file mode 100644
index 0000000..fced863
--- /dev/null
+++ b/aligned_enmemdup.c
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_enaligned_memdup(int status, const void *s, size_t alignment, size_t n)
+{
+ void *ret = aligned_memdup(s, aligned, n);
+ if (!ret)
+ enprintf(status, "aligned_memdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *s;
+
+ assert((s = libsimple_enaligned_memdup(1, "hello", 3, 5)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 3);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 5));
+ free(s);
+
+ assert((s = libsimple_ealigned_memdup("test", 7, 5)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 14);
+ assert(info->alignment == 7);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "test", 5));
+ free(s);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_memdup(44, "hello", 3, 2));
+ assert(exit_status == 44);
+ assert_stderr("%s: memdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 55;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_memdup("test", 7, 2));
+ assert(exit_status == 55);
+ assert_stderr("%s: memdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/aligned_memdup.c b/aligned_memdup.c
new file mode 100644
index 0000000..2dbba7b
--- /dev/null
+++ b/aligned_memdup.c
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_aligned_memdup(const void *s, size_t alignment, size_t n)
+{
+ void *ret = aligned_alloc(alignment, n + (alignment - n % alignment) % alignment);
+ if (!ret)
+ return NULL;
+ return memcpy(ret, s, n);
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ const char *s = "test";
+ void *p = libsimple_aligned_memdup(s, 4, 5);
+ assert(p);
+ assert(p != s);
+ assert(!((uintptr_t)s % 4));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(p)));
+ assert(info->size == 8);
+ assert(info->alignment == 4);
+ }
+ assert(!strcmpnul(p, s));
+ memset(p, 0, 5);
+ assert(!strcmpnul(s, "test"));
+ free(p);
+ return 0;
+}
+
+#endif
diff --git a/allocn.c b/allocn.c
index cc27dc5..bc199d2 100644
--- a/allocn.c
+++ b/allocn.c
@@ -4,11 +4,11 @@
static inline size_t
-alloc_size_product(size_t n, va_list ap)
+alloc_size_product(int *errp, size_t n, va_list ap)
{
size_t prod = n;
if (!n) {
- errno = EINVAL;
+ *errp = EINVAL;
return 0;
}
for (;;) {
@@ -16,7 +16,7 @@ alloc_size_product(size_t n, va_list ap)
if (!n)
break;
if (n >= SIZE_MAX / prod) {
- errno = ENOMEM;
+ *errp = ENOMEM;
return 0;
}
prod *= n;
@@ -27,17 +27,41 @@ alloc_size_product(size_t n, va_list ap)
void *
libsimple_vmalloczn(int clear, size_t n, va_list ap)
{
- n = alloc_size_product(n, ap);
+ n = alloc_size_product(&errno, n, ap);
return !n ? NULL : clear ? calloc(1, n) : malloc(n);
}
void *
libsimple_vreallocn(void *ptr, size_t n, va_list ap)
{
- n = alloc_size_product(n, ap);
+ n = alloc_size_product(&errno, n, ap);
return !n ? NULL : realloc(ptr, n);
}
+void *
+libsimple_valigned_alloczn(int clear, size_t alignment, size_t n, va_list ap)
+{
+ void *ret;
+ n = alloc_size_product(&errno, n, ap);
+ ret = !n ? NULL : aligned_alloc(alignment, n);
+ if (ret && clear)
+ memset(ret, 0, n);
+ return ret;
+}
+
+int
+libsimple_vposix_memalignzn(void **memptr, int clear, size_t alignment, size_t n, va_list ap)
+{
+ int ret = 0;
+ n = alloc_size_product(&ret, n, ap);
+ if (ret)
+ return ret;
+ ret = posix_memalign(memptr, alignment, n);
+ if (!ret && clear)
+ memset(*memptr, 0, n);
+ return ret;
+}
+
#else
#include "test.h"
@@ -58,6 +82,15 @@ main(void)
errno = 0;
assert(!libsimple_reallocn(NULL, 0) && errno == EINVAL);
errno = 0;
+ assert(!libsimple_aligned_alloczn(0, 128, 0) && errno == EINVAL);
+ errno = 0;
+ assert(!libsimple_aligned_alloczn(1, 128, 0) && errno == EINVAL);
+ errno = 0;
+ assert(!libsimple_aligned_allocn(128, 0) && errno == EINVAL);
+ errno = 0;
+ assert(libsimple_posix_memalignzn(&ptr, 0, 128, 0) == EINVAL && !errno);
+ assert(libsimple_posix_memalignzn(&ptr, 1, 128, 0) == EINVAL && !errno);
+ assert(libsimple_posix_memalignn(&ptr, 128, 0) == EINVAL && !errno);
assert(!libsimple_malloczn(0, SIZE_MAX, 2, 0) && errno == ENOMEM);
errno = 0;
@@ -69,12 +102,22 @@ main(void)
errno = 0;
assert(!libsimple_reallocn(NULL, SIZE_MAX, 2, 0) && errno == ENOMEM);
errno = 0;
+ assert(!libsimple_aligned_alloczn(0, 1024, SIZE_MAX, 2, 0) && errno == ENOMEM);
+ errno = 0;
+ assert(!libsimple_aligned_alloczn(1, 1024, SIZE_MAX, 2, 0) && errno == ENOMEM);
+ errno = 0;
+ assert(!libsimple_aligned_allocn(1024, SIZE_MAX, 2, 0) && errno == ENOMEM);
+ errno = 0;
+ assert(libsimple_posix_memalignzn(&ptr, 0, 1024, SIZE_MAX, 2, 0) == ENOMEM && !errno);
+ assert(libsimple_posix_memalignzn(&ptr, 1, 1024, SIZE_MAX, 2, 0) == ENOMEM && !errno);
+ assert(libsimple_posix_memalignn(&ptr, 1024, SIZE_MAX, 2, 0) == ENOMEM && !errno);
assert((ptr = libsimple_malloczn(0, 10, 10, 0)));
if (have_custom_malloc()) {
assert((info = get_allocinfo(ptr)));
assert(info->size == 100);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -83,6 +126,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 400);
assert(info->zeroed == 400);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -91,6 +135,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 121);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -99,6 +144,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 484);
assert(info->zeroed == 484);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -108,6 +154,7 @@ main(void)
assert(info->size == 5);
assert(!info->zeroed);
info->refcount += 1;
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
stpcpy(ptr, "test");
assert((ptr = libsimple_reallocn(old = ptr, 10, 0)));
@@ -116,11 +163,72 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 10);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
assert(ptr != old);
free(old);
}
free(ptr);
+ assert((ptr = libsimple_aligned_alloczn(0, 8, 12, 12, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 144);
+ assert(info->alignment == 8);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_aligned_alloczn(1, 16, 12, 12, 2, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 288);
+ assert(info->alignment == 16);
+ assert(info->zeroed == 288);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_aligned_allocn(32, 12, 12, 4, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 576);
+ assert(info->alignment == 32);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert(!libsimple_posix_memalignzn(&ptr, 0, sizeof(void *), 12, 12, 0));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 144);
+ assert(info->alignment == sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert(!libsimple_posix_memalignzn(&ptr, 1, 2 * sizeof(void *), 12, 12, 2, 0));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 288);
+ assert(info->alignment == 2 * sizeof(void *));
+ assert(info->zeroed == 288);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert(!libsimple_posix_memalignn(&ptr, 2 * sizeof(void *), 12, 12, 3, 0));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 432);
+ assert(info->alignment == 2 *sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
assert(!errno);
return 0;
diff --git a/config.mk b/config.mk
index 7a1e97a..f160bbd 100644
--- a/config.mk
+++ b/config.mk
@@ -2,5 +2,5 @@ PREFIX = /usr
MANPREFIX = $(PREFIX)/share/man
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700
-CFLAGS = -std=c99 -Wall -Wextra -O2 $(CPPFLAGS)
+CFLAGS = -std=c11 -Wall -Wextra -O2 $(CPPFLAGS)
LDFLAGS = -s
diff --git a/enaligned_allocz.c b/enaligned_allocz.c
new file mode 100644
index 0000000..f92df4f
--- /dev/null
+++ b/enaligned_allocz.c
@@ -0,0 +1,132 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_enaligned_allocz(int status, int clear, size_t alignment, size_t n)
+{
+ void *ret = libsimple_aligned_allocz(clear, alignment, n);
+ if (!ret)
+ enprintf(status, "aligned_alloc:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *ptr;
+
+ assert((ptr = libsimple_enaligned_allocz(1, 1, 8, 8)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 8);
+ assert(info->zeroed == 8);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_ealigned_allocz(1, 4, 8)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 4);
+ assert(info->zeroed == 8);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_enaligned_allocz(1, 0, 4, 8)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 4);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_ealigned_allocz(0, 2, 4)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 4);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_enaligned_alloc(1, 4, 8)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 4);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_ealigned_alloc(2, 4)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 4);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_allocz(3, 1, 2, 4));
+ assert(exit_status == 3);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 102;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_allocz(1, 1, 4));
+ assert(exit_status == 102);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_allocz(5, 0, 2, 4));
+ assert(exit_status == 5);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 103;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_allocz(0, 1, 4));
+ assert(exit_status == 103);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_alloc(7, 2, 4));
+ assert(exit_status == 7);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 104;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_alloc(1, 4));
+ assert(exit_status == 104);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/enaligned_memdup.c b/enaligned_memdup.c
new file mode 100644
index 0000000..ac94746
--- /dev/null
+++ b/enaligned_memdup.c
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_enaligned_memdup(int status, const void *s, size_t alignment, size_t n)
+{
+ void *ret = aligned_memdup(s, alignment, n);
+ if (!ret)
+ enprintf(status, "aligned_memdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *s;
+
+ assert((s = libsimple_enaligned_memdup(1, "hello", 2, 5)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 5));
+ free(s);
+
+ assert((s = libsimple_ealigned_memdup("test", 8, 5)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 8);
+ assert(info->alignment == 8);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "test", 5));
+ free(s);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_memdup(44, "hello", 2, 2));
+ assert(exit_status == 44);
+ assert_stderr("%s: aligned_memdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 55;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_memdup("test", 8, 2));
+ assert(exit_status == 55);
+ assert_stderr("%s: aligned_memdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/encalloc.c b/encalloc.c
index f930f82..82d25e3 100644
--- a/encalloc.c
+++ b/encalloc.c
@@ -27,6 +27,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 10);
assert(info->zeroed == 10);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -35,6 +36,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 12);
assert(info->zeroed == 12);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
diff --git a/enmalloc.c b/enmalloc.c
index edf4b5e..0da7c33 100644
--- a/enmalloc.c
+++ b/enmalloc.c
@@ -27,6 +27,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 5);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -35,6 +36,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 4);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
diff --git a/enposix_memalignz.c b/enposix_memalignz.c
new file mode 100644
index 0000000..64ae4f0
--- /dev/null
+++ b/enposix_memalignz.c
@@ -0,0 +1,145 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void
+libsimple_enposix_memalignz(int status, void **memptr, int clear, size_t alignment, size_t n)
+{
+ int err = libsimple_posix_memalignz(memptr, clear, alignment, n);
+ if (err) {
+ errno = err;
+ enprintf(status, "posix_memalign:");
+ }
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *ptr = NULL;
+
+ libsimple_enposix_memalignz(1, &ptr, 1, sizeof(void *), 8);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == sizeof(void *));
+ assert(info->zeroed == 8);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_eposix_memalignz(&ptr, 1, 2 * sizeof(void *), 8);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 2 * sizeof(void *));
+ assert(info->zeroed == 8);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_enposix_memalignz(1, &ptr, 0, 2 * sizeof(void *), 8);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 2 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_eposix_memalignz(&ptr, 0, 4 * sizeof(void *), 4);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 4);
+ assert(info->alignment == 4 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_enposix_memalign(1, &ptr, sizeof(void *), 8);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_eposix_memalign(&ptr, 8 * sizeof(void *), 4);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 4);
+ assert(info->alignment == 8 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalignz(3, &ptr, 1, sizeof(void *), 4));
+ assert(exit_status == 3);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 102;
+ alloc_fail_in = 1;
+ assert_exit(libsimple_eposix_memalignz(&ptr, 1, sizeof(void *), 4));
+ assert(exit_status == 102);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalignz(5, &ptr, 0, sizeof(void *), 4));
+ assert(exit_status == 5);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 103;
+ alloc_fail_in = 1;
+ assert_exit(libsimple_eposix_memalignz(&ptr, 0, sizeof(void *), 4));
+ assert(exit_status == 103);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalign(7, &ptr, sizeof(void *), 4));
+ assert(exit_status == 7);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 104;
+ alloc_fail_in = 1;
+ assert_exit(libsimple_eposix_memalign(&ptr, sizeof(void *), 4));
+ assert(exit_status == 104);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/enrealloc.c b/enrealloc.c
index 59033e7..878674c 100644
--- a/enrealloc.c
+++ b/enrealloc.c
@@ -27,6 +27,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 5);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
info->refcount += 1;
}
stpcpy(ptr, "test");
@@ -36,6 +37,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 10);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
assert(ptr != old);
free(old);
}
@@ -46,6 +48,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 5);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
info->refcount += 1;
}
stpcpy(ptr, "test");
@@ -55,6 +58,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 10);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
assert(ptr != old);
free(old);
}
diff --git a/enstrdup.c b/enstrdup.c
index 4ad78d4..f330422 100644
--- a/enstrdup.c
+++ b/enstrdup.c
@@ -6,9 +6,11 @@
char *
libsimple_enstrdup(int status, const char *s)
{
- char *ret = strdup(s);
+ size_t n = strlen(s) + 1;
+ char *ret = aligned_alloc(1, n);
if (!ret)
enprintf(status, "strdup:");
+ memcpy(ret, s, n);
return ret;
}
@@ -26,6 +28,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 6);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "hello"));
@@ -35,6 +38,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 5);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "test"));
diff --git a/enstrndup.c b/enstrndup.c
index a6bc7b3..c02c0fd 100644
--- a/enstrndup.c
+++ b/enstrndup.c
@@ -26,6 +26,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 6);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "hello"));
@@ -35,6 +36,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 5);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "test"));
@@ -44,6 +46,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 3);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "he"));
@@ -53,6 +56,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 4);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, "tes"));
@@ -62,6 +66,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 1);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, ""));
@@ -71,6 +76,7 @@ main(void)
if (have_custom_malloc()) {
assert((info = get_allocinfo(s)));
assert(info->size == 1);
+ assert(info->alignment == 1);
assert(!info->zeroed);
}
assert(!strcmp(s, ""));
diff --git a/envaligned_alloczn.c b/envaligned_alloczn.c
new file mode 100644
index 0000000..d79c6e7
--- /dev/null
+++ b/envaligned_alloczn.c
@@ -0,0 +1,159 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_envaligned_alloczn(int status, int clear, size_t alignment, size_t n, va_list ap)
+{
+ void *ret = libsimple_valigned_alloczn(clear, alignment, n, ap);
+ if (!ret)
+ enprintf(status, "aligned_alloc:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *ptr;
+
+ assert((ptr = libsimple_enaligned_alloczn(1, 0, 8, 4, 4, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 16);
+ assert(info->alignment == 8);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_enaligned_alloczn(1, 1, 16, 32, 2, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 64);
+ assert(info->alignment == 16);
+ assert(info->zeroed == 64);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_enaligned_allocn(1, 32, 8, 16, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 128);
+ assert(info->alignment == 32);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_alloczn(3, 0, 32, 256, 0));
+ assert(exit_status == 3);
+ stderr_buf[stderr_n] = 0;
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_alloczn(5, 1, 32, 128, 0));
+ assert(exit_status == 5);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_allocn(9, 32, 64, 0));
+ assert(exit_status == 9);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ }
+
+ assert_exit_ptr(libsimple_enaligned_alloczn(13, 0, 8, SIZE_MAX, 2, 0));
+ assert(exit_status == 13);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ assert_exit_ptr(libsimple_enaligned_alloczn(15, 1, 8, SIZE_MAX, 2, 0));
+ assert(exit_status == 15);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ assert_exit_ptr(libsimple_enaligned_allocn(19, 8, SIZE_MAX, 2, 0));
+ assert(exit_status == 19);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ assert((ptr = libsimple_ealigned_alloczn(0, 32, 2, 8, 8, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 128);
+ assert(info->alignment == 32);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_ealigned_alloczn(1, 8, 2, 4, 4, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 32);
+ assert(info->alignment == 8);
+ assert(info->zeroed == 32);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_ealigned_allocn(16, 2, 4, 8, 0)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 64);
+ assert(info->alignment == 16);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 23;
+ assert_exit_ptr(libsimple_ealigned_alloczn(0, 8, 16, 0));
+ assert(exit_status == 23);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 25;
+ assert_exit_ptr(libsimple_ealigned_alloczn(1, 8, 32, 0));
+ assert(exit_status == 25);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 29;
+ assert_exit_ptr(libsimple_ealigned_allocn(8, 64, 0));
+ assert(exit_status == 29);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ }
+
+ libsimple_default_failure_exit = 33;
+ assert_exit_ptr(libsimple_ealigned_alloczn(0, 8, SIZE_MAX, 2, 0));
+ assert(exit_status == 33);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ libsimple_default_failure_exit = 35;
+ assert_exit_ptr(libsimple_ealigned_alloczn(1, 8, SIZE_MAX, 2, 0));
+ assert(exit_status == 35);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ libsimple_default_failure_exit = 39;
+ assert_exit_ptr(libsimple_ealigned_allocn(8, SIZE_MAX, 2, 0));
+ assert(exit_status == 39);
+ assert_stderr("%s: aligned_alloc: %s\n", argv0, strerror(ENOMEM));
+
+ return 0;
+}
+
+#endif
diff --git a/envmalloczn.c b/envmalloczn.c
index 7531ecf..3e81b56 100644
--- a/envmalloczn.c
+++ b/envmalloczn.c
@@ -27,6 +27,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 15);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -35,6 +36,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 20);
assert(info->zeroed == 20);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -43,6 +45,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 12);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -51,6 +54,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 16);
assert(info->zeroed == 16);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -102,6 +106,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 30);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -110,6 +115,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 40);
assert(info->zeroed == 40);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -118,6 +124,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 24);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
@@ -126,6 +133,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 32);
assert(info->zeroed == 32);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
}
free(ptr);
diff --git a/envmemalloc.c b/envmemalloc.c
new file mode 100644
index 0000000..c500063
--- /dev/null
+++ b/envmemalloc.c
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void *
+libsimple_envmemalloc(int status, size_t n, va_list ap) /* TODO test (e[n][v]{mem,array}alloc) */
+{
+ void *ret;
+ int saved_errno = errno;
+ errno = 0;
+ ret = libsimple_vmemalloc(n, ap);
+ if (errno)
+ enprintf(status, "libsimple_vmemalloc:");
+ errno = saved_errno;
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/envposix_memalignzn.c b/envposix_memalignzn.c
new file mode 100644
index 0000000..62cc440
--- /dev/null
+++ b/envposix_memalignzn.c
@@ -0,0 +1,174 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+void
+libsimple_envposix_memalignzn(int status, void **memptr, int clear, size_t alignment, size_t n, va_list ap)
+{
+ int err = libsimple_vposix_memalignzn(memptr, clear, alignment, n, ap);
+ if (err) {
+ errno = err;
+ enprintf(status, "posix_memalign:");
+ }
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *ptr = NULL;
+
+ libsimple_enposix_memalignzn(1, &ptr, 0, sizeof(void *), 5, 3, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 15);
+ assert(info->alignment == sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_enposix_memalignzn(1, &ptr, 1, 2 * sizeof(void *), 5, 4, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 20);
+ assert(info->alignment == 2 * sizeof(void *));
+ assert(info->zeroed == 20);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_enposix_memalignn(1, &ptr, 4 * sizeof(void *), 4, 3, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 12);
+ assert(info->alignment == 4 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalignzn(3, &ptr, 0, 4 * sizeof(void *), 4, 0));
+ assert(exit_status == 3);
+ stderr_buf[stderr_n] = 0;
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalignzn(5, &ptr, 1, 4 * sizeof(void *), 2, 0));
+ assert(exit_status == 5);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert_exit(libsimple_enposix_memalignn(9, &ptr, 4 * sizeof(void *), 1, 0));
+ assert(exit_status == 9);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ }
+
+ assert_exit(libsimple_enposix_memalignzn(13, &ptr, 0, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 13);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ assert_exit(libsimple_enposix_memalignzn(15, &ptr, 1, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 15);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ assert_exit(libsimple_enposix_memalignn(19, &ptr, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 19);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ ptr = NULL;
+
+ libsimple_eposix_memalignzn(&ptr, 0, 4 * sizeof(void *), 2, 5, 3, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 30);
+ assert(info->alignment == 4 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_eposix_memalignzn(&ptr, 1, sizeof(void *), 2, 5, 4, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 40);
+ assert(info->alignment == sizeof(void *));
+ assert(info->zeroed == 40);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ libsimple_eposix_memalignn(&ptr, 2 * sizeof(void *), 2, 4, 3, 0);
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 24);
+ assert(info->alignment == 2 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 23;
+ assert_exit(libsimple_eposix_memalignzn(&ptr, 0, sizeof(void *), 4, 0));
+ assert(exit_status == 23);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 25;
+ assert_exit(libsimple_eposix_memalignzn(&ptr, 1, sizeof(void *), 2, 0));
+ assert(exit_status == 25);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ libsimple_default_failure_exit = 29;
+ assert_exit(libsimple_eposix_memalignn(&ptr, sizeof(void *), 1, 0));
+ assert(exit_status == 29);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ }
+
+ libsimple_default_failure_exit = 33;
+ assert_exit(libsimple_eposix_memalignzn(&ptr, 0, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 33);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ libsimple_default_failure_exit = 35;
+ assert_exit(libsimple_eposix_memalignzn(&ptr, 1, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 35);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ libsimple_default_failure_exit = 39;
+ assert_exit(libsimple_eposix_memalignn(&ptr, sizeof(void *), SIZE_MAX, 2, 0));
+ assert(exit_status == 39);
+ assert_stderr("%s: posix_memalign: %s\n", argv0, strerror(ENOMEM));
+
+ return 0;
+}
+
+#endif
diff --git a/envreallocn.c b/envreallocn.c
index 571d077..03394a1 100644
--- a/envreallocn.c
+++ b/envreallocn.c
@@ -27,6 +27,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 15);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
info->refcount += 1;
}
stpcpy(ptr, "test");
@@ -36,6 +37,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 20);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
assert(ptr != old);
free(old);
}
@@ -46,6 +48,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 20);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
info->refcount += 1;
}
stpcpy(ptr, "test");
@@ -55,6 +58,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 110);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)(info->alignment)));
assert(ptr != old);
free(old);
}
diff --git a/libsimple.c b/libsimple.c
index 641748a..a874258 100644
--- a/libsimple.c
+++ b/libsimple.c
@@ -87,9 +87,6 @@ test_vasprintfa(const char *expected, const char *format, ...)
}
#endif
-#ifdef __clang__
-__attribute__((optnone))
-#endif
int
main(void)
{
@@ -716,6 +713,19 @@ main(void)
fprintf(stderr, "warning: libsimple_memdupa missing\n");
#endif
+#ifdef libsimple_aligned_memdupa
+ cs = "xyz";
+ for (n = 1; n < 4; n++) {
+ s = libsimple_aligned_memdupa(cs, 4 + i, n);
+ assert(s);
+ assert(s != cs);
+ assert(!((uintptr_t)s % (4 + i)));
+ assert(!memcmp(s, cs, n));
+ }
+#else
+ fprintf(stderr, "warning: libsimple_aligned_memdupa missing\n");
+#endif
+
unsetenv("X");
assert(!getenv("X"));
assert(!libsimple_getenv_ne("X"));
@@ -1017,6 +1027,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 11);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
@@ -1025,6 +1036,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 12);
assert(info->zeroed == 12);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
@@ -1033,6 +1045,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 13);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
@@ -1041,6 +1054,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 14);
assert(info->zeroed == 14);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
@@ -1049,6 +1063,7 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 15);
assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
@@ -1057,8 +1072,55 @@ main(void)
assert((info = get_allocinfo(ptr)));
assert(info->size == 16);
assert(info->zeroed == 16);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_aligned_allocz(0, 8, 8)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 8);
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
+ }
+ free(ptr);
+
+ assert((ptr = libsimple_aligned_allocz(1, 8, 16)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 16);
+ assert(info->alignment == 8);
+ assert(info->zeroed == 16);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
+ }
+ free(ptr);
+
+ ptr = NULL;
+
+ assert(!libsimple_posix_memalignz(&ptr, 0, 8 * sizeof(void *), 8));
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 8);
+ assert(info->alignment == 8 * sizeof(void *));
+ assert(!info->zeroed);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
+ }
+ free(ptr);
+ ptr = NULL;
+
+ assert(!libsimple_posix_memalignz(&ptr, 1, 4 * sizeof(void *), 16));
+ assert(ptr);
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(ptr)));
+ assert(info->size == 16);
+ assert(info->alignment == 4 * sizeof(void *));
+ assert(info->zeroed == 16);
+ assert(!((uintptr_t)ptr % (uintptr_t)info->alignment));
}
free(ptr);
+ ptr = NULL;
if (have_custom_malloc()) {
alloc_fail_in = 1;
@@ -1094,6 +1156,24 @@ main(void)
alloc_fail_in = 1;
assert(!(ptr = libsimple_mallocz(1, 20)) && errno == ENOMEM);
assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert(!(ptr = libsimple_aligned_allocz(0, 8, 8)) && errno == ENOMEM);
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert(!(ptr = libsimple_aligned_allocz(1, 8, 16)) && errno == ENOMEM);
+ assert(!alloc_fail_in);
+
+ errno = 0;
+
+ alloc_fail_in = 1;
+ assert(libsimple_posix_memalignz(&ptr, 0, 4 * sizeof(void *), 8) == ENOMEM && !errno);
+ assert(!alloc_fail_in);
+
+ alloc_fail_in = 1;
+ assert(libsimple_posix_memalignz(&ptr, 1, 16 * sizeof(void *), 16) == ENOMEM && !errno);
+ assert(!alloc_fail_in);
}
assert((ptr = malloc(1)));
@@ -1122,6 +1202,16 @@ main(void)
assert(!read(fds[0], buf, sizeof(buf)));
close(fds[0]);
+ assert(libsimple_memeq("abcxyz", "abc123", 3));
+ assert(!libsimple_memeq("abcxyz", "abc123", 4));
+ assert(libsimple_memeq("abcxyz", "abcx23", 4));
+ assert(libsimple_memeq("1", "2", 0));
+ assert(!libsimple_memeq("1", "2", 1));
+
+ stpcpy(buf, "abc123");
+ assert(!strcmpnul(libsimple_mempset(buf, '.', 3), "123"));
+ assert(!strcmp(buf, "...123"));
+
#ifdef libsimple_asprintfa
s = libsimple_asprintfa("%sxyz%s", "abc", "123");
assert(s);
diff --git a/libsimple.h b/libsimple.h
index c9fbffc..96cd73c 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -50,431 +50,32 @@
extern int libsimple_default_failure_exit;
-#ifndef DONT_DEFINE_CLOCK_MONOTONIC_RAW
-# ifndef CLOCK_MONOTONIC_RAW
-# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
-# endif
-#endif
-
-
-#ifdef AF_LOCAL
-# ifndef AF_UNIX
-# define AF_UNIX AF_LOCAL
-# endif
-# ifndef AF_FILE
-# define AF_FILE AF_LOCAL
-# endif
-#endif
-
-#ifdef AF_UNIX
-# ifndef AF_LOCAL
-# define AF_LOCAL AF_UNIX
-# endif
-# ifndef AF_FILE
-# define AF_FILE AF_UNIX
-# endif
-#endif
-
-#ifdef AF_FILE
-# ifndef AF_LOCAL
-# define AF_LOCAL AF_FILE
-# endif
-# ifndef AF_UNIX
-# define AF_UNIX AF_FILE
-# endif
-#endif
-
-#ifdef AF_NETLINK
-# ifndef AF_ROUTE
-# define AF_ROUTE AF_NETLINK
-# endif
-#endif
-
-#ifdef AF_ROUTE
-# ifndef AF_NETLINK
-# define AF_NETLINK AF_ROUTE
-# endif
-#endif
-
-#ifdef PF_LOCAL
-# ifndef PF_UNIX
-# define PF_UNIX PF_LOCAL
-# endif
-# ifndef PF_FILE
-# define PF_FILE PF_LOCAL
-# endif
-#endif
-
-#ifdef PF_UNIX
-# ifndef PF_LOCAL
-# define PF_LOCAL PF_UNIX
-# endif
-# ifndef PF_FILE
-# define PF_FILE PF_UNIX
-# endif
-#endif
-
-#ifdef PF_FILE
-# ifndef PF_LOCAL
-# define PF_LOCAL PF_FILE
-# endif
-# ifndef PF_UNIX
-# define PF_UNIX PF_FILE
-# endif
-#endif
-
-#ifdef PF_NETLINK
-# ifndef PF_ROUTE
-# define PF_ROUTE PF_NETLINK
-# endif
-#endif
-
-#ifdef PF_ROUTE
-# ifndef PF_NETLINK
-# define PF_NETLINK PF_ROUTE
-# endif
-#endif
-
-#if !defined(PF_UNIX) && defined(AF_UNIX)
-# define PF_UNIX AF_UNIX
-#endif
-#if !defined(PF_LOCAL) && defined(AF_LOCAL)
-# define PF_LOCAL AF_LOCAL
-#endif
-#if !defined(PF_FILE) && defined(AF_FILE)
-# define PF_FILE AF_FILE
-#endif
-#if !defined(PF_INET) && defined(AF_INET)
-# define PF_INET AF_INET
-#endif
-#if !defined(PF_INET6) && defined(AF_INET6)
-# define PF_INET6 AF_INET6
-#endif
-#if !defined(PF_NETLINK) && defined(AF_NETLINK)
-# define PF_NETLINK AF_NETLINK
-#endif
-#if !defined(PF_ROUTE) && defined(AF_ROUTE)
-# define PF_ROUTE AF_ROUTE
-#endif
-
-
-#ifndef MIN
-# define MIN(A, B) ((A) < (B) ? (A) : (B))
-#endif
-
-
-#ifndef MAX
-# define MAX(A, B) ((A) > (B) ? (A) : (B))
-#endif
-
-
-#ifndef MIN3
-# define MIN3(A, B, C) MIN(MIN((A), (B)), (C))
-#endif
-
-
-#ifndef MAX3
-# define MAX3(A, B, C) MAX(MAX((A), (B)), (C))
-#endif
-
-
-#ifndef ELEMSOF
-# define ELEMSOF(ARR) (sizeof(ARR) / (sizeof(*(ARR))))
-#endif
-
-
-#ifndef STRLEN
-# define STRLEN(STR) (sizeof(STR) - 1)
-#endif
-
-
-#ifndef INTSTRLEN
-# define INTSTRLEN(TYPE) ((sizeof(TYPE) == 1 ? 3 : 5 * (sizeof(TYPE) / 2)) + ((TYPE)-1 < 0))
-#endif
-
-
-#ifndef TYPE_MAX
-# define TYPE_MAX(TYPE) ((TYPE)(((1ULL << (8 * sizeof(TYPE) - 1)) - 1) << ((TYPE)-1 > 0) | 1))
-#endif
-
-
-#ifndef TYPE_MIN
-# define TYPE_MIN(TYPE) ((TYPE)((TYPE)-1 > 0 ? 0 : (TYPE)~0 < (TYPE)-1 ? (TYPE)~0 : (TYPE)(1ULL << (8 * sizeof(TYPE) - 1))))
-#endif
-
-
-#ifndef BLKCNT64_MAX
-# define BLKCNT64_MAX TYPE_MAX(blkcnt64_t)
-#endif
-
-#ifndef BLKCNT_MAX
-# define BLKCNT_MAX TYPE_MAX(blkcnt_t)
-#endif
-
-#ifndef BLKSIZE_MAX
-# define BLKSIZE_MAX TYPE_MAX(blksize_t)
-#endif
-
-#ifndef CC_MAX
-# define CC_MAX TYPE_MAX(cc_t)
-#endif
-
-#ifndef CLOCKID_MAX
-# define CLOCKID_MAX TYPE_MAX(clockid_t)
-#endif
-
-#ifndef CLOCK_MAX
-# define CLOCK_MAX TYPE_MAX(clock_t)
-#endif
-
-#ifndef DEV_MAX
-# define DEV_MAX TYPE_MAX(dev_t)
-#endif
-
-#ifndef FSBLKCNT64_MAX
-# define FSBLKCNT64_MAX TYPE_MAX(fsblkcnt64_t)
-#endif
-
-#ifndef FSBLKCNT_MAX
-# define FSBLKCNT_MAX TYPE_MAX(fsblkcnt_t)
-#endif
-
-#ifndef FSFILCNT64_MAX
-# define FSFILCNT64_MAX TYPE_MAX(fsfilcnt64_t)
-#endif
-
-#ifndef FSFILCNT_MAX
-# define FSFILCNT_MAX TYPE_MAX(fsfilcnt_t)
-#endif
-
-#ifndef GID_MAX
-# define GID_MAX TYPE_MAX(gid_t)
-#endif
-
-#ifndef ID_MAX
-# define ID_MAX TYPE_MAX(id_t)
-#endif
-
-#ifndef INO64_MAX
-# define INO64_MAX TYPE_MAX(ino64_t)
-#endif
-
-#ifndef INO_MAX
-# define INO_MAX TYPE_MAX(ino_t)
-#endif
-
-#ifndef KEY_MAX
-# define KEY_MAX TYPE_MAX(key_t)
-#endif
-
-#ifndef LOFF_MAX
-# define LOFF_MAX TYPE_MAX(loff_t)
-#endif
-
-#ifndef MODE_MAX
-# define MODE_MAX TYPE_MAX(mode_t)
-#endif
-
-#ifndef NLINK_MAX
-# define NLINK_MAX TYPE_MAX(nlink_t)
-#endif
-
-#ifndef OFF64_MAX
-# define OFF64_MAX TYPE_MAX(off64_t)
-#endif
-
-#ifndef OFF_MAX
-# define OFF_MAX TYPE_MAX(off_t)
-#endif
-
-#ifndef PID_MAX
-# define PID_MAX TYPE_MAX(pid_t)
-#endif
-
-#ifndef QUAD_MAX
-# define QUAD_MAX TYPE_MAX(quad_t)
-#endif
-
-#ifndef REGISTER_MAX
-# define REGISTER_MAX TYPE_MAX(register_t)
-#endif
-
-#ifndef RLIM64_MAX
-# define RLIM64_MAX TYPE_MAX(rlim64_t)
-#endif
-
-#ifndef RLIM_MAX
-# define RLIM_MAX TYPE_MAX(rlim_t)
-#endif
-
-#ifndef SOCKLEN_MAX
-# define SOCKLEN_MAX TYPE_MAX(socklen_t)
-#endif
-
-#ifndef SPEED_MAX
-# define SPEED_MAX TYPE_MAX(speed_t)
-#endif
-
-#ifndef SUSECONDS_MAX
-# define SUSECONDS_MAX TYPE_MAX(suseconds_t)
-#endif
-
-#ifndef TCFLAG_MAX
-# define TCFLAG_MAX TYPE_MAX(tcflag_t)
-#endif
-
-#ifndef TIME_MAX
-# define TIME_MAX TYPE_MAX(time_t)
-#endif
-
-#ifndef UID_MAX
-# define UID_MAX TYPE_MAX(uid_t)
-#endif
-
-#ifndef USECONDS_MAX
-# define USECONDS_MAX TYPE_MAX(useconds_t)
-#endif
-
-#ifndef U_QUAD_MAX
-# define U_QUAD_MAX TYPE_MAX(u_quad_t)
-#endif
-
-
-#ifndef BLKCNT64_MIN
-# define BLKCNT64_MIN TYPE_MIN(blkcnt64_t)
-#endif
-
-#ifndef BLKCNT_MIN
-# define BLKCNT_MIN TYPE_MIN(blkcnt_t)
-#endif
-
-#ifndef BLKSIZE_MIN
-# define BLKSIZE_MIN TYPE_MIN(blksize_t)
-#endif
-
-#ifndef CC_MIN
-# define CC_MIN TYPE_MIN(cc_t)
-#endif
-
-#ifndef CLOCKID_MIN
-# define CLOCKID_MIN TYPE_MIN(clockid_t)
-#endif
-
-#ifndef CLOCK_MIN
-# define CLOCK_MIN TYPE_MIN(clock_t)
-#endif
-
-#ifndef DEV_MIN
-# define DEV_MIN TYPE_MIN(dev_t)
-#endif
-
-#ifndef FSBLKCNT64_MIN
-# define FSBLKCNT64_MIN TYPE_MIN(fsblkcnt64_t)
-#endif
-
-#ifndef FSBLKCNT_MIN
-# define FSBLKCNT_MIN TYPE_MIN(fsblkcnt_t)
-#endif
-
-#ifndef FSFILCNT64_MIN
-# define FSFILCNT64_MIN TYPE_MIN(fsfilcnt64_t)
-#endif
-
-#ifndef FSFILCNT_MIN
-# define FSFILCNT_MIN TYPE_MIN(fsfilcnt_t)
-#endif
-
-#ifndef GID_MIN
-# define GID_MIN TYPE_MIN(gid_t)
-#endif
-
-#ifndef ID_MIN
-# define ID_MIN TYPE_MIN(id_t)
-#endif
-
-#ifndef INO64_MIN
-# define INO64_MIN TYPE_MIN(ino64_t)
-#endif
-
-#ifndef INO_MIN
-# define INO_MIN TYPE_MIN(ino_t)
-#endif
-
-#ifndef KEY_MIN
-# define KEY_MIN TYPE_MIN(key_t)
-#endif
-
-#ifndef LOFF_MIN
-# define LOFF_MIN TYPE_MIN(loff_t)
-#endif
-
-#ifndef MODE_MIN
-# define MODE_MIN TYPE_MIN(mode_t)
-#endif
-
-#ifndef NLINK_MIN
-# define NLINK_MIN TYPE_MIN(nlink_t)
-#endif
-
-#ifndef OFF64_MIN
-# define OFF64_MIN TYPE_MIN(off64_t)
-#endif
-
-#ifndef OFF_MIN
-# define OFF_MIN TYPE_MIN(off_t)
-#endif
-
-#ifndef PID_MIN
-# define PID_MIN TYPE_MIN(pid_t)
-#endif
-
-#ifndef QUAD_MIN
-# define QUAD_MIN TYPE_MIN(quad_t)
-#endif
-
-#ifndef REGISTER_MIN
-# define REGISTER_MIN TYPE_MIN(register_t)
-#endif
-
-#ifndef RLIM64_MIN
-# define RLIM64_MIN TYPE_MIN(rlim64_t)
-#endif
-
-#ifndef RLIM_MIN
-# define RLIM_MIN TYPE_MIN(rlim_t)
-#endif
-
-#ifndef SOCKLEN_MIN
-# define SOCKLEN_MIN TYPE_MIN(socklen_t)
-#endif
-
-#ifndef SPEED_MIN
-# define SPEED_MIN TYPE_MAX(speed_t)
-#endif
-
-#ifndef SUSECONDS_MIN
-# define SUSECONDS_MIN TYPE_MIN(suseconds_t)
-#endif
-
-#ifndef TCFLAG_MIN
-# define TCFLAG_MIN TYPE_MAX(tcflag_t)
-#endif
-
-#ifndef TIME_MIN
-# define TIME_MIN TYPE_MIN(time_t)
-#endif
-
-#ifndef UID_MIN
-# define UID_MIN TYPE_MIN(uid_t)
-#endif
-
-#ifndef USECONDS_MIN
-# define USECONDS_MIN TYPE_MIN(useconds_t)
-#endif
-
-#ifndef U_QUAD_MIN
-# define U_QUAD_MIN TYPE_MIN(u_quad_t)
-#endif
+#include "libsimple/definitions.h"
+#include "libsimple/memalloc.h"
+#include "libsimple/strdup.h"
+#include "libsimple/strndup.h"
+#include "libsimple/memdup.h"
+#include "libsimple/aligned_memdup.h"
+#include "libsimple/mallocz.h"
+#include "libsimple/malloc.h"
+#include "libsimple/calloc.h"
+#include "libsimple/realloc.h"
+#include "libsimple/memalignz.h"
+#include "libsimple/memalign.h"
+#include "libsimple/vallocz.h"
+#include "libsimple/valloc.h"
+#include "libsimple/pvallocz.h"
+#include "libsimple/pvalloc.h"
+#include "libsimple/aligned_allocz.h"
+#include "libsimple/aligned_alloc.h"
+#include "libsimple/posix_memalignz.h"
+#include "libsimple/posix_memalign.h"
+#include "libsimple/env.h"
+#include "libsimple/time.h"
+#include "libsimple/printf.h"
+#include "libsimple/mem.h"
+#include "libsimple/str.h"
+#include "libsimple/strn.h"
#define FREE(PTR) ((void)(free(PTR), (PTR) = NULL))
@@ -493,39 +94,6 @@ libsimple_close(int *__fdp)
return __ret;
}
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-void *libsimple_rawmemchr(const void *, int);
-#ifndef rawmemchr
-# define rawmemchr libsimple_rawmemchr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-void *libsimple_memrchr(const void *, int, size_t);
-#ifndef memrchr
-# define memrchr libsimple_memrchr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-void *libsimple_rawmemrchr(const void *, int, size_t);
-#ifndef rawmemrchr
-# define rawmemrchr libsimple_rawmemrchr
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strchrnul(const char *, int);
-#ifndef strchrnul
-# define strchrnul libsimple_strchrnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline char *libsimple_strend(const char *__s)
-{ return strchr(__s, '\0'); }
-#ifndef strend
-# define strend libsimple_strend
-#endif
-
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
static inline int libsimple_inchrset(int __c, const char *__s)
{ return __c && strchr(__s, __c); }
@@ -533,73 +101,6 @@ static inline int libsimple_inchrset(int __c, const char *__s)
# define inchrset libsimple_inchrset
#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__)))
-void *libsimple_memdup(const void *, size_t);
-#ifndef memdup
-# define memdup libsimple_memdup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strndup(const char *, size_t);
-#ifndef strndup
-# define strndup libsimple_strndup
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__)))
-static inline void *libsimple_mempcpy(void *__d, const void *__s, size_t __n)
-{ return &((char *)memcpy(__d, __s, __n))[__n]; }
-#ifndef mempcpy
-# define mempcpy libsimple_mempcpy
-#endif
-
-
-#if defined(__GNUC__) || defined(__clang__)
-# define libsimple_strdupa(s)\
- ({\
- const char *__s = (s);\
- size_t __n = strlen(__s) + 1;\
- char *__r = alloca(__n);\
- memcpy(__r, __s, __n);\
- })
-# ifndef strdupa
-# define strdupa(s) libsimple_strdupa(s)
-# endif
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-# define libsimple_strndupa(s, n)\
- ({\
- const char *__s = (s);\
- size_t __n = (n);\
- size_t __m = strlen(__s);\
- char *__r;\
- __n = __n < __m ? __n : __m;\
- __r = alloca(__n + 1);\
- memcpy(__r, __s, __n);\
- __r[__n] = '\0';\
- __r;\
- })
-# ifndef strndupa
-# define strndupa(s, n) libsimple_strndupa(s, n)
-# endif
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-# define libsimple_memdupa(s, n)\
- ({\
- const char *__s = (s);\
- size_t __n = (n);\
- char *__r = alloca(__n);\
- memcpy(__r, __s, __n);\
- })
-# ifndef memdupa
-# define memdupa(s, n) libsimple_memdupa(s, n)
-# endif
-#endif
-
-
/**
* Check whether a NUL-terminated string is encoded in UTF-8
*
@@ -613,888 +114,6 @@ int libsimple_isutf8(const char *, int);
# define isutf8 libsimple_isutf8
#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2), __format__(__printf__, 2, 3))))
-int libsimple_asprintf(char **, const char *, ...);
-#ifndef asprintf
-# define asprintf libsimple_asprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
-int libsimple_vasprintf(char **, const char *, va_list);
-#ifndef vasprintf
-# define vasprintf libsimple_vasprintf
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-# define libsimple_asprintfa(__fmt, ...)\
- ({\
- const char *__f = (__fmt);\
- char *__ret = NULL;\
- int __r = snprintf(NULL, 0, __f, __VA_ARGS__);\
- if (__r >= 0) {\
- __ret = alloca((size_t)__r + 1);\
- sprintf(__ret, __f, __VA_ARGS__);\
- }\
- __ret;\
- })
-# ifndef asprintfa
-# define asprintfa(...) libsimple_asprintfa(__VA_ARGS__)
-# endif
-#endif
-
-#if defined(__GNUC__) || defined(__clang__)
-# define libsimple_vasprintfa(__fmt, __ap)\
- ({\
- const char *__f = (__fmt);\
- va_list __a1;\
- va_list __a2;\
- char *__ret = NULL;\
- int __r;\
- va_copy(__a1, __ap);\
- va_copy(__a2, __a1);\
- __r = vsnprintf(NULL, 0, __f, __a1);\
- if (__r >= 0) {\
- __ret = alloca((size_t)__r + 1);\
- vsprintf(__ret, __f, __a2);\
- }\
- va_end(__a2);\
- va_end(__a1);\
- __ret;\
- })
-# ifndef vasprintfa
-# define vasprintfa(fmt, ap) libsimple_vasprintfa(fmt, ap)
-# endif
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-void *libsimple_memmem(const void *, size_t, const void *, size_t);
-#ifndef memmem
-# define memmem libsimple_memmem
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-void *libsimple_memrmem(const void *, size_t, const void *, size_t);
-#ifndef memrmem
-# define memrmem libsimple_memrmem
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-int libsimple_memstarts(const void *, size_t, const void *, size_t);
-#ifndef memstarts
-# define memstarts libsimple_memstarts
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-int libsimple_memends(const void *, size_t, const void *, size_t);
-#ifndef memends
-# define memends libsimple_memends
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strrstr(const char *, const char *);
-#ifndef strrstr
-# define strrstr libsimple_strrstr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strnstr(const char *, const char *, size_t);
-#ifndef strnstr
-# define strnstr libsimple_strnstr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strrnstr(const char *, const char *, size_t);
-#ifndef strrnstr
-# define strrnstr libsimple_strrnstr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-int libsimple_strstarts(const char *, const char *);
-#ifndef strstarts
-# define strstarts libsimple_strstarts
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline int libsimple_strcasestarts(const char *__s, const char *__t)
-{ return !strncasecmp(__s, __t, strlen(__t)); }
-#ifndef strcasestarts
-# define strcasestarts libsimple_strcasestarts
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-int libsimple_strends(const char *, const char *);
-#ifndef strends
-# define strends libsimple_strends
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-int libsimple_strcaseends(const char *, const char *);
-#ifndef strcaseends
-# define strcaseends libsimple_strcaseends
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strcasestr(const char *, const char *);
-#ifndef strcasestr
-# define strcasestr libsimple_strcasestr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strrcasestr(const char *, const char *);
-#ifndef strrcasestr
-# define strrcasestr libsimple_strrcasestr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strncasestr(const char *, const char *, size_t);
-#ifndef strncasestr
-# define strncasestr libsimple_strncasestr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-char *libsimple_strrncasestr(const char *, const char *, size_t);
-#ifndef strrncasestr
-# define strrncasestr libsimple_strrncasestr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strcmpnul(const char *__a, const char *__b)
-{ return (!__a || !__b) ? !__b - !__a : strcmp(__a, __b); }
-#ifndef strcmpnul
-# define strcmpnul libsimple_strcmpnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strncmpnul(const char *__a, const char *__b, size_t __n)
-{ return (!__a || !__b) ? !__b - !__a : strncmp(__a, __b, __n); }
-#ifndef strncmpnul
-# define strncmpnul libsimple_strncmpnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strcasecmpnul(const char *__a, const char *__b)
-{ return (!__a || !__b) ? !__b - !__a : strcasecmp(__a, __b); }
-#ifndef strcasecmpnul
-# define strcasecmpnul libsimple_strcasecmpnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strncasecmpnul(const char *__a, const char *__b, size_t __n)
-{ return (!__a || !__b) ? !__b - !__a : strncasecmp(__a, __b, __n); }
-#ifndef strncasecmpnul
-# define strncasecmpnul libsimple_strncasecmpnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline int libsimple_streq(const char *__a, const char *__b)
-{ return !strcmp(__a, __b); }
-#ifndef streq
-# define streq libsimple_streq
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline int libsimple_strneq(const char *__a, const char *__b, size_t __n)
-{ return !strncmp(__a, __b, __n); }
-#ifndef strneq
-# define strneq libsimple_strneq
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_streqnul(const char *__a, const char *__b)
-{ return !strcmpnul(__a, __b); }
-#ifndef streqnul
-# define streqnul libsimple_streqnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strneqnul(const char *__a, const char *__b, size_t __n)
-{ return !strncmpnul(__a, __b, __n); }
-#ifndef strneqnul
-# define strneqnul libsimple_strneqnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline int libsimple_strcaseeq(const char *__a, const char *__b)
-{ return !strcasecmp(__a, __b); }
-#ifndef strcaseeq
-# define strcaseeq libsimple_strcaseeq
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
-static inline int libsimple_strncaseeq(const char *__a, const char *__b, size_t __n)
-{ return !strncasecmp(__a, __b, __n); }
-#ifndef strncaseeq
-# define strncaseeq libsimple_strncaseeq
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strcaseeqnul(const char *__a, const char *__b)
-{ return !strcasecmpnul(__a, __b); }
-#ifndef strcaseeqnul
-# define strcaseeqnul libsimple_strcaseeqnul
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
-static inline int libsimple_strncaseeqnul(const char *__a, const char *__b, size_t __n)
-{ return !strncasecmpnul(__a, __b, __n); }
-#ifndef strncaseeqnul
-# define strncaseeqnul libsimple_strncaseeqnul
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-void *libsimple_vmalloczn(int, size_t, va_list);
-#ifndef vmalloczn
-# define vmalloczn libsimple_vmalloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *libsimple_vmallocn(size_t __n, va_list __ap)
-{ return libsimple_vmalloczn(0, __n, __ap); }
-#ifndef vmallocn
-# define vmallocn libsimple_vmallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *libsimple_vcallocn(size_t __n, va_list __ap)
-{ return libsimple_vmalloczn(1, __n, __ap); }
-#ifndef vcallocn
-# define vcallocn libsimple_vcallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-void *libsimple_vreallocn(void *, size_t, va_list);
-#ifndef vreallocn
-# define vreallocn libsimple_vreallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *
-libsimple_mallocz(int __clear, size_t __n)
-{ return __clear ? calloc(1, __n) : malloc(__n); }
-#ifndef mallocn
-# define mallocn libsimple_mallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *
-libsimple_malloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_vmalloczn(__clear, __n, __ap);
- va_end(__ap);
-}
-#ifndef malloczn
-# define malloczn libsimple_malloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *
-libsimple_mallocn(size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_vmalloczn(0, __n, __ap);
- va_end(__ap);
-}
-#ifndef mallocn
-# define mallocn libsimple_mallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *
-libsimple_callocn(size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_vmalloczn(1, __n, __ap);
- va_end(__ap);
-}
-#ifndef callocn
-# define callocn libsimple_callocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
-static inline void *
-libsimple_reallocn(void *__ptr, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_vreallocn(__ptr, __n, __ap);
- va_end(__ap);
-}
-#ifndef reallocn
-# define reallocn libsimple_reallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_enmalloc(int, size_t);
-#ifndef enmalloc
-# define enmalloc libsimple_enmalloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_encalloc(int, size_t, size_t);
-#ifndef encalloc
-# define encalloc libsimple_encalloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_enrealloc(int, void *, size_t);
-#ifndef enrealloc
-# define enrealloc libsimple_enrealloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_enmallocz(int __status, int __clear, size_t __n)
-{ return __clear ? libsimple_encalloc(__status, 1, __n) : libsimple_enmalloc(__status, __n); }
-#ifndef enmallocz
-# define enmallocz libsimple_enmallocz
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
-char *libsimple_enstrdup(int, const char *);
-#ifndef enstrdup
-# define enstrdup libsimple_enstrdup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
-char *libsimple_enstrndup(int, const char *, size_t);
-#ifndef enstrndup
-# define enstrndup libsimple_enstrndup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_enmemdup(int, const void *, size_t);
-#ifndef enmemdup
-# define enmemdup libsimple_enmemdup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_envmalloczn(int, int, size_t, va_list);
-#ifndef envmalloczn
-# define envmalloczn libsimple_envmalloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_envmallocn(int __st, size_t __n, va_list __ap)
-{ return libsimple_envmalloczn(__st, 0, __n, __ap); }
-#ifndef envmallocn
-# define envmallocn libsimple_envmallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_envcallocn(int __st, size_t __n, va_list __ap)
-{ return libsimple_envmalloczn(__st, 1, __n, __ap); }
-#ifndef envcallocn
-# define envcallocn libsimple_envcallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-void *libsimple_envreallocn(int, void *, size_t, va_list);
-#ifndef envreallocn
-# define envreallocn libsimple_envreallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_enmalloczn(int __status, int __clear, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_envmalloczn(__status, __clear, __n, __ap);
- va_end(__ap);
-}
-#ifndef enmalloczn
-# define enmalloczn libsimple_enmalloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_enmallocn(int __status, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_envmallocn(__status, __n, __ap);
- va_end(__ap);
-}
-#ifndef enmallocn
-# define enmallocn libsimple_enmallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_encallocn(int __status, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_envcallocn(__status, __n, __ap);
- va_end(__ap);
-}
-#ifndef encallocn
-# define encallocn libsimple_encallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_enreallocn(int __status, void *__ptr, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_envreallocn(__status, __ptr, __n, __ap);
- va_end(__ap);
-}
-#ifndef enreallocn
-# define enreallocn libsimple_enreallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_emallocz(int __clear, size_t __n)
-{ return libsimple_enmallocz(libsimple_default_failure_exit, __clear, __n); }
-#ifndef emallocz
-# define emallocz libsimple_emallocz
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_emalloc(size_t __n)
-{ return libsimple_enmalloc(libsimple_default_failure_exit, __n); }
-#ifndef emalloc
-# define emalloc libsimple_emalloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_ecalloc(size_t __n, size_t __m)
-{ return encalloc(libsimple_default_failure_exit, __n, __m); }
-#ifndef ecalloc
-# define ecalloc libsimple_ecalloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_erealloc(void *__ptr, size_t __n)
-{ return enrealloc(libsimple_default_failure_exit, __ptr, __n); }
-#ifndef erealloc
-# define erealloc libsimple_erealloc
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
-static inline char *libsimple_estrdup(const char *__s)
-{ return enstrdup(libsimple_default_failure_exit, __s); }
-#ifndef estrdup
-# define estrdup libsimple_estrdup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
-static inline char *libsimple_estrndup(const char *__s, size_t __n)
-{ return enstrndup(libsimple_default_failure_exit, __s, __n); }
-#ifndef estrndup
-# define estrndup libsimple_estrndup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_ememdup(const void *__s, size_t __n)
-{ return enmemdup(libsimple_default_failure_exit, __s, __n); }
-#ifndef ememdup
-# define ememdup libsimple_ememdup
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_evmalloczn(int __clear, size_t __n, va_list __ap)
-{ return libsimple_envmalloczn(libsimple_default_failure_exit, __clear, __n, __ap); }
-#ifndef evmalloczn
-# define evmalloczn libsimple_evmalloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_evmallocn(size_t __n, va_list __ap)
-{ return libsimple_envmallocn(libsimple_default_failure_exit, __n, __ap); }
-#ifndef evmallocn
-# define evmallocn libsimple_evmallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_evcallocn(size_t __n, va_list __ap)
-{ return libsimple_envcallocn(libsimple_default_failure_exit, __n, __ap); }
-#ifndef evcallocn
-# define evcallocn libsimple_evcallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *libsimple_evreallocn(void *__ptr, size_t __n, va_list __ap)
-{ return libsimple_envreallocn(libsimple_default_failure_exit, __ptr, __n, __ap); }
-#ifndef evreallocn
-# define evreallocn libsimple_evreallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_emalloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_evmalloczn(__clear, __n, __ap);
- va_end(__ap);
-}
-#ifndef emalloczn
-# define emalloczn libsimple_emalloczn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_emallocn(size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_evmallocn(__n, __ap);
- va_end(__ap);
-}
-#ifndef emallocn
-# define emallocn libsimple_emallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_ecallocn(size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_evcallocn(__n, __ap);
- va_end(__ap);
-}
-#ifndef ecallocn
-# define ecallocn libsimple_ecallocn
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
-static inline void *
-libsimple_ereallocn(void *__ptr, size_t __n, ... /*, (size_t)0 */)
-{
- va_list __ap;
- va_start(__ap, __n);
- return libsimple_evreallocn(__ptr, __n, __ap);
- va_end(__ap);
-}
-#ifndef ereallocn
-# define ereallocn libsimple_ereallocn
-#endif
-
-
-/**
- * Read an environment variable, but handle it as undefined if empty
- *
- * @param var The environment variable's name
- * @return The environment variable's value, `NULL` if empty or not defined
- */
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
-static inline char *
-libsimple_getenv_ne(const char *__name)
-{
- char *__env = getenv(__name);
- return (__env && *__env) ? __env : NULL;
-}
-#ifndef getenv_ne
-# define getenv_ne libsimple_getenv_ne
-#endif
-
-/**
- * Read an environment variable, but handle it as empty if undefined
- *
- * @param var The environment variable's name
- * @return The environment variable's value, "" if empty or not defined
- */
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__, __returns_nonnull__)))
-static inline const char *
-libsimple_getenv_e(const char *__name)
-{
- const char *__env = getenv(__name);
- return (__env && *__env) ? __env : "";
-}
-#ifndef getenv_e
-# define getenv_e libsimple_getenv_e
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_vputenvf(const char *, va_list);
-#ifndef vputenvf
-# define vputenvf libsimple_vputenvf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 1, 2))))
-static inline int
-libsimple_putenvf(const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- return libsimple_vputenvf(__fmt, __ap);
- va_end(__ap);
-}
-#ifndef putenvf
-# define putenvf libsimple_putenvf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-void libsimple_envputenvf(int, const char *, va_list);
-#ifndef envputenvf
-# define envputenvf libsimple_envputenvf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 2, 3))))
-static inline void
-libsimple_enputenvf(int __status, const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- libsimple_envputenvf(__status, __fmt, __ap);
- va_end(__ap);
-}
-#ifndef enputenvf
-# define enputenvf libsimple_enputenvf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-static inline void
-libsimple_evputenvf(const char *__fmt, va_list __ap)
-{
- libsimple_envputenvf(libsimple_default_failure_exit, __fmt, __ap);
-}
-#ifndef evputenvf
-# define evputenvf libsimple_evputenvf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 1, 2))))
-static inline void
-libsimple_eputenvf(const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- libsimple_evputenvf(__fmt, __ap);
- va_end(__ap);
-}
-#ifndef eputenvf
-# define eputenvf libsimple_eputenvf
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
-void libsimple_vweprintf(const char *, va_list);
-#ifndef vweprintf
-# define vweprintf libsimple_vweprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2))))
-static inline void
-libsimple_weprintf(const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- libsimple_vweprintf(__fmt, __ap);
- va_end(__ap);
-}
-#ifndef weprintf
-# define weprintf libsimple_weprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2), __noreturn__)))
-static inline void
-libsimple_venprintf(int __status, const char *__fmt, va_list __ap)
-{
- libsimple_vweprintf(__fmt, __ap);
- exit(__status);
-}
-#ifndef venprintf
-# define venprintf libsimple_venprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2), __format__(__printf__, 2, 3), __noreturn__)))
-static inline void
-libsimple_enprintf(int __status, const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- libsimple_venprintf(__status, __fmt, __ap);
- va_end(__ap);
-}
-#ifndef enprintf
-# define enprintf libsimple_enprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __noreturn__)))
-static inline void
-libsimple_veprintf(const char *__fmt, va_list __ap)
-{
- libsimple_vweprintf(__fmt, __ap);
- exit(libsimple_default_failure_exit);
-}
-#ifndef veprintf
-# define veprintf libsimple_veprintf
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2), __noreturn__)))
-static inline void
-libsimple_eprintf(const char *__fmt, ...)
-{
- va_list __ap;
- va_start(__ap, __fmt);
- libsimple_veprintf(__fmt, __ap);
- va_end(__ap);
-}
-#ifndef eprintf
-# define eprintf libsimple_eprintf
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_sumtimespec(struct timespec *, const struct timespec *, const struct timespec *);
-#ifndef sumtimespec
-# define sumtimespec libsimple_sumtimespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_difftimespec(struct timespec *, const struct timespec *, const struct timespec *);
-#ifndef difftimespec
-# define difftimespec libsimple_difftimespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_multimespec(struct timespec *, const struct timespec *, int);
-#ifndef multimespec
-# define multimespec libsimple_multimespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
-static inline int
-libsimple_cmptimespec(const struct timespec *__a, const struct timespec *__b)
-{
- if (__a->tv_sec != __b->tv_sec)
- return __a->tv_sec < __b->tv_sec ? -1 : +1;
- return __a->tv_nsec < __b->tv_nsec ? -1 : __a->tv_nsec > __b->tv_nsec;
-}
-#ifndef cmptimespec
-# define cmptimespec libsimple_cmptimespec
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_sumtimeval(struct timeval *, const struct timeval *, const struct timeval *);
-#ifndef sumtimeval
-# define sumtimeval libsimple_sumtimeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_difftimeval(struct timeval *, const struct timeval *, const struct timeval *);
-#ifndef difftimeval
-# define difftimeval libsimple_difftimeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_multimeval(struct timeval *, const struct timeval *, int);
-#ifndef multimeval
-# define multimeval libsimple_multimeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
-static inline int
-libsimple_cmptimeval(const struct timeval *__a, const struct timeval *__b)
-{
- if (__a->tv_sec != __b->tv_sec)
- return __a->tv_sec < __b->tv_sec ? -1 : +1;
- return __a->tv_usec < __b->tv_usec ? -1 : __a->tv_usec > __b->tv_usec;
-}
-#ifndef cmptimeval
-# define cmptimeval libsimple_cmptimeval
-#endif
-
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-static inline void
-libsimple_timeval2timespec(struct timespec *restrict __ts, const struct timeval *restrict __tv)
-{
- __ts->tv_sec = __tv->tv_sec;
- __ts->tv_nsec = __tv->tv_usec;
- __ts->tv_nsec *= 1000L;
-}
-#ifndef timeval2timespec
-# define timeval2timespec libsimple_timeval2timespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-int libsimple_timespec2timeval(struct timeval *restrict, const struct timespec *restrict);
-#ifndef timespec2timeval
-# define timespec2timeval libsimple_timespec2timeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
-int libsimple_strtotimespec(struct timespec *restrict, const char *restrict, char **restrict);
-#ifndef strtotimespec
-# define strtotimespec libsimple_strtotimespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
-int libsimple_strtotimeval(struct timeval *restrict, const char *restrict, char **restrict);
-#ifndef strtotimeval
-# define strtotimeval libsimple_strtotimeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
-char *libsimple_timespectostr(char *restrict, const struct timespec *restrict);
-#ifndef timespectostr
-# define timespectostr libsimple_timespectostr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
-char *libsimple_timevaltostr(char *restrict, const struct timeval *restrict);
-#ifndef timevaltostr
-# define timevaltostr libsimple_timevaltostr
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-static inline double
-libsimple_timespectodouble(const struct timespec *__ts)
-{
- double __ret = (double)(__ts->tv_nsec);
- __ret /= (double)1000000000L;
- __ret += (double)(__ts->tv_sec);
- return __ret;
-}
-#ifndef timespectodouble
-# define timespectodouble libsimple_timespectodouble
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-static inline double
-libsimple_timevaltodouble(const struct timeval *__tv)
-{
- double __ret = (double)(__tv->tv_usec);
- __ret /= (double)1000000L;
- __ret += (double)(__tv->tv_sec);
- return __ret;
-}
-#ifndef timevaltodouble
-# define timevaltodouble libsimple_timevaltodouble
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-void libsimple_doubletotimespec(struct timespec *, double);
-#ifndef doubletotimespec
-# define doubletotimespec libsimple_doubletotimespec
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
-void libsimple_doubletotimeval(struct timeval *, double);
-#ifndef doubletotimeval
-# define doubletotimeval libsimple_doubletotimeval
-#endif
-
-_LIBSIMPLE_GCC_ONLY(__attribute__((__returns_nonnull__, __nonnull__)))
-char *libsimple_minimise_number_string(char *);
-#ifndef minimise_number_string
-# define minimise_number_string libsimple_minimise_number_string
-#endif
-
-
#define LIBSIMPLE_UNLIST(LIST, I, NP) libsimple_unlist((LIST), (I), (NP), sizeof(*(LIST)))
#ifndef UNLIST
# define UNLIST(LIST, I, NP) LIBSIMPLE_UNLIST((LIST), (I), (NP))
diff --git a/libsimple/aligned_alloc.h b/libsimple/aligned_alloc.h
new file mode 100644
index 0000000..8e7d66f
--- /dev/null
+++ b/libsimple/aligned_alloc.h
@@ -0,0 +1,75 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__)))
+static inline void *libsimple_valigned_allocn(size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_valigned_alloczn(0, __alignment, __n, __ap); }
+#ifndef valigned_allocn
+# define valigned_allocn libsimple_valigned_allocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__)))
+static inline void *
+libsimple_aligned_allocn(size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_valigned_allocn(__alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef aligned_allocn
+# define aligned_allocn libsimple_aligned_allocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_enaligned_alloc(int __status, size_t __alignment, size_t __n)
+{ return libsimple_enaligned_allocz(__status, 0, __alignment, __n); }
+#ifndef enaligned_alloc
+# define enaligned_alloc libsimple_enaligned_alloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envaligned_allocn(int __status, size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envaligned_alloczn(__status, 0, __alignment, __n, __ap); }
+#ifndef envaligned_allocn
+# define envaligned_allocn libsimple_envaligned_allocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enaligned_allocn(int __status, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envaligned_alloczn(__status, 0, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enaligned_allocn
+# define enaligned_allocn libsimple_enaligned_allocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ealigned_alloc(size_t __alignment, size_t __n)
+{ return libsimple_enaligned_alloc(libsimple_default_failure_exit, __alignment, __n); }
+#ifndef ealigned_alloc
+# define ealigned_alloc libsimple_ealigned_alloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evaligned_allocn(size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envaligned_allocn(libsimple_default_failure_exit, __alignment, __n, __ap); }
+#ifndef evaligned_allocn
+# define evaligned_allocn libsimple_evaligned_allocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ealigned_allocn(size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evaligned_allocn(__alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef ealigned_allocn
+# define ealigned_allocn libsimple_ealigned_allocn
+#endif
diff --git a/libsimple/aligned_allocz.h b/libsimple/aligned_allocz.h
new file mode 100644
index 0000000..f34a015
--- /dev/null
+++ b/libsimple/aligned_allocz.h
@@ -0,0 +1,85 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__)))
+void *libsimple_valigned_alloczn(int, size_t, size_t, va_list);
+#ifndef valigned_alloczn
+# define valigned_alloczn libsimple_valigned_alloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__)))
+static inline void *
+libsimple_aligned_allocz(int __clear, size_t __alignment, size_t __n)
+{
+ void *__ret = aligned_alloc(__alignment, __n);
+ if (__ret && __clear)
+ memset(__ret, 0, __n);
+ return __ret;
+}
+#ifndef aligned_allocz
+# define aligned_allocz libsimple_aligned_allocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__)))
+static inline void *
+libsimple_aligned_alloczn(int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_valigned_alloczn(__clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef aligned_alloczn
+# define aligned_alloczn libsimple_aligned_alloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __alloc_size__(4), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enaligned_allocz(int, int, size_t, size_t);
+#ifndef enaligned_allocz
+# define enaligned_allocz libsimple_enaligned_allocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_envaligned_alloczn(int, int, size_t, size_t, va_list);
+#ifndef envaligned_alloczn
+# define envaligned_alloczn libsimple_envaligned_alloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enaligned_alloczn(int __status, int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envaligned_alloczn(__status, __clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enaligned_alloczn
+# define enaligned_alloczn libsimple_enaligned_alloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ealigned_allocz(int __clear, size_t __alignment, size_t __n)
+{ return libsimple_enaligned_allocz(libsimple_default_failure_exit, __clear, __alignment, __n); }
+#ifndef ealigned_allocz
+# define ealigned_allocz libsimple_ealigned_allocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evaligned_alloczn(int __clear, size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envaligned_alloczn(libsimple_default_failure_exit, __clear, __alignment, __n, __ap); }
+#ifndef evaligned_alloczn
+# define evaligned_alloczn libsimple_evaligned_alloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ealigned_alloczn(int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evaligned_alloczn(__clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef ealigned_alloczn
+# define ealigned_alloczn libsimple_ealigned_alloczn
+#endif
diff --git a/libsimple/aligned_memdup.h b/libsimple/aligned_memdup.h
new file mode 100644
index 0000000..8138eb2
--- /dev/null
+++ b/libsimple/aligned_memdup.h
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_memdupa(s, alignment, n)\
+ ({\
+ const char *__s = (s);\
+ size_t __n = (n);\
+ size_t __a = (alignment);\
+ uintptr_t __misalignment;\
+ char *__r;\
+ __a += !__a;\
+ __r = alloca(__n + (__a - 1));\
+ __misalignment = (uintptr_t)__r % (uintptr_t)__a;\
+ if (__misalignment)\
+ __r += (uintptr_t)__a - __misalignment;\
+ memcpy(__r, __s, __n);\
+ })
+# ifndef aligned_memdupa
+# define aligned_memdupa(s, alignment, n) libsimple_aligned_memdupa(s, alignment, n)
+# endif
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_align__(2), __alloc_size__(3), __nonnull__, __warn_unused_result__)))
+void *libsimple_aligned_memdup(const void *, size_t, size_t);
+#ifndef aligned_memdup
+# define aligned_memdup libsimple_aligned_memdup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_align__(3), __alloc_size__(4), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enaligned_memdup(int, const void *, size_t, size_t);
+#ifndef enaligned_memdup
+# define enaligned_memdup libsimple_enaligned_memdup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_align__(2), __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ealigned_memdup(const void *__s, size_t __alignment, size_t __n)
+{ return enaligned_memdup(libsimple_default_failure_exit, __s, __alignment, __n); }
+#ifndef ealigned_memdup
+# define ealigned_memdup libsimple_ealigned_memdup
+#endif
diff --git a/libsimple/calloc.h b/libsimple/calloc.h
new file mode 100644
index 0000000..ab73ff3
--- /dev/null
+++ b/libsimple/calloc.h
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_vcallocn(size_t __n, va_list __ap)
+{ return libsimple_vmalloczn(1, __n, __ap); }
+#ifndef vcallocn
+# define vcallocn libsimple_vcallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_callocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmalloczn(1, __n, __ap);
+ va_end(__ap);
+}
+#ifndef callocn
+# define callocn libsimple_callocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2, 3), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_encalloc(int, size_t, size_t);
+#ifndef encalloc
+# define encalloc libsimple_encalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envcallocn(int __st, size_t __n, va_list __ap)
+{ return libsimple_envmalloczn(__st, 1, __n, __ap); }
+#ifndef envcallocn
+# define envcallocn libsimple_envcallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_encallocn(int __status, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envcallocn(__status, __n, __ap);
+ va_end(__ap);
+}
+#ifndef encallocn
+# define encallocn libsimple_encallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(1, 2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ecalloc(size_t __n, size_t __m)
+{ return encalloc(libsimple_default_failure_exit, __n, __m); }
+#ifndef ecalloc
+# define ecalloc libsimple_ecalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evcallocn(size_t __n, va_list __ap)
+{ return libsimple_envcallocn(libsimple_default_failure_exit, __n, __ap); }
+#ifndef evcallocn
+# define evcallocn libsimple_evcallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ecallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evcallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef ecallocn
+# define ecallocn libsimple_ecallocn
+#endif
diff --git a/libsimple/definitions.h b/libsimple/definitions.h
new file mode 100644
index 0000000..9bbc649
--- /dev/null
+++ b/libsimple/definitions.h
@@ -0,0 +1,421 @@
+/* See LICENSE file for copyright and license details. */
+
+#ifndef DONT_DEFINE_CLOCK_MONOTONIC_RAW
+# ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+# endif
+#endif
+
+
+#ifdef AF_LOCAL
+# ifndef AF_UNIX
+# define AF_UNIX AF_LOCAL
+# endif
+# ifndef AF_FILE
+# define AF_FILE AF_LOCAL
+# endif
+#endif
+
+#ifdef AF_UNIX
+# ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+# endif
+# ifndef AF_FILE
+# define AF_FILE AF_UNIX
+# endif
+#endif
+
+#ifdef AF_FILE
+# ifndef AF_LOCAL
+# define AF_LOCAL AF_FILE
+# endif
+# ifndef AF_UNIX
+# define AF_UNIX AF_FILE
+# endif
+#endif
+
+#ifdef AF_NETLINK
+# ifndef AF_ROUTE
+# define AF_ROUTE AF_NETLINK
+# endif
+#endif
+
+#ifdef AF_ROUTE
+# ifndef AF_NETLINK
+# define AF_NETLINK AF_ROUTE
+# endif
+#endif
+
+#ifdef PF_LOCAL
+# ifndef PF_UNIX
+# define PF_UNIX PF_LOCAL
+# endif
+# ifndef PF_FILE
+# define PF_FILE PF_LOCAL
+# endif
+#endif
+
+#ifdef PF_UNIX
+# ifndef PF_LOCAL
+# define PF_LOCAL PF_UNIX
+# endif
+# ifndef PF_FILE
+# define PF_FILE PF_UNIX
+# endif
+#endif
+
+#ifdef PF_FILE
+# ifndef PF_LOCAL
+# define PF_LOCAL PF_FILE
+# endif
+# ifndef PF_UNIX
+# define PF_UNIX PF_FILE
+# endif
+#endif
+
+#ifdef PF_NETLINK
+# ifndef PF_ROUTE
+# define PF_ROUTE PF_NETLINK
+# endif
+#endif
+
+#ifdef PF_ROUTE
+# ifndef PF_NETLINK
+# define PF_NETLINK PF_ROUTE
+# endif
+#endif
+
+#if !defined(PF_UNIX) && defined(AF_UNIX)
+# define PF_UNIX AF_UNIX
+#endif
+#if !defined(PF_LOCAL) && defined(AF_LOCAL)
+# define PF_LOCAL AF_LOCAL
+#endif
+#if !defined(PF_FILE) && defined(AF_FILE)
+# define PF_FILE AF_FILE
+#endif
+#if !defined(PF_INET) && defined(AF_INET)
+# define PF_INET AF_INET
+#endif
+#if !defined(PF_INET6) && defined(AF_INET6)
+# define PF_INET6 AF_INET6
+#endif
+#if !defined(PF_NETLINK) && defined(AF_NETLINK)
+# define PF_NETLINK AF_NETLINK
+#endif
+#if !defined(PF_ROUTE) && defined(AF_ROUTE)
+# define PF_ROUTE AF_ROUTE
+#endif
+
+
+#ifndef MIN
+# define MIN(A, B) ((A) < (B) ? (A) : (B))
+#endif
+
+#ifndef MAX
+# define MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+#ifndef MIN3
+# define MIN3(A, B, C) MIN(MIN((A), (B)), (C))
+#endif
+
+#ifndef MAX3
+# define MAX3(A, B, C) MAX(MAX((A), (B)), (C))
+#endif
+
+
+#ifndef ELEMSOF
+# define ELEMSOF(ARR) (sizeof(ARR) / (sizeof(*(ARR))))
+#endif
+
+#ifndef STRLEN
+# define STRLEN(STR) (sizeof(STR) - 1)
+#endif
+
+#ifndef INTSTRLEN
+# define INTSTRLEN(TYPE) ((sizeof(TYPE) == 1 ? 3 : 5 * (sizeof(TYPE) / 2)) + ((TYPE)-1 < 0))
+#endif
+
+
+#ifndef TYPE_MAX
+# define TYPE_MAX(TYPE) ((TYPE)(((1ULL << (8 * sizeof(TYPE) - 1)) - 1) << ((TYPE)-1 > 0) | 1))
+#endif
+
+#ifndef TYPE_MIN
+# define TYPE_MIN(TYPE) ((TYPE)((TYPE)-1 > 0 ? 0 : (TYPE)~0 < (TYPE)-1 ? (TYPE)~0 : (TYPE)(1ULL << (8 * sizeof(TYPE) - 1))))
+#endif
+
+
+#ifndef BLKCNT64_MAX
+# define BLKCNT64_MAX TYPE_MAX(blkcnt64_t)
+#endif
+
+#ifndef BLKCNT_MAX
+# define BLKCNT_MAX TYPE_MAX(blkcnt_t)
+#endif
+
+#ifndef BLKSIZE_MAX
+# define BLKSIZE_MAX TYPE_MAX(blksize_t)
+#endif
+
+#ifndef CC_MAX
+# define CC_MAX TYPE_MAX(cc_t)
+#endif
+
+#ifndef CLOCKID_MAX
+# define CLOCKID_MAX TYPE_MAX(clockid_t)
+#endif
+
+#ifndef CLOCK_MAX
+# define CLOCK_MAX TYPE_MAX(clock_t)
+#endif
+
+#ifndef DEV_MAX
+# define DEV_MAX TYPE_MAX(dev_t)
+#endif
+
+#ifndef FSBLKCNT64_MAX
+# define FSBLKCNT64_MAX TYPE_MAX(fsblkcnt64_t)
+#endif
+
+#ifndef FSBLKCNT_MAX
+# define FSBLKCNT_MAX TYPE_MAX(fsblkcnt_t)
+#endif
+
+#ifndef FSFILCNT64_MAX
+# define FSFILCNT64_MAX TYPE_MAX(fsfilcnt64_t)
+#endif
+
+#ifndef FSFILCNT_MAX
+# define FSFILCNT_MAX TYPE_MAX(fsfilcnt_t)
+#endif
+
+#ifndef GID_MAX
+# define GID_MAX TYPE_MAX(gid_t)
+#endif
+
+#ifndef ID_MAX
+# define ID_MAX TYPE_MAX(id_t)
+#endif
+
+#ifndef INO64_MAX
+# define INO64_MAX TYPE_MAX(ino64_t)
+#endif
+
+#ifndef INO_MAX
+# define INO_MAX TYPE_MAX(ino_t)
+#endif
+
+#ifndef KEY_MAX
+# define KEY_MAX TYPE_MAX(key_t)
+#endif
+
+#ifndef LOFF_MAX
+# define LOFF_MAX TYPE_MAX(loff_t)
+#endif
+
+#ifndef MODE_MAX
+# define MODE_MAX TYPE_MAX(mode_t)
+#endif
+
+#ifndef NLINK_MAX
+# define NLINK_MAX TYPE_MAX(nlink_t)
+#endif
+
+#ifndef OFF64_MAX
+# define OFF64_MAX TYPE_MAX(off64_t)
+#endif
+
+#ifndef OFF_MAX
+# define OFF_MAX TYPE_MAX(off_t)
+#endif
+
+#ifndef PID_MAX
+# define PID_MAX TYPE_MAX(pid_t)
+#endif
+
+#ifndef QUAD_MAX
+# define QUAD_MAX TYPE_MAX(quad_t)
+#endif
+
+#ifndef REGISTER_MAX
+# define REGISTER_MAX TYPE_MAX(register_t)
+#endif
+
+#ifndef RLIM64_MAX
+# define RLIM64_MAX TYPE_MAX(rlim64_t)
+#endif
+
+#ifndef RLIM_MAX
+# define RLIM_MAX TYPE_MAX(rlim_t)
+#endif
+
+#ifndef SOCKLEN_MAX
+# define SOCKLEN_MAX TYPE_MAX(socklen_t)
+#endif
+
+#ifndef SPEED_MAX
+# define SPEED_MAX TYPE_MAX(speed_t)
+#endif
+
+#ifndef SUSECONDS_MAX
+# define SUSECONDS_MAX TYPE_MAX(suseconds_t)
+#endif
+
+#ifndef TCFLAG_MAX
+# define TCFLAG_MAX TYPE_MAX(tcflag_t)
+#endif
+
+#ifndef TIME_MAX
+# define TIME_MAX TYPE_MAX(time_t)
+#endif
+
+#ifndef UID_MAX
+# define UID_MAX TYPE_MAX(uid_t)
+#endif
+
+#ifndef USECONDS_MAX
+# define USECONDS_MAX TYPE_MAX(useconds_t)
+#endif
+
+#ifndef U_QUAD_MAX
+# define U_QUAD_MAX TYPE_MAX(u_quad_t)
+#endif
+
+
+#ifndef BLKCNT64_MIN
+# define BLKCNT64_MIN TYPE_MIN(blkcnt64_t)
+#endif
+
+#ifndef BLKCNT_MIN
+# define BLKCNT_MIN TYPE_MIN(blkcnt_t)
+#endif
+
+#ifndef BLKSIZE_MIN
+# define BLKSIZE_MIN TYPE_MIN(blksize_t)
+#endif
+
+#ifndef CC_MIN
+# define CC_MIN TYPE_MIN(cc_t)
+#endif
+
+#ifndef CLOCKID_MIN
+# define CLOCKID_MIN TYPE_MIN(clockid_t)
+#endif
+
+#ifndef CLOCK_MIN
+# define CLOCK_MIN TYPE_MIN(clock_t)
+#endif
+
+#ifndef DEV_MIN
+# define DEV_MIN TYPE_MIN(dev_t)
+#endif
+
+#ifndef FSBLKCNT64_MIN
+# define FSBLKCNT64_MIN TYPE_MIN(fsblkcnt64_t)
+#endif
+
+#ifndef FSBLKCNT_MIN
+# define FSBLKCNT_MIN TYPE_MIN(fsblkcnt_t)
+#endif
+
+#ifndef FSFILCNT64_MIN
+# define FSFILCNT64_MIN TYPE_MIN(fsfilcnt64_t)
+#endif
+
+#ifndef FSFILCNT_MIN
+# define FSFILCNT_MIN TYPE_MIN(fsfilcnt_t)
+#endif
+
+#ifndef GID_MIN
+# define GID_MIN TYPE_MIN(gid_t)
+#endif
+
+#ifndef ID_MIN
+# define ID_MIN TYPE_MIN(id_t)
+#endif
+
+#ifndef INO64_MIN
+# define INO64_MIN TYPE_MIN(ino64_t)
+#endif
+
+#ifndef INO_MIN
+# define INO_MIN TYPE_MIN(ino_t)
+#endif
+
+#ifndef KEY_MIN
+# define KEY_MIN TYPE_MIN(key_t)
+#endif
+
+#ifndef LOFF_MIN
+# define LOFF_MIN TYPE_MIN(loff_t)
+#endif
+
+#ifndef MODE_MIN
+# define MODE_MIN TYPE_MIN(mode_t)
+#endif
+
+#ifndef NLINK_MIN
+# define NLINK_MIN TYPE_MIN(nlink_t)
+#endif
+
+#ifndef OFF64_MIN
+# define OFF64_MIN TYPE_MIN(off64_t)
+#endif
+
+#ifndef OFF_MIN
+# define OFF_MIN TYPE_MIN(off_t)
+#endif
+
+#ifndef PID_MIN
+# define PID_MIN TYPE_MIN(pid_t)
+#endif
+
+#ifndef QUAD_MIN
+# define QUAD_MIN TYPE_MIN(quad_t)
+#endif
+
+#ifndef REGISTER_MIN
+# define REGISTER_MIN TYPE_MIN(register_t)
+#endif
+
+#ifndef RLIM64_MIN
+# define RLIM64_MIN TYPE_MIN(rlim64_t)
+#endif
+
+#ifndef RLIM_MIN
+# define RLIM_MIN TYPE_MIN(rlim_t)
+#endif
+
+#ifndef SOCKLEN_MIN
+# define SOCKLEN_MIN TYPE_MIN(socklen_t)
+#endif
+
+#ifndef SPEED_MIN
+# define SPEED_MIN TYPE_MAX(speed_t)
+#endif
+
+#ifndef SUSECONDS_MIN
+# define SUSECONDS_MIN TYPE_MIN(suseconds_t)
+#endif
+
+#ifndef TCFLAG_MIN
+# define TCFLAG_MIN TYPE_MAX(tcflag_t)
+#endif
+
+#ifndef TIME_MIN
+# define TIME_MIN TYPE_MIN(time_t)
+#endif
+
+#ifndef UID_MIN
+# define UID_MIN TYPE_MIN(uid_t)
+#endif
+
+#ifndef USECONDS_MIN
+# define USECONDS_MIN TYPE_MIN(useconds_t)
+#endif
+
+#ifndef U_QUAD_MIN
+# define U_QUAD_MIN TYPE_MIN(u_quad_t)
+#endif
diff --git a/libsimple/env.h b/libsimple/env.h
new file mode 100644
index 0000000..1c10a75
--- /dev/null
+++ b/libsimple/env.h
@@ -0,0 +1,93 @@
+/* See LICENSE file for copyright and license details. */
+
+/**
+ * Read an environment variable, but handle it as undefined if empty
+ *
+ * @param var The environment variable's name
+ * @return The environment variable's value, `NULL` if empty or not defined
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
+static inline char *
+libsimple_getenv_ne(const char *__name)
+{
+ char *__env = getenv(__name);
+ return (__env && *__env) ? __env : NULL;
+}
+#ifndef getenv_ne
+# define getenv_ne libsimple_getenv_ne
+#endif
+
+/**
+ * Read an environment variable, but handle it as empty if undefined
+ *
+ * @param var The environment variable's name
+ * @return The environment variable's value, "" if empty or not defined
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline const char *
+libsimple_getenv_e(const char *__name)
+{
+ const char *__env = getenv(__name);
+ return (__env && *__env) ? __env : "";
+}
+#ifndef getenv_e
+# define getenv_e libsimple_getenv_e
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_vputenvf(const char *, va_list);
+#ifndef vputenvf
+# define vputenvf libsimple_vputenvf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 1, 2))))
+static inline int
+libsimple_putenvf(const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ return libsimple_vputenvf(__fmt, __ap);
+ va_end(__ap);
+}
+#ifndef putenvf
+# define putenvf libsimple_putenvf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+void libsimple_envputenvf(int, const char *, va_list);
+#ifndef envputenvf
+# define envputenvf libsimple_envputenvf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 2, 3))))
+static inline void
+libsimple_enputenvf(int __status, const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ libsimple_envputenvf(__status, __fmt, __ap);
+ va_end(__ap);
+}
+#ifndef enputenvf
+# define enputenvf libsimple_enputenvf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+static inline void libsimple_evputenvf(const char *__fmt, va_list __ap)
+{ libsimple_envputenvf(libsimple_default_failure_exit, __fmt, __ap); }
+#ifndef evputenvf
+# define evputenvf libsimple_evputenvf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __format__(__printf__, 1, 2))))
+static inline void
+libsimple_eputenvf(const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ libsimple_evputenvf(__fmt, __ap);
+ va_end(__ap);
+}
+#ifndef eputenvf
+# define eputenvf libsimple_eputenvf
+#endif
diff --git a/libsimple/malloc.h b/libsimple/malloc.h
new file mode 100644
index 0000000..feb1944
--- /dev/null
+++ b/libsimple/malloc.h
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_vmallocn(size_t __n, va_list __ap)
+{ return libsimple_vmalloczn(0, __n, __ap); }
+#ifndef vmallocn
+# define vmallocn libsimple_vmallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_mallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmalloczn(0, __n, __ap);
+ va_end(__ap);
+}
+#ifndef mallocn
+# define mallocn libsimple_mallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enmalloc(int, size_t);
+#ifndef enmalloc
+# define enmalloc libsimple_enmalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envmallocn(int __st, size_t __n, va_list __ap)
+{ return libsimple_envmalloczn(__st, 0, __n, __ap); }
+#ifndef envmallocn
+# define envmallocn libsimple_envmallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enmallocn(int __status, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envmallocn(__status, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enmallocn
+# define enmallocn libsimple_enmallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_emalloc(size_t __n)
+{ return libsimple_enmalloc(libsimple_default_failure_exit, __n); }
+#ifndef emalloc
+# define emalloc libsimple_emalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evmallocn(size_t __n, va_list __ap)
+{ return libsimple_envmallocn(libsimple_default_failure_exit, __n, __ap); }
+#ifndef evmallocn
+# define evmallocn libsimple_evmallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_emallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evmallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef emallocn
+# define emallocn libsimple_emallocn
+#endif
diff --git a/libsimple/mallocz.h b/libsimple/mallocz.h
new file mode 100644
index 0000000..80b2ef1
--- /dev/null
+++ b/libsimple/mallocz.h
@@ -0,0 +1,87 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2, 3), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_encalloc(int, size_t, size_t);
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enmalloc(int, size_t);
+
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+void *libsimple_vmalloczn(int, size_t, va_list);
+#ifndef vmalloczn
+# define vmalloczn libsimple_vmalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__)))
+static inline void *libsimple_mallocz(int __clear, size_t __n)
+{ return __clear ? calloc(1, __n) : malloc(__n); }
+#ifndef mallocz
+# define mallocz libsimple_mallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_malloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef malloczn
+# define malloczn libsimple_malloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_enmallocz(int __status, int __clear, size_t __n)
+{ return __clear ? libsimple_encalloc(__status, 1, __n) : libsimple_enmalloc(__status, __n); }
+#ifndef enmallocz
+# define enmallocz libsimple_enmallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_envmalloczn(int, int, size_t, va_list);
+#ifndef envmalloczn
+# define envmalloczn libsimple_envmalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enmalloczn(int __status, int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envmalloczn(__status, __clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enmalloczn
+# define enmalloczn libsimple_enmalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_emallocz(int __clear, size_t __n)
+{ return libsimple_enmallocz(libsimple_default_failure_exit, __clear, __n); }
+#ifndef emallocz
+# define emallocz libsimple_emallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evmalloczn(int __clear, size_t __n, va_list __ap)
+{ return libsimple_envmalloczn(libsimple_default_failure_exit, __clear, __n, __ap); }
+#ifndef evmalloczn
+# define evmalloczn libsimple_evmalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_emalloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evmalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef emalloczn
+# define emalloczn libsimple_emalloczn
+#endif
diff --git a/libsimple/mem.h b/libsimple/mem.h
new file mode 100644
index 0000000..37913d0
--- /dev/null
+++ b/libsimple/mem.h
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+void *libsimple_rawmemchr(const void *, int);
+#ifndef rawmemchr
+# define rawmemchr libsimple_rawmemchr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+void *libsimple_memrchr(const void *, int, size_t);
+#ifndef memrchr
+# define memrchr libsimple_memrchr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+void *libsimple_rawmemrchr(const void *, int, size_t);
+#ifndef rawmemrchr
+# define rawmemrchr libsimple_rawmemrchr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+void *libsimple_memmem(const void *, size_t, const void *, size_t);
+#ifndef memmem
+# define memmem libsimple_memmem
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+void *libsimple_memrmem(const void *, size_t, const void *, size_t);
+#ifndef memrmem
+# define memrmem libsimple_memrmem
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+int libsimple_memstarts(const void *, size_t, const void *, size_t);
+#ifndef memstarts
+# define memstarts libsimple_memstarts
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+int libsimple_memends(const void *, size_t, const void *, size_t);
+#ifndef memends
+# define memends libsimple_memends
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_memeq(const void *__s1, const void *__s2, size_t __n)
+{ return !memcmp(__s1, __s2, __n); }
+#ifndef memeq
+# define memeq libsimple_memeq
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__)))
+static inline void *libsimple_mempcpy(void *__d, const void *__s, size_t __n)
+{ return &((char *)memcpy(__d, __s, __n))[__n]; }
+#ifndef mempcpy
+# define mempcpy libsimple_mempcpy
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__)))
+static inline void *libsimple_mempset(void *__s, int __c, size_t __n)
+{ return &((char *)memset(__s, __c, __n))[__n]; }
+#ifndef mempset
+# define mempset libsimple_mempset
+#endif
diff --git a/libsimple/memalign.h b/libsimple/memalign.h
new file mode 100644
index 0000000..046edd4
--- /dev/null
+++ b/libsimple/memalign.h
@@ -0,0 +1,82 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__)))
+static inline void *libsimple_vmemalignn(size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_vmemalignzn(0, __alignment, __n, __ap); }
+#ifndef vmemalignn
+# define vmemalignn libsimple_vmemalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __alloc_size__(2), __warn_unused_result__)))
+static inline void *libsimple_memalign(size_t __alignment, size_t __n)
+{ return libsimple_memalignz(0, __alignment, __n); }
+#ifndef memalign
+# define memalign libsimple_memalign
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__)))
+static inline void *
+libsimple_memalignn(size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmemalignn(__alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef memalignn
+# define memalignn libsimple_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_enmemalign(int __status, size_t __alignment, size_t __n)
+{ return libsimple_enmemalignz(__status, 0, __alignment, __n); }
+#ifndef enmemalign
+# define enmemalign libsimple_enmemalign
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envmemalignn(int __status, size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envmemalignzn(__status, 0, __alignment, __n, __ap); }
+#ifndef envmemalignn
+# define envmemalignn libsimple_envmemalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enmemalignn(int __status, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envmemalignzn(__status, 0, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enmemalignn
+# define enmemalignn libsimple_enmemalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ememalign(size_t __alignment, size_t __n)
+{ return libsimple_enmemalign(libsimple_default_failure_exit, __alignment, __n); }
+#ifndef ememalign
+# define ememalign libsimple_ememalign
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evmemalignn(size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envmemalignn(libsimple_default_failure_exit, __alignment, __n, __ap); }
+#ifndef evmemalignn
+# define evmemalignn libsimple_evmemalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ememalignn(size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evmemalignn(__alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef ememalignn
+# define ememalignn libsimple_ememalignn
+#endif
diff --git a/libsimple/memalignz.h b/libsimple/memalignz.h
new file mode 100644
index 0000000..8a20295
--- /dev/null
+++ b/libsimple/memalignz.h
@@ -0,0 +1,123 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__)))
+static inline void *
+libsimple_vmemalignzn(int __clear, size_t __alignment, size_t __n, va_list __ap) /* TODO test ([v]memalign[z]n) */
+{
+ if (!__alignment || (__alignment & (__alignment - 1UL))) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return libsimple_memalloc(0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, __alignment,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef vmemalignzn
+# define vmemalignzn libsimple_vmemalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__)))
+static inline void *
+libsimple_memalignz(int __clear, size_t __alignment, size_t __n) /* TODO test (memalign[z]) */
+{
+ if (!__alignment || (__alignment & (__alignment - 1UL))) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return libsimple_memalloc(__n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, __alignment,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef memalignz
+# define memalignz libsimple_memalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__)))
+static inline void *
+libsimple_memalignzn(int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmemalignzn(__clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef memalignzn
+# define memalignzn libsimple_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __alloc_size__(4), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enmemalignz(int __status, int __clear, size_t __alignment, size_t __n) /* TODO test (e[n]memalign[z]) */
+{
+ if (!__alignment || (__alignment & (__alignment - 1UL))) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return libsimple_enmemalloc(__status, __n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, __alignment,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef enmemalignz
+# define enmemalignz libsimple_enmemalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envmemalignzn(int __status, int __clear, size_t __alignment, size_t __n, va_list __ap) /* TODO test (e[n][v]memalign[z]n) */
+{
+ if (!__alignment || (__alignment & (__alignment - 1UL))) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return libsimple_enmemalloc(__status,
+ 0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, __alignment,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef envmemalignzn
+# define envmemalignzn libsimple_envmemalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enmemalignzn(int __status, int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envmemalignzn(__status, __clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enmemalignzn
+# define enmemalignzn libsimple_enmemalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ememalignz(int __clear, size_t __alignment, size_t __n)
+{ return libsimple_enmemalignz(libsimple_default_failure_exit, __alignment, __clear, __n); }
+#ifndef ememalignz
+# define ememalignz libsimple_ememalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evmemalignzn(int __clear, size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_envmemalignzn(libsimple_default_failure_exit, __alignment, __clear, __n, __ap); }
+#ifndef evmemalignzn
+# define evmemalignzn libsimple_evmemalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ememalignzn(int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evmemalignzn(__clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef ememalignzn
+# define ememalignzn libsimple_ememalignzn
+#endif
diff --git a/libsimple/memalloc.h b/libsimple/memalloc.h
new file mode 100644
index 0000000..181bc72
--- /dev/null
+++ b/libsimple/memalloc.h
@@ -0,0 +1,113 @@
+/* See LICENSE file for copyright and license details. */
+
+enum libsimple_memalloc_option {
+ LIBSIMPLE_MEMALLOC_END,
+ LIBSIMPLE_MEMALLOC_ZERO_INIT,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT,
+ LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO,
+ LIBSIMPLE_MEMALLOC_NULL_IF_ZERO,
+ LIBSIMPLE_MEMALLOC_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ELEMENT_SIZE,
+ LIBSIMPLE_MEMALLOC_PRODUCT_SIZE,
+ LIBSIMPLE_MEMALLOC_VA_PRODUCT_SIZE,
+ LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE,
+ LIBSIMPLE_MEMALLOC_VA_LIST,
+};
+#define libsimple_arrayalloc_option libsimple_memalloc_option
+
+#define LIBSIMPLE_MEMALLOC_END LIBSIMPLE_MEMALLOC_END
+#define LIBSIMPLE_MEMALLOC_ZERO_INIT LIBSIMPLE_MEMALLOC_ZERO_INIT
+#define LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT
+#define LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO
+#define LIBSIMPLE_MEMALLOC_NULL_IF_ZERO LIBSIMPLE_MEMALLOC_NULL_IF_ZERO
+#define LIBSIMPLE_MEMALLOC_ALIGNMENT LIBSIMPLE_MEMALLOC_ALIGNMENT
+#define LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT
+#define LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT
+#define LIBSIMPLE_MEMALLOC_ELEMENT_SIZE LIBSIMPLE_MEMALLOC_ELEMENT_SIZE
+#define LIBSIMPLE_MEMALLOC_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_PRODUCT_SIZE
+#define LIBSIMPLE_MEMALLOC_VA_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_VA_PRODUCT_SIZE
+#define LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE
+#define LIBSIMPLE_MEMALLOC_VA_LIST LIBSIMPLE_MEMALLOC_VA_LIST
+
+#define LIBSIMPLE_ARRAYALLOC_END LIBSIMPLE_MEMALLOC_END
+#define LIBSIMPLE_ARRAYALLOC_ZERO_INIT LIBSIMPLE_MEMALLOC_ZERO_INIT
+#define LIBSIMPLE_ARRAYALLOC_CONDITIONAL_ZERO_INIT LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT
+#define LIBSIMPLE_ARRAYALLOC_UNIQUE_IF_ZERO LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO
+#define LIBSIMPLE_ARRAYALLOC_NULL_IF_ZERO LIBSIMPLE_MEMALLOC_NULL_IF_ZERO
+#define LIBSIMPLE_ARRAYALLOC_ROUND_UP_SIZE_TO_ALIGNMENT LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT
+#define LIBSIMPLE_ARRAYALLOC_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_PRODUCT_SIZE
+#define LIBSIMPLE_ARRAYALLOC_VA_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_VA_PRODUCT_SIZE
+#define LIBSIMPLE_ARRAYALLOC_1_VA_PRODUCT_SIZE LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE
+#define LIBSIMPLE_ARRAYALLOC_VA_LIST LIBSIMPLE_MEMALLOC_VA_LIST
+
+#define libsimple_varrayalloc(TYPE, N, AP)\
+ libsimple_memalloc(N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ LIBSIMPLE_MEMALLOC_VA_LIST, AP, LIBSIMPLE_MEMALLOC_END)
+
+#define libsimple_evarrayalloc(TYPE, N, AP)\
+ libsimple_ememalloc(N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ LIBSIMPLE_MEMALLOC_VA_LIST, AP, LIBSIMPLE_MEMALLOC_END)
+
+#define libsimple_envarrayalloc(STATUS, TYPE, N, AP)\
+ libsimple_enmemalloc(STATUS, N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ LIBSIMPLE_MEMALLOC_VA_LIST, AP, LIBSIMPLE_MEMALLOC_END)
+
+#define libsimple_arrayalloc(TYPE, N, ... /*, LIBSIMPLE_ARRAYALLOC_END */)\
+ libsimple_memalloc(N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ __VA_ARGS__)
+
+#define libsimple_earrayalloc(TYPE, N, ... /*, LIBSIMPLE_ARRAYALLOC_END */)\
+ libsimple_ememalloc(N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ __VA_ARGS__)
+
+#define libsimple_enarrayalloc(STATUS, TYPE, N, ... /*, LIBSIMPLE_ARRAYALLOC_END */)\
+ libsimple_enmemalloc(STATUS, N, LIBSIMPLE_MEMALLOC_ELEMENT_SIZE, sizeof(TYPE),\
+ LIBSIMPLE_MEMALLOC_ALIGNMENT, _Alignof(TYPE),\
+ __VA_ARGS__)
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+void *libsimple_vmemalloc(size_t, va_list);
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+void *libsimple_envmemalloc(int, size_t, va_list);
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_evmemalloc(size_t __n, va_list __ap)
+{ return libsimple_envmemalloc(libsimple_default_failure_exit, __n, __ap); }
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_memalloc(size_t __n, ... /*, LIBSIMPLE_MEMALLOC_END */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vmemalloc(__n, __ap);
+ va_end(__ap);
+}
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_enmemalloc(int __status, size_t __n, ... /*, LIBSIMPLE_MEMALLOC_END */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envmemalloc(__status, __n, __ap);
+ va_end(__ap);
+}
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_ememalloc(size_t __n, ... /*, LIBSIMPLE_MEMALLOC_END */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evmemalloc(__n, __ap);
+ va_end(__ap);
+}
diff --git a/libsimple/memdup.h b/libsimple/memdup.h
new file mode 100644
index 0000000..44d3a2a
--- /dev/null
+++ b/libsimple/memdup.h
@@ -0,0 +1,33 @@
+/* See LICENSE file for copyright and license details. */
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_memdupa(s, n)\
+ ({\
+ const char *__s = (s);\
+ size_t __n = (n);\
+ char *__r = alloca(__n);\
+ memcpy(__r, __s, __n);\
+ })
+# ifndef memdupa
+# define memdupa(s, n) libsimple_memdupa(s, n)
+# endif
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(2), __nonnull__, __warn_unused_result__)))
+void *libsimple_memdup(const void *, size_t);
+#ifndef memdup
+# define memdup libsimple_memdup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enmemdup(int, const void *, size_t);
+#ifndef enmemdup
+# define enmemdup libsimple_enmemdup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_ememdup(const void *__s, size_t __n)
+{ return enmemdup(libsimple_default_failure_exit, __s, __n); }
+#ifndef ememdup
+# define ememdup libsimple_ememdup
+#endif
diff --git a/libsimple/posix_memalign.h b/libsimple/posix_memalign.h
new file mode 100644
index 0000000..dfe7a53
--- /dev/null
+++ b/libsimple/posix_memalign.h
@@ -0,0 +1,75 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline int libsimple_vposix_memalignn(void **__memptr, size_t __alignment, size_t __n, va_list __ap)
+{ return libsimple_vposix_memalignzn(__memptr, 0, __alignment, __n, __ap); }
+#ifndef vposix_memalignn
+# define vposix_memalignn libsimple_vposix_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline int
+libsimple_posix_memalignn(void **__memptr, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vposix_memalignn(__memptr, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef posix_memalignn
+# define posix_memalignn libsimple_posix_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+static inline void libsimple_enposix_memalign(int __status, void **__memptr, size_t __alignment, size_t __n)
+{ libsimple_enposix_memalignz(__status, __memptr, 0, __alignment, __n); }
+#ifndef enposix_memalign
+# define enposix_memalign libsimple_enposix_memalign
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+static inline void libsimple_envposix_memalignn(int __status, void **__memptr, size_t __alignment, size_t __n, va_list __ap)
+{ libsimple_envposix_memalignzn(__status, __memptr, 0, __alignment, __n, __ap); }
+#ifndef envposix_memalignn
+# define envposix_memalignn libsimple_envposix_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+static inline void
+libsimple_enposix_memalignn(int __status, void **__memptr, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ libsimple_envposix_memalignzn(__status, __memptr, 0, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enposix_memalignn
+# define enposix_memalignn libsimple_enposix_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void libsimple_eposix_memalign(void **__memptr, size_t __alignment, size_t __n)
+{ libsimple_enposix_memalign(libsimple_default_failure_exit, __memptr, __alignment, __n); }
+#ifndef eposix_memalign
+# define eposix_memalign libsimple_eposix_memalign
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void libsimple_evposix_memalignn(void **__memptr, size_t __alignment, size_t __n, va_list __ap)
+{ libsimple_envposix_memalignn(libsimple_default_failure_exit, __memptr, __alignment, __n, __ap); }
+#ifndef evposix_memalignn
+# define evposix_memalignn libsimple_evposix_memalignn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void
+libsimple_eposix_memalignn(void **__memptr, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ libsimple_evposix_memalignn(__memptr, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef eposix_memalignn
+# define eposix_memalignn libsimple_eposix_memalignn
+#endif
diff --git a/libsimple/posix_memalignz.h b/libsimple/posix_memalignz.h
new file mode 100644
index 0000000..94fc82c
--- /dev/null
+++ b/libsimple/posix_memalignz.h
@@ -0,0 +1,85 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+int libsimple_vposix_memalignzn(void **, int, size_t, size_t, va_list);
+#ifndef vposix_memalignzn
+# define vposix_memalignzn libsimple_vposix_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline int
+libsimple_posix_memalignz(void **__memptr, int __clear, size_t __alignment, size_t __n)
+{
+ int __ret = posix_memalign(__memptr, __alignment, __n);
+ if (!__ret && __clear)
+ memset(*__memptr, 0, __n);
+ return __ret;
+}
+#ifndef posix_memalignz
+# define posix_memalignz libsimple_posix_memalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline int
+libsimple_posix_memalignzn(void **__memptr, int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vposix_memalignzn(__memptr, __clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef posix_memalignzn
+# define posix_memalignzn libsimple_posix_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+void libsimple_enposix_memalignz(int, void **, int, size_t, size_t);
+#ifndef enposix_memalignz
+# define enposix_memalignz libsimple_enposix_memalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+void libsimple_envposix_memalignzn(int, void **, int, size_t, size_t, va_list);
+#ifndef envposix_memalignzn
+# define envposix_memalignzn libsimple_envposix_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+static inline void
+libsimple_enposix_memalignzn(int __status, void **__memptr, int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ libsimple_envposix_memalignzn(__status, __memptr, __clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enposix_memalignzn
+# define enposix_memalignzn libsimple_enposix_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void libsimple_eposix_memalignz(void **__memptr, int __clear, size_t __alignment, size_t __n)
+{ libsimple_enposix_memalignz(libsimple_default_failure_exit, __memptr, __clear, __alignment, __n); }
+#ifndef eposix_memalignz
+# define eposix_memalignz libsimple_eposix_memalignz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void libsimple_evposix_memalignzn(void **__memptr, int __clear, size_t __alignment, size_t __n, va_list __ap)
+{ libsimple_envposix_memalignzn(libsimple_default_failure_exit, __memptr, __clear, __alignment, __n, __ap); }
+#ifndef evposix_memalignzn
+# define evposix_memalignzn libsimple_evposix_memalignzn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+static inline void
+libsimple_eposix_memalignzn(void **__memptr, int __clear, size_t __alignment, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ libsimple_evposix_memalignzn(__memptr, __clear, __alignment, __n, __ap);
+ va_end(__ap);
+}
+#ifndef eposix_memalignzn
+# define eposix_memalignzn libsimple_eposix_memalignzn
+#endif
diff --git a/libsimple/printf.h b/libsimple/printf.h
new file mode 100644
index 0000000..f1e0b0d
--- /dev/null
+++ b/libsimple/printf.h
@@ -0,0 +1,122 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2), __format__(__printf__, 2, 3))))
+int libsimple_asprintf(char **, const char *, ...);
+#ifndef asprintf
+# define asprintf libsimple_asprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
+int libsimple_vasprintf(char **, const char *, va_list);
+#ifndef vasprintf
+# define vasprintf libsimple_vasprintf
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_asprintfa(__fmt, ...)\
+ ({\
+ const char *__f = (__fmt);\
+ char *__ret = NULL;\
+ int __r = snprintf(NULL, 0, __f, __VA_ARGS__);\
+ if (__r >= 0) {\
+ __ret = alloca((size_t)__r + 1);\
+ sprintf(__ret, __f, __VA_ARGS__);\
+ }\
+ __ret;\
+ })
+# ifndef asprintfa
+# define asprintfa(...) libsimple_asprintfa(__VA_ARGS__)
+# endif
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_vasprintfa(__fmt, __ap)\
+ ({\
+ const char *__f = (__fmt);\
+ va_list __a1;\
+ va_list __a2;\
+ char *__ret = NULL;\
+ int __r;\
+ va_copy(__a1, __ap);\
+ va_copy(__a2, __a1);\
+ __r = vsnprintf(NULL, 0, __f, __a1);\
+ if (__r >= 0) {\
+ __ret = alloca((size_t)__r + 1);\
+ vsprintf(__ret, __f, __a2);\
+ }\
+ va_end(__a2);\
+ va_end(__a1);\
+ __ret;\
+ })
+# ifndef vasprintfa
+# define vasprintfa(fmt, ap) libsimple_vasprintfa(fmt, ap)
+# endif
+#endif
+
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1))))
+void libsimple_vweprintf(const char *, va_list);
+#ifndef vweprintf
+# define vweprintf libsimple_vweprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2))))
+static inline void
+libsimple_weprintf(const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ libsimple_vweprintf(__fmt, __ap);
+ va_end(__ap);
+}
+#ifndef weprintf
+# define weprintf libsimple_weprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2), __noreturn__)))
+static inline void
+libsimple_venprintf(int __status, const char *__fmt, va_list __ap)
+{
+ libsimple_vweprintf(__fmt, __ap);
+ exit(__status);
+}
+#ifndef venprintf
+# define venprintf libsimple_venprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2), __format__(__printf__, 2, 3), __noreturn__)))
+static inline void
+libsimple_enprintf(int __status, const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ libsimple_venprintf(__status, __fmt, __ap);
+ va_end(__ap);
+}
+#ifndef enprintf
+# define enprintf libsimple_enprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __noreturn__)))
+static inline void
+libsimple_veprintf(const char *__fmt, va_list __ap)
+{
+ libsimple_vweprintf(__fmt, __ap);
+ exit(libsimple_default_failure_exit);
+}
+#ifndef veprintf
+# define veprintf libsimple_veprintf
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1), __format__(__printf__, 1, 2), __noreturn__)))
+static inline void
+libsimple_eprintf(const char *__fmt, ...)
+{
+ va_list __ap;
+ va_start(__ap, __fmt);
+ libsimple_veprintf(__fmt, __ap);
+ va_end(__ap);
+}
+#ifndef eprintf
+# define eprintf libsimple_eprintf
+#endif
diff --git a/libsimple/pvalloc.h b/libsimple/pvalloc.h
new file mode 100644
index 0000000..876366b
--- /dev/null
+++ b/libsimple/pvalloc.h
@@ -0,0 +1,82 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_vpvallocn(size_t __n, va_list __ap)
+{ return libsimple_vpvalloczn(0, __n, __ap); }
+#ifndef vpvallocn
+# define vpvallocn libsimple_vpvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_pvalloc(size_t __n)
+{ return libsimple_pvallocz(0, __n); }
+#ifndef pvalloc
+# define pvalloc libsimple_pvalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_pvallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vpvallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef pvallocn
+# define pvallocn libsimple_pvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_enpvalloc(int __status, size_t __n)
+{ return libsimple_enpvallocz(__status, 0, __n); }
+#ifndef enpvalloc
+# define enpvalloc libsimple_enpvalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envpvallocn(int __status, size_t __n, va_list __ap)
+{ return libsimple_envpvalloczn(__status, 0, __n, __ap); }
+#ifndef envpvallocn
+# define envpvallocn libsimple_envpvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enpvallocn(int __status, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envpvalloczn(__status, 0, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enpvallocn
+# define enpvallocn libsimple_enpvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_epvalloc(size_t __n)
+{ return libsimple_enpvalloc(libsimple_default_failure_exit, __n); }
+#ifndef epvalloc
+# define epvalloc libsimple_epvalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evpvallocn(size_t __n, va_list __ap)
+{ return libsimple_envpvallocn(libsimple_default_failure_exit, __n, __ap); }
+#ifndef evpvallocn
+# define evpvallocn libsimple_evpvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_epvallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evpvallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef epvallocn
+# define epvallocn libsimple_epvallocn
+#endif
diff --git a/libsimple/pvallocz.h b/libsimple/pvallocz.h
new file mode 100644
index 0000000..f1e58ed
--- /dev/null
+++ b/libsimple/pvallocz.h
@@ -0,0 +1,111 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_vpvalloczn(int __clear, size_t __n, va_list __ap) /* TODO test ([v]pvalloc[z]n) */
+{
+ return libsimple_memalloc(0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef vpvalloczn
+# define vpvalloczn libsimple_vpvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__)))
+static inline void *
+libsimple_pvallocz(int __clear, size_t __n) /* TODO test (pvalloc[z]) */
+{
+ return libsimple_memalloc(__n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef pvallocz
+# define pvallocz libsimple_pvallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_pvalloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vpvalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef pvalloczn
+# define pvalloczn libsimple_pvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enpvallocz(int __status, int __clear, size_t __n) /* TODO test (e[n]pvalloc[z]) */
+{
+ return libsimple_enmemalloc(__status, __n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef enpvallocz
+# define enpvallocz libsimple_enpvallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envpvalloczn(int __status, int __clear, size_t __n, va_list __ap) /* TODO test (e[n][v]pvalloc[z]n) */
+{
+ return libsimple_enmemalloc(__status,
+ 0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef envpvalloczn
+# define envpvalloczn libsimple_envpvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enpvalloczn(int __status, int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envpvalloczn(__status, __clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enpvalloczn
+# define enpvalloczn libsimple_enpvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_epvallocz(int __clear, size_t __n)
+{ return libsimple_enpvallocz(libsimple_default_failure_exit, __clear, __n); }
+#ifndef epvallocz
+# define epvallocz libsimple_epvallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evpvalloczn(int __clear, size_t __n, va_list __ap)
+{ return libsimple_envpvalloczn(libsimple_default_failure_exit, __clear, __n, __ap); }
+#ifndef evpvalloczn
+# define evpvalloczn libsimple_evpvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_epvalloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evpvalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef epvalloczn
+# define epvalloczn libsimple_epvalloczn
+#endif
diff --git a/libsimple/realloc.h b/libsimple/realloc.h
new file mode 100644
index 0000000..3e2fece
--- /dev/null
+++ b/libsimple/realloc.h
@@ -0,0 +1,72 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__)))
+void *libsimple_vreallocn(void *, size_t, va_list);
+#ifndef vreallocn
+# define vreallocn libsimple_vreallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__)))
+static inline void *
+libsimple_reallocn(void *__ptr, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vreallocn(__ptr, __n, __ap);
+ va_end(__ap);
+}
+#ifndef reallocn
+# define reallocn libsimple_reallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+void *libsimple_enrealloc(int, void *, size_t);
+#ifndef enrealloc
+# define enrealloc libsimple_enrealloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__)))
+void *libsimple_envreallocn(int, void *, size_t, va_list);
+#ifndef envreallocn
+# define envreallocn libsimple_envreallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_enreallocn(int __status, void *__ptr, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envreallocn(__status, __ptr, __n, __ap);
+ va_end(__ap);
+}
+#ifndef enreallocn
+# define enreallocn libsimple_enreallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_erealloc(void *__ptr, size_t __n)
+{ return enrealloc(libsimple_default_failure_exit, __ptr, __n); }
+#ifndef erealloc
+# define erealloc libsimple_erealloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evreallocn(void *__ptr, size_t __n, va_list __ap)
+{ return libsimple_envreallocn(libsimple_default_failure_exit, __ptr, __n, __ap); }
+#ifndef evreallocn
+# define evreallocn libsimple_evreallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_ereallocn(void *__ptr, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evreallocn(__ptr, __n, __ap);
+ va_end(__ap);
+}
+#ifndef ereallocn
+# define ereallocn libsimple_ereallocn
+#endif
diff --git a/libsimple/str.h b/libsimple/str.h
new file mode 100644
index 0000000..cacec57
--- /dev/null
+++ b/libsimple/str.h
@@ -0,0 +1,99 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strchrnul(const char *, int);
+#ifndef strchrnul
+# define strchrnul libsimple_strchrnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline char *libsimple_strend(const char *__s)
+{ return strchr(__s, '\0'); }
+#ifndef strend
+# define strend libsimple_strend
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+int libsimple_strstarts(const char *, const char *);
+#ifndef strstarts
+# define strstarts libsimple_strstarts
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline int libsimple_strcasestarts(const char *__s, const char *__t)
+{ return !strncasecmp(__s, __t, strlen(__t)); }
+#ifndef strcasestarts
+# define strcasestarts libsimple_strcasestarts
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+int libsimple_strends(const char *, const char *);
+#ifndef strends
+# define strends libsimple_strends
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+int libsimple_strcaseends(const char *, const char *);
+#ifndef strcaseends
+# define strcaseends libsimple_strcaseends
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strrstr(const char *, const char *);
+#ifndef strrstr
+# define strrstr libsimple_strrstr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strcasestr(const char *, const char *);
+#ifndef strcasestr
+# define strcasestr libsimple_strcasestr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strrcasestr(const char *, const char *);
+#ifndef strrcasestr
+# define strrcasestr libsimple_strrcasestr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strcmpnul(const char *__a, const char *__b)
+{ return (!__a || !__b) ? !__b - !__a : strcmp(__a, __b); }
+#ifndef strcmpnul
+# define strcmpnul libsimple_strcmpnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strcasecmpnul(const char *__a, const char *__b)
+{ return (!__a || !__b) ? !__b - !__a : strcasecmp(__a, __b); }
+#ifndef strcasecmpnul
+# define strcasecmpnul libsimple_strcasecmpnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline int libsimple_streq(const char *__a, const char *__b)
+{ return !strcmp(__a, __b); }
+#ifndef streq
+# define streq libsimple_streq
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_streqnul(const char *__a, const char *__b)
+{ return !strcmpnul(__a, __b); }
+#ifndef streqnul
+# define streqnul libsimple_streqnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline int libsimple_strcaseeq(const char *__a, const char *__b)
+{ return !strcasecmp(__a, __b); }
+#ifndef strcaseeq
+# define strcaseeq libsimple_strcaseeq
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strcaseeqnul(const char *__a, const char *__b)
+{ return !strcasecmpnul(__a, __b); }
+#ifndef strcaseeqnul
+# define strcaseeqnul libsimple_strcaseeqnul
+#endif
diff --git a/libsimple/strdup.h b/libsimple/strdup.h
new file mode 100644
index 0000000..1397893
--- /dev/null
+++ b/libsimple/strdup.h
@@ -0,0 +1,27 @@
+/* See LICENSE file for copyright and license details. */
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_strdupa(s)\
+ ({\
+ const char *__s = (s);\
+ size_t __n = strlen(__s) + 1;\
+ char *__r = alloca(__n);\
+ memcpy(__r, __s, __n);\
+ })
+# ifndef strdupa
+# define strdupa(s) libsimple_strdupa(s)
+# endif
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __assume_aligned__(1), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+char *libsimple_enstrdup(int, const char *);
+#ifndef enstrdup
+# define enstrdup libsimple_enstrdup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __assume_aligned__(1), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline char *libsimple_estrdup(const char *__s)
+{ return enstrdup(libsimple_default_failure_exit, __s); }
+#ifndef estrdup
+# define estrdup libsimple_estrdup
+#endif
diff --git a/libsimple/strn.h b/libsimple/strn.h
new file mode 100644
index 0000000..e2dffdb
--- /dev/null
+++ b/libsimple/strn.h
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+
+/* TODO strnchrnul */
+/* TODO strnend */
+/* TODO strnstarts */
+/* TODO strncasestarts */
+/* TODO strnends */
+/* TODO strncaseends */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strnstr(const char *, const char *, size_t);
+#ifndef strnstr
+# define strnstr libsimple_strnstr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strrnstr(const char *, const char *, size_t);
+#ifndef strrnstr
+# define strrnstr libsimple_strrnstr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strncasestr(const char *, const char *, size_t);
+#ifndef strncasestr
+# define strncasestr libsimple_strncasestr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+char *libsimple_strrncasestr(const char *, const char *, size_t);
+#ifndef strrncasestr
+# define strrncasestr libsimple_strrncasestr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strncmpnul(const char *__a, const char *__b, size_t __n)
+{ return (!__a || !__b) ? !__b - !__a : strncmp(__a, __b, __n); }
+#ifndef strncmpnul
+# define strncmpnul libsimple_strncmpnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strncasecmpnul(const char *__a, const char *__b, size_t __n)
+{ return (!__a || !__b) ? !__b - !__a : strncasecmp(__a, __b, __n); }
+#ifndef strncasecmpnul
+# define strncasecmpnul libsimple_strncasecmpnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline int libsimple_strneq(const char *__a, const char *__b, size_t __n)
+{ return !strncmp(__a, __b, __n); }
+#ifndef strneq
+# define strneq libsimple_strneq
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strneqnul(const char *__a, const char *__b, size_t __n)
+{ return !strncmpnul(__a, __b, __n); }
+#ifndef strneqnul
+# define strneqnul libsimple_strneqnul
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
+static inline int libsimple_strncaseeq(const char *__a, const char *__b, size_t __n)
+{ return !strncasecmp(__a, __b, __n); }
+#ifndef strncaseeq
+# define strncaseeq libsimple_strncaseeq
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
+static inline int libsimple_strncaseeqnul(const char *__a, const char *__b, size_t __n)
+{ return !strncasecmpnul(__a, __b, __n); }
+#ifndef strncaseeqnul
+# define strncaseeqnul libsimple_strncaseeqnul
+#endif
diff --git a/libsimple/strndup.h b/libsimple/strndup.h
new file mode 100644
index 0000000..28ec293
--- /dev/null
+++ b/libsimple/strndup.h
@@ -0,0 +1,38 @@
+/* See LICENSE file for copyright and license details. */
+
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_strndupa(s, n)\
+ ({\
+ const char *__s = (s);\
+ size_t __n = (n);\
+ size_t __m = strlen(__s);\
+ char *__r;\
+ __n = __n < __m ? __n : __m;\
+ __r = alloca(__n + 1);\
+ memcpy(__r, __s, __n);\
+ __r[__n] = '\0';\
+ __r;\
+ })
+# ifndef strndupa
+# define strndupa(s, n) libsimple_strndupa(s, n)
+# endif
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __assume_aligned__(1), __nonnull__, __warn_unused_result__)))
+char *libsimple_strndup(const char *, size_t);
+#ifndef strndup
+# define strndup libsimple_strndup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __assume_aligned__(1), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+char *libsimple_enstrndup(int, const char *, size_t);
+#ifndef enstrndup
+# define enstrndup libsimple_enstrndup
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __assume_aligned__(1), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline char *libsimple_estrndup(const char *__s, size_t __n)
+{ return enstrndup(libsimple_default_failure_exit, __s, __n); }
+#ifndef estrndup
+# define estrndup libsimple_estrndup
+#endif
diff --git a/libsimple/time.h b/libsimple/time.h
new file mode 100644
index 0000000..7304030
--- /dev/null
+++ b/libsimple/time.h
@@ -0,0 +1,149 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_sumtimespec(struct timespec *, const struct timespec *, const struct timespec *);
+#ifndef sumtimespec
+# define sumtimespec libsimple_sumtimespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_difftimespec(struct timespec *, const struct timespec *, const struct timespec *);
+#ifndef difftimespec
+# define difftimespec libsimple_difftimespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_multimespec(struct timespec *, const struct timespec *, int);
+#ifndef multimespec
+# define multimespec libsimple_multimespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
+static inline int
+libsimple_cmptimespec(const struct timespec *__a, const struct timespec *__b)
+{
+ if (__a->tv_sec != __b->tv_sec)
+ return __a->tv_sec < __b->tv_sec ? -1 : +1;
+ return __a->tv_nsec < __b->tv_nsec ? -1 : __a->tv_nsec > __b->tv_nsec;
+}
+#ifndef cmptimespec
+# define cmptimespec libsimple_cmptimespec
+#endif
+
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_sumtimeval(struct timeval *, const struct timeval *, const struct timeval *);
+#ifndef sumtimeval
+# define sumtimeval libsimple_sumtimeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_difftimeval(struct timeval *, const struct timeval *, const struct timeval *);
+#ifndef difftimeval
+# define difftimeval libsimple_difftimeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_multimeval(struct timeval *, const struct timeval *, int);
+#ifndef multimeval
+# define multimeval libsimple_multimeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__)))
+static inline int
+libsimple_cmptimeval(const struct timeval *__a, const struct timeval *__b)
+{
+ if (__a->tv_sec != __b->tv_sec)
+ return __a->tv_sec < __b->tv_sec ? -1 : +1;
+ return __a->tv_usec < __b->tv_usec ? -1 : __a->tv_usec > __b->tv_usec;
+}
+#ifndef cmptimeval
+# define cmptimeval libsimple_cmptimeval
+#endif
+
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+static inline void
+libsimple_timeval2timespec(struct timespec *restrict __ts, const struct timeval *restrict __tv)
+{
+ __ts->tv_sec = __tv->tv_sec;
+ __ts->tv_nsec = __tv->tv_usec;
+ __ts->tv_nsec *= 1000L;
+}
+#ifndef timeval2timespec
+# define timeval2timespec libsimple_timeval2timespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+int libsimple_timespec2timeval(struct timeval *restrict, const struct timespec *restrict);
+#ifndef timespec2timeval
+# define timespec2timeval libsimple_timespec2timeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
+int libsimple_strtotimespec(struct timespec *restrict, const char *restrict, char **restrict);
+#ifndef strtotimespec
+# define strtotimespec libsimple_strtotimespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(1, 2))))
+int libsimple_strtotimeval(struct timeval *restrict, const char *restrict, char **restrict);
+#ifndef strtotimeval
+# define strtotimeval libsimple_strtotimeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+char *libsimple_timespectostr(char *restrict, const struct timespec *restrict);
+#ifndef timespectostr
+# define timespectostr libsimple_timespectostr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__(2))))
+char *libsimple_timevaltostr(char *restrict, const struct timeval *restrict);
+#ifndef timevaltostr
+# define timevaltostr libsimple_timevaltostr
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+static inline double
+libsimple_timespectodouble(const struct timespec *__ts)
+{
+ double __ret = (double)(__ts->tv_nsec);
+ __ret /= (double)1000000000L;
+ __ret += (double)(__ts->tv_sec);
+ return __ret;
+}
+#ifndef timespectodouble
+# define timespectodouble libsimple_timespectodouble
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+static inline double
+libsimple_timevaltodouble(const struct timeval *__tv)
+{
+ double __ret = (double)(__tv->tv_usec);
+ __ret /= (double)1000000L;
+ __ret += (double)(__tv->tv_sec);
+ return __ret;
+}
+#ifndef timevaltodouble
+# define timevaltodouble libsimple_timevaltodouble
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+void libsimple_doubletotimespec(struct timespec *, double);
+#ifndef doubletotimespec
+# define doubletotimespec libsimple_doubletotimespec
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__nonnull__)))
+void libsimple_doubletotimeval(struct timeval *, double);
+#ifndef doubletotimeval
+# define doubletotimeval libsimple_doubletotimeval
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__returns_nonnull__, __nonnull__)))
+char *libsimple_minimise_number_string(char *);
+#ifndef minimise_number_string
+# define minimise_number_string libsimple_minimise_number_string
+#endif
diff --git a/libsimple/valloc.h b/libsimple/valloc.h
new file mode 100644
index 0000000..02d301a
--- /dev/null
+++ b/libsimple/valloc.h
@@ -0,0 +1,82 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *libsimple_vvallocn(size_t __n, va_list __ap)
+{ return libsimple_vvalloczn(0, __n, __ap); }
+#ifndef vvallocn
+# define vvallocn libsimple_vvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(1), __warn_unused_result__)))
+static inline void *libsimple_valloc(size_t __n)
+{ return libsimple_vallocz(0, __n); }
+#ifndef valloc
+# define valloc libsimple_valloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_vallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vvallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef vallocn
+# define vallocn libsimple_vallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envalloc(int __status, size_t __n)
+{ return libsimple_envallocz(__status, 0, __n); }
+#ifndef envalloc
+# define envalloc libsimple_envalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_envvallocn(int __status, size_t __n, va_list __ap)
+{ return libsimple_envvalloczn(__status, 0, __n, __ap); }
+#ifndef envvallocn
+# define envvallocn libsimple_envvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envallocn(int __status, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envvalloczn(__status, 0, __n, __ap);
+ va_end(__ap);
+}
+#ifndef envallocn
+# define envallocn libsimple_envallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(1), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evalloc(size_t __n)
+{ return libsimple_envalloc(libsimple_default_failure_exit, __n); }
+#ifndef evalloc
+# define evalloc libsimple_evalloc
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evvallocn(size_t __n, va_list __ap)
+{ return libsimple_envvallocn(libsimple_default_failure_exit, __n, __ap); }
+#ifndef evvallocn
+# define evvallocn libsimple_evvallocn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_evallocn(size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evvallocn(__n, __ap);
+ va_end(__ap);
+}
+#ifndef evallocn
+# define evallocn libsimple_evallocn
+#endif
diff --git a/libsimple/vallocz.h b/libsimple/vallocz.h
new file mode 100644
index 0000000..d32598e
--- /dev/null
+++ b/libsimple/vallocz.h
@@ -0,0 +1,107 @@
+/* See LICENSE file for copyright and license details. */
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_vvalloczn(int __clear, size_t __n, va_list __ap) /* TODO test ([v]valloc[z]n) */
+{
+ return libsimple_memalloc(0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef vvalloczn
+# define vvalloczn libsimple_vvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__)))
+static inline void *
+libsimple_vallocz(int __clear, size_t __n) /* TODO test (valloc[z]) */
+{
+ return libsimple_memalloc(__n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef vallocz
+# define vallocz libsimple_vallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__)))
+static inline void *
+libsimple_valloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_vvalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef valloczn
+# define valloczn libsimple_valloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envallocz(int __status, int __clear, size_t __n) /* TODO test (e[n]valloc[z]) */
+{
+ return libsimple_enmemalloc(__status, __n,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef envallocz
+# define envallocz libsimple_envallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envvalloczn(int __status, int __clear, size_t __n, va_list __ap) /* TODO test (e[n][v]valloc[z]n, e[n]vallocn) */
+{
+ return libsimple_enmemalloc(__status,
+ 0, LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE, __n, __ap,
+ LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT, __clear,
+ LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT,
+ LIBSIMPLE_MEMALLOC_END);
+}
+#ifndef envvalloczn
+# define envvalloczn libsimple_envvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_envalloczn(int __status, int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_envvalloczn(__status, __clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef envalloczn
+# define envalloczn libsimple_envalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evallocz(int __clear, size_t __n)
+{ return libsimple_envallocz(libsimple_default_failure_exit, __clear, __n); }
+#ifndef evallocz
+# define evallocz libsimple_evallocz
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *libsimple_evvalloczn(int __clear, size_t __n, va_list __ap)
+{ return libsimple_envvalloczn(libsimple_default_failure_exit, __clear, __n, __ap); }
+#ifndef evvalloczn
+# define evvalloczn libsimple_evvalloczn
+#endif
+
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __warn_unused_result__, __returns_nonnull__)))
+static inline void *
+libsimple_evalloczn(int __clear, size_t __n, ... /*, (size_t)0 */)
+{
+ va_list __ap;
+ va_start(__ap, __n);
+ return libsimple_evvalloczn(__clear, __n, __ap);
+ va_end(__ap);
+}
+#ifndef evalloczn
+# define evalloczn libsimple_evalloczn
+#endif
diff --git a/strndup.c b/strndup.c
index faa3bb1..d4c681f 100644
--- a/strndup.c
+++ b/strndup.c
@@ -13,7 +13,7 @@ libsimple_strndup(const char *s, size_t n)
errno = ENOMEM;
return NULL;
}
- if (!(ret = malloc(n + 1)))
+ if (!(ret = aligned_alloc(1, n + 1)))
return NULL;
memcpy(ret, s, n);
ret[n] = '\0';
@@ -27,6 +27,7 @@ libsimple_strndup(const char *s, size_t n)
int
main(void)
{
+ struct allocinfo *info;
const char *s = "test";
void *p;
@@ -35,6 +36,10 @@ main(void)
assert(!strcmpnul(p, "test"));
memset(p, 0, 5);
assert(!strcmpnul(s, "test"));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(p)));
+ assert(info->alignment == 1);
+ }
free(p);
p = libsimple_strndup(s, 3);
@@ -42,6 +47,10 @@ main(void)
assert(!strcmpnul(p, "tes"));
memset(p, 0, 4);
assert(!strcmpnul(s, "test"));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(p)));
+ assert(info->alignment == 1);
+ }
free(p);
p = libsimple_strndup(s, 0);
@@ -49,6 +58,10 @@ main(void)
assert(!strcmpnul(p, ""));
memset(p, 0, 1);
assert(!strcmpnul(s, "test"));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(p)));
+ assert(info->alignment == 1);
+ }
free(p);
return 0;
diff --git a/test.c b/test.c
index 084359e..b954ccd 100644
--- a/test.c
+++ b/test.c
@@ -2,10 +2,12 @@
#include "libsimple.h"
#include "test.h"
#include <sys/syscall.h>
-#include <malloc.h>
#undef strndup
#undef memdup
+#undef memalign
+#undef valloc
+#undef pvalloc
char *argv0 = (char []){"<test>"};
@@ -21,6 +23,7 @@ volatile int stderr_real = 0;
volatile int stderr_ok = 0;
static volatile int custom_malloc = 0;
+static volatile void *just_alloced = NULL;
size_t
@@ -59,59 +62,6 @@ get_allocinfo(void *ptr)
void *
-malloc(size_t size)
-{
- size_t alignment = get_pagesize();
- while (alignment < sizeof(long long int))
- alignment *= 2;
- while (alignment < sizeof(long double))
- alignment *= 2;
- return memalign(alignment, size);
-}
-
-
-void *
-calloc(size_t nelem, size_t elsize)
-{
- struct allocinfo *info;
- void *volatile ret;
- assert(nelem && elsize); /* unspecified behaviour otherwise */
- if (nelem > SIZE_MAX / elsize) {
- errno = ENOMEM;
- return NULL;
- }
- ret = malloc(nelem * elsize);
- if (!ret)
- return NULL;
- memset(ret, 0, nelem * elsize);
- info = get_allocinfo(ret);
- info->zeroed = nelem * elsize;
- return ret;
-}
-
-
-void *
-realloc(void *ptr, size_t size)
-{
- struct allocinfo *info;
- void *volatile ret;
- size_t n;
- assert(size); /* unspecified behaviour otherwise */
- if (!ptr)
- return malloc(size);
- ret = malloc(size);
- if (!ret)
- return malloc;
- info = get_allocinfo(ret);
- n = MIN(size, info->size);
- info->zeroed = MIN(n, info->zeroed);
- memcpy(ret, ptr, n);
- free(ptr);
- return ret;
-}
-
-
-void *
memalign(size_t alignment, size_t size)
{
struct allocinfo *info;
@@ -156,14 +106,69 @@ memalign(size_t alignment, size_t size)
info->zeroed = 0;
info->refcount = 1;
+ just_alloced = ptr;
return ptr;
enomem:
+ just_alloced = NULL;
errno = ENOMEM;
return NULL;
}
+void *
+malloc(size_t size)
+{
+ size_t alignment = get_pagesize();
+ while (alignment < sizeof(long long int))
+ alignment *= 2;
+ while (alignment < sizeof(long double))
+ alignment *= 2;
+ return memalign(alignment, size);
+}
+
+
+void *
+calloc(size_t nelem, size_t elsize)
+{
+ struct allocinfo *info;
+ void *volatile ret;
+ assert(nelem && elsize); /* unspecified behaviour otherwise */
+ if (nelem > SIZE_MAX / elsize) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ ret = malloc(nelem * elsize);
+ if (!ret)
+ return NULL;
+ memset(ret, 0, nelem * elsize);
+ info = get_allocinfo(ret);
+ info->zeroed = nelem * elsize;
+ return ret;
+}
+
+
+void *
+realloc(void *ptr, size_t size)
+{
+ struct allocinfo *info;
+ void *volatile ret;
+ size_t n;
+ assert(size); /* unspecified behaviour otherwise */
+ if (!ptr)
+ return malloc(size);
+ ret = malloc(size);
+ if (!ret)
+ return malloc;
+ info = get_allocinfo(ret);
+ n = MIN(size, info->size);
+ info->zeroed = MIN(n, info->zeroed);
+ memcpy(ret, ptr, n);
+ free(ptr);
+ return ret;
+}
+
+
int
posix_memalign(void **memptr, size_t alignment, size_t size)
{
@@ -171,8 +176,9 @@ posix_memalign(void **memptr, size_t alignment, size_t size)
void *volatile *volatile ptrp = memptr;
assert(!(alignment % sizeof(void *)));
assert(ptrp);
+ errno = 0;
*memptr = memalign(alignment, size);
- ret = *memptr ? ENOMEM : 0;
+ ret = errno;
errno = saved_errno;
return ret;
}
@@ -237,6 +243,21 @@ free(void *ptr)
}
+void *
+memset(void *s, int c, size_t n)
+{
+ char *str = s;
+ struct allocinfo *info;
+ if (just_alloced && s == just_alloced) {
+ info = get_allocinfo(s);
+ info->zeroed = MAX(info->zeroed, n);
+ }
+ while (n--)
+ str[n] = (char)c;
+ return s;
+}
+
+
void
exit(int status)
{
diff --git a/vmemalloc.c b/vmemalloc.c
new file mode 100644
index 0000000..855d078
--- /dev/null
+++ b/vmemalloc.c
@@ -0,0 +1,232 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+struct memalloc_state {
+ int zero_init;
+ int if_zero;
+ int round_up_size;
+ int have_size;
+ size_t alignment;
+ size_t elem_size;
+ size_t size_prod;
+};
+
+static int
+vmemalloc_parse_size_prod(struct memalloc_state *state, size_t n, size_t arg, va_list ap)
+{
+ if (state->have_size++)
+ goto inval;
+ state->elem_size = arg;
+ if (n) {
+ for (n--; n--;) {
+ arg = va_arg(ap, size_t);
+ if (!state->elem_size)
+ continue;
+ if (arg > SIZE_MAX / state->elem_size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ state->elem_size *= arg;
+ }
+ } else {
+ if (!arg)
+ goto inval;
+ for (;;) {
+ arg = va_arg(ap, size_t);
+ if (!arg)
+ break;
+ if (arg > SIZE_MAX / state->elem_size) {
+ errno = ENOMEM;
+ return -1;
+ }
+ state->elem_size *= arg;
+ }
+ }
+
+ return 0;
+inval:
+ errno = EINVAL;
+ return -1;
+}
+
+static int
+vmemalloc_parse_args(struct memalloc_state *state, size_t n, va_list ap)
+{
+ enum libsimple_memalloc_option opt;
+ long int page_size;
+ va_list *subapp;
+ size_t arg;
+
+ for (;;) {
+ opt = va_arg(ap, enum libsimple_memalloc_option);
+ switch (opt) {
+ case LIBSIMPLE_MEMALLOC_END:
+ return 0;
+
+ case LIBSIMPLE_MEMALLOC_ZERO_INIT:
+ if (state->zero_init >= 0)
+ goto inval;
+ state->zero_init = 1;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_CONDITIONAL_ZERO_INIT:
+ if (state->zero_init >= 0)
+ goto inval;
+ state->zero_init = va_arg(ap, int);
+ state->zero_init = !!state->zero_init;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO:
+ case LIBSIMPLE_MEMALLOC_NULL_IF_ZERO:
+ if (state->if_zero >= 0)
+ goto inval;
+ state->if_zero = (opt == LIBSIMPLE_MEMALLOC_UNIQUE_IF_ZERO);
+ break;
+
+ case LIBSIMPLE_MEMALLOC_ALIGNMENT:
+ if (state->alignment)
+ goto inval;
+ state->alignment = va_arg(ap, size_t);
+ if (!state->alignment)
+ goto inval;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_PAGE_ALIGNMENT:
+ if (state->alignment)
+ goto inval;
+ page_size = sysconf(_SC_PAGESIZE);
+ if (page_size <= 0)
+ return -1;
+ state->alignment = (size_t)page_size;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_ROUND_UP_SIZE_TO_ALIGNMENT:
+ if (state->round_up_size++)
+ goto inval;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_ELEMENT_SIZE:
+ if (state->elem_size)
+ goto inval;
+ state->elem_size = va_arg(ap, size_t);
+ if (!state->elem_size)
+ goto inval;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_PRODUCT_SIZE:
+ arg = va_arg(ap, size_t);
+ if (vmemalloc_parse_size_prod(state, n, arg, ap))
+ return -1;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_VA_PRODUCT_SIZE:
+ subapp = va_arg(ap, va_list *);
+ arg = va_arg(*subapp, size_t);
+ if (vmemalloc_parse_size_prod(state, n, arg, *subapp))
+ return -1;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_1_VA_PRODUCT_SIZE:
+ arg = va_arg(ap, size_t);
+ subapp = va_arg(ap, va_list *);
+ if (vmemalloc_parse_size_prod(state, n, arg, *subapp))
+ return -1;
+ break;
+
+ case LIBSIMPLE_MEMALLOC_VA_LIST:
+ subapp = va_arg(ap, va_list *);
+ if (vmemalloc_parse_args(state, n, *subapp))
+ return -1;
+ break;
+
+ default:
+ goto inval;
+ }
+ }
+
+ return 0;
+inval:
+ errno = EINVAL;
+ return -1;
+}
+
+void *
+libsimple_vmemalloc(size_t n, va_list ap) /* TODO test ([v]{mem,array}alloc) */
+{
+ struct memalloc_state state;
+ size_t misalignment, size;
+ void *ptr = NULL;
+ int saved_errno;
+
+ state.zero_init = -1;
+ state.if_zero = -1;
+ state.round_up_size = 0;
+ state.have_size = 0;
+ state.alignment = 0;
+ state.elem_size = 0;
+ state.size_prod = 1;
+
+ if (vmemalloc_parse_args(&state, n, ap))
+ return NULL;
+
+ state.elem_size = state.elem_size ? state.elem_size : 1;
+ state.zero_init = state.zero_init >= 0 ? state.zero_init : 0;
+ n = state.have_size ? state.size_prod : n;
+ if (state.elem_size > 1) {
+ if (n > SIZE_MAX / state.elem_size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ n *= state.elem_size;
+ }
+ if (state.round_up_size) {
+ if (!state.alignment) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if ((misalignment = n % state.alignment))
+ n += state.alignment - misalignment;
+ }
+ if (!n && state.if_zero == 0)
+ return NULL;
+ n = n ? n : (state.if_zero > 0);
+
+ saved_errno = errno;
+ errno = 0;
+ if (state.alignment) {
+ if (state.alignment % sizeof(void *)) {
+ size = n;
+ if ((misalignment = size % state.alignment))
+ size += state.alignment - misalignment;
+ ptr = aligned_alloc(state.alignment, size);
+ } else {
+ errno = posix_memalign(&ptr, state.alignment, n);
+ }
+ if (ptr && state.zero_init)
+ memset(ptr, 0, n);
+ } else {
+ ptr = state.zero_init ? calloc(n, 1) : malloc(n);
+ }
+ if (!ptr && n) {
+ if (!errno)
+ errno = ENOMEM;
+ return NULL;
+ }
+ errno = errno ? errno : saved_errno;
+
+ return ptr;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif