278 lines
5.4 KiB
C
278 lines
5.4 KiB
C
|
|
#include <stdbool.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#ifndef __arm__
|
||
|
|
void* memset(void* dest, int fill, size_t nbytes)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < nbytes; ++i)
|
||
|
|
((uint8_t*)dest)[i] = fill;
|
||
|
|
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
#endif //__arm__
|
||
|
|
|
||
|
|
void* memmove(void* dest, const void* src, size_t nbytes)
|
||
|
|
{
|
||
|
|
if (src > dest) {
|
||
|
|
memcpy(dest, src, nbytes);
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = nbytes - 1; i >= 0; --i)
|
||
|
|
((uint8_t*)dest)[i] = ((uint8_t*)src)[i];
|
||
|
|
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* This optimized version of memcpy uses 32 bit chunks to copy over data on
|
||
|
|
the 32 bit architecture this library is built for. If this function gets
|
||
|
|
used on a 64 bit arch, be sure to use 8 byte chunks so each chunk fits
|
||
|
|
in a single register. The important part is this should be compiled with
|
||
|
|
atleast -O1 or -Os, because -O0 just makes this function too big for what
|
||
|
|
it does.
|
||
|
|
|
||
|
|
GCC does a better job at optimizing this if the pointers are restricted,
|
||
|
|
making the copying part have less instructions. Clang on the other hand
|
||
|
|
does not really change anything if the pointers are restricted or not. */
|
||
|
|
void* memcpy(void* __restrict dest, const void* __restrict src, size_t nbytes)
|
||
|
|
{
|
||
|
|
size_t chunks, rest, i;
|
||
|
|
|
||
|
|
rest = nbytes % 4;
|
||
|
|
chunks = (nbytes - rest) >> 2;
|
||
|
|
|
||
|
|
if (!chunks)
|
||
|
|
goto skip_chunks;
|
||
|
|
|
||
|
|
for (i = 0; i < chunks; i++)
|
||
|
|
((uint32_t*)dest)[i] = ((uint32_t*)src)[i];
|
||
|
|
|
||
|
|
skip_chunks:
|
||
|
|
|
||
|
|
/* Multiplying chunks by 4 will give us the offset of the 'rest' bytes,
|
||
|
|
which were not copied over along with the 4 byte chunks. */
|
||
|
|
chunks <<= 2;
|
||
|
|
|
||
|
|
for (i = 0; i < rest; i++)
|
||
|
|
((uint8_t*)dest)[chunks + i] = ((uint8_t*)src)[chunks + i];
|
||
|
|
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
void* memccpy(void* dest, const void* src, int stop, size_t nbytes)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < nbytes; i++) {
|
||
|
|
*((uint8_t*)dest + i) = *((uint8_t*)src + i);
|
||
|
|
|
||
|
|
if (*((uint8_t*)src + i) == stop)
|
||
|
|
return ((uint8_t*)dest + i + 1);
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
int memcmp(const void* src1, const void* src2, size_t nbytes)
|
||
|
|
{
|
||
|
|
const uint8_t* first = src1;
|
||
|
|
const uint8_t* second = src2;
|
||
|
|
|
||
|
|
for (int i = 0; i < nbytes; i++) {
|
||
|
|
/* Return the difference if the byte does not match. */
|
||
|
|
if (first[i] != second[i])
|
||
|
|
return (int)first[i] - (int)second[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void* memchr(const void* ptr, int c, size_t size)
|
||
|
|
{
|
||
|
|
char ch = c;
|
||
|
|
const char* cptr = (const char*)ptr;
|
||
|
|
for (size_t i = 0; i < size; i++) {
|
||
|
|
if (cptr[i] == ch) {
|
||
|
|
return (char*)(cptr + i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
int strcmp(const char* a, const char* b)
|
||
|
|
{
|
||
|
|
while (*a == *b && *a != '\0' && *b != '\0') {
|
||
|
|
a++;
|
||
|
|
b++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (*a < *b) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (*a > *b) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int strncmp(const char* a, const char* b, size_t num)
|
||
|
|
{
|
||
|
|
while (*a == *b && *a != 0 && *b != 0 && num) {
|
||
|
|
a++;
|
||
|
|
b++;
|
||
|
|
num--;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!num) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (*a < *b) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (*a > *b) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t strlen(const char* str)
|
||
|
|
{
|
||
|
|
size_t i = 0;
|
||
|
|
while (str[i])
|
||
|
|
++i;
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strcpy(char* dest, const char* src)
|
||
|
|
{
|
||
|
|
size_t i;
|
||
|
|
for (i = 0; src[i] != 0; i++)
|
||
|
|
dest[i] = src[i];
|
||
|
|
|
||
|
|
dest[i] = '\0';
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strncpy(char* dest, const char* src, size_t nbytes)
|
||
|
|
{
|
||
|
|
size_t i;
|
||
|
|
|
||
|
|
for (i = 0; i < nbytes && src[i] != 0; i++)
|
||
|
|
dest[i] = src[i];
|
||
|
|
|
||
|
|
/* Fill the rest with null bytes */
|
||
|
|
for (; i < nbytes; i++)
|
||
|
|
dest[i] = 0;
|
||
|
|
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strchr(const char* s, int c)
|
||
|
|
{
|
||
|
|
for (;; s++) {
|
||
|
|
if (*s == c) {
|
||
|
|
return (char*)s;
|
||
|
|
}
|
||
|
|
if (!(*s)) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strtok_r(char* str, const char* delim, char** saveptr)
|
||
|
|
{
|
||
|
|
if (!str) {
|
||
|
|
if (!saveptr) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
str = *saveptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t start = 0;
|
||
|
|
size_t end = 0;
|
||
|
|
size_t n = strlen(str);
|
||
|
|
size_t m = strlen(delim);
|
||
|
|
bool ok = false;
|
||
|
|
|
||
|
|
for (size_t i = 0; i < n; i++) {
|
||
|
|
ok = false;
|
||
|
|
for (size_t j = 0; j < m; j++) {
|
||
|
|
if (str[i] == delim[j]) {
|
||
|
|
if (end - start == 0) {
|
||
|
|
start++;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
ok = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ok) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
end++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (str[start] == '\0') {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (end == 0) {
|
||
|
|
*saveptr = NULL;
|
||
|
|
return &str[start];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (str[end] == '\0') {
|
||
|
|
*saveptr = &str[end];
|
||
|
|
} else {
|
||
|
|
*saveptr = &str[end + 1];
|
||
|
|
}
|
||
|
|
|
||
|
|
str[end] = '\0';
|
||
|
|
return &str[start];
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strtok(char* str, const char* delim)
|
||
|
|
{
|
||
|
|
static char* saveptr;
|
||
|
|
return strtok_r(str, delim, &saveptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strstr(const char* haystack, const char* needle)
|
||
|
|
{
|
||
|
|
size_t n = strlen(needle);
|
||
|
|
|
||
|
|
while (*haystack) {
|
||
|
|
if (!memcmp(haystack, needle, n)) {
|
||
|
|
return (char*)haystack;
|
||
|
|
}
|
||
|
|
haystack++;
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strcat(char* dest, const char* src)
|
||
|
|
{
|
||
|
|
size_t dest_len = strlen(dest);
|
||
|
|
size_t i = 0;
|
||
|
|
|
||
|
|
while (src[i] != '\0') {
|
||
|
|
dest[dest_len + i] = src[i];
|
||
|
|
i++;
|
||
|
|
}
|
||
|
|
dest[dest_len + i] = '\0';
|
||
|
|
return dest;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* strrchr(const char* str, int ch)
|
||
|
|
{
|
||
|
|
char c;
|
||
|
|
char* last = NULL;
|
||
|
|
|
||
|
|
while ((c = *str)) {
|
||
|
|
if (c == ch) {
|
||
|
|
last = (char*)(str);
|
||
|
|
}
|
||
|
|
str++;
|
||
|
|
}
|
||
|
|
return last;
|
||
|
|
}
|