Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347/* 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 */