mirror of
https://github.com/google/nanolibc.git
synced 2025-10-19 09:51:49 +08:00
300 lines
6.0 KiB
C
300 lines
6.0 KiB
C
// Copyright 2022 Google LLC.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/*
|
|
* Implementation of libC string.h functions.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* These are weak symbols, so that we continue using gnu-efi's version
|
|
* when we link against it */
|
|
int memcmp(const void *p1, const void *p2, size_t n)
|
|
__attribute__ ((weak));
|
|
void *memcpy(void *dstpp, const void *srcpp, size_t n)
|
|
__attribute__ ((weak));
|
|
void *memmove(void *dstpp, const void *srcpp, size_t n)
|
|
__attribute__ ((weak));
|
|
void *memset(void *dstpp, int c, size_t n)
|
|
__attribute__ ((weak));
|
|
|
|
/* Highly NON optimized, but simple */
|
|
int memcmp(const void *p1, const void *p2, size_t n) {
|
|
const char *s1 = p1;
|
|
const char *s2 = p2;
|
|
|
|
while (n > 0) {
|
|
if (*s1 != *s2) return *s1 - *s2;
|
|
|
|
s1++;
|
|
s2++;
|
|
n--;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Highly NON optimized, but simple */
|
|
void *memcpy(void *dstpp, const void *srcpp, size_t n) {
|
|
char *d = dstpp;
|
|
const char *s = srcpp;
|
|
|
|
while (n > 0) {
|
|
*d++ = *s++;
|
|
n--;
|
|
}
|
|
|
|
return dstpp;
|
|
}
|
|
|
|
/* Highly NON optimized, but simple */
|
|
void *memmove(void *dstpp, const void *srcpp, size_t n) {
|
|
if (dstpp <= srcpp) {
|
|
return memcpy(dstpp, srcpp, n);
|
|
}
|
|
char *d = dstpp + n;
|
|
const char *s = srcpp + n;
|
|
|
|
while (n > 0) {
|
|
*--d = *--s;
|
|
n--;
|
|
}
|
|
|
|
return dstpp;
|
|
}
|
|
|
|
/* Highly NON optimized, but simple */
|
|
void *memset(void *dstpp, int c, size_t n) {
|
|
char *d = dstpp;
|
|
|
|
while (n > 0) {
|
|
*d++ = c;
|
|
n--;
|
|
}
|
|
|
|
return dstpp;
|
|
}
|
|
|
|
const void *rawmemchr(const void *spp, int c) {
|
|
const unsigned char *s = spp;
|
|
|
|
while (*s != (unsigned char)c) s++;
|
|
|
|
return s;
|
|
}
|
|
|
|
void *memchr(const void *spp, int c, size_t n) {
|
|
const unsigned char *s = spp;
|
|
|
|
while (n-- != 0) {
|
|
if (*s == (unsigned char)c) {
|
|
return (void*)s;
|
|
}
|
|
s++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int strcmp(const char *p1, const char *p2) {
|
|
const unsigned char *s1 = (const unsigned char *)p1;
|
|
const unsigned char *s2 = (const unsigned char *)p2;
|
|
|
|
while (1) {
|
|
const unsigned char c1 = *s1++;
|
|
const unsigned char c2 = *s2++;
|
|
if ((c1 == '\0') || (c1 != c2)) return (c1 - c2);
|
|
}
|
|
|
|
/* not reached */
|
|
return 0;
|
|
}
|
|
|
|
/* Highly NON optimized, but simple */
|
|
int strncmp(const char *p1, const char *p2, size_t n) {
|
|
const unsigned char *s1 = (const unsigned char *)p1;
|
|
const unsigned char *s2 = (const unsigned char *)p2;
|
|
|
|
while (n > 0) {
|
|
const unsigned char c1 = *s1++;
|
|
const unsigned char c2 = *s2++;
|
|
if ((c1 == '\0') || (c1 != c2)) return (c1 - c2);
|
|
n--;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *strcpy(char *dest, const char *src) {
|
|
char *d = dest;
|
|
const char *s = src;
|
|
|
|
while (*s) *d++ = *s++;
|
|
|
|
*d = '\0';
|
|
return dest;
|
|
}
|
|
|
|
/* strncpy borrowed from Linux man pages 3.35 */
|
|
char *strncpy(char *dest, const char *src, size_t n) {
|
|
size_t i;
|
|
|
|
for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i];
|
|
for (; i < n; i++) dest[i] = '\0';
|
|
|
|
return dest;
|
|
}
|
|
|
|
/* Highly NON optimized, but simple */
|
|
size_t strlen(const char *s) {
|
|
size_t i;
|
|
for (i = 0; *s; ++s, ++i) continue;
|
|
return i;
|
|
}
|
|
|
|
char *strchr(const char *s, int i) {
|
|
for (; *s; ++s)
|
|
if (*s == i) return (char *)s;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *strrchr(const char *s, int i) {
|
|
const char *last = NULL;
|
|
|
|
for (; *s; ++s)
|
|
if (*s == i) last = s;
|
|
|
|
return (char *)last;
|
|
}
|
|
|
|
const char *strstr(const char *haystack, const char *needle) {
|
|
const char *h = haystack;
|
|
const char *n = needle;
|
|
const char *found = NULL;
|
|
|
|
if (*needle == '\0') return haystack;
|
|
|
|
while (*h) {
|
|
if ((found != NULL) && (*h != *n)) {
|
|
found = NULL;
|
|
n = needle;
|
|
}
|
|
|
|
if (*h == *n) {
|
|
if (found == NULL) found = h;
|
|
n++;
|
|
if (*n == '\0') return found;
|
|
}
|
|
|
|
h++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* strspn borrowed from eglibc 2.17 */
|
|
size_t strspn(const char *s, const char *accept) {
|
|
const char *p;
|
|
const char *a;
|
|
size_t count = 0;
|
|
|
|
for (p = s; *p != '\0'; ++p) {
|
|
for (a = accept; *a != '\0'; ++a)
|
|
if (*p == *a) break;
|
|
if (*a == '\0')
|
|
return count;
|
|
else
|
|
++count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/* Naive O(M*N) implementation, good enough if "accept" is small */
|
|
const char *strpbrk(const char *s, const char *accept) {
|
|
while (*s != '\0') {
|
|
const char *a = accept;
|
|
while (*a != '\0')
|
|
if (*a++ == *s) return s;
|
|
++s;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* strtok_r borrowed from eglibc 2.17's strtok */
|
|
char *strtok_r(char *s, const char *delim, char **saveptr) {
|
|
char *token;
|
|
|
|
if (s == NULL) s = *saveptr;
|
|
|
|
/* Scan leading delimiters. */
|
|
s += strspn(s, delim);
|
|
if (*s == '\0') {
|
|
*saveptr = s;
|
|
return NULL;
|
|
}
|
|
|
|
/* Find the end of the token. */
|
|
token = s;
|
|
s = (char *)strpbrk(token, delim);
|
|
if (s == NULL) {
|
|
/* This token finishes the string. */
|
|
*saveptr = (char *)rawmemchr(token, '\0');
|
|
} else {
|
|
/* Terminate the token and make *saveptr point past it. */
|
|
*s = '\0';
|
|
*saveptr = s + 1;
|
|
}
|
|
return token;
|
|
}
|
|
|
|
char *strtok(char *s, const char *delim) {
|
|
static char *global_saveptr = NULL;
|
|
return strtok_r(s, delim, &global_saveptr);
|
|
}
|
|
|
|
char *strdup(const char *s) {
|
|
const size_t len = strlen(s);
|
|
char *result = malloc(len+1);
|
|
if (NULL != result) {
|
|
strcpy(result, s);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
char *strndup(const char *s, size_t n) {
|
|
size_t len = strlen(s);
|
|
if (n < len) {
|
|
len = n;
|
|
}
|
|
char *result = malloc(len+1);
|
|
if (NULL != result) {
|
|
memcpy(result, s, len);
|
|
result[len] = '\0';
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int errno = 0; /* NOT MT-aware/MT-safe */
|
|
|
|
char *strerror(int errnum) {
|
|
if (errnum == 0) return "no error";
|
|
return "unexpected error";
|
|
}
|