mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 08:08:50 +00:00
vendor/libc: a bunch of additions
All these additions are to allow Dear ImGui to be compiled natively.
This commit is contained in:
Vendored
+412
-1
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user