diff options
author | Mattias Andrée <maandree@kth.se> | 2018-11-25 23:05:59 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2018-11-25 23:06:03 +0100 |
commit | d8ccc87fed8a4c588e4ad9279e62925f416d36b3 (patch) | |
tree | f02a2138183c53ab95ef96dafeba75ebd9c0c422 | |
parent | Include wchar.h and wctype.h (diff) | |
download | libsimple-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>
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | aligned_enmemdup.c | 64 | ||||
-rw-r--r-- | aligned_memdup.c | 4 | ||||
-rw-r--r-- | aligned_wcsndup.c | 34 | ||||
-rw-r--r-- | aligned_wmemdup.c | 32 | ||||
-rw-r--r-- | enaligned_wcsdup.c | 25 | ||||
-rw-r--r-- | enaligned_wcsndup.c | 25 | ||||
-rw-r--r-- | enaligned_wmemdup.c | 25 | ||||
-rw-r--r-- | enwcsdup.c | 32 | ||||
-rw-r--r-- | enwcsndup.c | 25 | ||||
-rw-r--r-- | enwmemdup.c | 25 | ||||
-rw-r--r-- | libsimple.h | 6 | ||||
-rw-r--r-- | libsimple/aligned_memdup.h | 6 | ||||
-rw-r--r-- | libsimple/aligned_strdup.h | 4 | ||||
-rw-r--r-- | libsimple/aligned_strndup.h | 5 | ||||
-rw-r--r-- | libsimple/aligned_wcsdup.h | 74 | ||||
-rw-r--r-- | libsimple/aligned_wcsndup.h | 79 | ||||
-rw-r--r-- | libsimple/aligned_wmemdup.h | 79 | ||||
-rw-r--r-- | libsimple/memdup.h | 4 | ||||
-rw-r--r-- | libsimple/str.h | 8 | ||||
-rw-r--r-- | libsimple/strdup.h | 2 | ||||
-rw-r--r-- | libsimple/strn.h | 6 | ||||
-rw-r--r-- | libsimple/strndup.h | 2 | ||||
-rw-r--r-- | libsimple/wcsdup.h | 49 | ||||
-rw-r--r-- | libsimple/wcsndup.h | 69 | ||||
-rw-r--r-- | libsimple/wmemdup.h | 66 | ||||
-rw-r--r-- | memdup.c | 2 | ||||
-rw-r--r-- | test.c | 28 | ||||
-rw-r--r-- | wcsndup.c | 33 | ||||
-rw-r--r-- | wmemdup.c | 31 |
30 files changed, 767 insertions, 85 deletions
@@ -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 @@ -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); @@ -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 |