aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2018-11-25 23:05:59 +0100
committerMattias Andrée <maandree@kth.se>2018-11-25 23:06:03 +0100
commitd8ccc87fed8a4c588e4ad9279e62925f416d36b3 (patch)
treef02a2138183c53ab95ef96dafeba75ebd9c0c422
parentInclude wchar.h and wctype.h (diff)
downloadlibsimple-d8ccc87fed8a4c588e4ad9279e62925f416d36b3.tar.gz
libsimple-d8ccc87fed8a4c588e4ad9279e62925f416d36b3.tar.bz2
libsimple-d8ccc87fed8a4c588e4ad9279e62925f416d36b3.tar.xz
Some fixes and add wide-character string duplication functions
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r--Makefile8
-rw-r--r--aligned_enmemdup.c64
-rw-r--r--aligned_memdup.c4
-rw-r--r--aligned_wcsndup.c34
-rw-r--r--aligned_wmemdup.c32
-rw-r--r--enaligned_wcsdup.c25
-rw-r--r--enaligned_wcsndup.c25
-rw-r--r--enaligned_wmemdup.c25
-rw-r--r--enwcsdup.c32
-rw-r--r--enwcsndup.c25
-rw-r--r--enwmemdup.c25
-rw-r--r--libsimple.h6
-rw-r--r--libsimple/aligned_memdup.h6
-rw-r--r--libsimple/aligned_strdup.h4
-rw-r--r--libsimple/aligned_strndup.h5
-rw-r--r--libsimple/aligned_wcsdup.h74
-rw-r--r--libsimple/aligned_wcsndup.h79
-rw-r--r--libsimple/aligned_wmemdup.h79
-rw-r--r--libsimple/memdup.h4
-rw-r--r--libsimple/str.h8
-rw-r--r--libsimple/strdup.h2
-rw-r--r--libsimple/strn.h6
-rw-r--r--libsimple/strndup.h2
-rw-r--r--libsimple/wcsdup.h49
-rw-r--r--libsimple/wcsndup.h69
-rw-r--r--libsimple/wmemdup.h66
-rw-r--r--memdup.c2
-rw-r--r--test.c28
-rw-r--r--wcsndup.c33
-rw-r--r--wmemdup.c31
30 files changed, 767 insertions, 85 deletions
diff --git a/Makefile b/Makefile
index 6bb1c38..1111419 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,9 @@ SUBHDR =\
libsimple/aligned_memdup.h\
libsimple/aligned_strdup.h\
libsimple/aligned_strndup.h\
+ libsimple/aligned_wcsdup.h\
+ libsimple/aligned_wcsndup.h\
+ libsimple/aligned_wmemdup.h\
libsimple/array.h\
libsimple/calloc.h\
libsimple/definitions.h\
@@ -34,7 +37,10 @@ SUBHDR =\
libsimple/strndup.h\
libsimple/time.h\
libsimple/valloc.h\
- libsimple/vallocz.h
+ libsimple/vallocz.h\
+ libsimple/wcsdup.h\
+ libsimple/wcsndup.h\
+ libsimple/wmemdup.h
HDR =\
$(SUBHDR)\
diff --git a/aligned_enmemdup.c b/aligned_enmemdup.c
deleted file mode 100644
index fced863..0000000
--- a/aligned_enmemdup.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* 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
index d66a846..ec06c38 100644
--- a/aligned_memdup.c
+++ b/aligned_memdup.c
@@ -6,9 +6,9 @@
void *
libsimple_aligned_memdup(const void *s, size_t alignment, size_t n)
{
+ size_t size = n + (alignment - n % alignment) % alignment;
void *ret;
- n = n ? n : 1;
- ret = aligned_alloc(alignment, n + (alignment - n % alignment) % alignment);
+ ret = aligned_alloc(alignment, size ? size : alignment);
if (!ret)
return NULL;
return memcpy(ret, s, n);
diff --git a/aligned_wcsndup.c b/aligned_wcsndup.c
new file mode 100644
index 0000000..f3fbf23
--- /dev/null
+++ b/aligned_wcsndup.c
@@ -0,0 +1,34 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_aligned_wcsndup(const wchar_t *s, size_t alignment, size_t n)
+{
+ size_t size;
+ void *ret;
+ if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n + 1, sizeof(wchar_t), &size, SIZE_MAX)) {
+ errno = ENOMEM;
+ enprintf(status, "wcsdup:");
+ }
+ size = size + (alignment - size % alignment) % alignment;
+ ret = aligned_alloc(alignment, size);
+ if (!ret)
+ return NULL;
+ wmemcpy(ret, s, n);
+ ret[n] = 0;
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/aligned_wmemdup.c b/aligned_wmemdup.c
new file mode 100644
index 0000000..bda654d
--- /dev/null
+++ b/aligned_wmemdup.c
@@ -0,0 +1,32 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_aligned_wmemdup(const wchar_t *s, size_t alignment, size_t n)
+{
+ size_t size;
+ void *ret;
+ if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n, sizeof(wchar_t), &size, SIZE_MAX)) {
+ errno = ENOMEM;
+ enprintf(status, "wcsdup:");
+ }
+ size = size + (alignment - size % alignment) % alignment;
+ ret = aligned_alloc(alignment, size ? size : alignment);
+ if (!ret)
+ return NULL;
+ return wmemcpy(ret, s, n);
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enaligned_wcsdup.c b/enaligned_wcsdup.c
new file mode 100644
index 0000000..17d0a4c
--- /dev/null
+++ b/enaligned_wcsdup.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enaligned_wcsdup(int status, const wchar_t *s, size_t alignment) /* TOOD test */
+{
+ void *ret = aligned_wcsdup(s, alignment);
+ if (!ret)
+ enprintf(status, "aligned_wcsdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enaligned_wcsndup.c b/enaligned_wcsndup.c
new file mode 100644
index 0000000..9b1aae8
--- /dev/null
+++ b/enaligned_wcsndup.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enaligned_wcsndup(int status, const wchar_t *s, size_t alignment, size_t n) /* TOOD test */
+{
+ void *ret = aligned_wcsndup(s, alignment, n);
+ if (!ret)
+ enprintf(status, "aligned_wcsndup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enaligned_wmemdup.c b/enaligned_wmemdup.c
new file mode 100644
index 0000000..e55e863
--- /dev/null
+++ b/enaligned_wmemdup.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enaligned_wmemdup(int status, const wchar_t *s, size_t alignment, size_t n) /* TOOD test */
+{
+ void *ret = aligned_wmemdup(s, alignment, n);
+ if (!ret)
+ enprintf(status, "aligned_wmemdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enwcsdup.c b/enwcsdup.c
new file mode 100644
index 0000000..d9edbb0
--- /dev/null
+++ b/enwcsdup.c
@@ -0,0 +1,32 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enwcsdup(int status, const wchar_t *s) /* TODO test */
+{
+ size_t n = wcslen(s) + 1, size;
+ wchar_t *ret;
+ if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n, sizeof(wchar_t), &size, SIZE_MAX)) {
+ errno = ENOMEM;
+ enprintf(status, "wcsdup:");
+ }
+ ret = aligned_alloc(_Alignof(wchar_t), size);
+ if (!ret)
+ enprintf(status, "wcsdup:");
+ wmemcpy(ret, s, n);
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enwcsndup.c b/enwcsndup.c
new file mode 100644
index 0000000..551311d
--- /dev/null
+++ b/enwcsndup.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enwcsndup(int status, const wchar_t *s, size_t n) /* TODO test */
+{
+ wchar_t *ret = wcsndup(s, n);
+ if (!ret)
+ enprintf(status, "wcsndup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/enwmemdup.c b/enwmemdup.c
new file mode 100644
index 0000000..8f99007
--- /dev/null
+++ b/enwmemdup.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_enwmemdup(int status, const wchar_t *s, size_t n) /* TODO test */
+{
+ wchar_t *ret = wmemdup(s, n);
+ if (!ret)
+ enprintf(status, "wmemdup:");
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/libsimple.h b/libsimple.h
index bdaefa7..941d864 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -59,6 +59,12 @@
#include "libsimple/aligned_strdup.h"
#include "libsimple/strndup.h"
#include "libsimple/aligned_strndup.h"
+#include "libsimple/wmemdup.h"
+#include "libsimple/aligned_wmemdup.h"
+#include "libsimple/wcsdup.h"
+#include "libsimple/aligned_wcsdup.h"
+#include "libsimple/wcsndup.h"
+#include "libsimple/aligned_wcsndup.h"
#include "libsimple/mallocz.h"
#include "libsimple/malloc.h"
#include "libsimple/calloc.h"
diff --git a/libsimple/aligned_memdup.h b/libsimple/aligned_memdup.h
index d2fa91f..0192a14 100644
--- a/libsimple/aligned_memdup.h
+++ b/libsimple/aligned_memdup.h
@@ -15,10 +15,12 @@
const char *__s = (s);\
size_t __n = (n);\
size_t __a = (alignment);\
+ size_t __size;\
uintptr_t __misalignment;\
char *__r;\
__a += !__a;\
- __r = alloca(__n + (__a - 1));\
+ __size = __n + (__a - 1);\
+ __r = alloca(__size + !__size);\
__misalignment = (uintptr_t)__r % (uintptr_t)__a;\
if (__misalignment)\
__r += (uintptr_t)__a - __misalignment;\
@@ -71,7 +73,7 @@ void *libsimple_enaligned_memdup(int, const void *, size_t, size_t);
*/
_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); }
+{ return libsimple_enaligned_memdup(libsimple_default_failure_exit, __s, __alignment, __n); }
#ifndef ealigned_memdup
# define ealigned_memdup libsimple_ealigned_memdup
#endif
diff --git a/libsimple/aligned_strdup.h b/libsimple/aligned_strdup.h
index 6dc3bfa..514a4da 100644
--- a/libsimple/aligned_strdup.h
+++ b/libsimple/aligned_strdup.h
@@ -2,7 +2,7 @@
/**
- * Stack allocation version of `aligned_strdup`
+ * Stack allocation version of `libsimple_aligned_strdup`
*
* @param s:const char * The string to copy
* @param alignment:size_t The alignment of the returned pointer
@@ -68,7 +68,7 @@ char *libsimple_enaligned_strdup(int, const char *, size_t); /* TODO man */
*/
_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); }
+{ return libsimple_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
index cf41ae1..c51b351 100644
--- a/libsimple/aligned_strndup.h
+++ b/libsimple/aligned_strndup.h
@@ -17,7 +17,8 @@
size_t __a = (alignment);\
uintptr_t __misalignment;\
char *__r;\
- __r = alloca(__n + (__a - 1));\
+ __a += !__a;\
+ __r = alloca(__n + 1 + (__a - 1));\
__misalignment = (uintptr_t)__r % (uintptr_t)__a;\
if (__misalignment)\
__r += (uintptr_t)__a - __misalignment;\
@@ -72,7 +73,7 @@ char *libsimple_enaligned_strndup(int, const char *, size_t, size_t); /* TODO ma
*/
_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); }
+{ return libsimple_enaligned_strndup(libsimple_default_failure_exit, __s, __alignment, __n); }
#ifndef ealigned_strndup
# define ealigned_strndup libsimple_ealigned_strndup
#endif
diff --git a/libsimple/aligned_wcsdup.h b/libsimple/aligned_wcsdup.h
new file mode 100644
index 0000000..3d5e96b
--- /dev/null
+++ b/libsimple/aligned_wcsdup.h
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_aligned_wcsdup`
+ *
+ * @param s:const wchar_t * The string to copy
+ * @param alignment:size_t The alignment of the returned pointer
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_wcsdupa(s, alignment) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = wcslen(__s) + 1;\
+ size_t __a = (alignment);\
+ uintptr_t __misalignment;\
+ char *__r;\
+ __a += !__a;\
+ __r = alloca(__n * sizeof(wchar_t) + (__a - 1));\
+ __misalignment = (uintptr_t)__r % (uintptr_t)__a;\
+ if (__misalignment)\
+ __r += (uintptr_t)__a - __misalignment;\
+ wmemcpy(__r, __s, __n);\
+ })
+# ifndef aligned_wcsdupa
+# define aligned_wcsdupa(s, alignment) libsimple_aligned_wcsdupa(s, alignment)
+# endif
+#endif
+
+
+/**
+ * Version of wcsdup(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 wchar_t *libsimple_aligned_wcsdup(const wchar_t * __s, size_t __alignment) /* TODO test, man */
+{ return libsimple_aligned_wmemdup(__s, __alignment, wcslen(__s) + 1); }
+#ifndef aligned_wcsdup
+# define aligned_wcsdup libsimple_aligned_wcsdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wcsdup` 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__)))
+wchar_t *libsimple_enaligned_wcsdup(int, const wchar_t *, size_t); /* TODO man */
+#ifndef enaligned_wcsdup
+# define enaligned_wcsdup libsimple_enaligned_wcsdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wcsdup` 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 wchar_t *libsimple_ealigned_wcsdup(const wchar_t *__s, size_t __alignment) /* TODO test, man */
+{ return libsimple_enaligned_wcsdup(libsimple_default_failure_exit, __s, __alignment); }
+#ifndef ealigned_wcsdup
+# define ealigned_wcsdup libsimple_ealigned_wcsdup
+#endif
diff --git a/libsimple/aligned_wcsndup.h b/libsimple/aligned_wcsndup.h
new file mode 100644
index 0000000..3378181
--- /dev/null
+++ b/libsimple/aligned_wcsndup.h
@@ -0,0 +1,79 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_aligned_wcsndup`
+ *
+ * @param s:const wchar_t * The string to copy
+ * @param alignment:size_t The alignment of the returned pointer
+ * @param n:size_t The maximum number of wide characters to copy
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_wcsndupa(s, alignment, n) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = wcsnlen(__s, n);\
+ size_t __a = (alignment);\
+ uintptr_t __misalignment;\
+ wchar_t *__r;\
+ __a += !__a;\
+ __r = alloca((__n + 1) * sizeof(wchar_t) + (__a - 1));\
+ __misalignment = (uintptr_t)__r % (uintptr_t)__a;\
+ if (__misalignment)\
+ __r += (uintptr_t)__a - __misalignment;\
+ wmemcpy(__r, __s, __n);\
+ __r[__n] = '\0';\
+ __r;\
+ })
+# ifndef aligned_wcsndupa
+# define aligned_wcsndupa(s, alignment, n) libsimple_aligned_wcsndupa(s, alignment, n)
+# endif
+#endif
+
+
+/**
+ * Version of wcsndup(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 wide characters to copy
+ * @return Duplicate of `s`, `NULL` on failure
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__)))
+wchar_t *libsimple_aligned_wcsndup(const wchar_t * __s, size_t __alignment, size_t __n); /* TODO man */
+#ifndef aligned_wcsndup
+# define aligned_wcsndup libsimple_aligned_wcsndup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wcsndup` 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 wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(3), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_enaligned_wcsndup(int, const wchar_t *, size_t, size_t); /* TODO man */
+#ifndef enaligned_wcsndup
+# define enaligned_wcsndup libsimple_enaligned_wcsndup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wcsndup` 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 wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_align__(2), __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline wchar_t *libsimple_ealigned_wcsndup(const wchar_t *__s, size_t __alignment, size_t __n) /* TODO test, man */
+{ return libsimple_enaligned_wcsndup(libsimple_default_failure_exit, __s, __alignment, __n); }
+#ifndef ealigned_wcsndup
+# define ealigned_wcsndup libsimple_ealigned_wcsndup
+#endif
diff --git a/libsimple/aligned_wmemdup.h b/libsimple/aligned_wmemdup.h
new file mode 100644
index 0000000..1ab537e
--- /dev/null
+++ b/libsimple/aligned_wmemdup.h
@@ -0,0 +1,79 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_aligned_wmemdup`
+ *
+ * @param s:const wchar_t * The wide characters to copy
+ * @param alignment:size_t The alignment of the returned pointer
+ * @param n:size_t The number of wide characters to copy
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_aligned_wmemdupa(s, alignment, n) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = (n);\
+ size_t __a = (alignment);\
+ size_t __size;\
+ uintptr_t __misalignment;\
+ char *__r;\
+ __a += !__a;\
+ __size = __n * sizeof(wchar_t) + (__a - 1);\
+ __r = alloca(__size + !__size);\
+ __misalignment = (uintptr_t)__r % (uintptr_t)__a;\
+ if (__misalignment)\
+ __r += (uintptr_t)__a - __misalignment;\
+ wmemcpy(__r, __s, __n);\
+ })
+# ifndef aligned_wmemdupa
+# define aligned_wmemdupa(s, alignment, n) libsimple_aligned_wmemdupa(s, alignment, n)
+# endif
+#endif
+
+
+/**
+ * Create a new allocation, with custom alignment, and copy wide characters into it
+ *
+ * @param s The wide characters to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`, `NULL` on failure
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(3), __nonnull__, __warn_unused_result__)))
+wchar_t *libsimple_aligned_wmemdup(const wchar_t *, size_t, size_t); /* TODO man */
+#ifndef aligned_wmemdup
+# define aligned_wmemdup libsimple_aligned_wmemdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wmemdup` that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The wide characters to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(4), __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_enaligned_wmemdup(int, const wchar_t *, size_t, size_t); /* TODO man */
+#ifndef enaligned_wmemdup
+# define enaligned_wmemdup libsimple_enaligned_wmemdup
+#endif
+
+
+/**
+ * Version of `libsimple_aligned_wmemdup` that calls `libsimple_eprintf` on error
+ *
+ * @param s The wide characters to copy
+ * @param alignment The alignment of the returned pointer
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+static inline wchar_t *libsimple_ealigned_wmemdup(const wchar_t *__s, size_t __alignment, size_t __n) /* TODO test, man */
+{ return libsimple_enaligned_wmemdup(libsimple_default_failure_exit, __s, __alignment, __n); }
+#ifndef ealigned_wmemdup
+# define ealigned_wmemdup libsimple_ealigned_wmemdup
+#endif
diff --git a/libsimple/memdup.h b/libsimple/memdup.h
index ce84f6b..75353b8 100644
--- a/libsimple/memdup.h
+++ b/libsimple/memdup.h
@@ -13,7 +13,7 @@
({\
const char *__s = (s);\
size_t __n = (n);\
- char *__r = alloca(__n);\
+ char *__r = alloca(__n + !__n);\
memcpy(__r, __s, __n);\
})
# ifndef memdupa
@@ -60,7 +60,7 @@ void *libsimple_enmemdup(int, const void *, size_t);
*/
_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); }
+{ return libsimple_enmemdup(libsimple_default_failure_exit, __s, __n); }
#ifndef ememdup
# define ememdup libsimple_ememdup
#endif
diff --git a/libsimple/str.h b/libsimple/str.h
index 3693c14..4bf5793 100644
--- a/libsimple/str.h
+++ b/libsimple/str.h
@@ -338,7 +338,7 @@ static inline int libsimple_streq(const char *__a, const char *__b)
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
static inline int libsimple_streqnul(const char *__a, const char *__b)
-{ return !strcmpnul(__a, __b); }
+{ return !libsimple_strcmpnul(__a, __b); }
#ifndef streqnul
# define streqnul libsimple_streqnul
#endif
@@ -370,7 +370,7 @@ static inline int libsimple_strcaseeq(const char *__a, const char *__b)
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __warn_unused_result__)))
static inline int libsimple_strcaseeqnul(const char *__a, const char *__b)
-{ return !strcasecmpnul(__a, __b); }
+{ return !libsimple_strcasecmpnul(__a, __b); }
#ifndef strcaseeqnul
# define strcaseeqnul libsimple_strcaseeqnul
#endif
@@ -416,7 +416,7 @@ size_t libsimple_strcaseeqlen(const char *, const char *);
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
static inline size_t libsimple_strreqlen(const char *__a, const char *__b)
-{ return memreqlen(__a, strlen(__a), __b, strlen(__b)); }
+{ return libsimple_memreqlen(__a, strlen(__a), __b, strlen(__b)); }
#ifndef strreqlen
# define strreqlen libsimple_strreqlen
#endif
@@ -432,7 +432,7 @@ static inline size_t libsimple_strreqlen(const char *__a, const char *__b)
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
static inline size_t libsimple_strrcaseeqlen(const char *__a, const char *__b)
-{ return memrcaseeqlen(__a, strlen(__a), __b, strlen(__b)); }
+{ return libsimple_memrcaseeqlen(__a, strlen(__a), __b, strlen(__b)); }
#ifndef strrcaseeqlen
# define strrcaseeqlen libsimple_strrcaseeqlen
#endif
diff --git a/libsimple/strdup.h b/libsimple/strdup.h
index 33994e3..74e689e 100644
--- a/libsimple/strdup.h
+++ b/libsimple/strdup.h
@@ -43,7 +43,7 @@ char *libsimple_enstrdup(int, const char *);
*/
_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); }
+{ return libsimple_enstrdup(libsimple_default_failure_exit, __s); }
#ifndef estrdup
# define estrdup libsimple_estrdup
#endif
diff --git a/libsimple/strn.h b/libsimple/strn.h
index e9272a4..aa8a889 100644
--- a/libsimple/strn.h
+++ b/libsimple/strn.h
@@ -459,7 +459,7 @@ static inline int libsimple_strncaseeq(const char *__a, const char *__b, size_t
*/
_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); }
+{ return !libsimple_strncasecmpnul(__a, __b, __n); }
#ifndef strncaseeqnul
# define strncaseeqnul libsimple_strncaseeqnul
#endif
@@ -511,7 +511,7 @@ size_t libsimple_strncaseeqlen(const char *, const char *, size_t);
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
static inline size_t libsimple_strrneqlen(const char *__a, const char *__b, size_t __n)
-{ return memreqlen(__a, strnlen(__a, __n), __b, strnlen(__b, __n)); }
+{ return libsimple_memreqlen(__a, strnlen(__a, __n), __b, strnlen(__b, __n)); }
#ifndef strrneqlen
# define strrneqlen libsimple_strrneqlen
#endif
@@ -529,7 +529,7 @@ static inline size_t libsimple_strrneqlen(const char *__a, const char *__b, size
*/
_LIBSIMPLE_GCC_ONLY(__attribute__((__pure__, __nonnull__, __warn_unused_result__)))
static inline size_t libsimple_strrncaseeqlen(const char *__a, const char *__b, size_t __n)
-{ return memrcaseeqlen(__a, strnlen(__a, __n), __b, strnlen(__b, __n)); }
+{ return libsimple_memrcaseeqlen(__a, strnlen(__a, __n), __b, strnlen(__b, __n)); }
#ifndef strrncaseeqlen
# define strrncaseeqlen libsimple_strrncaseeqlen
#endif
diff --git a/libsimple/strndup.h b/libsimple/strndup.h
index 2b5bbd0..174a10a 100644
--- a/libsimple/strndup.h
+++ b/libsimple/strndup.h
@@ -49,7 +49,7 @@ char *libsimple_enstrndup(int, const char *, size_t);
*/
_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); }
+{ return libsimple_enstrndup(libsimple_default_failure_exit, __s, __n); }
#ifndef estrndup
# define estrndup libsimple_estrndup
#endif
diff --git a/libsimple/wcsdup.h b/libsimple/wcsdup.h
new file mode 100644
index 0000000..685b8ac
--- /dev/null
+++ b/libsimple/wcsdup.h
@@ -0,0 +1,49 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of wcsdup(3)
+ *
+ * @param s:const wchar_t * The string to copy
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_wcsdupa(s) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = wcslen(__s) + 1;\
+ wchar_t *__r = alloca(__n * sizeof(wchar_t));\
+ wmemcpy(__r, __s, __n);\
+ })
+# ifndef wcsdupa
+# define wcsdupa(s) libsimple_wcsdupa(s)
+# endif
+#endif
+
+
+/**
+ * Version of wcsdup(3) that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The string to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_enwcsdup(int, const wchar_t *); /* TODO man */
+#ifndef enwcsdup
+# define enwcsdup libsimple_enwcsdup
+#endif
+
+
+/**
+ * Version of wcsdup(3) that calls `libsimple_eprintf` on error
+ *
+ * @param s The string to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline wchar_t *libsimple_ewcsdup(const wchar_t *__s) /* TODO man */
+{ return enwcsdup(libsimple_default_failure_exit, __s); }
+#ifndef ewcsdup
+# define ewcsdup libsimple_ewcsdup
+#endif
diff --git a/libsimple/wcsndup.h b/libsimple/wcsndup.h
new file mode 100644
index 0000000..0f00d9e
--- /dev/null
+++ b/libsimple/wcsndup.h
@@ -0,0 +1,69 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_wcsndup`
+ *
+ * @param s:const wchar_t * The string to copy
+ * @param n:size_t The maximum number of wide characters to copy
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_wcsndupa(s, n) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = wcsnlen(__s, n);\
+ wchar_t *__r;\
+ __r = alloca((__n + 1) * sizeof(wchar_t));\
+ wmemcpy(__r, __s, __n);\
+ __r[__n] = '\0';\
+ __r;\
+ })
+# ifndef wcsndupa
+# define wcsndupa(s, n) libsimple_wcsndupa(s, n)
+# endif
+#endif
+
+
+/**
+ * Create a new allocation and copy a wide-character string into it
+ *
+ * @param s The string to copy
+ * @param n The maximum number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_wcsndup(const wchar_t *, size_t); /* TODO man */
+#ifndef wcsndup
+# define wcsndup libsimple_wcsndup
+#endif
+
+
+/**
+ * Version of `libsimple_wcsndup` that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The string to copy
+ * @param n The maximum number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_enwcsndup(int, const wchar_t *, size_t); /* TODO man */
+#ifndef enwcsndup
+# define enwcsndup libsimple_enwcsndup
+#endif
+
+
+/**
+ * Version of `libsimple_wcsndup` that calls `libsimple_eprintf` on error
+ *
+ * @param s The string to copy
+ * @param n The maximum number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__malloc__, __nonnull__, __warn_unused_result__, __returns_nonnull__)))
+static inline wchar_t *libsimple_ewcsndup(const wchar_t *__s, size_t __n) /* TODO test, man */
+{ return libsimple_enwcsndup(libsimple_default_failure_exit, __s, __n); }
+#ifndef ewcsndup
+# define ewcsndup libsimple_ewcsndup
+#endif
diff --git a/libsimple/wmemdup.h b/libsimple/wmemdup.h
new file mode 100644
index 0000000..5d6730e
--- /dev/null
+++ b/libsimple/wmemdup.h
@@ -0,0 +1,66 @@
+/* See LICENSE file for copyright and license details. */
+
+
+/**
+ * Stack allocation version of `libsimple_wmemdup`
+ *
+ * @param s:const wchar_t * The wide characters to copy
+ * @param n:size_t The number of wide characters to copy
+ * @return :wchar_t * Duplicate of `s` with automatic storage
+ */
+#if defined(__GNUC__) || defined(__clang__)
+# define libsimple_wmemdupa(s, n) /* TODO test, man */\
+ ({\
+ const wchar_t *__s = (s);\
+ size_t __n = (n);\
+ wchar_t *__r = alloca(__n * sizeof(wchar_t) + !__n);\
+ wmemcpy(__r, __s, __n);\
+ })
+# ifndef wmemdupa
+# define wmemdupa(s, n) libsimple_wmemdupa(s, n)
+# endif
+#endif
+
+
+/**
+ * Create a new allocation and copy wide characters into it
+ *
+ * @param s The wide characters to copy
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`, `NULL` on failure
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(2), __nonnull__, __warn_unused_result__)))
+wchar_t *libsimple_wmemdup(const wchar_t *, size_t); /* TODO man */
+#ifndef wmemdup
+# define wmemdup libsimple_wmemdup
+#endif
+
+
+/**
+ * Version of `libsimple_wmemdup` that calls `libsimple_enprintf` on error
+ *
+ * @param status Exit value in case of failure
+ * @param s The wide characters to copy
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(3), __warn_unused_result__, __returns_nonnull__)))
+wchar_t *libsimple_enwmemdup(int, const wchar_t *, size_t); /* TODO man */
+#ifndef enwmemdup
+# define enwmemdup libsimple_enwmemdup
+#endif
+
+
+/**
+ * Version of `libsimple_wmemdup` that calls `libsimple_eprintf` on error
+ *
+ * @param s The wide characters to copy
+ * @param n The number of wide characters to copy
+ * @return Duplicate of `s`
+ */
+_LIBSIMPLE_GCC_ONLY(__attribute__((__alloc_size__(2), __warn_unused_result__, __returns_nonnull__)))
+static inline wchar_t *libsimple_ewmemdup(const wchar_t *__s, size_t __n) /* TODO test, man */
+{ return libsimple_enwmemdup(libsimple_default_failure_exit, __s, __n); }
+#ifndef ewmemdup
+# define ewmemdup libsimple_ewmemdup
+#endif
diff --git a/memdup.c b/memdup.c
index a1d0959..5d158b0 100644
--- a/memdup.c
+++ b/memdup.c
@@ -6,7 +6,7 @@
void *
libsimple_memdup(const void *s, size_t n)
{
- void *ret = malloc(n ? n : (size_t)1);
+ void *ret = malloc(n + !n);
if (!ret)
return NULL;
return memcpy(ret, s, n);
diff --git a/test.c b/test.c
index f785483..01100e8 100644
--- a/test.c
+++ b/test.c
@@ -236,6 +236,34 @@ memdup(const void *s, size_t size)
}
+wchar_t *
+wcsdup(const wchar_t *s)
+{
+ wchar_t *r;
+ size_t n = wcslen(s) + 1;
+ if (n > SIZE_MAX / sizeof(wchar_t)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ r = malloc(n * sizeof(wchar_t));
+ return r ? wcscpy(r, s) : r;
+}
+
+
+wchar_t *
+wcsndup(const wchar_t *s, size_t n)
+{
+ return libsimple_wcsndup(s, n);
+}
+
+
+wchar_t *
+wmemdup(const wchar_t *s, size_t n)
+{
+ return libsimple_wmemdup(s, n);
+}
+
+
void
free(void *ptr)
{
diff --git a/wcsndup.c b/wcsndup.c
new file mode 100644
index 0000000..83e227d
--- /dev/null
+++ b/wcsndup.c
@@ -0,0 +1,33 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_wcsndup(const wchar_t *s, size_t n) /* TODO test */
+{
+ size_t n = wcsnlen(s, n), size;
+ wchar_t *ret;
+ if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n + 1, sizeof(wchar_t), &size, SIZE_MAX)) {
+ errno = ENOMEM;
+ enprintf(status, "wcsdup:");
+ }
+ ret = aligned_alloc(_Alignof(wchar_t), size);
+ if (!ret)
+ enprintf(status, "wcsdup:");
+ wmemcpy(ret, s, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/wmemdup.c b/wmemdup.c
new file mode 100644
index 0000000..239ae7d
--- /dev/null
+++ b/wmemdup.c
@@ -0,0 +1,31 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#ifndef TEST
+
+
+wchar_t *
+libsimple_wmemdup(const wchar_t *s, size_t n) /* TODO test */
+{
+ wchar_t *ret;
+ size_t size;
+ if (LIBSIMPLE_UMUL_OVERFLOW_NONZERO(n + !n, sizeof(wchar_t), &size, SIZE_MAX)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ ret = aligned_alloc(_Alignof(wchar_t), size);
+ if (!ret)
+ return NULL;
+ return wmemcpy(ret, s, n);
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif