From bdd316724e167d8d26a531a6dee93a9227912bfa Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 3 Nov 2025 19:27:02 +0100 Subject: [PATCH] new_os: vendor/libc --- vendor/libc/stdio.odin | 66 +++++++----------------- vendor/libc/stdio_js.odin | 60 ++++++++++++++++++++++ vendor/libc/stdio_os.odin | 104 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 49 deletions(-) create mode 100644 vendor/libc/stdio_js.odin create mode 100644 vendor/libc/stdio_os.odin diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin index d41f790ee..5a1a63113 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc/stdio.odin @@ -4,93 +4,60 @@ package odin_libc import "base:runtime" import "core:c" -import "core:io" -import "core:os" import "core:strconv" import stb "vendor:stb/sprintf" -FILE :: uintptr +FILE :: rawptr EOF :: -1 @(require, linkage="strong", link_name="fopen") fopen :: proc "c" (path: cstring, mode: cstring) -> FILE { context = g_ctx - unimplemented("vendor/libc: fopen") + return _fopen(path, mode) } @(require, linkage="strong", link_name="fseek") fseek :: proc "c" (file: FILE, offset: c.long, whence: i32) -> i32 { context = g_ctx - handle := os.Handle(file-1) - _, err := os.seek(handle, i64(offset), int(whence)) - if err != nil { - return -1 - } - return 0 + return _fseek(file, offset, whence) } @(require, linkage="strong", link_name="ftell") ftell :: proc "c" (file: FILE) -> c.long { context = g_ctx - handle := os.Handle(file-1) - off, err := os.seek(handle, 0, os.SEEK_CUR) - if err != nil { - return -1 - } - return c.long(off) + return _ftell(file) } @(require, linkage="strong", link_name="fclose") fclose :: proc "c" (file: FILE) -> i32 { context = g_ctx - handle := os.Handle(file-1) - if os.close(handle) != nil { - return -1 - } - return 0 + return _fclose(file) } @(require, linkage="strong", link_name="fread") fread :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { context = g_ctx - handle := os.Handle(file-1) - n, _ := os.read(handle, buffer[:min(size, count)]) - return uint(max(0, n)) + return _fread(buffer, size, count, file) } @(require, linkage="strong", link_name="fwrite") fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { context = g_ctx - handle := os.Handle(file-1) - n, _ := os.write(handle, buffer[:min(size, count)]) - return uint(max(0, n)) + return _fwrite(buffer, size, count, file) } @(require, linkage="strong", link_name="putchar") putchar :: proc "c" (char: c.int) -> c.int { context = g_ctx - - n, err := os.write_byte(os.stdout, byte(char)) - if n == 0 || err != nil { - return EOF - } - return char + return _putchar(char) } @(require, linkage="strong", link_name="getchar") getchar :: proc "c" () -> c.int { - when #defined(os.stdin) { - ret: [1]byte - n, err := os.read(os.stdin, ret[:]) - if n == 0 || err != nil { - return EOF - } - return c.int(ret[0]) - } else { - return EOF - } + context = g_ctx + return _getchar() } @(require, linkage="strong", link_name="vsnprintf") @@ -109,8 +76,6 @@ vsprintf :: proc "c" (buf: [^]byte, fmt: cstring, args: ^c.va_list) -> i32 { vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { context = g_ctx - handle := os.Handle(file-1) - MAX_STACK :: 4096 buf: []byte @@ -133,12 +98,15 @@ vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { delete(buf) } - _, err := io.write_full(os.stream_from_handle(handle), buf) - if err != nil { - return -1 + written: i32 + for len(buf) > 0 { + n := _fwrite(raw_data(buf), size_of(byte), len(buf), file) + if n == 0 { break } + buf = buf[n:] + written += i32(n) } - return i32(len(buf)) + return written } /* diff --git a/vendor/libc/stdio_js.odin b/vendor/libc/stdio_js.odin new file mode 100644 index 000000000..2382ed449 --- /dev/null +++ b/vendor/libc/stdio_js.odin @@ -0,0 +1,60 @@ +#+private +package odin_libc + +import "core:c" + +foreign import "odin_env" + +_fopen :: proc(path, mode: cstring) -> FILE { + unimplemented("vendor/libc: fopen in JS") +} + +_fseek :: proc(file: FILE, offset: c.long, whence: i32) -> i32 { + unimplemented("vendor/libc: fseek in JS") +} + +_ftell :: proc(file: FILE) -> c.long { + unimplemented("vendor/libc: ftell in JS") +} + +_fclose :: proc(file: FILE) -> i32 { + unimplemented("vendor/libc: fclose in JS") +} + +_fread :: proc(buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { + unimplemented("vendor/libc: fread in JS") +} + +_fwrite :: proc(buffer: [^]byte, size: uint, count: uint, file: FILE) -> uint { + fd, ok := __fd(file) + if !ok { + return 0 + } + + __write(fd, buffer[:size*count]) + return count +} + +_putchar :: proc(char: c.int) -> c.int { + __write(1, {byte(char)}) + return char +} + +_getchar :: proc() -> c.int { + return EOF +} + +@(private="file") +foreign odin_env { + @(link_name="write") + __write :: proc "contextless" (fd: u32, p: []byte) --- +} + +@(private="file") +__fd :: proc(file: FILE) -> (u32, bool) { + switch (uint(uintptr(file))) { + case 2: return 1, true // stdout + case 3: return 2, true // stderr + case: return 0, false + } +} diff --git a/vendor/libc/stdio_os.odin b/vendor/libc/stdio_os.odin new file mode 100644 index 000000000..db40fb250 --- /dev/null +++ b/vendor/libc/stdio_os.odin @@ -0,0 +1,104 @@ +#+build !freestanding +#+build !js +package odin_libc + +import "core:io" +import "core:c" +import os "core:os/os2" + +_fopen :: proc(path, _mode: cstring) -> FILE { + flags: os.File_Flags + + mode := string(_mode) + if len(mode) > 1 { + switch mode[0] { + case 'r': + flags += {.Read} + case 'w': + flags += {.Write, .Create, .Trunc} + case 'a': + flags += {.Write, .Create, .Append} + case: + return nil + } + + if len(mode) > 1 && mode[1] == '+' { + flags += {.Write, .Read} + } else if len(mode) > 2 && mode[1] == 'b' && mode[2] == '+' { + flags += {.Write, .Read} + } + } + + file, err := os.open(string(path), flags, os.Permissions_Read_Write_All) + if err != nil { + return nil + } + + return FILE(file) +} + +_fseek :: proc(_file: FILE, offset: c.long, whence: i32) -> i32 { + file := __file(_file) + if _, err := os.seek(file, i64(offset), io.Seek_From(whence)); err != nil { + return -1 + } + + return 0 +} + +_ftell :: proc(_file: FILE) -> c.long { + file := __file(_file) + pos, err := os.seek(file, 0, .Current) + if err != nil { + return -1 + } + + return c.long(pos) +} + +_fclose :: proc(_file: FILE) -> i32 { + file := __file(_file) + if err := os.close(file); err != nil { + return EOF + } + + return 0 +} + +_fread :: proc(buffer: [^]byte, size: uint, count: uint, _file: FILE) -> uint { + file := __file(_file) + n, _ := os.read(file, buffer[:size*count]) + return uint(max(0, n)) / size +} + +_fwrite :: proc(buffer: [^]byte, size: uint, count: uint, _file: FILE) -> uint { + file := __file(_file) + n, _ := os.write(file, buffer[:size*count]) + return uint(max(0, n)) / size +} + +_putchar :: proc(char: c.int) -> c.int { + n, err := os.write_byte(os.stdout, byte(char)) + if n == 0 || err != nil { + return EOF + } + return char +} + +_getchar :: proc() -> c.int { + ret: [1]byte + n, err := os.read(os.stdin, ret[:]) + if n == 0 || err != nil { + return EOF + } + return c.int(ret[0]) +} + +@(private="file") +__file :: proc(file: FILE) -> ^os.File { + switch (uint(uintptr(file))) { + case 2: return os.stdout + case 3: return os.stderr + case: return (^os.File)(file) + } +}