diff options
Diffstat (limited to 'lib/string')
-rw-r--r-- | lib/string/sprintf.c | 24 | ||||
-rw-r--r-- | lib/string/sprintf.h | 97 | ||||
-rw-r--r-- | lib/string/stpecpy.c | 20 | ||||
-rw-r--r-- | lib/string/stpecpy.h | 90 | ||||
-rw-r--r-- | lib/string/stpeprintf.c | 25 | ||||
-rw-r--r-- | lib/string/stpeprintf.h | 120 | ||||
-rw-r--r-- | lib/string/strftime.c | 7 | ||||
-rw-r--r-- | lib/string/strftime.h | 19 | ||||
-rw-r--r-- | lib/string/strncpy.h | 21 | ||||
-rw-r--r-- | lib/string/strtcpy.c | 18 | ||||
-rw-r--r-- | lib/string/strtcpy.h | 80 | ||||
-rw-r--r-- | lib/string/zustr2stp.h | 58 |
12 files changed, 579 insertions, 0 deletions
diff --git a/lib/string/sprintf.c b/lib/string/sprintf.c new file mode 100644 index 0000000..cf3c210 --- /dev/null +++ b/lib/string/sprintf.c @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org> + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <config.h> + +#ident "$Id$" + +#include "string/sprintf.h" + +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> + + +extern inline int xasprintf(char **restrict s, const char *restrict fmt, ...); +extern inline int xvasprintf(char **restrict s, const char *restrict fmt, + va_list ap); + +extern inline int snprintf_(char *restrict s, size_t size, + const char *restrict fmt, ...); +extern inline int vsnprintf_(char *restrict s, size_t size, + const char *restrict fmt, va_list ap); diff --git a/lib/string/sprintf.h b/lib/string/sprintf.h new file mode 100644 index 0000000..7485369 --- /dev/null +++ b/lib/string/sprintf.h @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org> + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_SPRINTF_H_ +#define SHADOW_INCLUDE_LIB_SPRINTF_H_ + + +#include <config.h> + +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> + +#include "attr.h" +#include "defines.h" +#include "sizeof.h" + + +#define SNPRINTF(s, fmt, ...) \ + snprintf_(s, NITEMS(s), fmt __VA_OPT__(,) __VA_ARGS__) + + +format_attr(printf, 2, 3) +inline int xasprintf(char **restrict s, const char *restrict fmt, ...); +format_attr(printf, 2, 0) +inline int xvasprintf(char **restrict s, const char *restrict fmt, va_list ap); + +format_attr(printf, 3, 4) +inline int snprintf_(char *restrict s, size_t size, const char *restrict fmt, + ...); +format_attr(printf, 3, 0) +inline int vsnprintf_(char *restrict s, size_t size, const char *restrict fmt, + va_list ap); + + +inline int +xasprintf(char **restrict s, const char *restrict fmt, ...) +{ + int len; + va_list ap; + + va_start(ap, fmt); + len = xvasprintf(s, fmt, ap); + va_end(ap); + + return len; +} + + +inline int +xvasprintf(char **restrict s, const char *restrict fmt, va_list ap) +{ + int len; + + len = vasprintf(s, fmt, ap); + if (len == -1) { + perror("asprintf"); + exit(EXIT_FAILURE); + } + + return len; +} + + +inline int +snprintf_(char *restrict s, size_t size, const char *restrict fmt, ...) +{ + int len; + va_list ap; + + va_start(ap, fmt); + len = vsnprintf_(s, size, fmt, ap); + va_end(ap); + + return len; +} + + +inline int +vsnprintf_(char *restrict s, size_t size, const char *restrict fmt, va_list ap) +{ + int len; + + len = vsnprintf(s, size, fmt, ap); + if (len == -1) + return -1; + if ((size_t) len >= size) + return -1; + + return len; +} + + +#endif // include guard diff --git a/lib/string/stpecpy.c b/lib/string/stpecpy.c new file mode 100644 index 0000000..9759388 --- /dev/null +++ b/lib/string/stpecpy.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include <config.h> + +#if !defined(HAVE_STPECPY) + +#ident "$Id$" + +#include "string/stpecpy.h" + + +extern inline char *stpecpy(char *dst, char *end, const char *restrict src); + + +#endif // !HAVE_STPECPY diff --git a/lib/string/stpecpy.h b/lib/string/stpecpy.h new file mode 100644 index 0000000..2324baa --- /dev/null +++ b/lib/string/stpecpy.h @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STPECPY_H_ +#define SHADOW_INCLUDE_LIB_STPECPY_H_ + + +#include <config.h> + +#if !defined(HAVE_STPECPY) + +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +#include "attr.h" + + +ATTR_STRING(3) +inline char *stpecpy(char *dst, char *end, const char *restrict src); + + +/* + * SYNOPSIS + * [[gnu::null_terminated_string_arg(3)]] + * char *_Nullable stpecpy(char *_Nullable dst, char end[0], + * const char *restrict src); + * + * ARGUMENTS + * dst Destination buffer where to copy a string. + * + * end Pointer to one after the last element of the buffer + * pointed to by `dst`. Usually, it should be calculated + * as `dst + NITEMS(dst)`. + * + * src Source string to be copied into dst. + * + * DESCRIPTION + * This function copies the string pointed to by src, into a string + * at the buffer pointed to by dst. If the destination buffer, + * limited by a pointer to its end --one after its last element--, + * isn't large enough to hold the copy, the resulting string is + * truncated. + * + * This function can be chained with calls to [v]stpeprintf(). + * + * RETURN VALUE + * dst + strlen(dst) + * • On success, this function returns a pointer to the + * terminating NUL byte. + * + * end + * • If this call truncated the resulting string. + * • If `dst == end` (a previous chained call to these + * functions truncated). + * NULL + * • If `dst == NULL` (a previous chained call to + * [v]stpeprintf() failed). + * + * ERRORS + * This function doesn't set errno. + */ + + +inline char * +stpecpy(char *dst, char *end, const char *restrict src) +{ + bool trunc; + size_t dsize, dlen, slen; + + if (dst == end) + return end; + if (dst == NULL) + return NULL; + + dsize = end - dst; + slen = strnlen(src, dsize); + trunc = (slen == dsize); + dlen = slen - trunc; + + return stpcpy(mempcpy(dst, src, dlen), "") + trunc; +} + + +#endif // !HAVE_STPECPY +#endif // include guard diff --git a/lib/string/stpeprintf.c b/lib/string/stpeprintf.c new file mode 100644 index 0000000..cecd95d --- /dev/null +++ b/lib/string/stpeprintf.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include <config.h> + +#if !defined(HAVE_STPEPRINTF) + +#ident "$Id$" + +#include "string/stpeprintf.h" + +#include <stdarg.h> + + +extern inline char *stpeprintf(char *dst, char *end, const char *restrict fmt, + ...); +extern inline char *vstpeprintf(char *dst, char *end, const char *restrict fmt, + va_list ap); + + +#endif // !HAVE_STPEPRINTF diff --git a/lib/string/stpeprintf.h b/lib/string/stpeprintf.h new file mode 100644 index 0000000..14ee7b6 --- /dev/null +++ b/lib/string/stpeprintf.h @@ -0,0 +1,120 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STPEPRINTF_H_ +#define SHADOW_INCLUDE_LIB_STPEPRINTF_H_ + + +#include <config.h> + +#if !defined(HAVE_STPEPRINTF) + +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> + +#include "attr.h" +#include "defines.h" + + +format_attr(printf, 3, 4) +inline char *stpeprintf(char *dst, char *end, const char *restrict fmt, ...); + +format_attr(printf, 3, 0) +inline char *vstpeprintf(char *dst, char *end, const char *restrict fmt, + va_list ap); + + +/* + * SYNOPSIS + * [[gnu::format(printf, 3, 4)]] + * char *_Nullable stpeprintf(char *_Nullable dst, char end[0], + * const char *restrict fmt, ...); + * + * [[gnu::format(printf, 3, 0)]] + * char *_Nullable vstpeprintf(char *_Nullable dst, char end[0], + * const char *restrict fmt, va_list ap); + * + * + * ARGUMENTS + * dst Destination buffer where to write a string. + * + * end Pointer to one after the last element of the buffer + * pointed to by `dst`. Usually, it should be calculated + * as `dst + NITEMS(dst)`. + * + * fmt Format string + * + * ... + * ap Variadic argument list + * + * DESCRIPTION + * These functions are very similar to [v]snprintf(3). + * + * The destination buffer is limited by a pointer to its end --one + * after its last element-- instead of a size. This allows + * chaining calls to it safely, unlike [v]snprintf(3), which is + * difficult to chain without invoking Undefined Behavior. + * + * RETURN VALUE + * dst + strlen(dst) + * • On success, these functions return a pointer to the + * terminating NUL byte. + * + * end + * • If this call truncated the resulting string. + * • If `dst == end` (a previous chained call to these + * functions truncated). + * NULL + * • If this function failed (see ERRORS). + * • If `dst == NULL` (a previous chained call to these + * functions failed). + * + * ERRORS + * These functions may fail for the same reasons as vsnprintf(3). + */ + + +inline char * +stpeprintf(char *dst, char *end, const char *restrict fmt, ...) +{ + char *p; + va_list ap; + + va_start(ap, fmt); + p = vstpeprintf(dst, end, fmt, ap); + va_end(ap); + + return p; +} + + +inline char * +vstpeprintf(char *dst, char *end, const char *restrict fmt, va_list ap) +{ + int len; + ptrdiff_t size; + + if (dst == end) + return end; + if (dst == NULL) + return NULL; + + size = end - dst; + len = vsnprintf(dst, size, fmt, ap); + + if (len == -1) + return NULL; + if (len >= size) + return end; + + return dst + len; +} + + +#endif // !HAVE_STPEPRINTF +#endif // include guard diff --git a/lib/string/strftime.c b/lib/string/strftime.c new file mode 100644 index 0000000..ea1deb3 --- /dev/null +++ b/lib/string/strftime.c @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org> +// SPDX-License-Identifier: BSD-3-Clause + + +#include <config.h> + +#include "strftime.h" diff --git a/lib/string/strftime.h b/lib/string/strftime.h new file mode 100644 index 0000000..bebb31a --- /dev/null +++ b/lib/string/strftime.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org> +// SPDX-License-Identifier: BSD-3-Clause + + +#ifndef SHADOW_INCLUDE_LIB_STRFTIME_H_ +#define SHADOW_INCLUDE_LIB_STRFTIME_H_ + + +#include <config.h> + +#include <time.h> + +#include "sizeof.h" + + +#define STRFTIME(dst, fmt, ...) strftime(dst, NITEMS(dst), fmt, __VA_ARGS__) + + +#endif // include guard diff --git a/lib/string/strncpy.h b/lib/string/strncpy.h new file mode 100644 index 0000000..fc6fcc9 --- /dev/null +++ b/lib/string/strncpy.h @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org> + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STRNCPY_H_ +#define SHADOW_INCLUDE_LIB_STRNCPY_H_ + + +#include <config.h> + +#include <string.h> + +#include "sizeof.h" + + +#define STRNCPY(dst, src) strncpy(dst, src, NITEMS(dst)) + + +#endif // include guard diff --git a/lib/string/strtcpy.c b/lib/string/strtcpy.c new file mode 100644 index 0000000..74de4fc --- /dev/null +++ b/lib/string/strtcpy.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2022-2023, Alejandro Colomar <alx@kernel.org> + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include <config.h> + +#include <stddef.h> +#include <sys/types.h> + +#ident "$Id$" + +#include "string/strtcpy.h" + + +extern inline ssize_t strtcpy(char *restrict dst, const char *restrict src, + size_t dsize); diff --git a/lib/string/strtcpy.h b/lib/string/strtcpy.h new file mode 100644 index 0000000..4ff6e11 --- /dev/null +++ b/lib/string/strtcpy.h @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org> + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STRTCPY_H_ +#define SHADOW_INCLUDE_LIB_STRTCPY_H_ + + +#include <config.h> + +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +#include <sys/types.h> + +#include "attr.h" +#include "defines.h" +#include "sizeof.h" + + +/* + * SYNOPSIS + * [[gnu::null_terminated_string_arg(2)]] + * int STRTCPY(char dst[restrict], const char *restrict src); + * + * ARGUMENTS + * dst Destination buffer where to copy a string. + * src Source string to be copied into dst. + * + * DESCRIPTION + * This macro copies the string pointed to by src, into a string + * at the buffer pointed to by dst. If the destination buffer, + * isn't large enough to hold the copy, the resulting string is + * truncated. The size of the buffer is calculated internally via + * NITEMS(). + * + * RETURN VALUE + * -1 If this call truncated the resulting string. + * + * strlen(dst) + * On success. + * + * ERRORS + * This function doesn't set errno. + */ + + +#define STRTCPY(dst, src) strtcpy(dst, src, NITEMS(dst)) + + +ATTR_STRING(2) +inline ssize_t strtcpy(char *restrict dst, const char *restrict src, + size_t dsize); + + +inline ssize_t +strtcpy(char *restrict dst, const char *restrict src, size_t dsize) +{ + bool trunc; + size_t dlen, slen; + + if (dsize == 0) + return -1; + + slen = strnlen(src, dsize); + trunc = (slen == dsize); + dlen = slen - trunc; + + stpcpy(mempcpy(dst, src, dlen), ""); + + if (trunc) + return -1; + + return slen; +} + + +#endif // include guard diff --git a/lib/string/zustr2stp.h b/lib/string/zustr2stp.h new file mode 100644 index 0000000..152102b --- /dev/null +++ b/lib/string/zustr2stp.h @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2022-2024, Alejandro Colomar <alx@kernel.org> +// SPDX-License-Identifier: BSD-3-Clause + + +#ifndef SHADOW_INCLUDE_LIB_STRING_ZUSTR2STP_H_ +#define SHADOW_INCLUDE_LIB_STRING_ZUSTR2STP_H_ + + +#include <config.h> + +#include <assert.h> +#include <string.h> + +#include "must_be.h" +#include "sizeof.h" + + +/* + * SYNOPSIS + * char *ZUSTR2STP(char *restrict dst, const char src[restrict]); + * + * ARGUMENTS + * dst Destination buffer. + * src Source null-padded character sequence. + * + * DESCRIPTION + * This macro copies at most NITEMS(src) non-null bytes from the + * array pointed to by src, followed by a null character, to the + * buffer pointed to by dst. + * + * RETURN VALUE + * dst + strlen(dst) + * This function returns a pointer to the terminating NUL + * byte. + * + * CAVEATS + * This function doesn't know the size of the destination buffer. + * It assumes it will always be large enough. Since the size of + * the source buffer is known to the caller, it should make sure to + * allocate a destination buffer of at least `NITEMS(src) + 1`. + * + * EXAMPLES + * char hostname[NITEMS(utmp->ut_host) + 1]; + * + * len = ZUSTR2STP(hostname, utmp->ut_host) - hostname; + * puts(hostname); + */ + + +#define ZUSTR2STP(dst, src) \ +({ \ + static_assert(!is_array(dst) || sizeof(dst) > SIZEOF_ARRAY(src), ""); \ + \ + stpcpy(mempcpy(dst, src, strnlen(src, NITEMS(src))), ""); \ +}) + + +#endif // include guard |