소스 검색

vendor/libc: a bunch of additions

All these additions are to allow Dear ImGui to be compiled natively.
Laytan Laats 4 달 전
부모
커밋
140c902eff

+ 33 - 0
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
+}

+ 21 - 0
vendor/libc/include/alloca.h

@@ -0,0 +1,21 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
+#include <stddef.h>
+
+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

+ 12 - 0
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

+ 15 - 0
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

+ 0 - 0
vendor/libc/include/inttypes.h


+ 47 - 2
vendor/libc/include/math.h

@@ -1,21 +1,66 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
 #include <stdbool.h>
 
+#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

+ 56 - 2
vendor/libc/include/stdio.h

@@ -1,8 +1,14 @@
-#include <stddef.h>
-#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 #pragma once
 
+#include <alloca.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+
 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

+ 25 - 0
vendor/libc/include/stdlib.h

@@ -1,3 +1,9 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
 #include <stddef.h>
 
 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

+ 11 - 0
vendor/libc/include/string.h

@@ -1,9 +1,16 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
 #include <stddef.h>
 
 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

+ 16 - 0
vendor/libc/include/time.h

@@ -0,0 +1,16 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#pragma once
+
+#include <stdint.h>
+
+typedef int64_t clock_t;
+typedef clock_t time_t;
+
+clock_t clock();
+
+#ifdef __cplusplus
+}
+#endif

+ 115 - 9
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="__isnand")
+isnand :: proc "c" (v: f64) -> bool {
 	return math.is_nan(v)
 }
 
-@(require, linkage="strong", link_name="isinf")
-isinf :: proc "c" (v: f32) -> bool {
+@(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
+}

+ 412 - 1
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
+}

+ 72 - 1
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,
+	}
+}

+ 10 - 0
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:]
+}

+ 10 - 0
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
+}