From 140c902eff2569e5f1491fc12649c6718a6ba600 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 12 Mar 2025 18:45:14 +0100 Subject: [PATCH] vendor/libc: a bunch of additions All these additions are to allow Dear ImGui to be compiled natively. --- vendor/libc/ctype.odin | 33 +++ vendor/libc/include/alloca.h | 21 ++ vendor/libc/include/assert.h | 12 + vendor/libc/include/ctype.h | 15 ++ vendor/libc/include/inttypes.h | 0 vendor/libc/include/math.h | 49 +++- vendor/libc/include/stdio.h | 58 ++++- vendor/libc/include/stdlib.h | 25 ++ vendor/libc/include/string.h | 11 + vendor/libc/include/time.h | 16 ++ vendor/libc/math.odin | 124 +++++++++- vendor/libc/stdio.odin | 413 ++++++++++++++++++++++++++++++++- vendor/libc/stdlib.odin | 73 +++++- vendor/libc/string.odin | 10 + vendor/libc/time.odin | 10 + 15 files changed, 855 insertions(+), 15 deletions(-) create mode 100644 vendor/libc/ctype.odin create mode 100644 vendor/libc/include/alloca.h create mode 100644 vendor/libc/include/ctype.h create mode 100644 vendor/libc/include/inttypes.h create mode 100644 vendor/libc/include/time.h create mode 100644 vendor/libc/time.odin diff --git a/vendor/libc/ctype.odin b/vendor/libc/ctype.odin new file mode 100644 index 000000000..8813055d7 --- /dev/null +++ b/vendor/libc/ctype.odin @@ -0,0 +1,33 @@ +package odin_libc + +@(require, linkage="strong", link_name="isdigit") +isdigit :: proc "c" (c: i32) -> b32 { + switch c { + case '0'..='9': return true + case: return false + } +} + +@(require, linkage="strong", link_name="isblank") +isblank :: proc "c" (c: i32) -> b32 { + switch c { + case '\t', ' ': return true + case: return false + } +} + +@(require, linkage="strong", link_name="isspace") +isspace :: proc "c" (c: i32) -> b32 { + switch c { + case '\t', ' ', '\n', '\v', '\f', '\r': return true + case: return false + } +} + +@(require, linkage="strong", link_name="toupper") +toupper :: proc "c" (c: i32) -> i32 { + if c >= 'a' && c <= 'z' { + return c - ('a' - 'A') + } + return c +} diff --git a/vendor/libc/include/alloca.h b/vendor/libc/include/alloca.h new file mode 100644 index 000000000..8b4d19018 --- /dev/null +++ b/vendor/libc/include/alloca.h @@ -0,0 +1,21 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +#include + +void *alloca(size_t); /* built-in for gcc */ + +#if defined(__GNUC__) && __GNUC__ >= 3 +/* built-in for gcc 3 */ +#undef alloca +#undef __alloca +#define alloca(size) __alloca(size) +#define __alloca(size) __builtin_alloca(size) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/assert.h b/vendor/libc/include/assert.h index a6fb6c696..4e8cd85a4 100644 --- a/vendor/libc/include/assert.h +++ b/vendor/libc/include/assert.h @@ -1,3 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #ifdef NDEBUG #define assert(e) ((void)0) #else @@ -14,3 +20,9 @@ void __odin_libc_assert_fail(const char *, const char *, int, const char *); (__builtin_expect(!(e), 0) ? __odin_libc_assert_fail(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0) #endif /* NDEBUG */ + +#define static_assert _Static_assert + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/ctype.h b/vendor/libc/include/ctype.h new file mode 100644 index 000000000..a579b5674 --- /dev/null +++ b/vendor/libc/include/ctype.h @@ -0,0 +1,15 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +int isdigit(int c); +int isblank(int c); +int isspace(int c); + +int toupper(int c); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/inttypes.h b/vendor/libc/include/inttypes.h new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h index 9d486da11..9903ac3f9 100644 --- a/vendor/libc/include/math.h +++ b/vendor/libc/include/math.h @@ -1,21 +1,66 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include +#define INFINITY (1.0 / 0.0) +#define NAN (0.0 / 0.0) + float sqrtf(float); float cosf(float); float sinf(float); float atan2f(float, float); -bool isnan(float); -bool isinf(float); + +float floorf(float x); double floor(double x); +float ceilf(float x); double ceil(double x); double sqrt(double x); +float powf(float x, float y); double pow(double x, double y); +float fmodf(float x, float y); double fmod(double x, double y); double cos(double x); +float acosf(float x); double acos(double x); +float fabsf(float x); double fabs(double x); int abs(int); double ldexp(double, int); double exp(double); +float logf(float); double log(double); double sin(double); +double trunc(double); +double log2(double); +double log10(double); +double asin(double); +double atan(double); +double tan(double); +double atan2(double, double); +double modf(double, double*); + +bool __isnanf(float); +bool __isnand(double); +#define isnan(x) \ + ( sizeof(x) == sizeof(float) ? __isnanf((float)(x)) \ + : : __isnand((double)(x))) + +bool __isinff(float); +bool __isinfd(double); +#define isinf(x) \ + ( sizeof(x) == sizeof(float) ? __isinff((float)(x)) \ + : : __isinfd((double)(x))) + +bool __isfinitef(float); +bool __isfinited(double); +#define isfinite(x) \ + ( sizeof(x) == sizeof(float) ? __isfinitef((float)(x)) \ + : : __isfinited((double)(x))) + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/stdio.h b/vendor/libc/include/stdio.h index 807437f3c..06339c1a3 100644 --- a/vendor/libc/include/stdio.h +++ b/vendor/libc/include/stdio.h @@ -1,8 +1,14 @@ -#include -#include +#ifdef __cplusplus +extern "C" { +#endif #pragma once +#include +#include +#include +#include + typedef struct {} FILE; #define SEEK_SET 0 @@ -12,6 +18,8 @@ typedef struct {} FILE; #define stdout ((FILE *)2) #define stderr ((FILE *)3) +#define EOF -1 + FILE *fopen(const char *, char *); int fclose(FILE *); int fseek(FILE *, long, int); @@ -21,6 +29,10 @@ size_t fwrite(const void *, size_t, size_t, FILE *); int vfprintf(FILE *, const char *, va_list); int vsnprintf(char *, size_t, const char *, va_list); +int vsprintf(char *, const char *, va_list); + +int putchar(int ch); +int getchar(); static inline int snprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; @@ -30,6 +42,14 @@ static inline int snprintf(char *buf, size_t size, const char *fmt, ...) { return result; } +static inline int sprintf(char *buf, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int result = vsprintf(buf, fmt, args); + va_end(args); + return result; +} + static inline int fprintf(FILE *f, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -45,3 +65,37 @@ static inline int printf(const char *fmt, ...) { va_end(args); return result; } + +int __sscanf(const char *str, const char *format, void *ptrs); + +static inline int vsscanf(const char *str, const char *format, va_list ap) { + int count = 0; + for (int i = 0; format[i]; i++) { + if (format[i] == '%') { + if (format[i+1] == '%') { + i++; + continue; + } + count++; + } + } + + void **ptrs = (void **)(alloca(count*sizeof(void *))); + for (int i = 0; i < count; i++) { + ptrs[i] = va_arg(ap, void *); + } + + return __sscanf(str, format, ptrs); +} + +static inline int sscanf(const char *str, const char *format, ...) { + va_list args; + va_start(args, format); + int res = vsscanf(str, format, args); + va_end(args); + return res; +} + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/stdlib.h b/vendor/libc/include/stdlib.h index 22cfc528b..01c6ac6b2 100644 --- a/vendor/libc/include/stdlib.h +++ b/vendor/libc/include/stdlib.h @@ -1,3 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include void *malloc(size_t size); @@ -17,3 +23,22 @@ long long atoll(const char *); double atof(const char *); long strtol(const char *, char **, int); +double strtod(const char *, char **); + +void abort(); +void exit(int exit_code); + +#define ATEXIT_MAX 32 + +int atexit(typeof(void (void)) *); + +typedef struct { + long int quot; + long int rem; +} ldiv_t; + +ldiv_t ldiv(long int number, long int denom); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/string.h b/vendor/libc/include/string.h index 4571f9454..7e5e2b252 100644 --- a/vendor/libc/include/string.h +++ b/vendor/libc/include/string.h @@ -1,9 +1,16 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include void *memcpy(void *, const void *, size_t); void *memset(void *, int, size_t); void *memmove(void *, void *, size_t); int memcmp(const void *, const void *, size_t); +void *memchr(const void *, int, size_t); unsigned long strlen(const char *str); @@ -19,3 +26,7 @@ int strcmp(const char *, const char *); int strncmp(const char *, const char *, size_t); char *strstr(const char *, const char *); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/time.h b/vendor/libc/include/time.h new file mode 100644 index 000000000..369e25256 --- /dev/null +++ b/vendor/libc/include/time.h @@ -0,0 +1,16 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +#include + +typedef int64_t clock_t; +typedef clock_t time_t; + +clock_t clock(); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin index af319ac6d..93df1fea6 100644 --- a/vendor/libc/math.odin +++ b/vendor/libc/math.odin @@ -14,23 +14,28 @@ cosf :: proc "c" (v: f32) -> f32 { return math.cos(v) } -@(require, linkage="strong", link_name="sinf") -sinf :: proc "c" (v: f32) -> f32 { - return math.sin(v) -} - @(require, linkage="strong", link_name="atan2f") atan2f :: proc "c" (v: f32, v2: f32) -> f32 { return math.atan2(v, v2) } -@(require, linkage="strong", link_name="isnan") -isnan :: proc "c" (v: f32) -> bool { +@(require, linkage="strong", link_name="__isnanf") +isnanf :: proc "c" (v: f32) -> bool { return math.is_nan(v) } -@(require, linkage="strong", link_name="isinf") -isinf :: proc "c" (v: f32) -> bool { +@(require, linkage="strong", link_name="__isnand") +isnand :: proc "c" (v: f64) -> bool { + return math.is_nan(v) +} + +@(require, linkage="strong", link_name="__isinff") +isinff :: proc "c" (v: f32) -> bool { + return math.is_inf(v) +} + +@(require, linkage="strong", link_name="__isinfd") +isinfd :: proc "c" (v: f64) -> bool { return math.is_inf(v) } @@ -39,21 +44,41 @@ sqrt :: proc "c" (x: f64) -> f64 { return math.sqrt(x) } +@(require, linkage="strong", link_name="floorf") +floorf :: proc "c" (x: f32) -> f32 { + return math.floor(x) +} + @(require, linkage="strong", link_name="floor") floor :: proc "c" (x: f64) -> f64 { return math.floor(x) } +@(require, linkage="strong", link_name="ceilf") +ceilf :: proc "c" (x: f32) -> f32 { + return math.ceil(x) +} + @(require, linkage="strong", link_name="ceil") ceil :: proc "c" (x: f64) -> f64 { return math.ceil(x) } +@(require, linkage="strong", link_name="powf") +powf :: proc "c" (x, y: f32) -> f32 { + return math.pow(x, y) +} + @(require, linkage="strong", link_name="pow") pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } +@(require, linkage="strong", link_name="fmodf") +fmodf :: proc "c" (x, y: f32) -> f32 { + return math.mod(x, y) +} + @(require, linkage="strong", link_name="fmod") fmod :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) @@ -64,11 +89,21 @@ cos :: proc "c" (x: f64) -> f64 { return math.cos(x) } +@(require, linkage="strong", link_name="acosf") +acosf :: proc "c" (x: f32) -> f32 { + return math.acos(x) +} + @(require, linkage="strong", link_name="acos") acos :: proc "c" (x: f64) -> f64 { return math.acos(x) } +@(require, linkage="strong", link_name="fabsf") +fabsf :: proc "c" (x: f32) -> f32 { + return math.abs(x) +} + @(require, linkage="strong", link_name="fabs") fabs :: proc "c" (x: f64) -> f64 { return math.abs(x) @@ -89,6 +124,11 @@ exp :: proc "c" (x: f64) -> f64 { return math.exp(x) } +@(require, linkage="strong", link_name="logf") +logf :: proc "c" (x: f32) -> f32 { + return math.ln(x) +} + @(require, linkage="strong", link_name="log") log :: proc "c" (x: f64) -> f64 { return math.ln(x) @@ -98,3 +138,69 @@ log :: proc "c" (x: f64) -> f64 { sin :: proc "c" (x: f64) -> f64 { return math.sin(x) } + +@(require, linkage="strong", link_name="sinf") +sinf :: proc "c" (v: f32) -> f32 { + return math.sin(v) +} + + +@(require, linkage="strong", link_name="trunc") +trunc :: proc "c" (x: f64) -> f64 { + return math.trunc(x) +} + +@(require, linkage="strong", link_name="__isfinitef") +isfinitef :: proc "c" (x: f32) -> bool { + switch math.classify(x) { + case .Normal, .Subnormal, .Zero, .Neg_Zero: return true + case .Inf, .Neg_Inf, .NaN: return false + case: unreachable() + } +} + +@(require, linkage="strong", link_name="__isfinited") +isfinited :: proc "c" (x: f64) -> bool { + switch math.classify(x) { + case .Normal, .Subnormal, .Zero, .Neg_Zero: return true + case .Inf, .Neg_Inf, .NaN: return false + case: unreachable() + } +} + +@(require, linkage="strong", link_name="log2") +log2 :: proc "c" (x: f64) -> f64 { + return math.log2(x) +} + +@(require, linkage="strong", link_name="log10") +log10 :: proc "c" (x: f64) -> f64 { + return math.log10(x) +} + +@(require, linkage="strong", link_name="asin") +asin :: proc "c" (x: f64) -> f64 { + return math.asin(x) +} + +@(require, linkage="strong", link_name="atan") +atan :: proc "c" (x: f64) -> f64 { + return math.atan(x) +} + +@(require, linkage="strong", link_name="tan") +tan :: proc "c" (x: f64) -> f64 { + return math.tan(x) +} + +@(require, linkage="strong", link_name="atan2") +atan2 :: proc "c" (y: f64, x: f64) -> f64 { + return math.atan2(y, x) +} + +@(require, linkage="strong", link_name="modf") +modf :: proc "c" (num: f64, iptr: ^f64) -> f64 { + integral, fractional := math.modf(num) + iptr^ = integral + return fractional +} diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin index 97667a5c8..d41f790ee 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc/stdio.odin @@ -1,18 +1,23 @@ #+build !freestanding 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 +EOF :: -1 + @(require, linkage="strong", link_name="fopen") fopen :: proc "c" (path: cstring, mode: cstring) -> FILE { context = g_ctx - unimplemented("odin_libc.fopen") + unimplemented("vendor/libc: fopen") } @(require, linkage="strong", link_name="fseek") @@ -63,6 +68,31 @@ fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uin return uint(max(0, n)) } +@(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 +} + +@(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 + } +} + @(require, linkage="strong", link_name="vsnprintf") vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list) -> i32 { i32_count := i32(count) @@ -70,6 +100,11 @@ vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list return stb.vsnprintf(buf, i32_count, fmt, args) } +@(require, linkage="strong", link_name="vsprintf") +vsprintf :: proc "c" (buf: [^]byte, fmt: cstring, args: ^c.va_list) -> i32 { + return stb.vsprintf(buf, fmt, args) +} + @(require, linkage="strong", link_name="vfprintf") vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { context = g_ctx @@ -105,3 +140,379 @@ vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { return i32(len(buf)) } + +/* +Derived from musl libc - MIT licensed - Copyright © 2005-2020 Rich Felker, et al. +*/ +@(require, linkage="strong", link_name="__sscanf") +_sscanf :: proc "c" (str, fmt: [^]byte, orig_ptrs: [^]rawptr) -> i32 { + Size :: enum u8 { + None, + hh, + h, + l, + L, + ll, + } + + store_int :: proc(dest: rawptr, size: Size, i: u64) { + if dest == nil { return } + #partial switch size { + case .hh: + (^c.char)(dest)^ = c.char(i) + case .h: + (^c.short)(dest)^ = c.short(i) + case .None: + (^c.int)(dest)^ = c.int(i) + case .l: + (^c.long)(dest)^ = c.long(i) + case .ll: + (^c.longlong)(dest)^ = c.longlong(i) + } + } + + context = g_ctx + + str := str + ptrs := orig_ptrs + + // TODO: implement wide char variants + + pos: u64 + dest: rawptr + ch, t: byte + // wcs: [^]c.wchar_t + s: [^]byte + k, i, width: int + alloc: bool + scanset: [257]byte + invert: u8 + matches: i32 + size: Size + input_fail, match_fail, fmt_fail, alloc_fail: bool + + main_loop: for p := fmt; p[0] != 0; p = p[1:] { + alloc = false + + if isspace(i32(p[0])) { + for isspace(i32(p[0])) { + p = p[1:] + } + for isspace(i32(str[0])) { + str = str[1:] + pos += 1 + } + } + + if p[0] != '%' || p[1] == '%' { + if p[0] == '%' { + p = p[1:] + } + ch = str[0] + if ch != p[0] { + if ch == 0 { + input_fail = true + break + } + match_fail = true + break + } + pos += 1 + continue + } + + p = p[1:] + if p[0] == '*' { + dest = nil + p = p[1:] + } else if isdigit(i32(p[0])) && p[1] == '$' { + dest = orig_ptrs[p[0] - '0'] + p = p[2:] + } else { + dest = ptrs[0] + ptrs = ptrs[1:] + } + + for width = 0; isdigit(i32(p[0])); p = p[1:] { + width = 10 * width + int(p[0] - '0') + } + + if p[0] == 'm' { + // wcs = nil + s = nil + alloc = dest != nil + p = p[1:] + } else { + alloc = false + } + + size = .None + p = p[1:] + switch p[-1] { + case 'h': + size = .h + if p[0] == 'h' { + p = p[1:] + size = .hh + } + case 'l': + size = .l + if p[0] == 'l' { + p = p[1:] + size = .ll + } + case 'j': + size = .ll + case 'z', 't': + size = .l + case 'L': + size = .L + case 'd', 'i', 'o', 'u', 'x', + 'a', 'e', 'f', 'g', + 'A', 'E', 'F', 'G', 'X', + 's', 'c', '[', + 'S', 'C', 'p', 'n': + p = p[-1:] + case: + fmt_fail = true + break main_loop + } + + t = p[0] + + switch t { + case 'C': + t = 'c' + size = .l + case 'S': + t = 's' + size = .l + } + + switch t { + case 'c': + if width < 1 { + width = 1 + } + case '[': + case 'n': + store_int(dest, size, pos) + continue + case: + for isspace(i32(str[0])) { + str = str[1:] + pos += 1 + } + } + + if str[0] == 0 { + input_fail = true + break + } + + if width == 0 { + width = max(int) + } + + switch t { + case 's', 'c', '[': + if t == 'c' || t == 's' { + runtime.memset(&scanset, -1, size_of(scanset)) + scanset[0] = 0 + if t == 's' { + scanset['\t'] = 0 + scanset['\n'] = 0 + scanset['\v'] = 0 + scanset['\f'] = 0 + scanset['\r'] = 0 + scanset[' '] = 0 + } + } else { + p = p[1:] + invert = 0 + if p[0] == '^' { + p = p[1:] + invert = 1 + } + + runtime.memset(&scanset, i32(invert), size_of(scanset)) + scanset[0] = 0 + if p[0] == '-' { + p = p[1:] + scanset['-'] = 1 - invert + } else if p[0] == ']' { + p = p[1:] + scanset[']'] = 1 - invert + } + + for ; p[0] != ']'; p = p[1:] { + if p[0] == 0 { + fmt_fail = true + break main_loop + } + if p[0] == '-' && p[1] != ']' { + c := p + p = p[1:] + for ch = c[0]; c[0] < p[0]; c, ch = c[1:], c[0] { + scanset[ch] = 1 - invert + } + scanset[p[0]] = 1 - invert + } + } + } + + // wcs = nil + s = nil + i = 0 + k = t == 'c' ? width + 1 : 31 + if size == .l { + unimplemented("vendor/libc: sscanf wide character support") + } else if alloc { + s = make([^]byte, k) + if s == nil { + alloc_fail = true + break main_loop + } + + for ch = str[0]; scanset[ch] != 0 && i < width; { + s[i] = ch + i += 1 + if i == k { + old_size := k + k += k + 1 + tmp, _ := runtime.non_zero_mem_resize(s, old_size, k) + if tmp == nil { + alloc_fail = true + break main_loop + } + s = raw_data(tmp) + } + + str = str[1:] + ch = str[0] + } + } else { + s = cast([^]byte)dest + if s != nil { + for ch = str[0]; scanset[ch] != 0 && i < width; { + s[i] = ch + i += 1 + + str = str[1:] + ch = str[0] + } + } else { + for ; scanset[str[0]] != 0 && i < width; str = str[1:] {} + } + } + + if i == 0 { + match_fail = true + break main_loop + } + + str = str[-1:] + + if t == 'c' && i != width { + match_fail = true + break main_loop + } + + if alloc { + (^rawptr)(dest)^ = s + } + + if t != 'c' { + if s != nil {s[i] = 0} + } + case: + base := -1 + switch t { + case 'p', 'X', 'x': + base = 16 + if i + 2 < width && str[0] == '0' && str[1] == 'x' { + str = str[2:] + } + case 'o': + base = 8 + if i + 1 < width && str[0] == '0' { + str = str[1:] + } + case 'd', 'u': + base = 10 + case 'i': + base = 0 + } + + odin_str := string(cstring(str)) + odin_str = odin_str[:min(len(odin_str), width-i)] + cnt: int + if base >= 0 { + x: i64 + if base == 0 { + x, _ = strconv.parse_i64_maybe_prefixed(odin_str, &cnt) + } else { + x, _ = strconv.parse_i64_of_base(odin_str, base, &cnt) + } + + if cnt == 0 { + match_fail = true + break main_loop + } + + if t == 'p' && dest != nil { + (^rawptr)(dest)^ = rawptr(uintptr(x)) + } else { + store_int(dest, size, u64(x)) + } + } else { + // should be a guarantee bcs of validation above. + // switch t { + // case 'a', 'A', + // 'e', 'E', + // 'f', 'F', + // 'g', 'G': + // } + x, _ := strconv.parse_f64(odin_str, &cnt) + + if cnt == 0 { + match_fail = true + break main_loop + } + + if dest != nil { + #partial switch size { + case .None: + (^c.float)(dest)^ = c.float(x) + case .l: + (^c.double)(dest)^ = c.double(x) + case .L: + (^c.double)(dest)^ = c.double(x) // longdouble + } + } + } + + pos += u64(cnt) + str = str[cnt:] + } + + if dest != nil { + matches += 1 + } + } + + if fmt_fail || alloc_fail || input_fail { + if matches == 0 { + matches = -1 + } + } + + if match_fail { + if alloc { + free(s) + // free(wcs) + } + } + + return matches +} diff --git a/vendor/libc/stdlib.odin b/vendor/libc/stdlib.odin index 54590c1c9..9f578a436 100644 --- a/vendor/libc/stdlib.odin +++ b/vendor/libc/stdlib.odin @@ -1,8 +1,10 @@ package odin_libc +import "base:intrinsics" import "base:runtime" import "core:c" +import "core:os" import "core:slice" import "core:sort" import "core:strconv" @@ -108,12 +110,81 @@ atof :: proc "c" (str: cstring) -> f64 { @(require, linkage="strong", link_name="strtol") strtol :: proc "c" (str: cstring, str_end: ^cstring, base: i32) -> c.long { context = g_ctx - sstr := string(str) sstr = strings.trim_left_space(sstr) n: int i, _ := strconv.parse_i64_of_base(sstr, int(base), &n) str_end ^= cstring(raw_data(sstr)[n:]) + if str_end != nil { + str_end ^= cstring(raw_data(sstr)[n:]) + } return c.long(clamp(i, i64(min(c.long)), i64(max(c.long)))) } + +@(require, linkage="strong", link_name="strtod") +strtod :: proc "c" (str: cstring, str_end: ^cstring) -> c.double { + context = g_ctx + + sstr := string(str) + sstr = strings.trim_left_space(sstr) + + n: int + val, _ := strconv.parse_f64(sstr, &n) + if str_end != nil { + str_end ^= cstring(raw_data(sstr)[n:]) + } + + return c.double(val) +} + +@(require, linkage="strong", link_name="abort") +abort :: proc "c" () -> ! { + intrinsics.trap() +} + +ATEXIT_MAX :: 32 + +@(private) +atexit_functions: [ATEXIT_MAX]proc "c" () +@(private) +atexit_functions_count: int + +@(require, linkage="strong", link_name="atexit") +atexit :: proc "c" (function: proc "c" ()) -> i32 { + entry := intrinsics.atomic_add(&atexit_functions_count, 1) + if entry >= ATEXIT_MAX { + return -1 + } + + atexit_functions[entry] = function + return 0 +} + + +@(require, linkage="strong", link_name="exit") +exit :: proc "c" (exit_code: c.int) -> ! { + finish_atexit() + os.exit(int(exit_code)) +} + +@(private, fini) +finish_atexit :: proc "c" () { + n := intrinsics.atomic_exchange(&atexit_functions_count, 0) + for function in atexit_functions[:n] { + function() + } +} + +ldiv_t :: struct { + quot: c.long, + rem: c.long, +} + +@(require, linkage="strong", link_name="ldiv") +ldiv :: proc "c" (number: c.long, denom: c.long) -> ldiv_t { + return { + quot = number / denom, + rem = number %% denom, + } +} diff --git a/vendor/libc/string.odin b/vendor/libc/string.odin index 1ab0803da..b8115ea88 100644 --- a/vendor/libc/string.odin +++ b/vendor/libc/string.odin @@ -5,6 +5,7 @@ import "base:intrinsics" import "core:c" import "core:strings" import "core:mem" +import "core:bytes" // NOTE: already defined by Odin. // void *memcpy(void *, const void *, size_t); @@ -109,3 +110,12 @@ strstr :: proc "c" (str: cstring, substr: cstring) -> cstring { return cstring(([^]byte)(str)[idx:]) } +@(require, linkage="strong", link_name="memchr") +memchr :: proc "c" (str: [^]byte, c: i32, n: uint) -> [^]byte { + idx := bytes.index_byte(str[:n], u8(c)) + if idx < 0 { + return nil + } + + return str[idx:] +} diff --git a/vendor/libc/time.odin b/vendor/libc/time.odin new file mode 100644 index 000000000..6d8b8f611 --- /dev/null +++ b/vendor/libc/time.odin @@ -0,0 +1,10 @@ +package odin_libc + +import "core:time" + +clock_t :: i64 + +@(require, linkage="strong", link_name="clock") +clock :: proc "c" () -> clock_t { + return time.tick_now()._nsec +}