summaryrefslogtreecommitdiff
path: root/kernel/lib/string.cpp
blob: 1365147fd52a29b53badcfac045713570f12e8df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// ============================================================================
// lib/string.cpp - Freestanding memory and string operations
//
// These are required because we compile with -nostdlib.
// The compiler may generate implicit calls to memcpy/memset/memmove
// (e.g., for struct copies, array init), so these must exist with
// standard C linkage and standard names.
// ============================================================================

#include <stdint.h>
#include <stddef.h>

extern "C" {

void* memcpy(void* dest, const void* src, size_t n) {
    auto* d = static_cast<uint8_t*>(dest);
    auto* s = static_cast<const uint8_t*>(src);
    for (size_t i = 0; i < n; i++) d[i] = s[i];
    return dest;
}

void* memmove(void* dest, const void* src, size_t n) {
    auto* d = static_cast<uint8_t*>(dest);
    auto* s = static_cast<const uint8_t*>(src);
    if (d < s) {
        for (size_t i = 0; i < n; i++) d[i] = s[i];
    } else {
        for (size_t i = n; i > 0; i--) d[i - 1] = s[i - 1];
    }
    return dest;
}

void* memset(void* dest, int val, size_t n) {
    auto* d = static_cast<uint8_t*>(dest);
    for (size_t i = 0; i < n; i++) d[i] = static_cast<uint8_t>(val);
    return dest;
}

int memcmp(const void* s1, const void* s2, size_t n) {
    auto* a = static_cast<const uint8_t*>(s1);
    auto* b = static_cast<const uint8_t*>(s2);
    for (size_t i = 0; i < n; i++) {
        // Cast to int before subtracting: uint8_t → int is safe, range [0, 255]
        if (a[i] != b[i]) return static_cast<int>(a[i]) - static_cast<int>(b[i]);
    }
    return 0;
}

size_t strlen(const char* s) {
    size_t len = 0;
    while (s[len]) len++;
    return len;
}

int strcmp(const char* s1, const char* s2) {
    // Cast to unsigned before comparison — char may be signed,
    // and unsigned subtraction gives the correct lexicographic ordering.
    const auto* u1 = reinterpret_cast<const uint8_t*>(s1);
    const auto* u2 = reinterpret_cast<const uint8_t*>(s2);
    while (*u1 && *u1 == *u2) { ++u1; ++u2; }
    return static_cast<int>(*u1) - static_cast<int>(*u2);
}

char* strcpy(char* dest, const char* src) {
    char* ret = dest;
    while (*src) *dest++ = *src++;
    *dest = '\0';
    return ret;
}

char* strncpy(char* dest, const char* src, size_t n) {
    size_t i = 0;
    for (; i < n && src[i]; i++) dest[i] = src[i];
    for (; i < n; i++) dest[i] = '\0';
    return dest;
}

void* memchr(const void* s, int c, size_t n) {
    auto* p = static_cast<const uint8_t*>(s);
    auto uc = static_cast<uint8_t>(c);
    for (size_t i = 0; i < n; i++)
        if (p[i] == uc) return const_cast<void*>(static_cast<const void*>(p + i));
    return nullptr;
}

int strncmp(const char* s1, const char* s2, size_t n) {
    const auto* u1 = reinterpret_cast<const uint8_t*>(s1);
    const auto* u2 = reinterpret_cast<const uint8_t*>(s2);
    for (size_t i = 0; i < n; i++) {
        if (u1[i] != u2[i]) return static_cast<int>(u1[i]) - static_cast<int>(u2[i]);
        if (u1[i] == 0) break;
    }
    return 0;
}

} // extern "C"