264 lines
6.6 KiB
C
264 lines
6.6 KiB
C
// Small freestanding C runtime subset shared by boot, kernel, drivers, and user support libraries.
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <intrin.h>
|
|
|
|
// Implements the strcpy operation.
|
|
char* strcpy(char* dest, const char* src) {
|
|
char* d = dest;
|
|
while (*src) *d++ = *src++;
|
|
*d = 0;
|
|
return dest;
|
|
}
|
|
|
|
// Implements the strncpy operation.
|
|
char* strncpy(char* dest, const char* src, size_t n) {
|
|
size_t i;
|
|
for (i = 0; i < n && src[i]; i++) dest[i] = src[i];
|
|
for (; i < n; i++) dest[i] = 0;
|
|
return dest;
|
|
}
|
|
|
|
char* strstr(const char* haystack, const char* needle) {
|
|
// An empty needle matches the beginning of haystack
|
|
if (!*needle) {
|
|
return (char*)haystack;
|
|
}
|
|
|
|
for (; *haystack != '\0'; haystack++) {
|
|
const char* h = haystack;
|
|
const char* n = needle;
|
|
|
|
// Match as many characters as possible
|
|
while (*h != '\0' && *n != '\0' && *h == *n) {
|
|
h++;
|
|
n++;
|
|
}
|
|
|
|
// If we reached the end of needle, we found a match
|
|
if (*n == '\0') {
|
|
return (char*)haystack;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Implements the strcat operation.
|
|
char* strcat(char* dest, const char* src) {
|
|
char* ptr = dest;
|
|
while (*ptr != '\0') {
|
|
ptr++;
|
|
}
|
|
while (*src != '\0') {
|
|
*ptr = *src;
|
|
ptr++;
|
|
src++;
|
|
}
|
|
*ptr = '\0';
|
|
return dest;
|
|
}
|
|
|
|
// Implements the strncat operation.
|
|
char* strncat(char* dest, const char* src, size_t n) {
|
|
char* ptr = dest;
|
|
while (*ptr != '\0') {
|
|
ptr++;
|
|
}
|
|
while (n > 0 && *src != '\0') {
|
|
*ptr = *src;
|
|
ptr++;
|
|
src++;
|
|
n--;
|
|
}
|
|
*ptr = '\0';
|
|
return dest;
|
|
}
|
|
|
|
// Implements the strcmp operation.
|
|
int strcmp(const char* s1, const char* s2) {
|
|
while (*s1 && *s1 == *s2) s1++, s2++;
|
|
return (unsigned char)*s1 - (unsigned char)*s2;
|
|
}
|
|
|
|
// Implements the strncmp operation.
|
|
int strncmp(const char* s1, const char* s2, size_t n) {
|
|
while (n && *s1 && (*s1 == *s2)) {
|
|
s1++;
|
|
s2++;
|
|
n--;
|
|
}
|
|
return n == 0 ? 0 : *(unsigned char*)s1 - *(unsigned char*)s2;
|
|
}
|
|
|
|
// Implements the stricmp operation.
|
|
int _stricmp(const char* s1, const char* s2) {
|
|
// ASCII case folding works here because bit 0x20 distinguishes 'A' from 'a'.
|
|
while (*s1 && ((*s1 | 0x20) == (*s2 | 0x20))) {
|
|
s1++, s2++;
|
|
}
|
|
return (unsigned char)(*s1 | 0x20) - (unsigned char)(*s2 | 0x20);
|
|
}
|
|
|
|
// Implements the strlen operation.
|
|
size_t strlen(const char* s) {
|
|
size_t n = 0;
|
|
while (*s++) n++;
|
|
return n;
|
|
}
|
|
|
|
// Implements the strnlen operation.
|
|
size_t strnlen(const char* s, size_t maxlen) {
|
|
size_t len;
|
|
for (len = 0; len < maxlen; len++) {
|
|
if (s[len] == '\0') {
|
|
break;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
// Implements the strchr operation.
|
|
char* strchr(const char* s, int c) {
|
|
while (*s) {
|
|
if (*s == (char)c) return (char*)s;
|
|
s++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Implements the strrchr operation.
|
|
char* strrchr(const char* s, int c) {
|
|
char ch = (char)c;
|
|
const char* last = NULL;
|
|
do {
|
|
if (*s == ch) last = s;
|
|
} while (*s++);
|
|
return (char*)last;
|
|
}
|
|
|
|
void *memchr(const void *s, int c, size_t n) {
|
|
const unsigned char *p = s;
|
|
unsigned char ch = (unsigned char)c;
|
|
while (n--) {
|
|
if (*p == ch) {
|
|
return (void *)p;
|
|
}
|
|
p++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Implements the memset operation.
|
|
void* memset(void* dest, int c, size_t n) {
|
|
unsigned char* d = (unsigned char*)dest;
|
|
size_t qwords = n / 8;
|
|
size_t tail = n % 8;
|
|
|
|
if (qwords > 0) {
|
|
uint64_t value = (unsigned char)c;
|
|
value |= value << 8;
|
|
value |= value << 16;
|
|
value |= value << 32;
|
|
__stosq((unsigned __int64*)d, value, qwords);
|
|
d += qwords * 8;
|
|
}
|
|
|
|
if (tail > 0) {
|
|
__stosb(d, (unsigned char)c, tail);
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
// Implements the memcpy operation.
|
|
void* memcpy(void* dest, const void* src, size_t n) {
|
|
unsigned char* d = (unsigned char*)dest;
|
|
const unsigned char* s = (const unsigned char*)src;
|
|
size_t qwords = n / 8;
|
|
size_t tail = n % 8;
|
|
|
|
if (qwords > 0) {
|
|
__movsq((unsigned __int64*)d, (const unsigned __int64*)s, qwords);
|
|
d += qwords * 8;
|
|
s += qwords * 8;
|
|
}
|
|
|
|
if (tail > 0) {
|
|
__movsb(d, s, tail);
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
// Implements the memmove operation.
|
|
void* memmove(void* dest, const void* src, size_t n) {
|
|
unsigned char* d = (unsigned char*)dest;
|
|
const unsigned char* s = (const unsigned char*)src;
|
|
|
|
if (d < s) {
|
|
// Forward copy: safe to use chunked __movsq + tail.
|
|
size_t qwords = n / 8;
|
|
size_t tail = n % 8;
|
|
if (qwords > 0) {
|
|
__movsq((unsigned __int64*)d, (const unsigned __int64*)s, qwords);
|
|
d += qwords * 8;
|
|
s += qwords * 8;
|
|
}
|
|
if (tail > 0) {
|
|
__movsb(d, s, tail);
|
|
}
|
|
} else if (d > s) {
|
|
// Backward copy: must process from end to avoid corruption.
|
|
size_t qwords = n / 8;
|
|
size_t tail = n % 8;
|
|
|
|
// Copy tail bytes first from the very end.
|
|
if (tail > 0) {
|
|
for (size_t i = tail; i > 0; i--) {
|
|
d[qwords * 8 + i - 1] = s[qwords * 8 + i - 1];
|
|
}
|
|
}
|
|
|
|
// Copy 64-bit chunks backward.
|
|
if (qwords > 0) {
|
|
unsigned __int64* dq = (unsigned __int64*)d;
|
|
const unsigned __int64* sq = (const unsigned __int64*)s;
|
|
for (size_t i = qwords; i > 0; i--) {
|
|
dq[i - 1] = sq[i - 1];
|
|
}
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
// Implements the memcmp operation.
|
|
int memcmp(const void* s1, const void* s2, size_t n) {
|
|
const unsigned __int64* a64 = (const unsigned __int64*)s1;
|
|
const unsigned __int64* b64 = (const unsigned __int64*)s2;
|
|
size_t qwords = n / 8;
|
|
size_t tail = n % 8;
|
|
|
|
// Compare 8-byte blocks.
|
|
for (size_t i = 0; i < qwords; i++) {
|
|
if (a64[i] != b64[i]) {
|
|
// Locate the exact mismatching byte within the quadword.
|
|
const unsigned char* a8 = (const unsigned char*)&a64[i];
|
|
const unsigned char* b8 = (const unsigned char*)&b64[i];
|
|
for (size_t j = 0; j < 8; j++) {
|
|
if (a8[j] != b8[j]) return (int)a8[j] - (int)b8[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compare remaining tail bytes.
|
|
const unsigned char* a8 = (const unsigned char*)(a64 + qwords);
|
|
const unsigned char* b8 = (const unsigned char*)(b64 + qwords);
|
|
for (size_t i = 0; i < tail; i++) {
|
|
if (a8[i] != b8[i]) return (int)a8[i] - (int)b8[i];
|
|
}
|
|
|
|
return 0;
|
|
}
|