blob: ab6a724a3144acd36c2437e78e7c8a2ed37cb63a [file] [log] [blame]
/*
* libc string functions
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License version 2.
*/
#include "libcflat.h"
#include "ctype.h"
#include "stdlib.h"
#include "linux/compiler.h"
size_t strlen(const char *buf)
{
size_t len = 0;
while (*buf++)
++len;
return len;
}
size_t strnlen(const char *buf, size_t maxlen)
{
const char *sc;
for (sc = buf; maxlen-- && *sc != '\0'; ++sc)
/* nothing */ ;
return sc - buf;
}
char *strcat(char *dest, const char *src)
{
char *p = dest;
while (*p)
++p;
while ((*p++ = *src++) != 0)
;
return dest;
}
char *strcpy(char *dest, const char *src)
{
*dest = 0;
return strcat(dest, src);
}
int strncmp(const char *a, const char *b, size_t n)
{
for (; n--; ++a, ++b)
if (*a != *b || *a == '\0')
return *a - *b;
return 0;
}
int strncasecmp(const char *a, const char *b, size_t n)
{
for (; n--; ++a, ++b)
if (tolower(*a) != tolower(*b) || *a == '\0')
return tolower(*a) - tolower(*b);
return 0;
}
int strcmp(const char *a, const char *b)
{
return strncmp(a, b, SIZE_MAX);
}
int strcasecmp(const char *a, const char *b)
{
return strncasecmp(a, b, SIZE_MAX);
}
char *strchr(const char *s, int c)
{
while (*s != (char)c)
if (*s++ == '\0')
return NULL;
return (char *)s;
}
char *strrchr(const char *s, int c)
{
const char *last = NULL;
do {
if (*s == (char)c)
last = s;
} while (*s++);
return (char *)last;
}
char *strchrnul(const char *s, int c)
{
while (*s && *s != (char)c)
s++;
return (char *)s;
}
char *strstr(const char *s1, const char *s2)
{
size_t l1, l2;
l2 = strlen(s2);
if (!l2)
return (char *)s1;
l1 = strlen(s1);
while (l1 >= l2) {
l1--;
if (!memcmp(s1, s2, l2))
return (char *)s1;
s1++;
}
return NULL;
}
void *memset(void *s, int c, size_t n)
{
size_t i;
char *a = s;
for (i = 0; i < n; ++i)
a[i] = c;
return s;
}
void *memcpy(void *dest, const void *src, size_t n)
{
size_t i;
char *a = dest;
const char *b = src;
for (i = 0; i < n; ++i)
a[i] = b[i];
return dest;
}
int memcmp(const void *s1, const void *s2, size_t n)
{
const unsigned char *a = s1, *b = s2;
int ret = 0;
while (n--) {
ret = *a - *b;
if (ret)
break;
++a, ++b;
}
return ret;
}
void *memmove(void *dest, const void *src, size_t n)
{
const unsigned char *s = src;
unsigned char *d = dest;
if (d <= s) {
while (n--)
*d++ = *s++;
} else {
d += n, s += n;
while (n--)
*--d = *--s;
}
return dest;
}
void *memchr(const void *s, int c, size_t n)
{
const unsigned char *str = s, chr = (unsigned char)c;
while (n--)
if (*str++ == chr)
return (void *)(str - 1);
return NULL;
}
static unsigned long long __strtoll(const char *nptr, char **endptr,
int base, bool is_signed, bool is_longlong)
{
unsigned long long ull = 0;
const char *s = nptr;
int neg, c;
assert(base == 0 || (base >= 2 && base <= 36));
while (isspace(*s))
s++;
if (*s == '-') {
neg = 1;
s++;
} else {
neg = 0;
if (*s == '+')
s++;
}
if (base == 0 || base == 16) {
if (*s == '0') {
s++;
if (*s == 'x' || *s == 'X') {
s++;
base = 16;
} else if (base == 0)
base = 8;
} else if (base == 0)
base = 10;
}
while (*s) {
if (*s >= '0' && *s < '0' + base && *s <= '9')
c = *s - '0';
else if (*s >= 'a' && *s < 'a' + base - 10)
c = *s - 'a' + 10;
else if (*s >= 'A' && *s < 'A' + base - 10)
c = *s - 'A' + 10;
else
break;
if (!is_longlong) {
if (is_signed) {
long sl = (long)ull;
assert(!check_mul_overflow(sl, base));
assert(!check_add_overflow(sl * base, c));
} else {
unsigned long ul = (unsigned long)ull;
assert(!check_mul_overflow(ul, base));
assert(!check_add_overflow(ul * base, c));
}
} else {
if (is_signed) {
long long sll = (long long)ull;
assert(!check_mul_overflow(sll, base));
assert(!check_add_overflow(sll * base, c));
} else {
assert(!check_mul_overflow(ull, base));
assert(!check_add_overflow(ull * base, c));
}
}
ull = ull * base + c;
s++;
}
if (neg)
ull = -ull;
if (endptr)
*endptr = (char *)s;
return ull;
}
long int strtol(const char *nptr, char **endptr, int base)
{
return __strtoll(nptr, endptr, base, true, false);
}
unsigned long int strtoul(const char *nptr, char **endptr, int base)
{
return __strtoll(nptr, endptr, base, false, false);
}
long long int strtoll(const char *nptr, char **endptr, int base)
{
return __strtoll(nptr, endptr, base, true, true);
}
unsigned long long int strtoull(const char *nptr, char **endptr, int base)
{
return __strtoll(nptr, endptr, base, false, true);
}
long atol(const char *ptr)
{
return strtol(ptr, NULL, 10);
}
extern char **environ;
char *getenv(const char *name)
{
char **envp = environ, *delim;
int len;
while (*envp) {
delim = strchr(*envp, '=');
assert(delim);
len = delim - *envp;
if (memcmp(name, *envp, len) == 0 && !name[len])
return delim + 1;
++envp;
}
return NULL;
}
/* Very simple glob matching. Allows '*' at beginning and end of pattern. */
bool simple_glob(const char *text, const char *pattern)
{
bool star_start = false;
bool star_end = false;
size_t n = strlen(pattern);
char copy[n + 1];
if (pattern[0] == '*') {
pattern += 1;
n -= 1;
star_start = true;
}
strcpy(copy, pattern);
if (n > 0 && pattern[n - 1] == '*') {
n -= 1;
copy[n] = '\0';
star_end = true;
}
if (star_start && star_end)
return strstr(text, copy);
if (star_end)
return strstr(text, copy) == text;
if (star_start) {
size_t text_len = strlen(text);
const char *suffix;
if (n > text_len)
return false;
suffix = text + text_len - n;
return !strcmp(suffix, copy);
}
return !strcmp(text, copy);
}