400 lines
8.0 KiB
C
400 lines
8.0 KiB
C
|
// Copyright (c) 2025, Zak Fenton
|
||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||
|
// http://license.coscl.org.cn/MulanPSL2
|
||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||
|
// any kind, either express or implied, including but not limited to
|
||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||
|
// See the Mulan PSL v2 for more details.
|
||
|
|
||
|
// For auditing purposes, this is NEW CODE
|
||
|
|
||
|
#ifdef KERNEL_MODE
|
||
|
#define size_t long
|
||
|
#define NULL ((void*)0ULL)
|
||
|
#else
|
||
|
#include <string.h>
|
||
|
#include "internal.h"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//ifdef _ZCC
|
||
|
#ifdef NOT_USED_YET
|
||
|
/* Works like memset except assumes n is a multiple of 8 and src>=dst+8.
|
||
|
* Doesn't return a useful value.
|
||
|
*/
|
||
|
void __naked memset_quick64(void* dst, uint64 v, uint64 n) __asm {
|
||
|
add a3, a0, a2
|
||
|
.setloop:
|
||
|
sd a1, 0(a0)
|
||
|
addi a0, a0, 8
|
||
|
bne a0, a3, .setloop
|
||
|
ret
|
||
|
}
|
||
|
void __naked memset_quick(void* dst, uint64 v, uint64 n) __asm {
|
||
|
add a3, a0, a2
|
||
|
.setloopa:
|
||
|
sb a1, 0(a0)
|
||
|
addi a0, a0, 1
|
||
|
bne a0, a3, .setloopa
|
||
|
ret
|
||
|
}
|
||
|
void* __naked memset_opt(void* dst, uint64 v, uint64 n) __asm {
|
||
|
add a3, a0, a2
|
||
|
add a4, a0, zero
|
||
|
beq a2, zero, .endopt
|
||
|
addi a6, zero, 16
|
||
|
blt a2, a6, .setloopoptshort
|
||
|
addi a6, zero, 128
|
||
|
blt a6, a2, .setloopoptlong
|
||
|
.setloopopt:
|
||
|
sb a1, 0(a4)
|
||
|
addi a4, a4, 1
|
||
|
andi a5, a4, 7
|
||
|
beq a5, zero, .setloopopt64
|
||
|
.setloopstartopt:
|
||
|
bne a4, a3, .setloopopt
|
||
|
.endopt:
|
||
|
ret
|
||
|
.setloopoptshort:
|
||
|
sb a1, 0(a4)
|
||
|
addi a4, a4, 1
|
||
|
bne a4, a3, .setloopoptshort
|
||
|
ret
|
||
|
.setloopopt64adjust:
|
||
|
addi a3, a3, -1
|
||
|
sb a1, 0(a3)
|
||
|
.setloopopt64:
|
||
|
bne a1, zero, .setloopstartopt
|
||
|
andi a6, a3, 7
|
||
|
bne a6, zero, .setloopopt64adjust
|
||
|
//addi a6, zero, 8
|
||
|
.setloopopt64b:
|
||
|
//sub a5, a3, a4
|
||
|
//blt a5, a6, .setloopstartopt
|
||
|
sd a1, 0(a4)
|
||
|
addi a4, a4, 8
|
||
|
blt a4, a3, .setloopopt64b
|
||
|
//j .setloopstartopt
|
||
|
ret
|
||
|
.setloopoptlong:
|
||
|
bne a1, zero, .setloopstartopt
|
||
|
andi a6, a2, 127
|
||
|
bne a6, zero, .setloopstartopt
|
||
|
.setloopoptlongb:
|
||
|
sd zero, 0(a4)
|
||
|
sd zero, 8(a4)
|
||
|
sd zero, 16(a4)
|
||
|
sd zero, 24(a4)
|
||
|
sd zero, 32(a4)
|
||
|
sd zero, 40(a4)
|
||
|
sd zero, 48(a4)
|
||
|
sd zero, 56(a4)
|
||
|
sd zero, 64(a4)
|
||
|
sd zero, 72(a4)
|
||
|
sd zero, 80(a4)
|
||
|
sd zero, 88(a4)
|
||
|
sd zero, 96(a4)
|
||
|
sd zero, 104(a4)
|
||
|
sd zero, 112(a4)
|
||
|
sd zero, 120(a4)
|
||
|
addi a4, a4, 128
|
||
|
bne a4, a3, .setloopoptlongb
|
||
|
ret
|
||
|
}
|
||
|
void* __naked memcpy_opt(void* dst, void* src, uint64 n) __asm {
|
||
|
add a3, a0, a2
|
||
|
add a4, a0, zero
|
||
|
beq a2, zero, .endcpy
|
||
|
addi a6, zero, 16
|
||
|
blt a2, a6, .cpyloopoptshort
|
||
|
addi a6, zero, 128
|
||
|
blt a6, a2, .cpyloopoptlong
|
||
|
.cpyloopopt:
|
||
|
lb a6, 0(a1)
|
||
|
sb a6, 0(a4)
|
||
|
addi a4, a4, 1
|
||
|
addi a1, a1, 1
|
||
|
andi a5, a4, 7
|
||
|
beq a5, zero, .cpyloopopt64
|
||
|
.cpyloopstartopt:
|
||
|
bne a4, a3, .cpyloopopt
|
||
|
.endcpy:
|
||
|
ret
|
||
|
.cpyloopoptshort:
|
||
|
lb a6, 0(a1)
|
||
|
sb a6, 0(a4)
|
||
|
addi a4, a4, 1
|
||
|
addi a1, a1, 1
|
||
|
bne a4, a3, .cpyloopoptshort
|
||
|
ret
|
||
|
.cpyloopopt64adjust:
|
||
|
addi a3, a3, -1
|
||
|
sub a5, a3, a4
|
||
|
add a5, a5, a1
|
||
|
lb a6, 0(a5)
|
||
|
sb a6, 0(a3)
|
||
|
.cpyloopopt64:
|
||
|
andi a6, a3, 7
|
||
|
bne a6, zero, .cpyloopopt64adjust
|
||
|
//addi a6, zero, 8
|
||
|
.cpyloopopt64b:
|
||
|
//sub a5, a3, a4
|
||
|
//blt a5, a6, .setloopstartopt
|
||
|
ld a6, 0(a1)
|
||
|
sd a6, 0(a4)
|
||
|
addi a4, a4, 8
|
||
|
addi a1, a1, 8
|
||
|
blt a4, a3, .cpyloopopt64b
|
||
|
//j .setloopstartopt
|
||
|
ret
|
||
|
.cpyloopoptlong:
|
||
|
andi a6, a2, 127
|
||
|
bne a6, zero, .cpyloopstartopt
|
||
|
.cpyloopoptlongb:
|
||
|
ld a6, 0(a1)
|
||
|
sd a6, 0(a4)
|
||
|
ld a6, 8(a1)
|
||
|
sd a6, 8(a4)
|
||
|
ld a6, 16(a1)
|
||
|
sd a6, 16(a4)
|
||
|
ld a6, 24(a1)
|
||
|
sd a6, 24(a4)
|
||
|
ld a6, 32(a1)
|
||
|
sd a6, 32(a4)
|
||
|
ld a6, 40(a1)
|
||
|
sd a6, 40(a4)
|
||
|
ld a6, 48(a1)
|
||
|
sd a6, 48(a4)
|
||
|
ld a6, 56(a1)
|
||
|
sd a6, 56(a4)
|
||
|
ld a6, 64(a1)
|
||
|
sd a6, 64(a4)
|
||
|
ld a6, 72(a1)
|
||
|
sd a6, 72(a4)
|
||
|
ld a6, 80(a1)
|
||
|
sd a6, 80(a4)
|
||
|
ld a6, 88(a1)
|
||
|
sd a6, 88(a4)
|
||
|
ld a6, 96(a1)
|
||
|
sd a6, 96(a4)
|
||
|
ld a6, 104(a1)
|
||
|
sd a6, 104(a4)
|
||
|
ld a6, 112(a1)
|
||
|
sd a6, 112(a4)
|
||
|
ld a6, 120(a1)
|
||
|
sd a6, 120(a4)
|
||
|
addi a4, a4, 128
|
||
|
addi a1, a1, 128
|
||
|
bne a4, a3, .cpyloopoptlongb
|
||
|
ret
|
||
|
}
|
||
|
// Works like memcpy except assumes n is a multiple of 8 and src>=dst+8.
|
||
|
// Doesn't return a useful value.
|
||
|
void __naked memcpy_quick64(void* dst, void* src, uint64 n) __asm {
|
||
|
add a3, a0, a2
|
||
|
.cpyloop:
|
||
|
ld a4, 0(a1)
|
||
|
addi a1, a1, 8
|
||
|
sd a4, 0(a0)
|
||
|
addi a0, a0, 8
|
||
|
bne a0, a3, .cpyloop
|
||
|
ret
|
||
|
}
|
||
|
// Expands a byte to a word.
|
||
|
uint64 __naked expandbyte_quick64(int b) __asm {
|
||
|
andi a1, a0, 255
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
slli a0, a0, 8
|
||
|
or a0, a0, a1
|
||
|
ret
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Copied from my preexisting number parser in numbered.c
|
||
|
unsigned long long _libc_scandec(const char** strvar) {
|
||
|
unsigned long long val = 0;
|
||
|
const char* s = *strvar;
|
||
|
char c;
|
||
|
while ((c = *s) >= '0' && c <= '9') {
|
||
|
unsigned long long oldval = val;
|
||
|
val = val * 10 + c - '0';
|
||
|
if (val / 10 != oldval) {
|
||
|
return 0;
|
||
|
}
|
||
|
s++;
|
||
|
}
|
||
|
|
||
|
*strvar = s;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
long long atoll(const char* str) {
|
||
|
if (*str == '-') {
|
||
|
str++;
|
||
|
long long x = (long long) _libc_scandec(&str);
|
||
|
return -x;
|
||
|
} else if (*str == '+') {
|
||
|
str++;
|
||
|
return (long long) _libc_scandec(&str);
|
||
|
} else {
|
||
|
return (long long) _libc_scandec(&str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long atol(const char* str) {
|
||
|
return (long) atoll(str);
|
||
|
}
|
||
|
|
||
|
int atoi(const char* str) {
|
||
|
return (int) atoll(str);
|
||
|
}
|
||
|
|
||
|
size_t strlen(const char* foo) {
|
||
|
if (foo == NULL) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
size_t i = 0;
|
||
|
while (foo[i] != 0) i++;
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void* memcpy(void* dst, const void* src, size_t nbytes) {
|
||
|
char* cdst = (char*) dst;
|
||
|
const char* csrc = (char*) src;
|
||
|
size_t i = 0;
|
||
|
for (i = 0; i < nbytes; i++) {
|
||
|
cdst[i] = csrc[i];
|
||
|
}
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
void* memset(void* mem, int byt, size_t nbytes) {
|
||
|
char* tmp = mem;
|
||
|
for (size_t i = 0; i < nbytes; i++) {
|
||
|
tmp[i] = (char) byt;
|
||
|
}
|
||
|
return mem;
|
||
|
}
|
||
|
|
||
|
int strcmp(const char* a, const char* b) {
|
||
|
while (*a == *b) {
|
||
|
if (*a == 0) {
|
||
|
return 0; // Got to the end, strings are equal
|
||
|
}
|
||
|
a++;
|
||
|
b++;
|
||
|
}
|
||
|
return *a - *b;
|
||
|
}
|
||
|
|
||
|
char* strcat(char* dst, const char* src) {
|
||
|
char* end = dst;
|
||
|
while (*end) { // Find the terminating zero of the dst string
|
||
|
end++;
|
||
|
}
|
||
|
while (*src) { // Overwrite the end of dst from src until it's terminating zero
|
||
|
*end++ = *src++;
|
||
|
}
|
||
|
*end = 0; // Add terminating zero back to dst
|
||
|
return dst; // Return the start of the dst string
|
||
|
}
|
||
|
|
||
|
char* strcpy(char *dst, const char* src) {
|
||
|
char *d = dst;
|
||
|
while (*src) {
|
||
|
*d++ = *src++;
|
||
|
}
|
||
|
*d = 0;
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
char* strncpy(char* dst, const char* src, size_t n) {
|
||
|
size_t i = 0;
|
||
|
char *d = dst;
|
||
|
while (*src) {
|
||
|
*d++ = *src++;
|
||
|
i++;
|
||
|
}
|
||
|
while (i < n) { // TODO: Is this right??
|
||
|
dst[i] = 0;
|
||
|
i++;
|
||
|
}
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
#ifndef KERNEL_MODE
|
||
|
char* strdup(const char* src) {
|
||
|
char* result = malloc(strlen(src) + 1);
|
||
|
if (result) {
|
||
|
strcpy(result, src);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
char* strndup(const char* str, size_t n) {
|
||
|
size_t resultlen = strlen(str);
|
||
|
if (resultlen > n) {
|
||
|
resultlen = n;
|
||
|
}
|
||
|
char* result = malloc(resultlen + 1);
|
||
|
if (result) {
|
||
|
for (size_t i = 0; i < resultlen; i++) {
|
||
|
result[i] = str[i];
|
||
|
}
|
||
|
str[resultlen] = 0;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
const char* strpbrk(const char* str, const char* search) {
|
||
|
char c;
|
||
|
while ((c = *str)) {
|
||
|
const char* s = search;
|
||
|
while (*s++) {
|
||
|
if (c == *s) {
|
||
|
return str;
|
||
|
}
|
||
|
}
|
||
|
str++;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
char *strchr(const char* str, int chr) {
|
||
|
int c;
|
||
|
while ((c = *str)) {
|
||
|
if (c == chr) {
|
||
|
return (char*) str;
|
||
|
}
|
||
|
str++;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
char *strrchr(const char* str, int chr) {
|
||
|
int c;
|
||
|
char* result = NULL;
|
||
|
while ((c = *str)) {
|
||
|
if (c == chr) {
|
||
|
result = (char*) str;
|
||
|
}
|
||
|
str++;
|
||
|
}
|
||
|
return result;
|
||
|
}
|