From bca2c685101c18aa766cf90969c407a73f07be48 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Wed, 21 Feb 2024 22:57:06 +0100 Subject: [PATCH 1/7] Add some libc support, create short examples and use it in snake game (fenv.h, math.h, stdlib.h, string.h, time.h, stdio.h(parts)) --- examples/libc/exit.c | 65 ++ examples/libc/file.c | 84 ++ examples/libc/malloc.c | 79 ++ examples/libc/math.c | 69 ++ examples/tsoding_snake/tsoding_snake.c | 545 ++++++------ include/math.h | 17 - index.html | 7 + libc/include/assert.h | 32 + libc/include/errno.h | 98 +++ libc/include/fenv.h | 140 +++ libc/include/math.h | 239 ++++++ .../include}/stb_sprintf.h | 801 +++++++++++------- libc/include/stdio.h | 742 ++++++++++++++++ libc/include/stdlib.h | 485 +++++++++++ libc/include/string.h | 549 ++++++++++++ libc/include/time.h | 437 ++++++++++ libc/js/fenv.js | 38 + libc/js/math.js | 450 ++++++++++ libc/js/stdio.js | 81 ++ libc/js/stdlib.js | 497 +++++++++++ libc/js/time.js | 104 +++ libc/libc.h | 30 + nob.c | 26 + raylib.js | 44 +- wasm/file_example.wasm | Bin 0 -> 60090 bytes wasm/libc_exit.wasm | Bin 0 -> 56611 bytes wasm/libc_file.wasm | Bin 0 -> 61073 bytes wasm/libc_malloc.wasm | Bin 0 -> 60154 bytes wasm/libc_math.wasm | Bin 0 -> 57128 bytes wasm/tsoding_snake.wasm | Bin 80423 -> 86662 bytes 30 files changed, 5087 insertions(+), 572 deletions(-) create mode 100644 examples/libc/exit.c create mode 100644 examples/libc/file.c create mode 100644 examples/libc/malloc.c create mode 100644 examples/libc/math.c delete mode 100644 include/math.h create mode 100644 libc/include/assert.h create mode 100644 libc/include/errno.h create mode 100644 libc/include/fenv.h create mode 100644 libc/include/math.h rename {examples/tsoding_snake => libc/include}/stb_sprintf.h (78%) create mode 100644 libc/include/stdio.h create mode 100644 libc/include/stdlib.h create mode 100644 libc/include/string.h create mode 100644 libc/include/time.h create mode 100644 libc/js/fenv.js create mode 100644 libc/js/math.js create mode 100644 libc/js/stdio.js create mode 100644 libc/js/stdlib.js create mode 100644 libc/js/time.js create mode 100644 libc/libc.h create mode 100644 wasm/file_example.wasm create mode 100644 wasm/libc_exit.wasm create mode 100644 wasm/libc_file.wasm create mode 100644 wasm/libc_malloc.wasm create mode 100644 wasm/libc_math.wasm diff --git a/examples/libc/exit.c b/examples/libc/exit.c new file mode 100644 index 0000000..b3d47b7 --- /dev/null +++ b/examples/libc/exit.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +void raylib_js_set_entry(void (*entry)(void)); + +const double time_per_calc = 1; // in s +double time_since_last_calc = 0; +char buf[BUFSIZ]; +int counter = 3; + +void GameFrame() +{ + BeginDrawing(); + + ClearBackground((Color){20, 20, 20, 255}); + + if (counter <= 0) + { + exit(0); + } + + const size_t w = GetScreenWidth(); + const size_t h = GetScreenHeight(); + const size_t font_size = 72; + + const int ch = h / 2 - (font_size / 2); + + sprintf(buf, "%d%c", counter, '\0'); + size_t text_size = MeasureText(buf, font_size); + int cw = w / 2 - (text_size / 2); + DrawText(buf, cw, ch, font_size, RED); + + if (time_since_last_calc >= time_per_calc) + { + counter--; + time_since_last_calc = 0; + } + else + { + time_since_last_calc += GetFrameTime(); + } + + EndDrawing(); +} + +int main() +{ + InitWindow(800, 600, "Hello, with math.h"); + SetTargetFPS(60); + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + while (!WindowShouldClose()) + { + GameFrame(); + } + CloseWindow(); +#endif + return 0; +} diff --git a/examples/libc/file.c b/examples/libc/file.c new file mode 100644 index 0000000..74d3c18 --- /dev/null +++ b/examples/libc/file.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +void raylib_js_set_entry(void (*entry)(void)); + +bool once = true; +FILE *read_me = NULL; + +char buf[BUFSIZ]; +const double time_per_calc = 2; // in s +double time_since_last_calc = 0; + +void GameFrame() +{ + BeginDrawing(); + + ClearBackground((Color){20, 20, 20, 255}); + + const size_t w = GetScreenWidth(); + const size_t h = GetScreenHeight(); + const size_t font_size = 48; + + if (time_since_last_calc >= time_per_calc) + { + // Get new line + if (is_file_ready(read_me)) + { + if (feof(read_me)) + { + rewind(read_me); + } + + fgets(buf, BUFSIZ, read_me); + } + + time_since_last_calc = 0; + } + else + { + time_since_last_calc += GetFrameTime(); + } + + // display text somewhat sensibly + size_t current_font_size = font_size; + size_t text_size = MeasureText(buf, font_size); + while (text_size > w && current_font_size > font_size / 2) + { + text_size = MeasureText(buf, --current_font_size); + } + if (text_size <= w) + { + DrawText(buf, w / 2 - (text_size / 2), h / 2 - (current_font_size / 2), current_font_size, RED); + } + else + { + DrawText(buf, 10, h / 2 - (current_font_size / 2), current_font_size, RED); + } + + EndDrawing(); +} + +int main() +{ + InitWindow(800, 600, "Hello, with loaded README.md"); + SetTargetFPS(60); + + read_me = fopen("README.md", "rb"); + + int w = GetScreenWidth(); + int h = GetScreenHeight(); + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + while (!WindowShouldClose()) + { + GameFrame(); + } + CloseWindow(); +#endif + return 0; +} diff --git a/examples/libc/malloc.c b/examples/libc/malloc.c new file mode 100644 index 0000000..786fac1 --- /dev/null +++ b/examples/libc/malloc.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include + +void raylib_js_set_entry(void (*entry)(void)); + +const double time_per_calc = 1; // in s +double time_since_last_calc = 0; + +char buf[128]; + +char *buf_dym = NULL; +int counter = 1; + +void GameFrame() +{ + BeginDrawing(); + + ClearBackground((Color){20, 20, 20, 255}); + + const size_t w = GetScreenWidth(); + const size_t h = GetScreenHeight(); + const size_t font_size = 72; + + const int ch = h / 2 - (font_size / 2); + + buf_dym = realloc(buf_dym, counter + 1); + + memset(buf_dym, 'a', counter); + buf_dym[counter] = '\0'; + size_t text_size = MeasureText(buf_dym, font_size); + int cw = w / 2 - (text_size / 2); + DrawText(buf_dym, cw, ch - font_size, font_size, RED); + + sprintf(buf, "malloc size: %d%c", counter + 1, '\0'); + size_t m_text_size = MeasureText(buf, font_size); + cw = w / 2 - (m_text_size / 2); + DrawText(buf, cw, ch + font_size, font_size, RED); + + if (text_size > w) + { + counter = 1; + free(buf_dym); + buf_dym = NULL; + } + + if (time_since_last_calc >= time_per_calc) + { + counter++; + time_since_last_calc = 0; + } + else + { + time_since_last_calc += GetFrameTime(); + } + + EndDrawing(); +} + +int main() +{ + InitWindow(800, 600, "Hello, with malloc"); + SetTargetFPS(60); + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + while (!WindowShouldClose()) + { + GameFrame(); + } + CloseWindow(); +#endif + return 0; +} diff --git a/examples/libc/math.c b/examples/libc/math.c new file mode 100644 index 0000000..be69906 --- /dev/null +++ b/examples/libc/math.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +void raylib_js_set_entry(void (*entry)(void)); + +const double time_per_calc = 2; // in s +double time_since_last_calc = 0; +char buf[BUFSIZ]; +double random = 0; +void GameFrame() +{ + BeginDrawing(); + + ClearBackground((Color){20, 20, 20, 255}); + + const size_t w = GetScreenWidth(); + const size_t h = GetScreenHeight(); + const size_t font_size = 48; + + const int ch = h / 2 - (font_size / 2); + + sprintf(buf, "cos(%.2g) = %.2g%c", random, cos(random), '\0'); + size_t text_size = MeasureText(buf, font_size); + int cw = w / 2 - (text_size / 2); + DrawText(buf, cw, ch - font_size, font_size, RED); + + sprintf(buf, "sin(%.2g) = %.2g%c", random, sin(random), '\0'); + text_size = MeasureText(buf, font_size); + cw = w / 2 - (text_size / 2); + DrawText(buf, cw, ch + font_size, font_size, RED); + + if (time_since_last_calc >= time_per_calc) + { + const int random_int = rand(); + random = ((random_int / (double)RAND_MAX) - 0.5) * 2 * 4; + + time_since_last_calc = 0; + } + else + { + time_since_last_calc += GetFrameTime(); + } + + EndDrawing(); +} + +int main() +{ + InitWindow(800, 600, "Hello, with math.h"); + SetTargetFPS(60); + + int w = GetScreenWidth(); + int h = GetScreenHeight(); + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + while (!WindowShouldClose()) + { + GameFrame(); + } + CloseWindow(); +#endif + return 0; +} diff --git a/examples/tsoding_snake/tsoding_snake.c b/examples/tsoding_snake/tsoding_snake.c index 32cbdf5..ca307c1 100644 --- a/examples/tsoding_snake/tsoding_snake.c +++ b/examples/tsoding_snake/tsoding_snake.c @@ -1,25 +1,27 @@ #include "./tsoding_snake.h" #include +#include +#include +#include // #define FEATURE_DYNAMIC_CAMERA // #define FEATURE_DEV -#define STB_SPRINTF_IMPLEMENTATION -#include "stb_sprintf.h" - #define TRUE 1 #define FALSE 0 static char logf_buf[4096] = {0}; -#define LOGF(...) \ - do { \ - stbsp_snprintf(logf_buf, sizeof(logf_buf), __VA_ARGS__); \ - platform_log(logf_buf); \ - } while(0) +#define LOGF(...) \ + do \ + { \ + snprintf(logf_buf, sizeof(logf_buf), __VA_ARGS__); \ + platform_log(logf_buf); \ + } while (0) static void platform_assert(const char *file, i32 line, b32 cond, const char *message) { - if (!cond) { + if (!cond) + { TraceLog(LOG_FATAL, "%s:%d: GAME ASSERTION FAILED: %s\n", file, line, message); } } @@ -48,7 +50,8 @@ static void platform_assert(const char *file, i32 line, b32 cond, const char *me #define RAND_A 6364136223846793005ULL #define RAND_C 1442695040888963407ULL -typedef enum { +typedef enum +{ ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, @@ -57,10 +60,16 @@ typedef enum { static void fill_text_aligned(i32 x, i32 y, const char *text, u32 size, u32 color, Align align) { u32 width = platform_text_width(text, size); - switch (align) { - case ALIGN_LEFT: break; - case ALIGN_CENTER: x -= width/2; break; - case ALIGN_RIGHT: x -= width; break; + switch (align) + { + case ALIGN_LEFT: + break; + case ALIGN_CENTER: + x -= width / 2; + break; + case ALIGN_RIGHT: + x -= width; + break; } platform_fill_text(x, y, text, size, color); } @@ -68,19 +77,12 @@ static void fill_text_aligned(i32 x, i32 y, const char *text, u32 size, u32 colo static u32 my_rand(void) { static u64 rand_state = 0; - rand_state = rand_state*RAND_A + RAND_C; - return (rand_state >> 32)&0xFFFFFFFF; + rand_state = rand_state * RAND_A + RAND_C; + return (rand_state >> 32) & 0xFFFFFFFF; } -static void *memset(void *mem, u32 c, u32 n) +typedef enum { - void *result = mem; - u8 *bytes = mem; - while (n-- > 0) *bytes++ = c; - return result; -} - -typedef enum { DIR_RIGHT = 0, DIR_UP, DIR_LEFT, @@ -91,14 +93,16 @@ typedef enum { static Dir dir_opposite(Dir dir) { ASSERT(0 <= dir && dir < COUNT_DIRS, "Invalid direction"); - return (dir + 2)%COUNT_DIRS; + return (dir + 2) % COUNT_DIRS; } -typedef struct { +typedef struct +{ f32 x, y, w, h; } Rect; -typedef struct { +typedef struct +{ f32 lens[COUNT_DIRS]; } Sides; @@ -106,12 +110,11 @@ static Sides rect_sides(Rect rect) { Sides sides = { .lens = { - [DIR_LEFT] = rect.x, + [DIR_LEFT] = rect.x, [DIR_RIGHT] = rect.x + rect.w, - [DIR_UP] = rect.y, - [DIR_DOWN] = rect.y + rect.h, - } - }; + [DIR_UP] = rect.y, + [DIR_DOWN] = rect.y + rect.h, + }}; return sides; } @@ -126,42 +129,49 @@ static Rect sides_rect(Sides sides) return rect; } -typedef struct { +typedef struct +{ i32 x, y; } Cell; -typedef struct { +typedef struct +{ f32 x, y; } Vec; -#define SNAKE_CAP (ROWS*COLS) -typedef struct { +#define SNAKE_CAP (ROWS * COLS) +typedef struct +{ Cell items[SNAKE_CAP]; u32 begin; u32 size; } Snake; -typedef struct { +typedef struct +{ Rect items[SNAKE_CAP]; Vec vels[SNAKE_CAP]; u8 masks[SNAKE_CAP]; u32 size; } Dead_Snake; -typedef enum { +typedef enum +{ STATE_GAMEPLAY = 0, STATE_PAUSE, STATE_GAMEOVER, } State; #define DIR_QUEUE_CAP 3 -typedef struct { +typedef struct +{ u32 begin; u32 size; Dir items[DIR_QUEUE_CAP]; } Dir_Queue; -typedef struct { +typedef struct +{ u32 width; u32 height; @@ -195,8 +205,8 @@ static Game game = {0}; static Rect cell_rect(Cell cell) { Rect result = { - .x = cell.x*CELL_SIZE, - .y = cell.y*CELL_SIZE, + .x = cell.x * CELL_SIZE, + .y = cell.y * CELL_SIZE, .w = CELL_SIZE, .h = CELL_SIZE, }; @@ -205,43 +215,49 @@ static Rect cell_rect(Cell cell) #define ring_empty(ring) ((ring)->size == 0) -#define ring_cap(ring) (sizeof((ring)->items)/sizeof((ring)->items[0])) +#define ring_cap(ring) (sizeof((ring)->items) / sizeof((ring)->items[0])) -#define ring_push_back(ring, item) \ - do { \ +#define ring_push_back(ring, item) \ + do \ + { \ ASSERT((ring)->size < ring_cap(ring), "Ring buffer overflow"); \ - u32 index = ((ring)->begin + (ring)->size)%ring_cap(ring); \ - (ring)->items[index] = (item); \ - (ring)->size += 1; \ + u32 index = ((ring)->begin + (ring)->size) % ring_cap(ring); \ + (ring)->items[index] = (item); \ + (ring)->size += 1; \ } while (0) -#define ring_displace_back(ring, item) \ - do { \ - u32 index = ((ring)->begin + (ring)->size)%ring_cap(ring); \ - (ring)->items[index] = (item); \ - if ((ring)->size < ring_cap(ring)) { \ - (ring)->size += 1; \ - } else { \ - (ring)->begin = ((ring)->begin + 1)%ring_cap(ring); \ - } \ +#define ring_displace_back(ring, item) \ + do \ + { \ + u32 index = ((ring)->begin + (ring)->size) % ring_cap(ring); \ + (ring)->items[index] = (item); \ + if ((ring)->size < ring_cap(ring)) \ + { \ + (ring)->size += 1; \ + } \ + else \ + { \ + (ring)->begin = ((ring)->begin + 1) % ring_cap(ring); \ + } \ } while (0) -#define ring_pop_front(ring) \ - do { \ - ASSERT((ring)->size > 0, "Ring buffer underflow"); \ - (ring)->begin = ((ring)->begin + 1)%ring_cap(ring); \ - (ring)->size -= 1; \ +#define ring_pop_front(ring) \ + do \ + { \ + ASSERT((ring)->size > 0, "Ring buffer underflow"); \ + (ring)->begin = ((ring)->begin + 1) % ring_cap(ring); \ + (ring)->size -= 1; \ } while (0) -#define ring_back(ring) \ +#define ring_back(ring) \ (ASSERT((ring)->size > 0, "Ring buffer is empty"), \ - &(ring)->items[((ring)->begin + (ring)->size - 1)%ring_cap(ring)]) -#define ring_front(ring) \ + &(ring)->items[((ring)->begin + (ring)->size - 1) % ring_cap(ring)]) +#define ring_front(ring) \ (ASSERT((ring)->size > 0, "Ring buffer is empty"), \ &(ring)->items[(ring)->begin]) -#define ring_get(ring, index) \ +#define ring_get(ring, index) \ (ASSERT((ring)->size > 0, "Ring buffer is empty"), \ - &(ring)->items[((ring)->begin + (index))%ring_cap(ring)]) + &(ring)->items[((ring)->begin + (index)) % ring_cap(ring)]) static b32 cell_eq(Cell a, Cell b) { @@ -251,8 +267,10 @@ static b32 cell_eq(Cell a, Cell b) static i32 is_cell_snake_body(Cell cell) { // TODO: ignoring the tail feel hacky @tail-ignore - for (u32 index = 1; index < game.snake.size; ++index) { - if (cell_eq(*ring_get(&game.snake, index), cell)) { + for (u32 index = 1; index < game.snake.size; ++index) + { + if (cell_eq(*ring_get(&game.snake, index), cell)) + { return index; } } @@ -261,7 +279,7 @@ static i32 is_cell_snake_body(Cell cell) static i32 emod(i32 a, i32 b) { - return (a%b + b)%b; + return (a % b + b) % b; } static Cell cell_wrap(Cell cell) @@ -272,10 +290,10 @@ static Cell cell_wrap(Cell cell) } static Cell dir_cell_data[COUNT_DIRS] = { - [DIR_LEFT] = {.x = -1}, - [DIR_RIGHT] = {.x = 1}, - [DIR_UP] = {.y = -1}, - [DIR_DOWN] = {.y = 1}, + [DIR_LEFT] = {.x = -1}, + [DIR_RIGHT] = {.x = 1}, + [DIR_UP] = {.y = -1}, + [DIR_DOWN] = {.y = 1}, }; static Cell cell_add(Cell a, Cell b) @@ -285,19 +303,22 @@ static Cell cell_add(Cell a, Cell b) return a; } -#define dir_cell(dir) (ASSERT((u32) dir < COUNT_DIRS, "Invalid direction"), dir_cell_data[dir]) +#define dir_cell(dir) (ASSERT((u32)dir < COUNT_DIRS, "Invalid direction"), dir_cell_data[dir]) #define dir_vec(dir) cell_vec(dir_cell(dir)) static Cell step_cell(Cell head, Dir dir) { - if (game.infinite_field) { + if (game.infinite_field) + { return cell_add(head, dir_cell(dir)); - } else { + } + else + { return cell_wrap(cell_add(head, dir_cell(dir))); } } -#define SNAKE_INIT_ROW (ROWS/2) +#define SNAKE_INIT_ROW (ROWS / 2) static void random_egg(b32 first) { @@ -307,18 +328,20 @@ static void random_egg(b32 first) i32 row2 = ROWS - 1; // TODO: make a single formula that works for any mode - if (game.infinite_field) { - col1 = (i32)(game.camera_pos.x - game.width*0.5f + CELL_SIZE)/CELL_SIZE; - col2 = (i32)(game.camera_pos.x + game.width*0.5f - CELL_SIZE)/CELL_SIZE; - row1 = (i32)(game.camera_pos.y - game.height*0.5f + CELL_SIZE)/CELL_SIZE; - row2 = (i32)(game.camera_pos.y + game.height*0.5f - CELL_SIZE)/CELL_SIZE; + if (game.infinite_field) + { + col1 = (i32)(game.camera_pos.x - game.width * 0.5f + CELL_SIZE) / CELL_SIZE; + col2 = (i32)(game.camera_pos.x + game.width * 0.5f - CELL_SIZE) / CELL_SIZE; + row1 = (i32)(game.camera_pos.y - game.height * 0.5f + CELL_SIZE) / CELL_SIZE; + row2 = (i32)(game.camera_pos.y + game.height * 0.5f - CELL_SIZE) / CELL_SIZE; } #define RANDOM_EGG_MAX_ATTEMPTS 1000 u32 attempt = 0; - do { - game.egg.x = my_rand()%(col2 - col1 + 1) + col1; - game.egg.y = my_rand()%(row2 - row1 + 1) + row1; + do + { + game.egg.x = my_rand() % (col2 - col1 + 1) + col1; + game.egg.y = my_rand() % (row2 - row1 + 1) + row1; attempt += 1; } while ((is_cell_snake_body(game.egg) >= 0 || (first && game.egg.y == SNAKE_INIT_ROW)) && attempt < RANDOM_EGG_MAX_ATTEMPTS); @@ -334,37 +357,38 @@ static void game_restart(u32 width, u32 height) game.dt_scale = 1.0f; #endif - game.width = width; - game.height = height; - game.camera_pos.x = width/2; - game.camera_pos.y = height/2; + game.width = width; + game.height = height; + game.camera_pos.x = width / 2; + game.camera_pos.y = height / 2; - for (u32 i = 0; i < SNAKE_INIT_SIZE; ++i) { + for (u32 i = 0; i < SNAKE_INIT_SIZE; ++i) + { Cell head = {.x = i, .y = SNAKE_INIT_ROW}; ring_push_back(&game.snake, head); } random_egg(TRUE); game.dir = DIR_RIGHT; // TODO: Using snprintf to render Score is an overkill - // I believe snprintf should be only used for LOGF and in the "release" build stbsp_snprintf should not be included at all - stbsp_snprintf(game.score_buffer, sizeof(game.score_buffer), "Score: %u", game.score); + // I believe snprintf should be only used for LOGF and in the "release" build snprintf should not be included at all + snprintf(game.score_buffer, sizeof(game.score_buffer), "Score: %u", game.score); } static f32 lerpf(f32 a, f32 b, f32 t) { - return (b - a)*t + a; + return (b - a) * t + a; } static f32 ilerpf(f32 a, f32 b, f32 v) { - return (v - a)/(b - a); + return (v - a) / (b - a); } static void fill_rect(Rect rect, u32 color) { platform_fill_rect( - rect.x - game.camera_pos.x + game.width/2, - rect.y - game.camera_pos.y + game.height/2, + rect.x - game.camera_pos.x + game.width / 2, + rect.y - game.camera_pos.y + game.height / 2, rect.w, rect.h, color); } @@ -372,16 +396,16 @@ static void fill_rect(Rect rect, u32 color) static void stroke_rect(Rect rect, u32 color) { platform_stroke_rect( - rect.x - game.camera_pos.x + game.width/2, - rect.y - game.camera_pos.y + game.height/2, + rect.x - game.camera_pos.x + game.width / 2, + rect.y - game.camera_pos.y + game.height / 2, rect.w, rect.h, color); } #endif static Rect scale_rect(Rect r, float a) { - r.x = lerpf(r.x, r.x + r.w*0.5f, 1.0f - a); - r.y = lerpf(r.y, r.y + r.h*0.5f, 1.0f - a); + r.x = lerpf(r.x, r.x + r.w * 0.5f, 1.0f - a); + r.y = lerpf(r.y, r.y + r.h * 0.5f, 1.0f - a); r.w = lerpf(0.0f, r.w, a); r.h = lerpf(0.0f, r.h, a); return r; @@ -399,8 +423,10 @@ static void fill_sides(Sides sides, u32 color) static Dir cells_dir(Cell a, Cell b) { - for (Dir dir = 0; dir < COUNT_DIRS; ++dir) { - if (cell_eq(step_cell(a, dir), b)) return dir; + for (Dir dir = 0; dir < COUNT_DIRS; ++dir) + { + if (cell_eq(step_cell(a, dir), b)) + return dir; } UNREACHABLE(); return 0; @@ -408,58 +434,60 @@ static Dir cells_dir(Cell a, Cell b) static Vec cell_center(Cell a) { - return (Vec) { - .x = a.x*CELL_SIZE + CELL_SIZE/2, - .y = a.y*CELL_SIZE + CELL_SIZE/2, + return (Vec){ + .x = a.x * CELL_SIZE + CELL_SIZE / 2, + .y = a.y * CELL_SIZE + CELL_SIZE / 2, }; } static Sides slide_sides(Sides sides, Dir dir, f32 a) { f32 d = sides.lens[dir] - sides.lens[dir_opposite(dir)]; - sides.lens[dir] += lerpf(0, d, a); + sides.lens[dir] += lerpf(0, d, a); sides.lens[dir_opposite(dir)] += lerpf(0, d, a); return sides; } Vec sides_center(Sides sides) { - return (Vec) { - .x = sides.lens[DIR_LEFT] + (sides.lens[DIR_RIGHT] - sides.lens[DIR_LEFT])*0.5f, - .y = sides.lens[DIR_UP] + (sides.lens[DIR_DOWN] - sides.lens[DIR_UP])*0.5f, + return (Vec){ + .x = sides.lens[DIR_LEFT] + (sides.lens[DIR_RIGHT] - sides.lens[DIR_LEFT]) * 0.5f, + .y = sides.lens[DIR_UP] + (sides.lens[DIR_DOWN] - sides.lens[DIR_UP]) * 0.5f, }; } static void fill_spine(Vec center, Dir dir, float len) { - f32 thicc = CELL_SIZE*SNAKE_SPINE_THICCNESS_PERCENT; + f32 thicc = CELL_SIZE * SNAKE_SPINE_THICCNESS_PERCENT; Sides sides = { .lens = { - [DIR_LEFT] = center.x - thicc, - [DIR_RIGHT] = center.x + thicc, - [DIR_UP] = center.y - thicc, - [DIR_DOWN] = center.y + thicc, - } - }; - if (dir == DIR_RIGHT || dir == DIR_DOWN) sides.lens[dir] += len; - if (dir == DIR_LEFT || dir == DIR_UP) sides.lens[dir] -= len; + [DIR_LEFT] = center.x - thicc, + [DIR_RIGHT] = center.x + thicc, + [DIR_UP] = center.y - thicc, + [DIR_DOWN] = center.y + thicc, + }}; + if (dir == DIR_RIGHT || dir == DIR_DOWN) + sides.lens[dir] += len; + if (dir == DIR_LEFT || dir == DIR_UP) + sides.lens[dir] -= len; fill_sides(sides, SNAKE_SPINE_COLOR); } static void fill_fractured_spine(Sides sides, u8 mask) { - f32 thicc = CELL_SIZE*SNAKE_SPINE_THICCNESS_PERCENT; + f32 thicc = CELL_SIZE * SNAKE_SPINE_THICCNESS_PERCENT; Vec center = sides_center(sides); - for (Dir dir = 0; dir < COUNT_DIRS; ++dir) { - if (mask&(1< 1e-6; ++i) { - x -= (x*x - a)/(2*x); - } - return x; -} - static f32 vec_len(Vec a) { - return sqrtf(a.x*a.x + a.y*a.y); + return sqrtf(a.x * a.x + a.y * a.y); } void game_resize(u32 width, u32 height) @@ -665,56 +696,72 @@ void game_update(f32 dt) #ifdef FEATURE_DEV dt *= game.dt_scale; - #define DEV_DT_SCALE_STEP 0.05f - if (IsKeyPressed(KEY_Z)) { +#define DEV_DT_SCALE_STEP 0.05f + if (IsKeyPressed(KEY_Z)) + { game.dt_scale -= DEV_DT_SCALE_STEP; - if (game.dt_scale < 0.0f) game.dt_scale = 0.0f; + if (game.dt_scale < 0.0f) + game.dt_scale = 0.0f; LOGF("dt scale = %f", game.dt_scale); } - if (IsKeyPressed(KEY_X)) { + if (IsKeyPressed(KEY_X)) + { game.dt_scale += DEV_DT_SCALE_STEP; LOGF("dt scale = %f", game.dt_scale); } - if (IsKeyPressed(KEY_C)) { + if (IsKeyPressed(KEY_C)) + { game.dt_scale = 1.0f; LOGF("dt scale = %f", game.dt_scale); } #endif #define CAMERA_VELOCITY_FACTOR 0.80f - if (game.infinite_field) { - game.camera_pos.x += game.camera_vel.x*CAMERA_VELOCITY_FACTOR*dt; - game.camera_pos.y += game.camera_vel.y*CAMERA_VELOCITY_FACTOR*dt; + if (game.infinite_field) + { + game.camera_pos.x += game.camera_vel.x * CAMERA_VELOCITY_FACTOR * dt; + game.camera_pos.y += game.camera_vel.y * CAMERA_VELOCITY_FACTOR * dt; game.camera_vel = vec_sub( - cell_center(*ring_back(&game.snake)), - game.camera_pos); + cell_center(*ring_back(&game.snake)), + game.camera_pos); } - switch (game.state) { - case STATE_GAMEPLAY: { - if (IsKeyPressed(KEY_W)) { + switch (game.state) + { + case STATE_GAMEPLAY: + { + if (IsKeyPressed(KEY_W)) + { ring_displace_back(&game.next_dirs, DIR_UP); } - if (IsKeyPressed(KEY_S)) { + if (IsKeyPressed(KEY_S)) + { ring_displace_back(&game.next_dirs, DIR_DOWN); } - if (IsKeyPressed(KEY_A)) { + if (IsKeyPressed(KEY_A)) + { ring_displace_back(&game.next_dirs, DIR_LEFT); } - if (IsKeyPressed(KEY_D)) { + if (IsKeyPressed(KEY_D)) + { ring_displace_back(&game.next_dirs, DIR_RIGHT); } - if (IsKeyPressed(KEY_SPACE)) { + if (IsKeyPressed(KEY_SPACE)) + { game.state = STATE_PAUSE; } - if (IsKeyPressed(KEY_R)) { + if (IsKeyPressed(KEY_R)) + { game_restart(game.width, game.height); } game.step_cooldown -= dt; - if (game.step_cooldown <= 0.0f) { - if (!ring_empty(&game.next_dirs)) { - if (dir_opposite(game.dir) != *ring_front(&game.next_dirs)) { + if (game.step_cooldown <= 0.0f) + { + if (!ring_empty(&game.next_dirs)) + { + if (dir_opposite(game.dir) != *ring_front(&game.next_dirs)) + { game.dir = *ring_front(&game.next_dirs); } ring_pop_front(&game.next_dirs); @@ -722,7 +769,8 @@ void game_update(f32 dt) Cell next_head = step_cell(*ring_back(&game.snake), game.dir); - if (cell_eq(game.egg, next_head)) { + if (cell_eq(game.egg, next_head)) + { ring_push_back(&game.snake, next_head); random_egg(FALSE); game.eating_egg = TRUE; @@ -730,10 +778,13 @@ void game_update(f32 dt) game.infinite_field = TRUE; #endif game.score += 1; - stbsp_snprintf(game.score_buffer, sizeof(game.score_buffer), "Score: %u", game.score); - } else { + snprintf(game.score_buffer, sizeof(game.score_buffer), "Score: %u", game.score); + } + else + { i32 next_head_index = is_cell_snake_body(next_head); - if (next_head_index >= 0) { + if (next_head_index >= 0) + { // NOTE: reseting step_cooldown to 0 is important bcause the whole smooth movement is based on it. // Without this reset the head of the snake "detaches" from the snake on the Game Over, when // step_cooldown < 0.0f @@ -742,49 +793,60 @@ void game_update(f32 dt) game.dead_snake.size = game.snake.size; Vec head_center = cell_center(next_head); - for (u32 i = 0; i < game.snake.size; ++i) { + for (u32 i = 0; i < game.snake.size; ++i) + { #define GAMEOVER_EXPLOSION_RADIUS 1000.0f #define GAMEOVER_EXPLOSION_MAX_VEL 200.0f Cell cell = *ring_get(&game.snake, i); game.dead_snake.items[i] = cell_rect(cell); - if (!cell_eq(cell, next_head)) { + if (!cell_eq(cell, next_head)) + { Vec vel_vec = vec_sub(cell_center(cell), head_center); f32 vel_len = vec_len(vel_vec); f32 t = ilerpf(0.0f, GAMEOVER_EXPLOSION_RADIUS, vel_len); - if (t > 1.0f) t = 1.0f; + if (t > 1.0f) + t = 1.0f; t = 1.0f - t; - f32 noise_x = (my_rand()%1000)*0.01; - f32 noise_y = (my_rand()%1000)*0.01; - vel_vec.x = vel_vec.x/vel_len*GAMEOVER_EXPLOSION_MAX_VEL*t + noise_x; - vel_vec.y = vel_vec.y/vel_len*GAMEOVER_EXPLOSION_MAX_VEL*t + noise_y; + f32 noise_x = (my_rand() % 1000) * 0.01; + f32 noise_y = (my_rand() % 1000) * 0.01; + vel_vec.x = vel_vec.x / vel_len * GAMEOVER_EXPLOSION_MAX_VEL * t + noise_x; + vel_vec.y = vel_vec.y / vel_len * GAMEOVER_EXPLOSION_MAX_VEL * t + noise_y; game.dead_snake.vels[i] = vel_vec; // TODO: additional velocities along the body of the dead snake - } else { + } + else + { game.dead_snake.vels[i].x = 0; game.dead_snake.vels[i].y = 0; } // @tail-ignore - if (i > 0) { + if (i > 0) + { game.dead_snake.masks[i] = 0; - if (i > 1) { + if (i > 1) + { game.dead_snake.masks[i] |= 1 << cells_dir(cell, *ring_get(&game.snake, i - 1)); } - if (i < game.snake.size - 1) { + if (i < game.snake.size - 1) + { game.dead_snake.masks[i] |= 1 << cells_dir(cell, *ring_get(&game.snake, i + 1)); } } - if (i == game.snake.size - 1) { + if (i == game.snake.size - 1) + { game.dead_snake.masks[i] |= 1 << game.dir; } } game.dead_snake.masks[next_head_index] |= 1 << cells_dir( - *ring_get(&game.snake, next_head_index), - *ring_get(&game.snake, game.snake.size - 1)); + *ring_get(&game.snake, next_head_index), + *ring_get(&game.snake, game.snake.size - 1)); return; - } else { + } + else + { ring_push_back(&game.snake, next_head); ring_pop_front(&game.snake); game.eating_egg = FALSE; @@ -796,50 +858,58 @@ void game_update(f32 dt) } break; - case STATE_PAUSE: { - if (IsKeyPressed(KEY_SPACE)) { + case STATE_PAUSE: + { + if (IsKeyPressed(KEY_SPACE)) + { game.state = STATE_GAMEPLAY; } - if (IsKeyPressed(KEY_R)) { + if (IsKeyPressed(KEY_R)) + { game_restart(game.width, game.height); } - } break; + } + break; - case STATE_GAMEOVER: { - if (IsKeyPressed(KEY_A) || IsKeyPressed(KEY_S) || IsKeyPressed(KEY_D) || IsKeyPressed(KEY_W) || IsKeyPressed(KEY_SPACE)) { + case STATE_GAMEOVER: + { + if (IsKeyPressed(KEY_A) || IsKeyPressed(KEY_S) || IsKeyPressed(KEY_D) || IsKeyPressed(KEY_W) || IsKeyPressed(KEY_SPACE)) + { game_restart(game.width, game.height); } // @tail-ignore - for (u32 i = 1; i < game.dead_snake.size; ++i) { + for (u32 i = 1; i < game.dead_snake.size; ++i) + { game.dead_snake.vels[i].x *= 0.99f; game.dead_snake.vels[i].y *= 0.99f; - game.dead_snake.items[i].x += game.dead_snake.vels[i].x*dt; - game.dead_snake.items[i].y += game.dead_snake.vels[i].y*dt; + game.dead_snake.items[i].x += game.dead_snake.vels[i].x * dt; + game.dead_snake.items[i].y += game.dead_snake.vels[i].y * dt; } } break; - default: { + default: + { UNREACHABLE(); } } } #define FACTOR 100 -#define WIDTH (16*FACTOR) -#define HEIGHT (9*FACTOR) +#define WIDTH (16 * FACTOR) +#define HEIGHT (9 * FACTOR) static Font font = {0}; void platform_fill_rect(i32 x, i32 y, i32 w, i32 h, u32 color) { - DrawRectangle(x, y, w, h, *(Color*)&color); + DrawRectangle(x, y, w, h, *(Color *)&color); } void platform_stroke_rect(i32 x, i32 y, i32 w, i32 h, u32 color) { - DrawRectangleLines(x, y, w, h, *(Color*)&color); + DrawRectangleLines(x, y, w, h, *(Color *)&color); } u32 platform_text_width(const char *text, u32 size) @@ -851,7 +921,7 @@ void platform_fill_text(i32 x, i32 y, const char *text, u32 fontSize, u32 color) { Vector2 size = MeasureTextEx(font, text, fontSize, 0); Vector2 position = {.x = x, .y = y - size.y}; - DrawTextEx(font, text, position, fontSize, 0.0, *(Color*)&color); + DrawTextEx(font, text, position, fontSize, 0.0, *(Color *)&color); } void platform_log(const char *message) @@ -881,7 +951,8 @@ int main(void) #ifdef PLATFORM_WEB raylib_js_set_entry(GameFrame); #else - while (!WindowShouldClose()) { + while (!WindowShouldClose()) + { GameFrame(); } diff --git a/include/math.h b/include/math.h deleted file mode 100644 index 3d32b52..0000000 --- a/include/math.h +++ /dev/null @@ -1,17 +0,0 @@ -// Phony math.h. Since we are compiling with --no-standard-libraries raymath.h can't find math.h. -// But it only needs it for few function definitions. So we've put those definitions here. -#ifndef MATH_H_ -#define MATH_H_ -float floorf(float); -float fabsf(float); -double fabs(double); -float fmaxf(float, float); -float fminf(float, float); -float sqrtf(float); -float atan2f(float, float); -float cosf(float); -float sinf(float); -float acosf(float); -float asinf(float); -double tan(double); -#endif // MATH_H_ diff --git a/index.html b/index.html index 960a2cd..14bce2a 100644 --- a/index.html +++ b/index.html @@ -57,6 +57,12 @@ src: url(fonts/acme_7_wide_xtnd.woff); } + + + + + + @@ -72,6 +78,7 @@ "shapes": ["shapes_colors_palette"], "text": ["text_writing_anim"], "textures": ["textures_logo_raylib"], + "libc": ["libc_math", "libc_exit", "libc_malloc", "libc_file"], } const defaultWasm = Object.values(wasmPaths)[0][0]; diff --git a/libc/include/assert.h b/libc/include/assert.h new file mode 100644 index 0000000..0e1e602 --- /dev/null +++ b/libc/include/assert.h @@ -0,0 +1,32 @@ +#ifndef _INC_ASSERT +#define _INC_ASSERT + +#ifdef NDEBUG + +#define assert(expression) ((void)0) + +#else + +#ifndef NO_ASSERT_INCLUDE +void _assert(const char *message, const char *file, unsigned line); +#endif + +#ifdef ASSERT_IMPL +#include +#include + +void exit(int); +int printf(const char *, ...); +void _assert(const char *message, const char *file, unsigned line) +{ + printf("Assertion failed at %s : %i\n\t%s", file, line, message); + exit(1); +} +#endif + +#define assert(expression) (void)((!!(expression)) || \ + (_assert(#expression, __FILE__, (unsigned)(__LINE__)), 0)) + +#endif + +#endif // _INC_ASSERT \ No newline at end of file diff --git a/libc/include/errno.h b/libc/include/errno.h new file mode 100644 index 0000000..d08fd85 --- /dev/null +++ b/libc/include/errno.h @@ -0,0 +1,98 @@ +#ifndef _INC_ERRNO +#define _INC_ERRNO + +// SAVE WITHOUT FORMAT VSCODE: CTRL + K CTRL + SHIFT + S + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define EDEADLK 36 +#define ENAMETOOLONG 38 +#define ENOLCK 39 +#define ENOSYS 40 +#define ENOTEMPTY 41 + +// Error codes used in the Secure CRT functions +#define EINVAL 22 +#define ERANGE 34 +#define EILSEQ 42 +#define STRUNCATE 80 + +// POSIX +#define EADDRINUSE 100 +#define EADDRNOTAVAIL 101 +#define EAFNOSUPPORT 102 +#define EALREADY 103 +#define EBADMSG 104 +#define ECANCELED 105 +#define ECONNABORTED 106 +#define ECONNREFUSED 107 +#define ECONNRESET 108 +#define EDESTADDRREQ 109 +#define EHOSTUNREACH 110 +#define EIDRM 111 +#define EINPROGRESS 112 +#define EISCONN 113 +#define ELOOP 114 +#define EMSGSIZE 115 +#define ENETDOWN 116 +#define ENETRESET 117 +#define ENETUNREACH 118 +#define ENOBUFS 119 +#define ENODATA 120 +#define ENOLINK 121 +#define ENOMSG 122 +#define ENOPROTOOPT 123 +#define ENOSR 124 +#define ENOSTR 125 +#define ENOTCONN 126 +#define ENOTRECOVERABLE 127 +#define ENOTSOCK 128 +#define ENOTSUP 129 +#define EOPNOTSUPP 130 +#define EOTHER 131 +#define EOVERFLOW 132 +#define EOWNERDEAD 133 +#define EPROTO 134 +#define EPROTONOSUPPORT 135 +#define EPROTOTYPE 136 +#define ETIME 137 +#define ETIMEDOUT 138 +#define ETXTBSY 139 +#define EWOULDBLOCK 140 + +#define errno __errno_impl +int __errno_impl; + +#ifdef ERRNO_IMPL +int __errno_impl = 0; +#endif + +#endif \ No newline at end of file diff --git a/libc/include/fenv.h b/libc/include/fenv.h new file mode 100644 index 0000000..10b9a03 --- /dev/null +++ b/libc/include/fenv.h @@ -0,0 +1,140 @@ +#ifndef _INC_FENV +#define _INC_FENV + +// DEFINES + +#define FE_DOWNWARD 0 +#define FE_TONEAREST 1 +#define FE_TOWARDZERO 2 +#define FE_UPWARD 3 + +#define FE_DIVBYZERO 0x01 // Pole error: division by zero, or some other asymptotically infinite result (from finite arguments). +#define FE_INEXACT 0x02 // Inexact: the result is not exact. +#define FE_INVALID 0x04 // Domain error: At least one of the arguments is a value for which the function is not defined. +#define FE_OVERFLOW 0x08 // Overflow range error: The result is too large in magnitude to be represented as a value of the return type. +#define FE_UNDERFLOW 0x10 // Underflow range error: The result is too small in magnitude to be represented as a value of the return type. +#define FE_ALL_EXCEPT 0x1F // All exceptions (selects all of the exceptions supported by the implementation). + +#ifndef NO_FENV_INCLUDE + +// TYPES +typedef int fexcept_t; +typedef struct fenv_t fenv_t; + +// DEFINITIONS +fenv_t *_create_default_env(); +#define FE_DFL_ENV _create_default_env() + +// EXCEPTIONS +int feclearexcept(int excepts); +int feraiseexcept(int excepts); +int fegetexceptflag(fexcept_t *flagp, int excepts); +int fesetexceptflag(const fexcept_t *flagp, int excepts); +int fetestexcept(int excepts); + +// ENV +int fegetenv(fenv_t *envp); +int fesetenv(const fenv_t *envp); +int feholdexcept(fenv_t *envp); +int feupdateenv(const fenv_t *envp); + +// ROUNDING +int fegetround(void); +int fesetround(int mode); + +#endif + +// IMPLEMENTATION +#ifdef FENV_IMPL + +#ifdef NO_FENV_INCLUDE +typedef int fexcept_t; +#endif +struct fenv_t +{ + int exception_flags; + int rounding_mode; +}; + +// +// NOT PER THREAD +int __fe_exception_flag = 0; +int __fe_rounding_mode = 0; + +struct fenv_t __fe_env; +struct fenv_t *_create_default_env() +{ + __fe_env.exception_flags = 0; + __fe_env.rounding_mode = 0; + return &__fe_env; +} + +// EXCEPTIONS +int feclearexcept(int excepts) +{ + __fe_exception_flag = __fe_exception_flag & ~excepts; + return 0; +} +int feraiseexcept(int excepts) +{ + __fe_exception_flag = __fe_exception_flag | excepts; + return 0; +} +int fegetexceptflag(fexcept_t *flagp, int excepts) +{ + *flagp = excepts; + return 0; +} +int fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + __fe_exception_flag = __fe_exception_flag | (*flagp) & excepts; + return 0; +} +int fetestexcept(int excepts) +{ + return __fe_exception_flag & excepts; +} + +// ENV +int fegetenv(struct fenv_t *envp) +{ + envp->exception_flags = __fe_exception_flag; + envp->rounding_mode = __fe_rounding_mode; + return 0; +} +int fesetenv(const struct fenv_t *envp) +{ + __fe_exception_flag = envp->exception_flags; + __fe_rounding_mode = envp->rounding_mode; + return 0; +} +int feholdexcept(struct fenv_t *envp) +{ + fegetenv(envp); + + __fe_exception_flag = 0; + __fe_rounding_mode = 0; + + return 0; +} +int feupdateenv(const struct fenv_t *envp) +{ + fesetenv(envp); + // raise the exceptions ? + return 0; +} + +// ROUNDING +int fegetround(void) +{ + return __fe_rounding_mode; +} +void _js_fesetround(int mode); +int fesetround(int mode) +{ + __fe_rounding_mode = mode; + _js_fesetround(mode); + return 0; +} +#endif +#endif \ No newline at end of file diff --git a/libc/include/math.h b/libc/include/math.h new file mode 100644 index 0000000..acb86e7 --- /dev/null +++ b/libc/include/math.h @@ -0,0 +1,239 @@ +#ifndef _INC_MATH +#define _INC_MATH + +#include // wasm needs the export + +#define INFINITY (1.0 / 0.0) +#define NAN (0.0 / 0.0) +#define HUGE_VAL (double)INFINITY +#define HUGE_VALF INFINITY +#define HUGE_VALL (long double)INFINITY + +#define FP_ILOGB0 -2147483648 +#define FP_ILOGBNAN -2147483648 + +#define FP_FAST_FMA 1 +#define FP_FAST_FMAF 1 +#define FP_FAST_FMAL 1 + +#define FP_INFINITE 0x01 +#define FP_NAN 0x02 +#define FP_NORMAL 0x04 +#define FP_SUBNORMAL 0x08 // https://stackoverflow.com/questions/8341395/what-is-a-subnormal-floating-point-number +#define FP_ZERO 0x10 + +// CLASSIFICATION +#define fpclassify(arg) \ + (arg == 0 ? FP_ZERO : (isnan(arg) ? FP_NAN : (isinf(arg) ? FP_INFINITE : ((arg > 0 ? arg : -arg) < 1 * 2 ^ (-126)) ? FP_SUBNORMAL \ + : FP_NORMAL))) +#define isinf(arg) ((float)arg == INFINITY) +#define isfinite(arg) !isinf(arg) +#define isnan(arg) (arg != arg) +#define isnormal(arg) (!isnan(arg) && isfinite(arg) && (arg > 0 ? arg : -arg) >= 1 * 2 ^ (-126)) +#define signbit(arg) (isnan(arg) ? 1 : arg < 0) + +// COMPARISON +#define isgreater(x, y) (x > y) +#define isgreaterequal(x, y) (x >= y) +#define isless(x, y) (x < y) +#define islessequal(x, y) (x <= y) +#define islessgreater(x, y) (x < y || x > y) +#define isunordered(x, y) (isnan(x) || isnan(y)) + +// FUNCTIONS +double atan(double); +double cos(double); +double sin(double); +double tan(double); +double tanh(double); +double frexp(double, int *); +double modf(double, double *); +double ceil(double); +double fabs(double); +double floor(double); + +double acos(double); +double asin(double); +double atan2(double, double); +double cosh(double); +double sinh(double); +double exp(double); +double ldexp(double, int); +double log(double); +double log10(double); +double pow(double, double); +double sqrt(double); +double fmod(double, double); + +double infinity(void); +double nan(const char *); +double copysign(double, double); +double logb(double); +int ilogb(double); + +double asinh(double); +double cbrt(double); +double nextafter(double, double); +double rint(double); +double scalbn(double, int); + +double exp2(double); +double scalbln(double, long int); +double tgamma(double); +double nearbyint(double); +long int lrint(double); +long long int llrint(double); +double round(double); +long int lround(double); +long long int llround(double); +double trunc(double); +double remquo(double, double, int *); +double fdim(double, double); +double fmax(double, double); +double fmin(double, double); +double fma(double, double, double); + +double log1p(double); +double expm1(double); + +double acosh(double); +double atanh(double); +double remainder(double, double); +double gamma(double); +double lgamma(double); +double erf(double); +double erfc(double); +double log2(double); + +double hypot(double, double); + +// Single Precision +float atanf(float); +float cosf(float); +float sinf(float); +float tanf(float); +float tanhf(float); +float frexpf(float, int *); +float modff(float, float *); +float ceilf(float); +float fabsf(float); +float floorf(float); + +float acosf(float); +float asinf(float); +float atan2f(float, float); +float coshf(float); +float sinhf(float); +float expf(float); +float ldexpf(float, int); +float logf(float); +float log10f(float); +float powf(float, float); +float sqrtf(float); +float fmodf(float, float); + +float exp2f(float); +float scalblnf(float, long int); +float tgammaf(float); +float nearbyintf(float); +long int lrintf(float); +long long int llrintf(float); +float roundf(float); +long int lroundf(float); +long long int llroundf(float); +float truncf(float); +float remquof(float, float, int *); +float fdimf(float, float); +float fmaxf(float, float); +float fminf(float, float); +float fmaf(float, float, float); + +float infinityf(void); +float nanf(const char *); +float copysignf(float, float); +float logbf(float); +int ilogbf(float); + +float asinhf(float); +float cbrtf(float); +float nextafterf(float, float); +float rintf(float); +float scalbnf(float, int); +float log1pf(float); +float expm1f(float); + +float acoshf(float); +float atanhf(float); +float remainderf(float, float); +float gammaf(float); +float lgammaf(float); +float erff(float); +float erfcf(float); +float log2f(float); +float hypotf(float, float); + +// long double (js has no support for this but is like a define over the double variant) +long double atanl(long double); +long double cosl(long double); +long double sinl(long double); +long double tanl(long double); +long double tanhl(long double); +long double frexpl(long double, int *); +long double modfl(long double, long double *); +long double ceill(long double); +long double fabsl(long double); +long double floorl(long double); +long double log1pl(long double); +long double expm1l(long double); + +long double acosl(long double); +long double asinl(long double); +long double atan2l(long double, long double); +long double coshl(long double); +long double sinhl(long double); +long double expl(long double); +long double ldexpl(long double, int); +long double logl(long double); +long double log10l(long double); +long double powl(long double, long double); +long double sqrtl(long double); +long double fmodl(long double, long double); +long double hypotl(long double, long double); + +long double copysignl(long double, long double); +long double nanl(const char *); +int ilogbl(long double); +long double asinhl(long double); +long double cbrtl(long double); +long double nextafterl(long double, long double); +float nexttowardf(float, long double); +double nexttoward(double, long double); +long double nexttowardl(long double, long double); +long double logbl(long double); +long double log2l(long double); +long double rintl(long double); +long double scalbnl(long double, int); +long double exp2l(long double); +long double scalblnl(long double, long); +long double tgammal(long double); +long double nearbyintl(long double); +long int lrintl(long double); +long long int llrintl(long double); +long double roundl(long double); +long lroundl(long double); +long long int llroundl(long double); +long double truncl(long double); +long double remquol(long double, long double, int *); +long double fdiml(long double, long double); +long double fmaxl(long double, long double); +long double fminl(long double, long double); +long double fmal(long double, long double, long double); + +long double acoshl(long double); +long double atanhl(long double); +long double remainderl(long double, long double); +long double lgammal(long double); +long double erfl(long double); +long double erfcl(long double); + +#endif // _INC_MATH diff --git a/examples/tsoding_snake/stb_sprintf.h b/libc/include/stb_sprintf.h similarity index 78% rename from examples/tsoding_snake/stb_sprintf.h rename to libc/include/stb_sprintf.h index ca432a6..bb8b180 100644 --- a/examples/tsoding_snake/stb_sprintf.h +++ b/libc/include/stb_sprintf.h @@ -143,21 +143,21 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): */ #if defined(__clang__) - #if defined(__has_feature) && defined(__has_attribute) - #if __has_feature(address_sanitizer) - #if __has_attribute(__no_sanitize__) - #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) - #elif __has_attribute(__no_sanitize_address__) - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #elif __has_attribute(__no_address_safety_analysis__) - #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) - #endif - #endif - #endif +#if defined(__has_feature) && defined(__has_attribute) +#if __has_feature(address_sanitizer) +#if __has_attribute(__no_sanitize__) +#define STBSP__ASAN __attribute__((__no_sanitize__("address"))) +#elif __has_attribute(__no_sanitize_address__) +#define STBSP__ASAN __attribute__((__no_sanitize_address__)) +#elif __has_attribute(__no_address_safety_analysis__) +#define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) +#endif +#endif +#endif #elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) - #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ - #define STBSP__ASAN __attribute__((__no_sanitize_address__)) - #endif +#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ +#define STBSP__ASAN __attribute__((__no_sanitize_address__)) +#endif #endif #ifndef STBSP__ASAN @@ -178,19 +178,19 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): #endif #if defined(__has_attribute) - #if __has_attribute(format) - #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) - #endif +#if __has_attribute(format) +#define STBSP__ATTRIBUTE_FORMAT(fmt, va) __attribute__((format(printf, fmt, va))) +#endif #endif #ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#define STBSP__ATTRIBUTE_FORMAT(fmt, va) #endif #ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) +#define STBSP__NOTUSED(v) (void)(v) #else -#define STBSP__NOTUSED(v) (void)sizeof(v) +#define STBSP__NOTUSED(v) (void)sizeof(v) #endif #include // for va_arg(), va_list() @@ -206,9 +206,9 @@ typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); #endif STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, size_t count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2, 3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, size_t count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3, 4); STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); @@ -263,13 +263,12 @@ static struct short temp; // force next field to be 2-byte aligned char pair[201]; } stbsp__digitpair = -{ - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899" -}; + { + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899"}; STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) { @@ -294,13 +293,18 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char ppe static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) { sign[0] = 0; - if (fl & STBSP__NEGATIVE) { + if (fl & STBSP__NEGATIVE) + { sign[0] = 1; sign[1] = '-'; - } else if (fl & STBSP__LEADINGSPACE) { + } + else if (fl & STBSP__LEADINGSPACE) + { sign[0] = 1; sign[1] = ' '; - } else if (fl & STBSP__LEADINGPLUS) { + } + else if (fl & STBSP__LEADINGPLUS) + { sign[0] = 1; sign[1] = '+'; } @@ -308,10 +312,11 @@ static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) { - char const * sn = s; + char const *sn = s; // get up to 4-byte alignment - for (;;) { + for (;;) + { if (((stbsp__uintptr)sn & 3) == 0) break; @@ -327,7 +332,8 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin // but becase it works 4B aligned, it will never cross page boundaries // (hence the STBSP__ASAN markup; the over-read here is intentional // and harmless) - while (limit >= 4) { + while (limit >= 4) + { stbsp__uint32 v = *(stbsp__uint32 *)sn; // bit hack to find if there's a 0 byte in there if ((v - 0x01010101) & (~v) & 0x80808080UL) @@ -338,7 +344,8 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin } // handle the last few characters to find actual size - while (limit && *sn) { + while (limit && *sn) + { ++sn; --limit; } @@ -356,41 +363,47 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, bf = buf; f = fmt; - for (;;) { + for (;;) + { stbsp__int32 fw, pr, tz; stbsp__uint32 fl; - // macros for the callback buffer stuff - #define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } - #define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } - #define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer - #define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } +// macros for the callback buffer stuff +#define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) \ + { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } +#define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) \ + { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } +#define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer +#define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) \ + { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } // fast copy everything up to the next % (or end of string) - for (;;) { - while (((stbsp__uintptr)f) & 3) { + for (;;) + { + while (((stbsp__uintptr)f) & 3) + { schk1: if (f[0] == '%') goto scandd; @@ -401,7 +414,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, *bf++ = f[0]; ++f; } - for (;;) { + for (;;) + { // Check if the next 4 bytes contain %(0x25) or end of string. // Using the 'hasless' trick: // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord @@ -415,16 +429,18 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if (callback) if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) goto schk1; - #ifdef STB_SPRINTF_NOUNALIGNED - if(((stbsp__uintptr)bf) & 3) { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } else - #endif +#ifdef STB_SPRINTF_NOUNALIGNED + if (((stbsp__uintptr)bf) & 3) { - *(stbsp__uint32 *)bf = v; + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } + else +#endif + { + *(stbsp__uint32 *)bf = v; } bf += 4; f += 4; @@ -441,8 +457,10 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, tz = 0; // flags - for (;;) { - switch (f[0]) { + for (;;) + { + switch (f[0]) + { // if we have left justify case '-': fl |= STBSP__LEFTJUST; @@ -470,13 +488,19 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, continue; // if we have kilo marker (none->kilo->kibi->jedec) case '$': - if (fl & STBSP__METRIC_SUFFIX) { - if (fl & STBSP__METRIC_1024) { + if (fl & STBSP__METRIC_SUFFIX) + { + if (fl & STBSP__METRIC_1024) + { fl |= STBSP__METRIC_JEDEC; - } else { + } + else + { fl |= STBSP__METRIC_1024; } - } else { + } + else + { fl |= STBSP__METRIC_SUFFIX; } ++f; @@ -491,30 +515,40 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fl |= STBSP__LEADINGZERO; ++f; goto flags_done; - default: goto flags_done; + default: + goto flags_done; } } flags_done: // get the field width - if (f[0] == '*') { + if (f[0] == '*') + { fw = va_arg(va, stbsp__uint32); ++f; - } else { - while ((f[0] >= '0') && (f[0] <= '9')) { + } + else + { + while ((f[0] >= '0') && (f[0] <= '9')) + { fw = fw * 10 + f[0] - '0'; f++; } } // get the precision - if (f[0] == '.') { + if (f[0] == '.') + { ++f; - if (f[0] == '*') { + if (f[0] == '*') + { pr = va_arg(va, stbsp__uint32); ++f; - } else { + } + else + { pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) { + while ((f[0] >= '0') && (f[0] <= '9')) + { pr = pr * 10 + f[0] - '0'; f++; } @@ -522,19 +556,21 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, } // handle integer size overrides - switch (f[0]) { + switch (f[0]) + { // are we halfwidth? case 'h': fl |= STBSP__HALFWIDTH; ++f; if (f[0] == 'h') - ++f; // QUARTERWIDTH + ++f; // QUARTERWIDTH break; // are we 64-bit (unix style) case 'l': fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); ++f; - if (f[0] == 'l') { + if (f[0] == 'l') + { fl |= STBSP__INTMAX; ++f; } @@ -555,22 +591,29 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, break; // are we 64-bit (msft style) case 'I': - if ((f[1] == '6') && (f[2] == '4')) { + if ((f[1] == '6') && (f[2] == '4')) + { fl |= STBSP__INTMAX; f += 3; - } else if ((f[1] == '3') && (f[2] == '2')) { + } + else if ((f[1] == '3') && (f[2] == '2')) + { f += 3; - } else { + } + else + { fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); ++f; } break; - default: break; + default: + break; } // handle each replacement - switch (f[0]) { - #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + switch (f[0]) + { +#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 char num[STBSP__NUMSZ]; char lead[8]; char tail[8]; @@ -616,7 +659,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, { int *d = va_arg(va, int *); *d = tlen + (int)(bf - buf); - } break; + } + break; #ifdef STB_SPRINTF_NOFLOAT case 'A': // float @@ -657,7 +701,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n64 <<= (64 - 56); if (pr < 15) n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); -// add leading chars + // add leading chars #ifdef STB_SPRINTF_MSVC_MODE *s++ = '0'; @@ -680,21 +724,25 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if (pr > (stbsp__int32)n) tz = pr - n; pr = 0; - while (n--) { + while (n--) + { *s++ = h[(n64 >> 60) & 15]; n64 <<= 4; } // print the expo tail[1] = h[17]; - if (dp < 0) { + if (dp < 0) + { tail[2] = '-'; dp = -dp; - } else + } + else tail[2] = '+'; n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); tail[0] = (char)n; - for (;;) { + for (;;) + { tail[n] = '0' + dp % 10; if (n <= 3) break; @@ -724,13 +772,15 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n = pr; if (l > (stbsp__uint32)pr) l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + while ((l > 1) && (pr) && (sn[l - 1] == '0')) + { --pr; --l; } // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if ((dp <= -4) || (dp > (stbsp__int32)n)) + { if (pr > (stbsp__int32)l) pr = l - 1; else if (pr) @@ -738,10 +788,13 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, goto doexpfromg; } // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) { + if (dp > 0) + { pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } else { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + else + { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32)l : pr); } goto dofloatfromg; @@ -757,7 +810,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, doexpfromg: tail[0] = 0; stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { + if (dp == STBSP__SPECIAL) + { s = (char *)sn; cs = 0; pr = 0; @@ -781,10 +835,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // dump expo tail[1] = h[0xe]; dp -= 1; - if (dp < 0) { + if (dp < 0) + { tail[2] = '-'; dp = -dp; - } else + } + else tail[2] = '+'; #ifdef STB_SPRINTF_MSVC_MODE n = 5; @@ -792,7 +848,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n = (dp >= 100) ? 5 : 4; #endif tail[0] = (char)n; - for (;;) { + for (;;) + { tail[n] = '0' + dp % 10; if (n <= 3) break; @@ -806,12 +863,14 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fv = va_arg(va, double); doafloat: // do kilos - if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_SUFFIX) + { double divisor; divisor = 1000.0f; if (fl & STBSP__METRIC_1024) divisor = 1024.0; - while (fl < 0x4000000) { + while (fl < 0x4000000) + { if ((fv < divisor) && (fv > -divisor)) break; fv /= divisor; @@ -826,7 +885,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, dofloatfromg: tail[0] = 0; stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) { + if (dp == STBSP__SPECIAL) + { s = (char *)sn; cs = 0; pr = 0; @@ -835,7 +895,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s = num + 64; // handle the three decimal varieties - if (dp <= 0) { + if (dp <= 0) + { stbsp__int32 i; // handle 0.000*000xxxx *s++ = '0'; @@ -845,84 +906,110 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if ((stbsp__int32)n > pr) n = pr; i = n; - while (i) { + while (i) + { if ((((stbsp__uintptr)s) & 3) == 0) break; *s++ = '0'; --i; } - while (i >= 4) { + while (i >= 4) + { *(stbsp__uint32 *)s = 0x30303030; s += 4; i -= 4; } - while (i) { + while (i) + { *s++ = '0'; --i; } if ((stbsp__int32)(l + n) > pr) l = pr - n; i = l; - while (i) { + while (i) + { *s++ = *sn++; --i; } tz = pr - (n + l); cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } else { + } + else + { cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) { + if ((stbsp__uint32)dp >= l) + { // handle xxxx000*000.0 n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + for (;;) + { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) + { cs = 0; *s++ = stbsp__comma; - } else { + } + else + { *s++ = sn[n]; ++n; if (n >= l) break; } } - if (n < (stbsp__uint32)dp) { + if (n < (stbsp__uint32)dp) + { n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (n) { + if ((fl & STBSP__TRIPLET_COMMA) == 0) + { + while (n) + { if ((((stbsp__uintptr)s) & 3) == 0) break; *s++ = '0'; --n; } - while (n >= 4) { + while (n >= 4) + { *(stbsp__uint32 *)s = 0x30303030; s += 4; n -= 4; } } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + while (n) + { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) + { cs = 0; *s++ = stbsp__comma; - } else { + } + else + { *s++ = '0'; --n; } } } cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) { + if (pr) + { *s++ = stbsp__period; tz = pr; } - } else { + } + else + { // handle xxxxx.xxxx000*000 n = 0; - for (;;) { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + for (;;) + { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) + { cs = 0; *s++ = stbsp__comma; - } else { + } + else + { *s++ = sn[n]; ++n; if (n >= (stbsp__uint32)dp) @@ -934,7 +1021,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, *s++ = stbsp__period; if ((l - dp) > (stbsp__uint32)pr) l = pr + dp; - while (n < l) { + while (n < l) + { *s++ = sn[n]; ++n; } @@ -944,7 +1032,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, pr = 0; // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_SUFFIX) + { char idx; idx = 1; if (fl & STBSP__METRIC_NOSPACE) @@ -952,14 +1041,16 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, tail[0] = idx; tail[1] = ' '; { - if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl >> 24) + { // SI kilo is 'k', JEDEC and SI kibits are 'K'. if (fl & STBSP__METRIC_1024) tail[idx + 1] = "_KMGT"[fl >> 24]; else tail[idx + 1] = "_kMGT"[fl >> 24]; idx++; // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) + { tail[idx + 1] = 'i'; idx++; } @@ -979,7 +1070,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'b': // lower binary h = (f[0] == 'B') ? hexu : hex; lead[0] = 0; - if (fl & STBSP__LEADING_0X) { + if (fl & STBSP__LEADING_0X) + { lead[0] = 2; lead[1] = '0'; lead[2] = h[0xb]; @@ -990,7 +1082,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'o': // octal h = hexu; lead[0] = 0; - if (fl & STBSP__LEADING_0X) { + if (fl & STBSP__LEADING_0X) + { lead[0] = 1; lead[1] = '0'; } @@ -1008,7 +1101,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, h = (f[0] == 'X') ? hexu : hex; l = (4 << 4) | (4 << 8); lead[0] = 0; - if (fl & STBSP__LEADING_0X) { + if (fl & STBSP__LEADING_0X) + { lead[0] = 2; lead[1] = '0'; lead[2] = h[16]; @@ -1024,23 +1118,28 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, dp = 0; // clear tail, and clear leading if value is zero tail[0] = 0; - if (n64 == 0) { + if (n64 == 0) + { lead[0] = 0; - if (pr == 0) { + if (pr == 0) + { l = 0; cs = 0; goto scopy; } } // convert to string - for (;;) { + for (;;) + { *--s = h[n64 & ((1 << (l >> 8)) - 1)]; n64 >>= (l >> 8); if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) break; - if (fl & STBSP__TRIPLET_COMMA) { + if (fl & STBSP__TRIPLET_COMMA) + { ++l; - if ((l & 15) == ((l >> 4) & 15)) { + if ((l & 15) == ((l >> 4) & 15)) + { l &= ~15; *--s = stbsp__comma; } @@ -1057,24 +1156,30 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'i': case 'd': // integer // get the integer and abs it - if (fl & STBSP__INTMAX) { + if (fl & STBSP__INTMAX) + { stbsp__int64 i64 = va_arg(va, stbsp__int64); n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) { + if ((f[0] != 'u') && (i64 < 0)) + { n64 = (stbsp__uint64)-i64; fl |= STBSP__NEGATIVE; } - } else { + } + else + { stbsp__int32 i = va_arg(va, stbsp__int32); n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) { + if ((f[0] != 'u') && (i < 0)) + { n64 = (stbsp__uint32)-i; fl |= STBSP__NEGATIVE; } } #ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_SUFFIX) + { if (n64 < 1024) pr = 0; else if (pr == -1) @@ -1088,44 +1193,58 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s = num + STBSP__NUMSZ; l = 0; - for (;;) { + for (;;) + { // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) char *o = s - 8; - if (n64 >= 100000000) { + if (n64 >= 100000000) + { n = (stbsp__uint32)(n64 % 100000000); n64 /= 100000000; - } else { + } + else + { n = (stbsp__uint32)n64; n64 = 0; } - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - do { + if ((fl & STBSP__TRIPLET_COMMA) == 0) + { + do + { s -= 2; *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; n /= 100; } while (n); } - while (n) { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + while (n) + { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) + { l = 0; *--s = stbsp__comma; --o; - } else { + } + else + { *--s = (char)(n % 10) + '0'; n /= 10; } } - if (n64 == 0) { + if (n64 == 0) + { if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) ++s; break; } while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) + { l = 0; *--s = stbsp__comma; --o; - } else { + } + else + { *--s = '0'; } } @@ -1135,7 +1254,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // get the length that we copied l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) { + if (l == 0) + { *--s = '0'; l = 1; } @@ -1154,38 +1274,46 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, pr -= l; // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) { + if ((fl & STBSP__LEFTJUST) == 0) + { if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr { pr = (fw > pr) ? fw : pr; fw = 0; - } else { + } + else + { fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas } } // copy the spaces and/or zeros - if (fw + pr) { + if (fw + pr) + { stbsp__int32 i; stbsp__uint32 c; // copy leading spaces (or when doing %8.4d stuff) if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) { + while (fw > 0) + { stbsp__cb_buf_clamp(i, fw); fw -= i; - while (i) { + while (i) + { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = ' '; --i; } - while (i >= 4) { + while (i >= 4) + { *(stbsp__uint32 *)bf = 0x20202020; bf += 4; i -= 4; } - while (i) { + while (i) + { *bf++ = ' '; --i; } @@ -1194,10 +1322,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy leader sn = lead + 1; - while (lead[0]) { + while (lead[0]) + { stbsp__cb_buf_clamp(i, lead[0]); lead[0] -= (char)i; - while (i) { + while (i) + { *bf++ = *sn++; --i; } @@ -1208,27 +1338,34 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, c = cs >> 24; cs &= 0xffffff; cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) { + while (pr > 0) + { stbsp__cb_buf_clamp(i, pr); pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) { - while (i) { + if ((fl & STBSP__TRIPLET_COMMA) == 0) + { + while (i) + { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = '0'; --i; } - while (i >= 4) { + while (i >= 4) + { *(stbsp__uint32 *)bf = 0x30303030; bf += 4; i -= 4; } } - while (i) { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + while (i) + { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) + { cs = 0; *bf++ = stbsp__comma; - } else + } + else *bf++ = '0'; --i; } @@ -1238,11 +1375,13 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy leader if there is still one sn = lead + 1; - while (lead[0]) { + while (lead[0]) + { stbsp__int32 i; stbsp__cb_buf_clamp(i, lead[0]); lead[0] -= (char)i; - while (i) { + while (i) + { *bf++ = *sn++; --i; } @@ -1251,7 +1390,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy the string n = l; - while (n) { + while (n) + { stbsp__int32 i; stbsp__cb_buf_clamp(i, n); n -= i; @@ -1261,7 +1401,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s += 4; i -= 4; }) - while (i) { + while (i) + { *bf++ = *s++; --i; } @@ -1269,22 +1410,26 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, } // copy trailing zeros - while (tz) { + while (tz) + { stbsp__int32 i; stbsp__cb_buf_clamp(i, tz); tz -= i; - while (i) { + while (i) + { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = '0'; --i; } - while (i >= 4) { + while (i >= 4) + { *(stbsp__uint32 *)bf = 0x30303030; bf += 4; i -= 4; } - while (i) { + while (i) + { *bf++ = '0'; --i; } @@ -1293,11 +1438,13 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy tail if there is one sn = tail + 1; - while (tail[0]) { + while (tail[0]) + { stbsp__int32 i; stbsp__cb_buf_clamp(i, tail[0]); tail[0] -= (char)i; - while (i) { + while (i) + { *bf++ = *sn++; --i; } @@ -1306,18 +1453,22 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // handle the left justify if (fl & STBSP__LEFTJUST) - if (fw > 0) { - while (fw) { + if (fw > 0) + { + while (fw) + { stbsp__int32 i; stbsp__cb_buf_clamp(i, fw); fw -= i; - while (i) { + while (i) + { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = ' '; --i; } - while (i >= 4) { + while (i >= 4) + { *(stbsp__uint32 *)bf = 0x20202020; bf += 4; i -= 4; @@ -1383,7 +1534,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, . return result; } -typedef struct stbsp__context { +typedef struct stbsp__context +{ char *buf; int count; int length; @@ -1398,14 +1550,17 @@ static char *stbsp__clamp_callback(const char *buf, void *user, int len) if (len > c->count) len = c->count; - if (len) { - if (buf != c->buf) { + if (len) + { + if (buf != c->buf) + { const char *s, *se; char *d; d = c->buf; s = buf; se = buf + len; - do { + do + { *d++ = *s++; } while (s < se); } @@ -1418,24 +1573,25 @@ static char *stbsp__clamp_callback(const char *buf, void *user, int len) return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can } -static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +static char *stbsp__count_clamp_callback(const char *buf, void *user, int len) { - stbsp__context * c = (stbsp__context*)user; - (void) sizeof(buf); + stbsp__context *c = (stbsp__context *)user; + (void)sizeof(buf); c->length += len; return c->tmp; // go direct into buffer if you can } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, size_t count, char const *fmt, va_list va) { stbsp__context c; - if ( (count == 0) && !buf ) + if ((count == 0) && !buf) { c.length = 0; - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + STB_SPRINTF_DECORATE(vsprintfcb) + (stbsp__count_clamp_callback, &c, c.tmp, fmt, va); } else { @@ -1445,11 +1601,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, c c.count = count; c.length = 0; - STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + STB_SPRINTF_DECORATE(vsprintfcb) + (stbsp__clamp_callback, &c, stbsp__clamp_callback(0, &c, 0), fmt, va); // zero-terminate - l = (int)( c.buf - buf ); - if ( l >= count ) // should never be greater, only equal (or less) than count + l = (int)(c.buf - buf); + if (l >= count) // should never be greater, only equal (or less) than count l = count - 1; buf[l] = 0; } @@ -1457,7 +1614,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, c return c.length; } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, size_t count, char const *fmt, ...) { int result; va_list va; @@ -1501,98 +1658,89 @@ static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, *bits = b & ((((stbsp__uint64)1) << 52) - 1); *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - return (stbsp__int32)((stbsp__uint64) b >> 63); + return (stbsp__int32)((stbsp__uint64)b >> 63); } static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 -}; + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022}; static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 -}; + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022}; static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 -}; + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039}; static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 -}; + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299}; static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 -}; + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299}; static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282 -}; + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282}; static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317 -}; + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317}; #if defined(_MSC_VER) && (_MSC_VER <= 1200) static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U -}; + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U}; #define stbsp__tento19th ((stbsp__uint64)1000000000000000000) #else static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL -}; + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL}; #define stbsp__tento19th (1000000000000000000ULL) #endif @@ -1638,9 +1786,12 @@ static stbsp__uint64 const stbsp__powten[20] = { static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 { double ph, pl; - if ((power >= 0) && (power <= 22)) { + if ((power >= 0) && (power <= 22)) + { stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } else { + } + else + { stbsp__int32 e, et, eb; double p2h, p2l; @@ -1654,13 +1805,16 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i ph = d; pl = 0.0; - if (power < 0) { - if (eb) { + if (power < 0) + { + if (eb) + { --eb; stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); } - if (et) { + if (et) + { stbsp__ddrenorm(ph, pl); --et; stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); @@ -1668,14 +1822,18 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i ph = p2h; pl = p2l; } - } else { - if (eb) { + } + else + { + if (eb) + { e = eb; if (eb > 22) eb = 22; e -= eb; stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) { + if (e) + { stbsp__ddrenorm(ph, pl); stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); @@ -1683,7 +1841,8 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i pl = p2l; } } - if (et) { + if (et) + { stbsp__ddrenorm(ph, pl); --et; stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); @@ -1711,7 +1870,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c d = value; STBSP__COPYFP(bits, d); expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + ng = (stbsp__int32)((stbsp__uint64)bits >> 63); if (ng) d = -d; @@ -1725,7 +1884,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c if (expo == 0) // is zero or denormal { - if (((stbsp__uint64) bits << 1) == 0) // do zero + if (((stbsp__uint64)bits << 1) == 0) // do zero { *decimal_pos = 1; *start = out; @@ -1736,7 +1895,8 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // find the right expo for denormals { stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) { + while ((bits & v) == 0) + { --expo; v >>= 1; } @@ -1764,16 +1924,19 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // now do the rounding in integer land frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) { + if ((frac_digits < 24)) + { stbsp__uint32 dg = 1; if ((stbsp__uint64)bits >= stbsp__powten[9]) dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + while ((stbsp__uint64)bits >= stbsp__powten[dg]) + { ++dg; if (dg == 20) goto noround; } - if (frac_digits < dg) { + if (frac_digits < dg) + { stbsp__uint64 r; // add 0.5 at the right position and round e = dg - frac_digits; @@ -1789,9 +1952,11 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c } // kill long trailing runs of zeros - if (bits) { + if (bits) + { stbsp__uint32 n; - for (;;) { + for (;;) + { if (bits <= 0xffffffff) break; if (bits % 1000) @@ -1808,31 +1973,39 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // convert to string out += 64; e = 0; - for (;;) { + for (;;) + { stbsp__uint32 n; char *o = out - 8; // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) { + if (bits >= 100000000) + { n = (stbsp__uint32)(bits % 100000000); bits /= 100000000; - } else { + } + else + { n = (stbsp__uint32)bits; bits = 0; } - while (n) { + while (n) + { out -= 2; *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; n /= 100; e += 2; } - if (bits == 0) { - if ((e) && (out[0] == '0')) { + if (bits == 0) + { + if ((e) && (out[0] == '0')) + { ++out; --e; } break; } - while (out != o) { + while (out != o) + { *--out = '0'; ++e; } diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 0000000..c96511b --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,742 @@ +#ifndef INC_STDIO +#define INC_STDIO + +#ifndef NO_STDIO_INCLUDE + +// IMPORTED FNS +#define SIMPLE_PRINT +void _print_string(const char *); + +// DEFINES +#include +#include +#include +#define BUFSIZ 512 +#define EOF (-1) +#define FILENAME_MAX 128 +#define FOPEN_MAX 16 +#define L_tmpnam 0 +#define TMP_MAX 0 + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +#define SEEK_CUR 0 +#define SEEK_END 1 +#define SEEK_SET 2 + +// DECLARATIONS +typedef struct FILE FILE; +typedef size_t fpos_t; + +// STRING PRINT +#define STB_SPRINTF_DECORATE(name) name +#include "stb_sprintf.h" +#undef STB_SPRINTF_DECORATE + +// PRINT +int fprintf(FILE *, const char *, ...); +int printf(const char *, ...); +int vfprintf(FILE *, const char *, va_list); +int vprintf(const char *, va_list); + +// SCAN +int fscanf(FILE *, const char *, ...); +int scanf(const char *, ...); +int vfscanf(FILE *, const char *, va_list); +int vscanf(const char *, va_list); +int sscanf(const char *, const char *, ...); +int vsscanf(const char *, const char *, va_list); + +// OPEN/CLOSE +int remove(const char *filename); +int rename(const char *oldname, const char *newname); +FILE *tmpfile(void); +char *tmpnam(char *); +FILE *fopen(const char *name, const char *mode); +FILE *freopen(const char *name, const char *mode, FILE *stream); +int fclose(FILE *stream); + +// BUFFER FNS +int fflush(FILE *stream); +void setbuf(FILE *stream, char *buffer); +void setvbuf(FILE *stream, char *buffer, int mode, size_t size); + +// CHARACTER INPUT/OUTPUT +int fgetc(FILE *stream); +char *fgets(char *str, int max_size, FILE *stream); +int fputc(int character, FILE *stream); +int fputs(const char *str, FILE *stream); +int getc(FILE *stream); +int getchar(); +char *gets(char *str); +int putc(int character, FILE *stream); +int putchar(int character); +int puts(const char *str, FILE *stream); +int ungetc(int character, FILE *stream); + +// DIRECT INPUT/OUTPUT +size_t fread(void *buffer, size_t size, size_t count, FILE *stream); +size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream); + +// FILE POSITIONING +int fgetpos(FILE *stream, fpos_t *pos); +int fseek(FILE *stream, long int offset, int origin); +int fsetpos(FILE *stream, const fpos_t *pos); +long int ftell(FILE *stream); +void rewind(FILE *stream); + +// ERROR HANDLING +void clearerr(FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +void perror(const char *buf); + +#endif + +#define STDIO_IMPL +#ifdef STDIO_IMPL + +#include +#include +#include +#include +#include +#include +#include +#include + +// TYPES + +// if file is not stdout or stderr buf is assumed to contain the whole file +struct FILE +{ + bool used; + bool error; + bool eof; + + bool ready; // true: files was fetched or is std stream + bool is_writable; + bool is_readable; + + size_t buf_index; + char *buf; + size_t buf_size; + unsigned char mode; + bool own_buf; +}; + +bool __files_were_init = false; +FILE __files[FOPEN_MAX]; + +// STD FILES +FILE __stderr__hold; +bool __stderr_was_init = false; +FILE *stderr = &__stderr__hold; + +FILE __stdout__hold; +bool __stdout_was_init = false; +FILE *stdout = &__stdout__hold; + +FILE __stdin__hold; +bool __stdin_was_init = false; +FILE *stdin = &__stdin__hold; + +// BASE FNS +FILE *_init_file(FILE *init) +{ + init->used = true; + init->error = false; + init->eof = false; + + init->ready = false; + init->is_writable = false; + init->is_readable = false; + + init->buf_index = 0; + init->buf = (char *)malloc(BUFSIZ + 1); + init->buf_size = BUFSIZ; + init->mode = _IOFBF; + init->own_buf = true; + + return init; +} +FILE *_create_file() +{ + if (!__files_were_init) + { + for (size_t i = 0; i < FOPEN_MAX; i++) + { + __files[i].used = false; + } + __files_were_init = true; + } + + // Find first free file + size_t found_free = 0; + while (__files[found_free].used && found_free < FOPEN_MAX) + { + found_free++; + } + + if (found_free >= FOPEN_MAX) + { + // Reached max possible file count + return NULL; + } + + return _init_file(__files + found_free); +} +void _init_std_file(FILE *stream) +{ + if (stream == stderr && !__stderr_was_init) + { + _init_file(stream); + __stderr_was_init = true; + stream->ready = true; + stream->is_writable = true; + } + else if (stream == stdout && !__stdout_was_init) + { + _init_file(stream); + __stdout_was_init = true; + stream->ready = true; + stream->is_writable = true; + } + else if (stream == stdin && !__stdin_was_init) + { + _init_file(stream); + __stdin_was_init = true; + stream->ready = true; + } +} +void _set_file_ready(FILE *stream) +{ + stream->ready = true; +} + +// STRING PRINT +#define STB_SPRINTF_IMPLEMENTATION +#define STB_SPRINTF_DECORATE(name) name +#include "stb_sprintf.h" + +// PRINT +char __print_buf[BUFSIZ * 8]; // good enough for everyone ? +int fprintf(FILE *stream, const char *format, ...) +{ + va_list argptr; + va_start(argptr, format); + int res = vsprintf(__print_buf, format, argptr); + va_end(argptr); + + fputs(__print_buf, stream); + + return res; +} +int printf(const char *format, ...) +{ + va_list argptr; + va_start(argptr, format); + int res = vprintf(format, argptr); + va_end(argptr); + + return res; +} +int vfprintf(FILE *stream, const char *format, va_list list) +{ + int res = vsprintf(__print_buf, format, list); + va_end(list); // ? + + fputs(__print_buf, stream); + + return res; +} +int vprintf(const char *format, va_list list) +{ + return vfprintf(stdout, format, list); +} + +// SCAN +int fscanf(FILE *stream, const char *format, ...) +{ + printf("scanf is not implemented"); + return -1; +} +int scanf(const char *format, ...) +{ + printf("scanf is not implemented"); + return -1; +} +int vfscanf(FILE *stream, const char *format, va_list args) +{ + printf("scanf is not implemented"); + return -1; +} +int vscanf(const char *format, va_list args) +{ + printf("scanf is not implemented"); + return -1; +} +int sscanf(const char *src, const char *format, ...) +{ + printf("scanf is not implemented"); + return -1; +} +int vsscanf(const char *src, const char *format, va_list args) +{ + printf("scanf is not implemented"); + return -1; +} + +// OPEN/CLOSE +int remove(const char *filename) +{ + printf("ERROR: Cannot Remove files on server"); + return 0; +} +int rename(const char *oldname, const char *newname) +{ + printf("ERROR: Cannot Rename files on server"); + return 0; +} +FILE *tmpfile(void) +{ + printf("ERROR: Cannot Create a files on server"); + return 0; +} +char *tmpnam(char *filename_buf) +{ + printf("ERROR: Creating temporary filename is not implemented"); + return NULL; +} +size_t open_files_count = 0; +FILE *_append_fetch_promise(const char *name, FILE *optional_file); +FILE *fopen(const char *name, const char *mode) +{ + if (open_files_count >= FOPEN_MAX) + { + // MAX FILES OPEN NUMBER REACHED + return NULL; + } + else if (strcmp(mode, "rb") != 0) + { + printf("ERROR: Only supports mode 'rb'"); + return NULL; + } + + FILE *f = _append_fetch_promise(name, NULL); + f->is_readable = true; + return f; +} +FILE *freopen(const char *name, const char *mode, FILE *stream) +{ + _init_std_file(stream); + + if (strcmp(mode, "rb") != 0) + { + printf("ERROR: Only supports mode 'rb'"); + return NULL; + } + + _init_file(stream); + + FILE *f = _append_fetch_promise(name, stream); + f->is_readable = true; + return f; +} +int fclose(FILE *stream) +{ + _init_std_file(stream); + + fflush(stream); + stream->used = false; + stream->ready = false; + + if (stream->own_buf) + { + free(stream->buf); + } + + if (stream == stderr) + { + stderr = NULL; + } + else if (stream == stdout) + { + stdout = NULL; + } + else if (stream == stdin) + { + stdin = NULL; + } + + return 0; +} + +// BUFFER FNS +int fflush(FILE *stream) +{ + _init_std_file(stream); + + if (stream == NULL) + { + // FLUSH ALL streams with output + fflush(stderr); + fflush(stdout); + + // flush others + } + else + { + stream->buf[stream->buf_index] = '\0'; + _print_string(stream->buf); + stream->buf_index = 0; + } + + return 0; +} +void setbuf(FILE *stream, char *buffer) +{ + _init_std_file(stream); + + free(stream->buf); + stream->buf_size = BUFSIZ; + stream->buf = buffer; + stream->own_buf = false; +} +void setvbuf(FILE *stream, char *buffer, int mode, size_t size) +{ + _init_std_file(stream); + + if (stream->own_buf) + { + free(stream->buf); + } + + switch (mode) + { + case _IOFBF: + case _IOLBF: + case _IONBF: + stream->mode = mode; + break; + + default: + assert(0 && "Unknown mode given"); + return; + } + + if (buffer == NULL) + { + stream->buf = (char *)malloc(size + 1); + stream->own_buf = true; + } + else + { + stream->buf = buffer; + stream->own_buf = false; + } + stream->buf_size = size; +} + +// CHARACTER INPUT/OUTPUT +int fgetc(FILE *stream) +{ + _init_std_file(stream); + + if (stream == stderr || stream == stdout) + { + // Cannot read from stderr or stdout + stream->eof = true; + return EOF; + } + else if (stream == stdin) + { + // How read from stdin? + return EOF; + } + else if (stream->is_readable == true) + { + if (stream->buf_index < stream->buf_size) + { + return stream->buf[stream->buf_index++]; + } + else + { + stream->eof = true; + return EOF; + } + } + + return EOF; +} +char *fgets(char *str, int max_size, FILE *stream) +{ + if (max_size > 0) + { + size_t i = 0; + int c = fgetc(stream); + while (c != EOF && c != '\n' && i < max_size) + { + str[i++] = c; + c = fgetc(stream); + } + str[i] = '\0'; + } + + return str; +} +int fputc(int character, FILE *stream) +{ + _init_std_file(stream); + + if (stream->is_writable) + { + if (stream->buf_index >= stream->buf_size) + { + fflush(stream); + } + + stream->buf[stream->buf_index++] = (char)character; + + if (character == '\n') + { + fflush(stream); + } + + return character; + } + else + { + printf("ERROR: Cannot put char in read only stream"); + return EOF; + } +} +int fputs(const char *str, FILE *stream) +{ + const size_t len_str = strlen(str); + + for (size_t i = 0; i < len_str; i++) + { + if (fputc(str[i], stream) == EOF) + { + return EOF; + } + } + + return 0; +} +int getc(FILE *stream) +{ + return fgetc(stream); +} +int getchar() +{ + return getc(stdin); +} +char *gets(char *str) +{ + return fgets(str, INT_MAX, stdin); +} +int putc(int character, FILE *stream) +{ + return fputc(character, stream); +} +int putchar(int character) +{ + return fputc(character, stdout); +} +int puts(const char *str, FILE *stream) +{ + return fputs(str, stream); +} +int ungetc(int character, FILE *stream) +{ + printf("ERROR: ungetc not supported"); + return EOF; +} + +// DIRECT INPUT/OUTPUT +size_t fread(void *buffer, size_t size, size_t count, FILE *stream) +{ + unsigned char *buf = (unsigned char *)buffer; + + if (size == 0 || count == 0) + return 0; + + for (size_t i = 0; i < count; i++) + { + for (size_t j = 0; i < size; j++) + { + int res = fgetc(stream); + + if (res == EOF) + return i; + + buf[i + j] = (unsigned char)res; + } + } + + return count; +} +size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream) +{ + unsigned char *buf = (unsigned char *)buffer; + + if (size == 0 || count == 0) + return 0; + + for (size_t i = 0; i < count; i++) + { + for (size_t j = 0; i < size; j++) + { + int res = fputc((int)buf[i + j], stream); + + if (res == EOF) + return i; + } + } + + return count; +} + +// FILE POSITIONING +int fgetpos(FILE *stream, fpos_t *pos) +{ + _init_std_file(stream); + + if (stream->is_readable) + { + const long res = ftell(stream); + if (res >= 0) + { + *pos = res; + return 0; + } + return res; + } + else + { + printf("ERROR: fgetpos is not implemented for writable files"); + return -1; + } +} +int fseek(FILE *stream, long int offset, int origin) +{ + _init_std_file(stream); + + if (stream->is_readable) + { + switch (origin) + { + case SEEK_CUR: + { + if (stream->buf_index + offset > 0 && stream->buf_index + offset < stream->buf_size) + { + stream->buf_index += offset; + } + else + { + return EOF; + } + } + break; + + case SEEK_SET: + { + if (offset > 0 && offset < stream->buf_size) + { + stream->buf_index = offset; + } + else + { + return EOF; + } + } + break; + + case SEEK_END: + return EOF; + + default: + break; + } + return 0; + } + else + { + printf("ERROR: fseek is not implemented for writable files"); + return -1L; + } +} +int fsetpos(FILE *stream, const fpos_t *pos) +{ + _init_std_file(stream); + + if (stream->is_readable) + { + return fseek(stream, *pos, SEEK_SET); + } + else + { + printf("ERROR: fsetpos is not implemented for writable files"); + return -1; + } +} +long int ftell(FILE *stream) +{ + _init_std_file(stream); + + if (stream->is_readable) + { + return stream->buf_index; + } + else + { + printf("ERROR: ftell is not implemented for writable files"); + return -1L; + } +} +void rewind(FILE *stream) +{ + _init_std_file(stream); + + stream->eof = false; + stream->error = false; + + if (stream->is_readable) + { + stream->buf_index = 0; + } + else + { + printf("ERROR: rewind is not implemented for writable files"); + } +} + +// ERROR HANDLING +void clearerr(FILE *stream) +{ + stream->eof = false; + stream->error = false; +} +int feof(FILE *stream) +{ + return stream->eof; +} +int ferror(FILE *stream) +{ + return stream->error; +} +void perror(const char *buf) +{ + if (buf != NULL) + { + fprintf(stderr, "%s: ", buf); + } + fprintf(stderr, "%s\n", strerror(errno)); +} + +#endif +#endif \ No newline at end of file diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 0000000..5ec528f --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,485 @@ +#ifndef _INC_STDLIB +#define _INC_STDLIB + +#include +#include +#include + +#ifndef NO_STDLIB_INCLUDE + +// DEFINES +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 +#define MB_CUR_MAX 4 +#define RAND_MAX 2147483647 + +// #define SIMPLE_PRINT +#ifdef SIMPLE_PRINT +void _print_string(const char *); +#endif + +// DECLARATIONS + +// STRING TO NUMBER +double atof(const char *); +int atoi(const char *); +long atol(const char *); +long long atoll(const char *); + +double strtod(const char *, char **); +float strtof(const char *, char **); +long double strtold(const char *, char **); +long strtol(const char *, char **, int); +long long strtoll(const char *, char **, int); +unsigned long strtoul(const char *, char **, int); +unsigned long long strtoull(const char *, char **, int); + +// RANDOM +int rand(void); +void srand(unsigned int); + +// MEMORY +void *malloc(size_t byte_count); +void *calloc(size_t size, size_t element_size); +void free(void *ptr); +void *realloc(void *ptr, size_t new_byte_count); + +// ENVIRONMENT +void abort(void); +void exit(int status); +void quick_exit(int); +int atexit(void (*)(void)); +int at_quick_exit(void (*)(void)); + +// ALGORITHMS +void *bsearch(const void *key, const void *base, size_t num, size_t size, int (*compar)(const void *, const void *)); +void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)); + +// INTEGER ARITHMETICS +int abs(int); +long labs(long); +long long llabs(long long); + +typedef struct div_t div_t; +typedef struct ldiv_t ldiv_t; +typedef struct lldiv_t lldiv_t; + +div_t div(int a, int b); +ldiv_t ldiv(long a, long b); +lldiv_t lldiv(long long a, long long b); + +// MULTIBYTE CHARACTERS +int mblen(const char *, size_t); +int mbtowc(wchar_t *, const char *, size_t); +int wctomb(char *, wchar_t); + +// MULTIBYTE STRING +size_t mbstowcs(wchar_t *dest, const char *src, size_t max); +size_t wcstombs(char *dest, const wchar_t *src, size_t max); + +#endif + +// IMPLEMENTATION +#ifdef STDLIB_IMPL + +// MEMORY ALLOCATOR +#define MAX_PAGE_COUNT 16 +#define PAGE_SIZE (64 * 1024) + +#define BLOCKS_PER_PAGE 32 +#define MAX_BLOCK_COUNT (MAX_PAGE_COUNT * BLOCKS_PER_PAGE) +#define DEFAULT_SIZE_OF_BLOCK (PAGE_SIZE / BLOCKS_PER_PAGE) + +#define BLOCK_NUM_IN_PTR_TYPE size_t +#define BLOCK_NUM_IN_PTR_SIZE sizeof(BLOCK_NUM_IN_PTR_TYPE) + +unsigned char *_heap_start(); +unsigned char *_grow_memory(unsigned size); + +unsigned __page_block_count[MAX_PAGE_COUNT]; +size_t __used_page_count = 0; +unsigned char *__last_page_start = 0; +unsigned char *__last_page_end = 0; + +size_t __used_block_start = 0; +size_t __block_size[MAX_BLOCK_COUNT]; +unsigned char *__block_start[MAX_BLOCK_COUNT]; +size_t __block_page_i[MAX_BLOCK_COUNT]; +bool __block_used[MAX_BLOCK_COUNT]; + +size_t _next_unused_block(size_t start) +{ + for (unsigned i = start; i < MAX_BLOCK_COUNT; i++) + { + if (!__block_used[i]) + return i; + } + + return MAX_BLOCK_COUNT; +} +void _add_pages_for(size_t byte_count) +{ + unsigned page_count; + unsigned char *page_start; + size_t pages_size; + + if (__used_page_count == 0) + { + page_start = _heap_start(); + const size_t heap_start_num = (size_t)page_start; + const size_t page_size_left = PAGE_SIZE - (heap_start_num % PAGE_SIZE); + page_count = page_size_left < byte_count ? ceil((double)(byte_count - page_size_left) / PAGE_SIZE) : 0; + if (page_count != 0) + { + _grow_memory(page_count); + } + pages_size = page_size_left + page_count * PAGE_SIZE; + page_count++; + } + else + { + page_count = ceil((double)byte_count / PAGE_SIZE); + page_start = _grow_memory(page_count); + pages_size = page_count * PAGE_SIZE; + } + + for (unsigned i = 0; i < page_count * BLOCKS_PER_PAGE; i++) + { + __block_start[__used_block_start + i] = page_start + i * DEFAULT_SIZE_OF_BLOCK; + __block_size[__used_block_start + i] = DEFAULT_SIZE_OF_BLOCK; + __block_page_i[__used_block_start + i] = i / BLOCKS_PER_PAGE; + __block_used[__used_page_count + i] = false; + } + __used_block_start += page_count * BLOCKS_PER_PAGE; + + for (unsigned i = 0; i < page_count; i++) + { + __page_block_count[__used_page_count + i] = BLOCKS_PER_PAGE; + } + __used_page_count += page_count; + + __last_page_start = page_start; + __last_page_end = page_start + pages_size; +} +size_t _find_block(size_t start, size_t byte_count, long long end) +{ + // end == -1 : do not add new page & just end with return MAX_BLOCK_COUNT + // end <= -2 : use default end of MAX_BLOCK_COUNT + size_t MAX = end > MAX_BLOCK_COUNT ? end : MAX_BLOCK_COUNT; + + size_t unused = _next_unused_block(start); + if (unused >= MAX) + { + if (end != -1) + { + _add_pages_for(byte_count); + unused = _next_unused_block(start); + } + } + while (unused < MAX) + { + unsigned int bs = __block_size[unused]; + + // block does not fit + if (bs < byte_count) + { + // Try to create block with large enough size + unsigned size = bs; + unsigned i = 1; + while (!__block_used[unused + i] && unused + i < MAX && size < byte_count) + { + size += __block_size[unused + i]; + i++; + } + + if (size >= byte_count) + { + __block_size[unused] = size; + + for (unsigned j = 1; j < i; j++) + { + __block_size[unused + j] = 0; + __block_start[unused + j] = 0; + __page_block_count[__block_page_i[unused + j]]--; + } + bs = size; + } + } + + // Found fitting block || new blocks were added + if (bs >= byte_count) + { + if (unused > 0 && !__block_used[unused - 1] && __block_size[unused - 1] == 0) // block unused & not assigned + { + unsigned split_i = unused - 1; + __block_start[split_i] = __block_start[unused]; + __block_size[split_i] = byte_count; + __block_used[split_i] = true; + + __block_start[unused] += byte_count; + __block_size[unused] -= byte_count; + + return split_i; + } + else if (unused + 1 < MAX && !__block_used[unused + 1] && __block_size[unused + 1] == 0) + { + unsigned split_i = unused + 1; + __block_start[split_i] = __block_start[unused] + byte_count; + __block_size[split_i] = __block_size[unused]; + + __block_size[unused] = byte_count; + + return unused; + } + return unused; // cannot split blocks + } + + unused = _next_unused_block(start); + if (unused >= MAX) + { + if (end != -1) + { + _add_pages_for(byte_count); + unused = _next_unused_block(start); + } + } + } + + return MAX_BLOCK_COUNT; +} + +void *malloc(size_t byte_count) +{ + if (__used_page_count == 0) + { + _add_pages_for(byte_count); + } + + size_t block = _find_block(0, byte_count + BLOCK_NUM_IN_PTR_SIZE, -2); + + if (block < MAX_BLOCK_COUNT) + { + // Store block number at start + ((BLOCK_NUM_IN_PTR_TYPE *)(__block_start[block]))[0] = block; + __block_used[block] = true; + return __block_start[block] + BLOCK_NUM_IN_PTR_SIZE; // give ptr to 4 byte after start (after block num) + } + else + { + return (void *)0; + } +} +void *calloc(size_t size, size_t element_size) +{ + return malloc(size * element_size); +} +void free(void *ptr) +{ + unsigned block = ((unsigned *)ptr)[-1]; // get block number from before ptr + + if (0 <= block && block < MAX_BLOCK_COUNT) + { + if (__block_start[block] == (unsigned char *)ptr - 4) + { + __block_used[block] = false; + } + else + { +#ifdef SIMPLE_PRINT + _print_string("ERROR: Segmentation fault: Invalid ptr given to free"); +#endif + } + } + else + { +#ifdef SIMPLE_PRINT + _print_string("ERROR: Index out of bounds: Invalid ptr given to free"); +#endif + } +} + +void *memcpy(void *, const void *, size_t); +void *memmove(void *, const void *, size_t); + +void *realloc(void *ptr, size_t new_byte_count) +{ + if (ptr == NULL) + { + return malloc(new_byte_count); + } + + unsigned block = ((unsigned *)ptr)[-1]; // get block number from before ptr + + if (0 <= block && block < MAX_BLOCK_COUNT) + { + if (__block_start[block] != (unsigned char *)ptr - 4) + { +#ifdef SIMPLE_PRINT + _print_string("ERROR: Segmentation fault: Invalid ptr given to realloc"); +#endif + return (void *)0; + } + } + else + { +#ifdef SIMPLE_PRINT + _print_string("ERROR: Index out of bounds: Invalid ptr given to realloc"); +#endif + return (void *)0; + } + + size_t old___block_size = __block_size[block]; + unsigned char *old___block_start = __block_start[block]; + + if (__block_size[block] < new_byte_count + BLOCK_NUM_IN_PTR_SIZE) + { + __block_used[block] = false; // mark temporary as unused + + size_t new_block = _find_block(block, new_byte_count + BLOCK_NUM_IN_PTR_SIZE, -1); + if (new_block >= MAX_BLOCK_COUNT) + { + new_block = _find_block(0, new_byte_count + BLOCK_NUM_IN_PTR_SIZE, block); + } + if (new_block >= MAX_BLOCK_COUNT) + { + new_block = _find_block(block, new_byte_count + BLOCK_NUM_IN_PTR_SIZE, -2); + } + + if (block < new_block || (block > new_block && __block_size[block] != 0)) + { + // block is before new block + // or old block was after but was not overwritten + memcpy(__block_start[new_block], old___block_start, old___block_size); + __block_used[new_block] = true; + ((BLOCK_NUM_IN_PTR_TYPE *)(__block_start[block]))[0] = new_block; + return __block_start[new_block] + BLOCK_NUM_IN_PTR_SIZE; + } + else if (block > new_block) + { + // old block is in new block + memmove(__block_start[new_block], old___block_start, old___block_size); + __block_used[new_block] = true; + ((BLOCK_NUM_IN_PTR_TYPE *)(__block_start[block]))[0] = new_block; + return __block_start[new_block] + BLOCK_NUM_IN_PTR_SIZE; + } + else // == + { + __block_used[block] = true; + return __block_start[block] + BLOCK_NUM_IN_PTR_SIZE; + } + } + else if (__block_size[block] > new_byte_count + BLOCK_NUM_IN_PTR_SIZE) + { + return __block_start[block] + BLOCK_NUM_IN_PTR_SIZE; + } + else + { + return __block_start[block] + BLOCK_NUM_IN_PTR_SIZE; + } +} + +// ALGORITHMS +// https://cplusplus.com/reference/cstdlib/bsearch/ +void *bsearch(const void *key, const void *base, size_t num, size_t size, int (*compar)(const void *, const void *)) +{ + size_t start = 0; + size_t end = num; + size_t middle = num / 2; + const unsigned char *ptr = (const unsigned char *)base + (middle * size); + int cmp = compar(key, ptr); + while (cmp != 0) + { + if (cmp < 0) + { + end = middle - 1; + } + else + { + start = middle + 1; + } + + middle = start + (end - start) / 2; + ptr = (const unsigned char *)base + (middle * size); + cmp = compar(key, ptr); + } + + return (void *)ptr; +} +// https://cplusplus.com/reference/cstdlib/qsort/ +void qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)) +{ + unsigned char *tmp = (unsigned char *)malloc(size); + unsigned char *base_c = (unsigned char *)base; + + for (size_t i = 1; i < num; i++) + { + size_t j = 0; + + // while want to insert is larger + int cmp = compar(base_c + i * size, base_c + j * size); + while (cmp >= 0) + { + j++; + cmp = compar(base_c + i * size, base_c + j * size); + } + + // swap + for (size_t k = 0; k < size; k++) + { + tmp[k] = base_c[i + k]; + base_c[i + k] = base_c[j + k]; + base_c[j + k] = tmp[k]; + } + break; + } + + free(tmp); +} + +// INTEGER ARITHMETICS +struct div_t +{ + int quot; + int rem; +}; +struct ldiv_t +{ + long quot; + long rem; +}; +struct lldiv_t +{ + long long quot; + long long rem; +}; + +struct div_t div(int a, int b) +{ + const int quot = a / b; + const int rem = a - (quot * b); + struct div_t res; + res.quot = quot; + res.rem = rem; + return res; +}; +struct ldiv_t ldiv(long a, long b) +{ + const long quot = a / b; + const long rem = a - (quot * b); + struct ldiv_t res; + res.quot = quot; + res.rem = rem; + return res; +} +struct lldiv_t lldiv(long long a, long long b) +{ + const long long quot = a / b; + const long long rem = a - (quot * b); + struct lldiv_t res; + res.quot = quot; + res.rem = rem; + return res; +} + +#endif +#endif \ No newline at end of file diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 0000000..9360020 --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,549 @@ +#ifndef _INC_STRING +#define _INC_STRING + +#include +#include + +#ifndef NO_STRING_INCLUDE + +// DEFINES +#include + +#ifdef SIMPLE_PRINT +void _print_string(const char *); +#endif + +// INCLUDES + +// MEMORY +void *memchr(const void *ptr, int value, size_t num); +int memcmp(const void *ptr1, const void *ptr2, size_t num); +void *memcpy(void *dest, const void *src, size_t size); +void *memmove(void *dest, const void *src, size_t num); +void *memset(void *ptr, int value, size_t num); + +// STRING +size_t strlen(const char *str); +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); +char *strchr(const char *str, int character); +int strcmp(const char *str1, const char *str2); +int strcoll(const char *str1, const char *str2); +size_t strcspn(const char *str1, const char *str2); +char *strerror(int errnum); +char *strncat(char *dest, const char *src, size_t num); +int strncmp(const char *str1, const char *str2, size_t num); +char *strncpy(char *dest, const char *src, size_t num); +char *strpbrk(const char *str1, const char *str2); +char *strrchr(const char *str, int character); +size_t strspn(const char *str1, const char *str2); +char *strstr(const char *str1, const char *str2); +char *strtok(char *str, const char *delimiters); +size_t strxfrm(char *dest, const char *src, size_t num); + +#endif + +// IMPLEMENTATIONS +#ifdef STRING_IMPL + +// MEMORY +void *memchr(const void *ptr, int value, size_t num) +{ + unsigned char *dest_cast = (unsigned char *)ptr; + for (size_t i = 0; i < num; i++) + { + if (dest_cast[i] == (unsigned char)value) + { + return (unsigned char *)ptr + i; + } + } + + return (void *)0; +} +int memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + unsigned char *ptr1_cast = (unsigned char *)ptr1; + unsigned char *ptr2_cast = (unsigned char *)ptr2; + for (size_t i = 0; i < num; i++) + { + if (ptr1_cast[i] < ptr2_cast[i]) + { + return -1; + } + else if (ptr1_cast[i] > ptr2_cast[i]) + { + return 1; + } + } + + return 0; +} +void *memcpy(void *dest, const void *src, size_t size) +{ + unsigned char div8_leftover = size % sizeof(unsigned long long); + unsigned long size64 = (size - div8_leftover) / sizeof(unsigned long long); + + unsigned long long *dest_cast_8 = (unsigned long long *)dest; + unsigned long long *src_cast_8 = (unsigned long long *)src; + for (size_t i = 0; i < size64; i++) + { + dest_cast_8[i] = src_cast_8[i]; + } + + unsigned char *dest_cast = (unsigned char *)dest; + unsigned char *src_cast = (unsigned char *)src; + for (unsigned char i = 0; i < div8_leftover; i++) + { + dest_cast[i] = src_cast[i]; + } + + return dest; +} +void *memmove(void *dest, const void *src, size_t num) +{ + unsigned char *src_buff = (unsigned char *)malloc(num); + memcpy(src_buff, (void *)src, num); + + unsigned char *dest_cast = (unsigned char *)dest; + for (unsigned char i = 0; i < num; i++) + { + dest_cast[i] = src_buff[i]; + } + + free(src_buff); + return dest; +} +void *memset(void *ptr, int value, size_t num) +{ + unsigned char *dest_cast = (unsigned char *)ptr; + for (size_t i = 0; i < num; i++) + { + dest_cast[i] = (unsigned char)value; + } + + return ptr; +} + +// STRING +size_t strlen(const char *str) +{ + size_t size = 0; + while (str[size] != '\0') + { + size++; + } + return size; +} +char *strcpy(char *dest, const char *src) +{ + size_t len_src = strlen(src); + memcpy(dest, (void *)src, len_src); + return dest; +} +char *strcat(char *dest, const char *src) +{ + size_t len_dest = strlen(dest); + strcpy(dest + len_dest, src); + return dest; +} +char *strchr(const char *str, int character) +{ + size_t len_str = strlen(str); + + if (character == '\0') + return (char *)str + len_str; + + return (char *)memchr((void *)str, character, len_str); +} +int strcmp(const char *str1, const char *str2) +{ + size_t len_str1 = strlen(str1); + size_t len_str2 = strlen(str2); + + size_t lower_len = len_str1 < len_str2 ? len_str1 : len_str2; + return memcmp((void *)str1, (void *)str2, lower_len); +} +int strcoll(const char *str1, const char *str2) +{ +// TODO: Implement with c locale +#ifdef SIMPLE_PRINT + _print_string("strcoll not yet implemented"); +#endif + return 0; +} +size_t strcspn(const char *str1, const char *str2) +{ + size_t len_str2 = strlen(str2); + + size_t index = 0; + while (str1[index] != 0) + { + char st1_char = str1[index]; + for (size_t i = 0; i < len_str2 + 1; i++) + { + if (st1_char == str2[i]) + { + return index; + } + } + } + + return strlen(str1); // unreachable but fallback? +} +char *strerror(int errnum) +{ + switch (errnum) + { + case EAFNOSUPPORT: + return (char *)"Address family is not supported"; + case EADDRINUSE: + return (char *)"Address already in use"; + case EADDRNOTAVAIL: + return (char *)"Address not available"; + case EISCONN: + return (char *)"Already connected"; + case E2BIG: + return (char *)"Argument list too long"; + case EDOM: + return (char *)"Argument out of domain"; + case EFAULT: + return (char *)"Bad Address"; + case EBADF: + return (char *)"Bad filter descriptor"; + case EBADMSG: + return (char *)"Bad message"; + case EPIPE: + return (char *)"Broken pipe"; + case ECONNABORTED: + return (char *)"Connection aborted"; + case EALREADY: + return (char *)"Connection already in progress"; + case ECONNREFUSED: + return (char *)"Connection refused"; + case ECONNRESET: + return (char *)"Connection reset"; + case EXDEV: + return (char *)"Cross device link"; + case EDESTADDRREQ: + return (char *)"Destination address required"; + case EBUSY: + return (char *)"Devicec or resource busy"; + case ENOTEMPTY: + return (char *)"Directory not empty"; + case ENOEXEC: + return (char *)"Executable format error"; + case EEXIST: + return (char *)"File already exists"; + case EFBIG: + return (char *)"File too large"; + case ENAMETOOLONG: + return (char *)"Filename too long"; + case ENOSYS: + return (char *)"Function not supported"; + case EHOSTUNREACH: + return (char *)"Host is unreachable"; + case EIDRM: + return (char *)"Identifier removed"; + case EILSEQ: + return (char *)"Illegal byte sequence"; + case ENOTTY: + return (char *)"Inappropriate IO control operation"; + case EINTR: + return (char *)"Interrupted"; + case EINVAL: + return (char *)"Invalid argument"; + case ESPIPE: + return (char *)"Invalid seek"; + case EIO: + return (char *)"IO error"; + case EISDIR: + return (char *)"Is a directory"; + case EMSGSIZE: + return (char *)"Message size"; + case ENETDOWN: + return (char *)"Network down"; + case ENETRESET: + return (char *)"Network reset"; + case ENETUNREACH: + return (char *)"Network unreachable"; + case ENOBUFS: + return (char *)"No buffer space"; + case ECHILD: + return (char *)"No child process"; + case ENOLINK: + return (char *)"No link"; + // case ENOLOCK: + // return (char *)"No lock available"; + case ENOMSG: + return (char *)"No message"; + case ENODATA: + return (char *)"No message available"; + case ENOPROTOOPT: + return (char *)"No protocol option"; + case ENOSPC: + return (char *)"No space on device"; + case ENOSR: + return (char *)"No stream resources"; + case ENODEV: + return (char *)"No such device"; + case ENXIO: + return (char *)"No such device or address"; + case ENOENT: + return (char *)"No such file or directory"; + case ESRCH: + return (char *)"No such proccess"; + case ENOTDIR: + return (char *)"Not a directory"; + case ENOTSOCK: + return (char *)"Not a socket"; + case ENOSTR: + return (char *)"Not a stream"; + case ENOTCONN: + return (char *)"Not connected"; + case ENOMEM: + return (char *)"Not enough memory"; + case ENOTSUP: + return (char *)"Not supported"; + case ECANCELED: + return (char *)"Operation canceled"; + case EINPROGRESS: + return (char *)"Operation in progress"; + case EPERM: + return (char *)"Operation was not permitted"; + case EOPNOTSUPP: + return (char *)"Operation not supported"; + case EWOULDBLOCK: + return (char *)"Operation would block"; + case EOWNERDEAD: + return (char *)"Owner dead"; + case EACCES: + return (char *)"Permission denied"; + case EPROTO: + return (char *)"Protocol error"; + case EPROTONOSUPPORT: + return (char *)"Protocol not supported"; + case EROFS: + return (char *)"Read only file system"; + case EDEADLK: + return (char *)"Resource deadlock would occur"; + case EAGAIN: + return (char *)"Resource unavailable try again"; + case ERANGE: + return (char *)"Result out of range"; + case ENOTRECOVERABLE: + return (char *)"State not recoverable"; + case ETIME: + return (char *)"Stream timeout"; + case ETXTBSY: + return (char *)"Text file busy"; + case ETIMEDOUT: + return (char *)"Timed out"; + case EMFILE: + return (char *)"Too many files open"; + case ENFILE: + return (char *)"Too many files open in system"; + case EMLINK: + return (char *)"Too many links"; + case ELOOP: + return (char *)"Too many symbolic link levels"; + case EOVERFLOW: + return (char *)"Value too large"; + case EPROTOTYPE: + return (char *)"Wrong protocol type"; + + default: + return (char *)"UNKNOWN ERROR CODE"; + } +} +char *strncat(char *dest, const char *src, size_t num) +{ + size_t len_dest = strlen(dest); + size_t len_src = strlen(src); + if (len_src > num) + { + len_src = num; + } + + memcpy(dest + len_dest, (void *)src, len_src); + dest[len_src] = '\0'; + + return dest; +} +int strncmp(const char *str1, const char *str2, size_t num) +{ + const size_t len_str1 = strlen(str1); + const size_t len_str2 = strlen(str2); + size_t len = len_str1 < len_str2 ? len_str1 : len_str2; + len = len < num ? len : num; + + return memcmp(str1, str2, len); +} +char *strncpy(char *dest, const char *src, size_t num) +{ + const size_t len_src = strlen(src); + const size_t len = len_src < num ? len_src : num; + + memcpy(dest, src, len); + + if (len_src < num) + { + memset(dest + len, 0, num - len_src); + } + + return dest; +} +char *strpbrk(const char *str1, const char *str2) +{ + const size_t len_str2 = strlen(str2); + + size_t i = 0; + while (str1[i] != '\0') + { + for (size_t j = 0; j < len_str2; j++) + { + if (str1[i] == str2[j]) + { + return (char *)(str1 + i); + } + } + i++; + } + + return (char *)NULL; +} +char *strrchr(const char *str, int character) +{ + if (character == 0) + { + return (char *)(str + strlen(str)); + } + else + { + size_t last_index = 0; + bool found = false; + + size_t i = 0; + while (str[i] != '\0') + { + if (str[i] == (char)character) + { + found = true; + last_index = i; + } + i++; + } + + if (found) + { + return (char *)(str + last_index); + } + } + + return (char *)NULL; +} +size_t strspn(const char *str1, const char *str2) +{ + const size_t len_str2 = strlen(str2); + + size_t i = 0; + while (str1[i] != '\0') + { + bool not_found = true; + for (size_t j = 0; j < len_str2; j++) + { + if (str1[i] == str2[j]) + { + not_found = false; + break; + } + } + + if (not_found) + { + return i; + } + i++; + } + + return i; +} +char *strstr(const char *str1, const char *str2) +{ + if (str2[0] == '\0') + { + return (char *)str1; + } + + const size_t len_str1 = strlen(str1); + const size_t len_str2 = strlen(str2); + + if (len_str2 > len_str1) + { + return (char *)NULL; + } + + for (size_t i = 0; i < len_str1 + 1 - len_str2; i++) + { + bool found = true; + for (size_t j = 0; j < len_str2; j++) + { + if (str1[i + j] != str2[j]) + { + found = false; + } + } + + if (found) + { + return (char *)(str1 + i); + } + } + + return (char *)NULL; +} +char *strtok(char *str, const char *delimiters) +{ + // As static or outside of fn? + static char *token_string_start = (char *)NULL; + static bool end_found = true; + + if (end_found) + { + return (char *)NULL; + } + + if (str != (char *)NULL) + { + token_string_start = str; + end_found = false; + } + + size_t span_with_delimiters = strspn(token_string_start, delimiters); + token_string_start += span_with_delimiters; + + char *first_occurrence = strpbrk(token_string_start, delimiters); + + if (first_occurrence != (char *)NULL) + { + first_occurrence[0] = '\0'; + return token_string_start; + } + else + { + token_string_start = (char *)NULL; + end_found = true; + return (char *)NULL; + } +} +size_t strxfrm(char *dest, const char *src, size_t num) +{ + if (num != 0 && dest != (char *)NULL) + { + // Transform src according to c locale (not mention how) + strncpy(dest, src, num); + } + return strlen(src); +} +#endif + +#endif \ No newline at end of file diff --git a/libc/include/time.h b/libc/include/time.h new file mode 100644 index 0000000..3f0e115 --- /dev/null +++ b/libc/include/time.h @@ -0,0 +1,437 @@ +#ifndef _INC_TIME +#define _INC_TIME + +#include + +#ifndef NO_TIME_INCLUDE + +#define CLOCKS_PER_SEC 1000 + +typedef unsigned int clock_t; +typedef unsigned int time_t; +typedef struct tm tm; + +// DECLARATIONS + +// TIME MANIPULATION +clock_t clock(); +time_t time(time_t *timer); +double difftime(time_t end, time_t start); +time_t mktime(tm *time_ptr); + +// CONVERSION +char *asctime(const tm *time_ptr); +char *ctime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +struct tm *localtime(const time_t *timer); +size_t strftime(char *ptr, size_t maxsize, const char *format, const struct tm *time_ptr); + +#endif + +// IMPLEMENTATION +#ifdef TIME_IMPL + +#include +#include + +#ifdef NO_TIME_INCLUDE +typedef unsigned int clock_t; +typedef unsigned int time_t; +#endif +struct tm +{ + int tm_sec; // seconds after the minute + int tm_min; // minutes after the hour + int tm_hour; // hours since midnight + int tm_mon; // months since january + int tm_year; // years since 1900 + int tm_wday; // days since sunday + int tm_mday; // day of the month + int tm_yday; // days since january 1 + int tm_isdst; // daylight saving flag +}; + +#define __FIRST_LEAP_YEAR_AFTER_START 2 // 1972 +#define __STARTING_WEEK_DAY 3 // 0: monday - 6: sunday (on 01.01.1970) + +// TIME MANIPULATION +double difftime(time_t end, time_t start) +{ + time_t diff = end - start; + return (double)diff / 1000.0; +} +time_t mktime(struct tm *time_ptr) +{ + const int ys1970 = time_ptr->tm_year - 70; // do this ? + // const int ys1970 = time_ptr->tm_year; + + time_t t = 0; + t += ys1970 * 356; + t += (__FIRST_LEAP_YEAR_AFTER_START + ys1970) / 4; + t *= 24; // go from days to hours + t += time_ptr->tm_hour + (time_ptr->tm_isdst > 0 ? 1 : 0); + t *= 60; // from hours to minutes + t += time_ptr->tm_min; + t *= 60; // from minutes to seconds + t += time_ptr->tm_sec; + t += 10; // 10 leap secs in ~1970 (cannot account for leap secs after) + + return t; +} + +static const char week_days[][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char week_days_long[][10] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; +static const char months[][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static const char months_long[][10] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; +static const unsigned char month_lengths[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +// CONVERSION +char *asctime(const struct tm *time_ptr) +{ + + static char str[3 + 1 + 3 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 4 + 1]; + + int res = sprintf(str, "%.3s %.3s %.2d %.2d:%.2d:%.2d %.4d\n%c", + week_days[time_ptr->tm_wday], + months[time_ptr->tm_mon], + time_ptr->tm_mon, + time_ptr->tm_hour + (time_ptr->tm_isdst > 0 ? 1 : 0), + time_ptr->tm_min, + time_ptr->tm_sec, + 1900 + time_ptr->tm_year, + '\0'); + + if (res != 8) + return (char *)NULL; + + return str; +} +char __ctime_buf[25]; +char *ctime(const time_t *timer) +{ + return asctime(localtime(timer)); +} +struct tm __gm_time_tm = {0}; +int _get_year(int); +int _get_month(int); +int _get_day(int); +int _get_day_of_month(int); +int _get_days_since_year(int); +int _get_hours(int); +int _get_minutes(int); +int _get_seconds(int); +struct tm *gmtime(const time_t *timer) +{ + time_t timer_cpy = *timer; + + __gm_time_tm.tm_year = _get_year(timer_cpy) + 70; + __gm_time_tm.tm_mon = _get_month(timer_cpy); + __gm_time_tm.tm_yday = _get_days_since_year(timer_cpy); + __gm_time_tm.tm_mday = _get_day_of_month(timer_cpy); + __gm_time_tm.tm_wday = _get_day(timer_cpy); + __gm_time_tm.tm_hour = _get_hours(timer_cpy); + __gm_time_tm.tm_min = _get_minutes(timer_cpy); + __gm_time_tm.tm_sec = _get_seconds(timer_cpy); + __gm_time_tm.tm_isdst = -1; // don't care about Daylight Saving Time + + return &__gm_time_tm; +} +int _get_local_year(int); +int _get_local_month(int); +int _get_local_day(int); +int _get_local_day_of_month(int); +int _get_local_days_since_year(int); +int _get_local_hours(int); +int _get_local_minutes(int); +int _get_local_seconds(int); +struct tm *localtime(const time_t *timer) +{ + time_t timer_cpy = *timer; + + __gm_time_tm.tm_year = _get_local_year(timer_cpy) + 70; + __gm_time_tm.tm_mon = _get_local_month(timer_cpy); + __gm_time_tm.tm_yday = _get_local_days_since_year(timer_cpy); + __gm_time_tm.tm_mday = _get_local_day_of_month(timer_cpy); + __gm_time_tm.tm_wday = _get_local_day(timer_cpy); + __gm_time_tm.tm_hour = _get_local_hours(timer_cpy); + __gm_time_tm.tm_min = _get_local_minutes(timer_cpy); + __gm_time_tm.tm_sec = _get_local_seconds(timer_cpy); + __gm_time_tm.tm_isdst = -1; // don't care about Daylight Saving Time + + return &__gm_time_tm; +} +int _get_weeks_in_year(int); +int _get_timezone_offset(int); +// https://cplusplus.com/reference/ctime/strftime/ +size_t strftime(char *ptr, size_t maxsize, const char *format, const struct tm *time_ptr) +{ + size_t fi = 0; + size_t wi = 0; + while (format[fi] != '\0' && wi < maxsize) + { + + if (format[fi] == '%') + { + fi++; + + switch (format[fi]) + { + case '%': + ptr[wi++] = '%'; + break; + + case 'a': + memcpy(ptr + wi, week_days[time_ptr->tm_wday], 3); + wi += 3; + break; + case 'A': + strcpy(ptr + wi, week_days_long[time_ptr->tm_wday]); + wi += strlen(week_days_long[time_ptr->tm_wday]); + break; + + case 'b': + case 'h': + memcpy(ptr + wi, months[time_ptr->tm_wday], 3); + wi += 3; + break; + case 'B': + strcpy(ptr + wi, months_long[time_ptr->tm_wday]); + wi += strlen(months_long[time_ptr->tm_wday]); + break; + + case 'c': + + case 'C': + sprintf(ptr + wi, "%.2d", time_ptr->tm_year / 20); + wi += 2; + break; + + case 'd': + sprintf(ptr + wi, "%.2d", time_ptr->tm_mday); + wi += 2; + break; + + case 'D': + sprintf(ptr + wi, "%.2d/%.2d/%.2d", time_ptr->tm_mon + 1, time_ptr->tm_mday, time_ptr->tm_year % 100); + wi += 2 + 1 + 2 + 1 + 2; + break; + + case 'e': + if (time_ptr->tm_mday < 10) + { + sprintf(ptr + wi, " %.1d", time_ptr->tm_mday); + } + else + { + sprintf(ptr + wi, "%.2d", time_ptr->tm_mday); + } + wi += 2; + break; + + case 'F': + sprintf(ptr + wi, "%.4d-%.2d-%.2d", time_ptr->tm_year, time_ptr->tm_mon + 1, time_ptr->tm_mday); + wi += 4 + 1 + 2 + 1 + 2; + break; + + // diff to y,Y ? + case 'g': + sprintf(ptr + wi, "%.2d", time_ptr->tm_year % 100); + wi += 2; + break; + case 'G': + sprintf(ptr + wi, "%.4d", time_ptr->tm_year); + wi += 4; + break; + + case 'H': + sprintf(ptr + wi, "%.2d", time_ptr->tm_hour); + wi += 2; + break; + + case 'I': + { + const int mod_12 = time_ptr->tm_hour % 12; + sprintf(ptr + wi, "%.2d", mod_12 == 0 ? 12 : mod_12); + wi += 2; + } + break; + + case 'j': + sprintf(ptr + wi, "%.3d", time_ptr->tm_yday); + wi += 3; + break; + + case 'm': + sprintf(ptr + wi, "%.2d", time_ptr->tm_mon + 1); + wi += 2; + break; + + case 'M': + sprintf(ptr + wi, "%.2d", time_ptr->tm_min); + wi += 2; + break; + + case 'n': + sprintf(ptr + wi, "\n"); + wi += 1; + break; + + case 'p': + if (time_ptr->tm_hour < 12) + { + sprintf(ptr + wi, "AM"); + } + else + { + sprintf(ptr + wi, "PM"); + } + wi += 2; + break; + + case 'r': + { + int mod_12 = time_ptr->tm_hour % 12; + sprintf(ptr + wi, "%.2d:%.2d:%.2d %s", mod_12 == 0 ? 12 : mod_12, time_ptr->tm_min, time_ptr->tm_sec, time_ptr->tm_hour < 12 ? "am" : "pm"); + wi += 2 + 1 + 2 + 1 + 2 + 1 + 2; + } + break; + case 'R': + sprintf(ptr + wi, "%.2d:%.2d", time_ptr->tm_hour, time_ptr->tm_min); + wi += 2 + 1 + 2; + break; + + case 'S': + sprintf(ptr + wi, "%.2d", time_ptr->tm_sec); + wi += 2; + break; + + case 't': + sprintf(ptr + wi, "\t"); + wi += 1; + break; + + case 'T': + sprintf(ptr + wi, "%.2d:%.2d:%.2d", time_ptr->tm_hour, time_ptr->tm_min, time_ptr->tm_sec); + wi += 2 + 1 + 2 + 1 + 2; + break; + + case 'u': + sprintf(ptr + wi, "%.1d", time_ptr->tm_wday); + wi += 1; + break; + + case 'U': + { + int last_sun = time_ptr->tm_yday - time_ptr->tm_wday; + sprintf(ptr + wi, "%.2d", last_sun / 7); + wi += 2; + } + break; + + case 'V': + { + int last_sun = 10 + time_ptr->tm_yday - time_ptr->tm_wday; + int w = last_sun / 7; + int woy; + if (w < 1) + { + woy = _get_weeks_in_year(time_ptr->tm_year - 1); + } + else if (w > _get_weeks_in_year(time_ptr->tm_year)) + { + woy = 1; + } + else + { + woy = w; + } + sprintf(ptr + wi, "%.2d", woy); + wi += 2; + } + break; + + case 'w': + sprintf(ptr + wi, "%.1d", time_ptr->tm_wday); + wi += 1; + break; + + case 'W': + { + int last_mon = time_ptr->tm_yday - (time_ptr->tm_wday == 1 ? 6 : time_ptr->tm_wday - 1); + sprintf(ptr + wi, "%.2d", last_mon / 7); + wi += 2; + } + break; + + case 'x': + sprintf(ptr + wi, "%.2d/%.2d/%.2d", time_ptr->tm_mon + 1, time_ptr->tm_mday, time_ptr->tm_year % 100); + wi += 2 + 1 + 2 + 1 + 2; + break; + case 'X': + sprintf(ptr + wi, "%.2d:%.2d:%.2d", time_ptr->tm_hour, time_ptr->tm_min, time_ptr->tm_sec); + wi += 2 + 1 + 2 + 1 + 2; + break; + + case 'y': + sprintf(ptr + wi, "%.2d", time_ptr->tm_year % 100); + wi += 2; + break; + case 'Y': + sprintf(ptr + wi, "%.4d", time_ptr->tm_year); + wi += 4; + break; + + case 'z': + { + tm tmp; + memcpy(&tmp, time_ptr, sizeof(tm)); + const int offset = _get_timezone_offset(mktime(&tmp)); // - if ahead + if behind + const int min = (offset < 0 ? -offset : offset) % 60; + const int hours = (offset < 0 ? -offset : offset) / 60; + sprintf(ptr + wi, "%c%.d", (offset < 0 ? '+' : '-'), (hours * 100) + min); + wi += 1 + (int)log10(hours) + (int)log10(min); + } + break; + + case 'Z': + // No support for printing time zone abbreviation + wi += 1; + break; + + case 'E': + case 'O': + wi += 2; + // No support for local alternative representation + break; + + default: + break; + } + } + else + { + ptr[wi++] = format[fi]; + } + } + + if (wi < maxsize) + { + ptr[wi] = '\0'; + return wi; + } + else + { + return 0; + } +} + +#endif + +#endif \ No newline at end of file diff --git a/libc/js/fenv.js b/libc/js/fenv.js new file mode 100644 index 0000000..e179376 --- /dev/null +++ b/libc/js/fenv.js @@ -0,0 +1,38 @@ +const FeRoundingMode = { + FE_TONEAREST: 0, + FE_DOWNWARD: 1, + FE_UPWARD: 2, + FE_TOWARDZERO: 3, +}; + +const fe_exception_flag = { + FE_DIVBYZERO: 0x01, // Pole error: division by zero, or some other asymptotically infinite result (from finite arguments). + FE_INEXACT: 0x02, // Inexact: the result is not exact. + FE_INVALID: 0x04, // Domain error: At least one of the arguments is a value for which the function is not defined. + FE_OVERFLOW: 0x08, // Overflow range error: The result is too large in magnitude to be represented as a value of the return type. + FE_UNDERFLOW: 0x10, // Underflow range error: The result is too small in magnitude to be represented as a value of the return type. + FE_ALL_EXCEPT: 0x1f, // All exceptions (selects all of the exceptions supported by the implementation). +}; + +// https://en.cppreference.com/w/c/numeric/fenv +class FeEnvJs { + #reset() { + this.__memory = undefined; + + this.__double_view = new Float64Array(1); + this.__float_view = new Float32Array(this.__double_view.buffer); + + this.___fe_rounding_mode_default = FeRoundingMode.FE_DOWNWARD; + this.___fe_rounding_mode = this.___fe_rounding_mode_default; + + this; + } + + constructor() { + this.#reset(); + } + + _js_fesetround(round) { + this.___fe_rounding_mode = round; + } +} diff --git a/libc/js/math.js b/libc/js/math.js new file mode 100644 index 0000000..9768fe0 --- /dev/null +++ b/libc/js/math.js @@ -0,0 +1,450 @@ +// https=//www.gnu.org/software/libc/manual/html_node/Floating-Point-Parameters.html +const FLT_RADIX = 2; // assume to always be 2 (is not for IBM 360 or derivatives) +const FP_ILOGB0 = 1 << 31; // -2147483648 +const FP_ILOGBNAN = 1 << 31; // -2147483648 +const INT_MAX = 2147483647; +const UINT_MAX = -1 >>> 0; +const INT_MIN = 1 << 31; +const UINT_MIN = 0; +const SMALLEST_DENORM = Math.pow(2, -1074); + +// ENDIANNESS +function find_endianness() { + var double_view = new Float64Array(1); + var int_view = new Uint32Array(double_view.buffer); + double_view[0] = -0; + + if (int_view[0] === 0) return 'little'; + else return 'big'; +} +const ENDIANNESS = find_endianness(); + +// https=//blog.codefrau.net/2014/08/deconstructing-floats-frexp-and-ldexp.html +function frexp(value) { + if (value === 0) return [value, 0]; + let data = new DataView(new ArrayBuffer(8)); + data.setFloat64(0, value); + let bits = (data.getUint32(0) >>> 20) & 0x7ff; + if (bits === 0) { + // denormal + data.setFloat64(0, value * Math.pow(2, 64)); // exp + 64 + bits = ((data.getUint32(0) >>> 20) & 0x7ff) - 64; + } + let exponent = bits - 1022; + let mantissa = ldexp(value, -exponent); + return [mantissa, exponent]; +} +function ldexp(mantissa, exponent) { + let steps = Math.min(3, Math.ceil(Math.abs(exponent) / 1023)); + let result = mantissa; + for (let i = 0; i < steps; i++) + result *= Math.pow(2, Math.floor((exponent + i) / steps)); + return result; +} + +// Implementation of https://de.wikipedia.org/wiki/Fehlerfunktion +function erf(x) { + const c = [ + 1.26551223, 1.00002368, 0.37409196, 0.09678418, 0.18628806, 0.27886807, + 1.13520398, 1.48851587, 0.82215223, 0.17087277, + ]; + + const tau = (x) => { + const t = 1 / (1 + 0.5 * Math.abs(x)); + + exp_inner = 0; + exp_inner += -c[0]; + t_mul = t; + exp_inner += c[1] * t_mul; + t_mul *= t; + exp_inner += c[2] * t_mul; + t_mul *= t; + exp_inner += c[3] * t_mul; + t_mul *= t; + exp_inner += -c[4] * t_mul; + t_mul *= t; + exp_inner += c[5] * t_mul; + t_mul *= t; + exp_inner += -c[6] * t_mul; + t_mul *= t; + exp_inner += c[7] * t_mul; + t_mul *= t; + exp_inner += -c[8] * t_mul; + t_mul *= t; + exp_inner += c[9] * t_mul; + + return t * Math.exp(-(x * x) + exp_inner); + }; + + if (x >= 0) { + return 1 - tau(x); + } else { + return tau(-x) - 1; + } +} + +class MathJs { + #reset() { + this.__wasm = undefined; + this.__memory = undefined; + this.__fenv = new FeEnvJs(); + this.__stdlib = new StdlibJs(); + } + + constructor() { + this.#reset(); + } + + init(wasm) { + this.__wasm = wasm; + this.__memory = wasm.instance.exports.memory; + } + + // Double precision + + // misc + fabs = Math.abs; + fmod = (x, y) => x % y; + remainder = (x, y) => { + // https://en.cppreference.com/w/c/numeric/math/remainder + if (isNaN(x) || isNaN(y)) return NaN; + if (!isFinite(x) || y === 0) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + return NaN; + } + + return x % y; + }; + remquo = (x, y, quo_ptr) => { + // https://en.cppreference.com/w/c/numeric/math/remquo + if (isNaN(x) || isNaN(y)) return NaN; + if (!isFinite(x) || y === 0) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + return NaN; + } + + let remainder = x % y; + + let sign = 0; + if (remainder === 0) { + if (x !== 0) sign = Math.sign(x); + else if (x === -0) sign = -1; + else sign = 1; + } else if (remainder < 0) sign = -1; + else sign = 1; + + if (x === 0 && y === 0) + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + if (y === 0) { + this.__wasm.instance.exports.feraiseexcept( + fe_exception_flag.FE_DIVBYZERO + ); + } + + let quo = Math.floor(x / y); + quo &= 0x7fffffff; + + let buf = new Uint32Array(this.__memory.buffer, quo_ptr, 1); + buf.set([sign * quo]); + return remainder; + }; + fma = (x, y, z) => x * y + z; + fmax = Math.max; + fmin = Math.min; + fdim = (x, y) => (x > y ? x - y : 0); // https://en.cppreference.com/w/c/numeric/math/fdim + infinity = () => Infinity; + nan = (content_ptr) => { + const content_str = cstr_by_ptr(this.__memory.buffer, content_ptr); + const num = parseInt(content_str); + + if (num <= 0 || num > 0xffffffff || num === NaN) { + return NaN; + } else { + let nan = new Uint32Array(2); + let buf_double = new Float64Array(nan.buffer, 0, 1); + + if (ENDIANNESS === 'big') { + nan[0] = 0x80000000; + nan[0] |= 0x7ff00000; + // nan[0] |= 0x000fffff & num; + nan[1] |= num; + } else if (ENDIANNESS === 'little') { + nan[1] = 0x80000000; + nan[1] |= 0x7ff00000; + // nan[1] |= 0x000fffff & num; + nan[0] |= num; + } else { + throw new Error( + 'Could not determine if numbers are little or big ENDIANNESS' + ); + } + return buf_double[0]; + } + }; + + // exponential + exp = Math.exp; + exp2 = (x) => Math.pow(2, x); + expm1 = Math.expm1; + log = Math.log; + log2 = Math.log2 || ((x) => Math.log(x) * Math.LOG2E); + log10 = Math.log10; + log1p = Math.log1p; + ilogb = (x) => { + // https://en.cppreference.com/w/c/numeric/math/ilogb + if (x === 0) return FP_ILOGB0; + else if (!isFinite(x)) return INT_MAX; + else if (isNaN(x)) return FP_ILOGBNAN; + + return Math.floor(this.logb(x)); + }; + logb = (x) => Math.log(x) / Math.log(FLT_RADIX); + + // power + pow = Math.pow; + sqrt = (x) => { + if (x < 0) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + } + return Math.sqrt(x); + }; + cbrt = Math.cbrt; + hypot = Math.hypot; + + //trigonometric + sin = Math.sin; + cos = Math.cos; + tan = Math.tan; + asin = Math.asin; + acos = Math.acos; + atan = Math.atan; + atan2 = Math.atan2; + + // hyperbolic + sinh = Math.sinh; + cosh = Math.cosh; + tanh = Math.tanh; + asinh = Math.asinh; + acosh = Math.acosh; + atanh = Math.atanh; + + // error/gamma + erf = erf; + erfc = (x) => 1 - this.erf(x); + lgamma = (x) => { + throw new ERROR('MATH GAMMA functions not implemented.'); + }; + tgamma = (x) => { + throw new ERROR('MATH GAMMA functions not implemented.'); + }; + + // floating point to int + ceil = Math.ceil; + floor = Math.floor; + trunc = Math.trunc; + round = Math.round; + lround = Math.round; + llround = Math.round; + nearbyint = (x) => { + let rounding_mode_before = this.__fenv.___fe_rounding_mode; + this.__fenv.___fe_rounding_mode = FeRoundingModes.FE_TONEAREST; + const res = this.rint(x); + this.__fenv.___fe_rounding_mode = rounding_mode_before; + return res; + }; + rint = (x) => { + switch (this.__fenv.___fe_rounding_mode) { + case FeRoundingModes.FE_DOWNWARD: + return Math.floor(x); + case FeRoundingModes.FE_UPWARD: + return Math.ceil(x); + case FeRoundingModes.FE_TOWARDZERO: + return x >= 0 ? Math.floor(x) : Math.ceil(x); + case FeRoundingModes.FE_TONEAREST: + return Math.floor(x) + 0.5 <= x ? Math.ceil(x) : Math.floor(x); + } + }; + lrint = this.rint; + llrint = this.rint; + + // floating point manipulation + frexp = (x, exponent_ptr) => { + const [mantissa, exponent] = frexp(x); + let buf = new Uint32Array(this.__memory.buffer, exponent_ptr, 1); + buf.set([exponent]); + return mantissa; + }; + ldexp = (x, y) => x * Math.pow(2, y); + modf = (x, int_part_ptr) => { + // TODO: This implementation is right for small values but is not C compliant + const int_part = Math.floor(x); + let buf = new Uint32Array(this.__memory.buffer, int_part_ptr, 1); + buf.set([int_part]); + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INEXACT); + return x - int_part; + }; + scalbln = (x, y) => x * Math.pow(FLT_RADIX, y); + scalbn = this.scalbln; + nextafter = (from, to) => { + // https://github.com/scijs/nextafter (MIT) + // https://www.npmjs.com/package/double-bits (MIT) + if (isNaN(from) || isNaN(to)) return NaN; + else if (from === to) return from; + else if (from === 0) return to < 0 ? -SMALLEST_DENORM : SMALLEST_DENORM; + + double_view[0] = from; + + var lo = ENDIANNESS === 'little' ? float_view[0] : float_view[1]; + var hi = ENDIANNESS === 'little' ? float_view[1] : float_view[0]; + + if (y > x === x > 0) { + if (lo === UINT_MAX) { + hi += 1; + lo = 0; + } else { + lo += 1; + } + } else { + if (lo === 0) { + lo = UINT_MAX; + hi -= 1; + } else { + lo -= 1; + } + } + + // TODO: raise fe exceptions + + return double_view[0]; + }; + nexttoward = this.nextafter; + copysign = (x, y) => Math.abs(x) * Math.sign(y); + + // Single precision + atanf = this.atan; + cosf = this.cos; + sinf = this.sin; + tanf = this.tan; + tanhf = this.tanh; + frexpf = this.frexp; + modff = this.modf; + ceilf = this.ceil; + fabsf = this.fabs; + floorf = this.floor; + + acosf = this.acos; + atan2f = this.atan2; + coshf = this.cosh; + sinhf = this.sinh; + expf = this.exp; + ldexpf = this.ldexp; + logf = this.log; + log10f = this.log10; + powf = this.pow; + sqrtf = this.sqrt; + fmodf = this.fmod; + + exp2f = this.exp2; + scalblnf = this.scalbln; + tgammaf = this.tgamma; + nearbyintf = this.nearbyint; + lrintf = this.lrint; + llrintf = this.llrint; + roundf = this.round; + lroundf = this.lround; + llroundf = this.llround; + truncf = this.trunc; + remquof = this.remquo; + fdimf = this.fdim; + fmaxf = this.fmax; + fminf = this.fmin; + fmaf = this.fma; + + infinityf = this.infinity; + nanf = this.nan; + copysignf = this.copysign; + logbf = this.logb; + ilogbf = this.ilogb; + + asinhf = this.asinh; + cbrtf = this.cbrt; + nextafterf = this.nextafter; + rintf = this.rint; + scalbnf = this.scalbn; + log1pf = this.log1p; + expm1f = this.expm1; + + acoshf = this.acosh; + atanhf = this.atanh; + remainderf = this.remainder; + lgammaf = this.lgamma; + erff = this.erf; + erfcf = this.erfc; + log2f = this.log2; + hypotf = this.hypot; + + // long double precision + // (WARNING: only for completness, is not more preccise) + + atanl = this.atan; + cosl = this.cos; + sinl = this.sin; + tanl = this.tan; + tanhl = this.tanh; + frexpl = this.frexp; + modfl = this.modf; + ceill = this.ceil; + fabsl = this.fabs; + floorl = this.floor; + + acosl = this.acos; + atan2l = this.atan2; + coshl = this.cosh; + sinhl = this.sinh; + expl = this.exp; + ldexpl = this.ldexp; + logl = this.log; + log10l = this.log10; + powl = this.pow; + sqrtl = this.sqrt; + fmodl = this.fmod; + + exp2l = this.exp2; + scalblnl = this.scalbln; + tgammal = this.tgamma; + nearbyintl = this.nearbyint; + lrintl = this.lrint; + llrintl = this.llrint; + roundl = this.round; + lroundl = this.lround; + llroundl = this.llround; + truncl = this.trunc; + remquol = this.remquo; + fdiml = this.fdim; + fmaxl = this.fmax; + fminl = this.fmin; + fmal = this.fma; + + infinityl = this.infinity; + nanl = this.nan; + copysignl = this.copysign; + logbl = this.logb; + ilogbl = this.ilogb; + + asinhl = this.asinh; + cbrtl = this.cbrt; + nextafterl = this.nextafter; + rintl = this.rint; + scalbnl = this.scalbn; + log1pl = this.log1p; + expm1l = this.expm1; + + acoshl = this.acosh; + atanhl = this.atanh; + remainderl = this.remainder; + lgammal = this.lgamma; + erfl = this.erf; + erfcl = this.erfc; + log2l = this.log2; + hypotl = this.hypot; +} diff --git a/libc/js/stdio.js b/libc/js/stdio.js new file mode 100644 index 0000000..470f8b4 --- /dev/null +++ b/libc/js/stdio.js @@ -0,0 +1,81 @@ +const BUFSIZ = 512; + +class StdioJs { + #reset() { + this.__wasm = undefined; + this.__memory = undefined; + + this.__file_promises = []; + } + + constructor() { + this.#reset(); + } + + init(wasm) { + this.__wasm = wasm; + this.__memory = wasm.instance.exports.memory; + + this.__file_promises = []; + } + + _print_string = (str_ptr) => { + const str = cstr_by_ptr(this.__memory.buffer, str_ptr); + console.log(str); + }; + + // Fetching a file and giving it to the c instance is difficult, as fetch is async and one + // cannot await the fetch while in fn called from c (while loop blocks fetch). + + // An option is to fopen() in one frame and have the FILE ready in next frame, so js can wait for fetch in between, + // but this would make fopen inconsistent between native and web. + + // to solve this, introduced is_file_ready() that is always true on native and true in the next frame on web. + // This needs a ready field in FILE & a way to set it, eg. _set_file_ready. + // Also need malloc & setvbuf from c to allocate a new buffer for the content and set it for the FILE ptr. + // The _append_fetch_promise is the fn being called from c. + // It creates a file with the exported fn _create_file and appends the fetch + // for the file to a promise list that is awaited all with wait_open_files between frames. + + // Just read that async was implemented so can fix that with another worker? + + _fetch_file = async (file_ptr, path_ptr) => { + const path = cstr_by_ptr(this.__memory.buffer, path_ptr); + const res = await fetch(path); + + const data_buf = await res.arrayBuffer(); + + const buf_start = this.__wasm.instance.exports.malloc( + data_buf.byteLength + 1 + ); + let buf = new Int8Array( + this.__memory.buffer, + buf_start, + data_buf.byteLength + 1 + ); + buf.set(new Int8Array(data_buf, 0, data_buf.byteLength)); + this.__wasm.instance.exports.setvbuf( + file_ptr, + buf_start, + 0, + data_buf.byteLength + ); + buf.set([0], data_buf.byteLength); + this.__wasm.instance.exports._set_file_ready(file_ptr); + }; + _append_fetch_promise = (path_ptr, optional_file_ptr) => { + let file_ptr = + optional_file_ptr == 0 + ? this.__wasm.instance.exports._create_file() + : optional_file_ptr; + + let prom = this._fetch_file(file_ptr, path_ptr); + this.__file_promises.push(prom); + + return file_ptr; + }; + wait_open_files() { + Promise.all(this.__file_promises); + this.__file_promises.length = 0; + } +} diff --git a/libc/js/stdlib.js b/libc/js/stdlib.js new file mode 100644 index 0000000..c80365d --- /dev/null +++ b/libc/js/stdlib.js @@ -0,0 +1,497 @@ +const RAND_MAX = INT_MAX; + +// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript +function splitmix32(a) { + return function () { + a |= 0; + a = (a + 0x9e3779b9) | 0; + var t = a ^ (a >>> 16); + t = Math.imul(t, 0x21f0aaad); + t = t ^ (t >>> 15); + t = Math.imul(t, 0x735a2d97); + return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296; + }; +} + +function cstr_by_ptr_len(mem_buffer, ptr, str_len) { + const bytes = new Uint8Array(mem_buffer, ptr, str_len); + return new TextDecoder().decode(bytes); +} + +class ExitWasmException extends Error { + constructor() { + super('This is a exception thrown to exist wasm'); + this.name = this.constructor.name; + } +} + +class StdlibJs { + #reset() { + this.__memory = undefined; + this.__fn_table = undefined; + + // STRING TO NUMBER + this.__had_dot = undefined; + this.__had_e = undefined; + this.__had_x = undefined; + + this.___had_helpers = {}; + this.___had_helpers.is_second_dot = (x) => { + if (str[i] === '.') { + if (!this.__had_dot) { + this.__had_dot = true; + return false; + } else { + return true; + } + } + return false; + }; + this.___had_helpers.is_second_e = (x) => { + if (str[i] === 'e' || str[i] === 'E') { + if (!this.__had_e) { + this.__had_e = true; + return false; + } else { + return true; + } + } + return false; + }; + this.___had_helpers.is_second_x = (x) => { + if (str[i] === 'x' || str[i] === 'X') { + if (!this.__had_x) { + this.__had_x = true; + return false; + } else { + return true; + } + } + return false; + }; + + // RANDOM + this.__current_random_generator = splitmix32(1); + + // ENVIRONMENT + this.__ctx = undefined; + this.__change_running_fn = undefined; + this.__wasm = undefined; + this.__at_exit_fns = []; + this.__at_quick_exit_fns = []; + } + + constructor() { + this.#reset(); + } + + init(ctx, wasm, change_running_fn) { + this.__ctx = ctx; + this.__wasm = wasm; + this.__memory = wasm.instance.exports.memory; + this.__fn_table = wasm.instance.exports.__indirect_function_table; + this.__change_running_fn = change_running_fn; + } + handle_exit() { + for (let i = 0; i < this.__at_exit_fns.length; i++) { + this.__at_exit_fns[this.__at_exit_fns.length - 1 - i](); + } + } + + // STRING TO NUMBER + atof = (str_ptr) => { + var str = cstr_by_ptr(this.__memory.buffer, str_ptr); + return parseFloat(str); + }; + atoi = (str_ptr) => { + var str = cstr_by_ptr(this.__memory.buffer, str_ptr); + return parseInt(str); + }; + atol = this.atoi; + atoll = this.atoi; + + _next_is_num(i, str) { + return ( + (str[i] >= '0' && str[i] <= '9') || + (str[i] === '-' && + str[i + 1] !== undefined && + !isNaN(parseInt(str[i + 1], 10))) + ); + } + _parse_num(start_i, str) { + let i = start_i; + + // eat until first non number char + this.__had_dot = false; + this.__had_e = false; + while ( + str[i] !== undefined && + (!isNaN(parseInt(str[i], 10)) || + str[i] === '-' || + str[i] === '.' || + str[i].toLowerCase() === 'e') && + !this.___had_helpers.is_second_dot(str[i]) && + !this.___had_helpers.is_second_e(str[i]) + ) { + i++; + } + + return [parseFloat(str), i]; + } + + _next_is_nan(i, str) { + return ( + (str[i] === '-' && + str[i + 1] !== undefined && + str[i + 1].toLowerCase() === 'n') || + str[i].toLowerCase() === 'n' + ); + } + _parse_nan(start_i, str, is_float) { + let i = start_i; + + let is_negative = false; + if (str[i] === '-') { + is_negative = true; + i++; + } + + i++; + const valid2 = str[i] === 'A' || str[i] === 'a'; + i++; + const valid3 = str[i] === 'N' || str[i] === 'n'; + i++; + + if (!valid2 || !valid3) { + i -= 3; + return [0, i]; + } else if (str[i] === '(') { + i++; + const substr = str.substring(i); + const num = parseInt(substr); + + // eat until first non number char + while (!isNaN(parseInt(str[i], 10))) { + i++; + } + + if (str[i] === ')') { + i++; + if (num <= 0 || num > 0xffffffff) { + return [is_negative ? -NaN : NaN, i]; + } else { + if (is_float) { + let nan = new Uint32Array(1); + let buf_float = new Float32Array(nan.buffer, 0, 1); + + nan[0] = 0x7fc00000; + nan[0] |= 0x3fffff & num; + + return [is_negative ? -buf_float[0] : buf_float[0], i]; + } else { + let nan = new Uint32Array(2); + let buf_double = new Float64Array(nan.buffer, 0, 1); + + if (ENDIANNESS === 'big') { + nan[0] = 0x7ff80000; + // nan[0] |= 0x000fffff & num; + nan[1] |= num; + } else if (ENDIANNESS === 'little') { + nan[1] = 0x7ff80000; + // nan[1] |= 0x000fffff & num; + nan[0] |= num; + } + return [is_negative ? -buf_double[0] : buf_double[0], i]; + } + } + } else { + return [0, start_i]; + } + } else { + return [is_negative ? -NaN : NaN, i]; + } + } + + _next_is_inf(i, str) { + return ( + (str[i] === '-' && + str[i + 1] !== undefined && + str[i + 1].toLowerCase() === 'i') || + str[i].toLowerCase() === 'i' + ); + } + _parse_inf(start_i, str) { + let i = start_i; + + let is_negative = false; + if (str[i] === '-') { + is_negative = true; + i++; + } + + i++; + const find = 'infinity'; + let j = 1; + while ( + i < str.length && + j < find.length && + str[i].toLowerCase() === find[j].toLowerCase() + ) { + i++; + j++; + } + + if (j >= 3 && j <= 7) { + i -= j - 3; + return [is_negative ? -Infinity : Infinity, i]; + } else if (j === 8) { + return [is_negative ? -Infinity : Infinity, i]; + } else { + i -= j; + return [0, i]; + } + } + + _strtodf(str_ptr, end_ptr, is_float) { + let str = cstr_by_ptr(this.__memory.buffer, str_ptr); + let i = 0; + + // eat whitespace + while (str.length < i && ' \t\n\r\v'.indexOf(str[i]) > -1) { + i++; + } + + let res; + if (str[i] === undefined) { + res = 0; + } else if (this._next_is_num(i, str)) { + [res, i] = this._parse_num(i, str); + } else if (this._next_is_nan(i, str)) { + [res, i] = this._parse_nan(i, str, is_float); + } else if (this._next_is_inf(i, str)) { + [res, i] = this._parse_inf(i, str); + } else { + res = 0; + } + + // eat whitespace + while (str.length < i && ' \t\n\r\v'.indexOf(str[i]) > -1) { + i++; + } + + var buf = new Uint32Array(this.__memory.buffer, end_ptr); + buf.set([str_ptr + i]); // do not find + return res; + } + + strtod = (str_ptr, end_ptr) => this._strtodf(str_ptr, end_ptr, false); + strtof = (str_ptr, end_ptr) => this._strtodf(str_ptr, end_ptr, true); + strtol = (str_ptr, end_ptr, base) => { + var str = cstr_by_ptr(this.__memory.buffer, str_ptr); + + var i = 0; + + // eat whitespace + while (str.length < i && ' \t\n\r\v'.indexOf(str[i]) > -1) { + i++; + } + + // eat until first non number char + this.__had_x = false; + while ( + !isNaN(parseInt(str[i], base)) && + !this.___had_helpers.is_second_x(str[i]) // TODO: x is accepted for bases other than 0 and 16 + ) { + i++; + } + + var buf = Uint32Array(this.__memory.buffer, end_ptr); + buf.set([str_ptr + i]); // do not find + return parseInt(str, base); + }; + strtoll = this.strtol; + strtoul = this.strtol; + strtoull = this.strtol; + + // RANDOM + rand = () => { + return this.__current_random_generator() * RAND_MAX; + }; + srand = (seed) => { + this.__current_random_generator = splitmix32(seed); + }; + + // MEMORY ALLOCATOR + _heap_start = () => { + return this.__wasm.instance.exports.__heap_base; + }; + _grow_memory = (page_size) => { + var first_free_mem_index = this.__memory.buffer.byteLength; + this.__memory.grow(page_size); + return first_free_mem_index; + }; + + // ENVIRONMENT + abort = () => { + this.__change_running_fn(() => { + const w = this.__ctx.canvas.width; + const h = this.__ctx.canvas.height; + const old_style = this.__ctx.fillStyle; + + this.__ctx.fillStyle = '#fa4141'; + this.__ctx.fillRect(0, 0, w, h); + + const fontSize = 20; + const text = `Program aborted`; + this.__ctx.font = `${fontSize}px grixel`; + this.__ctx.fillStyle = 'black'; + const textWidth = this.__ctx.measureText(text); + this.__ctx.fillText(text, w / 2 - textWidth.width / 2, h / 2 + fontSize); + + this.__ctx.fillStyle = old_style; + }); + throw new ExitWasmException(); // exit wasm + }; + exit = (status) => { + for (let i = 0; i < this.__at_exit_fns.length; i++) { + this.__at_exit_fns[this.__at_exit_fns.length - 1 - i](); + } + + this.__change_running_fn(() => { + const w = this.__ctx.canvas.width; + const h = this.__ctx.canvas.height; + const old_style = this.__ctx.fillStyle; + + this.__ctx.fillStyle = status == 0 ? '#37bd3b' : '#fa4141'; + this.__ctx.fillRect(0, 0, w, h); + + const fontSize = 20; + const text = `Exited with status ${status}`; + this.__ctx.font = `${fontSize}px grixel`; + this.__ctx.fillStyle = 'black'; + const textWidth = this.__ctx.measureText(text); + this.__ctx.fillText(text, w / 2 - textWidth.width / 2, h / 2 + fontSize); + + this.__ctx.fillStyle = old_style; + }); + throw new ExitWasmException(); // exit wasm + }; + quick_exit = (status) => { + for (let i = 0; i < this.__at_quick_exit_fn.length; i++) { + this.__at_quick_exit_fn[this.__at_quick_exit_fn.length - 1 - i](); + } + + this.__change_running_fn(() => { + const w = this.__ctx.canvas.width; + const h = this.__ctx.canvas.height; + const old_style = this.__ctx.fillStyle; + + this.__ctx.fillStyle = status == 0 ? '#37bd3b' : '#fa4141'; + this.__ctx.fillRect(0, 0, w, h); + + const fontSize = 20; + const text = `Exited with status ${status}`; + this.__ctx.font = `${fontSize}px grixel`; + this.__ctx.fillStyle = 'black'; + const textWidth = this.__ctx.measureText(text); + this.__ctx.fillText(text, w / 2 - textWidth.width / 2, h / 2 + fontSize); + + this.__ctx.fillStyle = old_style; + }); + throw new ExitWasmException(); // exit wasm + }; + atexit = (fn_ptr) => { + try { + this.__at_exit_fns.push(this.__fn_table.get(fn_ptr)); + } catch (e) { + return 1; + } + return 0; + }; + at_quick_exit = (fn_ptr) => { + try { + this.__at_quick_exit_fns.push(this.__fn_table.get(fn_ptr)); + } catch (e) { + return 1; + } + return 0; + }; + + // INTEGER ARITHMETICS + abs = Math.abs; + labs = this.abs; + llabs = this.abs; + + // MULTIBYTE CHARACTERS (UTF-ONLY (LC_CTYPE=UTF-8)) + mblen = (mbc_ptr, max) => { + if (mbc_ptr == 0) return 0; // not state dependant + + let str = cstr_by_ptr_len(mbc_ptr, max); + let first_char = str[0]; + return new Blob([first_char]).size; + }; + mbtowc = (wc_ptr, mbc_ptr, max) => { + if (mbc_ptr == 0) return 0; // not state dependant + + let str = cstr_by_ptr_len(mbc_ptr, max); + + if (wc_ptr != 0) { + // assume sizeof(wchar_t) == 4 + let buf = new Int32Array(this.__memory.buffer, wc_ptr, max); + buf[0] = str.codePointAt(0); + } + + return new Blob([str[0]]).size; + }; + wctomb = (mbc_ptr, wc) => { + if (mbc_ptr == 0) return 0; // not state dependant + + let mbc; + try { + mbc = String.fromCodePoint(wc); + } catch (e) { + return -1; // handles invalid code points + } + + let encoded = new TextEncoder().encode(mbc); + let buf = new Int8Array(this.__memory.buffer, mbc_ptr, encoded.byteLength); + + for (i = 0; i < encoded.byteLength; i++) { + buf[i] = encoded[i]; + } + + return encoded.length; + }; + + mbstowcs = (dest_ptr, src_ptr, max) => { + const src_buf = new Int8Array(this.__memory.buffer, src_ptr, max); + const str = new TextDecoder('utf-8').decode(src_buf); + + let dest_buf = new Int32Array(this.__memory.buffer, dest_ptr, max); + + for (let i = 0; i < Math.min(str.length, max); i++) { + dest_buf[i] = str.codePointAt(i); + } + if (str.length < max) { + dest_buf[str.length] = 0; // add '\0'; + } + + return Math.min(str.length, max); + }; + wcstombs = (dest_ptr, src_ptr, max) => { + const src_buf = new Int32Array(this.__memory.buffer, src_ptr, max); + const str = new TextDecoder('utf-8').decode(src_buf); + + let cur_len = 0; + + let last = src_buf[0]; + for (let i = 0; i < max && last != 0; i++) { + last = String.fromCodePoint(src_buf[i]); + let len = this.wctomb(dest_ptr + cur_len); + if (len < 0) return -1; + cur_len += len; + } + + return cur_len; + }; +} diff --git a/libc/js/time.js b/libc/js/time.js new file mode 100644 index 0000000..cb3b10e --- /dev/null +++ b/libc/js/time.js @@ -0,0 +1,104 @@ +class TimeJs { + #reset() { + this.__memory = undefined; + } + + constructor() { + this.#reset(); + } + + init(wasm) { + this.__memory = wasm.instance.exports.memory; + } + + clock = () => Date.now(); + time = (timer_ptr) => { + if (timer_ptr != 0) { + var buf = new Int32Array(this.__memory.buffer, timer_ptr, 1); + buf[0] = this.clock(); + } + + return this.clock(); + }; + + // Get UTC time + _get_year = (time_num) => { + return new Date(time_num).getUTCFullYear(); + }; + _get_month = (time_num) => { + return new Date(time_num).getUTCMonth(); + }; + _get_day = (time_num) => { + return new Date(time_num).getUTCDay(); + }; + _get_day_of_month = (time_num) => { + return new Date(time_num).getUTCDate(); + }; + _get_days_since_year = (time_num) => { + const date = new Date(time_num); + return ( + (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - + Date.UTC(date.getUTCFullYear(), 0, 0)) / + 24 / + 60 / + 60 / + 1000 + ); + }; + _get_hours = (time_num) => { + return new Date(time_num).getUTCHours(); + }; + _get_minutes = (time_num) => { + return new Date(time_num).getUTCMinutes(); + }; + _get_seconds = (time_num) => { + return new Date(time_num).getUTCSeconds(); + }; + + // Get Local time + _get_local_year = (time_num) => { + return new Date(time_num).getFullYear(); + }; + _get_local_month = (time_num) => { + return new Date(time_num).getMonth(); + }; + _get_local_day = (time_num) => { + return new Date(time_num).getDay(); + }; + _get_local_day_of_month = (time_num) => { + return new Date(time_num).getDate(); + }; + _get_local_days_since_year = (time_num) => { + const date = new Date(time_num); + return ( + (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - + Date.UTC(date.getFullYear(), 0, 0)) / + 24 / + 60 / + 60 / + 1000 + ); + }; + _get_local_hours = (time_num) => { + return new Date(time_num).getHours(); + }; + _get_local_minutes = (time_num) => { + return new Date(time_num).getMinutes(); + }; + _get_local_seconds = (time_num) => { + return new Date(time_num).getSeconds(); + }; + + _get_weeks_in_year = (year) => { + let last_date_of_year = new Date(year, 11, 31); + let d = new Date(+last_date_of_year); + d.setHours(0, 0, 0, 0); + d.setDate(d.getDate() + 4 - (d.getDay() || 7)); + let yearStart = new Date(d.getFullYear(), 0, 1); + let weekNo = Math.ceil(((d - yearStart) / 86400000 + 1) / 7); + return weekNo == 1 ? 52 : 53; + }; + _get_timezone_offset = (time_num) => { + return new Date(time_num).getTimezoneOffset(); + }; +} diff --git a/libc/libc.h b/libc/libc.h new file mode 100644 index 0000000..3099b2f --- /dev/null +++ b/libc/libc.h @@ -0,0 +1,30 @@ +#ifdef PLATFORM_WEB + +#define FENV_IMPL +#include "fenv.h" + +#define STDLIB_IMPL +#include "stdlib.h" + +#define STRING_IMPL +#include "string.h" + +#define TIME_IMPL +#include "time.h" + +#define STDIO_IMPL +#include "stdio.h" + +#define ERRNO_IMPL +#include "errno.h" + +#define ASSERT_IMPL +#include "assert.h" + +#include +bool is_file_ready(FILE *stream) { return stream->ready; } +#else +#include +#include +bool is_file_ready(FILE *stream) { return true; } +#endif \ No newline at end of file diff --git a/nob.c b/nob.c index 15ef36d..fb3b841 100644 --- a/nob.c +++ b/nob.c @@ -48,6 +48,26 @@ Example examples[] = { .bin_path = "./build/text_writing_anim", .wasm_path = "./wasm/text_writing_anim.wasm", }, + { + .src_path = "./examples/libc/math.c", + .bin_path = "./build/libc_math", + .wasm_path = "./wasm/libc_math.wasm", + }, + { + .src_path = "./examples/libc/exit.c", + .bin_path = "./build/libc_exit", + .wasm_path = "./wasm/libc_exit.wasm", + }, + { + .src_path = "./examples/libc/malloc.c", + .bin_path = "./build/libc_malloc", + .wasm_path = "./wasm/libc_malloc.wasm", + }, + { + .src_path = "./examples/libc/file.c", + .bin_path = "./build/libc_file", + .wasm_path = "./wasm/libc_file.wasm", + }, }; bool build_native(void) @@ -56,6 +76,7 @@ bool build_native(void) for (size_t i = 0; i < NOB_ARRAY_LEN(examples); ++i) { cmd.count = 0; nob_cmd_append(&cmd, "clang", "-I./include/"); + nob_cmd_append(&cmd, "-includelibc/libc.h"); // for stdio compatibility nob_cmd_append(&cmd, "-o", examples[i].bin_path, examples[i].src_path); nob_cmd_append(&cmd, "-L./lib/", "-lraylib", "-lm"); if (!nob_cmd_run_sync(cmd)) return 1; @@ -70,11 +91,16 @@ bool build_wasm(void) nob_cmd_append(&cmd, "clang"); nob_cmd_append(&cmd, "--target=wasm32"); nob_cmd_append(&cmd, "-I./include"); + nob_cmd_append(&cmd, "-I./libc/include"); + nob_cmd_append(&cmd, "-includelibc/libc.h"); nob_cmd_append(&cmd, "--no-standard-libraries"); nob_cmd_append(&cmd, "-Wl,--export-table"); nob_cmd_append(&cmd, "-Wl,--no-entry"); nob_cmd_append(&cmd, "-Wl,--allow-undefined"); nob_cmd_append(&cmd, "-Wl,--export=main"); + nob_cmd_append(&cmd, "-Wl,--export=__heap_base", "-Wl,--export=feraiseexcept"); // libc + nob_cmd_append(&cmd, "-Wl,--export=malloc"); // libc + nob_cmd_append(&cmd, "-Wl,--export=_create_file", "-Wl,--export=setvbuf", "-Wl,--export=_set_file_ready"); // libc nob_cmd_append(&cmd, "-o"); nob_cmd_append(&cmd, examples[i].wasm_path); nob_cmd_append(&cmd, examples[i].src_path); diff --git a/raylib.js b/raylib.js index a6a0154..49e0eec 100644 --- a/raylib.js +++ b/raylib.js @@ -1,9 +1,14 @@ -function make_environment(env) { +function make_environment(env, ...envs) { return new Proxy(env, { get(target, prop, receiver) { if (env[prop] !== undefined) { return env[prop].bind(env); } + for (var i = 0; i < envs.length; i++) { + if (envs[i][prop] !== undefined) { + return envs[i][prop].bind(envs[i]); + } + } return (...args) => { throw new Error(`NOT IMPLEMENTED: ${prop} ${args}`); } @@ -44,6 +49,12 @@ class RaylibJs { this.currentMousePosition = {x: 0, y: 0}; this.images = []; this.quit = false; + + //libc + this.math = new MathJs(); + this.stdlib = new StdlibJs(); + this.stdio = new StdioJs(); + this.time = new TimeJs(); } constructor() { @@ -67,9 +78,17 @@ class RaylibJs { } this.wasm = await WebAssembly.instantiateStreaming(fetch(wasmPath), { - env: make_environment(this) + env: make_environment(this, this.math, this.stdlib, this.stdio, this.time) }); + // Init libc + this.math.init(this.wasm); + this.stdlib.init(this.ctx, this.wasm, (js_fn) => { + this.entryFunction = js_fn; + }); + this.stdio.init(this.wasm); + this.time.init(this.wasm); + const keyDown = (e) => { this.currentPressedKeyState.add(glfwKeyMapping[e.code]); }; @@ -87,9 +106,17 @@ class RaylibJs { window.addEventListener("wheel", wheelMove); window.addEventListener("mousemove", mouseMove); - this.wasm.instance.exports.main(); + try { + this.wasm.instance.exports.main(); + } catch (e) { + if (!(e instanceof ExitWasmException)) { + throw e; + } + } + const next = (timestamp) => { if (this.quit) { + this.stdlib.handle_exit(); this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); window.removeEventListener("keydown", keyDown); this.#reset() @@ -97,7 +124,16 @@ class RaylibJs { } this.dt = (timestamp - this.previous)/1000.0; this.previous = timestamp; - this.entryFunction(); + + try { + this.stdio.wait_open_files(); + this.entryFunction(); + } catch (e) { + if (!(e instanceof ExitWasmException)) { + throw e; + } + } + window.requestAnimationFrame(next); }; window.requestAnimationFrame((timestamp) => { diff --git a/wasm/file_example.wasm b/wasm/file_example.wasm new file mode 100644 index 0000000000000000000000000000000000000000..2219de639072c558e8354228d9fb3cb3f7372302 GIT binary patch literal 60090 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 XD6{k@jhcK^r%{WNNorYX+UEZPqaPwn literal 0 HcmV?d00001 diff --git a/wasm/libc_file.wasm b/wasm/libc_file.wasm new file mode 100644 index 0000000000000000000000000000000000000000..85a3209eefd787fabebb89d5dbf924d45aecb803 GIT binary patch literal 61073 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 delta 24200 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 XH*cNRjxb@{eQH1Z!qc^%uJiu@U$iAH From 83438a2ca6f2afaa4526f40a9920c1a5ac554b55 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Thu, 22 Feb 2024 00:20:42 +0100 Subject: [PATCH 2/7] Create time example and fix time.h --- examples/libc/time.c | 54 ++++++++++++++++++++++++++++++++++++++++ index.html | 2 +- libc/include/assert.h | 11 ++++---- libc/include/time.h | 46 +++++++++++++++++----------------- libc/js/time.js | 48 +++++++++++++++++++---------------- libc/libc.h | 12 ++++----- nob.c | 5 ++++ raylib.js | 6 ++--- wasm/libc_exit.wasm | Bin 56611 -> 58492 bytes wasm/libc_file.wasm | Bin 61073 -> 61236 bytes wasm/libc_malloc.wasm | Bin 60154 -> 62068 bytes wasm/libc_math.wasm | Bin 57128 -> 59026 bytes wasm/libc_time.wasm | Bin 0 -> 59840 bytes wasm/tsoding_snake.wasm | Bin 86662 -> 88576 bytes 14 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 examples/libc/time.c create mode 100644 wasm/libc_time.wasm diff --git a/examples/libc/time.c b/examples/libc/time.c new file mode 100644 index 0000000..9d5680e --- /dev/null +++ b/examples/libc/time.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +void raylib_js_set_entry(void (*entry)(void)); + +char buf[BUFSIZ]; + +void GameFrame() +{ + BeginDrawing(); + + ClearBackground((Color){20, 20, 20, 255}); + + const size_t w = GetScreenWidth(); + const size_t h = GetScreenHeight(); + const size_t font_size = 48; + + const int ch = h / 2 - (font_size / 2); + + time_t t = time(NULL); + printf("%lli\n", t); + + struct tm *ts = localtime(&t); + printf("%i\n", ts->tm_mday); + + char *time_text = asctime(ts); // ctime(&t); + sprintf(buf, "%s%c", time_text, '\0'); + + size_t text_size = MeasureText(buf, font_size); + int cw = w / 2 - (text_size / 2); + DrawText(buf, cw, ch, font_size, RED); + + EndDrawing(); +} + +int main() +{ + InitWindow(800, 600, "Hello, with math.h"); + SetTargetFPS(60); + +#ifdef PLATFORM_WEB + raylib_js_set_entry(GameFrame); +#else + while (!WindowShouldClose()) + { + GameFrame(); + } + CloseWindow(); +#endif + return 0; +} \ No newline at end of file diff --git a/index.html b/index.html index 14bce2a..f195eef 100644 --- a/index.html +++ b/index.html @@ -78,7 +78,7 @@ "shapes": ["shapes_colors_palette"], "text": ["text_writing_anim"], "textures": ["textures_logo_raylib"], - "libc": ["libc_math", "libc_exit", "libc_malloc", "libc_file"], + "libc": ["libc_math", "libc_exit", "libc_malloc", "libc_file", "libc_time"], } const defaultWasm = Object.values(wasmPaths)[0][0]; diff --git a/libc/include/assert.h b/libc/include/assert.h index 0e1e602..d883d97 100644 --- a/libc/include/assert.h +++ b/libc/include/assert.h @@ -12,8 +12,12 @@ void _assert(const char *message, const char *file, unsigned line); #endif #ifdef ASSERT_IMPL -#include -#include + +#define assert(expression) (void)((!!(expression)) || \ + (_assert(#expression, __FILE__, (unsigned)(__LINE__)), 0)) + +// #include +// #include void exit(int); int printf(const char *, ...); @@ -24,9 +28,6 @@ void _assert(const char *message, const char *file, unsigned line) } #endif -#define assert(expression) (void)((!!(expression)) || \ - (_assert(#expression, __FILE__, (unsigned)(__LINE__)), 0)) - #endif #endif // _INC_ASSERT \ No newline at end of file diff --git a/libc/include/time.h b/libc/include/time.h index 3f0e115..51f58b7 100644 --- a/libc/include/time.h +++ b/libc/include/time.h @@ -7,8 +7,8 @@ #define CLOCKS_PER_SEC 1000 -typedef unsigned int clock_t; -typedef unsigned int time_t; +typedef long long clock_t; +typedef long long time_t; typedef struct tm tm; // DECLARATIONS @@ -101,14 +101,14 @@ char *asctime(const struct tm *time_ptr) int res = sprintf(str, "%.3s %.3s %.2d %.2d:%.2d:%.2d %.4d\n%c", week_days[time_ptr->tm_wday], months[time_ptr->tm_mon], - time_ptr->tm_mon, + time_ptr->tm_mday, time_ptr->tm_hour + (time_ptr->tm_isdst > 0 ? 1 : 0), time_ptr->tm_min, time_ptr->tm_sec, 1900 + time_ptr->tm_year, '\0'); - if (res != 8) + if (res != 26) return (char *)NULL; return str; @@ -119,19 +119,19 @@ char *ctime(const time_t *timer) return asctime(localtime(timer)); } struct tm __gm_time_tm = {0}; -int _get_year(int); -int _get_month(int); -int _get_day(int); -int _get_day_of_month(int); -int _get_days_since_year(int); -int _get_hours(int); -int _get_minutes(int); -int _get_seconds(int); +int _get_year(time_t); +int _get_month(time_t); +int _get_day(time_t); +int _get_day_of_month(time_t); +int _get_days_since_year(time_t); +int _get_hours(time_t); +int _get_minutes(time_t); +int _get_seconds(time_t); struct tm *gmtime(const time_t *timer) { time_t timer_cpy = *timer; - __gm_time_tm.tm_year = _get_year(timer_cpy) + 70; + __gm_time_tm.tm_year = _get_year(timer_cpy) - 1900; __gm_time_tm.tm_mon = _get_month(timer_cpy); __gm_time_tm.tm_yday = _get_days_since_year(timer_cpy); __gm_time_tm.tm_mday = _get_day_of_month(timer_cpy); @@ -143,19 +143,19 @@ struct tm *gmtime(const time_t *timer) return &__gm_time_tm; } -int _get_local_year(int); -int _get_local_month(int); -int _get_local_day(int); -int _get_local_day_of_month(int); -int _get_local_days_since_year(int); -int _get_local_hours(int); -int _get_local_minutes(int); -int _get_local_seconds(int); +int _get_local_year(time_t); +int _get_local_month(time_t); +int _get_local_day(time_t); +int _get_local_day_of_month(time_t); +int _get_local_days_since_year(time_t); +int _get_local_hours(time_t); +int _get_local_minutes(time_t); +int _get_local_seconds(time_t); struct tm *localtime(const time_t *timer) { time_t timer_cpy = *timer; - __gm_time_tm.tm_year = _get_local_year(timer_cpy) + 70; + __gm_time_tm.tm_year = _get_local_year(timer_cpy) - 1900; __gm_time_tm.tm_mon = _get_local_month(timer_cpy); __gm_time_tm.tm_yday = _get_local_days_since_year(timer_cpy); __gm_time_tm.tm_mday = _get_local_day_of_month(timer_cpy); @@ -168,7 +168,7 @@ struct tm *localtime(const time_t *timer) return &__gm_time_tm; } int _get_weeks_in_year(int); -int _get_timezone_offset(int); +int _get_timezone_offset(time_t); // https://cplusplus.com/reference/ctime/strftime/ size_t strftime(char *ptr, size_t maxsize, const char *format, const struct tm *time_ptr) { diff --git a/libc/js/time.js b/libc/js/time.js index cb3b10e..06dc322 100644 --- a/libc/js/time.js +++ b/libc/js/time.js @@ -11,31 +11,37 @@ class TimeJs { this.__memory = wasm.instance.exports.memory; } - clock = () => Date.now(); + clock = () => BigInt(Date.now()); time = (timer_ptr) => { if (timer_ptr != 0) { - var buf = new Int32Array(this.__memory.buffer, timer_ptr, 1); - buf[0] = this.clock(); + var buf = new BigInt64Array(this.__memory.buffer, timer_ptr, 1); + buf[0] = BigInt(Date.now()); } - return this.clock(); + return BigInt(Date.now()); }; + create_date(time_num) { + let num = Number(time_num); + return new Date(num); + } + // Get UTC time _get_year = (time_num) => { - return new Date(time_num).getUTCFullYear(); + // console.log(time_num) + return this.create_date(time_num).getUTCFullYear(); }; _get_month = (time_num) => { - return new Date(time_num).getUTCMonth(); + return this.create_date(time_num).getUTCMonth(); }; _get_day = (time_num) => { - return new Date(time_num).getUTCDay(); + return this.create_date(time_num).getUTCDay(); }; _get_day_of_month = (time_num) => { - return new Date(time_num).getUTCDate(); + return this.create_date(time_num).getUTCDate(); }; _get_days_since_year = (time_num) => { - const date = new Date(time_num); + const date = this.create_date(time_num); return ( (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(date.getUTCFullYear(), 0, 0)) / @@ -46,30 +52,30 @@ class TimeJs { ); }; _get_hours = (time_num) => { - return new Date(time_num).getUTCHours(); + return this.create_date(time_num).getUTCHours(); }; _get_minutes = (time_num) => { - return new Date(time_num).getUTCMinutes(); + return this.create_date(time_num).getUTCMinutes(); }; _get_seconds = (time_num) => { - return new Date(time_num).getUTCSeconds(); + return this.create_date(time_num).getUTCSeconds(); }; // Get Local time _get_local_year = (time_num) => { - return new Date(time_num).getFullYear(); + return this.create_date(time_num).getFullYear(); }; _get_local_month = (time_num) => { - return new Date(time_num).getMonth(); + return this.create_date(time_num).getMonth(); }; _get_local_day = (time_num) => { - return new Date(time_num).getDay(); + return this.create_date(time_num).getDay(); }; _get_local_day_of_month = (time_num) => { - return new Date(time_num).getDate(); + return this.create_date(time_num).getDate(); }; _get_local_days_since_year = (time_num) => { - const date = new Date(time_num); + const date = this.create_date(time_num); return ( (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / @@ -80,13 +86,13 @@ class TimeJs { ); }; _get_local_hours = (time_num) => { - return new Date(time_num).getHours(); + return this.create_date(time_num).getHours(); }; _get_local_minutes = (time_num) => { - return new Date(time_num).getMinutes(); + return this.create_date(time_num).getMinutes(); }; _get_local_seconds = (time_num) => { - return new Date(time_num).getSeconds(); + return this.create_date(time_num).getSeconds(); }; _get_weeks_in_year = (year) => { @@ -99,6 +105,6 @@ class TimeJs { return weekNo == 1 ? 52 : 53; }; _get_timezone_offset = (time_num) => { - return new Date(time_num).getTimezoneOffset(); + return this.create_date(time_num).getTimezoneOffset(); }; } diff --git a/libc/libc.h b/libc/libc.h index 3099b2f..94e9c8a 100644 --- a/libc/libc.h +++ b/libc/libc.h @@ -1,5 +1,11 @@ #ifdef PLATFORM_WEB +#define ERRNO_IMPL +#include "errno.h" + +#define ASSERT_IMPL +#include "assert.h" + #define FENV_IMPL #include "fenv.h" @@ -15,12 +21,6 @@ #define STDIO_IMPL #include "stdio.h" -#define ERRNO_IMPL -#include "errno.h" - -#define ASSERT_IMPL -#include "assert.h" - #include bool is_file_ready(FILE *stream) { return stream->ready; } #else diff --git a/nob.c b/nob.c index fb3b841..8f83383 100644 --- a/nob.c +++ b/nob.c @@ -63,6 +63,11 @@ Example examples[] = { .bin_path = "./build/libc_malloc", .wasm_path = "./wasm/libc_malloc.wasm", }, + { + .src_path = "./examples/libc/time.c", + .bin_path = "./build/libc_time", + .wasm_path = "./wasm/libc_time.wasm", + }, { .src_path = "./examples/libc/file.c", .bin_path = "./build/libc_file", diff --git a/raylib.js b/raylib.js index 49e0eec..ee8ff9f 100644 --- a/raylib.js +++ b/raylib.js @@ -54,7 +54,7 @@ class RaylibJs { this.math = new MathJs(); this.stdlib = new StdlibJs(); this.stdio = new StdioJs(); - this.time = new TimeJs(); + this.time_js = new TimeJs(); } constructor() { @@ -78,7 +78,7 @@ class RaylibJs { } this.wasm = await WebAssembly.instantiateStreaming(fetch(wasmPath), { - env: make_environment(this, this.math, this.stdlib, this.stdio, this.time) + env: make_environment(this, this.math, this.stdlib, this.stdio, this.time_js) }); // Init libc @@ -87,7 +87,7 @@ class RaylibJs { this.entryFunction = js_fn; }); this.stdio.init(this.wasm); - this.time.init(this.wasm); + this.time_js.init(this.wasm); const keyDown = (e) => { this.currentPressedKeyState.add(glfwKeyMapping[e.code]); diff --git a/wasm/libc_exit.wasm b/wasm/libc_exit.wasm index c005f5b4af654ee6a4b90abce91f6a04bb89e0fb..e8d139cf37a4199cf2b9f93aaae803a34a37de78 100644 GIT binary patch delta 3935 zcmahMZE#f8_1*j4?!Mi(*?q}wvdLzXoJ$h&p)wIA!je!H5F#B!g%Q-&&62z%yCj>i zy8*PyLa16=rY5sW+mlT z$*7El7p%IMdQ~gARkOCoGYSzujcA`08;Yhgu~bH(0^^SMrUth~2dsg?)J=*iP({(9 zR6LnME(E;_89Uh6DNlP=S($ZRDa%T3h<9iD@&deHAUmvhZ(l*IvBrv}hf~&iYkNkq z390&uRBW5v+NEARwlWnPu-3;1EXBbW66V(>VV#v(A4~Nj`Koma;RB?iov1a{y3MAl z#HkWhrG&U_hP%k4C^nm-dNpd(Y-ET~YEy|q?OvKCk%@n5Mpi+fB#^Y zQs$1L2eFJ5?TPnWO3)ikTN(K~is;m|iLx2#|k*2p&0UWJVLtt;EN@VBv zgd8V0!DfyMnZXEQE^wJrfnsbX&RJzNVlovdsGFGvTAgG74U|@zbt6RmI%tj5&1?eb zLOWV0+2wi(>d}kP4u;+E7BB5Ic zJ2*f$e|9w8(A9qm$vAy zT;KJ~$2H^)TJn)$ycmCOyMv^yK8;7ppz56GIAGx#y6Mzi2v31O+3`>zs!?2 zKnA}mGQ$V`=a7&rwS1D`CWayYyv7}bctsZU$t+Mo!#t)-)us6?kjYTUcj6Bf`UOrv=IN8TX%f{%D zmw9bq108*Z-x63OcETi;pU9Z!tPj0wqu!R*-a0#Ui{S{Pl_!a-2JYHKkwh)gfO!)I(iZ zInEac!}RDl-xi!l&hkTFWxEX77NP~0g_X0pH-c+@=J1+|qT3 z=H{{sVrh(mi|l+JPN(_nzFzfnR$CdGuB*n+pi3iDxsIQHMi8uc^a=rf_}F`tj_%Ff{P?XB ze)7Z^5&ONlVnQZ!_divS_bvCr(>o}FBj8sBYO@H-nKzF$ z!3$=B6+^MOt0j1We0Upt8RiE+_=Z`jVDqywD1|cfkkk{1WLY@`SOt``AXGqbC9A}n z6oN_!ZDCb(DO6ovq##o@8dTj%LvGc`E2}{^fNTvwf-xkrR_YeF9W9=N+d0T9IYX>A z0;~>EbqR6n3IVD08lO|r^kqQ)SBphgMTeDbN)wIGyhm6rjL?`J+ucQqhP{e^xG#{^ zL{$HOat&RD@yjfOjo3MX3N2inp*5bg%>+%uDlu&pa%I2jzJk<0iF~ zLa7LPS$-FQfKXA6QZQ;zk-)$OAc(~-3uREAV3im=e^`-1bry=aSQUgYfK{vps-b2j z13Zec1Ga_DK?CM|VSwmK=NTZwCIU;0$b@{b)MI?-V(pqc`)J9s28>VxG8q_mVP_*I zU=!k+608}T3-NCB8kp2>k<5KEnPq7gF?2*mPl($rdOf}!%!g%S;Ijyv_)f~_y{o{3 z)gE6+2W5-|MZuac;%m#-d{04{8=DIyAx&3|j=gkkEX5U+}hyhHN9&aiO>f ziV9vM(E}d&vOzp{i~=6r&o?C#Od+K>zr$KDzJw2o!IxluJY9;3UMfN_m6bu6;KmPT z?v^>&5>-<(`Pe#}2U84ht-^L&vh z`5pX`M^sej6AH~c`I@QK*xB|^Jx;#MJ5H_f+$Qv)Y?+Uf{Gn6x$xiRJgaVZ{Vn zg-jjL0jn0NNPg?|dh!mx^vsp9M}-ND0`(fkF}HX+>&9VMB%QWWnfPE5dSdvN?}k_g z>eCR0`nbzkpH?ov=9;zFgkgCsnH z|8TSBIZ|TWMW3oulqvlCM{e}bZgTxDo0h~$g}kQWO&7xy`RW`+&l{oC^QR}xz0B&3 zC&lc8vy{!dyx)qYmc_a@Y}&E~Sgm=n-?a7-(=qkH{UvceUO zC*%1kCwSicQ|ZZ5(wS~K1BJdm4pq6frt`*hZK^I!XEtTiLs2mqqS$DEd?22&x@-K1 z7ibJ+e>5|Qwxu#@Fbi1pxI3DT_a<4%*Z5G(oWLwj_$dz$ZnIJsx70ccdh7IA3+in> zL&K3wdai((t_FQ;Pu{dfdrwdQaJsK)c64iYuEOsn$IA=6(db|*j^6-n6Z71K{J@(d F{{d7YJx~Au delta 2324 zcmZ8jYfu~472bPyCG-GENQj3e#NB`clS~qfYizKFv8Wrz&Jf2n^(&oO7PR0Mk|3+a zj~NFkI5f1T4dU8P;zvT_)bTiNOuJK@NsH^|Ror15`lB|+`9Y_hj+@MM=uA6pW4r0O zE8%gf(VnyCobP`3+`D)6>COy)=6$}FlT!)AaU6e2f4O9>^>ryb-lOBG0RDy0B`&ra3#T3AX@ z4yZb3-nup^`t~kOQIb2=sJ=JH;=Y%BLQ#A6=DD41ikuqIly>ES&RH3cZKEddH^TyR zav1iwCMT43HKA}e+JZ!xHw)Vpy*Twk?C0LBC zD^j-_SGZEQ$))r0o-609Us2M`?n!G-C9Njp$?DH zn|uh3(J%P{G)en~iQ=P2GZ{{_;0<^Ku@rHhj3HVcMd*3@wDl_3s)FNX6DDLQ;p?y< z?jk$Mu9&zxGD&9(YV$QISL+}W>4=Fk)Eu^!e62TEi<4dwkBJGWNw!*al)h*SK?`SX z>jOFdK{7}V#l&=k6EldwH{FOQ=pEahV6Md8wHLhv_SK?i!8%=Guur%)gB^E0geHw?mmNXyTlZ?Px7|Cye%sRkcG%Ml_Oho1 z>{lK?SbuRF*skJ>U;|!;-|A)fv)+whzwokAAs@5bd~EEf?-}UwmT%m9Uzg`FIftRo z(UL>u_Z}I0U~IuQ(MqhIEG7O2(Ky}Ye-c=zf30hhJ-FQVS4Jl3y#K#YxL&IG%t9e@ zI@#rR9>b^-PDm;JTNy=^4wYx|(hT)i?8I|dXtJV>Mbi}(ESj&lS~+)x9hs&`x!6qB zk>WSo@4aG6`gn~OKSu5`0q1xcOX=HjBWOc2oj6osd$N(6gP8F`eC36 z|07Fh0`+K={wGl7zlW;<+)A>N)HHLW^pRjQ{&$wD!AH?K`bzLV*jj+CgAUdwPP7`-4@Bv4>tc8O&EK(SeIwL z3t8j9lfweOn>D`Lx@199bm=>vv*@!OpJ4Fxt=-emOy?fW0_=Z~fZYgp)FMW&$bT^h zwso)J8T18}%}Sq({h1MT_3koJ)A1pUFOASh-ynW(#Q06$uidOXlvaZFk4D(q!;uTd z(#b4FuNgzHmGS63dg6`UcxlA==No$vc)IP3#=?)!s63i79(&s%pfRKQo!bap<4-p; zmwESdjOUIR@t-|s`Y((uV)5WFiV?~fV^b^PJus#&4q|X?-XCYt%rCtNP0*Xag15#f zpWeoJVwV6hX8iRsAjXVCAN-uT$39B1S;CC@rTbw=2qUco{ zOh*%+h9Nlr>2ZW!rIFu1Oe5DGM=#TnYir;~;L^3`;EcI&Uu4+yC6V*I=qEl>Lj0Z~ zT5^309B=9R1$3CY=i6K_u!9MQ$Uz)+I74Ie4QQC2p8sxB#{9(#LaCBqQrU$wxYI7=IDjAC$?ZRzvUMg}@4v7-%<; z4Hv}-+_aKb5^3TA^z1@_VSltx%G}w7b~tXg7oIA8lW~ifV7JqGq!3!j*qpcQ^!!bw zfXjUh=Vyb0YpK|I6zeq{HwM>FjF%S+QTqi!NP=*oj8Mbfud3*4f{K^5lrL;mdekJ7 zKQ-ASxW5@!WUW>1>IL;3NJcHDz|y;a97-2;E1ImP6y-pd(yx2GQWDft8b}VLl&I7R zlGR)6lH_Pq>X&fK$PEBqE%z5j;;no!wtj;+=l+_zuRR;{Y9D#*`EmZev;Z-Tux|0z7+mZUySg}sCs MnI2cuFaI?3KU7H>1^@s6 diff --git a/wasm/libc_file.wasm b/wasm/libc_file.wasm index 85a3209eefd787fabebb89d5dbf924d45aecb803..eb7444809769ce02b60e3dcf88a6b9913de6126b 100644 GIT binary patch delta 3076 zcmZuzYjjlA6~5=*JMYZQ&E!RrnQ$)2Bq2};F$p0=>c}G?LKP@MX}L@?cajP7V&*2m zTGdHVl!v7W2M`oByip!Tt`E9eC95o?1_i7kyyRhtmZD(lVzocITD#93!U9)+%--kh z{hht{Id`8kU*~1+-78!r=4UByTh-hkcS? zRvMb5Xe<&6#ASx3J}XQEVFe<9YD@-Ac~ou;gr~&3%cx05VfM*E*_((x>TOs8;akGK zB+^zZD{~uSvK+1p_>`t(1@?Q!>2jd4X{au+PK$X%^1MJuX7n_uWtQxXx5VUm@^U3v zjgcnRrUnWyPYwI-D~vZ%C}cSSHzFEz)d zxU5KWSb>8;T%p^@^Bjjv9AY@0V-Yg*mK3Xv;dw}I=K#X#Sf1CRC}LS1pjf?~O(4(U zKX^-m0Yz>jS52BeU*jUL@WvFC%Q2I)i@w~gbt&I^) z*o1XLXB&)jJV-QSvjF2Zh9NJV^`H&p)Y--CMnX#abI_Y)X1|Lh*h17r_ON*%kFzbP zhfL(UQg>~l!F22+>?2rbWrTM1J8ld@D@m^I6v&&p&8VBS>oWlUvc3q$N44=;{iLjJ zZRrxs6|=k;#7l6nSqyo4NQt2cC&R{*J_X0I(k!-k7_k+%;MQuUhb%QrgkT2^*&t6C zo^~b|tVMJMBd$XjhU-wX_!5GM4;vfMF0$R22eQYQjrNg?#!=`1(VLE=jpS2POn_3_ z7%q$Drh`<~1PmE!`mdEWZQkOIZrCKcxm_nso-qUt3F1kGk4wLNM82 zdkEymw)r4k_A-!9*sDRVvro$Eq5Gvd%EeC+)mZ$DR(H)l3lL+34?un+(DgZ~bp6uQ zDIniZrBVK_NvDIxs&g!as#V7Z$9+}rWAQ!~>aI)s&9HmlgnkivAVyJ-^};6dZCWAP zOdRPmA$s z*|uKtVon{pMy}?}rjxO`*)W-rdm3c6GZ$?m70!CLgOIJxQntO9oOI@8ZX4>fRQQYz z?7*qj47h%DPM~d8?J8xr^^&0LK41X=-Pnx_su^%~xhAk%2)X1MgN_h$-tdfj0mlQb z3RmIr)yxrfQr<7p(2r#OxRq$Tnp$=PnR^KB(3QNWOXbRWgmw^P#VWK@U0;#MvD=7x zsA|6MF6c!)fNYaqKxmh`>F4eIUGp9TnDLakU?$2`KiWwyP5l>L+Ba?f5ayiG(?!Z> z?uMhgI8#5A^*>-$Z$7??XI~@g(kBOXsGro=-K4YG3qEE+lgx!5LNR>{V>*al>xJm* zA#V|);m_57qb)qzSiw=~KbvV*^8Jzl8sKbjfrc6zUdf{4Nz^=KW&6`Yp<1+Gq5{jM#|v*dXko0pOw3 zVH3QY^v0%$W=|4h!4`Ni_ma!~PeIdwAGOoAV;i;$uWBm=coT)GR>pH$b0r%; z6+0l|o^$!=InsOX8K`*r`Re=*tx2ueDkQ6h+HBZX3|E7eV26Vxfs)zQ0zfa+}G_j`!{$UNmdTo4I^BX_S zvzWD8EPJi+Puym-thSKb1Lb+1cwCMtfk+tpz3`Xs!(Iiuc443b3WJcVIV+?xbZ=)QS{E=9u z1sDymMa`LYm+lPX{Xp}w^}s6|LeU&O@Wr4U&ZQdW)17810L)CILaqmhQJyX7i7UWA z;iQKDlqX?xYdl$NL%m2+Z)GM%q{o%|cvPZ1Dkv!tC@rSM^M$)sV4^-L9%u{~IDUeI zV%%9nHo9qTab%es8&_Ir97Ue*|dqs0DhzKiCp)8a>3{ zex~ySzib$zsrXoZOa@}?E9L!i#6Qj&fJ3`S`pQhT@O3qw`;c9dBC!B4Y1jnif91q} Hd*%NC3YY|q delta 3023 zcmZuz3vd(18NS^+$$D7QS(a^V%VH1P*t`t*A;2XB@p7O*n?Nv-hO=y)jBHCXk_@B` z$T$$769%I#kAyUs7F^;s!Qlv@BrUXsG=`AS4B?d~ybO~ekD8gzG!#Pm@5xR=rZcC1 zZ~w=)|Nrmp>O1%ezvW}z&3U6i#Bm(*i8XvY9!K#S4t|KeU~P)xoMz!_IC#*i8eKfT z#XTYZCKh=mwA?H&RlLn|H0F)OIK(uma(yJcLJlgyaO5ctGgXG{ZEjXVKH0Ct>XypQ zk#H~&RXCp6EHDj(Vt@ccJtr_-itLR>6#&#}fK!zEKxkUTyMj6BnaVb`uu1Vorg-Zb zVX>BwFBxa8QeyM!B8n2K4)|hAIYdR2(U8mvOfw?hpfW!YRJardVxFUTqb(6-zOpiw z%*DVK(WVCGV45ECJ+Q24W+)J=4upK+75%BrQ)2VIk$S-X={!!Ln^E=@fiEn;STJG% zipNM0OuRYOVuclWp5w6%a{|VC#0xsqj4;;mh{Jjtjw8>R+k!dHdCt(!kZYo-4|kJc^Ak$p#^nNDs-f+-P+p9Njf|kPbNAGC$_57bR`I_p;7&NAg82k z%WBtLstI3=1!*CvCJP&+MV=1&uau&Go1C=O5Si38NM5jwGEC~XH70FMq>(f=NI|f* z8H&(a+GTJ-3O$A&CY8ru_qf1OD&=y)?j);j?D3Iui@pvhpHN#cD(_xn(N@=@J)!Y!ORA?h`9PUKb~2 zb+8VxHOi%T5gUng8hJYC__R6T@od@~ASc;be8kS;d+gIdTGJVdN0YI1hP6Na3CP;) zNZ7xZ^*&7YVaR*G#S%v4aT3c#xDrQpD{P<;2l8x+do&`W2m>y9HnAp_g;3 z(J?yCIoElm2g1zI@f?CljvEX7WP;gek?T1|cRSw)w`F;`=y|#+uNLb4frIG{YG{ChJJ4vhLuJ+Js*983U1WmZcxbJBQ1Y9IS zh_p-^LWT?=us!`2p#TsHNg*kyjw?o}F_$TS;GQC;ahF($wWuGEb2W2>If~Qq|qC!Au7p-xxgPz`W zyLfyrq3SCa==z=3>%qzY@UsZ*R==3MM(9^}rht0o^m(AB@6PbUu9Q{%hlP%OWWj*X zd4s2wJ~w+W0GH0u53Kq%Xw@lm*9rLRgxd31pAH?OM;6{>GvC1hvE)Q-__)Y-eUcyyTh_AJ7E8`YzG79$vGZfAr|H+KejbV$AP zvPnSgs_^PvgxU{u&jhK?dhHfQXVi*=tJ!eyPy)eFb=ZzjtGf7)g$Q-4tw+Gtt$y3XI%vSnvxm`6y6eLr>Y|o& zagdwN4N5z>f%TveK9QmDkqs3)>7jF@`9@@@*8D5ChS}Is2`4{)|LNjBc!59jTJZlk_nYGck#K=;HH>;5;2XKXv4b zTJvqhN^If|EmDN*TAXg-Jo`0M^5~=yJLHsqAs@BTstc>2f)f`i^ZVc~f%8W!VpsB{ zac~f=#gHM>!(kM==#Yz5=o#8@aV5lDzgU5`((Fr>&i6FzbWg8Vx5LxLOBp1cI7o)L zmWD6Qf*az%gI; zHw)y9-WB+p4fJTQYiL4ip}~{fK_l$GQG8h|#smv$JMG5DDSzX!%mbPl6Kpe^*IO{> zX*HNXHPOZ!6nC)WZgX|!8qug@npd+U{` z><>rM&A>>2;AuujKXu6v{J_OB^*{ydg3VcapmA=o^6r?K&Lb&lk)(_iRW6A zrf3W(Baj~F4>?bsX?awmjsCh?S4K2e8*P>ug9LcFDG&_A6yIP+zZytVlN<{}u8~-j zi2Yiik3KmXs1Hf@ANWOM@yL*@0VQjL79C!pM8=NEHw-LXpz}Ak#G-}TP&ZVcOs6Pi zdGe*$u-u<~8>aJzf&32F`~6KV(WN5>*xE>)A9!QkC~b(A=pzd7Ti!Ku+tiUEw#yVI1&Ix3}rF8S4Izf+4etnCgxWF diff --git a/wasm/libc_malloc.wasm b/wasm/libc_malloc.wasm index a9b3632870d796da143a22abd6f0c9cdca96819f..8c06e4066847dca0fe6dd261732d8b5f55d46b8c 100644 GIT binary patch delta 4735 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 aPE?V&g;r5)5BcH5fSqZ|BKr3S+y4heHuxR@ diff --git a/wasm/libc_math.wasm b/wasm/libc_math.wasm index 37e1fb48413c7411b80be8815061f6860f29db73..d215f41704bc8809e638b66fc98f5ab4582e3d76 100644 GIT binary patch delta 4504 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 delta 2753 zcmZ8jd2kcg8Q=G`vQA4YSu#St-r@sy%mhP%0LLa4HkT7xGInC)cDk0WwUMmDkz^oK zK;|%*BoJGVBZmVfA>e@=PB#G(65_OJjs{5DKRBC~Vd8|e%?z3T(JM^)y_HN29<9Fj z-M{a>=hZKDPBVH&Gn4bh!-(TJ6tJ~vlF1}WwsG(vwqQEf#&MtxiTOiyb3DheO(RFv znxr+duSbd}e6a+Fn8hr0#iHw^upExY9_KJK=_Fq~E<=E3=yZ8f%S@JKa-y*#Cd-lL zfIqP&ooc;pTrLN?)?^B5I-+qdOKrAN_QiW+a+AD1!ReSqUmx?WQ&l}vHSs_s9m>ai z5q|~{R9zbLh2^F|Smq21S)g%A#LrR#kuHu`4J#snL~|hGkFMi1%wTSm6HUHY7v!#L zbVSmru0)*7)EBdyk?GiO_@oWLU;uSGowJQ~E|EGteT@69iGQ<4Kgze5Gp zwydx(6pD6mPO}7)`x3I$83@Uo%PPg?gu0f%?0=kd>%g$Ky|1=&X z#@U^AhDbLF1;wy;{1n}$FGGjvaeX0!@tM9VFWqAk*+e!3#U$YELj*oa4<4h$&hCv?A|9hCnV3iDLtth7UX4nfBAh`{GLG{D*0PA=qesooV-E?`Gmmb`KMkmisXb8MZ9PfcT{4C(vHGZqXx_ z@ptQ77DI$bSj;+M4im?Oh0Hi1)VRjkp0S4aiDwa$L_CMso>kc%Vle}@6Rb?FT`iNa zt7Sg3*Re7}4pbYZb!o9SM=knBPAkk}cBJf6W*Nm~6vH%Qjt#Ec2g#0+ZHr#aB3S~Z z_0BT1hju$3WVKH@J=Qcf^)w3@q+8Bg%=JUA->$mM$Yf%V)wCC*l(U!?x^|$w^oVN+ z_0a{>Tky3{X=?gPP_9jPGv$Zr=b1R`cBB3D8+SVzqz!p<;P!0DD{}5r|7#=qvk`@0p7+%XmDc z>}t?XHoXOAW%$8<9=)KV zz$UKtzOFcihcFsZjvSb#!IyT@_Ybw8LB;jr&k>wT;-xq!H(m;A0G85p)WD-L<(J3* zi$Ju#x`K(rul*I{n@=i(Z){Yh_01u~^cUZWRcc*Re zfAMtcz5AI~^WG{}YxkK=7)165DW;A5=GRO#ei&xP4?coDA5)fpf|zLd^ruWb`}-jC z@#nTOZQ#5fTGFAv`K6V)+t_s!`q{T=B$yaIc)hTl9=}xYzHycrbKq(@ zh@(Q2R-I5~2Q^%-Fe++!xA*2*y6EyW*P-;izNsb^dMm{uQb>w~0UEx%!>wA~-by#Y zt} z+PjEK*4-RM$LNXPbeowxv_4_D%}R`nkeF01Vm42uA=y(1h{gDS?qR)ycEC^ESB|7D zyHk$&0&!Vh-y!!T>~<*v{734I^u}es)DDcIJI5mV{C=s&*CofL&S=bG0y+`NIGq{Z zk;``i-jWqdnglPqfE- zB%pq=kQ|Xhfp8!p`wJWyGccKul!yYRSR!61WUR2cekmU4iWJ%Jii0wQ9-MH^7Im2( hGbUM3v0)h;s7m2VtdbOs1>nG-I-^FVRQP(!{{X#~pI!g} diff --git a/wasm/libc_time.wasm b/wasm/libc_time.wasm new file mode 100644 index 0000000000000000000000000000000000000000..847fd12aee187b7ff9f001471e8c4d1974c95e10 GIT binary patch literal 59840 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 br^xrX*=yrVg*}YX)1OlmKcUW^2y_1zCIoE3 From fb0e7cf1aa592feeccd37760db8242f76bf39dc8 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Thu, 22 Feb 2024 00:25:31 +0100 Subject: [PATCH 3/7] Remove debug printf --- examples/libc/time.c | 5 +---- wasm/libc_time.wasm | Bin 59840 -> 59744 bytes 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/libc/time.c b/examples/libc/time.c index 9d5680e..c6aeff1 100644 --- a/examples/libc/time.c +++ b/examples/libc/time.c @@ -21,12 +21,9 @@ void GameFrame() const int ch = h / 2 - (font_size / 2); time_t t = time(NULL); - printf("%lli\n", t); - struct tm *ts = localtime(&t); - printf("%i\n", ts->tm_mday); - char *time_text = asctime(ts); // ctime(&t); + char *time_text = asctime(ts); sprintf(buf, "%s%c", time_text, '\0'); size_t text_size = MeasureText(buf, font_size); diff --git a/wasm/libc_time.wasm b/wasm/libc_time.wasm index 847fd12aee187b7ff9f001471e8c4d1974c95e10..b9836d10058ff7dd5329c02a42f6fe0297597692 100644 GIT binary patch delta 527 zcmXw$yG{Z@6ozMKfrLQfguBb_99U(!C=2SCY%H9Ff&#VDS1^Iz(xtTX!VB2j7%5Dw zd<3JF2{ANUXyPNNXI7nJ=FfNjbLOAj`zLe$XkLTKKW?WL6Q7fJAv5V4$5p>Nrp1t{ zhsnXL;tW&@L%<>Au^p0Ol3|bSs&4}$q$3{N1MaZFHZexASZ4DzDRsg zaz}FqEt;7pl9yahu_PDj>qNh!pzc5QSyTc`R4VyHEJG0rP!?BulJ#c*N`L@>;yk#Z zLgtF(w!WZ`Rb`+JRj`k6NfR5FiPT^jYDeh65;!BQQ%7BL&~?CuKDMx_-VCJl(DGP8 z)p5lqz2dQ=+Qe0os~#)qkJ%>O_E`Bhjip?R`dI;8;;!Vmzmy$H*;P4QBfK`mb?86? un$U%HaiL?2iQd%%!wqt53{ir#360r8?AVCY-<`g`92!yfzoz^1QS=AA5^!_? delta 610 zcmXX@J4_ov5MA$KBtFFo8!!i$85_gd=5v7AGmAfrL_tA;Qlz3tK>>%8R3Tk1Wm4ti zCQ3z5gK(3QK1~!VBnzl0QbaUqlgysk;^y6ZZ)VOfh;|=%Q6S&UGx)C)hqGqU#s8fIe!@!7!eXJ_usu4|k6321Lce!8G zaD#;nEvt{$FdTD}s#s&X7GfO?tU(1fp{_pL*s5*6^dPXojz)-0Xm(!Tyh;odTCJl& NQ8*gx{JA|I_zx@|hzI}x From dfb6d1d1cbf2186c4ca851abe5425c1729e3a44f Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Thu, 22 Feb 2024 20:44:52 +0100 Subject: [PATCH 4/7] Fix math/stdlib ll fns not returning bigint and impl setting errno from js --- libc/include/errno.h | 10 ++++ libc/js/math.js | 124 ++++++++++++++++++++++++++++++++++++++-- libc/js/stdlib.js | 4 +- nob.c | 1 + wasm/libc_exit.wasm | Bin 58492 -> 58675 bytes wasm/libc_file.wasm | Bin 61236 -> 61419 bytes wasm/libc_malloc.wasm | Bin 62068 -> 62251 bytes wasm/libc_math.wasm | Bin 59026 -> 59209 bytes wasm/libc_time.wasm | Bin 59744 -> 59927 bytes wasm/tsoding_snake.wasm | Bin 88576 -> 88759 bytes 10 files changed, 134 insertions(+), 5 deletions(-) diff --git a/libc/include/errno.h b/libc/include/errno.h index d08fd85..61a8eed 100644 --- a/libc/include/errno.h +++ b/libc/include/errno.h @@ -91,8 +91,18 @@ #define errno __errno_impl int __errno_impl; +void _set_errno(int error_code); +void _add_errno(int error_code); + #ifdef ERRNO_IMPL int __errno_impl = 0; + +void _set_errno(int error_code) { + errno = error_code; +} +void _add_errno(int error_code) { + errno |= error_code; +} #endif #endif \ No newline at end of file diff --git a/libc/js/math.js b/libc/js/math.js index 9768fe0..d6ad697 100644 --- a/libc/js/math.js +++ b/libc/js/math.js @@ -8,6 +8,94 @@ const INT_MIN = 1 << 31; const UINT_MIN = 0; const SMALLEST_DENORM = Math.pow(2, -1074); +// ERRNO +const ERROR_CODES = { + EPERM: 1, + ENOENT: 2, + ESRCH: 3, + EINTR: 4, + EIO: 5, + ENXIO: 6, + E2BIG: 7, + ENOEXEC: 8, + EBADF: 9, + ECHILD: 10, + EAGAIN: 11, + ENOMEM: 12, + EACCES: 13, + EFAULT: 14, + EBUSY: 16, + EEXIST: 17, + EXDEV: 18, + ENODEV: 19, + ENOTDIR: 20, + EISDIR: 21, + ENFILE: 23, + EMFILE: 24, + ENOTTY: 25, + EFBIG: 27, + ENOSPC: 28, + ESPIPE: 29, + EROFS: 30, + EMLINK: 31, + EPIPE: 32, + EDOM: 33, + EDEADLK: 36, + ENAMETOOLONG: 38, + ENOLCK: 39, + ENOSYS: 40, + ENOTEMPTY: 41, + + // Error codes used in the Secure CRT functions + EINVAL: 22, + ERANGE: 34, + EILSEQ: 42, + STRUNCATE: 80, + + // POSIX + EADDRINUSE: 100, + EADDRNOTAVAIL: 101, + EAFNOSUPPORT: 102, + EALREADY: 103, + EBADMSG: 104, + ECANCELED: 105, + ECONNABORTED: 106, + ECONNREFUSED: 107, + ECONNRESET: 108, + EDESTADDRREQ: 109, + EHOSTUNREACH: 110, + EIDRM: 111, + EINPROGRESS: 112, + EISCONN: 113, + ELOOP: 114, + EMSGSIZE: 115, + ENETDOWN: 116, + ENETRESET: 117, + ENETUNREACH: 118, + ENOBUFS: 119, + ENODATA: 120, + ENOLINK: 121, + ENOMSG: 122, + ENOPROTOOPT: 123, + ENOSR: 124, + ENOSTR: 125, + ENOTCONN: 126, + ENOTRECOVERABLE: 127, + ENOTSOCK: 128, + ENOTSUP: 129, + EOPNOTSUPP: 130, + EOTHER: 131, + EOVERFLOW: 132, + EOWNERDEAD: 133, + EPROTO: 134, + EPROTONOSUPPORT: 135, + EPROTOTYPE: 136, + ETIME: 137, + ETIMEDOUT: 138, + ETXTBSY: 139, + EWOULDBLOCK: 140, +}; + // ENDIANNESS function find_endianness() { var double_view = new Float64Array(1); @@ -110,6 +198,7 @@ class MathJs { if (isNaN(x) || isNaN(y)) return NaN; if (!isFinite(x) || y === 0) { this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); return NaN; } @@ -120,6 +209,7 @@ class MathJs { if (isNaN(x) || isNaN(y)) return NaN; if (!isFinite(x) || y === 0) { this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); return NaN; } @@ -133,12 +223,15 @@ class MathJs { } else if (remainder < 0) sign = -1; else sign = 1; - if (x === 0 && y === 0) + if (x === 0 && y === 0) { this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); + } if (y === 0) { this.__wasm.instance.exports.feraiseexcept( fe_exception_flag.FE_DIVBYZERO ); + this.__wasm.instance.exports._add_errno(ERROR_CODES.ERANGE); } let quo = Math.floor(x / y); @@ -205,6 +298,7 @@ class MathJs { sqrt = (x) => { if (x < 0) { this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); } return Math.sqrt(x); }; @@ -243,8 +337,30 @@ class MathJs { floor = Math.floor; trunc = Math.trunc; round = Math.round; - lround = Math.round; - llround = Math.round; + lround = (x) => { + if (!isFinite(x)) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); + return Infinity; + } else if (isNaN(x)) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); + return NaN; + } + return Math.round(x); + }; + llround = (x) => { + if (!isFinite(x)) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); + return Infinity; + } else if (isNaN(x)) { + this.__wasm.instance.exports.feraiseexcept(fe_exception_flag.FE_INVALID); + this.__wasm.instance.exports._add_errno(ERROR_CODES.EDOM); + return NaN; + } + return BigInt(Math.round(x)); + }; nearbyint = (x) => { let rounding_mode_before = this.__fenv.___fe_rounding_mode; this.__fenv.___fe_rounding_mode = FeRoundingModes.FE_TONEAREST; @@ -265,7 +381,7 @@ class MathJs { } }; lrint = this.rint; - llrint = this.rint; + llrint = (x) => BigInt(this.rint(x)); // floating point manipulation frexp = (x, exponent_ptr) => { diff --git a/libc/js/stdlib.js b/libc/js/stdlib.js index c80365d..d0dacf4 100644 --- a/libc/js/stdlib.js +++ b/libc/js/stdlib.js @@ -420,7 +420,9 @@ class StdlibJs { // INTEGER ARITHMETICS abs = Math.abs; labs = this.abs; - llabs = this.abs; + llabs = (x) => { + return x > 0 ? x : -x; + }; // MULTIBYTE CHARACTERS (UTF-ONLY (LC_CTYPE=UTF-8)) mblen = (mbc_ptr, max) => { diff --git a/nob.c b/nob.c index 8f83383..a217795 100644 --- a/nob.c +++ b/nob.c @@ -106,6 +106,7 @@ bool build_wasm(void) nob_cmd_append(&cmd, "-Wl,--export=__heap_base", "-Wl,--export=feraiseexcept"); // libc nob_cmd_append(&cmd, "-Wl,--export=malloc"); // libc nob_cmd_append(&cmd, "-Wl,--export=_create_file", "-Wl,--export=setvbuf", "-Wl,--export=_set_file_ready"); // libc + nob_cmd_append(&cmd, "-Wl,--export=_add_errno", "-Wl,--export=_set_errno"); // libc nob_cmd_append(&cmd, "-o"); nob_cmd_append(&cmd, examples[i].wasm_path); nob_cmd_append(&cmd, examples[i].src_path); diff --git a/wasm/libc_exit.wasm b/wasm/libc_exit.wasm index e8d139cf37a4199cf2b9f93aaae803a34a37de78..16a5f13977ef79def316d3c0d300fd4909fc13e6 100644 GIT binary patch delta 1116 zcmZ8gU2NM_6!x*>#7(v(Ym@#ZwAXZuvW`)HRw3A?O%yi90}pIMJ@vbPJzX<`I0Eo9>M`acw!2&B3`4L$PQ-`^fac&o-XqXzgT=OBe-elac z9LC17tmI1ZV8O`ei&?329nErPxQv=so=K@_J%fLyNav17Jt0gvnkk#oK%ih)wzRE_ zQp?U+oMl~Vmc^jFsby>U-!Bxh9aQmbM>0v2etDf9*dysGQAuD({{EfGNhun61~fk| z+LO`VI;96mkOa6MLa9bH68c{%((++AF20qY10lMVarj7_P@aIQxS{kw)w`**11x(R z)pIheh_6CB5&sGuKzv%;3CrR&EuCEPi|P|(f{Y*1D_CI?2(HSIydrLCX;eMmGJ&|% z(vw{FwSL=ieGX7M4+Pg749P!=Xm|jA7LSK7!L)z~kIhW_TD4z(RPQ5wv1#vUB&T8Q z_qOA$YhnvBS&(DX;*I!tXFa{H%DaiWzFtQ2ZyuWwB(WJzczY9%De$g0)wx@SdGSs6 zmxyD@(}-QElQ8dHNd49Zr@d2yf6H)2%shMy-uF_E1jBIF>)Z8{3TK5pY$9h3|C7Ki zljc5GqdvFe#V2>cIdAIZ#fRXO*t2*P@zUZ!m=npX$6!I6xq1QK6X|OO_*h)NRzciX z?Z+?wa`ja>FaE6R@S#Z54xr{xZ5X4U)jANrt9^~k>r2~VR$N><2yct{_5FASdi@H( z2i}$+dS&>;+kfMQU}RPe*hYcDAAtwNr@t&#)>t&Q#-STS)NmZe-PT}}*=SD`0ZQD&0ZH<#}c& z!{}lQ9gJ2_-8KYwZD>RsH&>7L+&L4y;Zdj2TQ)-yj+=2xls2-`yj8GVmeb=+8iy!P z-6Aa++;#4bIhBSwkF!M`YsBtry+eq3Hg&9W{>0YbF22I}gM;^knsqm8s~y~{nx(Sq z^w+oSecGtm=xj^SH1lQWrGeG)-P*Djf5TJl9P$1rrA2OyST;825A`;2^Vg~W0OLZ2 AQUCw| delta 987 zcmZ8gS!)wf6rM9lrdg_uvFW0N2HsK_xPXcvs32&Ywr+@sxcmW86!By!E^zto;rs4A%jLWF6UWa-j{d_S zR#oD0SiGUlBgJ_k{1CC1kF7AY*$Q|q97~XR1g{xTaTn^80 zkFye<*OfVAE3x+KCoY<4dpM0XS6XNuEU~2+g3Kf1zS0PcOIO@ch3(HMhBar6K@Y5ge%xMbQ8Mq z`%oPEuqE9__$ggW&+i}ZsJ@h$RPo3z*;6lOM=n&n%Z@(Hus+!*d;OR3#&8qe_l&Hd zo9jkO3DuGN#LO670H<;5Xfqr^dvpzr_iOYCz(xD<%PJAB*MdVNkh{ubwWXFE(rWvv@oUMWZYkYT+hR z6GqTSj??pEN#2^JPSxPNOfoGa#`SV9({wH8%t_?gwm+twJU%CxRy1qeivK-4#oKD; zdW(cBgQgWWlZ@rkvX~avEFP^Y&eN1O#;gSOW>}`|&$BW53e416bS02y3dasoo~hXQ zp=?uiLB7Z|_gJ~Lnc;3#b8Xa0sv1j~+h>mbty!Mc^tP)Eg1REc5{A~I P>C{N(!_CHl5Bq-u{~uq4 diff --git a/wasm/libc_file.wasm b/wasm/libc_file.wasm index eb7444809769ce02b60e3dcf88a6b9913de6126b..2239a0c37cbb295e671516f8e2babd784063f167 100644 GIT binary patch delta 1324 zcmZ8hUrZcD7~gO2cJH_oSgv=#fxv9Ra<;X${5kuAq0&EzZQ?_%4Zq z9&HVB(4vMc4$I2oSkyDpl40R(nay?x|-{VgMrH}aIaEZ1!df;=q;An$!`mduJ#;q!6 zDZr%FB#iSgN0(hKES9<7WHIh;fk`^$Zm*oP_m_K7FX}lZXV?yXfY``{`8irs(9Trv z7WA_CPeFC%q^(7c5bu|Vfl03bVq+M>{4{Ow?1EYPj^{26(mJm$UGB5BLWtil*P>c! z(3G=32Yg$&Nghq|(jdL%?sVzg52N&A)f|hjRgbawuzD0mt@AY-+u&16 zZTyR8RXQ2I0H0YKVbKE<*6*#W0!+~F4=W67Jo0ydO}pRLZR}cyjfv4iufh%M*!8a( z;1lXuJOLy0Oa4Ey$#ibB?moJw3S>^WMm*FODzkd^5%^qH2 z7nBYaatD6+(7sCvE2IyVAfH5O?Stzq(cK3JgEO|Yf>A}ND8yf)wz3!%OEYx)^4CoB zaJdjEP4AA7t>o7zYR%T$#>iRLx!!3I6r^hUQv)a$32iH3GnQrL|66yvr`yP# zHQG@dFw71kg>f!Bj;jgPB(XYw9?mec$FZ5jsfcbGFGzVf&RPIA)J|=OFOO{MSf2W_ zP0VgA*~Q5-MBleJFdldt7hio6O6C z(n-wd-t1)T6LoTiRjk3OkfhRBsIoFX?MzJtN7w@%)>&vS#yF{~ovOwzVK=ETz4PS! Ef9(Uz-T(jq delta 1159 zcmZ8hU2GIp6rMA?Gy7Azoo;ta+l6+<+Ok4btflfo(*|oJ55`2Qfy7K^XYbUJ-Pz5| zY%NK%TbeX#;)CTD!3CNYi}VMuX29^E#-H$_4+KS4plPLwF)7g}jXoGWyIT?=nSA%o zcfOo^?z#87Yb&k`%dW+FU|U=0dD#7O&c`Q7GG!iQnM#eAif$1yq>{AF)bL3qkw~e` z#tpJ+62&I6rY8uqxk|Q(U7E{C#}6`19wY{18I5UkCl%dbI%te-_qF?fx$J7mf|tVb zPWp;#JB-t}Tra_4y5t&$Il9li8>Z+xwt|%Ll@_^Fg zAmW#YPIi`F^>2f-^k4sFn4n)*m;y>s%SG9pQnT1BOgOz8;$Do+hYkn-7n^0pSyq^! zFNBBdO6etz?H0Mp(lTC&7kS|bT@AOwdycO*>#oli(<1E_`A#+@x}$8JV&N3M*Et3sIAhQ7e(cga zJ)Eowe!D+OflP*ZLt(?_C>%SvvN^C77gL z*ORb7&tA_VwiTjyF8zf=@F6V}BsfF=Da?t-OT`PgL7}&j>ACWDaWB=_$e>s)28D6@ z)sNGdD1PJF`h}vj0Yd>X5M?K5QCTHc2@CYg8(*Mi^yUsYMlap$hj(e<)*d)Y_uV=N zla6O8!NNIeFW*H}Rt}-`=an>!J9~e66X0XIbbBivzh|`xKB8Mzqj27Nakbk8^K|@< z3Xb#Vor`?MRnBcFNdl+19rWVe-*O&Vu`FWR)qL924OvzRmNQ1i zB5^r}*Ze>@AS>~>oK^;iC2J|OwgT_Cu^!yGZiYIyW)f0g^o*KJH}IBiCWsL!j`*M3 zfp8f}-5 z?G)B(+E%l$&L+qvB`#a~fbnSXAtB~zp;vyd%e8v%ud;>H(iz)|mIn1P@1Ry*eJiJ> z(!|)tYg!^>z1DW$+mCbF0I}64N`v(zZ<05#JKNnFNoh}2>ew=T9Lf(uyRQ!qwd=Q+Q!vJg)y7Cj?bERl1t@rbsNDOKcs_R;ss}M;nktlumHz-t( zsRpI{<1}M(L02l4Os3;pO&N*nG-gtws7cC66~zknJ3%|q&o#QSWUeQxa9f?Jn5uE@ zwS=fzLe**9BubWTxp$*J;pu>7_NHfV{i?mDJSYuH1Fy(=Tww?#eDYC#bTunkFl8m{?*lk$&1^j9gd?n5-U3tXfcy(gSkE=q*)#WryLdRx zK50IW+S_sh)f1V9l_J|3h{8 zz7m{TEJfih;coW&Uq9#9@!(&F!!2$SGYqPm0ar#>HB+f{=hj|=H*yjR5RL9PNmk1m zG(mchn7*p=B3GGMFExmg)~kJpj#diRl(?#ODmtb4IyXXOb5?I78qf4^bmN#x=jg4r zfn+tf3{y{1ZIg&lsR$I3C*8oLT)q}D%tSHTcr&6+V$N9WKHd`!8D@`>A*5K9-M`}P z*c>cbb}Ph8lT1uEjb?wzO(NyQPH5xV<>U w@9^Z5wGQrdDM~VHyu9`LtOJYrK&b>L` zx%YlI_nf)A-UmzG&))?h5yz8|I#ddYS)R?A!-8k6%1uSHI6s=^dD{~evx=_g(w^ou zENybd=1kRe?&(<1EN)lVjOfg;M+y*894x4wZeLc>3{Nla5q65(!#BS3#_@0A2%JF8 zdjQ_Y8{QF^!`;3;P{vVT2b7&jUo*gxbKO5JKm}h5_7RQ;4-(#|^%8Ck9d56j8XNP- zqtd7}@`hY`-Xo8JM5DAzsNng~VN(4S8YLVKceF3LTFILfn&b%}={b;SOu#N-8NUc` zgZnri{ss`I8_WnvN$XDv&&UZW5kaSOO(saScbZN{|5KY0q!}TC*b^IRtsXD?g_Pu9 zTfHVIi;@^QgSmvA1JZ)M?AJX9_b{!~uVpZ!xl1~YhUL55kJS~y6Wm4z3m+IPE!aNzb$ zVwxA9hH-p(aRA=K3yb^c3BN6t06xI%o#)`3^VuB^aM@}6~V50IvDZmuV;-(!D^QLCl>SKXoZ4q7V%f=`(_)(h`jDp28Y>*s!q-h;f zG8vXvhPcJloEd8%dm8m(bKS=+KGo#BH9($qZT-0G`*eP|EkJWNS1R&$mmw!_5G~u( zxv??KG()R7y<=4do>*6_SaznG1L^;fki$i*)_r;~9<%I0E6-T%RHkcL&E}azQ=NAE zVRk7;?VGl>DN?6(iWal9A!BoNl`!X?)7kQfa|6q4+MIinn>%{91nT!DgO57s@~ioR zZEdYi>21NHTI=jdQC0PV^?G+Ty%NQDd*~(lk$#h)XFX#%QybC@YR=7cFV6n{*1zk? BkemPj diff --git a/wasm/libc_math.wasm b/wasm/libc_math.wasm index d215f41704bc8809e638b66fc98f5ab4582e3d76..a32f726b676debde02402da3af8a768afecb75fd 100644 GIT binary patch delta 1114 zcmZ8gTWlLe6y3Y_t~YiYTZ!E`aUQeefuYcMqJl^WYM@g4Ns2^%rW<=UU9w(Vv+Jl8 zksYYYA4p_cl%yq8rKIU2Qp83GQK>?z`oRZCO_Nqsfcl~h&<{Q$1pR?o+eK-m(V3ZZ zkM5nhI(Phg-*-Rw=D!5LiU8OGyi%NmkenfzEIlL&L2MHT6H2YDP!q&jI$gQcuGb0G z44aUHDUx%9Iys}6W;P`x*5MQ-nnSQ|m_%p^moj)~%<1$YK@ISfBZGNe*yPV>h9zvR z$Jnsa1|=y6>v`5Mwgol^FMs7jovfv)y;e{qBq4v7c+y}k1$NQ53+}Ohea&#sZT4>fSaCb0(;}?0 zn}KeQaiyPQM(KtXc3v4sta^3T0xF=sER!WLH)mGFRnQ+g9(h85Qi;mZ< ziOq^=R*X!r`RHi8lwOs@UL>tAl~KH(MSQIPT8GdqtRL4;mIYo=BYJ z*xfh{)9z1=_iN#E_wts%L^#d9*?t7RaC>*iL6~uO_xvKk4D0CAIrm}T-!Z;@FhD)- zAMA1a_rKl)XWW_TOWWWSBUcY|{O#&K_>{f6cm&R~D~n&lNmjU)fjRc@T9Ko^wushfH z!BMvJ#vcBu!#5TIX5F`b-0N+pZhkDnyu0J)yc{|!`7JF&;E{hDTey3>xW=@#Ydjkb zV9mA(bz*Xk8kVDP2#k~ubx)c(UV|-i(7|~tZ<910si_m;{LWO z!9>OUjeeaHQf!iKhnmD{4su@`+|%6rEl-REsxC)tCtZrFPfy7+!4bRsw$xy2%ytIt z9LD9W*fcVRL(*;03eCsL#7-9HH0s#x5xcFdHuyLr#wpd7Y@G0swB$gucBypi6@ IBKP0_4@ZTFhyVZp delta 1000 zcmZ8gOH30{6rDSr4())@07dz<%z$83@E0`3Uo?s)vT)%i5f_hs-r#6EZDyt@kTfK^!v}Hy`nb!_gp9numfK_8S<=Zk8Nr^R# zlmwBU#1eLr+;=w9s4}6G;z_|yLN`4BDp_e?$ z)m+DuR;=B}E|sdqYFDqhJ}=~;zTx7Y!oPe&tT@EFddVht$BcA($=M94Nm*ae2i6#WxlGaN6AGnJ9v@W?Xkq8WvBO?ilxuZTh`G(OhxI}J^N-#uTj&7kb^)J?y4qJaOqXWtp z^L^|{k2T=}vA{J<4!?LnW17YmLm%lH+X_8oY-}U_RMpEAz(w=ht0v2=d3}_HtLF2! zaX$B`om2f044=3KWb^pPL=N)nI@XLLKBg(EAs6SgWiIZ2C00_1RJ_+faW$^v5DHMS z?Vg^G{Gkwv`CGA$)x;mMdh;_b z-3X-xTlv3sMWId4^cDdks;COR{G~TXMz~n?agbNI_A-~Q zFiA<3RKZDxAK;R*Dy!lDGgvA#1n;odLr=rI>{{p;e9koCA$2yWhs8r_z6O&;Ra%og z>(2@s0OtH(#rJtwU?cJ_#EbF)#QMlCm}5^yo<;jyB!T!X+H)+ayo5NZY)1TANx)_H zv$7q2U}E$e7-Qc@o%r|&ZmNoDzAxFPw#CQ%Cu*`Xa?|Ta>sE17ygJ3l$Jn8UV@-3F zKKb3MxQ+|Dm4ldw)9j5amoVn3#U6N%y|Q=^PO;_1$M8^Ff0B9l z#P9s&Umm_-9ZQWc!ya9F1YM&`F93Y$3s*~0^gBtgHH*UA(!Kt*>qAgnHM~u$W;YQg zn(I=>+bHE7!}j#%@NmUwSv%C5>WEE`c%)z#T$&{VINn2>Ys(_YYlGA!dd}Gr#W}aD zq*@h0QqUbri>;FDIVQE+6r67ZXB$P3S|g9!Yb%WFWy@^)t!lYL8FnkZWd_m>t~cQ3 z38_>irePT#&2C*^b)&pY;^jzQb3Auj+$~n3O;jCmjX`^R-7SGwXGi0TFVJ#1JNF`W zI(FU}uI_u6ywbtlqMk2!?#}X(>5zx@N@tytuA2q-`K}dVcZW4M;~Cp5+7rP$(@f8> fXm8|Ue4Kp_!aXrUa*i=**w}FJ3+Q9Zf1LOaulSYX delta 1014 zcmZ8gO>7fa5Z+na>t7NpZ9*JE*d_e9g#t;FfRG3v2t{zJARGei)5d=Z{d_hq=$o&z8NF8x-Y1G2F-hE55fw z*~wLGc0s>07uhDlHNLib81c92tB5C;_QN$tsd@PUeCzn?{}Ew;|KHFHgHCUw6o4V; z%+?nk7~+W*4Y{$Ff6MXt@t~FGn$~WXues zang=XOH`K-H6ABvwSzLErL3hvw3%5<))f7?%&l3J$`Z3JgPKZ!=%!w<<8m}=_Kj0( zOA0Aw$LHO;;(g<;40N)BwpjbBa%Q))G$Dny#L$zvP2;OSEYjH4Aa)A1SvHG?i>!hE zCrs}!KPoFSp@l;1^Dz&oYY$jdn(4U!>!|XSuY*}v!k74kC8`J$C-Om#7X+U_BHF|`T(0&_Ob0hFI6NZH zFLv^QU_@tKiNovlJ0lV-oKxT(L7sDaynKW$Qn4WO9En{^B6{h`WLaUUJ0e9>;_&z) z7Ift}kI&^1cxRAvm$F7xA9MfYeADVmZEh;G>{yqC1e-cZWwC3ur_@VvfMsbiv4T}- zdSFFphb9iF2p!YDufn^`X~-bD#W08Hec~(FFk=DnzcY3vx{LS z62G)pf&8w6jlL?RsT5d_y_0>tjBJ37zV(ExVIP~4@q2dD^ckwyKC@t5x13Dbv`MOT zdv9BBYgK5l#bqF@veP@!PhmS%ww)?#6&n$|v`d?Jt!kW2+aW@BW02Fgu4Ct76R|$@ zL+m3pHiTNbj#FV1OX+rq=#6fhiB@#qh)tosJ+8;#{ZPl0`zmZ>+SHZU9$KBMGhs*Q zow0w{Vh4LQ+fA~I*$-oB`Ql|kmSs6)*=|Sn80-wSY#KfkTUoz`9PDPL4e8h#+Sf2x zgI(rM^2GO|NBT04U?L~6APrarRovVw_-i zTM|*r;_s}&XKc%z8HBdnd6Ur6yE58*cP2^3{cwt?;og3n3{~ILgH&to=abd=2V;pA zJXnTP?9zkRiN5skEUEVSaVyDB|JXwOM?W+JEj5o$%jtsHwD~0H-U9k&Ba+M=&a;POhCzm83eWvDd0?wQ6gv zMB(Jcgr5TH)wX&W2mrhAS1DeF={PNUR2YvsX}1bI!cvqPmuUG;jV9DcbsFT8N^dQ4 za8mMXF_JVt&|*HR=yljjRu1bhJ?8XdFKaaR%NpBd4S9*vV-#u6(&JY+Bc0b{2hN7e z42T5INvn)tI3dNGP=@o;S`+?+bhbJQwYVa^9<5kxipFLYPKB4n zqOTSgrS0)JgHTvVz}p~kYd3V29d_=C&6IR?Pb$dg;T|^pR)@pV-bC!CF!K9iA?Y0N zi)LC5CgE?itm=nGS_=E)8ikORj64cqLo!4XMh-v&s-lTuNP~qgu~al%*(RoAt-P%sL0N{S71TQF;q+0cMmVe=jbsADLo<*?zinyp z7~IFXjw@a}JEa<*+sv zm3s4blg8&L;qk!8N!#Y&r}C$UW6V>tv6G&2h$1fpV|4++;|sdu^kr>K=VymzmuSw% zFAj30zEY8QafLKKi@SDIhHSu5#EYEUFT|T^j{4fcg!UoZP2(1LeqMKZOw%y!p%a6G zm-qEF(H!;A45eXfdu9yVJGLQW(50Zgo}bFSO=V(RjLyP7(tJz3P9ED{ zF6ie14k0KeTHB>w8s?nnDf0D=eol{qNsk0kZMs_ffs|6QJN*-bp)x>C7jn^G(7UjuC0gZCc)uz`Aayy zsAz<_{h-gq3nQcC$cqF@$3-QQMWall)XtB#h`w@1vHa+fp^PYM3RO{Vx5G$@<%NKIyxHmZ`UN@@Sm>Bwlo7J%3}%{?*ODk_m}Q~26Xy>E z{GunwXPZSYNvSoia$cOM91%Ivm}F9nD@P`q6-#ZUnbHmfJU)J^K>_HUmlN}(5=zvI zJg(rvY0*!FPx8ra3tEn6dM8Ed797rCslb=h1(A);XscUkz(vo(U+BwtCnuH`&NPZa zp6&ppG)u2|U`NG((RMm;|$I>DMeBES2XnUbuEyV<>S}? E1943rUH||9 delta 2738 zcmZ8j2~(vCRNRB9A8RwEi{tKt&lIacjaqH#^4?R{^+6Fq0n{r~^o?=Js$ z|Cu|XI$h0P-5v|a6&5fn=bl+@)Rzn8K5+r3>EsebyIT^3`3}J!(8TM@?H-TMp-Hsx z4pFcN1m5NL2$~+zyd(tFJx^-q0*%c;ipr7-mnKzPZg+b%bJ$HTEi$EFk?FnFx&pR2 zq7011YNuf}b7>c17rUw*hZ>fw>w%hJo-P4c8l0=&#G#gP#!)1*jnhf4q5V?UY@AK| zL8e5K<4vdQ%C!sIa1zEz65qLjX+clfRN9;_uy(Hi5zJX+Nk3Zm};L#q};_yju zXW9b}8`-8|%djcfKSOWAr@%EyGTB>D+$&k;&)Fv76~yt4S_v zO(FJowJydEmUOUyHVT@;GPHkjV-yM0P1fPE3ljWP!}9^^Jft_5L|zYvNf=+w+G?x?BBPC;Q;H@ z)`#}#ZR2QP)i#P`U0W7Gziq2h%Aa><4-T@#yYulmTXnZD4zc>X@8U4a{%$f^YrlJk ztex*E*5BQmLYm9>j*;AQe>WO~MGp)hDF3jSqSikgP4e->ML5FdKl(Mv2aiq?^zh@2 zq%Zyc4(*G7xJYvNkIgvB%ugnuk0vU=I2kB6Y{@L?~}ap zzc10SW;bTzsB8izqEVg&jEFm?uxH~^xRctX#t2(ug!PcT8JHPY_Y*@?gsn+2M041N zFXVa-lPFAN1jgW)oF4%Jb@HAFoTFvA78lVV&(oopAcu4)piEJEWD#aa+D`O8oO{vejH6TG|0JDOpR?&(k1n>=~Fn1`mH_` z+Ga%@&?Fy-p{%Fn$1#{ozD2QU#Cf?}oEmXq95!$`66&6SWF7t`=e~>+_;V$@XSNw}{kHqfPuY(&VZ&;c7(>JgL+ld*%!c$AEJgt4dKHZ5=VLklf^`lFQ=48RpC z;pza)q!O|QLL%j^foR4)dC99-f$ehiAPmGAdE_A6q7?lH;{fWmTptY3^>3s?Ccni) zFpF&Ghro+d@`N;`;44{7!*Ddq+taWBE%Gbr$VE%&?Q}FL1!rZT0ga)@8L-eZmi3wH z@kl0quN;fA=$3VI?-4joJ-jsn`%xF#Jd%o~^{Y|Hp>Ma`Wi%cj7>dfqaV6r}vG|sj z}L;Z7+t%NVj!+SU#x}Qg+^=wreqqV`N&EPaPq;T3K z-54YNeCp^2v{l|a9!-WX6_7O~FQ0(L_)Ex=PpnaAZx>)1En^F*vIg0!E};(!VFb>G zHciADgL$P%>$R5)xNMv&=gh$O)dt=!NrD)N)B8oYH{j}Qs0?r7pC4@rvAkE9AK)vz z6_ViOOK8ZIb&2BbPABiTmkJW^@`*2*X~KEijfw4}u&dT33c}0E#H5MWO)mvRkKpZY z;@w_%fUj1@V~^*CWzVRvNeVdCfoXejb|#rBrEraol3wvrphWWXd^jxcahJOTg0pw$ zb~O!K4@12V7<%bsgUNS zcKjh2Vv*cVBGe&x1A>@lETw*_jHFxCttdzVy3J6F-&1W55bfo>$5%Qm+V5#Ug&Ue- z67626ubdZ3ONX1=J-tpr%#2Y=EERnf)GAR>RIix`)V|NMNM3uH(0&>bLk%JZmDbxm z#F*e58RJyxBUE(K(^lbk(jU1=hDyP~OBE%P zjZ#3MUek@L-!!OMgh{t*R{kdzn{wIysVIlHwDgzMIY%Bg H8%zEV13C6Q From c6817c550aeb2758af93a23e2efbcbfa23939e34 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Fri, 23 Feb 2024 16:53:33 +0100 Subject: [PATCH 5/7] Update stdout/stderr/stdin to not rely on a init_std fn called in every stream related fn --- libc/include/stdio.h | 123 ++++++++++++++++++++++++---------------- wasm/libc_exit.wasm | Bin 58675 -> 58584 bytes wasm/libc_file.wasm | Bin 61419 -> 61271 bytes wasm/libc_malloc.wasm | Bin 62251 -> 62160 bytes wasm/libc_math.wasm | Bin 59209 -> 59118 bytes wasm/libc_time.wasm | Bin 59927 -> 59836 bytes wasm/tsoding_snake.wasm | Bin 88759 -> 88668 bytes 7 files changed, 75 insertions(+), 48 deletions(-) diff --git a/libc/include/stdio.h b/libc/include/stdio.h index c96511b..f2daca1 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -131,17 +131,53 @@ bool __files_were_init = false; FILE __files[FOPEN_MAX]; // STD FILES -FILE __stderr__hold; -bool __stderr_was_init = false; -FILE *stderr = &__stderr__hold; - -FILE __stdout__hold; -bool __stdout_was_init = false; -FILE *stdout = &__stdout__hold; - -FILE __stdin__hold; -bool __stdin_was_init = false; -FILE *stdin = &__stdin__hold; +char __stderr_buf[BUFSIZ + 1]; +FILE __stderr_hold = { + .used = true, + .error = false, + .eof = false, + .ready = true, + .is_writable = true, + .is_readable = false, + .buf_index = 0, + .buf = __stderr_buf, + .buf_size = BUFSIZ, + .mode = _IOFBF, + .own_buf = false, +}; +FILE *stderr = &__stderr_hold; + +char __stdout_buf[BUFSIZ + 1]; +FILE __stdout_hold = { + .used = true, + .error = false, + .eof = false, + .ready = true, + .is_writable = true, + .is_readable = false, + .buf_index = 0, + .buf = __stdout_buf, + .buf_size = BUFSIZ, + .mode = _IOFBF, + .own_buf = false, +}; +FILE *stdout = &__stdout_hold; + +char __stdin_buf[BUFSIZ + 1]; +FILE __stdin_hold = { + .used = true, + .error = true, + .eof = true, + .ready = false, + .is_writable = false, + .is_readable = false, + .buf_index = 0, + .buf = NULL, + .buf_size = BUFSIZ, + .mode = _IOFBF, + .own_buf = false, +}; +FILE *stdin = &__stdin_hold; // BASE FNS FILE *_init_file(FILE *init) @@ -188,29 +224,6 @@ FILE *_create_file() return _init_file(__files + found_free); } -void _init_std_file(FILE *stream) -{ - if (stream == stderr && !__stderr_was_init) - { - _init_file(stream); - __stderr_was_init = true; - stream->ready = true; - stream->is_writable = true; - } - else if (stream == stdout && !__stdout_was_init) - { - _init_file(stream); - __stdout_was_init = true; - stream->ready = true; - stream->is_writable = true; - } - else if (stream == stdin && !__stdin_was_init) - { - _init_file(stream); - __stdin_was_init = true; - stream->ready = true; - } -} void _set_file_ready(FILE *stream) { stream->ready = true; @@ -331,7 +344,6 @@ FILE *fopen(const char *name, const char *mode) } FILE *freopen(const char *name, const char *mode, FILE *stream) { - _init_std_file(stream); if (strcmp(mode, "rb") != 0) { @@ -347,7 +359,6 @@ FILE *freopen(const char *name, const char *mode, FILE *stream) } int fclose(FILE *stream) { - _init_std_file(stream); fflush(stream); stream->used = false; @@ -377,7 +388,6 @@ int fclose(FILE *stream) // BUFFER FNS int fflush(FILE *stream) { - _init_std_file(stream); if (stream == NULL) { @@ -398,7 +408,6 @@ int fflush(FILE *stream) } void setbuf(FILE *stream, char *buffer) { - _init_std_file(stream); free(stream->buf); stream->buf_size = BUFSIZ; @@ -407,7 +416,6 @@ void setbuf(FILE *stream, char *buffer) } void setvbuf(FILE *stream, char *buffer, int mode, size_t size) { - _init_std_file(stream); if (stream->own_buf) { @@ -429,8 +437,34 @@ void setvbuf(FILE *stream, char *buffer, int mode, size_t size) if (buffer == NULL) { - stream->buf = (char *)malloc(size + 1); - stream->own_buf = true; + if (size <= BUFSIZ) + { + if (stream == stderr) + { + stream->buf = __stderr_buf; + stream->own_buf = false; + } + else if (stream == stdout) + { + stream->buf = __stdout_buf; + stream->own_buf = false; + } + else if (stream == stdin) + { + stream->buf = __stdin_buf; + stream->own_buf = false; + } + else + { + stream->buf = (char *)malloc(size + 1); + stream->own_buf = true; + } + } + else + { + stream->buf = (char *)malloc(size + 1); + stream->own_buf = true; + } } else { @@ -443,7 +477,6 @@ void setvbuf(FILE *stream, char *buffer, int mode, size_t size) // CHARACTER INPUT/OUTPUT int fgetc(FILE *stream) { - _init_std_file(stream); if (stream == stderr || stream == stdout) { @@ -489,7 +522,6 @@ char *fgets(char *str, int max_size, FILE *stream) } int fputc(int character, FILE *stream) { - _init_std_file(stream); if (stream->is_writable) { @@ -604,7 +636,6 @@ size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream) // FILE POSITIONING int fgetpos(FILE *stream, fpos_t *pos) { - _init_std_file(stream); if (stream->is_readable) { @@ -624,7 +655,6 @@ int fgetpos(FILE *stream, fpos_t *pos) } int fseek(FILE *stream, long int offset, int origin) { - _init_std_file(stream); if (stream->is_readable) { @@ -672,7 +702,6 @@ int fseek(FILE *stream, long int offset, int origin) } int fsetpos(FILE *stream, const fpos_t *pos) { - _init_std_file(stream); if (stream->is_readable) { @@ -686,7 +715,6 @@ int fsetpos(FILE *stream, const fpos_t *pos) } long int ftell(FILE *stream) { - _init_std_file(stream); if (stream->is_readable) { @@ -700,7 +728,6 @@ long int ftell(FILE *stream) } void rewind(FILE *stream) { - _init_std_file(stream); stream->eof = false; stream->error = false; diff --git a/wasm/libc_exit.wasm b/wasm/libc_exit.wasm index 16a5f13977ef79def316d3c0d300fd4909fc13e6..e69cb15d6ce9ff4cddca88962fd4034a6b98909e 100644 GIT binary patch delta 2828 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 delta 3585 zcmZ8keQZPIx>2lQw_sBpg zEgp?$b`I=F2+h*A{^XDlVf|v8rNjEyi>8K7VrD&+UN#)CvkRhyOt4F0J3b$YKI_Dx zTuyK(dx*@`GH<@aR7}VltXrxiKVs{o733Hjmjd{FU)mu~9%60gH_6HT$L3>V*?U}* zt_4#_l;}EG3+qyJy*7D-y(ZTem@$L-0>t2j6z$h0PqE+1OA5@b26GU$!eEMS(?8xh|-#LipRSDn;@_$J}D1bTn~emy`^ z^jk!myu>=J18DDi)!XszB4%iHJRxGZ&pH~#$xHdHLq^3zY`@yZWqzqX$7S5kR{mP$ z?Bc||&Lv#rL#LY)uQ{LM#JbX-a^lTWUC-&#^|rWHaFKUhsD6q~8!wleTggA|{yM>g zE_?QKk>|V-$0X0+C}b6{{h0R=XC3ivLd*FteY+)+W4rz9#OcfIs{bohxyvZ8U;!#X zgo=nLnR-Cv8(68KL{HW4xS$$XCGD3;H+wMEBAG+tL6*Exn+2uUE}*6jY+>OgZim`6 zLQB97C28sahg}cEMpaPNALNi{R0nlX z8#Qzc^Yy6M0QJx?8$}2yjSzyyxluHs@;sOq5)Wq?&w4&I(J;)X%@Bs>KH7ph3!nuS zq-iV0*J{Mq25n*CXL@|?D9{1z(2=H{&^Z%d1R{^)TZk?e!6H}~HFS*lx==9+T@c0i z6h+ZgFI@~KSe&BW&|Qla=AGMWGcamdwT6>xLUOC*CILk`iAou z$b}6fW;ET_kEZiS`fvikWSm{!`YDnw46f$_5)hp85#4kpk!mgPn;fgf)@%Tj`AWX z3JVe~*4WZ9Usj@4u!cmLDh3yk9THV)2Zf^=AzcEFXQ+z1-~<(%XjR9282EZZyKLON&1ho;-h7F{B@+!w_9RjN!fnTp8BzQ+=5%Cf< zppfF{0orItQxWqLG^S`1G#Rjh5ZipEuXXw(ZbJqcilA6M$t_R|n86Ye1;D{zqgKt3 zQ9uE!dWub5SualCV_jFLq*p}Z$783-15#lN^wu|HL`7g`=^OsJBZW^HZr%>|LQW`G z0wsFyBOT{Ufj&DOaL(`$oJOPBr3xWU5m{x|8Qi-1Il4^bRR86O&1jxP2)pI_>9gn;xlkl zj)#H{+X^V-Wk$?Yg1_%^Y11@_yBoxsqY*$Oyr=~P%Xn(huwbUMb*Yba1qG8p?R^ z@B%MHX*_UXQHpj!1iBFa&Q}Z+?N#@u{y$9}rT?XUL+tXs{K~V1^>}%agLW}q#fb=S;nxO}@2fDqW zmXi=HLA=uh)N^e2?eZt@at21N;tW8KwNU$hVYb)LGwDq1x(2A5z;Q0%ILB7&GU$r7 z0NYK3rikcA`)um=F%e(;{(Rl1d&7%hNO05VQRI2N4|0*rU-nfPJk6@JRXT+1AuJqc zm)<$;I-`eSMPK^lk6>o(_jlIVf1=Yx5FLv0c0T;+cg^ZSQK}OJ!2fRiZ=Rp8`P@X5 z&&<+L|F$^!g?VAV^@}mGvLu!qN@ilCnN6`oaxhLEG5kfNe~pdA`#0^Xw(cAq9!U;m z5*r6lIiTL(JyFEENCz}q-D$Krb1RtG_SZw=9a&vMB OgX6#5BJ9fjz5fNQb!wmh diff --git a/wasm/libc_malloc.wasm b/wasm/libc_malloc.wasm index 1553db3f2081afdf88460ef91bb24ee8b1a8c9e5..b373d03db504399805d2dc0eded3eab931bc3414 100644 GIT binary patch delta 3018 zcmZ8j4NzRw6@K^bTi8F?w+jnl7nXBbU>8UrkU$I}2~WaCl3@N6h-TaXVJRCRED*?# zlOPC6ERDYWHM1cO#;^W&t!W-Qs+P8 zmr0kKrH}NCj&&W1N|o|JXWyVy&6{YAwaRwtZBw9@nE8od4j+=u{4&i*1G$c#o8)I` zjacSs4ldfKw1kkG+%Nmc8D1|p(VtK9gj^t&7vxbg$Fs~+^!%ju3-dJ1ePeQBLSpS; z3Q?JLKs$8A*dBF`AG8FMv4|1d2NBp8W1Sc~YuS*D9WY}3Z~*#aYye}_8pPVX!diet zE!K7U2ElPS4iCmyLY3GA0sJKD=o^!K%DP9OKey%~+GFb$o1?aZ{PRMUsGZH8Bbf6% z0sK5i>gel}T(gza*-7n+?P-EpamV9mKX;r%dnV(1Xd5!)XkX22K>PR17PPg_ax$mw zb6Q10Oj(8Y1*Hw`CrS<4kgFbTuRp-QD=ZJUCn+^09Rmd6LpTCceNra&HWnM zU%5q%kKCe0OV%c|Pi2Wpzt-)|EUc$hWj{znKW9CUVWci+O{P&lWHRUUmfSKwc%$~UJt;&s9o*F-O% zq8rg+GZJ+7BY}3YKS%__#{<{(#P^14O#Fmpv0LAlU=D~H@KCv z6F7gbUF2I>mQf}fvP0CtJh)3BM-JqOU@n$f2Dz{-#_}Ks^6IDsJdhh>UhqOzy`(F$ zFrR8;`QT#(kk9;30RAv5#7uxffH-3)fTaW!LDAO*1VDyB9d$T}U7dOim91sP_^U2~ zVkl9*uS-=EtQ1kDh|*O%SWs112wkBVD}%CPL`_H#m^UJ0|%=@=So<)bj;OI#cH6Mt%4d@6=tiEqZU>}ZJgEV9Ce8l$r|qIg+@^0>`tBJ z&J;(JI{S&>*aS_mN#{t2V{XQJVQ7Z%mn0I~jAibE&2U$YwLpvVtT-sP#b|viY=tc; zjoT2}3frI+)9rS9auyQ18~xkiZrC1UJ77n$!cL>YF4zS-u|lV@-Hp(DU^m<&N~EsC zy+*JN+Th+4TRV!?UoHex03^1@z}*M;!Jay**zwNak3Z-8V{9+%<(=0STywXDdgE7w zPp+v+-o8-k*S%N{A5S4_Kzz8(hkPCK{6b+e5zxzk>E5>%3K7fyvCuA-=If7&YL~88 z6wT`#n~=O2C^W}#q+-rtAkuMovIF8UN*oA@~&fCCk#H*fRU;wnM=qebtUCHxqSy~f57a~KZ8_*z6^9UP_d zUH#;az>#0FqZmF0$Mh067IP?8vV3?t^PG;LK%I8`OosOQht1}F*C>%Bg8%v-l;A>* z?~PUrd?mIr_+@Obh^4X&{8HXwj8!gA`XtTuuXJLcG0TIU13lymxkd}zm?Q~j1YcPr z(Z2qk$Z${R{v$=Uv5}$SzQNIGcUQnOGTJpV6p4(C4)^yAM*8~(`bK;97iTBkn9v^? zJs27493CAhQIg(%EE5^&>m4k0e*=eQg1Jk+&c2bJ$Y>X49~|!)u3i~RPx6*omK2nm zqeF*AM=JECd%0ySYA9Qg7LE2F8u?b`((87Wbu%^<9!9g$8HpSm?(6LvL~Y_7yqdrK H(L?_S{Y@at delta 3009 zcmY*bYj9K75x(c>%GS&Bm1I3^J-o-3Em_zGY%GFJDQbeD(*n~@ilILc58EJN9Bj+Z zm;hEDghxm_@o{EIGHFa6Zg`|MQD^caC8ZOF37LlQubm+jW{QC(g+j_qGELKT_g>ja zXY9SYyZh~aXV30Rmu5^SZyr%Wa3P|%4)6CcU1eBlA69F zFS0G}n$n@3+{l*UUS+jC*(dgOplk<9Lr0$d6M6nDE!X+8u#Cy$mbQ&1*SMx#d_$1 z^;xkYm6!dNSkaa?Y?~kro3dgv+D=)P6>U2VTOaIzzO2}ZHfD`sY?-izG0`e(N61L9 z5B9;HtQbovBF_N-#*+O0gnY%iA#_V;aF|gjMLfd*KR&~<;t0cV6}GJuZqybw{K%<7 zyvQ)lOAPSuMV93Mn2>MV68!E&;jgym80OvOIE3=wj%k!9%YKQn!#RNRE$32{pE`et za#4AL0`P&G5>Vx$fPVW9a5O1@ zq)?(P#e@^ez&Rkwp}b75ibH6iX|LqbUWH~CrgMWETa=siQE6NmvR6})> z@`=t6&_w`%7!Wm3Gt00RYQJR|MMNFcLA2e#7^&+K7=wC<%`uFlW~>3?(C}S~2}I9> zd2#-MPO%XZq6r#BGc-YSr$}e&qwC#+W=znP#RP@-vN1*(Ztl3D13%u? zW+K;;93__DE1VNe~osk7+!A7$nA`r&@k3e;&_-^kbftoo2)c*fR zAPTEgh$guMCoeU55DOvduWR4{#R3t&=DNwRjt} zD`aD!fxdL~A{)!749bf9QSSuj?0&!A zM13v!z(?L#dF@HP9dvCVl~9Z;z}oBU6Hgw*VGCwO2tvh^SC!k3npj*Ozm}S9rVaC}dCIgGD5ss&s&J;b(MUfM8Z{qcGy|gIX>??9 ztybulc8F^1NnN7L8^fcWFyYy7!Gc$Nj>1w!5M>cQJhdNuxL5tgp*jWaX?>**h>)Hs zRAi@!Fq*KXAd;o6svXs@5{&!;1OWDf@m7PLwNL}K?aEs3T(+oT)c5P0YdumZ?pCkP zN)d6xuK{quCb>rIEP>6F$kK9^=l?e2dh@n%LIuaABF-;O$lqVDkLX$qR|QpZZny;T z6|aR{#%HRFI6x)x)o}}Es?k;cWTuNACuR;%u+|&%`1EbL>4x8WoDNx)!ngd5qrqv) zTb24i!7t6Y5*HiryK_U5N6FrLb4&Xr`tgI&x52hq2HRn~ahIsh;C~jfkVzW!sDF0A zj(MiZ+w$X^tq~nA2C;ZUFbG3gkwb@J7=~PuXu&Pt;z?qF71a*w)gOh?cg1e>dJG<; zFlZEeU=Qq`6njxizti?Eq3}CzO*v2N5DvWDZolj(h`+BeYZLrjR8g+s|9|kmxv_Bm zPARj$YgYR=@9bem%&mpL{PTJCkTad>&*aiWx$bmtrmv@_JdHnQ^^fVnp3U8(wYHI= zU4xnaT<_K`QSVT0%h0YgdJp#X^r!nWJ2SbS?mBtwo;Oyn6^(reOAlqX^~c;r4F>8< z=N=(gTwb{s*w9c~jG3^^MxSTy-8GyWYSbTFn=B)}M%Lz%-rm09q3!c$e`GJPuEYa$ b4x(6Co=!h9nAw);$N2QiyG5?~{E7boW4|2% diff --git a/wasm/libc_math.wasm b/wasm/libc_math.wasm index a32f726b676debde02402da3af8a768afecb75fd..6c38db48c28eaca143f40a2ea167833d342d4999 100644 GIT binary patch delta 2798 zcmZ8jZ){W76@T}>=fwXKKRb3zY(maW;>3gmk^oK#5b_FffRI9=1OiA-0tvHmLi`7& zNmcEYwxj#fwRb@+R3cl`vTofL;ZF3!KxlMZR{^r zxS%vOnm#^qY)ooV#)qR5QY$}5+e?>Q-~EkTvzlM34%j4S0uv}9Iy=R$(so>4lPl5Y z7RdoZU*LR$;v>J{`;?9J{V9G{sTRv6B~9{trD>XeFqOM$dW(8LoXTb;wg==ORoGtG z1AAj^P|NdI%#DRu#E1<+1cqX47-QGWU4_^YBNm4v5Rb8OjMZ8iQJeQ!sxeX2vUahN z;5m2>o{h1LCb295{LO^uhg1BrWl*5~)+$7=wjLCl)7I+6ABd`iwws+M$T>p*e@~MT z{p}S0#M(qJPvst2UnR(T)&4SCf7vYBt7WgCJy4!Nd%b)eTAO1F+TD&OlFwxw7D4!- zx)SXrbpWl$*^YLzvlHzJXO}mx=QRcCDt46suE4GlEzfT``w`LLx`6htF2Q$I2!6C; z6WU)@2$j!u>vp47ZoB(gB6_*zIf;>h%8qhFSwH1!Ezi$X{ucwMy`v<5e$ihD{n5w# zR@EMQ`37(E^^0BBS0#35eAmTt#NV5{SUpogewrI;`;yr5TukkGMVsZh-7956-r|F+ zUL-TQzpYv#(;1$7)G=TxpngyyP($lqB;@VfeAoAtg8!XT;ZJVdiGKe3O=Dz+H~0KU zkOSd?1<poeYAwU zlj}MAo|(+&{&mjTM1I1R8z<17ym6QOoFDomt9(UCke`)nx%JP^OpBzj5{!GqV~y8`y$WWp=Q#GO)99D1-9t%z<O$0RCpK;RBv!VD)#Ec0 zfO-h1c%iXWEyEfR)qp6yYCCJxR2D>6Fvga`(t1Q?C1~WsH^Xh0Z{lZW2D3Ol^=Bf2 zM`i*`h)Uv_ursS>VDRX`s=mu_-KeH}dKUk!G_+P#zQrN*>=nMU2P!`0OnDCcFdBKkjig$vYIlv(n)z~?~DUR9&D!5{- z0@=LJXX(|E9`FbxPD4GRx2Su)h|#BlEIt+?}mFrBb9Mn$9EhhK=%c5DA zmKPJmF3!u$4KAnvxBBCZkQLn{%gj7jaV2<|7b=Y|!q@=82CBf9V17N5zfhgT7He5$ z;a;&CSOPWu3=oc&3s{2H>hRiPGj%9l5A{K63?%?{cylrV)(8#I7-m6aE`=a0O|T}N z*;HgM)22Tbr8mPeXvT|XwAg}r%b^99cS@c@2X?jsovqNiFyS^>!P=pXt%P=18D^_6 z$7)yws}n4w=LltrNjkLI>mtb$&;d^rldM6#PFMq--%PR=o$Fv-kWTB@Xg#cDU9g^Q zfG*e&X5E-XgKp3g>`6Vzlf@hxwafn&IX1yY*reykh%xt|UKn~H{5XlkdQoOG^up#C z+X7qEGy21_)o8sB`e19Z#%+k~hi%Z0beqjqI17nAh5qgE6l{;N9k8RI@U)?@6L!MW zs4#47cOmo{*agoBiQ;wGZ3G8k0CpF%?ZIO8|KLTYap(En3!e>3@0H82|et% zccuK-`dlbbhs}1OEH`&=w`pjO5=kQXr~g0z7ixUoVZp#RVy%sjV{s8HvJCtJ?9K<& zwVqUZBsCd{q|(Xw=tLwQ9gn6*57oH~ZY0Db>7$X!;bb~huNJ&IGhbIEAZ{bj; z!Moraj;2N<=@Dcf{qAV8t+lbVkT+;vs9>pSZ1Pw-)ub;6mzj@`8I?7cjE%*QrM}a$ i@U?Wgr5BqDC(*2ML?TC%(ZkURtWA7ZZRLNQfBt_R#npWP delta 2867 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 delta 3076 zcma)8eUMXE6@Tx(m(Q1MUcR&0WI1;~vtbu@7kIz|x^Z=DtCbnYQgAvA%Wk$!8WuJQ zXti!4h0@y5(Yfvjj#ii=7NjlpQKbsgRT)|7|`Pf2T-QyH`y?!TN?+SstNoXpL#X=N}zH(RSo)DCt~OVp8( zs1uyvFi>rtRXXM5DQ4-_6!B08;NnDx9US1)pJMN-BlMi`U;~9C>|g`?`y8E{W#hIA zS(s(NwS9*?KWl!@{wRsf3!~e)kxDni?XbB(w`3L$vQ@6Gx-x4iw?Y=S7U)=J;TS8s zHq@2(Sjr;Y1H}T}o>_Q?J@4v5_v|fKk_Yp-hZ0th8JL0l3bcx6tI2?$szK&wS~owbSE0lvVQ*{$4vNdWQ1whg5kzyL36t>ucl5pKLG&>0(E&AX7%EDe3B1rWO?}|=N*1AX(Dg@asE?!Cj}`$4fPcucu^>Uz zgrFLP(2%59qA-dg5QfN*qeINc0UJX|wvfjG2`(gd0$Apyy0+A1<^ zwK7}+OZucUB11q31pqot+n}wHVLP<*469a(9T=n&I-z68GO|KfnG%cgkb)dky0$mU5 zJFxmS$)^pljM8a-Au$t_A2Z)s{)VhAh%EQ0nK@?ubwH8jW9)B(`{d*1y(?N3a)y}) zjZL;XYQLSM{|6Xw-#pKxLr z^UFu|wER8x$i@5dx9!qv@=5leOEvX6k$aeYAi_Sadf1U)`@{NodHwk0RQa6klT@6u z>;ng)RTW#p%?GMxX|WknM5kWRcq3pJG=Xm;)$wlppo4#!2JqSgc}DV?;PROiEZHKZ9rQgNtZw? zEE%Qmr9CFlb|V4K{P!i$0V;GD#DguDIrJc&nsy@Hy09I(^lyqxGga&Z6}l0mC3u1! znnJeqpsc4r(~!2<1}XOEmqvZH7r77qM8XG-{sha+hrO0e0}b5zlWcsxUENRQ1Wusd zYQ55e(KZZ>52OEc1~sOZ7rgZop?MQDHD(14q`LgZG{M2dv-evKgi|SXCzd$~eh3z5 z2+hL~f-tYE$R`334#(Tj?-zU!(iq~zt>ATtVT-kB!Om+b&;%svwTSz)1B#qtdtc5p zj%eq;ur7U4_C(xwctsP!?b^FfDKsw1U@&Tm=PXKaYy z<1-KOI|ybj^82jf$&M>{G#s`N)(>*Gydr4qq!Bz!6e2idqt>BDDIeNmzE0DGh?L;u zL9|4Zs6vuKYXNz-L_fq`QLy4uz<)>)YuARzc4&k4A!%dyMzjt~DQ4{rXcwkXpR-|+ zl|)k(t_N`18bs%_EsbX04Vz7%(#3Dsa<1xEapn1YLEk5k6j5UqE^{Y3z1Nm%YJ8_%!V~uNl7jv`zmi z>FAWCVf@~K-(|gK`cI0iJ!e;^#@@5~~)RLo6fi}~&ON^YVjR2QQ`FOf^-76Zedv2AhxMO^*$p0FyoA9KgCHz_K%Vu|!@^|H@ Q#vH{ge}P}ahTh!sUzVH}p#T5? diff --git a/wasm/tsoding_snake.wasm b/wasm/tsoding_snake.wasm index 119cd7f05901d821f1a345f08388e548a80e2e92..b6eaf7545ac545a20c07ca57f0d71546d7ccad62 100755 GIT binary patch delta 7656 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 delta 7706 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 I8~o+}05rEY5dZ)H From a7114a746eac9d5923c4035b3aadf86135be36e9 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Mon, 26 Feb 2024 20:43:08 +0100 Subject: [PATCH 6/7] Cleanup Comments --- libc/include/assert.h | 4 +--- libc/include/errno.h | 2 -- libc/include/stdio.h | 12 +++++++++--- libc/include/string.h | 5 ++--- libc/include/time.h | 8 +++----- libc/js/math.js | 2 ++ libc/js/time.js | 1 - 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libc/include/assert.h b/libc/include/assert.h index d883d97..a70bdb4 100644 --- a/libc/include/assert.h +++ b/libc/include/assert.h @@ -16,9 +16,7 @@ void _assert(const char *message, const char *file, unsigned line); #define assert(expression) (void)((!!(expression)) || \ (_assert(#expression, __FILE__, (unsigned)(__LINE__)), 0)) -// #include -// #include - +// Cannot import stdlib or stdio as it is imported by them void exit(int); int printf(const char *, ...); void _assert(const char *message, const char *file, unsigned line) diff --git a/libc/include/errno.h b/libc/include/errno.h index 61a8eed..4269d41 100644 --- a/libc/include/errno.h +++ b/libc/include/errno.h @@ -1,8 +1,6 @@ #ifndef _INC_ERRNO #define _INC_ERRNO -// SAVE WITHOUT FORMAT VSCODE: CTRL + K CTRL + SHIFT + S - #define EPERM 1 #define ENOENT 2 #define ESRCH 3 diff --git a/libc/include/stdio.h b/libc/include/stdio.h index f2daca1..51d8ce4 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -109,7 +109,6 @@ void perror(const char *buf); // TYPES -// if file is not stdout or stderr buf is assumed to contain the whole file struct FILE { bool used; @@ -121,7 +120,7 @@ struct FILE bool is_readable; size_t buf_index; - char *buf; + char *buf; // if file is not stdout or stderr buf is assumed to contain the whole file size_t buf_size; unsigned char mode; bool own_buf; @@ -259,7 +258,7 @@ int printf(const char *format, ...) int vfprintf(FILE *stream, const char *format, va_list list) { int res = vsprintf(__print_buf, format, list); - va_end(list); // ? + va_end(list); // need? fputs(__print_buf, stream); @@ -396,6 +395,13 @@ int fflush(FILE *stream) fflush(stdout); // flush others + for (size_t i = 0; i < sizeof(__files) / sizeof(FILE); i++) + { + if (__files[i].ready) + { + fflush(__files + i); + } + } } else { diff --git a/libc/include/string.h b/libc/include/string.h index 9360020..1eef6ed 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -188,7 +188,7 @@ size_t strcspn(const char *str1, const char *str2) } } - return strlen(str1); // unreachable but fallback? + return strlen(str1); // unreachable } char *strerror(int errnum) { @@ -503,7 +503,6 @@ char *strstr(const char *str1, const char *str2) } char *strtok(char *str, const char *delimiters) { - // As static or outside of fn? static char *token_string_start = (char *)NULL; static bool end_found = true; @@ -539,7 +538,7 @@ size_t strxfrm(char *dest, const char *src, size_t num) { if (num != 0 && dest != (char *)NULL) { - // Transform src according to c locale (not mention how) + // Transform src according to c locale (no mention how) strncpy(dest, src, num); } return strlen(src); diff --git a/libc/include/time.h b/libc/include/time.h index 51f58b7..4e75444 100644 --- a/libc/include/time.h +++ b/libc/include/time.h @@ -52,7 +52,6 @@ struct tm }; #define __FIRST_LEAP_YEAR_AFTER_START 2 // 1972 -#define __STARTING_WEEK_DAY 3 // 0: monday - 6: sunday (on 01.01.1970) // TIME MANIPULATION double difftime(time_t end, time_t start) @@ -62,8 +61,7 @@ double difftime(time_t end, time_t start) } time_t mktime(struct tm *time_ptr) { - const int ys1970 = time_ptr->tm_year - 70; // do this ? - // const int ys1970 = time_ptr->tm_year; + const int ys1970 = time_ptr->tm_year - 70; time_t t = 0; t += ys1970 * 356; @@ -401,14 +399,14 @@ size_t strftime(char *ptr, size_t maxsize, const char *format, const struct tm * break; case 'Z': - // No support for printing time zone abbreviation + // TODO: No support for printing time zone abbreviation wi += 1; break; case 'E': case 'O': wi += 2; - // No support for local alternative representation + // TODO: No support for local alternative representation break; default: diff --git a/libc/js/math.js b/libc/js/math.js index d6ad697..ff43de2 100644 --- a/libc/js/math.js +++ b/libc/js/math.js @@ -1,4 +1,6 @@ // https=//www.gnu.org/software/libc/manual/html_node/Floating-Point-Parameters.html + +// DEFINES const FLT_RADIX = 2; // assume to always be 2 (is not for IBM 360 or derivatives) const FP_ILOGB0 = 1 << 31; // -2147483648 const FP_ILOGBNAN = 1 << 31; // -2147483648 diff --git a/libc/js/time.js b/libc/js/time.js index 06dc322..b118866 100644 --- a/libc/js/time.js +++ b/libc/js/time.js @@ -28,7 +28,6 @@ class TimeJs { // Get UTC time _get_year = (time_num) => { - // console.log(time_num) return this.create_date(time_num).getUTCFullYear(); }; _get_month = (time_num) => { From 9d2a6277239d3f32ccef5105b408c9cc75bf3103 Mon Sep 17 00:00:00 2001 From: Voidler-cell Date: Mon, 26 Feb 2024 21:10:15 +0100 Subject: [PATCH 7/7] Save stb_printf without format --- libc/include/stb_sprintf.h | 799 +++++++++++++++---------------------- 1 file changed, 313 insertions(+), 486 deletions(-) diff --git a/libc/include/stb_sprintf.h b/libc/include/stb_sprintf.h index bb8b180..c96bc40 100644 --- a/libc/include/stb_sprintf.h +++ b/libc/include/stb_sprintf.h @@ -143,21 +143,21 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): */ #if defined(__clang__) -#if defined(__has_feature) && defined(__has_attribute) -#if __has_feature(address_sanitizer) -#if __has_attribute(__no_sanitize__) -#define STBSP__ASAN __attribute__((__no_sanitize__("address"))) -#elif __has_attribute(__no_sanitize_address__) -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#elif __has_attribute(__no_address_safety_analysis__) -#define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) -#endif -#endif -#endif + #if defined(__has_feature) && defined(__has_attribute) + #if __has_feature(address_sanitizer) + #if __has_attribute(__no_sanitize__) + #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) + #elif __has_attribute(__no_sanitize_address__) + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #elif __has_attribute(__no_address_safety_analysis__) + #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) + #endif + #endif + #endif #elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) -#if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ -#define STBSP__ASAN __attribute__((__no_sanitize_address__)) -#endif + #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #endif #endif #ifndef STBSP__ASAN @@ -178,19 +178,19 @@ PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): #endif #if defined(__has_attribute) -#if __has_attribute(format) -#define STBSP__ATTRIBUTE_FORMAT(fmt, va) __attribute__((format(printf, fmt, va))) -#endif + #if __has_attribute(format) + #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) + #endif #endif #ifndef STBSP__ATTRIBUTE_FORMAT -#define STBSP__ATTRIBUTE_FORMAT(fmt, va) +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) #endif #ifdef _MSC_VER -#define STBSP__NOTUSED(v) (void)(v) +#define STBSP__NOTUSED(v) (void)(v) #else -#define STBSP__NOTUSED(v) (void)sizeof(v) +#define STBSP__NOTUSED(v) (void)sizeof(v) #endif #include // for va_arg(), va_list() @@ -207,8 +207,8 @@ typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, size_t count, char const *fmt, va_list va); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2, 3); -STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, size_t count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3, 4); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, size_t count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); @@ -263,12 +263,13 @@ static struct short temp; // force next field to be 2-byte aligned char pair[201]; } stbsp__digitpair = - { - 0, - "00010203040506070809101112131415161718192021222324" - "25262728293031323334353637383940414243444546474849" - "50515253545556575859606162636465666768697071727374" - "75767778798081828384858687888990919293949596979899"}; +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) { @@ -293,18 +294,13 @@ STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char ppe static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) { sign[0] = 0; - if (fl & STBSP__NEGATIVE) - { + if (fl & STBSP__NEGATIVE) { sign[0] = 1; sign[1] = '-'; - } - else if (fl & STBSP__LEADINGSPACE) - { + } else if (fl & STBSP__LEADINGSPACE) { sign[0] = 1; sign[1] = ' '; - } - else if (fl & STBSP__LEADINGPLUS) - { + } else if (fl & STBSP__LEADINGPLUS) { sign[0] = 1; sign[1] = '+'; } @@ -312,11 +308,10 @@ static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) { - char const *sn = s; + char const * sn = s; // get up to 4-byte alignment - for (;;) - { + for (;;) { if (((stbsp__uintptr)sn & 3) == 0) break; @@ -332,8 +327,7 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin // but becase it works 4B aligned, it will never cross page boundaries // (hence the STBSP__ASAN markup; the over-read here is intentional // and harmless) - while (limit >= 4) - { + while (limit >= 4) { stbsp__uint32 v = *(stbsp__uint32 *)sn; // bit hack to find if there's a 0 byte in there if ((v - 0x01010101) & (~v) & 0x80808080UL) @@ -344,8 +338,7 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin } // handle the last few characters to find actual size - while (limit && *sn) - { + while (limit && *sn) { ++sn; --limit; } @@ -363,47 +356,41 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, bf = buf; f = fmt; - for (;;) - { + for (;;) { stbsp__int32 fw, pr, tz; stbsp__uint32 fl; -// macros for the callback buffer stuff -#define stbsp__chk_cb_bufL(bytes) \ - { \ - int len = (int)(bf - buf); \ - if ((len + (bytes)) >= STB_SPRINTF_MIN) \ - { \ - tlen += len; \ - if (0 == (bf = buf = callback(buf, user, len))) \ - goto done; \ - } \ - } -#define stbsp__chk_cb_buf(bytes) \ - { \ - if (callback) \ - { \ - stbsp__chk_cb_bufL(bytes); \ - } \ - } -#define stbsp__flush_cb() \ - { \ - stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ - } // flush if there is even one byte in the buffer -#define stbsp__cb_buf_clamp(cl, v) \ - cl = v; \ - if (callback) \ - { \ - int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ - if (cl > lg) \ - cl = lg; \ - } + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } // fast copy everything up to the next % (or end of string) - for (;;) - { - while (((stbsp__uintptr)f) & 3) - { + for (;;) { + while (((stbsp__uintptr)f) & 3) { schk1: if (f[0] == '%') goto scandd; @@ -414,8 +401,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, *bf++ = f[0]; ++f; } - for (;;) - { + for (;;) { // Check if the next 4 bytes contain %(0x25) or end of string. // Using the 'hasless' trick: // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord @@ -429,18 +415,16 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if (callback) if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) goto schk1; -#ifdef STB_SPRINTF_NOUNALIGNED - if (((stbsp__uintptr)bf) & 3) + #ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else + #endif { - bf[0] = f[0]; - bf[1] = f[1]; - bf[2] = f[2]; - bf[3] = f[3]; - } - else -#endif - { - *(stbsp__uint32 *)bf = v; + *(stbsp__uint32 *)bf = v; } bf += 4; f += 4; @@ -457,10 +441,8 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, tz = 0; // flags - for (;;) - { - switch (f[0]) - { + for (;;) { + switch (f[0]) { // if we have left justify case '-': fl |= STBSP__LEFTJUST; @@ -488,19 +470,13 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, continue; // if we have kilo marker (none->kilo->kibi->jedec) case '$': - if (fl & STBSP__METRIC_SUFFIX) - { - if (fl & STBSP__METRIC_1024) - { + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { fl |= STBSP__METRIC_JEDEC; - } - else - { + } else { fl |= STBSP__METRIC_1024; } - } - else - { + } else { fl |= STBSP__METRIC_SUFFIX; } ++f; @@ -515,40 +491,30 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fl |= STBSP__LEADINGZERO; ++f; goto flags_done; - default: - goto flags_done; + default: goto flags_done; } } flags_done: // get the field width - if (f[0] == '*') - { + if (f[0] == '*') { fw = va_arg(va, stbsp__uint32); ++f; - } - else - { - while ((f[0] >= '0') && (f[0] <= '9')) - { + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { fw = fw * 10 + f[0] - '0'; f++; } } // get the precision - if (f[0] == '.') - { + if (f[0] == '.') { ++f; - if (f[0] == '*') - { + if (f[0] == '*') { pr = va_arg(va, stbsp__uint32); ++f; - } - else - { + } else { pr = 0; - while ((f[0] >= '0') && (f[0] <= '9')) - { + while ((f[0] >= '0') && (f[0] <= '9')) { pr = pr * 10 + f[0] - '0'; f++; } @@ -556,21 +522,19 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, } // handle integer size overrides - switch (f[0]) - { + switch (f[0]) { // are we halfwidth? case 'h': fl |= STBSP__HALFWIDTH; ++f; if (f[0] == 'h') - ++f; // QUARTERWIDTH + ++f; // QUARTERWIDTH break; // are we 64-bit (unix style) case 'l': fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); ++f; - if (f[0] == 'l') - { + if (f[0] == 'l') { fl |= STBSP__INTMAX; ++f; } @@ -591,29 +555,22 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, break; // are we 64-bit (msft style) case 'I': - if ((f[1] == '6') && (f[2] == '4')) - { + if ((f[1] == '6') && (f[2] == '4')) { fl |= STBSP__INTMAX; f += 3; - } - else if ((f[1] == '3') && (f[2] == '2')) - { + } else if ((f[1] == '3') && (f[2] == '2')) { f += 3; - } - else - { + } else { fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); ++f; } break; - default: - break; + default: break; } // handle each replacement - switch (f[0]) - { -#define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 char num[STBSP__NUMSZ]; char lead[8]; char tail[8]; @@ -659,8 +616,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, { int *d = va_arg(va, int *); *d = tlen + (int)(bf - buf); - } - break; + } break; #ifdef STB_SPRINTF_NOFLOAT case 'A': // float @@ -701,7 +657,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n64 <<= (64 - 56); if (pr < 15) n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); - // add leading chars +// add leading chars #ifdef STB_SPRINTF_MSVC_MODE *s++ = '0'; @@ -724,25 +680,21 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if (pr > (stbsp__int32)n) tz = pr - n; pr = 0; - while (n--) - { + while (n--) { *s++ = h[(n64 >> 60) & 15]; n64 <<= 4; } // print the expo tail[1] = h[17]; - if (dp < 0) - { + if (dp < 0) { tail[2] = '-'; dp = -dp; - } - else + } else tail[2] = '+'; n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); tail[0] = (char)n; - for (;;) - { + for (;;) { tail[n] = '0' + dp % 10; if (n <= 3) break; @@ -772,15 +724,13 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n = pr; if (l > (stbsp__uint32)pr) l = pr; - while ((l > 1) && (pr) && (sn[l - 1] == '0')) - { + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { --pr; --l; } // should we use %e - if ((dp <= -4) || (dp > (stbsp__int32)n)) - { + if ((dp <= -4) || (dp > (stbsp__int32)n)) { if (pr > (stbsp__int32)l) pr = l - 1; else if (pr) @@ -788,13 +738,10 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, goto doexpfromg; } // this is the insane action to get the pr to match %g semantics for %f - if (dp > 0) - { + if (dp > 0) { pr = (dp < (stbsp__int32)l) ? l - dp : 0; - } - else - { - pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32)l : pr); + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); } goto dofloatfromg; @@ -810,8 +757,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, doexpfromg: tail[0] = 0; stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) - { + if (dp == STBSP__SPECIAL) { s = (char *)sn; cs = 0; pr = 0; @@ -835,12 +781,10 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // dump expo tail[1] = h[0xe]; dp -= 1; - if (dp < 0) - { + if (dp < 0) { tail[2] = '-'; dp = -dp; - } - else + } else tail[2] = '+'; #ifdef STB_SPRINTF_MSVC_MODE n = 5; @@ -848,8 +792,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, n = (dp >= 100) ? 5 : 4; #endif tail[0] = (char)n; - for (;;) - { + for (;;) { tail[n] = '0' + dp % 10; if (n <= 3) break; @@ -863,14 +806,12 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, fv = va_arg(va, double); doafloat: // do kilos - if (fl & STBSP__METRIC_SUFFIX) - { + if (fl & STBSP__METRIC_SUFFIX) { double divisor; divisor = 1000.0f; if (fl & STBSP__METRIC_1024) divisor = 1024.0; - while (fl < 0x4000000) - { + while (fl < 0x4000000) { if ((fv < divisor) && (fv > -divisor)) break; fv /= divisor; @@ -885,8 +826,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, dofloatfromg: tail[0] = 0; stbsp__lead_sign(fl, lead); - if (dp == STBSP__SPECIAL) - { + if (dp == STBSP__SPECIAL) { s = (char *)sn; cs = 0; pr = 0; @@ -895,8 +835,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s = num + 64; // handle the three decimal varieties - if (dp <= 0) - { + if (dp <= 0) { stbsp__int32 i; // handle 0.000*000xxxx *s++ = '0'; @@ -906,110 +845,84 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, if ((stbsp__int32)n > pr) n = pr; i = n; - while (i) - { + while (i) { if ((((stbsp__uintptr)s) & 3) == 0) break; *s++ = '0'; --i; } - while (i >= 4) - { + while (i >= 4) { *(stbsp__uint32 *)s = 0x30303030; s += 4; i -= 4; } - while (i) - { + while (i) { *s++ = '0'; --i; } if ((stbsp__int32)(l + n) > pr) l = pr - n; i = l; - while (i) - { + while (i) { *s++ = *sn++; --i; } tz = pr - (n + l); cs = 1 + (3 << 24); // how many tens did we write (for commas below) - } - else - { + } else { cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; - if ((stbsp__uint32)dp >= l) - { + if ((stbsp__uint32)dp >= l) { // handle xxxx000*000.0 n = 0; - for (;;) - { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) - { + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { cs = 0; *s++ = stbsp__comma; - } - else - { + } else { *s++ = sn[n]; ++n; if (n >= l) break; } } - if (n < (stbsp__uint32)dp) - { + if (n < (stbsp__uint32)dp) { n = dp - n; - if ((fl & STBSP__TRIPLET_COMMA) == 0) - { - while (n) - { + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { if ((((stbsp__uintptr)s) & 3) == 0) break; *s++ = '0'; --n; } - while (n >= 4) - { + while (n >= 4) { *(stbsp__uint32 *)s = 0x30303030; s += 4; n -= 4; } } - while (n) - { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) - { + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { cs = 0; *s++ = stbsp__comma; - } - else - { + } else { *s++ = '0'; --n; } } } cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens - if (pr) - { + if (pr) { *s++ = stbsp__period; tz = pr; } - } - else - { + } else { // handle xxxxx.xxxx000*000 n = 0; - for (;;) - { - if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) - { + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { cs = 0; *s++ = stbsp__comma; - } - else - { + } else { *s++ = sn[n]; ++n; if (n >= (stbsp__uint32)dp) @@ -1021,8 +934,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, *s++ = stbsp__period; if ((l - dp) > (stbsp__uint32)pr) l = pr + dp; - while (n < l) - { + while (n < l) { *s++ = sn[n]; ++n; } @@ -1032,8 +944,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, pr = 0; // handle k,m,g,t - if (fl & STBSP__METRIC_SUFFIX) - { + if (fl & STBSP__METRIC_SUFFIX) { char idx; idx = 1; if (fl & STBSP__METRIC_NOSPACE) @@ -1041,16 +952,14 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, tail[0] = idx; tail[1] = ' '; { - if (fl >> 24) - { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. if (fl & STBSP__METRIC_1024) tail[idx + 1] = "_KMGT"[fl >> 24]; else tail[idx + 1] = "_kMGT"[fl >> 24]; idx++; // If printing kibits and not in jedec, add the 'i'. - if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) - { + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { tail[idx + 1] = 'i'; idx++; } @@ -1070,8 +979,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'b': // lower binary h = (f[0] == 'B') ? hexu : hex; lead[0] = 0; - if (fl & STBSP__LEADING_0X) - { + if (fl & STBSP__LEADING_0X) { lead[0] = 2; lead[1] = '0'; lead[2] = h[0xb]; @@ -1082,8 +990,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'o': // octal h = hexu; lead[0] = 0; - if (fl & STBSP__LEADING_0X) - { + if (fl & STBSP__LEADING_0X) { lead[0] = 1; lead[1] = '0'; } @@ -1101,8 +1008,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, h = (f[0] == 'X') ? hexu : hex; l = (4 << 4) | (4 << 8); lead[0] = 0; - if (fl & STBSP__LEADING_0X) - { + if (fl & STBSP__LEADING_0X) { lead[0] = 2; lead[1] = '0'; lead[2] = h[16]; @@ -1118,28 +1024,23 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, dp = 0; // clear tail, and clear leading if value is zero tail[0] = 0; - if (n64 == 0) - { + if (n64 == 0) { lead[0] = 0; - if (pr == 0) - { + if (pr == 0) { l = 0; cs = 0; goto scopy; } } // convert to string - for (;;) - { + for (;;) { *--s = h[n64 & ((1 << (l >> 8)) - 1)]; n64 >>= (l >> 8); if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) break; - if (fl & STBSP__TRIPLET_COMMA) - { + if (fl & STBSP__TRIPLET_COMMA) { ++l; - if ((l & 15) == ((l >> 4) & 15)) - { + if ((l & 15) == ((l >> 4) & 15)) { l &= ~15; *--s = stbsp__comma; } @@ -1156,30 +1057,24 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, case 'i': case 'd': // integer // get the integer and abs it - if (fl & STBSP__INTMAX) - { + if (fl & STBSP__INTMAX) { stbsp__int64 i64 = va_arg(va, stbsp__int64); n64 = (stbsp__uint64)i64; - if ((f[0] != 'u') && (i64 < 0)) - { + if ((f[0] != 'u') && (i64 < 0)) { n64 = (stbsp__uint64)-i64; fl |= STBSP__NEGATIVE; } - } - else - { + } else { stbsp__int32 i = va_arg(va, stbsp__int32); n64 = (stbsp__uint32)i; - if ((f[0] != 'u') && (i < 0)) - { + if ((f[0] != 'u') && (i < 0)) { n64 = (stbsp__uint32)-i; fl |= STBSP__NEGATIVE; } } #ifndef STB_SPRINTF_NOFLOAT - if (fl & STBSP__METRIC_SUFFIX) - { + if (fl & STBSP__METRIC_SUFFIX) { if (n64 < 1024) pr = 0; else if (pr == -1) @@ -1193,58 +1088,44 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s = num + STBSP__NUMSZ; l = 0; - for (;;) - { + for (;;) { // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) char *o = s - 8; - if (n64 >= 100000000) - { + if (n64 >= 100000000) { n = (stbsp__uint32)(n64 % 100000000); n64 /= 100000000; - } - else - { + } else { n = (stbsp__uint32)n64; n64 = 0; } - if ((fl & STBSP__TRIPLET_COMMA) == 0) - { - do - { + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { s -= 2; *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; n /= 100; } while (n); } - while (n) - { - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) - { + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { l = 0; *--s = stbsp__comma; --o; - } - else - { + } else { *--s = (char)(n % 10) + '0'; n /= 10; } } - if (n64 == 0) - { + if (n64 == 0) { if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) ++s; break; } while (s != o) - if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) - { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { l = 0; *--s = stbsp__comma; --o; - } - else - { + } else { *--s = '0'; } } @@ -1254,8 +1135,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // get the length that we copied l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); - if (l == 0) - { + if (l == 0) { *--s = '0'; l = 1; } @@ -1274,46 +1154,38 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, pr -= l; // handle right justify and leading zeros - if ((fl & STBSP__LEFTJUST) == 0) - { + if ((fl & STBSP__LEFTJUST) == 0) { if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr { pr = (fw > pr) ? fw : pr; fw = 0; - } - else - { + } else { fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas } } // copy the spaces and/or zeros - if (fw + pr) - { + if (fw + pr) { stbsp__int32 i; stbsp__uint32 c; // copy leading spaces (or when doing %8.4d stuff) if ((fl & STBSP__LEFTJUST) == 0) - while (fw > 0) - { + while (fw > 0) { stbsp__cb_buf_clamp(i, fw); fw -= i; - while (i) - { + while (i) { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = ' '; --i; } - while (i >= 4) - { + while (i >= 4) { *(stbsp__uint32 *)bf = 0x20202020; bf += 4; i -= 4; } - while (i) - { + while (i) { *bf++ = ' '; --i; } @@ -1322,12 +1194,10 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy leader sn = lead + 1; - while (lead[0]) - { + while (lead[0]) { stbsp__cb_buf_clamp(i, lead[0]); lead[0] -= (char)i; - while (i) - { + while (i) { *bf++ = *sn++; --i; } @@ -1338,34 +1208,27 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, c = cs >> 24; cs &= 0xffffff; cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; - while (pr > 0) - { + while (pr > 0) { stbsp__cb_buf_clamp(i, pr); pr -= i; - if ((fl & STBSP__TRIPLET_COMMA) == 0) - { - while (i) - { + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = '0'; --i; } - while (i >= 4) - { + while (i >= 4) { *(stbsp__uint32 *)bf = 0x30303030; bf += 4; i -= 4; } } - while (i) - { - if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) - { + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { cs = 0; *bf++ = stbsp__comma; - } - else + } else *bf++ = '0'; --i; } @@ -1375,13 +1238,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy leader if there is still one sn = lead + 1; - while (lead[0]) - { + while (lead[0]) { stbsp__int32 i; stbsp__cb_buf_clamp(i, lead[0]); lead[0] -= (char)i; - while (i) - { + while (i) { *bf++ = *sn++; --i; } @@ -1390,8 +1251,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy the string n = l; - while (n) - { + while (n) { stbsp__int32 i; stbsp__cb_buf_clamp(i, n); n -= i; @@ -1401,8 +1261,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, s += 4; i -= 4; }) - while (i) - { + while (i) { *bf++ = *s++; --i; } @@ -1410,26 +1269,22 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, } // copy trailing zeros - while (tz) - { + while (tz) { stbsp__int32 i; stbsp__cb_buf_clamp(i, tz); tz -= i; - while (i) - { + while (i) { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = '0'; --i; } - while (i >= 4) - { + while (i >= 4) { *(stbsp__uint32 *)bf = 0x30303030; bf += 4; i -= 4; } - while (i) - { + while (i) { *bf++ = '0'; --i; } @@ -1438,13 +1293,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // copy tail if there is one sn = tail + 1; - while (tail[0]) - { + while (tail[0]) { stbsp__int32 i; stbsp__cb_buf_clamp(i, tail[0]); tail[0] -= (char)i; - while (i) - { + while (i) { *bf++ = *sn++; --i; } @@ -1453,22 +1306,18 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, // handle the left justify if (fl & STBSP__LEFTJUST) - if (fw > 0) - { - while (fw) - { + if (fw > 0) { + while (fw) { stbsp__int32 i; stbsp__cb_buf_clamp(i, fw); fw -= i; - while (i) - { + while (i) { if ((((stbsp__uintptr)bf) & 3) == 0) break; *bf++ = ' '; --i; } - while (i >= 4) - { + while (i >= 4) { *(stbsp__uint32 *)bf = 0x20202020; bf += 4; i -= 4; @@ -1534,8 +1383,7 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, . return result; } -typedef struct stbsp__context -{ +typedef struct stbsp__context { char *buf; int count; int length; @@ -1550,17 +1398,14 @@ static char *stbsp__clamp_callback(const char *buf, void *user, int len) if (len > c->count) len = c->count; - if (len) - { - if (buf != c->buf) - { + if (len) { + if (buf != c->buf) { const char *s, *se; char *d; d = c->buf; s = buf; se = buf + len; - do - { + do { *d++ = *s++; } while (s < se); } @@ -1573,25 +1418,24 @@ static char *stbsp__clamp_callback(const char *buf, void *user, int len) return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can } -static char *stbsp__count_clamp_callback(const char *buf, void *user, int len) +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) { - stbsp__context *c = (stbsp__context *)user; - (void)sizeof(buf); + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); c->length += len; return c->tmp; // go direct into buffer if you can } -STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, size_t count, char const *fmt, va_list va) +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, size_t count, char const * fmt, va_list va ) { stbsp__context c; - if ((count == 0) && !buf) + if ( (count == 0) && !buf ) { c.length = 0; - STB_SPRINTF_DECORATE(vsprintfcb) - (stbsp__count_clamp_callback, &c, c.tmp, fmt, va); + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); } else { @@ -1601,12 +1445,11 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, size_t count, ch c.count = count; c.length = 0; - STB_SPRINTF_DECORATE(vsprintfcb) - (stbsp__clamp_callback, &c, stbsp__clamp_callback(0, &c, 0), fmt, va); + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); // zero-terminate - l = (int)(c.buf - buf); - if (l >= count) // should never be greater, only equal (or less) than count + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count l = count - 1; buf[l] = 0; } @@ -1658,89 +1501,98 @@ static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, *bits = b & ((((stbsp__uint64)1) << 52) - 1); *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); - return (stbsp__int32)((stbsp__uint64)b >> 63); + return (stbsp__int32)((stbsp__uint64) b >> 63); } static double const stbsp__bot[23] = { - 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, - 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022}; + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; static double const stbsp__negbot[22] = { - 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, - 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022}; + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; static double const stbsp__negboterr[22] = { - -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, - 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, - -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, - 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039}; + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; static double const stbsp__top[13] = { - 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299}; + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; static double const stbsp__negtop[13] = { - 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299}; + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; static double const stbsp__toperr[13] = { - 8388608, - 6.8601809640529717e+028, - -7.253143638152921e+052, - -4.3377296974619174e+075, - -1.5559416129466825e+098, - -3.2841562489204913e+121, - -3.7745893248228135e+144, - -1.7356668416969134e+167, - -3.8893577551088374e+190, - -9.9566444326005119e+213, - 6.3641293062232429e+236, - -5.2069140800249813e+259, - -5.2504760255204387e+282}; + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; static double const stbsp__negtoperr[13] = { - 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, - -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, - 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, - 8.0970921678014997e-317}; + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; #if defined(_MSC_VER) && (_MSC_VER <= 1200) static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U}; + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; #define stbsp__tento19th ((stbsp__uint64)1000000000000000000) #else static stbsp__uint64 const stbsp__powten[20] = { - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000ULL, - 100000000000ULL, - 1000000000000ULL, - 10000000000000ULL, - 100000000000000ULL, - 1000000000000000ULL, - 10000000000000000ULL, - 100000000000000000ULL, - 1000000000000000000ULL, - 10000000000000000000ULL}; + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; #define stbsp__tento19th (1000000000000000000ULL) #endif @@ -1786,12 +1638,9 @@ static stbsp__uint64 const stbsp__powten[20] = { static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 { double ph, pl; - if ((power >= 0) && (power <= 22)) - { + if ((power >= 0) && (power <= 22)) { stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); - } - else - { + } else { stbsp__int32 e, et, eb; double p2h, p2l; @@ -1805,16 +1654,13 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i ph = d; pl = 0.0; - if (power < 0) - { - if (eb) - { + if (power < 0) { + if (eb) { --eb; stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); } - if (et) - { + if (et) { stbsp__ddrenorm(ph, pl); --et; stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); @@ -1822,18 +1668,14 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i ph = p2h; pl = p2l; } - } - else - { - if (eb) - { + } else { + if (eb) { e = eb; if (eb > 22) eb = 22; e -= eb; stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); - if (e) - { + if (e) { stbsp__ddrenorm(ph, pl); stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); @@ -1841,8 +1683,7 @@ static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__i pl = p2l; } } - if (et) - { + if (et) { stbsp__ddrenorm(ph, pl); --et; stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); @@ -1870,7 +1711,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c d = value; STBSP__COPYFP(bits, d); expo = (stbsp__int32)((bits >> 52) & 2047); - ng = (stbsp__int32)((stbsp__uint64)bits >> 63); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); if (ng) d = -d; @@ -1884,7 +1725,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c if (expo == 0) // is zero or denormal { - if (((stbsp__uint64)bits << 1) == 0) // do zero + if (((stbsp__uint64) bits << 1) == 0) // do zero { *decimal_pos = 1; *start = out; @@ -1895,8 +1736,7 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // find the right expo for denormals { stbsp__int64 v = ((stbsp__uint64)1) << 51; - while ((bits & v) == 0) - { + while ((bits & v) == 0) { --expo; v >>= 1; } @@ -1924,19 +1764,16 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // now do the rounding in integer land frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); - if ((frac_digits < 24)) - { + if ((frac_digits < 24)) { stbsp__uint32 dg = 1; if ((stbsp__uint64)bits >= stbsp__powten[9]) dg = 10; - while ((stbsp__uint64)bits >= stbsp__powten[dg]) - { + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { ++dg; if (dg == 20) goto noround; } - if (frac_digits < dg) - { + if (frac_digits < dg) { stbsp__uint64 r; // add 0.5 at the right position and round e = dg - frac_digits; @@ -1952,11 +1789,9 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c } // kill long trailing runs of zeros - if (bits) - { + if (bits) { stbsp__uint32 n; - for (;;) - { + for (;;) { if (bits <= 0xffffffff) break; if (bits % 1000) @@ -1973,39 +1808,31 @@ static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, c // convert to string out += 64; e = 0; - for (;;) - { + for (;;) { stbsp__uint32 n; char *o = out - 8; // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) - if (bits >= 100000000) - { + if (bits >= 100000000) { n = (stbsp__uint32)(bits % 100000000); bits /= 100000000; - } - else - { + } else { n = (stbsp__uint32)bits; bits = 0; } - while (n) - { + while (n) { out -= 2; *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; n /= 100; e += 2; } - if (bits == 0) - { - if ((e) && (out[0] == '0')) - { + if (bits == 0) { + if ((e) && (out[0] == '0')) { ++out; --e; } break; } - while (out != o) - { + while (out != o) { *--out = '0'; ++e; } @@ -2076,4 +1903,4 @@ AUTHORS 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. ------------------------------------------------------------------------------ -*/ +*/ \ No newline at end of file