Merge pull request #4934 from laytan/vendor-libc-additions

vendor/libc: a bunch of additions
This commit is contained in:
gingerBill
2025-03-13 09:23:20 +00:00
committed by GitHub
15 changed files with 855 additions and 15 deletions

33
vendor/libc/ctype.odin vendored Normal file
View File

@@ -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
vendor/libc/include/alloca.h vendored Normal file
View File

@@ -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

View File

@@ -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
vendor/libc/include/ctype.h vendored Normal file
View File

@@ -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
vendor/libc/include/inttypes.h vendored Normal file
View File

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
vendor/libc/include/time.h vendored Normal file
View File

@@ -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

124
vendor/libc/math.odin vendored
View File

@@ -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
}

413
vendor/libc/stdio.odin vendored
View File

@@ -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
}

View File

@@ -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,
}
}

View File

@@ -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
vendor/libc/time.odin vendored Normal file
View File

@@ -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
}