diff --git a/build.cmd b/build.cmd index d3ac370..a9ce1f0 100644 --- a/build.cmd +++ b/build.cmd @@ -1,9 +1,15 @@ @echo off setlocal enabledelayedexpansion +set PLATFORM=win32 set CIABATTA_OPTIONS=-Iinc -g -gcodeview -nodefaultlibs -D_CRT_SECURE_NO_WARNINGS -for /R %%F in (*.c) do ( +for /R code %%F in (*.c) do ( + echo %%F + clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS% +) +for /R platform\%PLATFORM% %%F in (*.c) do ( + echo %%F clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS% ) llvm-ar rc ciabatta.lib build\*.obj diff --git a/code/stdlib/conv.c b/code/stdlib/conv.c new file mode 100644 index 0000000..f40392d --- /dev/null +++ b/code/stdlib/conv.c @@ -0,0 +1,160 @@ + +#include +#include +#include +#include +#include + +// TODO: strto*: locale-based parsing for integers +// TODO: i made a function that parses longs and i'm fucken +// tired. someone make float parsing :kekw: + +#define inrange(start, c, end) ((start) <= (c) && (c) <= (end)) + +static bool isbase(int c, int base) { + int val; + if(isdigit(c)) { + val = c-'0'; + } + else if(islower(c)) { + val = c-'a'+10; + } + else if(isupper(c)) { + val = c-'A'+10; + } + else { + return false; + } + return val < base; +} + +// Called only when isbase(c, base) for some base in range +static long todigitl(int c) { + int val; + if(isdigit(c)) { + val = c-'0'; + } + else if(islower(c)) { + val = c-'a'+10; + } + else if(isupper(c)) { + val = c-'A'+10; + } + return val; +} + +long +strtol(const char *restrict nptr, char **restrict endptr, int inbase) { + if(!inrange(0, inbase, 36)) { + *endptr = NULL; + return 0; + } + // Skip space on the beginning + while(isspace(*nptr)) { + ++nptr; + } + // Parse sign + long coef = 1; + if(*nptr == '-') { + coef = -1; + ++nptr; + } + if(*nptr == '+') { + ++nptr; + } + unsigned long base = (unsigned long)inbase; + unsigned long value = 0; + // See if we need to parse base in C-like format + if(*nptr == '0' && *(nptr+1) == 'x') { + ++nptr; + if(base == 16 || base == 0) { + ++nptr; + base = 16; + } + else { + value = 0; + goto end; + } + } + else if(*nptr == '0') { + ++nptr; + if(base == 8 || base == 0) { + base = 8; + } + } + while(isbase(*nptr, (int)base)) { + unsigned long digit = (unsigned long)todigitl(*nptr); + if(value > (ULONG_MAX - digit)/base) { + errno = ERANGE; + value = 0; + goto end; + } + value = base*value + digit; + ++nptr; + } + unsigned long max_modulo = (unsigned long)LONG_MAX+1; + if(value > max_modulo) { + errno = ERANGE; + value = 0; + goto end; + } + if(value == max_modulo) { + if(coef == 1) { + errno = ERANGE; + value = 0; + goto end; + } + else { + value = LONG_MIN; + coef = 1; + } + } +end: + if(endptr != NULL) { + *endptr = (char *)nptr; + } + return coef*(long)value; +} + +long long +strtoll(const char *restrict nptr, char **restrict endptr, int base) { + return 0; +} + +unsigned long +strtoul(const char *restrict nptr, char **restrict endptr, int base) { + return 0; +} + +unsigned long long +strtoull(const char *restrict nptr, char **restrict endptr, int base) { + return 0; +} + +double atof(const char *nptr) { + return strtod(nptr, (char **)NULL); +} + +int atoi(const char *nptr) { + return (int)strtol(nptr, (char **)NULL, 10); +} + +long int atol(const char *nptr) { + return strtol(nptr, (char **)NULL, 10); +} + +long long int atoll(const char *nptr) { + return strtoll(nptr, (char **)NULL, 10); +} + +double strtod(const char *restrict nptr, char **restrict endptr) { + return 0; +} + +float strtof(const char *restrict nptr, char **restrict endptr) { + return 0; +} + +long double strtold(const char *restrict nptr, char **restrict endptr) { + return 0; +} diff --git a/code/stdlib/rand.c b/code/stdlib/rand.c new file mode 100644 index 0000000..f9305a2 --- /dev/null +++ b/code/stdlib/rand.c @@ -0,0 +1,18 @@ + +#include +#include + +// TODO: the code for rand/srand was shamelessly copied +// from C11 standard's example and is a simple LCG. +// gotta implement a better random function, or no idc + +static int last_random_number; + +int rand(void) { + last_random_number = last_random_number * 1103515245 + 12345; + return (unsigned int)(last_random_number/65536) % RAND_MAX; +} + +void srand(unsigned int seed) { + last_random_number = seed; +} diff --git a/inc/_platform.h b/inc/_platform.h index ad2ab2a..a0742a0 100644 --- a/inc/_platform.h +++ b/inc/_platform.h @@ -51,3 +51,4 @@ typedef int errno_t; typedef size_t rsize_t; #endif + diff --git a/inc/errno.h b/inc/errno.h index a294129..a1783de 100644 --- a/inc/errno.h +++ b/inc/errno.h @@ -4,5 +4,5 @@ #define EILSEQ 2 #define ERANGE 3 -// TODO: -//_Thread_local int errno; +// TODO: make it thread-local +int errno; diff --git a/inc/stdlib.h b/inc/stdlib.h index 9f4bb3b..97d960d 100644 --- a/inc/stdlib.h +++ b/inc/stdlib.h @@ -1,4 +1,9 @@ -#include "_platform.h" + +#pragma once + +#if !defined(NULL) +#define NULL ((void *)0) +#endif // typedef struct div_t { // int quot; @@ -18,27 +23,31 @@ // #define EXIT_FAILURE 1 // #define EXIT_SUCCESS 0 -// #define RAND_MAX 65536 +#define RAND_MAX 65536 // #define MB_CUR_MAX 5 - -// double atof(const char *nptr); -// int atoi(const char *nptr); -// long int atol(const char *nptr); -// long long int atoll(const char *nptr); -// double strtod(const char * restrict nptr, char ** restrict endptr); -// float strtof(const char * restrict nptr, char ** restrict endptr); -// long double strtold(const char * restrict nptr, char ** restrict endptr); -// long int strtol(const char * restrict nptr, char ** restrict endptr, int base); -// long long int strtoll(const char * restrict nptr, char ** restrict endptr, int base); -// unsigned long int strtoul(const char * restrict nptr, char ** restrict endptr, int base); -// unsigned long long int strtoull(const char * restrict nptr, char ** restrict endptr, int base); -// int rand(void); -// void srand(unsigned int seed); -// void *aligned_alloc(size_t alignment, size_t size); -// void *calloc(size_t nmemb, size_t size); -// void free(void *ptr); -// void *malloc(size_t size); -// void *realloc(void *ptr, size_t size); + +double atof(const char *nptr); +int atoi(const char *nptr); +long int atol(const char *nptr); +long long int atoll(const char *nptr); +double strtod(const char * restrict nptr, char ** restrict endptr); +float strtof(const char * restrict nptr, char ** restrict endptr); +long double strtold(const char * restrict nptr, char ** restrict endptr); +long int strtol(const char *restrict nptr, char **restrict endptr, int base); +long long int strtoll(const char *restrict nptr, char **restrict endptr, int base); +unsigned long int strtoul(const char *restrict nptr, char **restrict endptr, int base); +unsigned long long int strtoull(const char *restrict nptr, char **restrict endptr, int base); +int rand(void); +void srand(unsigned int seed); + +typedef struct _os_heap _os_heap; +void _heap_setup(_os_heap *heap); +void *aligned_alloc(size_t alignment, size_t size); +void *calloc(size_t nmemb, size_t size); +void free(void *ptr); +void *malloc(size_t size); +void *realloc(void *ptr, size_t size); + // _Noreturn void abort(void); // int atexit(void (*func)(void)); // int at_quick_exit(void (*func)(void)); diff --git a/code/entry_windows.c b/platform/win32/entry.c similarity index 85% rename from code/entry_windows.c rename to platform/win32/entry.c index a4ae96e..447cb88 100644 --- a/code/entry_windows.c +++ b/platform/win32/entry.c @@ -1,9 +1,9 @@ -#include <_platform.h> + #include #include +#include -#define WIN32_LEAN_AND_MEAN -#include +#include "win32.h" extern int main(int argc, char** argv); @@ -58,8 +58,18 @@ void mainCRTStartup() { convert_wide_chars_to_ansi(args[i], args_wide[i], wide_len); } + _os_heap heap_data = { + .handle = heap, + }; + _heap_setup(&heap_data); + + srand(0); setlocale(LC_ALL, "C"); int exit_code = main(arg_count, args); ExitProcess(exit_code); } + +// This symbol is required to be present if we're using floating-point +// numbers +int _fltused=0; diff --git a/platform/win32/memory.c b/platform/win32/memory.c new file mode 100644 index 0000000..746c706 --- /dev/null +++ b/platform/win32/memory.c @@ -0,0 +1,74 @@ + +#include +#include +#include + +#include "win32.h" + +// TODO: lock the heap before allocation (?) + +HANDLE _heap; + +static bool is_power_of_two(size_t s) { + return (s & (s-1)) == 0; +} + +static intptr_t align_forward(intptr_t p, size_t a) { + return (p+a-1)&~(a-1); +} + +void _heap_setup(_os_heap *heap) { + _heap = heap->handle; +} + +void *aligned_alloc(size_t alignment, size_t size) { + if(size == 0) { + return NULL; + } + if(alignment == 0) { + alignment = 8; + } + if(!is_power_of_two(alignment)) { + return NULL; + } + // HeapAlloc is guaranteed to return 8-byte aligned pointer, + // so if our alignment is 8 or less we don't have to overallocate. + // otherwise we'll reserve extra `alignment` bytes to later adjust our + // memory buffer according to required alignment. + size_t min_req_size = size; + if(alignment > 8) { + min_req_size += alignment; + } + void *block_start = HeapAlloc(_heap, HEAP_ZERO_MEMORY, size+alignment); + intptr_t block_start_i = (intptr_t)block_start; + intptr_t aligned_block_start_i = align_forward(block_start_i, alignment); + void *aligned_block_start = (void *)aligned_block_start_i; + return aligned_block_start; +} + +void *calloc(size_t nmemb, size_t size) { + if(nmemb == 0 || size == 0) { + return NULL; + } + if(nmemb > SIZE_MAX/size) { + return NULL; + } + void *block_start = HeapAlloc(_heap, HEAP_ZERO_MEMORY, size*nmemb); + return block_start; +} + +void free(void *ptr) { + if(ptr == NULL) { + return; + } + HeapFree(_heap, 0, ptr); +} + +void *malloc(size_t size) { + return aligned_alloc(8, size); +} + +void *realloc(void *ptr, size_t size) { + void *buffer = HeapReAlloc(_heap, 0, ptr, size); + return buffer; +} diff --git a/platform/win32/win32.h b/platform/win32/win32.h new file mode 100644 index 0000000..1cebe50 --- /dev/null +++ b/platform/win32/win32.h @@ -0,0 +1,9 @@ + +#pragma once + +#define WIN32_LEAN_AND_MEAN +#include + +struct _os_heap { + HANDLE handle; +};