From d07bd08dd0446e8c41eccaccbb07e9112200e8ee Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Sun, 24 May 2026 11:09:31 +0000 Subject: rename and move, function renames in stdio --- api/lib/kstdio.h | 18 -- api/lib/kstring.h | 14 - kc/boot/Makefile | 4 +- kc/boot/kc_main.c | 2 +- kc/core/Makefile | 6 +- kc/core/arch_thread.c | 4 +- kc/core/cpu/cpu.c | 4 +- kc/core/cpu/exceptions.h | 4 +- kc/core/i8042.c | 18 +- kc/core/kc_main.c | 4 +- kc/core/kstdio.c | 18 -- kc/core/memory.h | 2 +- kc/core/memory/memory.c | 24 +- kc/core/memory/page_early.c | 12 +- kc/core/panic.c | 6 +- kc/core/pic8259.c | 12 +- kc/core/pit8253.c | 6 +- kc/core/stdio.c | 18 ++ kc/core/task.c | 16 +- kc/core/video.c | 6 +- kc/core/vm_tree.c | 6 +- lib/api/libc/stdio.h | 18 ++ lib/api/libc/string.h | 14 + lib/kprintf.c | 653 -------------------------------------------- lib/libc/memcmp.c | 16 ++ lib/libc/memcpy.c | 12 + lib/libc/memmove.c | 20 ++ lib/libc/memset.c | 11 + lib/libc/printf.c | 653 ++++++++++++++++++++++++++++++++++++++++++++ lib/libc/string.c | 158 +++++++++++ lib/memcmp.c | 16 -- lib/memcpy.c | 12 - lib/memmove.c | 20 -- lib/memset.c | 11 - lib/string.c | 158 ----------- loader/main_efi.c | 44 +-- 36 files changed, 1011 insertions(+), 1009 deletions(-) delete mode 100644 api/lib/kstdio.h delete mode 100644 api/lib/kstring.h delete mode 100644 kc/core/kstdio.c create mode 100644 kc/core/stdio.c create mode 100644 lib/api/libc/stdio.h create mode 100644 lib/api/libc/string.h delete mode 100644 lib/kprintf.c create mode 100644 lib/libc/memcmp.c create mode 100644 lib/libc/memcpy.c create mode 100644 lib/libc/memmove.c create mode 100644 lib/libc/memset.c create mode 100644 lib/libc/printf.c create mode 100644 lib/libc/string.c delete mode 100644 lib/memcmp.c delete mode 100644 lib/memcpy.c delete mode 100644 lib/memmove.c delete mode 100644 lib/memset.c delete mode 100644 lib/string.c diff --git a/api/lib/kstdio.h b/api/lib/kstdio.h deleted file mode 100644 index 80e47cc..0000000 --- a/api/lib/kstdio.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -typedef struct FILE FILE; - -extern FILE *kstdout; -extern FILE *kstderr; - -extern int kfputc(int c, FILE *f); - -int kvfprintf(FILE *f, const char *restrict format, va_list arguments); -int kfprintf(FILE *f, const char *restrict format, ...); -int kvprintf(const char *restrict format, va_list arguments); -int kprintf(const char *restrict format, ...); - diff --git a/api/lib/kstring.h b/api/lib/kstring.h deleted file mode 100644 index c28e17c..0000000 --- a/api/lib/kstring.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -void *memcpy(void *dest, const void *src, size_t size); -void *memmove(void *dest, const void *src, size_t size); -void *memset(void *dest, int val, size_t size); -int memcmp(const void *str1, const void *str2, size_t count); -size_t strlen(const char *s); -unsigned long long strtoull( - const char *restrict begin, - char **restrict end, - int base); - diff --git a/kc/boot/Makefile b/kc/boot/Makefile index b90f183..d0c1d76 100644 --- a/kc/boot/Makefile +++ b/kc/boot/Makefile @@ -2,12 +2,12 @@ include ../../defaults.mk include ../../efi.mk include ../defaults.mk -VPATH := ../../lib ../ +VPATH := ../../lib ../ ../../lib/libc TARGET := efi.os .DEFAULT: $(TARGET) -CPPFLAGS += -I../../api -I ../api -I../../lib +CPPFLAGS += -I../../api -I ../api -I../../lib/api CFLAGS += -fshort-wchar diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c index 943c082..e0f1786 100644 --- a/kc/boot/kc_main.c +++ b/kc/boot/kc_main.c @@ -10,7 +10,7 @@ #include -#include +#include #include #define KERNEL_IMAGE_BASE 0xffffffff80000000 diff --git a/kc/core/Makefile b/kc/core/Makefile index 56ddf55..9791762 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -1,12 +1,12 @@ include ../../defaults.mk include ../defaults.mk -VPATH := ../../lib ../ cpu/ memory/ +VPATH := ../../lib ../../lib/libc ../ cpu/ memory/ TARGET := kernel.os .DEFAULT: $(TARGET) -CPPFLAGS += -I../../api -I../api -I../../lib -I. +CPPFLAGS += -I../../api -I../api -I../../lib/api -I. CFLAGS += -mcmodel=small -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g AOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o @@ -14,7 +14,7 @@ COBJS := mmu.o cpu_thread.o irq.o exceptions.o cpu.o msr.o mmu.o port.o arch_thr POBJS := pic8259.o pic8259_isr.o pit8253.o i8042.o GOBJS := serial.o kc_main.o memory.o vm_tree.o panic.o task.o \ kcc_memory.o page_early.o page_stack.o video.o -LOBJS := kprintf.o memset.o memcpy.o memmove.o memcmp.o kstdio.o string.o +LOBJS := printf.o memset.o memcpy.o memmove.o memcmp.o stdio.o string.o OBJS := $(AOBJS) $(COBJS) $(POBJS) $(GOBJS) $(LOBJS) DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/kc/core/arch_thread.c b/kc/core/arch_thread.c index 180923d..c0d707a 100644 --- a/kc/core/arch_thread.c +++ b/kc/core/arch_thread.c @@ -1,8 +1,10 @@ #include #include #include + +#include + #include "task.h" -#include struct arch_register_context { diff --git a/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c index f61ed00..0eaccb7 100644 --- a/kc/core/cpu/cpu.c +++ b/kc/core/cpu/cpu.c @@ -10,7 +10,7 @@ #include #include -#include +#include #define GDT_ENTRIES 16 #define IDT_ENTRIES 256 @@ -53,7 +53,7 @@ uint64_t *get_tss_rsp0(void) static void syscall_entry(void) { - kprintf("system call\n"); + printf("system call\n"); halt(); } diff --git a/kc/core/cpu/exceptions.h b/kc/core/cpu/exceptions.h index 7babb65..14a2088 100644 --- a/kc/core/cpu/exceptions.h +++ b/kc/core/cpu/exceptions.h @@ -21,7 +21,7 @@ #ifndef __ASSEMBLER__ -#include +#include struct isr_context_param_regs { @@ -53,7 +53,7 @@ struct isr_context static inline void print_exception_context(struct isr_context *context) { - kprintf( + printf( "exception %#hhx:%x context:\n" "interrupt entry state:\n" "rip: %#hx:%p rflags: %#0.16lx\n" diff --git a/kc/core/i8042.c b/kc/core/i8042.c index 0ba12dc..f6b63b0 100644 --- a/kc/core/i8042.c +++ b/kc/core/i8042.c @@ -2,7 +2,7 @@ #include "port.h" #include "i8042.h" #include "pic8259.h" -#include +#include static void i8042_init(void); static void i8042_enable(void) {} @@ -99,21 +99,21 @@ static void i8042_set_config(void) i8042_command(0x20); uint8_t config_byte; i8042_read(&config_byte); - kprintf("i8042: current config: %#0.2x\n", config_byte); + printf("i8042: current config: %#0.2x\n", config_byte); config_byte &= 0xfc; if (config_byte & (0x1 << 5)) { maybe_dual_channel = true; } config_byte |= 0x01; - kprintf("i8042: new config: %#0.2x\n", config_byte); + printf("i8042: new config: %#0.2x\n", config_byte); i8042_command(0x60); i8042_write(config_byte); i8042_command(0xaa); uint8_t bist_result; if (i8042_read(&bist_result) && bist_result != 0x55) { - kprintf("i8042: warning: error self-testing device. aborting.\n"); + printf("i8042: warning: error self-testing device. aborting.\n"); return; } @@ -124,11 +124,11 @@ static void i8042_set_config(void) uint8_t config_byte; if (i8042_read(&config_byte) && config_byte & (0x1 << 5)) { - kprintf("i8042: single-channel controller detected\n"); + printf("i8042: single-channel controller detected\n"); } else { - kprintf("i8042: dual-channel controller detected\n"); + printf("i8042: dual-channel controller detected\n"); is_dual_channel = true; } } @@ -136,7 +136,7 @@ static void i8042_set_config(void) outb(PS2_COMMAND, 0xab); if (inb(PS2_DATA) != 0x00) { - kprintf("i8042: failed testing port a\n"); + printf("i8042: failed testing port a\n"); } else { @@ -147,7 +147,7 @@ static void i8042_set_config(void) outb(PS2_COMMAND, 0xa9); if (inb(PS2_DATA) != 0x00) { - kprintf("i8042: failed testing port b\n"); + printf("i8042: failed testing port b\n"); } else { @@ -162,7 +162,7 @@ static void i8042_set_config(void) i8042_write(0xff); if(inb(PS2_DATA) == 0xfa && inb(PS2_DATA) == 0xaa) { - kprintf("i8042: detected device on channel, type %#0.2x\n", inb(PS2_DATA)); + printf("i8042: detected device on channel, type %#0.2x\n", inb(PS2_DATA)); } } diff --git a/kc/core/kc_main.c b/kc/core/kc_main.c index 9a84727..4f70d00 100644 --- a/kc/core/kc_main.c +++ b/kc/core/kc_main.c @@ -10,7 +10,7 @@ #include "i8042.h" #include -#include +#include #include #include @@ -27,7 +27,7 @@ unsigned long kc_main(struct kc_boot_data *data) cpu_init(); serial_init(); video_init(); - kprintf("sophia starting, boot data %#lx\n", boot_data); + printf("sophia starting, boot data %#lx\n", boot_data); memory_init(); pic8259_init(); pit8253_timer_source.init(); diff --git a/kc/core/kstdio.c b/kc/core/kstdio.c deleted file mode 100644 index 680eb07..0000000 --- a/kc/core/kstdio.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "serial.h" -#include "video.h" - -#include -#include - -#include -#include - -FILE *kstdout; - -int kfputc(int c, FILE *f) -{ - (void)f; - video_putchar(c); - return serial_putchar(c); -} - diff --git a/kc/core/memory.h b/kc/core/memory.h index 6f70e57..425c2cd 100644 --- a/kc/core/memory.h +++ b/kc/core/memory.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include diff --git a/kc/core/memory/memory.c b/kc/core/memory/memory.c index 1c6fabb..82fba3f 100644 --- a/kc/core/memory/memory.c +++ b/kc/core/memory/memory.c @@ -20,7 +20,7 @@ #include #include -#include +#include #define align_next(x, a) (x + a - 1) & ~(a - 1) @@ -89,7 +89,7 @@ struct vm_tree *vm_get_tree(void) void page_init(void) { - kprintf("initializing page frame allocator\n"); + printf("initializing page frame allocator\n"); page_early_init(); page_stack_init(); } @@ -98,7 +98,7 @@ void page_init_final(void) { if (current_alloc_func == boot_page_alloc) { - kprintf("finishing page frame allocator initialization\n"); + printf("finishing page frame allocator initialization\n"); page_early_final(); current_alloc_func = page_stack_alloc; } @@ -176,7 +176,7 @@ static void *map_tableset(void *vaddr, uint64_t *tables[TABLESET_COUNT]) } else { - kprintf("error: failed allocating memory for page table\n"); + printf("error: failed allocating memory for page table\n"); PANIC(OUT_OF_MEMORY); } } @@ -380,7 +380,7 @@ static void temp_page_unmap(void *vaddr) static void vm_init(void) { - kprintf("initializing vm state\n"); + printf("initializing vm state\n"); struct kc_boot_data *boot_data = get_boot_data(); struct vm_core_static_state *states = &vm_state.statics[0]; @@ -433,7 +433,7 @@ static void vm_init(void) vm_state.zero_page = page_alloc(PAGE_ALLOC_CONV); if (!vm_state.zero_page) { - kprintf("failed allocating for zero page\n"); + printf("failed allocating for zero page\n"); PANIC(GENERAL_PANIC); } @@ -441,7 +441,7 @@ static void vm_init(void) if (!zero_temp) { - kprintf("failed mapping zero page for initialization\n"); + printf("failed mapping zero page for initialization\n"); PANIC(GENERAL_PANIC); } @@ -492,7 +492,7 @@ void *heap_alloc(size_t size) if ((void *)-1ULL == heap_root) { struct vm_tree_node *heap_node = &vm_state.statics[HEAP_VM_STATE].node; - kprintf("initializing heap at %#lx of %zu bytes\n", + printf("initializing heap at %#lx of %zu bytes\n", heap_node->key.address, heap_node->key.size); heap_root = NULL; header = (struct heap_header *)heap_node->key.address; @@ -631,7 +631,7 @@ int anonymous_page_handler( if (!paddr) { - kprintf("got zero from page_alloc :|\n"); + printf("got zero from page_alloc :|\n"); PANIC(OUT_OF_MEMORY); } page_map_at( @@ -657,14 +657,14 @@ void page_fault_handler(struct isr_context *context) if (!node) { print_exception_context(context); - kprintf("error: page fault in unmanaged address %#lx\n", address); + printf("error: page fault in unmanaged address %#lx\n", address); PANIC(UNHANDLED_FAULT); } if (!node->object->handler) { print_exception_context(context); - kprintf("error: vm object at %p has no fault handler\n"); + printf("error: vm object at %p has no fault handler\n"); PANIC(UNHANDLED_FAULT); } @@ -674,7 +674,7 @@ void page_fault_handler(struct isr_context *context) void general_protection_handler(struct isr_context *context) { //TODO: implement #gp handler - kprintf("general protection violation\n"); + printf("general protection violation\n"); print_exception_context(context); PANIC(UNHANDLED_FAULT); } diff --git a/kc/core/memory/page_early.c b/kc/core/memory/page_early.c index 9ac90d2..989f82a 100644 --- a/kc/core/memory/page_early.c +++ b/kc/core/memory/page_early.c @@ -1,7 +1,7 @@ #include "page_early.h" #include "panic.h" -#include +#include static struct page_early_state { @@ -13,20 +13,20 @@ early_state; void page_early_init(void) { - kprintf("initializing early page frame allocator\n"); + printf("initializing early page frame allocator\n"); struct kc_boot_data *boot_data = get_boot_data(); early_state.first = &boot_data->memory.entries[0]; early_state.last = &boot_data->memory.entries[boot_data->memory.count]; early_state.current = early_state.first; - /*kprintf("memory ranges\n"); + /*printf("memory ranges\n"); struct memory_range *current = early_state.first; do { - kprintf("base %#0.16lx size %#0.16lx type %d\n", current->base, current->size, current->type); + printf("base %#0.16lx size %#0.16lx type %d\n", current->base, current->size, current->type); current++; } while (current != early_state.last); @@ -37,7 +37,7 @@ void page_early_final(void) { if (early_state.first) { - kprintf("finalizing early page allocator\n"); + printf("finalizing early page allocator\n"); for (struct memory_range *current = early_state.first; current < early_state.last; current++) @@ -101,7 +101,7 @@ kc_phys_addr page_early_alloc(enum page_alloc_flags type) early_state.current++; } - kprintf("error: early allocator has run out of memory\n"); + printf("error: early allocator has run out of memory\n"); PANIC(OUT_OF_MEMORY); } diff --git a/kc/core/panic.c b/kc/core/panic.c index 7844487..02c58c7 100644 --- a/kc/core/panic.c +++ b/kc/core/panic.c @@ -1,6 +1,6 @@ #include "panic.h" -#include +#include #include @@ -13,12 +13,12 @@ static char const *reason_strings[] = { noreturn void panic(const char *file, int line, enum panic_reason reason) { - // TODO: kprintf() and friends + // TODO: printf() and friends if (reason > sizeof(reason_strings) / sizeof(*reason_strings)) { reason = 0; } - kprintf( + printf( "kernel panic:%s:%u %s\n", file, line, diff --git a/kc/core/pic8259.c b/kc/core/pic8259.c index 4ddd2e1..792d0bd 100644 --- a/kc/core/pic8259.c +++ b/kc/core/pic8259.c @@ -4,7 +4,7 @@ #include -#include +#include #define ICW1_ICW4 0x1 #define ICW1_SINGLE 0x2 @@ -28,7 +28,7 @@ void pic8259_irq_install(uint8_t irq, pic8259_handler_func h) { if (irq_handlers[irq]) { - kprintf("attempt to overwrite irq handler for %u\n", irq); + printf("attempt to overwrite irq handler for %u\n", irq); return; } irq_handlers[irq] = h; @@ -43,7 +43,7 @@ static void wait(void) void pic8259_init(void) { - kprintf("initializing legacy pic\n"); + printf("initializing legacy pic\n"); // basic init. not gonna fret with this too much outb(PIC_PRI_CMD, ICW1_INIT|ICW1_ICW4); wait(); @@ -171,7 +171,7 @@ void pic8259_irq_begin(uint8_t irq) // check for spurious activations if (irq_is_spurious(irq)) { - kprintf("spurious activation of irq%hhu\n", irq); + printf("spurious activation of irq%hhu\n", irq); return; } @@ -181,12 +181,12 @@ void pic8259_irq_begin(uint8_t irq) if (result) { - kprintf("error handling irq%hhu: % d\n", irq, result); + printf("error handling irq%hhu: % d\n", irq, result); } } else { - kprintf("unhandled irq%hhu\n", irq); + printf("unhandled irq%hhu\n", irq); } pic8259_irq_end(irq); diff --git a/kc/core/pit8253.c b/kc/core/pit8253.c index 360808f..31cf349 100644 --- a/kc/core/pit8253.c +++ b/kc/core/pit8253.c @@ -5,7 +5,7 @@ #include -#include +#include #define PIT8253_DATA0 0x40 #define PIT8253_CMD 0x43 @@ -82,9 +82,9 @@ void pit8253_set_frequency(uint32_t frequency) if (d > UINT16_MAX) { - kprintf("warning: %uHz is too slow for 8253 pit\n", PIT_HZ/d); + printf("warning: %uHz is too slow for 8253 pit\n", PIT_HZ/d); d = UINT16_MAX; - kprintf("warning: set timer to minimum frequency\n"); + printf("warning: set timer to minimum frequency\n"); } set_divisor(d); diff --git a/kc/core/stdio.c b/kc/core/stdio.c new file mode 100644 index 0000000..66c539f --- /dev/null +++ b/kc/core/stdio.c @@ -0,0 +1,18 @@ +#include "serial.h" +#include "video.h" + +#include +#include + +#include +#include + +FILE *stdout; + +int fputc(int c, FILE *f) +{ + (void)f; + video_putchar(c); + return serial_putchar(c); +} + diff --git a/kc/core/task.c b/kc/core/task.c index 5eaa3fb..a298a05 100644 --- a/kc/core/task.c +++ b/kc/core/task.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include "arch_thread.h" @@ -110,7 +110,7 @@ static volatile atomic_bool preempt_switch_flag = false; static void *idle_thread_entry(void *) { - kprintf("idle thread started\n"); + printf("idle thread started\n"); __asm__ ("sti"); @@ -132,7 +132,7 @@ static void *sleepy_thread_entry(void *p) { sleep_thread(sleep_nanoseconds); thread_slept_count++; - kprintf("thread slept %d times\n", thread_slept_count); + printf("thread slept %d times\n", thread_slept_count); } (void)thread_slept_count; @@ -414,19 +414,19 @@ union kc_thread_result kct_wait(struct kc_thread *target) static void *waited_thread_test(void *) { - kprintf("worker thread, sleeping for some time...\n"); + printf("worker thread, sleeping for some time...\n"); sleep_thread(30000000000); return (void *)1; } static void *waiting_thread_test(void *) { - kprintf("waiting thread\n"); + printf("waiting thread\n"); struct kc_thread *t = create_thread(waited_thread_test, nullptr); t->status = READY; thread_queue_push_back(&ready_queue, t); union kc_thread_result r = kct_wait(t); - kprintf("waited thread terminated result: %d\n", r); + printf("waited thread terminated result: %d\n", r); return nullptr; } @@ -439,7 +439,7 @@ noreturn void task_init(void) timesource = &pit8253_timer_source; timesource->append_callback(sleeping_thread_callback); timesource->start(); - kprintf( + printf( "starting task management, timesource delta %luns\n", timesource->nanoseconds_delta()); @@ -454,7 +454,7 @@ noreturn void task_init(void) thread_queue_push(&ready_queue, idle_thread); block_thread(BLOCKED); // shouldn't ever get here - kprintf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n"); + printf("the idle thread exited somehow. we're back in the boot thread. this is not good.\n"); PANIC(DEAD_END); } diff --git a/kc/core/video.c b/kc/core/video.c index 6d89c08..a3bdce2 100644 --- a/kc/core/video.c +++ b/kc/core/video.c @@ -46,8 +46,8 @@ #include -#include -#include +#include +#include #include #include @@ -227,7 +227,7 @@ int video_init(void) } } - kprintf("video output %ix%i pixels, %i bytes per line, %s 32 bytes per pixel\n", + printf("video output %ix%i pixels, %i bytes per line, %s 32 bytes per pixel\n", boot_data->width, boot_data->height, boot_data->pitch, video_format_name); diff --git a/kc/core/vm_tree.c b/kc/core/vm_tree.c index 9bab154..72affe8 100644 --- a/kc/core/vm_tree.c +++ b/kc/core/vm_tree.c @@ -31,8 +31,8 @@ #include "vm_tree.h" #include "panic.h" -#include -#include +#include +#include #define assert(expr) @@ -102,7 +102,7 @@ void vmt_init_node( } else { - kprintf("fatal: attempt to insert overlapping vm node\n" + printf("fatal: attempt to insert overlapping vm node\n" "node 1: %p: %p @ %zu bytes\n" "node 2: %p: %p @ %zu bytes\n", node->key.address, node->key.size, diff --git a/lib/api/libc/stdio.h b/lib/api/libc/stdio.h new file mode 100644 index 0000000..1edec4a --- /dev/null +++ b/lib/api/libc/stdio.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +typedef struct FILE FILE; + +extern FILE *stdout; +extern FILE *stderr; + +extern int fputc(int c, FILE *f); + +int vfprintf(FILE *f, const char *restrict format, va_list arguments); +int fprintf(FILE *f, const char *restrict format, ...); +int vprintf(const char *restrict format, va_list arguments); +int printf(const char *restrict format, ...); + diff --git a/lib/api/libc/string.h b/lib/api/libc/string.h new file mode 100644 index 0000000..c28e17c --- /dev/null +++ b/lib/api/libc/string.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +void *memcpy(void *dest, const void *src, size_t size); +void *memmove(void *dest, const void *src, size_t size); +void *memset(void *dest, int val, size_t size); +int memcmp(const void *str1, const void *str2, size_t count); +size_t strlen(const char *s); +unsigned long long strtoull( + const char *restrict begin, + char **restrict end, + int base); + diff --git a/lib/kprintf.c b/lib/kprintf.c deleted file mode 100644 index 3d803f6..0000000 --- a/lib/kprintf.c +++ /dev/null @@ -1,653 +0,0 @@ -#include -#include -#include -#include - -enum specifier_type -{ - INVALID_PRINT, - CHARACTER_PRINT, - STRING_PRINT, - INTEGER_PRINT, - COUNT_PRINT -}; - -enum specifier_flags -{ - INVALID_FLAGS, - LEFT_JUSTIFY_FLAG = 0x1, - EXPLICIT_SIGN_FLAG = 0x2, - PAD_SIGN_FLAG = 0x4, - SIGNED_TYPE_FLAG = 0x8, - SIGN_FLAG_MASK = 0x6, - ALTERNATE_FORM_FLAG = 0x10, - ZERO_PAD_FLAG = 0x20, -}; - -enum specifier_integer_base -{ - INVALID_BASE, - BIN_BASE = 2, - OCT_BASE = 8, - DEC_BASE = 10, - HEX_BASE = 16 -}; - -enum specifier_integer_width -{ - INVALID_WIDTH, - BYTE_WIDTH = 8, - SHORT_WIDTH = 16, - INT_WIDTH = 32, - LONG_WIDTH = 64 -}; - -struct method -{ - int (*write_character)(struct method *m, char c); - int (*write_wcharacter)(struct method *m, wchar_t c); - int (*write_string)(struct method *m, const char *s); - int (*write_wstring)(struct method *m, const wchar_t *s); - void *output; - int count; -}; - -struct specifier -{ - enum specifier_type type; - enum specifier_flags flags; - enum specifier_integer_width integer_width; - enum specifier_integer_base integer_base; - int field_width; - int field_precision; - size_t length; -}; - -static struct specifier parse_specifier(const char *format, va_list *arguments) -{ - struct specifier result = - { - INVALID_PRINT, - INVALID_FLAGS, - INVALID_WIDTH, - INVALID_BASE, - 0, - 0, - 0 - }; - - // keep a pointer to the beginning of the specifier - const char *begin = format; - - // step 1: scan for flags - bool flags_parsed = false; - - while (!flags_parsed) - { - switch (*begin) - { - case 0: - result.type = INVALID_PRINT; - return result; - case '-': - result.flags |= LEFT_JUSTIFY_FLAG; - begin++; - break; - case '+': - result.flags |= EXPLICIT_SIGN_FLAG; - begin++; - break; - case ' ': - result.flags |= PAD_SIGN_FLAG; - begin++; - break; - case '#': - result.flags |= ALTERNATE_FORM_FLAG; - begin++; - break; - case '0': - result.flags |= ZERO_PAD_FLAG; - begin++; - break; - default: - flags_parsed = true; - } - } - - // step 2: parse field width and precision - // TODO: parse field width and precision - /* procedure: - * 1. check if next character is * or . - * a. if *, field width is the value pointed to by the next item in - * arguments list - * b. if ., field width will be set to 0, proceed to 3. - * 2. if above check is false, check for numeric character - * a. if is numeric character, parse field width via strtoul, add length - * of numeric string to begin. - * b. if is not a numeric character, skip check for width and precision - * entirely - * 3. check if next character is * or numeric - * a. if *, field precision is the value pointed to by the next item - * in arguments list. - * b. if is numeric character, parse field precision via strtoul, add - * length of numeric string to begin. - */ - bool field_width_parsed = false; - bool field_precision_parsed = false; - - while (!field_width_parsed || !field_precision_parsed) - { - switch (*begin) - { - case '.': - if (!field_width_parsed) - { - result.field_width = 0; - field_width_parsed = true; - begin++; - } - else - { - // the specifier is invalid! - result.type = INVALID_PRINT; - } - break; - case '*': - { - int w = *va_arg(*arguments, int *); - if (!field_width_parsed) - { - result.field_width = w; - field_width_parsed = true; - } - else - { - result.field_precision = w; - field_precision_parsed = true; - } - begin++; - } - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - { - char *next; - unsigned long long w = strtoull(begin, &next, 10); - if (!field_width_parsed) - { - result.field_width = (int)w; - field_width_parsed = true; - } - else if (!field_precision_parsed) - { - result.field_precision = (int)w; - field_precision_parsed = true; - } - if (next > begin) - { - begin = next; - } - } - break; - default: - field_width_parsed = true; - field_precision_parsed = true; - } - } - - // step 3: check for type width arguments - switch (*begin) - { - case 0: // unexpected eos - result.type = INVALID_PRINT; - return result; - case 'h': - { - if (begin[0] == begin[1]) - { - result.integer_width = BYTE_WIDTH; - begin += 2; - } - else - { - result.integer_width = SHORT_WIDTH; - begin++; - } - break; - } - case 'l': - { - // TODO: deal with LLP64? idk. - if (begin[0] == begin[1]) - { - begin += 2; - } - else - { - begin++; - } - result.integer_width = LONG_WIDTH; - break; - } - case 'j': - // TODO: use INTMAX_T_WIDTH - result.integer_width = 64; - begin++; - break; - case 'z': - // TODO: use SIZE_T_WIDTH? - result.integer_width = 64; - begin++; - break; - case 't': - // TODO: use PTRDIFF_T_WIDTH? - result.integer_width = 32; - begin++; - break; - default: - // there is no width argument to be found. - result.integer_width = INT_WIDTH; - break; - } - - // step 4: parse field type - switch (*begin) - { - // unexpected EOS - case 0: - result.type = INVALID_PRINT; - return result; - case 'c': - result.type = CHARACTER_PRINT; - break; - case 's': - result.type = STRING_PRINT; - break; - case 'd': - case 'i': - result.type = INTEGER_PRINT; - result.flags |= SIGNED_TYPE_FLAG; - result.integer_base = DEC_BASE; - break; - case 'u': - result.type = INTEGER_PRINT; - result.integer_base = DEC_BASE; - break; - case 'b': - result.type = INTEGER_PRINT; - result.integer_base = BIN_BASE; - break; - case 'o': - result.type = INTEGER_PRINT; - result.integer_base = OCT_BASE; - break; - case 'x': - result.type = INTEGER_PRINT; - result.integer_base = HEX_BASE; - break; - case 'p': - // TODO: use UINTPTR_T_WIDTH here? - // pointer type overrides all flags - // i can do what i want it says "implementation-defined" in the spec - result.field_precision = 16; - result.type = INTEGER_PRINT; - result.integer_base = HEX_BASE; - result.integer_width = LONG_WIDTH; - result.flags = ALTERNATE_FORM_FLAG|ZERO_PAD_FLAG; - break; - case 'n': - // all flags are invalid/ignored and the current count will be - // stored in the value pointed to by the argument - result.type = COUNT_PRINT; - result.flags = INVALID_FLAGS; - result.integer_width = INVALID_WIDTH; - result.field_width = 0; - result.field_precision = 0; - break; - default: - // this byte of the specifier _must_ be valid. if not, - // the procedure to print should not proceed as it might - // output garbage. - // TODO: specify somehow in the output that the format is bad? - result.type = INVALID_PRINT; - return result; - } - - begin++; - - result.length = begin - format; - return result; -} - -static char *convert_integer( - uint64_t value, - unsigned base, - int zpadding, - char *buffer, - size_t bufsz) -{ - static const char *stringdigits = "0123456789abcdef"; - - // the string will be built from the lower-to-higher value, and the - // result pointer will point to the first character of the string in - // the supplied buffer - - // cannot currently work with a base > 16 - if (base > 16) - { - return NULL; - } - - // make absolutely sure there are no excess bits - - // the string is being built backwards, so the pointer needs to be - // at the last byte of the string - char *result = buffer + bufsz - 1; - - // result >= buffer condition ensures we don't underflow - - do - { - *--result = stringdigits[value % base]; - zpadding--; - value /= base; - } - while (value > 0 && result >= buffer); - - while (zpadding-- > 0 && result >= buffer) - { - *--result = '0'; - } - - return result; -} - -static int print_character( - struct method *m, - struct specifier *spec, - va_list *arguments) -{ - (void)spec; - // all specifier flags and etc. are ignored. - return m->write_character(m, va_arg(*arguments, int)); -} - -static int print_string( - struct method *m, - struct specifier *spec, - va_list *arguments) -{ - // TODO: respect field width - if (spec->integer_width == LONG_WIDTH) - { - return m->write_wstring(m, va_arg(*arguments, const wchar_t *)); - } - return m->write_string(m, va_arg(*arguments, const char *)); -} - -static inline bool is_negative(uint64_t value, unsigned width) -{ - switch (width) - { - case BYTE_WIDTH: - return ((int8_t)value) < 0; - case SHORT_WIDTH: - return ((int16_t)value) < 0; - case INT_WIDTH: - return ((int32_t)value) < 0; - case LONG_WIDTH: - return ((int64_t)value) < 0; - default: - return false; - } -} - -static int print_integer( - struct method *m, - struct specifier *spec, - va_list *arguments) -{ - // 65 bytes is the maximum length that convert_integer will need - // i.e. conversion of uintmax_t to binary plus NUL terminator - // TODO: use UINTMAX_T_WIDTH + 1? - char buffer[65] = {0}; - char *s; - bool negative = false; - uint64_t value = 0; - int r = 0; - unsigned zpad = 0; - - switch (spec->integer_width) - { - case BYTE_WIDTH: - case SHORT_WIDTH: - case INT_WIDTH: - value = va_arg(*arguments, unsigned int); - break; - case LONG_WIDTH: - value = va_arg(*arguments, uint64_t); - break; - default: - return -1; - } - - // check if we need to bother with signs - if (spec->flags & SIGNED_TYPE_FLAG) - { - if ((negative = is_negative(value, spec->integer_width))) - { - value = ~value + 1; - } - - if (negative) - { - r = m->write_character(m, '-'); - } - - else if (!negative && (spec->flags & SIGN_FLAG_MASK)) - { - if (spec->flags & EXPLICIT_SIGN_FLAG) - { - r = m->write_character(m, '+'); - } - else - { - r = m->write_character(m, ' '); - } - } - } - - // zero all the unnecessary bits - value &= (2ULL << (spec->integer_width - 1)) - 1; - - switch (spec->integer_base) - { - case BIN_BASE: - if (spec->flags & ALTERNATE_FORM_FLAG) - { - r = m->write_string(m, "0b"); - } - break; - case OCT_BASE: - if (spec->flags & ALTERNATE_FORM_FLAG) - { - r = m->write_character(m, '0'); - } - break; - case HEX_BASE: - if (spec->flags & ALTERNATE_FORM_FLAG) - { - r = m->write_string(m, "0x"); - } - break; - default: - break; - } - - if (spec->flags & ZERO_PAD_FLAG) - { - zpad = spec->field_precision; - } - s = convert_integer(value, spec->integer_base, zpad, buffer, sizeof(buffer)); - - if (s) - { - m->write_string(m, s); - } - else - { - m->write_string(m, "(INVALID)"); - r = -1; - } - - return r; -} - -static int printf_internal( - struct method *m, - const char *restrict format, - va_list *arguments) -{ - int r = 0; - - while (*format && !r) - { - // case 1: not a format specification - if (*format != '%') - { - r = m->write_character(m, *format++); - continue; - } - - // case 2: looks like a format specification, but isn't - else if (*format == '%' && format[0] == format[1]) - { - r = m->write_character(m, '%'); - format += 2; - continue; - } - - // case 3: is a format specification. parse it - struct specifier spec = parse_specifier(++format, arguments); - - switch (spec.type) - { - case CHARACTER_PRINT: - r = print_character(m, &spec, arguments); - break; - case STRING_PRINT: - r = print_string(m, &spec, arguments); - break; - case INTEGER_PRINT: - r = print_integer(m, &spec, arguments); - break; - default: - r = m->write_string(m, "(INVALID)"); - return -1; - } - format += spec.length; - } - - return r; -} - -static int kfp_write_character(struct method *m, char c) -{ - kfputc((int)c, (FILE *)m->output); - m->count++; - return 0; -} - -static int kfp_write_wcharacter(struct method *m, wchar_t c) -{ - kfputc((int)c, (FILE *)m->output); - m->count++; - return 0; -} - -static int kfp_write_string(struct method *m, const char *c) -{ - while (*c) - { - m->write_character(m, *c++); - } - return 0; -} - -static int kfp_write_wstring(struct method *m, const wchar_t *s) -{ - while (*s) - { - m->write_wcharacter(m, *s++); - } - return 0; -} - -int kvfprintf(FILE *f, const char *restrict format, va_list arguments) -{ - struct method m = { - kfp_write_character, - kfp_write_wcharacter, - kfp_write_string, - kfp_write_wstring, - (void *)f, - 0}; - va_list acopy; - va_copy(acopy, arguments); - int r = printf_internal(&m, format, &acopy); - va_end(acopy); - - if (!r) - { - return m.count; - } - else - { - return -1; - } -} - -int kfprintf(FILE *f, const char *restrict format, ...) -{ - va_list arguments; - va_start(arguments, format); - - int count = kvfprintf(f, format, arguments); - - va_end(arguments); - - return count; -} - -int kvprintf(const char *restrict format, va_list arguments) -{ - va_list acopy; - va_copy(acopy, arguments); - - int count = kvfprintf(kstdout, format, arguments); - - va_end(acopy); - - return count; -} - -int kprintf(const char *restrict format, ...) -{ - va_list arguments; - va_start(arguments, format); - - int count = kvprintf(format, arguments); - - va_end(arguments); - - return count; -} - diff --git a/lib/libc/memcmp.c b/lib/libc/memcmp.c new file mode 100644 index 0000000..2348afe --- /dev/null +++ b/lib/libc/memcmp.c @@ -0,0 +1,16 @@ +/* Public domain. */ +#include + +int +memcmp (const void *str1, const void *str2, size_t count) +{ + const unsigned char *s1 = str1; + const unsigned char *s2 = str2; + + while (count-- > 0) + { + if (*s1++ != *s2++) + return s1[-1] < s2[-1] ? -1 : 1; + } + return 0; +} diff --git a/lib/libc/memcpy.c b/lib/libc/memcpy.c new file mode 100644 index 0000000..58b1e40 --- /dev/null +++ b/lib/libc/memcpy.c @@ -0,0 +1,12 @@ +/* Public domain. */ +#include + +void * +memcpy (void *dest, const void *src, size_t len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} diff --git a/lib/libc/memmove.c b/lib/libc/memmove.c new file mode 100644 index 0000000..fd06bb6 --- /dev/null +++ b/lib/libc/memmove.c @@ -0,0 +1,20 @@ +/* Public domain. */ +#include + +void * +memmove (void *dest, const void *src, size_t len) +{ + char *d = dest; + const char *s = src; + if (d < s) + while (len--) + *d++ = *s++; + else + { + const char *lasts = s + (len-1); + char *lastd = d + (len-1); + while (len--) + *lastd-- = *lasts--; + } + return dest; +} diff --git a/lib/libc/memset.c b/lib/libc/memset.c new file mode 100644 index 0000000..3e7025e --- /dev/null +++ b/lib/libc/memset.c @@ -0,0 +1,11 @@ +/* Public domain. */ +#include + +void * +memset (void *dest, int val, size_t len) +{ + unsigned char *ptr = dest; + while (len-- > 0) + *ptr++ = val; + return dest; +} diff --git a/lib/libc/printf.c b/lib/libc/printf.c new file mode 100644 index 0000000..ad33cca --- /dev/null +++ b/lib/libc/printf.c @@ -0,0 +1,653 @@ +#include +#include +#include +#include + +enum specifier_type +{ + INVALID_PRINT, + CHARACTER_PRINT, + STRING_PRINT, + INTEGER_PRINT, + COUNT_PRINT +}; + +enum specifier_flags +{ + INVALID_FLAGS, + LEFT_JUSTIFY_FLAG = 0x1, + EXPLICIT_SIGN_FLAG = 0x2, + PAD_SIGN_FLAG = 0x4, + SIGNED_TYPE_FLAG = 0x8, + SIGN_FLAG_MASK = 0x6, + ALTERNATE_FORM_FLAG = 0x10, + ZERO_PAD_FLAG = 0x20, +}; + +enum specifier_integer_base +{ + INVALID_BASE, + BIN_BASE = 2, + OCT_BASE = 8, + DEC_BASE = 10, + HEX_BASE = 16 +}; + +enum specifier_integer_width +{ + INVALID_WIDTH, + BYTE_WIDTH = 8, + SHORT_WIDTH = 16, + INT_WIDTH = 32, + LONG_WIDTH = 64 +}; + +struct method +{ + int (*write_character)(struct method *m, char c); + int (*write_wcharacter)(struct method *m, wchar_t c); + int (*write_string)(struct method *m, const char *s); + int (*write_wstring)(struct method *m, const wchar_t *s); + void *output; + int count; +}; + +struct specifier +{ + enum specifier_type type; + enum specifier_flags flags; + enum specifier_integer_width integer_width; + enum specifier_integer_base integer_base; + int field_width; + int field_precision; + size_t length; +}; + +static struct specifier parse_specifier(const char *format, va_list *arguments) +{ + struct specifier result = + { + INVALID_PRINT, + INVALID_FLAGS, + INVALID_WIDTH, + INVALID_BASE, + 0, + 0, + 0 + }; + + // keep a pointer to the beginning of the specifier + const char *begin = format; + + // step 1: scan for flags + bool flags_parsed = false; + + while (!flags_parsed) + { + switch (*begin) + { + case 0: + result.type = INVALID_PRINT; + return result; + case '-': + result.flags |= LEFT_JUSTIFY_FLAG; + begin++; + break; + case '+': + result.flags |= EXPLICIT_SIGN_FLAG; + begin++; + break; + case ' ': + result.flags |= PAD_SIGN_FLAG; + begin++; + break; + case '#': + result.flags |= ALTERNATE_FORM_FLAG; + begin++; + break; + case '0': + result.flags |= ZERO_PAD_FLAG; + begin++; + break; + default: + flags_parsed = true; + } + } + + // step 2: parse field width and precision + // TODO: parse field width and precision + /* procedure: + * 1. check if next character is * or . + * a. if *, field width is the value pointed to by the next item in + * arguments list + * b. if ., field width will be set to 0, proceed to 3. + * 2. if above check is false, check for numeric character + * a. if is numeric character, parse field width via strtoul, add length + * of numeric string to begin. + * b. if is not a numeric character, skip check for width and precision + * entirely + * 3. check if next character is * or numeric + * a. if *, field precision is the value pointed to by the next item + * in arguments list. + * b. if is numeric character, parse field precision via strtoul, add + * length of numeric string to begin. + */ + bool field_width_parsed = false; + bool field_precision_parsed = false; + + while (!field_width_parsed || !field_precision_parsed) + { + switch (*begin) + { + case '.': + if (!field_width_parsed) + { + result.field_width = 0; + field_width_parsed = true; + begin++; + } + else + { + // the specifier is invalid! + result.type = INVALID_PRINT; + } + break; + case '*': + { + int w = *va_arg(*arguments, int *); + if (!field_width_parsed) + { + result.field_width = w; + field_width_parsed = true; + } + else + { + result.field_precision = w; + field_precision_parsed = true; + } + begin++; + } + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + { + char *next; + unsigned long long w = strtoull(begin, &next, 10); + if (!field_width_parsed) + { + result.field_width = (int)w; + field_width_parsed = true; + } + else if (!field_precision_parsed) + { + result.field_precision = (int)w; + field_precision_parsed = true; + } + if (next > begin) + { + begin = next; + } + } + break; + default: + field_width_parsed = true; + field_precision_parsed = true; + } + } + + // step 3: check for type width arguments + switch (*begin) + { + case 0: // unexpected eos + result.type = INVALID_PRINT; + return result; + case 'h': + { + if (begin[0] == begin[1]) + { + result.integer_width = BYTE_WIDTH; + begin += 2; + } + else + { + result.integer_width = SHORT_WIDTH; + begin++; + } + break; + } + case 'l': + { + // TODO: deal with LLP64? idk. + if (begin[0] == begin[1]) + { + begin += 2; + } + else + { + begin++; + } + result.integer_width = LONG_WIDTH; + break; + } + case 'j': + // TODO: use INTMAX_T_WIDTH + result.integer_width = 64; + begin++; + break; + case 'z': + // TODO: use SIZE_T_WIDTH? + result.integer_width = 64; + begin++; + break; + case 't': + // TODO: use PTRDIFF_T_WIDTH? + result.integer_width = 32; + begin++; + break; + default: + // there is no width argument to be found. + result.integer_width = INT_WIDTH; + break; + } + + // step 4: parse field type + switch (*begin) + { + // unexpected EOS + case 0: + result.type = INVALID_PRINT; + return result; + case 'c': + result.type = CHARACTER_PRINT; + break; + case 's': + result.type = STRING_PRINT; + break; + case 'd': + case 'i': + result.type = INTEGER_PRINT; + result.flags |= SIGNED_TYPE_FLAG; + result.integer_base = DEC_BASE; + break; + case 'u': + result.type = INTEGER_PRINT; + result.integer_base = DEC_BASE; + break; + case 'b': + result.type = INTEGER_PRINT; + result.integer_base = BIN_BASE; + break; + case 'o': + result.type = INTEGER_PRINT; + result.integer_base = OCT_BASE; + break; + case 'x': + result.type = INTEGER_PRINT; + result.integer_base = HEX_BASE; + break; + case 'p': + // TODO: use UINTPTR_T_WIDTH here? + // pointer type overrides all flags + // i can do what i want it says "implementation-defined" in the spec + result.field_precision = 16; + result.type = INTEGER_PRINT; + result.integer_base = HEX_BASE; + result.integer_width = LONG_WIDTH; + result.flags = ALTERNATE_FORM_FLAG|ZERO_PAD_FLAG; + break; + case 'n': + // all flags are invalid/ignored and the current count will be + // stored in the value pointed to by the argument + result.type = COUNT_PRINT; + result.flags = INVALID_FLAGS; + result.integer_width = INVALID_WIDTH; + result.field_width = 0; + result.field_precision = 0; + break; + default: + // this byte of the specifier _must_ be valid. if not, + // the procedure to print should not proceed as it might + // output garbage. + // TODO: specify somehow in the output that the format is bad? + result.type = INVALID_PRINT; + return result; + } + + begin++; + + result.length = begin - format; + return result; +} + +static char *convert_integer( + uint64_t value, + unsigned base, + int zpadding, + char *buffer, + size_t bufsz) +{ + static const char *stringdigits = "0123456789abcdef"; + + // the string will be built from the lower-to-higher value, and the + // result pointer will point to the first character of the string in + // the supplied buffer + + // cannot currently work with a base > 16 + if (base > 16) + { + return NULL; + } + + // make absolutely sure there are no excess bits + + // the string is being built backwards, so the pointer needs to be + // at the last byte of the string + char *result = buffer + bufsz - 1; + + // result >= buffer condition ensures we don't underflow + + do + { + *--result = stringdigits[value % base]; + zpadding--; + value /= base; + } + while (value > 0 && result >= buffer); + + while (zpadding-- > 0 && result >= buffer) + { + *--result = '0'; + } + + return result; +} + +static int print_character( + struct method *m, + struct specifier *spec, + va_list *arguments) +{ + (void)spec; + // all specifier flags and etc. are ignored. + return m->write_character(m, va_arg(*arguments, int)); +} + +static int print_string( + struct method *m, + struct specifier *spec, + va_list *arguments) +{ + // TODO: respect field width + if (spec->integer_width == LONG_WIDTH) + { + return m->write_wstring(m, va_arg(*arguments, const wchar_t *)); + } + return m->write_string(m, va_arg(*arguments, const char *)); +} + +static inline bool is_negative(uint64_t value, unsigned width) +{ + switch (width) + { + case BYTE_WIDTH: + return ((int8_t)value) < 0; + case SHORT_WIDTH: + return ((int16_t)value) < 0; + case INT_WIDTH: + return ((int32_t)value) < 0; + case LONG_WIDTH: + return ((int64_t)value) < 0; + default: + return false; + } +} + +static int print_integer( + struct method *m, + struct specifier *spec, + va_list *arguments) +{ + // 65 bytes is the maximum length that convert_integer will need + // i.e. conversion of uintmax_t to binary plus NUL terminator + // TODO: use UINTMAX_T_WIDTH + 1? + char buffer[65] = {0}; + char *s; + bool negative = false; + uint64_t value = 0; + int r = 0; + unsigned zpad = 0; + + switch (spec->integer_width) + { + case BYTE_WIDTH: + case SHORT_WIDTH: + case INT_WIDTH: + value = va_arg(*arguments, unsigned int); + break; + case LONG_WIDTH: + value = va_arg(*arguments, uint64_t); + break; + default: + return -1; + } + + // check if we need to bother with signs + if (spec->flags & SIGNED_TYPE_FLAG) + { + if ((negative = is_negative(value, spec->integer_width))) + { + value = ~value + 1; + } + + if (negative) + { + r = m->write_character(m, '-'); + } + + else if (!negative && (spec->flags & SIGN_FLAG_MASK)) + { + if (spec->flags & EXPLICIT_SIGN_FLAG) + { + r = m->write_character(m, '+'); + } + else + { + r = m->write_character(m, ' '); + } + } + } + + // zero all the unnecessary bits + value &= (2ULL << (spec->integer_width - 1)) - 1; + + switch (spec->integer_base) + { + case BIN_BASE: + if (spec->flags & ALTERNATE_FORM_FLAG) + { + r = m->write_string(m, "0b"); + } + break; + case OCT_BASE: + if (spec->flags & ALTERNATE_FORM_FLAG) + { + r = m->write_character(m, '0'); + } + break; + case HEX_BASE: + if (spec->flags & ALTERNATE_FORM_FLAG) + { + r = m->write_string(m, "0x"); + } + break; + default: + break; + } + + if (spec->flags & ZERO_PAD_FLAG) + { + zpad = spec->field_precision; + } + s = convert_integer(value, spec->integer_base, zpad, buffer, sizeof(buffer)); + + if (s) + { + m->write_string(m, s); + } + else + { + m->write_string(m, "(INVALID)"); + r = -1; + } + + return r; +} + +static int printf_internal( + struct method *m, + const char *restrict format, + va_list *arguments) +{ + int r = 0; + + while (*format && !r) + { + // case 1: not a format specification + if (*format != '%') + { + r = m->write_character(m, *format++); + continue; + } + + // case 2: looks like a format specification, but isn't + else if (*format == '%' && format[0] == format[1]) + { + r = m->write_character(m, '%'); + format += 2; + continue; + } + + // case 3: is a format specification. parse it + struct specifier spec = parse_specifier(++format, arguments); + + switch (spec.type) + { + case CHARACTER_PRINT: + r = print_character(m, &spec, arguments); + break; + case STRING_PRINT: + r = print_string(m, &spec, arguments); + break; + case INTEGER_PRINT: + r = print_integer(m, &spec, arguments); + break; + default: + r = m->write_string(m, "(INVALID)"); + return -1; + } + format += spec.length; + } + + return r; +} + +static int kfp_write_character(struct method *m, char c) +{ + fputc((int)c, (FILE *)m->output); + m->count++; + return 0; +} + +static int kfp_write_wcharacter(struct method *m, wchar_t c) +{ + fputc((int)c, (FILE *)m->output); + m->count++; + return 0; +} + +static int kfp_write_string(struct method *m, const char *c) +{ + while (*c) + { + m->write_character(m, *c++); + } + return 0; +} + +static int kfp_write_wstring(struct method *m, const wchar_t *s) +{ + while (*s) + { + m->write_wcharacter(m, *s++); + } + return 0; +} + +int vfprintf(FILE *f, const char *restrict format, va_list arguments) +{ + struct method m = { + kfp_write_character, + kfp_write_wcharacter, + kfp_write_string, + kfp_write_wstring, + (void *)f, + 0}; + va_list acopy; + va_copy(acopy, arguments); + int r = printf_internal(&m, format, &acopy); + va_end(acopy); + + if (!r) + { + return m.count; + } + else + { + return -1; + } +} + +int fprintf(FILE *f, const char *restrict format, ...) +{ + va_list arguments; + va_start(arguments, format); + + int count = vfprintf(f, format, arguments); + + va_end(arguments); + + return count; +} + +int vprintf(const char *restrict format, va_list arguments) +{ + va_list acopy; + va_copy(acopy, arguments); + + int count = vfprintf(stdout, format, arguments); + + va_end(acopy); + + return count; +} + +int printf(const char *restrict format, ...) +{ + va_list arguments; + va_start(arguments, format); + + int count = vprintf(format, arguments); + + va_end(arguments); + + return count; +} + diff --git a/lib/libc/string.c b/lib/libc/string.c new file mode 100644 index 0000000..9316d98 --- /dev/null +++ b/lib/libc/string.c @@ -0,0 +1,158 @@ +#include +#include + +size_t strlen(const char *s) +{ + size_t l = 0; + + while (*s++) l++; + + return l; +} + +static long long valueof(int c, int base) +{ + long long result = 0; + + if (base < 2 || base > 36) + { + // bases less than 2 or greater than 36 are invalid. + return -1; + } + + // check if value is an ascii numeric character + if (c >= '0' && c <= '9') + { + // simple as + result = (long long)(c ^ 0x30); + } + + // check if value is an uppercase ASCII alphabetical character + else if ( + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z')) + { + // mask in uppercase bit + c |= 0x20; + // value is 10 plus the alphabetical order of the character + result = (long long)(10 + c - 'a'); + } + else + { + // character has no valid interpretation under base 36 + return -1LL; + } + + if (result > (base - 1)) + { + // character is not valid under given base + return -1LL; + } + + return result; +} + +unsigned long long strtoull( + const char *restrict begin, + char **restrict end, + int base) +{ + long result = 0; + const char *current = begin; + + // check for empty string + if (*current == 0) + { + if (end) + { + *end = (char *)begin; + return result; + } + } + + // skip initial whitespace + bool whitespace = true; + while (whitespace) + { + switch (*current) + { + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x20: + current++; + break; + default: + whitespace = false; + } + } + + bool negative = false; + // detect if negative sign is used + if (*current == '-') + { + negative = true; + current++; + } + + // detect base from input + if (base == 0) + { + // base is non-decimal + if (current[0] == 0) + { + if (current[1] == 'b') + { + base = 2; + current += 2; + } + else if (current[1] == 'x') + { + base = 16; + current += 2; + } + else + { + base = 8; + current++; + } + } + // base is decimal otherwise + else + { + base = 10; + } + } + // do the actual conversion now + while (*current) + { + long long value = valueof(*current, base); + + // we've reached the end of the conversion + if (value == -1) + { + break; + } + + result *= base; + result += value; + current++; + } + + // store the end pointer if needed + if (end) + { + *end = (char *)current; + } + + // flip the result if we're meant to + if (negative) + { + result = -result; + } + + return result; +} + diff --git a/lib/memcmp.c b/lib/memcmp.c deleted file mode 100644 index 2348afe..0000000 --- a/lib/memcmp.c +++ /dev/null @@ -1,16 +0,0 @@ -/* Public domain. */ -#include - -int -memcmp (const void *str1, const void *str2, size_t count) -{ - const unsigned char *s1 = str1; - const unsigned char *s2 = str2; - - while (count-- > 0) - { - if (*s1++ != *s2++) - return s1[-1] < s2[-1] ? -1 : 1; - } - return 0; -} diff --git a/lib/memcpy.c b/lib/memcpy.c deleted file mode 100644 index 58b1e40..0000000 --- a/lib/memcpy.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Public domain. */ -#include - -void * -memcpy (void *dest, const void *src, size_t len) -{ - char *d = dest; - const char *s = src; - while (len--) - *d++ = *s++; - return dest; -} diff --git a/lib/memmove.c b/lib/memmove.c deleted file mode 100644 index fd06bb6..0000000 --- a/lib/memmove.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Public domain. */ -#include - -void * -memmove (void *dest, const void *src, size_t len) -{ - char *d = dest; - const char *s = src; - if (d < s) - while (len--) - *d++ = *s++; - else - { - const char *lasts = s + (len-1); - char *lastd = d + (len-1); - while (len--) - *lastd-- = *lasts--; - } - return dest; -} diff --git a/lib/memset.c b/lib/memset.c deleted file mode 100644 index 3e7025e..0000000 --- a/lib/memset.c +++ /dev/null @@ -1,11 +0,0 @@ -/* Public domain. */ -#include - -void * -memset (void *dest, int val, size_t len) -{ - unsigned char *ptr = dest; - while (len-- > 0) - *ptr++ = val; - return dest; -} diff --git a/lib/string.c b/lib/string.c deleted file mode 100644 index f6bc682..0000000 --- a/lib/string.c +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include - -size_t strlen(const char *s) -{ - size_t l = 0; - - while (*s++) l++; - - return l; -} - -static long long valueof(int c, int base) -{ - long long result = 0; - - if (base < 2 || base > 36) - { - // bases less than 2 or greater than 36 are invalid. - return -1; - } - - // check if value is an ascii numeric character - if (c >= '0' && c <= '9') - { - // simple as - result = (long long)(c ^ 0x30); - } - - // check if value is an uppercase ASCII alphabetical character - else if ( - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z')) - { - // mask in uppercase bit - c |= 0x20; - // value is 10 plus the alphabetical order of the character - result = (long long)(10 + c - 'a'); - } - else - { - // character has no valid interpretation under base 36 - return -1LL; - } - - if (result > (base - 1)) - { - // character is not valid under given base - return -1LL; - } - - return result; -} - -unsigned long long strtoull( - const char *restrict begin, - char **restrict end, - int base) -{ - long result = 0; - const char *current = begin; - - // check for empty string - if (*current == 0) - { - if (end) - { - *end = (char *)begin; - return result; - } - } - - // skip initial whitespace - bool whitespace = true; - while (whitespace) - { - switch (*current) - { - case 0x9: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0x20: - current++; - break; - default: - whitespace = false; - } - } - - bool negative = false; - // detect if negative sign is used - if (*current == '-') - { - negative = true; - current++; - } - - // detect base from input - if (base == 0) - { - // base is non-decimal - if (current[0] == 0) - { - if (current[1] == 'b') - { - base = 2; - current += 2; - } - else if (current[1] == 'x') - { - base = 16; - current += 2; - } - else - { - base = 8; - current++; - } - } - // base is decimal otherwise - else - { - base = 10; - } - } - // do the actual conversion now - while (*current) - { - long long value = valueof(*current, base); - - // we've reached the end of the conversion - if (value == -1) - { - break; - } - - result *= base; - result += value; - current++; - } - - // store the end pointer if needed - if (end) - { - *end = (char *)current; - } - - // flip the result if we're meant to - if (negative) - { - result = -result; - } - - return result; -} - diff --git a/loader/main_efi.c b/loader/main_efi.c index df156e3..b3df593 100644 --- a/loader/main_efi.c +++ b/loader/main_efi.c @@ -6,8 +6,8 @@ #include #include -#include -#include +#include +#include FILE *kstdout; FILE *kstderr; @@ -121,7 +121,7 @@ static const CHAR16 *efi_warning_strings[] = }; **/ -int kfputc(int c, FILE *f) +int fputc(int c, FILE *f) { (void)f; EFI_STATUS status = EFI_SUCCESS; @@ -184,7 +184,7 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) linebuf_ptr = linebuf; } - kprintf("loader interface %p\r\n" + printf("loader interface %p\r\n" "image_handle %p\r\n" "system_table %p\r\n" "page_alloc %p\r\n" @@ -203,25 +203,25 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table) if (EFI_ERROR((status = open_image(&shim_image)))) { - kprintf("error opening shim image: %ls\r\n", + printf("error opening shim image: %ls\r\n", efi_strerror(status)); } if (EFI_ERROR((status = allocate_image(&shim_image)))) { - kprintf("error allocating shim image: %ls\r\n", + printf("error allocating shim image: %ls\r\n", efi_strerror(status)); } if (EFI_ERROR((status = load_image(&shim_image)))) { - kprintf("error loading shim image: %ls\r\n", + printf("error loading shim image: %ls\r\n", efi_strerror(status)); } if (EFI_ERROR((status = enter_shim()))) { - kprintf("error running shim image: %ls\r\n", + printf("error running shim image: %ls\r\n", efi_strerror(status)); } @@ -280,7 +280,7 @@ EFI_STATUS open_image(struct efi_loader_image *image) if (EFI_ERROR(status)) { - kprintf( + printf( "failed locating image protocol: %ls\r\n", efi_strerror(status)); return status; @@ -296,7 +296,7 @@ EFI_STATUS open_image(struct efi_loader_image *image) if (EFI_ERROR(status)) { - kprintf( + printf( "failed locating ESP file system: %ls\r\n", efi_strerror(status)); return status; @@ -306,13 +306,13 @@ EFI_STATUS open_image(struct efi_loader_image *image) if (EFI_ERROR(status)) { - kprintf( + printf( "failed opening root device: %ls\r\n", efi_strerror(status)); return status; } - kprintf("opening image %ls\r\n", image->path); + printf("opening image %ls\r\n", image->path); status = root->Open(root, &image->file, @@ -326,7 +326,7 @@ EFI_STATUS open_image(struct efi_loader_image *image) } else { - kprintf("failed opening image %ls: %r\r\n", image->path, status); + printf("failed opening image %ls: %r\r\n", image->path, status); return status; } @@ -349,13 +349,13 @@ EFI_STATUS open_image(struct efi_loader_image *image) else { FreePool(phdrs); - kprintf("invalid image format detected\r\n"); + printf("invalid image format detected\r\n"); return EFI_INVALID_PARAMETER; } } else { - kprintf("failed reading shim image headers\r\n"); + printf("failed reading shim image headers\r\n"); return status; } @@ -365,11 +365,11 @@ EFI_STATUS open_image(struct efi_loader_image *image) { image->buffer_size = elf_size(&ehdr, phdrs); image->system_table = gST; - kprintf("elf image %d bytes\r\n", image->buffer_size); + printf("elf image %d bytes\r\n", image->buffer_size); } else { - kprintf("failed reading shim image segments\r\n"); + printf("failed reading shim image segments\r\n"); } FreePool(phdrs); @@ -379,7 +379,7 @@ EFI_STATUS open_image(struct efi_loader_image *image) EFI_STATUS allocate_image(struct efi_loader_image *image) { - kprintf("allocating image %ls\r\n", image->path); + printf("allocating image %ls\r\n", image->path); EFI_STATUS status; status = alloc_page(SystemMemoryType, @@ -399,7 +399,7 @@ static EFI_STATUS read_image(struct efi_loader_image *image, UINTN offset, UINTN length) { - kprintf("reading %d bytes from image at %p %ls\r\n", + printf("reading %d bytes from image at %p %ls\r\n", length, offset, image->path); @@ -413,7 +413,7 @@ static EFI_STATUS read_image(struct efi_loader_image *image, } else { - kprintf("failed seeking shim image: %ls\r\n", efi_strerror(status)); + printf("failed seeking shim image: %ls\r\n", efi_strerror(status)); } return status; @@ -449,7 +449,7 @@ EFI_STATUS load_image(struct efi_loader_image *image) if (!EFI_ERROR(status)) { - kprintf("loaded segment %p of %d bytes " + printf("loaded segment %p of %d bytes " "(file size %d bytes)\r\n", placement, phdrs[i].p_memsz, @@ -468,7 +468,7 @@ static EFI_STATUS enter_shim(void) efi_shim_entry_func *entry; entry = (efi_shim_entry_func *)(shim_image.buffer_base + ehdr->e_entry); - kprintf("entering shim @%p\r\n", entry); + printf("entering shim @%p\r\n", entry); status = entry(&loader_interface); -- cgit v1.3.1-1-g115d