--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "efi-string.h"
+
+/* String functions for both char and char16_t that should behave the same way as their respective
+ * counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas
+ * userspace does not allow for this (strlen8(NULL) returns 0 like strlen_ptr(NULL) for example). To make it
+ * easier to tell in code which kind of string they work on, we use 8/16 suffixes. This also makes is easier
+ * to unit test them. */
+
+#define DEFINE_STRNLEN(type, name) \
+ size_t name(const type *s, size_t n) { \
+ if (!s) \
+ return 0; \
+ \
+ size_t len = 0; \
+ while (len < n && *s) { \
+ s++; \
+ len++; \
+ } \
+ \
+ return len; \
+ }
+
+DEFINE_STRNLEN(char, strnlen8);
+DEFINE_STRNLEN(char16_t, strnlen16);
+
+size_t strlen8(const char *s) {
+ return strnlen8(s, SIZE_MAX);
+}
+
+size_t strlen16(const char16_t *s) {
+ return strnlen16(s, SIZE_MAX);
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stddef.h>
+#include <uchar.h>
+
+size_t strnlen8(const char *s, size_t n);
+size_t strnlen16(const char16_t *s, size_t n);
+
+size_t strlen8(const char *s);
+size_t strlen16(const char16_t *s);
'devicetree.h',
'disk.h',
'drivers.h',
+ 'efi-string.h',
'graphics.h',
'initrd.h',
'linux.h',
'assert.c',
'devicetree.c',
'disk.c',
+ 'efi-string.c',
'graphics.c',
'initrd.c',
'measure.c',
stub_sources += files('linux.c')
endif
+tests += [
+ [files('test-efi-string.c', 'efi-string.c')],
+]
+
# BCD parser only makes sense on arches that Windows supports.
if efi_arch[1] in ['ia32', 'x86_64', 'arm', 'aarch64']
systemd_boot_sources += files('bcd.c')
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "efi-string.h"
+#include "tests.h"
+
+TEST(strlen8) {
+ assert_se(strlen8(NULL) == 0);
+ assert_se(strlen8("") == 0);
+ assert_se(strlen8("1") == 1);
+ assert_se(strlen8("11") == 2);
+ assert_se(strlen8("123456789") == 9);
+ assert_se(strlen8("12\0004") == 2);
+}
+
+TEST(strlen16) {
+ assert_se(strlen16(NULL) == 0);
+ assert_se(strlen16(u"") == 0);
+ assert_se(strlen16(u"1") == 1);
+ assert_se(strlen16(u"11") == 2);
+ assert_se(strlen16(u"123456789") == 9);
+ assert_se(strlen16(u"12\0004") == 2);
+}
+
+TEST(strnlen8) {
+ assert_se(strnlen8(NULL, 0) == 0);
+ assert_se(strnlen8(NULL, 10) == 0);
+ assert_se(strnlen8("", 10) == 0);
+ assert_se(strnlen8("1", 10) == 1);
+ assert_se(strnlen8("11", 1) == 1);
+ assert_se(strnlen8("123456789", 7) == 7);
+ assert_se(strnlen8("12\0004", 5) == 2);
+}
+
+TEST(strnlen16) {
+ assert_se(strnlen16(NULL, 0) == 0);
+ assert_se(strnlen16(NULL, 10) == 0);
+ assert_se(strnlen16(u"", 10) == 0);
+ assert_se(strnlen16(u"1", 10) == 1);
+ assert_se(strnlen16(u"11", 1) == 1);
+ assert_se(strnlen16(u"123456789", 7) == 7);
+ assert_se(strnlen16(u"12\0004", 5) == 2);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);