mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-06 04:49:16 +00:00
userspace: Rewrite everything
Everything. Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
@ -1,22 +0,0 @@
|
||||
// extern void (*__preinit_array_start[])(void) __attribute__((weak));
|
||||
// extern void (*__preinit_array_end[])(void) __attribute__((weak));
|
||||
// extern void (*__init_array_start[])(void) __attribute__((weak));
|
||||
// extern void (*__init_array_end[])(void) __attribute__((weak));
|
||||
// extern void (*__fini_array_start []) (void) __attribute__((weak));
|
||||
// extern void (*__fini_array_end []) (void) __attribute__((weak));
|
||||
|
||||
typedef void (*fct)(void);
|
||||
extern fct __init_array_start[0], __init_array_end[0];
|
||||
extern fct __fini_array_start[0], __fini_array_end[0];
|
||||
|
||||
void __libc_init_array(void)
|
||||
{
|
||||
for (fct *func = __init_array_start; func != __init_array_end; func++)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
void __libc_fini_array(void)
|
||||
{
|
||||
for (fct *func = __fini_array_start; func != __fini_array_end; func++)
|
||||
(*func)();
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#include "lock.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
void LockClass::DeadLock(SpinLockData Lock)
|
||||
{
|
||||
fprintf(stdout, "Potential deadlock in lock '%s' held by '%s'! %ld locks in queue.",
|
||||
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count);
|
||||
}
|
||||
|
||||
int LockClass::Lock(const char *FunctionName)
|
||||
{
|
||||
LockData.AttemptingToGet = FunctionName;
|
||||
Retry:
|
||||
unsigned int i = 0;
|
||||
while (__atomic_exchange_n(&IsLocked, true, __ATOMIC_ACQUIRE) && ++i < 0x10000000)
|
||||
;
|
||||
if (i >= 0x10000000)
|
||||
{
|
||||
DeadLock(LockData);
|
||||
goto Retry;
|
||||
}
|
||||
LockData.Count++;
|
||||
LockData.CurrentHolder = FunctionName;
|
||||
__sync_synchronize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LockClass::Unlock()
|
||||
{
|
||||
__sync_synchronize();
|
||||
__atomic_store_n(&IsLocked, false, __ATOMIC_RELEASE);
|
||||
LockData.Count--;
|
||||
IsLocked = false;
|
||||
return 0;
|
||||
}
|
@ -1,47 +1,36 @@
|
||||
# Config file
|
||||
include ../../../config.mk
|
||||
default:
|
||||
$(error Do not run this Makefile directly!)
|
||||
|
||||
NAME=c
|
||||
DYNAMIC_NAME := libc.so
|
||||
STATIC_NAME := libc.a
|
||||
|
||||
ifeq ($(USERSPACE_STATIC_LIBS), 1)
|
||||
OBJECT_NAME := lib$(NAME).a
|
||||
else
|
||||
OBJECT_NAME := lib$(NAME).so
|
||||
endif
|
||||
OUTPUT_DIR=$(WORKSPACE_DIR)/out/lib/
|
||||
SYSROOT = --sysroot=$(WORKSPACE_DIR)/out/
|
||||
|
||||
OUTPUT_DIR=../../out/lib/
|
||||
SYSROOT = --sysroot=../../out/
|
||||
|
||||
CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
AR = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ar
|
||||
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
OBJ = ${C_SOURCES:.c=.o} ${CPP_SOURCES:.cpp=.o} ${S_SOURCES:.S=.o}
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CXX_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
OBJ = ${S_SOURCES:.S=.o} ${C_SOURCES:.c=.o} ${CXX_SOURCES:.cpp=.o}
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
ASM_ARCH := elf64
|
||||
else ifeq ($(OSARCH), i386)
|
||||
ASM_ARCH := elf32
|
||||
endif
|
||||
|
||||
CFLAGS := -fvisibility=hidden -fPIC -I../include -I../../out/include
|
||||
CFLAGS := -fvisibility=hidden -fPIC -I../include -I$(WORKSPACE_DIR)/out/include -DLIBC_GIT_COMMIT='"$(shell git rev-parse HEAD)"'
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
endif
|
||||
|
||||
build: $(OBJECT_NAME)
|
||||
build: $(DYNAMIC_NAME) $(STATIC_NAME)
|
||||
|
||||
$(OBJECT_NAME): $(OBJ)
|
||||
.PHONY: $(DYNAMIC_NAME) $(STATIC_NAME)
|
||||
|
||||
$(DYNAMIC_NAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
ifeq ($(USERSPACE_STATIC_LIBS), 1)
|
||||
$(AR) rcs $(OUTPUT_DIR)$@ $(OBJ)
|
||||
else
|
||||
$(CC) -nostdlib -shared -fPIC -fPIE -Wl,-soname,$(OBJECT_NAME) $(SYSROOT) $(OBJ) -o $(OUTPUT_DIR)$@
|
||||
endif
|
||||
$(CC) -nostdlib -shared -fPIC -fPIE -e _start -Wl,-soname,$(DYNAMIC_NAME) $(SYSROOT) $(OBJ) -o $(DYNAMIC_NAME)
|
||||
cp $(DYNAMIC_NAME) $(OUTPUT_DIR)$(DYNAMIC_NAME)
|
||||
|
||||
$(STATIC_NAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(AR) -rcs $(STATIC_NAME) $(OBJ)
|
||||
cp $(STATIC_NAME) $(OUTPUT_DIR)$(STATIC_NAME)
|
||||
|
||||
%.o: %.c
|
||||
$(info Compiling $<)
|
||||
@ -56,4 +45,4 @@ endif
|
||||
$(AS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
||||
rm -f $(OBJ) $(DYNAMIC_NAME) $(STATIC_NAME)
|
||||
|
@ -1,23 +0,0 @@
|
||||
#include <fennix/syscall.h>
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
extern void __libc_init_array(void);
|
||||
extern void __libc_fini_array(void);
|
||||
|
||||
extern void __libc_init_std(void);
|
||||
extern void __libc_fini_std(void);
|
||||
|
||||
PUBLIC void __libc_init(void)
|
||||
{
|
||||
__libc_init_array();
|
||||
__libc_init_std();
|
||||
}
|
||||
|
||||
PUBLIC void _exit(int Code)
|
||||
{
|
||||
__libc_fini_std();
|
||||
__libc_fini_array();
|
||||
syscall1(sc_exit, (long)Code);
|
||||
while (1)
|
||||
;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
static char *error = "Not implemented";
|
||||
|
||||
__attribute__((weak)) void *dlopen(const char *filename, int flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void *dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int dlclose(void *handle)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) char *dlerror(void)
|
||||
{
|
||||
return error;
|
||||
}
|
34
Userspace/libc/src/init.c
Normal file
34
Userspace/libc/src/init.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
This file is part of Fennix Userspace.
|
||||
|
||||
Fennix Userspace is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Userspace is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Userspace. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fennix/syscalls.h>
|
||||
|
||||
int __init_pthread(void);
|
||||
void __init_stdio(void);
|
||||
|
||||
__attribute__((visibility("default"))) void __libc_init(void)
|
||||
{
|
||||
__init_pthread();
|
||||
__init_stdio();
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) void _exit(int Code)
|
||||
{
|
||||
call_exit(Code);
|
||||
while (1)
|
||||
;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#ifndef __FENNIX_KERNEL_LOCK_H__
|
||||
#define __FENNIX_KERNEL_LOCK_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
/** @brief Please use this macro to create a new lock. */
|
||||
class LockClass
|
||||
{
|
||||
struct SpinLockData
|
||||
{
|
||||
uint64_t LockData = 0x0;
|
||||
const char *CurrentHolder = "(nul)";
|
||||
const char *AttemptingToGet = "(nul)";
|
||||
uint64_t Count = 0;
|
||||
};
|
||||
void DeadLock(SpinLockData Lock);
|
||||
|
||||
private:
|
||||
SpinLockData LockData;
|
||||
bool IsLocked = false;
|
||||
|
||||
public:
|
||||
SpinLockData *GetLockData() { return &LockData; }
|
||||
int Lock(const char *FunctionName);
|
||||
int Unlock();
|
||||
};
|
||||
|
||||
/** @brief Please use this macro to create a new smart lock. */
|
||||
class SmartLockClass
|
||||
{
|
||||
private:
|
||||
LockClass *LockPointer = nullptr;
|
||||
|
||||
public:
|
||||
SmartLockClass(LockClass &Lock, const char *FunctionName)
|
||||
{
|
||||
this->LockPointer = &Lock;
|
||||
this->LockPointer->Lock(FunctionName);
|
||||
}
|
||||
~SmartLockClass() { this->LockPointer->Unlock(); }
|
||||
};
|
||||
|
||||
/** @brief Create a new lock (can be used with SmartCriticalSection). */
|
||||
#define NewLock(Name) LockClass Name
|
||||
/** @brief Simple lock that is automatically released when the scope ends. */
|
||||
#define SmartLock(LockClassName) SmartLockClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__)
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // !__FENNIX_KERNEL_LOCK_H__
|
@ -1,5 +1,152 @@
|
||||
/* TODO: Show a message or something */
|
||||
int _start()
|
||||
/*
|
||||
This file is part of Fennix Userspace.
|
||||
|
||||
Fennix Userspace is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Userspace is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Userspace. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef void (*fct)(void);
|
||||
#define asm __asm__ __volatile__
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__preinit_array_start[])(void) __attribute__((weak));
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__preinit_array_end[])(void) __attribute__((weak));
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__init_array_start[])(void) __attribute__((weak));
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__init_array_end[])(void) __attribute__((weak));
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__fini_array_start[])(void) __attribute__((weak));
|
||||
__attribute__((__visibility__("hidden"))) extern void (*__fini_array_end[])(void) __attribute__((weak));
|
||||
const char __interp[] __attribute__((section(".interp"))) = "/lib/ld.so";
|
||||
|
||||
#ifndef LIBC_GIT_COMMIT
|
||||
#define LIBC_GIT_COMMIT "0000000000000000000000000000000000000000"
|
||||
#endif
|
||||
|
||||
#define HEX_DIGIT(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'a' + 10))
|
||||
#define CONVERT_TO_BYTE(h, l) ((HEX_DIGIT(h) << 4) | HEX_DIGIT(l))
|
||||
#define HASH_BYTES(hex) \
|
||||
{CONVERT_TO_BYTE(hex[0], hex[1]), \
|
||||
CONVERT_TO_BYTE(hex[2], hex[3]), \
|
||||
CONVERT_TO_BYTE(hex[4], hex[5]), \
|
||||
CONVERT_TO_BYTE(hex[6], hex[7]), \
|
||||
CONVERT_TO_BYTE(hex[8], hex[9]), \
|
||||
CONVERT_TO_BYTE(hex[10], hex[11]), \
|
||||
CONVERT_TO_BYTE(hex[12], hex[13]), \
|
||||
CONVERT_TO_BYTE(hex[14], hex[15]), \
|
||||
CONVERT_TO_BYTE(hex[16], hex[17]), \
|
||||
CONVERT_TO_BYTE(hex[18], hex[19]), \
|
||||
CONVERT_TO_BYTE(hex[20], hex[21]), \
|
||||
CONVERT_TO_BYTE(hex[22], hex[23]), \
|
||||
CONVERT_TO_BYTE(hex[24], hex[25]), \
|
||||
CONVERT_TO_BYTE(hex[26], hex[27]), \
|
||||
CONVERT_TO_BYTE(hex[28], hex[29]), \
|
||||
CONVERT_TO_BYTE(hex[30], hex[31]), \
|
||||
CONVERT_TO_BYTE(hex[32], hex[33]), \
|
||||
CONVERT_TO_BYTE(hex[34], hex[35]), \
|
||||
CONVERT_TO_BYTE(hex[36], hex[37]), \
|
||||
CONVERT_TO_BYTE(hex[38], hex[39])}
|
||||
|
||||
/* These are declared in GNU ld */
|
||||
enum
|
||||
{
|
||||
NT_FNX_ABI_TAG = 1,
|
||||
NT_FNX_VERSION = 2,
|
||||
NT_FNX_BUILD_ID = 3,
|
||||
NT_FNX_ARCH = 4
|
||||
};
|
||||
|
||||
typedef struct Elf_Nhdr
|
||||
{
|
||||
__UINT32_TYPE__ n_namesz;
|
||||
__UINT32_TYPE__ n_descsz;
|
||||
__UINT32_TYPE__ n_type;
|
||||
char n_name[];
|
||||
} __attribute__((packed)) Elf_Nhdr;
|
||||
|
||||
const struct
|
||||
{
|
||||
Elf_Nhdr header;
|
||||
char name[4];
|
||||
__UINT32_TYPE__ desc[4];
|
||||
} __abi_tag __attribute__((aligned(4), section(".note.ABI-tag"))) = {
|
||||
.header = {
|
||||
.n_namesz = 4, /* "FNX" + '\0' */
|
||||
.n_descsz = sizeof(__UINT32_TYPE__) * 4, /* Description Size */
|
||||
.n_type = NT_FNX_ABI_TAG, /* Type */
|
||||
},
|
||||
.name = "FNX",
|
||||
.desc = {0, 0, 0, 0},
|
||||
};
|
||||
|
||||
const struct
|
||||
{
|
||||
Elf_Nhdr header;
|
||||
char name[4];
|
||||
__UINT8_TYPE__ desc[20];
|
||||
} __build_id __attribute__((aligned(4), section(".note.build-id"))) = {
|
||||
.header = {
|
||||
.n_namesz = 4, /* "FNX" + '\0' */
|
||||
.n_descsz = sizeof(__UINT8_TYPE__) * 20, /* Description Size */
|
||||
.n_type = NT_FNX_BUILD_ID, /* Type */
|
||||
},
|
||||
.name = "FNX",
|
||||
.desc = HASH_BYTES(LIBC_GIT_COMMIT),
|
||||
};
|
||||
|
||||
void __crt_init_array(void)
|
||||
{
|
||||
for (fct *func = __init_array_start; func != __init_array_end; func++)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
void __crt_fini_array(void)
|
||||
{
|
||||
for (fct *func = __fini_array_start; func != __fini_array_end; func++)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
__attribute__((naked, used, no_stack_protector, section(".text"))) void _start()
|
||||
{
|
||||
asm("movq $0, %rbp\n"
|
||||
"pushq %rbp\n"
|
||||
"pushq %rbp\n"
|
||||
"movq %rsp, %rbp\n"
|
||||
|
||||
"pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n"
|
||||
|
||||
"call __libc_init\n"
|
||||
"call __crt_init_array\n"
|
||||
|
||||
"popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n"
|
||||
|
||||
"call main\n"
|
||||
|
||||
"pushq %rax\n"
|
||||
"call __crt_fini_array\n"
|
||||
"popq %rax\n"
|
||||
|
||||
"movl %eax, %edi\n"
|
||||
"call _exit\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)envp;
|
||||
/* FIXME: show printf license notice and some help and commands? */
|
||||
return -1;
|
||||
}
|
||||
|
10
Userspace/libc/src/mem/LICENSE
Normal file
10
Userspace/libc/src/mem/LICENSE
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
This code is released into the public domain. Use this code at your own
|
||||
risk. Feel free to use it for whatever purpose you want. I take no responsibilty or
|
||||
whatever if anything goes wrong. Use it at your own risk.
|
||||
|
||||
If you have any fixes or patches, please email me.
|
||||
|
||||
Durand Miller <clutter@djm.co.za>
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
#include <types.h>
|
||||
#include "../lock.hpp"
|
||||
|
||||
#include "../../../../Kernel/syscalls.h"
|
||||
|
||||
NewLock(liballocLock);
|
||||
|
||||
extern "C" int liballoc_lock()
|
||||
{
|
||||
return liballocLock.Lock(__FUNCTION__);
|
||||
}
|
||||
|
||||
extern "C" int liballoc_unlock()
|
||||
{
|
||||
return liballocLock.Unlock();
|
||||
}
|
||||
|
||||
extern "C" void *liballoc_alloc(size_t Pages)
|
||||
{
|
||||
return (void *)syscall6(sc_mmap, NULL,
|
||||
Pages * 0x1000,
|
||||
sc_PROT_READ | sc_PROT_WRITE,
|
||||
sc_MAP_ANONYMOUS | sc_MAP_PRIVATE,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
extern "C" int liballoc_free(void *Address, size_t Pages)
|
||||
{
|
||||
return syscall2(sc_munmap, (uintptr_t)Address, Pages * 0x1000);
|
||||
}
|
78
Userspace/libc/src/mem/liballoc.c
Normal file
78
Userspace/libc/src/mem/liballoc.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Taken directly from https://github.com/blanham/liballoc/blob/master/linux.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
#if !defined(MAP_FAILED)
|
||||
#define MAP_FAILED ((char *)-1)
|
||||
#endif
|
||||
|
||||
#ifndef MAP_NORESERVE
|
||||
#ifdef MAP_AUTORESRV
|
||||
#define MAP_NORESERVE MAP_AUTORESRV
|
||||
#else
|
||||
#define MAP_NORESERVE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int page_size = -1;
|
||||
|
||||
int liballoc_lock()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int liballoc_unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *liballoc_alloc(int pages)
|
||||
{
|
||||
if (page_size < 0)
|
||||
page_size = getpagesize();
|
||||
unsigned int size = pages * page_size;
|
||||
|
||||
char *p2 = (char *)mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0);
|
||||
if (p2 == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
if (mprotect(p2, size, PROT_READ | PROT_WRITE) != 0)
|
||||
{
|
||||
munmap(p2, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p2;
|
||||
}
|
||||
|
||||
int liballoc_free(void *ptr, int pages)
|
||||
{
|
||||
return munmap(ptr, pages * page_size);
|
||||
}
|
@ -43,17 +43,11 @@
|
||||
#define LIBALLOC_MAGIC 0xc001c0de
|
||||
#define LIBALLOC_DEAD 0xdeaddead
|
||||
|
||||
// #define LIBALLOCDEBUG 1
|
||||
#define LIBALLOCINFO 1
|
||||
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
// #include <debug.h>
|
||||
|
||||
#define FLUSH() fflush(stdout)
|
||||
#define atexit(x) atexit(x)
|
||||
// #define printf(m, ...) trace(m, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
@ -131,10 +125,10 @@ static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
|
||||
return s1;
|
||||
}
|
||||
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
static void liballoc_dump()
|
||||
{
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
struct liballoc_major *maj = l_memRoot;
|
||||
struct liballoc_minor *min = NULL;
|
||||
#endif
|
||||
@ -146,7 +140,7 @@ static void liballoc_dump()
|
||||
printf("liballoc: Error count: %i\n", l_errorCount);
|
||||
printf("liballoc: Possible overruns: %i\n", l_possibleOverruns);
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
while (maj != NULL)
|
||||
{
|
||||
printf("liballoc: %x: total = %i, used = %i\n",
|
||||
@ -198,7 +192,7 @@ static struct liballoc_major *allocate_new_page(unsigned int size)
|
||||
if (maj == NULL)
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -214,7 +208,7 @@ static struct liballoc_major *allocate_new_page(unsigned int size)
|
||||
|
||||
l_allocated += maj->size;
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size);
|
||||
|
||||
printf("liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))));
|
||||
@ -248,7 +242,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
if (size == 0)
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: WARNING: alloc( 0 ) called from %x\n",
|
||||
__builtin_return_address(0));
|
||||
FLUSH();
|
||||
@ -259,8 +253,8 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
|
||||
if (l_memRoot == NULL)
|
||||
{
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#if defined DEBUG || defined INFO
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: initialization of liballoc " VERSION "\n");
|
||||
#endif
|
||||
atexit(liballoc_dump);
|
||||
@ -272,20 +266,20 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
if (l_memRoot == NULL)
|
||||
{
|
||||
liballoc_unlock();
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: initial l_memRoot initialization failed\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: set up first memory major %x\n", l_memRoot);
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: %x PREFIX(malloc)( %i ): ",
|
||||
__builtin_return_address(0),
|
||||
size);
|
||||
@ -326,7 +320,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
// CASE 1: There is not enough space in this major block.
|
||||
if (diff < (size + sizeof(struct liballoc_minor)))
|
||||
{
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 1: Insufficient space in block %x\n", maj);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -378,7 +372,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -414,7 +408,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
p = (void *)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 3: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -460,7 +454,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
p = (void *)((uintptr_t)min + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 4.1: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -499,7 +493,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
p = (void *)((uintptr_t)new_min + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 4.2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -519,7 +513,7 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
// CASE 5: Block full! Ensure next block and loop.
|
||||
if (maj->next == NULL)
|
||||
{
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("CASE 5: block full\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -545,11 +539,11 @@ void *PREFIX(malloc)(size_t req_size)
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("All cases exhausted. No memory available.\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
|
||||
liballoc_dump();
|
||||
FLUSH();
|
||||
@ -565,7 +559,7 @@ void PREFIX(free)(void *ptr)
|
||||
if (ptr == NULL)
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
|
||||
__builtin_return_address(0));
|
||||
FLUSH();
|
||||
@ -590,7 +584,7 @@ void PREFIX(free)(void *ptr)
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC);
|
||||
@ -600,7 +594,7 @@ void PREFIX(free)(void *ptr)
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD)
|
||||
{
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0));
|
||||
@ -609,7 +603,7 @@ void PREFIX(free)(void *ptr)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0));
|
||||
@ -622,7 +616,7 @@ void PREFIX(free)(void *ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("liballoc: %x PREFIX(free)( %x ): ",
|
||||
__builtin_return_address(0),
|
||||
ptr);
|
||||
@ -674,7 +668,7 @@ void PREFIX(free)(void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBALLOCDEBUG
|
||||
#ifdef DEBUG
|
||||
printf("OK\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
@ -734,7 +728,7 @@ void *PREFIX(realloc)(void *p, size_t size)
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC);
|
||||
@ -744,7 +738,7 @@ void *PREFIX(realloc)(void *p, size_t size)
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD)
|
||||
{
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0));
|
||||
@ -753,7 +747,7 @@ void *PREFIX(realloc)(void *p, size_t size)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||
#if defined DEBUG || defined INFO
|
||||
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0));
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef _LIBALLOC_H
|
||||
#define _LIBALLOC_H
|
||||
|
||||
#include <types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/** \defgroup ALLOCHOOKS liballoc hooks
|
||||
*
|
||||
@ -17,6 +19,7 @@
|
||||
// typedef unsigned long uintptr_t;
|
||||
|
||||
// This lets you prefix malloc and friends
|
||||
// #define PREFIX(func) k##func
|
||||
#define PREFIX(func) __##func
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
23
Userspace/libc/src/print/LICENSE
Normal file
23
Userspace/libc/src/print/LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Marco Paland
|
||||
Copyright (c) 2021 Eyal Rozenberg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
20
Userspace/libc/src/print/print.c
Normal file
20
Userspace/libc/src/print/print.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void putchar_(char c) { putc(c, stdout); }
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
|
||||
* 2021-2022, Haifa, Palestine/Israel
|
||||
* 2021-2023, Haifa, Palestine/Israel
|
||||
* @author (c) Marco Paland (info@paland.com)
|
||||
* 2014-2019, PALANDesign Hannover, Germany
|
||||
*
|
||||
@ -9,8 +9,8 @@
|
||||
* or ask one of the authors.
|
||||
*
|
||||
* @brief Small stand-alone implementation of the printf family of functions
|
||||
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
|
||||
* a very limited resources.
|
||||
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
|
||||
* with a very limited resources.
|
||||
*
|
||||
* @note the implementations are thread-safe; re-entrant; use no functions from
|
||||
* the standard library; and do not dynamically allocate any memory.
|
||||
@ -39,27 +39,40 @@
|
||||
#ifndef PRINTF_H_
|
||||
#define PRINTF_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4)
|
||||
#define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(__printf__, (one_based_format_index), (first_arg))))
|
||||
#define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0)
|
||||
__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
|
||||
#else
|
||||
#define ATTR_PRINTF((one_based_format_index), (first_arg))
|
||||
#define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||
__attribute__((format(printf, (one_based_format_index), (first_arg))))
|
||||
#endif
|
||||
#define ATTR_VPRINTF(one_based_format_index) \
|
||||
ATTR_PRINTF((one_based_format_index), 0)
|
||||
#else
|
||||
#define ATTR_PRINTF(one_based_format_index, first_arg)
|
||||
#define ATTR_VPRINTF(one_based_format_index)
|
||||
#endif
|
||||
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 0
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
#define printf_ printf
|
||||
#define sprintf_ sprintf
|
||||
#define vsprintf_ vsprintf
|
||||
@ -69,126 +82,153 @@ extern "C"
|
||||
#endif
|
||||
|
||||
// If you want to include this implementation file directly rather than
|
||||
// link against, this will let you control the functions' visibility,
|
||||
// link against it, this will let you control the functions' visibility,
|
||||
// e.g. make them static so as not to clash with other objects also
|
||||
// using them.
|
||||
#ifndef PRINTF_VISIBILITY
|
||||
#define PRINTF_VISIBILITY __attribute__((visibility("default")))
|
||||
#define PRINTF_VISIBILITY
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Prints/send a single character to some opaque output entity
|
||||
*
|
||||
* @note This function is not implemented by the library, only declared; you must provide an
|
||||
* implementation if you wish to use the @ref printf / @ref vprintf function (and possibly
|
||||
* for linking against the library, if your toolchain does not support discarding unused functions)
|
||||
*
|
||||
* @note The output could be as simple as a wrapper for the `write()` system call on a Unix-like
|
||||
* system, or even libc's @ref putchar , for replicating actual functionality of libc's @ref printf
|
||||
* function; but on an embedded system it may involve interaction with a special output device,
|
||||
* like a UART, etc.
|
||||
*
|
||||
* @note in libc's @ref putchar, the parameter type is an int; this was intended to support the
|
||||
* representation of either a proper character or EOF in a variable - but this is really not
|
||||
* meaningful to pass into @ref putchar and is discouraged today. See further discussion in:
|
||||
* @link https://stackoverflow.com/q/17452847/1593077
|
||||
*
|
||||
* @param c the single character to print
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
int putchar(int c);
|
||||
/**
|
||||
* Prints/send a single character to some opaque output entity
|
||||
*
|
||||
* @note This function is not implemented by the library, only declared; you
|
||||
* must provide an implementation if you wish to use the @ref printf / @ref
|
||||
* vprintf function (and possibly for linking against the library, if your
|
||||
* toolchain does not support discarding unused functions)
|
||||
*
|
||||
* @note The output could be as simple as a wrapper for the `write()` system
|
||||
* call on a Unix-like * system, or even libc's @ref putchar , for replicating
|
||||
* actual functionality of libc's @ref printf * function; but on an embedded
|
||||
* system it may involve interaction with a special output device, like a UART,
|
||||
* etc.
|
||||
*
|
||||
* @note in libc's @ref putchar, the parameter type is an int; this was intended
|
||||
* to support the representation of either a proper character or EOF in a
|
||||
* variable - but this is really not meaningful to pass into @ref putchar and is
|
||||
* discouraged today. See further discussion in:
|
||||
* @link https://stackoverflow.com/q/17452847/1593077
|
||||
*
|
||||
* @param c the single character to print
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
void putchar_(char c);
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's printf/vprintf
|
||||
*
|
||||
* @note you must implement a @ref putchar_ function for using this function - it invokes @ref putchar_
|
||||
* rather than directly performing any I/O (which insulates it from any dependence on the operating system
|
||||
* and external libraries).
|
||||
*
|
||||
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||
* additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each %-specifier in @p format string
|
||||
* @return The number of characters written into @p s, not counting the terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int printf(const char *format, ...) ATTR_PRINTF(1, 2);
|
||||
PRINTF_VISIBILITY
|
||||
int vprintf(const char *format, va_list arg) ATTR_VPRINTF(1);
|
||||
///@}
|
||||
/**
|
||||
* An implementation of the C standard's printf/vprintf
|
||||
*
|
||||
* @note you must implement a @ref putchar_ function for using this function -
|
||||
* it invokes @ref putchar_ * rather than directly performing any I/O (which
|
||||
* insulates it from any dependence on the operating system * and external
|
||||
* libraries).
|
||||
*
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each %-specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int printf_(const char *format, ...) ATTR_PRINTF(1, 2);
|
||||
PRINTF_VISIBILITY
|
||||
int vprintf_(const char *format, va_list arg) ATTR_VPRINTF(1);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's sprintf/vsprintf
|
||||
*
|
||||
* @note For security considerations (the potential for exceeding the buffer bounds), please consider using
|
||||
* the size-constrained variant, @ref snprintf / @ref vsnprintf , instead.
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large enough to fit the formatted
|
||||
* output!
|
||||
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||
* additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||
* @return The number of characters written into @p s, not counting the terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int sprintf(char *s, const char *format, ...) ATTR_PRINTF(2, 3);
|
||||
PRINTF_VISIBILITY
|
||||
int vsprintf(char *s, const char *format, va_list arg) ATTR_VPRINTF(2);
|
||||
///@}
|
||||
/**
|
||||
* An implementation of the C standard's sprintf/vsprintf
|
||||
*
|
||||
* @note For security considerations (the potential for exceeding the buffer
|
||||
* bounds), please consider using the size-constrained variant, @ref snprintf /
|
||||
* @ref vsnprintf, instead.
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit the formatted output!
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters written into @p s, not counting the
|
||||
* terminating null character
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int sprintf_(char *s, const char *format, ...) ATTR_PRINTF(2, 3);
|
||||
PRINTF_VISIBILITY
|
||||
int vsprintf_(char *s, const char *format, va_list arg) ATTR_VPRINTF(2);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* An implementation of the C standard's snprintf/vsnprintf
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large enough to fit either the
|
||||
* entire formatted output, or at least @p n characters. Alternatively, it can be NULL, in which case
|
||||
* nothing will be printed, and only the number of characters which _could_ have been printed is
|
||||
* tallied and returned.
|
||||
* @param n The maximum number of characters to write to the array, including a terminating null character
|
||||
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||
* additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||
* @return The number of characters that COULD have been written into @p s, not counting the terminating
|
||||
* null character. A value equal or larger than @p n indicates truncation. Only when the returned value
|
||||
* is non-negative and less than @p n, the null-terminated string has been fully and successfully printed.
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int snprintf(char *s, size_t count, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vsnprintf(char *s, size_t count, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||
///@}
|
||||
/**
|
||||
* An implementation of the C standard's snprintf/vsnprintf
|
||||
*
|
||||
* @param s An array in which to store the formatted string. It must be large
|
||||
* enough to fit either the entire formatted output, or at least @p n
|
||||
* characters. Alternatively, it can be NULL, in which case nothing will
|
||||
* be printed, and only the number of characters which _could_ have been
|
||||
* printed is tallied and returned.
|
||||
* @param n The maximum number of characters to write to the array, including
|
||||
* a terminating null character
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters that COULD have been written into @p s, not
|
||||
* counting the terminating null character. A value equal or larger than
|
||||
* @p n indicates truncation. Only when the returned value is non-negative
|
||||
* and less than @p n, the null-terminated string has been fully and
|
||||
* successfully printed.
|
||||
*/
|
||||
///@{
|
||||
PRINTF_VISIBILITY
|
||||
int snprintf_(char *s, size_t count, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vsnprintf_(char *s, size_t count, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||
///@}
|
||||
|
||||
/**
|
||||
* printf/vprintf with user-specified output function
|
||||
*
|
||||
* An alternative to @ref printf_, in which the output function is specified dynamically
|
||||
* (rather than @ref putchar_ being used)
|
||||
*
|
||||
* @param out An output function which takes one character and a type-erased additional parameters
|
||||
* @param extra_arg The type-erased argument to pass to the output function @p out with each call
|
||||
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||
* additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||
* @return The number of characters for which the output f unction was invoked, not counting the terminating null character
|
||||
*
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||
/**
|
||||
* printf/vprintf with user-specified output function
|
||||
*
|
||||
* An alternative to @ref printf_, in which the output function is specified
|
||||
* dynamically (rather than @ref putchar_ being used)
|
||||
*
|
||||
* @param out An output function which takes one character and a type-erased
|
||||
* additional parameters
|
||||
* @param extra_arg The type-erased argument to pass to the output function @p
|
||||
* out with each call
|
||||
* @param format A string specifying the format of the output, with %-marked
|
||||
* specifiers of how to interpret additional arguments.
|
||||
* @param arg Additional arguments to the function, one for each specifier in
|
||||
* @p format
|
||||
* @return The number of characters for which the output f unction was invoked,
|
||||
* not counting the terminating null character
|
||||
*
|
||||
*/
|
||||
PRINTF_VISIBILITY
|
||||
int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||
PRINTF_VISIBILITY
|
||||
int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
||||
#undef printf_
|
||||
#undef sprintf_
|
||||
#undef vsprintf_
|
||||
#undef snprintf_
|
||||
#undef vsnprintf_
|
||||
#undef vprintf_
|
||||
#else
|
||||
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
||||
#define printf printf_
|
||||
#define sprintf sprintf_
|
||||
#define vsprintf vsprintf_
|
||||
#define snprintf snprintf_
|
||||
#define vsnprintf vsnprintf_
|
||||
#define vprintf vprintf_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PRINTF_H_
|
||||
#endif // PRINTF_H_
|
||||
|
@ -1,11 +0,0 @@
|
||||
#include <setjmp.h>
|
||||
|
||||
PUBLIC int setjmp(jmp_buf env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC __attribute__((noreturn)) void longjmp(jmp_buf env, int value)
|
||||
{
|
||||
_exit(value);
|
||||
}
|
26
Userspace/libc/src/std/assert.c
Normal file
26
Userspace/libc/src/std/assert.c
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
export void __assert_fail(const char *file, int line, const char *func)
|
||||
{
|
||||
printf("assertion failed: %s:%d:%s\n", file, line, func);
|
||||
abort();
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int tolower(int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
c -= 'A';
|
||||
c += 'a';
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
PUBLIC int toupper(int c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
c -= 'a';
|
||||
c += 'A';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
PUBLIC int isspace(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v';
|
||||
}
|
@ -1,10 +1,212 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
int __local_stub_errno = 0;
|
||||
|
||||
PUBLIC int *__errno_location(void)
|
||||
__iptr __check_errno(__iptr status, __iptr err)
|
||||
{
|
||||
return &__local_stub_errno;
|
||||
if (status >= EOK)
|
||||
return status;
|
||||
pthread_self()->CurrentError = status;
|
||||
return err;
|
||||
}
|
||||
|
||||
export int *__errno_location(void)
|
||||
{
|
||||
return &pthread_self()->CurrentError;
|
||||
}
|
||||
|
||||
export char *strerror(int errnum)
|
||||
{
|
||||
if (errnum < 0)
|
||||
errnum = -errnum;
|
||||
|
||||
if (errnum > __ERRNO_MAX)
|
||||
return (char *)"Not a valid error number";
|
||||
|
||||
switch (errnum)
|
||||
{
|
||||
case EOK:
|
||||
return (char *)"No error";
|
||||
case E2BIG:
|
||||
return (char *)"Argument list too long";
|
||||
case EACCES:
|
||||
return (char *)"Permission denied";
|
||||
case EADDRINUSE:
|
||||
return (char *)"Address in use";
|
||||
case EADDRNOTAVAIL:
|
||||
return (char *)"Address not available";
|
||||
case EAFNOSUPPORT:
|
||||
return (char *)"Address family not supported";
|
||||
case EAGAIN:
|
||||
return (char *)"Resource unavailable, try again";
|
||||
case EALREADY:
|
||||
return (char *)"Connection already in progress";
|
||||
case EBADF:
|
||||
return (char *)"Bad file descriptor";
|
||||
case EBADMSG:
|
||||
return (char *)"Bad message";
|
||||
case EBUSY:
|
||||
return (char *)"Device or resource busy";
|
||||
case ECANCELED:
|
||||
return (char *)"Operation canceled";
|
||||
case ECHILD:
|
||||
return (char *)"No child processes";
|
||||
case ECONNABORTED:
|
||||
return (char *)"Connection aborted";
|
||||
case ECONNREFUSED:
|
||||
return (char *)"Connection refused";
|
||||
case ECONNRESET:
|
||||
return (char *)"Connection reset";
|
||||
case EDEADLK:
|
||||
return (char *)"Resource deadlock would occur";
|
||||
case EDESTADDRREQ:
|
||||
return (char *)"Destination address required";
|
||||
case EDOM:
|
||||
return (char *)"Mathematics argument out of domain of function";
|
||||
case EDQUOT:
|
||||
return (char *)"Reserved";
|
||||
case EEXIST:
|
||||
return (char *)"File exists";
|
||||
case EFAULT:
|
||||
return (char *)"Bad address";
|
||||
case EFBIG:
|
||||
return (char *)"File too large";
|
||||
case EHOSTUNREACH:
|
||||
return (char *)"Host is unreachable";
|
||||
case EIDRM:
|
||||
return (char *)"Identifier removed";
|
||||
case EILSEQ:
|
||||
return (char *)"Illegal byte sequence";
|
||||
case EINPROGRESS:
|
||||
return (char *)"Operation in progress";
|
||||
case EINTR:
|
||||
return (char *)"Interrupted function";
|
||||
case EINVAL:
|
||||
return (char *)"Invalid argument";
|
||||
case EIO:
|
||||
return (char *)"I/O error";
|
||||
case EISCONN:
|
||||
return (char *)"Socket is connected";
|
||||
case EISDIR:
|
||||
return (char *)"Is a directory";
|
||||
case ELOOP:
|
||||
return (char *)"Too many levels of symbolic links";
|
||||
case EMFILE:
|
||||
return (char *)"File descriptor value too large";
|
||||
case EMLINK:
|
||||
return (char *)"Too many links";
|
||||
case EMSGSIZE:
|
||||
return (char *)"Message too large";
|
||||
case EMULTIHOP:
|
||||
return (char *)"Reserved";
|
||||
case ENAMETOOLONG:
|
||||
return (char *)"Filename too long";
|
||||
case ENETDOWN:
|
||||
return (char *)"Network is down";
|
||||
case ENETRESET:
|
||||
return (char *)"Connection aborted by network";
|
||||
case ENETUNREACH:
|
||||
return (char *)"Network unreachable";
|
||||
case ENFILE:
|
||||
return (char *)"Too many files open in system";
|
||||
case ENOBUFS:
|
||||
return (char *)"No buffer space available";
|
||||
case ENODATA:
|
||||
return (char *)"No message available on the STREAM head read queue";
|
||||
case ENODEV:
|
||||
return (char *)"No such device";
|
||||
case ENOENT:
|
||||
return (char *)"No such file or directory";
|
||||
case ENOEXEC:
|
||||
return (char *)"Executable file format error";
|
||||
case ENOLCK:
|
||||
return (char *)"No locks available";
|
||||
case ENOLINK:
|
||||
return (char *)"Reserved";
|
||||
case ENOMEM:
|
||||
return (char *)"Not enough space";
|
||||
case ENOMSG:
|
||||
return (char *)"No message of the desired type";
|
||||
case ENOPROTOOPT:
|
||||
return (char *)"Protocol not available";
|
||||
case ENOSPC:
|
||||
return (char *)"No space left on device";
|
||||
case ENOSR:
|
||||
return (char *)"No STREAM resources";
|
||||
case ENOSTR:
|
||||
return (char *)"Not a STREAM";
|
||||
case ENOSYS:
|
||||
return (char *)"Functionality not supported";
|
||||
case ENOTCONN:
|
||||
return (char *)"The socket is not connected";
|
||||
case ENOTDIR:
|
||||
return (char *)"Not a directory or a symbolic link to a directory";
|
||||
case ENOTEMPTY:
|
||||
return (char *)"Directory not empty";
|
||||
case ENOTRECOVERABLE:
|
||||
return (char *)"State not recoverable";
|
||||
case ENOTSOCK:
|
||||
return (char *)"Not a socket";
|
||||
case ENOTSUP:
|
||||
return (char *)"Not supported";
|
||||
case ENOTTY:
|
||||
return (char *)"Inappropriate I/O control operation";
|
||||
case ENXIO:
|
||||
return (char *)"No such device or address";
|
||||
case EOPNOTSUPP:
|
||||
return (char *)"Operation not supported on socket";
|
||||
case EOVERFLOW:
|
||||
return (char *)"Value too large to be stored in data type";
|
||||
case EOWNERDEAD:
|
||||
return (char *)"Previous owner died";
|
||||
case EPERM:
|
||||
return (char *)"Operation not permitted";
|
||||
case EPIPE:
|
||||
return (char *)"Broken pipe";
|
||||
case EPROTO:
|
||||
return (char *)"Protocol error";
|
||||
case EPROTONOSUPPORT:
|
||||
return (char *)"Protocol not supported";
|
||||
case EPROTOTYPE:
|
||||
return (char *)"Protocol wrong type for socket";
|
||||
case ERANGE:
|
||||
return (char *)"Result too large";
|
||||
case EROFS:
|
||||
return (char *)"Read-only file system";
|
||||
case ESPIPE:
|
||||
return (char *)"Invalid seek";
|
||||
case ESRCH:
|
||||
return (char *)"No such process";
|
||||
case ESTALE:
|
||||
return (char *)"Reserved";
|
||||
case ETIME:
|
||||
return (char *)"Stream ioctl() timeout";
|
||||
case ETIMEDOUT:
|
||||
return (char *)"Connection timed out";
|
||||
case ETXTBSY:
|
||||
return (char *)"Text file busy";
|
||||
case EWOULDBLOCK:
|
||||
return (char *)"Operation would block";
|
||||
case EXDEV:
|
||||
return (char *)"Cross-device link";
|
||||
default:
|
||||
return (char *)"Unknown error";
|
||||
}
|
||||
}
|
||||
|
@ -1,132 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fennix/syscall.h>
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC FILE *stdin = NULL;
|
||||
PUBLIC FILE *stdout = NULL;
|
||||
PUBLIC FILE *stderr = NULL;
|
||||
|
||||
PUBLIC FILE *freopen(const char *filename, const char *mode, FILE *stream)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC FILE *fopen(const char *filename, const char *mode)
|
||||
{
|
||||
int fd = syscall2(sc_open, (uint64_t)filename, (uint64_t)mode);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
FILE *FilePtr = malloc(sizeof(FILE));
|
||||
FilePtr->_fileno = fd;
|
||||
return FilePtr;
|
||||
}
|
||||
|
||||
PUBLIC size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
if (ptr == NULL || stream == NULL || size == 0 || nmemb == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
syscall3(sc_lseek, stream->_fileno, stream->_offset, SEEK_SET);
|
||||
return syscall3(sc_read, (uint64_t)stream->_fileno, (uint64_t)ptr, size * nmemb);
|
||||
}
|
||||
|
||||
PUBLIC size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
if (ptr == NULL || stream == NULL || size == 0 || nmemb == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
syscall3(sc_lseek, stream->_fileno, stream->_offset, SEEK_SET);
|
||||
return syscall3(sc_write, (uint64_t)stream->_fileno, (uint64_t)ptr, size * nmemb);
|
||||
}
|
||||
|
||||
PUBLIC int fclose(FILE *fp)
|
||||
{
|
||||
if (fp == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return syscall1(sc_close, fp->_fileno);
|
||||
}
|
||||
|
||||
PUBLIC off_t fseek(FILE *stream, off_t offset, int whence)
|
||||
{
|
||||
if (stream == NULL || whence < 0 || whence > 2)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t new_offset = syscall3(sc_lseek, stream->_fileno, offset, whence);
|
||||
if (new_offset < 0)
|
||||
return -1;
|
||||
stream->_offset = new_offset;
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
PUBLIC long ftell(FILE *stream)
|
||||
{
|
||||
return stream->_offset;
|
||||
}
|
||||
|
||||
PUBLIC int fflush(FILE *stream)
|
||||
{
|
||||
if (stream == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
errno = ENOSYS;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
PUBLIC int fprintf(FILE *stream, const char *format, ...)
|
||||
{
|
||||
if (stream == NULL || format == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int ret = vfprintf(stream, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PUBLIC void setbuf(FILE *stream, char *buf)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int vfprintf(FILE *stream, const char *format, va_list arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int vsscanf(const char *s, const char *format, va_list arg)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int sscanf(const char *s, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int ret = vsscanf(s, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int fgetc(FILE *stream)
|
||||
{
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int fputc(int c, FILE *stream)
|
||||
{
|
||||
// FIXME
|
||||
// if (stream == NULL)
|
||||
// {
|
||||
// errno = EBADF;
|
||||
// return EOF;
|
||||
// }
|
||||
char str[2] = {c, '\0'};
|
||||
// return syscall3(sys_KernelCTL, KCTL_PRINT, str, 0);
|
||||
}
|
||||
|
||||
PUBLIC int putc(int c, FILE *stream) { return fputc(c, stream); }
|
||||
|
||||
PUBLIC int fputs(const char *s, FILE *stream)
|
||||
{
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
fputc(s[i], stream);
|
||||
}
|
||||
|
||||
PUBLIC int puts(const char *s)
|
||||
{
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
fputc(s[i], stdout);
|
||||
}
|
||||
|
||||
PUBLIC int putchar(int c) { return fputc(c, stdout); }
|
||||
PUBLIC void perror(const char *s) { fputs(s, stderr); }
|
@ -1,87 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include "../mem/liballoc_1_1.h"
|
||||
|
||||
PUBLIC void abort(void)
|
||||
{
|
||||
syscall1(sc_exit, -0xAB057);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
PUBLIC int atexit(void (*function)(void))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
PUBLIC void exit(int status)
|
||||
{
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
PUBLIC int atoi(const char *nptr)
|
||||
{
|
||||
uint64_t Length = strlen((char *)nptr);
|
||||
if (nptr)
|
||||
while (nptr[Length] != '\0')
|
||||
++Length;
|
||||
uint64_t OutBuffer = 0;
|
||||
uint64_t Power = 1;
|
||||
for (uint64_t i = Length; i > 0; --i)
|
||||
{
|
||||
OutBuffer += (nptr[i - 1] - 48) * Power;
|
||||
Power *= 10;
|
||||
}
|
||||
return OutBuffer;
|
||||
}
|
||||
|
||||
PUBLIC char **environ = NULL;
|
||||
|
||||
PUBLIC char *getenv(const char *name)
|
||||
{
|
||||
char **env = environ;
|
||||
if (env == NULL)
|
||||
return NULL;
|
||||
size_t len = strlen(name);
|
||||
while (*env != NULL)
|
||||
{
|
||||
if ((strncmp(*env, name, len) == 0) && ((*env)[len] == '='))
|
||||
return &(*env)[len + 1];
|
||||
++env;
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC void *malloc(size_t Size) { return PREFIX(malloc)(Size); }
|
||||
PUBLIC void *realloc(void *Address, size_t Size) { return PREFIX(realloc)(Address, Size); }
|
||||
PUBLIC void *calloc(size_t Count, size_t Size) { return PREFIX(calloc)(Count, Size); }
|
||||
PUBLIC void free(void *Address)
|
||||
{
|
||||
PREFIX(free)
|
||||
(Address);
|
||||
}
|
||||
|
||||
PUBLIC int system(const char *command)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC double atof(const char *nptr)
|
||||
{
|
||||
// FIXME: This is a very bad implementation of atof.
|
||||
uint64_t Length = strlen((char *)nptr);
|
||||
if (nptr)
|
||||
while (nptr[Length] != '\0')
|
||||
++Length;
|
||||
double OutBuffer = 0;
|
||||
double Power = 1;
|
||||
for (uint64_t i = Length; i > 0; --i)
|
||||
{
|
||||
OutBuffer += (nptr[i - 1] - 48) * Power;
|
||||
Power *= 10;
|
||||
}
|
||||
return OutBuffer;
|
||||
}
|
121
Userspace/libc/src/std/pthread.c
Normal file
121
Userspace/libc/src/std/pthread.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
export int pthread_attr_destroy(pthread_attr_t *);
|
||||
export int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
|
||||
export int pthread_attr_getguardsize(const pthread_attr_t *, size_t *);
|
||||
export int pthread_attr_getinheritsched(const pthread_attr_t *, int *);
|
||||
export int pthread_attr_getschedparam(const pthread_attr_t *, struct sched_param *);
|
||||
export int pthread_attr_getschedpolicy(const pthread_attr_t *, int *);
|
||||
export int pthread_attr_getscope(const pthread_attr_t *, int *);
|
||||
export int pthread_attr_getstackaddr(const pthread_attr_t *, void **);
|
||||
export int pthread_attr_getstacksize(const pthread_attr_t *, size_t *);
|
||||
export int pthread_attr_init(pthread_attr_t *);
|
||||
export int pthread_attr_setdetachstate(pthread_attr_t *, int);
|
||||
export int pthread_attr_setguardsize(pthread_attr_t *, size_t);
|
||||
export int pthread_attr_setinheritsched(pthread_attr_t *, int);
|
||||
export int pthread_attr_setschedparam(pthread_attr_t *, const struct sched_param *);
|
||||
export int pthread_attr_setschedpolicy(pthread_attr_t *, int);
|
||||
export int pthread_attr_setscope(pthread_attr_t *, int);
|
||||
export int pthread_attr_setstackaddr(pthread_attr_t *, void *);
|
||||
export int pthread_attr_setstacksize(pthread_attr_t *, size_t);
|
||||
export int pthread_cancel(pthread_t);
|
||||
export void pthread_cleanup_push(void (*)(void *), void *);
|
||||
export void pthread_cleanup_pop(int);
|
||||
export int pthread_cond_broadcast(pthread_cond_t *);
|
||||
export int pthread_cond_destroy(pthread_cond_t *);
|
||||
export int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
|
||||
export int pthread_cond_signal(pthread_cond_t *);
|
||||
export int pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
|
||||
export int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
|
||||
export int pthread_condattr_destroy(pthread_condattr_t *);
|
||||
export int pthread_condattr_getpshared(const pthread_condattr_t *, int *);
|
||||
export int pthread_condattr_init(pthread_condattr_t *);
|
||||
export int pthread_condattr_setpshared(pthread_condattr_t *, int);
|
||||
export int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
|
||||
export int pthread_detach(pthread_t);
|
||||
export int pthread_equal(pthread_t, pthread_t);
|
||||
export void pthread_exit(void *);
|
||||
export int pthread_getconcurrency(void);
|
||||
export int pthread_getschedparam(pthread_t, int *, struct sched_param *);
|
||||
export void *pthread_getspecific(pthread_key_t);
|
||||
export int pthread_join(pthread_t, void **);
|
||||
export int pthread_key_create(pthread_key_t *, void (*)(void *));
|
||||
export int pthread_key_delete(pthread_key_t);
|
||||
export int pthread_mutex_destroy(pthread_mutex_t *);
|
||||
export int pthread_mutex_getprioceiling(const pthread_mutex_t *, int *);
|
||||
export int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
|
||||
|
||||
export int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (mutex->locked)
|
||||
return EBUSY;
|
||||
mutex->locked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export int pthread_mutex_setprioceiling(pthread_mutex_t *, int, int *);
|
||||
export int pthread_mutex_trylock(pthread_mutex_t *);
|
||||
|
||||
export int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (!mutex->locked)
|
||||
return EPERM;
|
||||
mutex->locked = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export int pthread_mutexattr_destroy(pthread_mutexattr_t *);
|
||||
export int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *);
|
||||
export int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *, int *);
|
||||
export int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *);
|
||||
export int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *);
|
||||
export int pthread_mutexattr_init(pthread_mutexattr_t *);
|
||||
export int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int);
|
||||
export int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
|
||||
export int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
|
||||
export int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
|
||||
export int pthread_once(pthread_once_t *, void (*)(void));
|
||||
export int pthread_rwlock_destroy(pthread_rwlock_t *);
|
||||
export int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
|
||||
export int pthread_rwlock_rdlock(pthread_rwlock_t *);
|
||||
export int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
|
||||
export int pthread_rwlock_trywrlock(pthread_rwlock_t *);
|
||||
export int pthread_rwlock_unlock(pthread_rwlock_t *);
|
||||
export int pthread_rwlock_wrlock(pthread_rwlock_t *);
|
||||
export int pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
|
||||
export int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *, int *);
|
||||
export int pthread_rwlockattr_init(pthread_rwlockattr_t *);
|
||||
export int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
|
||||
|
||||
export pthread_t pthread_self(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
__asm__ __volatile__("mov %%fs:0, %0"
|
||||
: "=r"(tid));
|
||||
return tid;
|
||||
}
|
||||
|
||||
export int pthread_setcancelstate(int, int *);
|
||||
export int pthread_setcanceltype(int, int *);
|
||||
export int pthread_setconcurrency(int);
|
||||
export int pthread_setschedparam(pthread_t, int, const struct sched_param *);
|
||||
export int pthread_setspecific(pthread_key_t, const void *);
|
||||
export void pthread_testcancel(void);
|
47
Userspace/libc/src/std/signal.c
Normal file
47
Userspace/libc/src/std/signal.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
export int kill(pid_t pid, int sig)
|
||||
{
|
||||
return syscall2(SYS_KILL, pid, sig);
|
||||
}
|
||||
|
||||
export int killpg(pid_t, int);
|
||||
export void psiginfo(const siginfo_t *, const char *);
|
||||
export void psignal(int, const char *);
|
||||
export int pthread_kill(pthread_t, int);
|
||||
export int pthread_sigmask(int, const sigset_t *restrict, sigset_t *restrict);
|
||||
export int raise(int);
|
||||
export int sig2str(int, char *);
|
||||
export int sigaction(int, const struct sigaction *restrict, struct sigaction *restrict);
|
||||
export int sigaddset(sigset_t *, int);
|
||||
export int sigaltstack(const stack_t *restrict, stack_t *restrict);
|
||||
export int sigdelset(sigset_t *, int);
|
||||
export int sigemptyset(sigset_t *);
|
||||
export int sigfillset(sigset_t *);
|
||||
export int sigismember(const sigset_t *, int);
|
||||
export void (*signal(int, void (*)(int)))(int);
|
||||
export int sigpending(sigset_t *);
|
||||
export int sigprocmask(int, const sigset_t *restrict, sigset_t *restrict);
|
||||
export int sigqueue(pid_t, int, union sigval);
|
||||
export int sigsuspend(const sigset_t *);
|
||||
export int sigtimedwait(const sigset_t *restrict, siginfo_t *restrict, const struct timespec *restrict);
|
||||
export int sigwait(const sigset_t *restrict, int *restrict);
|
||||
export int sigwaitinfo(const sigset_t *restrict, siginfo_t *restrict);
|
||||
export int str2sig(const char *restrict, int *restrict);
|
@ -1,17 +0,0 @@
|
||||
#include <spawn.h>
|
||||
|
||||
int posix_spawn(pid_t *pid, const char *path,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
}
|
||||
|
||||
int posix_spawnp(pid_t *pid, const char *file,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
void __libc_init_std(void)
|
||||
{
|
||||
/* FIXME: Temporal workaround */
|
||||
// int IsCritical = syscall1(_KernelCTL, 6 /* KCTL_IS_CRITICAL */);
|
||||
}
|
||||
|
||||
void __libc_fini_std(void)
|
||||
{
|
||||
}
|
343
Userspace/libc/src/std/stdio.c
Normal file
343
Userspace/libc/src/std/stdio.c
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fennix/syscalls.h>
|
||||
#include "../print/printf.h"
|
||||
|
||||
struct _IO_FILE *_i_open_files[256];
|
||||
|
||||
export FILE *stdin;
|
||||
export FILE *stdout;
|
||||
export FILE *stderr;
|
||||
|
||||
void __init_stdio(void)
|
||||
{
|
||||
stdin = malloc(sizeof(FILE));
|
||||
stdin->fd = 0;
|
||||
stdin->buffer = malloc(4096);
|
||||
stdin->buffer_size = 4096;
|
||||
stdin->buffer_pos = 0;
|
||||
stdin->flags = _i_READ;
|
||||
stdin->error = 0;
|
||||
stdin->eof = 0;
|
||||
|
||||
stdout = malloc(sizeof(FILE));
|
||||
stdout->fd = 1;
|
||||
stdout->buffer = malloc(4096);
|
||||
stdout->buffer_size = 4096;
|
||||
stdout->buffer_pos = 0;
|
||||
stdout->flags = _i_WRITE;
|
||||
stdout->error = 0;
|
||||
stdout->eof = 0;
|
||||
|
||||
stderr = malloc(sizeof(FILE));
|
||||
stderr->fd = 2;
|
||||
stderr->buffer = malloc(4096);
|
||||
stderr->buffer_size = 4096;
|
||||
stderr->buffer_pos = 0;
|
||||
stderr->flags = _i_WRITE;
|
||||
stderr->error = 0;
|
||||
stderr->eof = 0;
|
||||
|
||||
_i_open_files[0] = stdin;
|
||||
_i_open_files[1] = stdout;
|
||||
_i_open_files[2] = stderr;
|
||||
}
|
||||
|
||||
export void clearerr(FILE *);
|
||||
export char *ctermid(char *);
|
||||
export int dprintf(int, const char *restrict, ...);
|
||||
|
||||
export int fclose(FILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return EOF;
|
||||
|
||||
if (stream->buffer)
|
||||
free(stream->buffer);
|
||||
|
||||
call_close(stream->fd);
|
||||
_i_open_files[stream->fd] = NULL;
|
||||
free(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
export FILE *fdopen(int, const char *);
|
||||
export int feof(FILE *);
|
||||
export int ferror(FILE *);
|
||||
|
||||
export int fflush(FILE *stream)
|
||||
{
|
||||
if (!stream)
|
||||
return EOF;
|
||||
|
||||
if (stream->flags & _i_WRITE)
|
||||
{
|
||||
if (stream->buffer_pos > 0)
|
||||
{
|
||||
ssize_t written = call_write(stream->fd, stream->buffer, stream->buffer_pos);
|
||||
if (written < 0)
|
||||
{
|
||||
stream->error = 1;
|
||||
return EOF;
|
||||
}
|
||||
stream->buffer_pos = 0;
|
||||
}
|
||||
}
|
||||
else if (stream->flags & _i_READ)
|
||||
{
|
||||
stream->buffer_pos = 0;
|
||||
stream->buffer_size = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export int fgetc(FILE *);
|
||||
export int fgetpos(FILE *restrict, fpos_t *restrict);
|
||||
export char *fgets(char *restrict, int, FILE *restrict);
|
||||
export int fileno(FILE *);
|
||||
export void flockfile(FILE *);
|
||||
export FILE *fmemopen(void *restrict, size_t, const char *restrict);
|
||||
|
||||
export FILE *fopen(const char *restrict pathname, const char *restrict mode)
|
||||
{
|
||||
int flags = 0;
|
||||
mode_t perm = 0;
|
||||
|
||||
if (strcmp(mode, "r") == 0)
|
||||
flags = __SYS_O_RDONLY;
|
||||
else if (strcmp(mode, "r+") == 0)
|
||||
flags = __SYS_O_RDWR;
|
||||
else if (strcmp(mode, "w") == 0)
|
||||
{
|
||||
flags = __SYS_O_WRONLY | __SYS_O_CREAT | __SYS_O_TRUNC;
|
||||
perm = 0644;
|
||||
}
|
||||
else if (strcmp(mode, "w+") == 0)
|
||||
{
|
||||
flags = __SYS_O_RDWR | __SYS_O_CREAT | __SYS_O_TRUNC;
|
||||
perm = 0644;
|
||||
}
|
||||
else if (strcmp(mode, "a") == 0)
|
||||
{
|
||||
flags = __SYS_O_WRONLY | __SYS_O_CREAT | __SYS_O_APPEND;
|
||||
perm = 0644;
|
||||
}
|
||||
else if (strcmp(mode, "a+") == 0)
|
||||
{
|
||||
flags = __SYS_O_RDWR | __SYS_O_CREAT | __SYS_O_APPEND;
|
||||
perm = 0644;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
int fd = call_open(pathname, flags, perm);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
FILE *file = malloc(sizeof(FILE));
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
file->fd = fd;
|
||||
file->buffer = malloc(4096);
|
||||
file->buffer_size = 4096;
|
||||
file->buffer_pos = 0;
|
||||
file->flags = flags;
|
||||
file->error = 0;
|
||||
file->eof = 0;
|
||||
|
||||
_i_open_files[fd] = file;
|
||||
return file;
|
||||
}
|
||||
|
||||
export int fprintf(FILE *restrict, const char *restrict, ...);
|
||||
|
||||
export int fputc(int c, FILE *stream)
|
||||
{
|
||||
if (!stream || !(stream->flags & _i_WRITE))
|
||||
return EOF;
|
||||
|
||||
stream->buffer[stream->buffer_pos++] = (char)c;
|
||||
|
||||
if (stream->buffer_pos >= stream->buffer_size)
|
||||
{
|
||||
if (fflush(stream) == EOF)
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return (unsigned char)c;
|
||||
}
|
||||
|
||||
export int fputs(const char *restrict s, FILE *restrict stream)
|
||||
{
|
||||
if (!stream || !(stream->flags & _i_WRITE))
|
||||
return EOF;
|
||||
|
||||
while (*s)
|
||||
{
|
||||
if (fputc(*s++, stream) == EOF)
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream)
|
||||
{
|
||||
size_t total_bytes = size * nitems;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
while (bytes_read < total_bytes)
|
||||
{
|
||||
if (stream->buffer_pos >= stream->buffer_size)
|
||||
{
|
||||
int res = call_read(stream->fd, stream->buffer, stream->buffer_size);
|
||||
if (res <= 0)
|
||||
{
|
||||
if (res == 0)
|
||||
stream->eof = 1;
|
||||
else
|
||||
stream->error = 1;
|
||||
break;
|
||||
}
|
||||
stream->buffer_pos = 0;
|
||||
stream->buffer_size = res;
|
||||
}
|
||||
|
||||
size_t bytes_to_copy = total_bytes - bytes_read;
|
||||
size_t available = stream->buffer_size - stream->buffer_pos;
|
||||
if (bytes_to_copy > available)
|
||||
bytes_to_copy = available;
|
||||
|
||||
memcpy((char *)ptr + bytes_read, stream->buffer + stream->buffer_pos, bytes_to_copy);
|
||||
stream->buffer_pos += bytes_to_copy;
|
||||
bytes_read += bytes_to_copy;
|
||||
}
|
||||
|
||||
return bytes_read / size;
|
||||
}
|
||||
|
||||
export FILE *freopen(const char *restrict, const char *restrict, FILE *restrict);
|
||||
export int fscanf(FILE *restrict, const char *restrict, ...);
|
||||
|
||||
export int fseek(FILE *stream, long offset, int whence)
|
||||
{
|
||||
int res = call_seek(stream->fd, offset, whence);
|
||||
if (res < 0)
|
||||
{
|
||||
stream->error = 1;
|
||||
return EOF;
|
||||
}
|
||||
stream->buffer_pos = 0;
|
||||
stream->buffer_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export int fseeko(FILE *, off_t, int);
|
||||
export int fsetpos(FILE *, const fpos_t *);
|
||||
|
||||
export long ftell(FILE *stream)
|
||||
{
|
||||
return call_tell(stream->fd);
|
||||
}
|
||||
|
||||
export off_t ftello(FILE *);
|
||||
export int ftrylockfile(FILE *);
|
||||
export void funlockfile(FILE *);
|
||||
|
||||
export size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream)
|
||||
{
|
||||
size_t total_bytes = size * nitems;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < total_bytes)
|
||||
{
|
||||
size_t bytes_to_copy = total_bytes - bytes_written;
|
||||
size_t space_available = stream->buffer_size - stream->buffer_pos;
|
||||
|
||||
if (bytes_to_copy > space_available)
|
||||
bytes_to_copy = space_available;
|
||||
|
||||
memcpy(stream->buffer + stream->buffer_pos, (const char *)ptr + bytes_written, bytes_to_copy);
|
||||
stream->buffer_pos += bytes_to_copy;
|
||||
bytes_written += bytes_to_copy;
|
||||
|
||||
if (stream->buffer_pos == stream->buffer_size)
|
||||
{
|
||||
if (call_write(stream->fd, stream->buffer, stream->buffer_size) != stream->buffer_size)
|
||||
{
|
||||
stream->error = 1;
|
||||
break;
|
||||
}
|
||||
stream->buffer_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_written / size;
|
||||
}
|
||||
|
||||
export int getc(FILE *);
|
||||
export int getchar(void);
|
||||
export int getc_unlocked(FILE *);
|
||||
export int getchar_unlocked(void);
|
||||
export ssize_t getdelim(char **restrict, size_t *restrict, int, FILE *restrict);
|
||||
export ssize_t getline(char **restrict, size_t *restrict, FILE *restrict);
|
||||
export FILE *open_memstream(char **, size_t *);
|
||||
export int pclose(FILE *);
|
||||
export void perror(const char *);
|
||||
export FILE *popen(const char *, const char *);
|
||||
|
||||
export int printf(const char *restrict format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vprintf_(format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export int putc(int c, FILE *stream) { return fputc(c, stream); }
|
||||
export int putchar(int c) { return putc(c, stdout); }
|
||||
export int putc_unlocked(int c, FILE *stream) { return fputc(c, stream); }
|
||||
export int putchar_unlocked(int c) { return putc_unlocked(c, stdout); }
|
||||
export int puts(const char *s) { return fputs(s, stdout); }
|
||||
|
||||
export int remove(const char *);
|
||||
export int rename(const char *, const char *);
|
||||
export int renameat(int, const char *, int, const char *);
|
||||
export void rewind(FILE *);
|
||||
export int scanf(const char *restrict, ...);
|
||||
export void setbuf(FILE *restrict, char *restrict);
|
||||
export int setvbuf(FILE *restrict, char *restrict, int, size_t);
|
||||
export int snprintf(char *restrict, size_t, const char *restrict, ...);
|
||||
export int sprintf(char *restrict, const char *restrict, ...);
|
||||
export int sscanf(const char *restrict, const char *restrict, ...);
|
||||
export FILE *tmpfile(void);
|
||||
export char *tmpnam(char *);
|
||||
export int ungetc(int, FILE *);
|
||||
export int vdprintf(int, const char *restrict, va_list);
|
||||
export int vfprintf(FILE *restrict, const char *restrict, va_list);
|
||||
export int vfscanf(FILE *restrict, const char *restrict, va_list);
|
||||
export int vprintf(const char *restrict, va_list);
|
||||
export int vscanf(const char *restrict, va_list);
|
||||
export int vsnprintf(char *restrict, size_t, const char *restrict, va_list);
|
||||
export int vsprintf(char *restrict, const char *restrict, va_list);
|
||||
export int vsscanf(const char *restrict, const char *restrict, va_list);
|
105
Userspace/libc/src/std/stdlib.c
Normal file
105
Userspace/libc/src/std/stdlib.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "../mem/liballoc_1_1.h"
|
||||
|
||||
#define MAX_ATEXIT_FUNCS 32
|
||||
typedef void (*atexit_func_t)(void);
|
||||
static atexit_func_t __atexit_funcs[MAX_ATEXIT_FUNCS];
|
||||
static int __num_atexit_funcs = 0;
|
||||
|
||||
export long a64l(const char *);
|
||||
export _Noreturn void abort(void)
|
||||
{
|
||||
kill(getpid(), SIGABRT);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
export int abs(int);
|
||||
|
||||
export int atexit(void (*func)(void))
|
||||
{
|
||||
if (__num_atexit_funcs >= MAX_ATEXIT_FUNCS)
|
||||
return -1;
|
||||
__atexit_funcs[__num_atexit_funcs++] = func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export double atof(const char *);
|
||||
export int atoi(const char *);
|
||||
export long int atol(const char *);
|
||||
export void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
export void *calloc(size_t, size_t);
|
||||
export div_t div(int, int);
|
||||
export double drand48(void);
|
||||
export char *ecvt(double, int, int *, int *);
|
||||
export double erand48(unsigned short int[3]);
|
||||
|
||||
export void exit(int status)
|
||||
{
|
||||
for (int i = __num_atexit_funcs - 1; i >= 0; --i)
|
||||
__atexit_funcs[i]();
|
||||
_exit(status);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
export char *fcvt(double, int, int *, int *);
|
||||
export void free(void *ptr) { return PREFIX(free)(ptr); }
|
||||
export char *gcvt(double, int, char *);
|
||||
export char *getenv(const char *);
|
||||
export int getsubopt(char **, char *const *, char **);
|
||||
export int grantpt(int);
|
||||
export char *initstate(unsigned int, char *, size_t);
|
||||
export long int jrand48(unsigned short int[3]);
|
||||
export char *l64a(long);
|
||||
export long int labs(long int);
|
||||
export void lcong48(unsigned short int[7]);
|
||||
export ldiv_t ldiv(long int, long int);
|
||||
export long int lrand48(void);
|
||||
export void *malloc(size_t size) { return PREFIX(malloc)(size); }
|
||||
export int mblen(const char *, size_t);
|
||||
export size_t mbstowcs(wchar_t *, const char *, size_t);
|
||||
export int mbtowc(wchar_t *, const char *, size_t);
|
||||
export char *mktemp(char *);
|
||||
export int mkstemp(char *);
|
||||
export long int mrand48(void);
|
||||
export long int nrand48(unsigned short int[3]);
|
||||
export char *ptsname(int);
|
||||
export int putenv(char *);
|
||||
export void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
export int rand(void);
|
||||
export int rand_r(unsigned int *);
|
||||
export long random(void);
|
||||
export void *realloc(void *, size_t);
|
||||
export char *realpath(const char *, char *);
|
||||
export unsigned short int seed48(unsigned short int[3]);
|
||||
export void setkey(const char *);
|
||||
export char *setstate(const char *);
|
||||
export void srand(unsigned int);
|
||||
export void srand48(long int);
|
||||
export void srandom(unsigned);
|
||||
export double strtod(const char *, char **);
|
||||
export long int strtol(const char *, char **, int);
|
||||
export unsigned long int strtoul(const char *, char **, int);
|
||||
export int system(const char *);
|
||||
export int ttyslot(void);
|
||||
export int unlockpt(int);
|
||||
export void *valloc(size_t);
|
||||
export size_t wcstombs(char *, const wchar_t *, size_t);
|
||||
export int wctomb(char *, wchar_t);
|
86
Userspace/libc/src/std/string.c
Normal file
86
Userspace/libc/src/std/string.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
export void *memccpy(void *restrict, const void *restrict, int, size_t);
|
||||
export void *memchr(const void *, int, size_t);
|
||||
export int memcmp(const void *, const void *, size_t);
|
||||
|
||||
export void *memcpy(void *restrict s1, const void *restrict s2, size_t n)
|
||||
{
|
||||
unsigned char *dest = (unsigned char *)s1;
|
||||
const unsigned char *src = (const unsigned char *)s2;
|
||||
|
||||
while (n >= sizeof(unsigned long))
|
||||
{
|
||||
*(unsigned long *)dest = *(const unsigned long *)src;
|
||||
dest += sizeof(unsigned long);
|
||||
src += sizeof(unsigned long);
|
||||
n -= sizeof(unsigned long);
|
||||
}
|
||||
|
||||
while (n--)
|
||||
*dest++ = *src++;
|
||||
return s1;
|
||||
}
|
||||
|
||||
export void *memmem(const void *, size_t, const void *, size_t);
|
||||
export void *memmove(void *, const void *, size_t);
|
||||
export void *memset(void *, int, size_t);
|
||||
export char *stpcpy(char *restrict, const char *restrict);
|
||||
export char *stpncpy(char *restrict, const char *restrict, size_t);
|
||||
export char *strcat(char *restrict, const char *restrict);
|
||||
export char *strchr(const char *, int);
|
||||
|
||||
export int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
while (*s1 && (*s1 == *s2))
|
||||
{
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
|
||||
return *(unsigned char *)s1 - *(unsigned char *)s2;
|
||||
}
|
||||
|
||||
export int strcoll(const char *, const char *);
|
||||
export int strcoll_l(const char *, const char *, locale_t);
|
||||
export char *strcpy(char *restrict, const char *restrict);
|
||||
export size_t strcspn(const char *, const char *);
|
||||
export char *strdup(const char *);
|
||||
export char *strerror(int);
|
||||
export char *strerror_l(int, locale_t);
|
||||
export int strerror_r(int, char *, size_t);
|
||||
export size_t strlcat(char *restrict, const char *restrict, size_t);
|
||||
export size_t strlcpy(char *restrict, const char *restrict, size_t);
|
||||
export size_t strlen(const char *);
|
||||
export char *strncat(char *restrict, const char *restrict, size_t);
|
||||
export int strncmp(const char *, const char *, size_t);
|
||||
export char *strncpy(char *restrict, const char *restrict, size_t);
|
||||
export char *strndup(const char *, size_t);
|
||||
export size_t strnlen(const char *, size_t);
|
||||
export char *strpbrk(const char *, const char *);
|
||||
export char *strrchr(const char *, int);
|
||||
export char *strsignal(int);
|
||||
export size_t strspn(const char *, const char *);
|
||||
export char *strstr(const char *, const char *);
|
||||
export char *strtok(char *restrict, const char *restrict);
|
||||
export char *strtok_r(char *restrict, const char *restrict, char **restrict);
|
||||
export size_t strxfrm(char *restrict, const char *restrict, size_t);
|
||||
export size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t);
|
@ -1,346 +0,0 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
/* Some of the functions are from musl library */
|
||||
/* https://www.musl-libc.org/ */
|
||||
/*
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
PUBLIC void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define LS >>
|
||||
#define RS <<
|
||||
#else
|
||||
#define LS <<
|
||||
#define RS >>
|
||||
#endif
|
||||
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
uint32_t w, x;
|
||||
|
||||
for (; (uintptr_t)s % 4 && n; n--)
|
||||
*d++ = *s++;
|
||||
|
||||
if ((uintptr_t)d % 4 == 0)
|
||||
{
|
||||
for (; n >= 16; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
*(u32 *)(d + 4) = *(u32 *)(s + 4);
|
||||
*(u32 *)(d + 8) = *(u32 *)(s + 8);
|
||||
*(u32 *)(d + 12) = *(u32 *)(s + 12);
|
||||
}
|
||||
if (n & 8)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
*(u32 *)(d + 4) = *(u32 *)(s + 4);
|
||||
d += 8;
|
||||
s += 8;
|
||||
}
|
||||
if (n & 4)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
d += 4;
|
||||
s += 4;
|
||||
}
|
||||
if (n & 2)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
if (n & 1)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n >= 32)
|
||||
{
|
||||
switch ((uintptr_t)d % 4)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 3;
|
||||
for (; n >= 17; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 1);
|
||||
*(u32 *)(d + 0) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s + 5);
|
||||
*(u32 *)(d + 4) = (x LS 24) | (w RS 8);
|
||||
x = *(u32 *)(s + 9);
|
||||
*(u32 *)(d + 8) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s + 13);
|
||||
*(u32 *)(d + 12) = (x LS 24) | (w RS 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 2;
|
||||
for (; n >= 18; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 2);
|
||||
*(u32 *)(d + 0) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s + 6);
|
||||
*(u32 *)(d + 4) = (x LS 16) | (w RS 16);
|
||||
x = *(u32 *)(s + 10);
|
||||
*(u32 *)(d + 8) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s + 14);
|
||||
*(u32 *)(d + 12) = (x LS 16) | (w RS 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
n -= 1;
|
||||
for (; n >= 19; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 3);
|
||||
*(u32 *)(d + 0) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s + 7);
|
||||
*(u32 *)(d + 4) = (x LS 8) | (w RS 24);
|
||||
x = *(u32 *)(s + 11);
|
||||
*(u32 *)(d + 8) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s + 15);
|
||||
*(u32 *)(d + 12) = (x LS 8) | (w RS 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n & 16)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 8)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 4)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 2)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 1)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
#endif
|
||||
|
||||
for (; n; n--)
|
||||
*d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
PUBLIC void *memset(void *dest, int c, size_t n)
|
||||
{
|
||||
unsigned char *s = dest;
|
||||
size_t k;
|
||||
|
||||
if (!n)
|
||||
return dest;
|
||||
|
||||
s[0] = c;
|
||||
s[n - 1] = c;
|
||||
|
||||
if (n <= 2)
|
||||
return dest;
|
||||
|
||||
s[1] = c;
|
||||
s[2] = c;
|
||||
s[n - 2] = c;
|
||||
s[n - 3] = c;
|
||||
|
||||
if (n <= 6)
|
||||
return dest;
|
||||
|
||||
s[3] = c;
|
||||
s[n - 4] = c;
|
||||
|
||||
if (n <= 8)
|
||||
return dest;
|
||||
|
||||
k = -(uintptr_t)s & 3;
|
||||
s += k;
|
||||
n -= k;
|
||||
n &= -4;
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
typedef uint64_t __attribute__((__may_alias__)) u64;
|
||||
|
||||
u32 c32 = ((u32)-1) / 255 * (unsigned char)c;
|
||||
*(u32 *)(s + 0) = c32;
|
||||
*(u32 *)(s + n - 4) = c32;
|
||||
|
||||
if (n <= 8)
|
||||
return dest;
|
||||
|
||||
*(u32 *)(s + 4) = c32;
|
||||
*(u32 *)(s + 8) = c32;
|
||||
*(u32 *)(s + n - 12) = c32;
|
||||
*(u32 *)(s + n - 8) = c32;
|
||||
|
||||
if (n <= 24)
|
||||
return dest;
|
||||
|
||||
*(u32 *)(s + 12) = c32;
|
||||
*(u32 *)(s + 16) = c32;
|
||||
*(u32 *)(s + 20) = c32;
|
||||
*(u32 *)(s + 24) = c32;
|
||||
*(u32 *)(s + n - 28) = c32;
|
||||
*(u32 *)(s + n - 24) = c32;
|
||||
*(u32 *)(s + n - 20) = c32;
|
||||
*(u32 *)(s + n - 16) = c32;
|
||||
|
||||
k = 24 + ((uintptr_t)s & 4);
|
||||
s += k;
|
||||
n -= k;
|
||||
|
||||
u64 c64 = c32 | ((u64)c32 << 32);
|
||||
for (; n >= 32; n -= 32, s += 32)
|
||||
{
|
||||
*(u64 *)(s + 0) = c64;
|
||||
*(u64 *)(s + 8) = c64;
|
||||
*(u64 *)(s + 16) = c64;
|
||||
*(u64 *)(s + 24) = c64;
|
||||
}
|
||||
#else
|
||||
for (; n; n--, s++)
|
||||
*s = c;
|
||||
#endif
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
PUBLIC void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
typedef __attribute__((__may_alias__)) size_t WT;
|
||||
#define WS (sizeof(WT))
|
||||
#endif
|
||||
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d == s)
|
||||
return d;
|
||||
|
||||
if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n)
|
||||
return memcpy(d, s, n);
|
||||
|
||||
if (d < s)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
|
||||
{
|
||||
while ((uintptr_t)d % WS)
|
||||
{
|
||||
if (!n--)
|
||||
return dest;
|
||||
|
||||
*d++ = *s++;
|
||||
}
|
||||
for (; n >= WS; n -= WS, d += WS, s += WS)
|
||||
*(WT *)d = *(WT *)s;
|
||||
}
|
||||
#endif
|
||||
for (; n; n--)
|
||||
*d++ = *s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
|
||||
{
|
||||
while ((uintptr_t)(d + n) % WS)
|
||||
{
|
||||
if (!n--)
|
||||
return dest;
|
||||
|
||||
d[n] = s[n];
|
||||
}
|
||||
while (n >= WS)
|
||||
n -= WS, *(WT *)(d + n) = *(WT *)(s + n);
|
||||
}
|
||||
#endif
|
||||
while (n)
|
||||
n--, d[n] = s[n];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../../mem/liballoc_1_1.h"
|
||||
|
||||
PUBLIC size_t strlen(const char *str)
|
||||
{
|
||||
long unsigned i = 0;
|
||||
if (str)
|
||||
while (str[i] != '\0')
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
PUBLIC int strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l == *r && *l; l++, r++)
|
||||
;
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
||||
|
||||
PUBLIC int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
char c1 = s1[i], c2 = s2[i];
|
||||
if (c1 != c2)
|
||||
return c1 - c2;
|
||||
if (!c1)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
const unsigned char *p1 = (const unsigned char *)s1;
|
||||
const unsigned char *p2 = (const unsigned char *)s2;
|
||||
int result;
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
while ((result = tolower(*p1) - tolower(*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
|
||||
PUBLIC int strncasecmp(const char *string1, const char *string2, size_t count)
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
const unsigned char *s1 = (const unsigned char *)string1;
|
||||
const unsigned char *s2 = (const unsigned char *)string2;
|
||||
int result;
|
||||
do
|
||||
{
|
||||
if ((result = tolower(*s1) - tolower(*s2++)) != 0 || !*s1++)
|
||||
break;
|
||||
} while (--count);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC char *strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
const char *a = haystack, *b = needle;
|
||||
while (1)
|
||||
{
|
||||
if (!*b)
|
||||
return (char *)haystack;
|
||||
if (!*a)
|
||||
return NULL;
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
a = ++haystack;
|
||||
b = needle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC char *strncpy(char *destination, const char *source, unsigned long num)
|
||||
{
|
||||
if (destination == NULL)
|
||||
return NULL;
|
||||
char *ptr = destination;
|
||||
while (*source && num--)
|
||||
{
|
||||
*destination = *source;
|
||||
destination++;
|
||||
source++;
|
||||
}
|
||||
*destination = '\0';
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PUBLIC char *strdup(const char *s)
|
||||
{
|
||||
char *buf = (char *)__malloc(strlen((char *)s) + 1);
|
||||
strncpy(buf, s, strlen(s) + 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PUBLIC char *strchr(char const *s, int c)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (s[i] == c)
|
||||
return (char *)s + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC char *strrchr(char const *s, int c)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t pos = len;
|
||||
|
||||
while (s[pos] != c && pos-- != 0)
|
||||
;
|
||||
|
||||
if (pos == len)
|
||||
return NULL;
|
||||
|
||||
return (char *)s + pos;
|
||||
}
|
49
Userspace/libc/src/std/sys/mman.c
Normal file
49
Userspace/libc/src/std/sys/mman.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <fennix/syscalls.h>
|
||||
#include <errno.h>
|
||||
|
||||
export int mlock(const void *, size_t);
|
||||
export int mlockall(int);
|
||||
|
||||
export void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
|
||||
{
|
||||
return (void *)__check_errno((__iptr)call_mmap(addr, len, prot, flags, fildes, off), (__iptr)MAP_FAILED);
|
||||
}
|
||||
|
||||
export int mprotect(void *addr, size_t len, int prot)
|
||||
{
|
||||
return __check_errno(call_mprotect(addr, len, prot), -1);
|
||||
}
|
||||
|
||||
export int msync(void *, size_t, int);
|
||||
export int munlock(const void *, size_t);
|
||||
export int munlockall(void);
|
||||
|
||||
export int munmap(void *addr, size_t len)
|
||||
{
|
||||
return __check_errno(call_munmap(addr, len), -1);
|
||||
}
|
||||
|
||||
export int posix_madvise(void *, size_t, int);
|
||||
export int posix_mem_offset(const void *restrict, size_t, off_t *restrict, size_t *restrict, int *restrict);
|
||||
export int posix_typed_mem_get_info(int, struct posix_typed_mem_info *);
|
||||
export int posix_typed_mem_open(const char *, int, int);
|
||||
export int shm_open(const char *, int, mode_t);
|
||||
export int shm_unlink(const char *);
|
@ -1,14 +0,0 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
PUBLIC pid_t wait(int *wstatus)
|
||||
{
|
||||
return waitpid(-1, &wstatus, 0);
|
||||
}
|
||||
|
||||
PUBLIC pid_t waitpid(pid_t pid, int *wstatus, int options)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)
|
||||
{
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int mkdir(const char *path, mode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int remove(const char *pathname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int rename(const char *oldpath, const char *newpath)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
PUBLIC int execl(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execlp(const char *file, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execle(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execv(const char *pathname, char *const argv[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execvp(const char *file, char *const argv[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execvpe(const char *file, char *const argv[], char *const envp[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execve(const char *pathname, char *const argv[], char *const envp[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC pid_t fork(void)
|
||||
{
|
||||
return syscall0(sc_fork);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
PUBLIC unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
// return syscall1(sys_Sleep, seconds * 1000000);
|
||||
}
|
||||
|
||||
PUBLIC int usleep(useconds_t usec)
|
||||
{
|
||||
// return syscall1(sys_Sleep, usec);
|
||||
}
|
112
Userspace/libc/src/std/unistd.c
Normal file
112
Userspace/libc/src/std/unistd.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fennix/syscalls.h>
|
||||
|
||||
export char *optarg;
|
||||
export int optind, opterr, optopt;
|
||||
|
||||
export int access(const char *, int);
|
||||
export unsigned int alarm(unsigned int);
|
||||
export int brk(void *);
|
||||
export int chdir(const char *);
|
||||
export int chroot(const char *);
|
||||
export int chown(const char *, uid_t, gid_t);
|
||||
export int close(int);
|
||||
export size_t confstr(int, char *, size_t);
|
||||
export char *crypt(const char *, const char *);
|
||||
export char *ctermid(char *);
|
||||
export char *cuserid(char *s);
|
||||
export int dup(int);
|
||||
export int dup2(int, int);
|
||||
export void encrypt(char[64], int);
|
||||
export int execl(const char *, const char *, ...);
|
||||
export int execle(const char *, const char *, ...);
|
||||
export int execlp(const char *, const char *, ...);
|
||||
export int execv(const char *, char *const[]);
|
||||
export int execve(const char *, char *const[], char *const[]);
|
||||
export int execvp(const char *, char *const[]);
|
||||
export void _exit(int);
|
||||
export int fchown(int, uid_t, gid_t);
|
||||
export int fchdir(int);
|
||||
export int fdatasync(int);
|
||||
export pid_t fork(void);
|
||||
export long int fpathconf(int, int);
|
||||
export int fsync(int);
|
||||
export int ftruncate(int, off_t);
|
||||
export char *getcwd(char *, size_t);
|
||||
export int getdtablesize(void);
|
||||
export gid_t getegid(void);
|
||||
export uid_t geteuid(void);
|
||||
export gid_t getgid(void);
|
||||
export int getgroups(int, gid_t[]);
|
||||
export long gethostid(void);
|
||||
export char *getlogin(void);
|
||||
export int getlogin_r(char *, size_t);
|
||||
export int getopt(int, char *const[], const char *);
|
||||
|
||||
export int getpagesize(void) { return 0x1000; } /* TODO: getpagesize */
|
||||
|
||||
export char *getpass(const char *);
|
||||
export pid_t getpgid(pid_t);
|
||||
export pid_t getpgrp(void);
|
||||
|
||||
export pid_t getpid(void) { return syscall0(SYS_GETPID); }
|
||||
export pid_t getppid(void) { return syscall0(SYS_GETPPID); }
|
||||
|
||||
export pid_t getsid(pid_t);
|
||||
export uid_t getuid(void);
|
||||
export char *getwd(char *);
|
||||
export int isatty(int);
|
||||
export int lchown(const char *, uid_t, gid_t);
|
||||
export int link(const char *, const char *);
|
||||
export int lockf(int, int, off_t);
|
||||
export off_t lseek(int, off_t, int);
|
||||
export int nice(int);
|
||||
export long int pathconf(const char *, int);
|
||||
export int pause(void);
|
||||
export int pipe(int[2]);
|
||||
export ssize_t pread(int, void *, size_t, off_t);
|
||||
export int pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
|
||||
export ssize_t pwrite(int, const void *, size_t, off_t);
|
||||
export ssize_t read(int, void *, size_t);
|
||||
export int readlink(const char *, char *, size_t);
|
||||
export int rmdir(const char *);
|
||||
export void *sbrk(intptr_t);
|
||||
export int setgid(gid_t);
|
||||
export int setpgid(pid_t, pid_t);
|
||||
export pid_t setpgrp(void);
|
||||
export int setregid(gid_t, gid_t);
|
||||
export int setreuid(uid_t, uid_t);
|
||||
export pid_t setsid(void);
|
||||
export int setuid(uid_t);
|
||||
export unsigned int sleep(unsigned int);
|
||||
export void swab(const void *, void *, ssize_t);
|
||||
export int symlink(const char *, const char *);
|
||||
export void sync(void);
|
||||
export long int sysconf(int);
|
||||
export pid_t tcgetpgrp(int);
|
||||
export int tcsetpgrp(int, pid_t);
|
||||
export int truncate(const char *, off_t);
|
||||
export char *ttyname(int);
|
||||
export int ttyname_r(int, char *, size_t);
|
||||
export useconds_t ualarm(useconds_t, useconds_t);
|
||||
export int unlink(const char *);
|
||||
export int usleep(useconds_t);
|
||||
export pid_t vfork(void);
|
||||
export ssize_t write(int, const void *, size_t);
|
60
Userspace/libc/src/syscall_check.cpp
Normal file
60
Userspace/libc/src/syscall_check.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fennix/syscalls.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
static_assert(__SYS_PROT_READ == PROT_READ);
|
||||
static_assert(__SYS_PROT_WRITE == PROT_WRITE);
|
||||
static_assert(__SYS_PROT_EXEC == PROT_EXEC);
|
||||
static_assert(__SYS_PROT_NONE == PROT_NONE);
|
||||
|
||||
static_assert(__SYS_MAP_SHARED == MAP_SHARED);
|
||||
static_assert(__SYS_MAP_PRIVATE == MAP_PRIVATE);
|
||||
static_assert(__SYS_MAP_FIXED == MAP_FIXED);
|
||||
static_assert(__SYS_MAP_ANONYMOUS == MAP_ANONYMOUS);
|
||||
static_assert(__SYS_MAP_ANON == MAP_ANON);
|
||||
|
||||
static_assert(__SYS_F_OK == F_OK);
|
||||
static_assert(__SYS_R_OK == R_OK);
|
||||
static_assert(__SYS_W_OK == W_OK);
|
||||
static_assert(__SYS_X_OK == X_OK);
|
||||
|
||||
static_assert(sizeof(__SYS_clockid_t) == sizeof(clockid_t));
|
||||
// static_assert(sizeof(__SYS_socklen_t) == sizeof(socklen_t));
|
||||
|
||||
static_assert(__SYS_SEEK_SET == SEEK_SET);
|
||||
static_assert(__SYS_SEEK_CUR == SEEK_CUR);
|
||||
static_assert(__SYS_SEEK_END == SEEK_END);
|
||||
|
||||
static_assert(__SYS_SA_NOCLDSTOP == SA_NOCLDSTOP);
|
||||
static_assert(__SYS_SA_NOCLDWAIT == SA_NOCLDWAIT);
|
||||
static_assert(__SYS_SA_SIGINFO == SA_SIGINFO);
|
||||
static_assert(__SYS_SA_ONSTACK == SA_ONSTACK);
|
||||
static_assert(__SYS_SA_RESTART == SA_RESTART);
|
||||
static_assert(__SYS_SA_NODEFER == SA_NODEFER);
|
||||
static_assert(__SYS_SA_RESETHAND == SA_RESETHAND);
|
||||
|
||||
static_assert(__SYS_CLOCK_MONOTONIC == CLOCK_MONOTONIC);
|
||||
static_assert(__SYS_CLOCK_PROCESS_CPUTIME_ID == CLOCK_PROCESS_CPUTIME_ID);
|
||||
static_assert(__SYS_CLOCK_REALTIME == CLOCK_REALTIME);
|
||||
static_assert(__SYS_CLOCK_THREAD_CPUTIME_ID == CLOCK_THREAD_CPUTIME_ID);
|
||||
|
||||
// static_assert( == );
|
41
Userspace/libc/src/tls.c
Normal file
41
Userspace/libc/src/tls.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of Fennix C Library.
|
||||
|
||||
Fennix C Library is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix C Library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fennix/syscalls.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <fennix/syscalls.h>
|
||||
|
||||
export __attribute__((naked, used, no_stack_protector)) void *__tls_get_addr(void *__data)
|
||||
{
|
||||
__asm__("ud2");
|
||||
}
|
||||
|
||||
int __init_pthread(void)
|
||||
{
|
||||
__pthread *ptr = (__pthread *)call_mmap(0,
|
||||
0x1000,
|
||||
__SYS_PROT_READ | __SYS_PROT_WRITE,
|
||||
__SYS_MAP_ANONYMOUS | __SYS_MAP_PRIVATE,
|
||||
-1, 0);
|
||||
call_prctl(__SYS_SET_FS, ptr, 0, 0, 0);
|
||||
ptr->Self = ptr;
|
||||
ptr->CurrentError = 0;
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user