boredos_mirror/src/kernel/userland/libc/stdlib.c
boreddevnl 659feee6f7 LwIP
2026-03-02 12:12:23 +01:00

290 lines
6.6 KiB
C

#include "stdlib.h"
#include "syscall.h"
// Simple block allocator over sys_sbrk
typedef struct BlockMeta {
size_t size;
int free;
struct BlockMeta *next;
} BlockMeta;
#define META_SIZE sizeof(BlockMeta)
static void *global_base = NULL;
static BlockMeta *find_free_block(BlockMeta **last, size_t size) {
BlockMeta *current = global_base;
while (current && !(current->free && current->size >= size)) {
*last = current;
current = current->next;
}
return current;
}
static BlockMeta *request_space(BlockMeta* last, size_t size) {
BlockMeta *block;
block = (BlockMeta *)sys_sbrk(0);
size_t align = 8;
if (size % align != 0) {
size += align - (size % align);
}
void *request = sys_sbrk(size + META_SIZE);
if (request == (void*)-1) {
return NULL; // sbrk failed
}
if (last) { // NULL on first request
last->next = block;
}
block->size = size;
block->next = NULL;
block->free = 0;
return block;
}
void *malloc(size_t size) {
BlockMeta *block;
if (size <= 0) {
return NULL;
}
// Align size to 8 bytes for safety
size_t align = 8;
if (size % align != 0) {
size += align - (size % align);
}
if (!global_base) { // First call
block = request_space(NULL, size);
if (!block) return NULL;
global_base = block;
} else {
BlockMeta *last = global_base;
block = find_free_block(&last, size);
if (!block) { // Failed to find free block
block = request_space(last, size);
if (!block) return NULL;
} else { // Found free block
block->free = 0;
}
}
return (block + 1);
}
void free(void *ptr) {
if (!ptr) {
return;
}
BlockMeta *block = (BlockMeta*)ptr - 1;
block->free = 1;
}
void *calloc(size_t nelem, size_t elsize) {
size_t size = nelem * elsize;
void *ptr = malloc(size);
if (ptr) {
char *p = ptr;
for (size_t i = 0; i < size; i++) {
p[i] = 0;
}
}
return ptr;
}
void *realloc(void *ptr, size_t size) {
if (!ptr) {
return malloc(size);
}
if (size == 0) {
free(ptr);
return NULL;
}
BlockMeta *block = (BlockMeta*)ptr - 1;
if (block->size >= size) {
return ptr;
}
void *new_ptr = malloc(size);
if (!new_ptr) {
return NULL;
}
char *src = ptr;
char *dst = new_ptr;
for (size_t i = 0; i < block->size; i++) {
dst[i] = src[i];
}
free(ptr);
return new_ptr;
}
void *memset(void *s, int c, size_t n) {
unsigned char *p = (unsigned char *)s;
while (n--) *p++ = (unsigned char)c;
return s;
}
void *memcpy(void *dest, const void *src, size_t n) {
unsigned char *d = (unsigned char *)dest;
const unsigned char *s = (const unsigned char *)src;
while (n--) *d++ = *s++;
return dest;
}
// String functions
size_t strlen(const char *s) {
size_t len = 0;
while (s[len]) len++;
return len;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
char* strcpy(char *dest, const char *src) {
char *ret = dest;
while (*src) *dest++ = *src++;
*dest = 0;
return ret;
}
char* strcat(char *dest, const char *src) {
char *ret = dest;
while (*dest) dest++;
while (*src) *dest++ = *src++;
*dest = 0;
return ret;
}
int atoi(const char *nptr) {
int res = 0;
int sign = 1;
if (*nptr == '-') {
sign = -1;
nptr++;
}
while (*nptr >= '0' && *nptr <= '9') {
res = res * 10 + (*nptr - '0');
nptr++;
}
return sign * res;
}
void itoa(int n, char *buf) {
if (n == 0) {
buf[0] = '0'; buf[1] = 0; return;
}
int i = 0;
int sign = n < 0;
if (sign) n = -n;
while (n > 0) {
buf[i++] = (n % 10) + '0';
n /= 10;
}
if (sign) buf[i++] = '-';
buf[i] = 0;
// Reverse
for (int j = 0; j < i / 2; j++) {
char t = buf[j];
buf[j] = buf[i - 1 - j];
buf[i - 1 - j] = t;
}
}
// IO functions
void puts(const char *s) {
sys_write(1, s, strlen(s));
sys_write(1, "\n", 1);
}
void printf(const char *fmt, ...) {
__builtin_va_list args;
__builtin_va_start(args, fmt);
char buf[1024];
int buf_idx = 0;
while (*fmt) {
if (*fmt == '%') {
fmt++;
// Flush current buffer
if (buf_idx > 0) {
sys_write(1, buf, buf_idx);
buf_idx = 0;
}
if (*fmt == 's') {
char *s = __builtin_va_arg(args, char *);
if (s) sys_write(1, s, strlen(s));
else sys_write(1, "(null)", 6);
} else if (*fmt == 'd') {
int d = __builtin_va_arg(args, int);
char ibuf[32];
itoa(d, ibuf);
sys_write(1, ibuf, strlen(ibuf));
} else if (*fmt == 'X' || *fmt == 'x') {
uint32_t val = __builtin_va_arg(args, uint32_t);
char xbuf[16];
int xi = 0;
if (val == 0) xbuf[xi++] = '0';
else {
while (val > 0) {
uint32_t rem = val % 16;
xbuf[xi++] = (rem < 10) ? (rem + '0') : (rem - 10 + 'A');
val /= 16;
}
}
while (xi > 0) {
char c = xbuf[--xi];
sys_write(1, &c, 1);
}
} else if (*fmt == 'c') {
char c = (char)__builtin_va_arg(args, int);
sys_write(1, &c, 1);
} else if (*fmt == '%') {
char c = '%';
sys_write(1, &c, 1);
}
} else {
buf[buf_idx++] = *fmt;
if (buf_idx >= 1024) {
sys_write(1, buf, buf_idx);
buf_idx = 0;
}
}
fmt++;
}
if (buf_idx > 0) {
sys_write(1, buf, buf_idx);
}
__builtin_va_end(args);
}
// System/Process functions
int chdir(const char *path) {
return sys_chdir(path);
}
char* getcwd(char *buf, int size) {
if (sys_getcwd(buf, size) == 0) return buf;
return NULL;
}
void sleep(int ms) {
// We don't have a sleep syscall yet, so we'll just busy wait for now or skip
// Actually, BoredOS doesn't seem to have a sleep syscall.
// I'll add one if needed, but for now I'll just skip.
(void)ms;
}
void exit(int status) {
sys_exit(status);
}