summaryrefslogtreecommitdiffstats
path: root/lib/string
diff options
context:
space:
mode:
Diffstat (limited to 'lib/string')
-rw-r--r--lib/string/sprintf.c24
-rw-r--r--lib/string/sprintf.h97
-rw-r--r--lib/string/stpecpy.c20
-rw-r--r--lib/string/stpecpy.h90
-rw-r--r--lib/string/stpeprintf.c25
-rw-r--r--lib/string/stpeprintf.h120
-rw-r--r--lib/string/strftime.c7
-rw-r--r--lib/string/strftime.h19
-rw-r--r--lib/string/strncpy.h21
-rw-r--r--lib/string/strtcpy.c18
-rw-r--r--lib/string/strtcpy.h80
-rw-r--r--lib/string/zustr2stp.h58
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