While these functions are often dangerous, forcing the user to work around their absence is often much worse. Let's provide small versions of each of them. The respective sizes in bytes on a few architectures are: strncat(): x86:0x33 mips:0x68 arm:0x3c strlcat(): x86:0x25 mips:0x4c arm:0x2c The two are quite different, and strncat() is even different from strncpy() in that it limits the amount of data it copies and will always terminate the output by one zero, while strlcat() will always limit the total output to the specified size and will put a zero if possible. Signed-off-by: Willy Tarreau <w@1wt.eu> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
207 lines
3.2 KiB
C
207 lines
3.2 KiB
C
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
|
/*
|
|
* string function definitions for NOLIBC
|
|
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
|
*/
|
|
|
|
#ifndef _NOLIBC_STRING_H
|
|
#define _NOLIBC_STRING_H
|
|
|
|
#include "std.h"
|
|
|
|
/*
|
|
* 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;
|
|
char c1 = 0;
|
|
|
|
while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) {
|
|
ofs++;
|
|
}
|
|
return c1;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
void *_nolibc_memcpy_up(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;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
void *_nolibc_memcpy_down(void *dst, const void *src, size_t len)
|
|
{
|
|
while (len) {
|
|
len--;
|
|
((char *)dst)[len] = ((const char *)src)[len];
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
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;
|
|
}
|
|
|
|
/* must be exported, as it's used by libgcc on ARM */
|
|
__attribute__((weak,unused))
|
|
void *memcpy(void *dst, const void *src, size_t len)
|
|
{
|
|
return _nolibc_memcpy_up(dst, src, len);
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
void *memset(void *dst, int b, size_t len)
|
|
{
|
|
char *p = dst;
|
|
|
|
while (len--)
|
|
*(p++) = b;
|
|
return dst;
|
|
}
|
|
|
|
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))
|
|
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 */
|
|
static __attribute__((unused))
|
|
size_t nolibc_strlen(const char *str)
|
|
{
|
|
size_t len;
|
|
|
|
for (len = 0; str[len]; len++);
|
|
return len;
|
|
}
|
|
|
|
#define strlen(str) ({ \
|
|
__builtin_constant_p((str)) ? \
|
|
__builtin_strlen((str)) : \
|
|
nolibc_strlen((str)); \
|
|
})
|
|
|
|
static __attribute__((unused))
|
|
size_t strlcat(char *dst, const char *src, size_t size)
|
|
{
|
|
size_t len;
|
|
char c;
|
|
|
|
for (len = 0; dst[len]; len++)
|
|
;
|
|
|
|
for (;;) {
|
|
c = *src;
|
|
if (len < size)
|
|
dst[len] = c;
|
|
if (!c)
|
|
break;
|
|
len++;
|
|
src++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
size_t strlcpy(char *dst, const char *src, size_t size)
|
|
{
|
|
size_t len;
|
|
char c;
|
|
|
|
for (len = 0;;) {
|
|
c = src[len];
|
|
if (len < size)
|
|
dst[len] = c;
|
|
if (!c)
|
|
break;
|
|
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))
|
|
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;
|
|
}
|
|
|
|
#endif /* _NOLIBC_STRING_H */
|