346 lines · 6.4 KB · C
RawDownload
/* SPDX-License-Identifier: LGPL-2.1 OR MIT *//* * string function definitions for NOLIBC * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> */ /* make sure to include all global symbols */#include "nolibc.h" #ifndef _NOLIBC_STRING_H#define _NOLIBC_STRING_H #include "arch.h"#include "std.h" static void *malloc(size_t len); /* * As much as possible, please keep functions alphabetically sorted. */ static __attribute__((unused))int memcmp(const void *s1, const void *s2, size_t n){	size_t ofs = 0;	int c1 = 0; 	while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) {		ofs++;	}	return c1;} #ifndef NOLIBC_ARCH_HAS_MEMMOVE/* might be ignored by the compiler without -ffreestanding, then found as * missing. */void *memmove(void *dst, const void *src, size_t len);__attribute__((weak,unused,section(".text.nolibc_memmove")))void *memmove(void *dst, const void *src, size_t len){	size_t dir, pos; 	pos = len;	dir = -1; 	if (dst < src) {		pos = -1;		dir = 1;	} 	while (len) {		pos += dir;		((char *)dst)[pos] = ((const char *)src)[pos];		len--;	}	return dst;}#endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */ #ifndef NOLIBC_ARCH_HAS_MEMCPY/* must be exported, as it's used by libgcc on ARM */void *memcpy(void *dst, const void *src, size_t len);__attribute__((weak,unused,section(".text.nolibc_memcpy")))void *memcpy(void *dst, const void *src, size_t len){	size_t pos = 0; 	while (pos < len) {		((char *)dst)[pos] = ((const char *)src)[pos];		pos++;	}	return dst;}#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */ #ifndef NOLIBC_ARCH_HAS_MEMSET/* might be ignored by the compiler without -ffreestanding, then found as * missing. */void *memset(void *dst, int b, size_t len);__attribute__((weak,unused,section(".text.nolibc_memset")))void *memset(void *dst, int b, size_t len){	char *p = dst; 	while (len--) {		/* prevent gcc from recognizing memset() here */		__asm__ volatile("");		*(p++) = b;	}	return dst;}#endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */ #ifndef NOLIBC_ARCH_HAS_MEMCHRstatic __attribute__((unused))void *memchr(const void *s, int c, size_t len){	char *p = (char *)s; 	while (len--) {		if (*p == (char)c)			return p;		p++;	}	return NULL;}#endif /* #ifndef NOLIBC_ARCH_HAS_MEMCHR */ static __attribute__((unused))char *strchr(const char *s, int c){	while (*s) {		if (*s == (char)c)			return (char *)s;		s++;	}	return NULL;} static __attribute__((unused))int strcmp(const char *a, const char *b){	unsigned int c;	int diff; 	while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)		;	return diff;} static __attribute__((unused))char *strcpy(char *dst, const char *src){	char *ret = dst; 	while ((*dst++ = *src++));	return ret;} /* this function is only used with arguments that are not constants or when * it's not known because optimizations are disabled. Note that gcc 12 * recognizes an strlen() pattern and replaces it with a jump to strlen(), * thus itself, hence the asm() statement below that's meant to disable this * confusing practice. */size_t strlen(const char *str);__attribute__((weak,unused,section(".text.nolibc_strlen")))size_t strlen(const char *str){	size_t len; 	for (len = 0; str[len]; len++)		__asm__("");	return len;} /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and * the two branches, then will rely on an external definition of strlen(). */#if defined(__OPTIMIZE__)#define nolibc_strlen(x) strlen(x)#define strlen(str) ({                          \	__builtin_constant_p((str)) ?           \		__builtin_strlen((str)) :       \		nolibc_strlen((str));           \})#endif static __attribute__((unused))size_t strnlen(const char *str, size_t maxlen){	size_t len; 	for (len = 0; (len < maxlen) && str[len]; len++);	return len;} static __attribute__((unused))char *strdup(const char *str){	size_t len;	char *ret; 	len = strlen(str);	ret = malloc(len + 1);	if (__builtin_expect(ret != NULL, 1))		memcpy(ret, str, len + 1); 	return ret;} static __attribute__((unused))char *strndup(const char *str, size_t maxlen){	size_t len;	char *ret; 	len = strnlen(str, maxlen);	ret = malloc(len + 1);	if (__builtin_expect(ret != NULL, 1)) {		memcpy(ret, str, len);		ret[len] = '\0';	} 	return ret;} static __attribute__((unused))size_t strlcat(char *dst, const char *src, size_t size){	size_t len = strnlen(dst, size); 	/*	 * We want len < size-1. But as size is unsigned and can wrap	 * around, we use len + 1 instead.	 */	while (len + 1 < size) {		dst[len] = *src;		if (*src == '\0')			break;		len++;		src++;	} 	if (len < size)		dst[len] = '\0'; 	while (*src++)		len++; 	return len;} static __attribute__((unused))size_t strlcpy(char *dst, const char *src, size_t size){	size_t len; 	for (len = 0; len < size; len++) {		dst[len] = src[len];		if (!dst[len])			return len;	}	if (size)		dst[size-1] = '\0'; 	while (src[len])		len++; 	return len;} static __attribute__((unused))char *strncat(char *dst, const char *src, size_t size){	char *orig = dst; 	while (*dst)		dst++; 	while (size && (*dst = *src)) {		src++;		dst++;		size--;	} 	*dst = 0;	return orig;} static __attribute__((unused))int strncmp(const char *a, const char *b, size_t size){	unsigned int c;	int diff = 0; 	while (size-- &&	       !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c)		; 	return diff;} static __attribute__((unused))char *strncpy(char *dst, const char *src, size_t size){	size_t len; 	for (len = 0; len < size; len++)		if ((dst[len] = *src))			src++;	return dst;} static __attribute__((unused))char *strrchr(const char *s, int c){	const char *ret = NULL; 	while (*s) {		if (*s == (char)c)			ret = s;		s++;	}	return (char *)ret;} static __attribute__((unused))char *strstr(const char *haystack, const char *needle){	size_t len_haystack, len_needle; 	len_needle = strlen(needle);	if (!len_needle)		return NULL; 	len_haystack = strlen(haystack);	while (len_haystack >= len_needle) {		if (!memcmp(haystack, needle, len_needle))			return (char *)haystack;		haystack++;		len_haystack--;	} 	return NULL;} static __attribute__((unused))int tolower(int c){	if (c >= 'A' && c <= 'Z')		return c - 'A' + 'a';	return c;} static __attribute__((unused))int toupper(int c){	if (c >= 'a' && c <= 'z')		return c - 'a' + 'A';	return c;} #endif /* _NOLIBC_STRING_H */