aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--aligned_strndup.c29
-rw-r--r--enaligned_strdup.c64
-rw-r--r--enaligned_strndup.c134
-rw-r--r--libsimple.h6
-rw-r--r--libsimple/aligned_strdup.h74
-rw-r--r--libsimple/aligned_strndup.h78
7 files changed, 388 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 90e7363..6bb1c38 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,8 @@ SUBHDR =\
libsimple/aligned_alloc.h\
libsimple/aligned_allocz.h\
libsimple/aligned_memdup.h\
+ libsimple/aligned_strdup.h\
+ libsimple/aligned_strndup.h\
libsimple/array.h\
libsimple/calloc.h\
libsimple/definitions.h\
@@ -40,6 +42,7 @@ HDR =\
OBJ =\
aligned_memdup.o\
+ aligned_strndup.o\
allocn.o\
asprintf.o\
difftimespec.o\
@@ -48,6 +51,8 @@ OBJ =\
doubletotimeval.o\
enaligned_allocz.o\
enaligned_memdup.o\
+ enaligned_strdup.o\
+ enaligned_strndup.o\
encalloc.o\
enmalloc.o\
enmemdup.o\
diff --git a/aligned_strndup.c b/aligned_strndup.c
new file mode 100644
index 0000000..a714387
--- /dev/null
+++ b/aligned_strndup.c
@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+char *
+libsimple_aligned_strndup(const char *s, size_t alignment, size_t n) /* TODO test */
+{
+ char *ret;
+ n = strnlen(s, n);
+ ret = aligned_alloc(alignment, (n + 1) + (alignment - (n + 1) % alignment) % alignment);
+ if (!ret)
+ return NULL;
+ memcpy(ret, s, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enaligned_strdup.c b/enaligned_strdup.c
new file mode 100644
index 0000000..6390ab0
--- /dev/null
+++ b/enaligned_strdup.c
@@ -0,0 +1,64 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+char *
+libsimple_enaligned_strdup(int status, const char *s, size_t alignment)
+{
+ void *ret = aligned_strdup(s, alignment);
+ if (!ret)
+ enprintf(status, "aligned_strdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *s;
+
+ assert((s = libsimple_enaligned_strdup(1, "hello", 2)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 6));
+ free(s);
+
+ assert((s = libsimple_ealigned_strdup("test", 8)));
+ 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_strdup(44, "hello", 2));
+ assert(exit_status == 44);
+ assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 55;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_strdup("test", 8));
+ assert(exit_status == 55);
+ assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/enaligned_strndup.c b/enaligned_strndup.c
new file mode 100644
index 0000000..7778cb2
--- /dev/null
+++ b/enaligned_strndup.c
@@ -0,0 +1,134 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+char *
+libsimple_enaligned_strndup(int status, const char *s, size_t alignment, size_t n)
+{
+ void *ret = aligned_strndup(s, alignment, n);
+ if (!ret)
+ enprintf(status, "aligned_strdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ struct allocinfo *info;
+ void *s;
+
+ assert((s = libsimple_enaligned_strndup(1, "hello", 2, SIZE_MAX)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 6));
+ free(s);
+
+ assert((s = libsimple_ealigned_strndup("test", 8, SIZE_MAX)));
+ 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);
+
+ assert((s = libsimple_enaligned_strndup(1, "hello", 2, 100)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 6));
+ free(s);
+
+ assert((s = libsimple_ealigned_strndup("test", 8, 100)));
+ 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);
+
+ assert((s = libsimple_enaligned_strndup(1, "hello", 2, 6)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hello", 6));
+ free(s);
+
+ assert((s = libsimple_ealigned_strndup("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);
+
+ assert((s = libsimple_enaligned_strndup(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", 6));
+ free(s);
+
+ assert((s = libsimple_ealigned_strndup("test", 8, 4)));
+ 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);
+
+ assert((s = libsimple_enaligned_strndup(1, "hello", 2, 4)));
+ if (have_custom_malloc()) {
+ assert((info = get_allocinfo(s)));
+ assert(info->size == 6);
+ assert(info->alignment == 2);
+ assert(!info->zeroed);
+ }
+ assert(!memcmp(s, "hell", 5));
+ free(s);
+
+ if (have_custom_malloc()) {
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_enaligned_strndup(44, "hello", 2, 10));
+ assert(exit_status == 44);
+ assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+
+ libsimple_default_failure_exit = 55;
+ alloc_fail_in = 1;
+ assert_exit_ptr(libsimple_ealigned_strndup("test", 8, 10));
+ assert(exit_status == 55);
+ assert_stderr("%s: aligned_strdup: %s\n", argv0, strerror(ENOMEM));
+ assert(!alloc_fail_in);
+ libsimple_default_failure_exit = 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/libsimple.h b/libsimple.h
index f2dd4b9..22b0cca 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -51,10 +51,12 @@
#include "libsimple/printf.h"
#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/strdup.h"
+#include "libsimple/aligned_strdup.h"
+#include "libsimple/strndup.h"
+#include "libsimple/aligned_strndup.h"
#include "libsimple/mallocz.h"
#include "libsimple/malloc.h"
#include "libsimple/calloc.h"
diff --git a/libsimple/aligned_strdup.h b/libsimple/aligned_strdup.h
new file mode 100644
index 0000000..6dc3bfa
--- /dev/null
+++ b/libsimple/aligned_strdup.h
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `aligned_strdup`
+ *
+ * @param s:const char * The string to copy
+ * @param alignment:size_t The alignment of the returned pointer
+ * @return :char * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_strdupa(s, alignment) /* TODO test, man */\
+ ({\
+ const char *__s = (s);\
+ size_t __n = strlen(__s) + 1;\
+ 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_strdupa
+# define aligned_strdupa(s, alignment) libsimple_aligned_strdupa(s, alignment)
+# endif
+#endif
+
+
+/**
+ * Version of strdup(3) that returns a pointer with a custom alignment
+ *
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @return Duplicate of `s`, `NULL` on failure
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__)))
+static inline char *libsimple_aligned_strdup(const char * __s, size_t __alignment) /* TODO test, man */
+{ return libsimple_aligned_memdup(__s, __alignment, strlen(__s) + 1); }
+#ifndef aligned_strdup
+# define aligned_strdup libsimple_aligned_strdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_strdup` that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+char *libsimple_enaligned_strdup(int, const char *, size_t); /* TODO man */
+#ifndef enaligned_strdup
+# define enaligned_strdup libsimple_enaligned_strdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_strdup` that calls `libsimple_eprintf` on error
+ *
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline char *libsimple_ealigned_strdup(const char *__s, size_t __alignment) /* TODO man */
+{ return enaligned_strdup(libsimple_default_failure_exit, __s, __alignment); }
+#ifndef ealigned_strdup
+# define ealigned_strdup libsimple_ealigned_strdup
+#endif
diff --git a/libsimple/aligned_strndup.h b/libsimple/aligned_strndup.h
new file mode 100644
index 0000000..cf41ae1
--- /dev/null
+++ b/libsimple/aligned_strndup.h
@@ -0,0 +1,78 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_aligned_strndup`
+ *
+ * @param s:const char * The string to copy
+ * @param alignment:size_t The alignment of the returned pointer
+ * @param n:size_t The maximum number of bytes to copy
+ * @return :char * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_strndupa(s, alignment, n) /* TODO test, man */\
+ ({\
+ const char *__s = (s);\
+ size_t __n = strnlen(__s, n);\
+ size_t __a = (alignment);\
+ uintptr_t __misalignment;\
+ char *__r;\
+ __r = alloca(__n + (__a - 1));\
+ __misalignment = (uintptr_t)__r % (uintptr_t)__a;\
+ if (__misalignment)\
+ __r += (uintptr_t)__a - __misalignment;\
+ memcpy(__r, __s, __n);\
+ __r[__n] = '\0';\
+ __r;\
+ })
+# ifndef aligned_strndupa
+# define aligned_strndupa(s, alignment, n) libsimple_aligned_strndupa(s, alignment, n)
+# endif
+#endif
+
+
+/**
+ * Version of strndup(3) that returns a pointer with a custom alignment
+ *
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The maximum number of bytes to copy
+ * @return Duplicate of `s`, `NULL` on failure
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__)))
+char *libsimple_aligned_strndup(const char * __s, size_t __alignment, size_t __n); /* TODO man */
+#ifndef aligned_strndup
+# define aligned_strndup libsimple_aligned_strndup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_strndup` that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The maximum number of bytes to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+char *libsimple_enaligned_strndup(int, const char *, size_t, size_t); /* TODO man */
+#ifndef enaligned_strndup
+# define enaligned_strndup libsimple_enaligned_strndup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_strndup` that calls `libsimple_eprintf` on error
+ *
+ * @param s The string to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The maximum number of bytes to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline char *libsimple_ealigned_strndup(const char *__s, size_t __alignment, size_t __n) /* TODO man */
+{ return enaligned_strndup(libsimple_default_failure_exit, __s, __alignment, __n); }
+#ifndef ealigned_strndup
+# define ealigned_strndup libsimple_ealigned_strndup
+#endif