162306a36Sopenharmony_ci/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * string function definitions for NOLIBC
462306a36Sopenharmony_ci * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef _NOLIBC_STRING_H
862306a36Sopenharmony_ci#define _NOLIBC_STRING_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "std.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic void *malloc(size_t len);
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * As much as possible, please keep functions alphabetically sorted.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic __attribute__((unused))
1962306a36Sopenharmony_ciint memcmp(const void *s1, const void *s2, size_t n)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	size_t ofs = 0;
2262306a36Sopenharmony_ci	int c1 = 0;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {
2562306a36Sopenharmony_ci		ofs++;
2662306a36Sopenharmony_ci	}
2762306a36Sopenharmony_ci	return c1;
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic __attribute__((unused))
3162306a36Sopenharmony_civoid *_nolibc_memcpy_up(void *dst, const void *src, size_t len)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	size_t pos = 0;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	while (pos < len) {
3662306a36Sopenharmony_ci		((char *)dst)[pos] = ((const char *)src)[pos];
3762306a36Sopenharmony_ci		pos++;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci	return dst;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic __attribute__((unused))
4362306a36Sopenharmony_civoid *_nolibc_memcpy_down(void *dst, const void *src, size_t len)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	while (len) {
4662306a36Sopenharmony_ci		len--;
4762306a36Sopenharmony_ci		((char *)dst)[len] = ((const char *)src)[len];
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci	return dst;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* might be ignored by the compiler without -ffreestanding, then found as
5362306a36Sopenharmony_ci * missing.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memmove")))
5662306a36Sopenharmony_civoid *memmove(void *dst, const void *src, size_t len)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	size_t dir, pos;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	pos = len;
6162306a36Sopenharmony_ci	dir = -1;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (dst < src) {
6462306a36Sopenharmony_ci		pos = -1;
6562306a36Sopenharmony_ci		dir = 1;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	while (len) {
6962306a36Sopenharmony_ci		pos += dir;
7062306a36Sopenharmony_ci		((char *)dst)[pos] = ((const char *)src)[pos];
7162306a36Sopenharmony_ci		len--;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	return dst;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* must be exported, as it's used by libgcc on ARM */
7762306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memcpy")))
7862306a36Sopenharmony_civoid *memcpy(void *dst, const void *src, size_t len)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	return _nolibc_memcpy_up(dst, src, len);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* might be ignored by the compiler without -ffreestanding, then found as
8462306a36Sopenharmony_ci * missing.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci__attribute__((weak,unused,section(".text.nolibc_memset")))
8762306a36Sopenharmony_civoid *memset(void *dst, int b, size_t len)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	char *p = dst;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	while (len--) {
9262306a36Sopenharmony_ci		/* prevent gcc from recognizing memset() here */
9362306a36Sopenharmony_ci		__asm__ volatile("");
9462306a36Sopenharmony_ci		*(p++) = b;
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci	return dst;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic __attribute__((unused))
10062306a36Sopenharmony_cichar *strchr(const char *s, int c)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	while (*s) {
10362306a36Sopenharmony_ci		if (*s == (char)c)
10462306a36Sopenharmony_ci			return (char *)s;
10562306a36Sopenharmony_ci		s++;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	return NULL;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic __attribute__((unused))
11162306a36Sopenharmony_ciint strcmp(const char *a, const char *b)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	unsigned int c;
11462306a36Sopenharmony_ci	int diff;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
11762306a36Sopenharmony_ci		;
11862306a36Sopenharmony_ci	return diff;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic __attribute__((unused))
12262306a36Sopenharmony_cichar *strcpy(char *dst, const char *src)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	char *ret = dst;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	while ((*dst++ = *src++));
12762306a36Sopenharmony_ci	return ret;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* this function is only used with arguments that are not constants or when
13162306a36Sopenharmony_ci * it's not known because optimizations are disabled. Note that gcc 12
13262306a36Sopenharmony_ci * recognizes an strlen() pattern and replaces it with a jump to strlen(),
13362306a36Sopenharmony_ci * thus itself, hence the asm() statement below that's meant to disable this
13462306a36Sopenharmony_ci * confusing practice.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic __attribute__((unused))
13762306a36Sopenharmony_cisize_t strlen(const char *str)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	size_t len;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	for (len = 0; str[len]; len++)
14262306a36Sopenharmony_ci		__asm__("");
14362306a36Sopenharmony_ci	return len;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* do not trust __builtin_constant_p() at -O0, as clang will emit a test and
14762306a36Sopenharmony_ci * the two branches, then will rely on an external definition of strlen().
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_ci#if defined(__OPTIMIZE__)
15062306a36Sopenharmony_ci#define nolibc_strlen(x) strlen(x)
15162306a36Sopenharmony_ci#define strlen(str) ({                          \
15262306a36Sopenharmony_ci	__builtin_constant_p((str)) ?           \
15362306a36Sopenharmony_ci		__builtin_strlen((str)) :       \
15462306a36Sopenharmony_ci		nolibc_strlen((str));           \
15562306a36Sopenharmony_ci})
15662306a36Sopenharmony_ci#endif
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic __attribute__((unused))
15962306a36Sopenharmony_cisize_t strnlen(const char *str, size_t maxlen)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	size_t len;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	for (len = 0; (len < maxlen) && str[len]; len++);
16462306a36Sopenharmony_ci	return len;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic __attribute__((unused))
16862306a36Sopenharmony_cichar *strdup(const char *str)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	size_t len;
17162306a36Sopenharmony_ci	char *ret;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	len = strlen(str);
17462306a36Sopenharmony_ci	ret = malloc(len + 1);
17562306a36Sopenharmony_ci	if (__builtin_expect(ret != NULL, 1))
17662306a36Sopenharmony_ci		memcpy(ret, str, len + 1);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return ret;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic __attribute__((unused))
18262306a36Sopenharmony_cichar *strndup(const char *str, size_t maxlen)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	size_t len;
18562306a36Sopenharmony_ci	char *ret;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	len = strnlen(str, maxlen);
18862306a36Sopenharmony_ci	ret = malloc(len + 1);
18962306a36Sopenharmony_ci	if (__builtin_expect(ret != NULL, 1)) {
19062306a36Sopenharmony_ci		memcpy(ret, str, len);
19162306a36Sopenharmony_ci		ret[len] = '\0';
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return ret;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic __attribute__((unused))
19862306a36Sopenharmony_cisize_t strlcat(char *dst, const char *src, size_t size)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	size_t len;
20162306a36Sopenharmony_ci	char c;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	for (len = 0; dst[len];	len++)
20462306a36Sopenharmony_ci		;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for (;;) {
20762306a36Sopenharmony_ci		c = *src;
20862306a36Sopenharmony_ci		if (len < size)
20962306a36Sopenharmony_ci			dst[len] = c;
21062306a36Sopenharmony_ci		if (!c)
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci		len++;
21362306a36Sopenharmony_ci		src++;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return len;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic __attribute__((unused))
22062306a36Sopenharmony_cisize_t strlcpy(char *dst, const char *src, size_t size)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	size_t len;
22362306a36Sopenharmony_ci	char c;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	for (len = 0;;) {
22662306a36Sopenharmony_ci		c = src[len];
22762306a36Sopenharmony_ci		if (len < size)
22862306a36Sopenharmony_ci			dst[len] = c;
22962306a36Sopenharmony_ci		if (!c)
23062306a36Sopenharmony_ci			break;
23162306a36Sopenharmony_ci		len++;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	return len;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic __attribute__((unused))
23762306a36Sopenharmony_cichar *strncat(char *dst, const char *src, size_t size)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	char *orig = dst;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	while (*dst)
24262306a36Sopenharmony_ci		dst++;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	while (size && (*dst = *src)) {
24562306a36Sopenharmony_ci		src++;
24662306a36Sopenharmony_ci		dst++;
24762306a36Sopenharmony_ci		size--;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	*dst = 0;
25162306a36Sopenharmony_ci	return orig;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic __attribute__((unused))
25562306a36Sopenharmony_ciint strncmp(const char *a, const char *b, size_t size)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	unsigned int c;
25862306a36Sopenharmony_ci	int diff = 0;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	while (size-- &&
26162306a36Sopenharmony_ci	       !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)
26262306a36Sopenharmony_ci		;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return diff;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic __attribute__((unused))
26862306a36Sopenharmony_cichar *strncpy(char *dst, const char *src, size_t size)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	size_t len;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	for (len = 0; len < size; len++)
27362306a36Sopenharmony_ci		if ((dst[len] = *src))
27462306a36Sopenharmony_ci			src++;
27562306a36Sopenharmony_ci	return dst;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic __attribute__((unused))
27962306a36Sopenharmony_cichar *strrchr(const char *s, int c)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	const char *ret = NULL;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	while (*s) {
28462306a36Sopenharmony_ci		if (*s == (char)c)
28562306a36Sopenharmony_ci			ret = s;
28662306a36Sopenharmony_ci		s++;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return (char *)ret;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* make sure to include all global symbols */
29262306a36Sopenharmony_ci#include "nolibc.h"
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#endif /* _NOLIBC_STRING_H */
295