aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-11-27 09:06:36 +0000
committergingerBill <gingerBill@users.noreply.github.com>2025-11-27 09:06:36 +0000
commit49634246c5853dceb770161bea3742b9171b7a0f (patch)
tree68aa1e102b327404d41bc008666afbb388bc25a5 /core
parent5380cf8b90132e5a1a638d9e90d0e3b6b1ed0d64 (diff)
parentf48e87d77d1376f03cf53afbc51b695698d6e5a7 (diff)
Merge branch 'master' of https://github.com/odin-lang/Odin
Diffstat (limited to 'core')
-rw-r--r--core/encoding/base64/base64.odin54
-rw-r--r--core/fmt/fmt.odin2
-rw-r--r--core/math/math.odin29
-rw-r--r--core/os/os2/file.odin61
-rw-r--r--core/os/os2/file_linux.odin65
-rw-r--r--core/os/os2/file_posix.odin13
-rw-r--r--core/os/os2/file_stream.odin65
-rw-r--r--core/os/os2/file_windows.odin32
-rw-r--r--core/os/os2/stat.odin7
-rw-r--r--core/sys/linux/bits.odin43
-rw-r--r--core/sys/linux/constants.odin5
-rw-r--r--core/sys/linux/sys.odin298
-rw-r--r--core/sys/linux/types.odin57
-rw-r--r--core/sys/windows/ws2_32.odin10
14 files changed, 604 insertions, 137 deletions
diff --git a/core/encoding/base64/base64.odin b/core/encoding/base64/base64.odin
index 2cd7227b5..032716bde 100644
--- a/core/encoding/base64/base64.odin
+++ b/core/encoding/base64/base64.odin
@@ -26,23 +26,39 @@ ENC_TABLE := [64]byte {
PADDING :: '='
-DEC_TABLE := [128]int {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62, -1, -1, -1, 63,
+DEC_TABLE := [256]u8 {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 62, 0, 0, 0, 63,
52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6,
+ 60, 61, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32,
+ 23, 24, 25, 0, 0, 0, 0, 0,
+ 0, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, -1, -1, -1, -1, -1,
+ 49, 50, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
}
encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> (encoded: string, err: mem.Allocator_Error) #optional_allocator_error {
@@ -120,10 +136,10 @@ decode_into :: proc(w: io.Writer, data: string, DEC_TBL := DEC_TABLE) -> io.Erro
i, j: int
for ; j + 3 <= length; i, j = i + 4, j + 3 {
#no_bounds_check {
- c0 = DEC_TBL[data[i]]
- c1 = DEC_TBL[data[i + 1]]
- c2 = DEC_TBL[data[i + 2]]
- c3 = DEC_TBL[data[i + 3]]
+ c0 = int(DEC_TBL[data[i]])
+ c1 = int(DEC_TBL[data[i + 1]])
+ c2 = int(DEC_TBL[data[i + 2]])
+ c3 = int(DEC_TBL[data[i + 3]])
b0 = (c0 << 2) | (c1 >> 4)
b1 = (c1 << 4) | (c2 >> 2)
@@ -140,9 +156,9 @@ decode_into :: proc(w: io.Writer, data: string, DEC_TBL := DEC_TABLE) -> io.Erro
rest := length - j
if rest > 0 {
#no_bounds_check {
- c0 = DEC_TBL[data[i]]
- c1 = DEC_TBL[data[i + 1]]
- c2 = DEC_TBL[data[i + 2]]
+ c0 = int(DEC_TBL[data[i]])
+ c1 = int(DEC_TBL[data[i + 1]])
+ c2 = int(DEC_TBL[data[i + 2]])
b0 = (c0 << 2) | (c1 >> 4)
b1 = (c1 << 4) | (c2 >> 2)
diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin
index dec4e90fa..7ec3062e1 100644
--- a/core/fmt/fmt.odin
+++ b/core/fmt/fmt.odin
@@ -1067,7 +1067,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
}
}
- buf: [256]byte
+ buf: [BUF_SIZE]byte
start := 0
if fi.hash && !is_signed {
diff --git a/core/math/math.odin b/core/math/math.odin
index 34642049c..7afb32db6 100644
--- a/core/math/math.odin
+++ b/core/math/math.odin
@@ -457,7 +457,6 @@ gain :: proc "contextless" (t, g: $T) -> T where intrinsics.type_is_float(T) {
return bias(t*2 - 1, 1 - g) * 0.5 + 0.5
}
-
@(require_results) sign_f16 :: proc "contextless" (x: f16) -> f16 { return f16(int(0 < x) - int(x < 0)) }
@(require_results) sign_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(int(0 < x) - int(x < 0)) }
@(require_results) sign_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(int(0 < x) - int(x < 0)) }
@@ -467,10 +466,24 @@ gain :: proc "contextless" (t, g: $T) -> T where intrinsics.type_is_float(T) {
@(require_results) sign_f64 :: proc "contextless" (x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)) }
@(require_results) sign_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(int(0 < x) - int(x < 0)) }
@(require_results) sign_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(int(0 < x) - int(x < 0)) }
+@(require_results) sign_int :: proc "contextless" (x: int) -> int { return int(0 < x) - int(x < 0) }
+@(require_results) sign_i16 :: proc "contextless" (x: i16) -> i16 { return i16(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i16le :: proc "contextless" (x: i16le) -> i16le { return i16le(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i16be :: proc "contextless" (x: i16be) -> i16be { return i16be(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i32 :: proc "contextless" (x: i32) -> i32 { return i32(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i32le :: proc "contextless" (x: i32le) -> i32le { return i32le(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i32be :: proc "contextless" (x: i32be) -> i32be { return i32be(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i64 :: proc "contextless" (x: i64) -> i64 { return i64(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i64le :: proc "contextless" (x: i64le) -> i64le { return i64le(int(0 < x) - int(x < 0)) }
+@(require_results) sign_i64be :: proc "contextless" (x: i64be) -> i64be { return i64be(int(0 < x) - int(x < 0)) }
sign :: proc{
sign_f16, sign_f16le, sign_f16be,
sign_f32, sign_f32le, sign_f32be,
sign_f64, sign_f64le, sign_f64be,
+ sign_int,
+ sign_i16, sign_i16le, sign_i16be,
+ sign_i32, sign_i32le, sign_i32be,
+ sign_i64, sign_i64le, sign_i64be,
}
@(require_results) sign_bit_f16 :: proc "contextless" (x: f16) -> bool { return (transmute(u16)x) & (1<<15) != 0 }
@@ -482,10 +495,24 @@ sign :: proc{
@(require_results) sign_bit_f64 :: proc "contextless" (x: f64) -> bool { return (transmute(u64)x) & (1<<63) != 0 }
@(require_results) sign_bit_f64le :: proc "contextless" (x: f64le) -> bool { return #force_inline sign_bit_f64(f64(x)) }
@(require_results) sign_bit_f64be :: proc "contextless" (x: f64be) -> bool { return #force_inline sign_bit_f64(f64(x)) }
+@(require_results) sign_bit_int :: proc "contextless" (x: int) -> bool { return uint(x) & (1<<(size_of(int)*8 - 1)) != 0 }
+@(require_results) sign_bit_i16 :: proc "contextless" (x: i16) -> bool { return u16(x) & (1<<15) != 0 }
+@(require_results) sign_bit_i16le :: proc "contextless" (x: i16le) -> bool { return #force_inline sign_bit_i16(i16(x)) }
+@(require_results) sign_bit_i16be :: proc "contextless" (x: i16be) -> bool { return #force_inline sign_bit_i16(i16(x)) }
+@(require_results) sign_bit_i32 :: proc "contextless" (x: i32) -> bool { return u32(x) & (1<<31) != 0 }
+@(require_results) sign_bit_i32le :: proc "contextless" (x: i32le) -> bool { return #force_inline sign_bit_i32(i32(x)) }
+@(require_results) sign_bit_i32be :: proc "contextless" (x: i32be) -> bool { return #force_inline sign_bit_i32(i32(x)) }
+@(require_results) sign_bit_i64 :: proc "contextless" (x: i64) -> bool { return u64(x) & (1<<63) != 0 }
+@(require_results) sign_bit_i64le :: proc "contextless" (x: i64le) -> bool { return #force_inline sign_bit_i64(i64(x)) }
+@(require_results) sign_bit_i64be :: proc "contextless" (x: i64be) -> bool { return #force_inline sign_bit_i64(i64(x)) }
sign_bit :: proc{
sign_bit_f16, sign_bit_f16le, sign_bit_f16be,
sign_bit_f32, sign_bit_f32le, sign_bit_f32be,
sign_bit_f64, sign_bit_f64le, sign_bit_f64be,
+ sign_bit_int,
+ sign_bit_i16, sign_bit_i16le, sign_bit_i16be,
+ sign_bit_i32, sign_bit_i32le, sign_bit_i32be,
+ sign_bit_i64, sign_bit_i64le, sign_bit_i64be,
}
@(require_results)
diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin
index 85ebfcece..9e7788c31 100644
--- a/core/os/os2/file.odin
+++ b/core/os/os2/file.odin
@@ -22,8 +22,7 @@ import "base:runtime"
*/
File :: struct {
impl: rawptr,
- stream: io.Stream,
- fstat: Fstat_Callback,
+ stream: File_Stream,
}
/*
@@ -218,7 +217,11 @@ name :: proc(f: ^File) -> string {
*/
close :: proc(f: ^File) -> Error {
if f != nil {
- return io.close(f.stream)
+ if f.stream.procedure == nil {
+ return .Unsupported
+ }
+ _, err := f.stream.procedure(f, .Close, nil, 0, nil, runtime.nil_allocator())
+ return err
}
return nil
}
@@ -235,7 +238,10 @@ close :: proc(f: ^File) -> Error {
*/
seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
if f != nil {
- return io.seek(f.stream, offset, whence)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ return f.stream.procedure(f, .Seek, nil, offset, whence, runtime.nil_allocator())
}
return 0, .Invalid_File
}
@@ -247,7 +253,12 @@ seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Err
*/
read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
- return io.read(f.stream, p)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Read, p, 0, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -260,7 +271,12 @@ read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
*/
read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
- return io.read_at(f.stream, p, offset)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Read_At, p, offset, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -272,7 +288,12 @@ read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
*/
write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
- return io.write(f.stream, p)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Write, p, 0, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -284,7 +305,12 @@ write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
*/
write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
- return io.write_at(f.stream, p, offset)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n64: i64
+ n64, err = f.stream.procedure(f, .Write_At, p, offset, nil, runtime.nil_allocator())
+ return int(n64), err
}
return 0, .Invalid_File
}
@@ -294,7 +320,18 @@ write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
*/
file_size :: proc(f: ^File) -> (n: i64, err: Error) {
if f != nil {
- return io.size(f.stream)
+ if f.stream.procedure == nil {
+ return 0, .Unsupported
+ }
+ n, err = f.stream.procedure(f, .Size, nil, 0, nil, runtime.nil_allocator())
+ if err == .Unsupported {
+ n = 0
+ curr := seek(f, 0, .Current) or_return
+ end := seek(f, 0, .End) or_return
+ seek(f, curr, .Start) or_return
+ n = end
+ }
+ return
}
return 0, .Invalid_File
}
@@ -304,7 +341,11 @@ file_size :: proc(f: ^File) -> (n: i64, err: Error) {
*/
flush :: proc(f: ^File) -> Error {
if f != nil {
- return io.flush(f.stream)
+ if f.stream.procedure == nil {
+ return .Unsupported
+ }
+ _, err := f.stream.procedure(f, .Flush, nil, 0, nil, runtime.nil_allocator())
+ return err
}
return nil
}
diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin
index 6d66ffd75..fb25ca411 100644
--- a/core/os/os2/file_linux.odin
+++ b/core/os/os2/file_linux.odin
@@ -29,19 +29,16 @@ _stdin := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
_stdout := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
_stderr := File{
stream = {
procedure = _file_stream_proc,
},
- fstat = _fstat,
}
@init
@@ -55,7 +52,6 @@ _standard_stream_init :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -109,7 +105,6 @@ _new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file, nil
}
@@ -476,88 +471,76 @@ _read_entire_pseudo_file_cstring :: proc(name: cstring, allocator: runtime.Alloc
}
@(private="package")
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
@(private="package")
-_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_buffered_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin
index f445cb5f4..874ec7c7d 100644
--- a/core/os/os2/file_posix.odin
+++ b/core/os/os2/file_posix.odin
@@ -36,7 +36,6 @@ init_std_files :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -110,7 +109,6 @@ __new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -371,7 +369,7 @@ _exists :: proc(path: string) -> bool {
return posix.access(cpath) == .OK
}
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
fd := f.fd
@@ -489,18 +487,19 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
return
case .Flush:
- ferr := _sync(&f.file)
- err = error_to_io_error(ferr)
+ err = _sync(&f.file)
return
case .Close, .Destroy:
- ferr := _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
case:
return 0, .Unsupported
}
diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin
index e1c29a792..af6e50921 100644
--- a/core/os/os2/file_stream.odin
+++ b/core/os/os2/file_stream.odin
@@ -1,12 +1,50 @@
package os2
+import "base:intrinsics"
+import "base:runtime"
import "core:io"
+// A subset of the io.Stream_Mode with added File specific modes
+File_Stream_Mode :: enum {
+ Close,
+ Flush,
+ Read,
+ Read_At,
+ Write,
+ Write_At,
+ Seek,
+ Size,
+ Destroy,
+ Query, // query what modes are available on `io.Stream`
+
+ Fstat, // File specific (not available on io.Stream)
+}
+#assert(intrinsics.type_is_superset_of(File_Stream_Mode, io.Stream_Mode))
+
+// Superset interface of io.Stream_Proc with the added `runtime.Allocator` parameter needed for the Fstat mode
+File_Stream_Proc :: #type proc(
+ stream_data: rawptr,
+ mode: File_Stream_Mode,
+ p: []byte,
+ offset: i64,
+ whence: io.Seek_From,
+ allocator: runtime.Allocator,
+) -> (n: i64, err: Error)
+
+File_Stream :: struct {
+ procedure: File_Stream_Proc,
+ data: rawptr,
+}
+
+
// Converts a file `f` into an `io.Stream`
to_stream :: proc(f: ^File) -> (s: io.Stream) {
if f != nil {
assert(f.stream.procedure != nil)
- s = f.stream
+ s = {
+ file_io_stream_proc,
+ f,
+ }
}
return
}
@@ -24,3 +62,28 @@ to_writer :: to_stream
even if it has no logical difference.
*/
to_reader :: to_stream
+
+
+@(private="package")
+file_io_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+ f := (^File)(stream_data)
+
+ file_stream_mode := transmute(File_Stream_Mode)mode
+
+ ferr: Error
+ n, ferr = f.stream.procedure(f, file_stream_mode, p, offset, whence, runtime.nil_allocator())
+ err = error_to_io_error(ferr)
+ return
+}
+
+@(private="package")
+file_stream_fstat_utility :: proc(f: ^File_Impl, p: []byte, allocator: runtime.Allocator) -> (err: Error) {
+ fi: File_Info
+ if len(p) >= size_of(fi) {
+ fi, err = _fstat(&f.file, allocator)
+ runtime.mem_copy_non_overlapping(raw_data(p), &fi, size_of(fi))
+ } else {
+ err = .Short_Buffer
+ }
+ return
+} \ No newline at end of file
diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin
index 03fbc596e..0d2f28642 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/os2/file_windows.odin
@@ -65,7 +65,6 @@ init_std_files :: proc "contextless" () {
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file
}
@@ -185,7 +184,6 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -
data = impl,
procedure = _file_stream_proc,
}
- impl.file.fstat = _fstat
return &impl.file, nil
}
@@ -827,44 +825,38 @@ _exists :: proc(path: string) -> bool {
}
@(private="package")
-_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+_file_stream_proc :: proc(stream_data: rawptr, mode: File_Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From, allocator: runtime.Allocator) -> (n: i64, err: Error) {
f := (^File_Impl)(stream_data)
- ferr: Error
switch mode {
case .Read:
- n, ferr = _read(f, p)
- err = error_to_io_error(ferr)
+ n, err = _read(f, p)
return
case .Read_At:
- n, ferr = _read_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _read_at(f, p, offset)
return
case .Write:
- n, ferr = _write(f, p)
- err = error_to_io_error(ferr)
+ n, err = _write(f, p)
return
case .Write_At:
- n, ferr = _write_at(f, p, offset)
- err = error_to_io_error(ferr)
+ n, err = _write_at(f, p, offset)
return
case .Seek:
- n, ferr = _seek(f, offset, whence)
- err = error_to_io_error(ferr)
+ n, err = _seek(f, offset, whence)
return
case .Size:
- n, ferr = _file_size(f)
- err = error_to_io_error(ferr)
+ n, err = _file_size(f)
return
case .Flush:
- ferr = _flush(f)
- err = error_to_io_error(ferr)
+ err = _flush(f)
return
case .Close, .Destroy:
- ferr = _close(f)
- err = error_to_io_error(ferr)
+ err = _close(f)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query})
+ case .Fstat:
+ err = file_stream_fstat_utility(f, p, allocator)
+ return
}
return 0, .Unsupported
}
diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin
index f87afc4c9..58df45754 100644
--- a/core/os/os2/stat.odin
+++ b/core/os/os2/stat.odin
@@ -46,8 +46,11 @@ file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) {
fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
if f == nil {
return {}, nil
- } else if f.fstat != nil {
- return f->fstat(allocator)
+ } else if f.stream.procedure != nil {
+ fi: File_Info
+ data := ([^]byte)(&fi)[:size_of(fi)]
+ _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator)
+ return fi, err
}
return {}, .Invalid_Callback
}
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
index 12ae949ef..213d6c26f 100644
--- a/core/sys/linux/bits.odin
+++ b/core/sys/linux/bits.odin
@@ -2226,3 +2226,46 @@ IO_Uring_Submission_Queue_Flags_Bits :: enum {
CQ_OVERFLOW,
TASKRUN,
}
+
+Mount_Flags_Bits :: enum {
+ RDONLY = log2(1),
+ NOSUID = log2(2),
+ NODEV = log2(4),
+ NOEXEC = log2(8),
+ SYNCHRONOUS = log2(16),
+ REMOUNT = log2(32),
+ MANDLOCK = log2(64),
+ DIRSYNC = log2(128),
+ NOATIME = log2(1024),
+ NODIRATIME = log2(2048),
+ BIND = log2(4096),
+ MOVE = log2(8192),
+ REC = log2(16384),
+ SILENT = log2(32768),
+ POSIXACL = log2(1<<16),
+ UNBINDABLE = log2(1<<17),
+ PRIVATE = log2(1<<18),
+ SLAVE = log2(1<<19),
+ SHARED = log2(1<<20),
+ RELATIME = log2(1<<21),
+ KERNMOUNT = log2(1<<22),
+ I_VERSION = log2(1<<23),
+ STRICTATIME = log2(1<<24),
+ LAZYTIME = log2(1<<25),
+ ACTIVE = log2(1<<30),
+ NOUSER = log2(1<<31),
+ NOSYMFOLLOW = log2(256),
+}
+
+Umount2_Flags_Bits :: enum {
+ MNT_FORCE = log2(0x00000001),
+ MNT_DETACH = log2(0x00000002),
+ MNT_EXPIRE = log2(0x00000004),
+ UMOUNT_NOFOLLOW = log2(0x00000008),
+ UMOUNT_UNUSED = log2(0x80000000),
+}
+
+Swap_Flags_Bits :: enum {
+ PREFER = log2(0x8000),
+ DISCARD = log2(0x10000),
+}
diff --git a/core/sys/linux/constants.odin b/core/sys/linux/constants.odin
index c80777025..71a16312e 100644
--- a/core/sys/linux/constants.odin
+++ b/core/sys/linux/constants.odin
@@ -54,6 +54,8 @@ PRIO_MIN :: -20
SIGRTMIN :: Signal(32)
SIGRTMAX :: Signal(64)
+_NSIG :: 65
+
S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFIFO}
S_IFSOCK :: Mode{.IFREG, .IFDIR}
S_IFLNK :: Mode{.IFREG, .IFCHR}
@@ -405,3 +407,6 @@ IORING_OFF_SQES :: 0x10000000
IORING_OFF_PBUF_RING :: 0x80000000
IORING_OFF_PBUF_SHIFT :: 16
IORING_OFF_MMAP_MASK :: 0xf8000000
+
+SWAP_FLAG_PRIO_SHIFT :: u32(0)
+SWAP_FLAG_PRIO_MASK :: u32(0x7fff)
diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin
index cfd586a66..04305ece1 100644
--- a/core/sys/linux/sys.odin
+++ b/core/sys/linux/sys.odin
@@ -2100,19 +2100,67 @@ munlockall :: proc "contextless" () -> (Errno) {
return Errno(-ret)
}
-// TODO(flysand): vhangup
+/*
+ Virtually hangup the current terminal
+ Available since Linux 1.0.
+*/
+vhangup :: proc "contextless" () -> (Errno) {
+ ret := syscall(SYS_vhangup)
+ return Errno(-ret)
+}
-// TODO(flysand): modify_ldt
+when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
+ /*
+ Get or set local descriptor table
+ Available since Linux 2.1
+ */
+ modify_ldt :: proc "contextless" (func: i32, ptr: rawptr, bytecount: uint) -> (int, Errno) {
+ ret := syscall(SYS_modify_ldt, func, ptr, bytecount)
+ return errno_unwrap(ret, int)
+ }
+}
-// TODO(flysand): pivot_root
+/*
+ Change the root mount
+ Available since Linux 2.3.41
+*/
+pivot_root :: proc "contextless" (new_root: cstring, old_root: cstring) -> (Errno) {
+ ret := syscall(SYS_pivot_root, cast(rawptr) new_root, cast(rawptr) old_root)
+ return Errno(-ret)
+}
// TODO(flysand): _sysctl
+// Deprecated and discouraged
-// TODO(flysand): prctl
+/*
+ Operations on a process or thread
+ Available since Linux 2.1.57
+*/
+prctl :: proc "contextless" (op: i32, args: ..uint) -> (Errno) {
+ assert_contextless(len(args) <= 4)
+ ret := syscall(SYS_prctl, op, args[0], args[1], args[2], args[3])
+ return Errno(-ret)
+}
-// TODO(flysand): arch_prctl
+when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
+ /*
+ Set architecture-specific thread state
+ Available since Linux 2.6.19
+ */
+ arch_prctl :: proc "contextless" (op: i32, addr: uint) -> (Errno) {
+ ret := syscall(SYS_arch_prctl, op, addr)
+ return Errno(-ret)
+ }
+}
-// TODO(flysand): adj_timex
+/*
+ Display or set the kernel time variables
+ Available since Linux 1.0.
+*/
+adjtimex :: proc "contextless" (buf: ^Timex) -> (Clock_State, Errno) {
+ ret := syscall(SYS_adjtimex)
+ return errno_unwrap(ret, Clock_State)
+}
/*
Set limits on resources.
@@ -2123,21 +2171,86 @@ setrlimit :: proc "contextless" (kind: RLimit_Kind, resource: ^RLimit) -> (Errno
return Errno(-ret)
}
-// TODO(flysand): sync
+/*
+ Change root directory
+ Available since Linux 1.0.
+*/
+chroot :: proc "contextless" (pathname: cstring) -> (Errno) {
+ ret := syscall(SYS_chroot, cast(rawptr) pathname)
+ return Errno(-ret)
+}
+
+/*
+ Commit filesystem caches to disk
+ Available since Linux 1.0.
+*/
+sync :: proc "contextless" () -> (Errno) {
+ ret := syscall(SYS_sync)
+ return Errno(-ret)
+}
-// TODO(flysand): acct
+/*
+ Switch process accounting on or off
+ Available since Linux 2.3.23
+*/
+acct :: proc "contextless" (filename: cstring) -> (Errno) {
+ ret := syscall(SYS_acct, cast(rawptr) filename)
+ return Errno(-ret)
+}
-// TODO(flysand): settimeofday
+/*
+ Set Time
+ Available since Linux 1.0
+*/
+settimeofday :: proc "contextless" (tv: ^Time_Val) -> (Errno) {
+ ret := syscall(SYS_settimeofday, tv, rawptr(nil))
+ return Errno(-ret)
+}
-// TODO(flysand): mount
+/*
+ Mount filesystem
+ Available since Linux 1.0
+*/
+mount :: proc "contextless" (source: cstring, target: cstring, filesystemtype: cstring, mountflags: Mount_Flags, data: rawptr) -> (Errno) {
+ ret := syscall(SYS_mount, cast(rawptr) source, cast(rawptr) target, cast(rawptr) filesystemtype, transmute(uint) mountflags, data)
+ return Errno(-ret)
+}
-// TODO(flysand): umount2
+/*
+ Unmount filesystem
+ Available since Linux 2.1
+*/
+umount2 :: proc "contextless" (target: cstring, flags: Umount2_Flags) -> (Errno) {
+ ret := syscall(SYS_umount2, cast(rawptr) target, transmute(u32) flags)
+ return Errno(-ret)
+}
-// TODO(flysand): swapon
+/*
+ Start swapping to file/device
+ Available since Linux 2.0
+*/
+swapon :: proc "contextless" (path: cstring, swapflags: Swap_Flags) -> (Errno) {
+ ret := syscall(SYS_swapon, cast(rawptr) path, transmute(u32) swapflags)
+ return Errno(-ret)
+}
-// TODO(flysand): swapoff
+/*
+ Stop swapping to file/device
+ Available since Linux 2.0
+*/
+swapoff :: proc "contextless" (path: cstring) -> (Errno) {
+ ret := syscall(SYS_swapoff, cast(rawptr) path)
+ return Errno(-ret)
+}
-// TODO(flysand): reboot
+/*
+ Reboot or enable/disable Ctrl-Alt-Del
+ Available since Linux 1.0
+*/
+reboot :: proc "contextless" (magic: Reboot_Magic, magic2: Reboot_Magic, op: Reboot_Operation, arg: rawptr) -> (Errno) {
+ ret := syscall(SYS_reboot, cast(i32)magic, cast(i32)magic2, cast(i32)op, arg)
+ return Errno(-ret)
+}
/*
Set hostname.
@@ -2160,16 +2273,48 @@ setdomainname :: proc "contextless" (name: string) -> (Errno) {
}
// TODO(flysand): iopl
+// deprecated
-// TODO(flysand): ioperm
+when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
+ /*
+ Set port input/output permissions
+ Available since Linux 1.0
+ */
+ ioperm :: proc "contextless" (form: u32, num: u32, turn_on: i32) -> (Errno) {
+ ret := syscall(SYS_ioperm, form, num, turn_on)
+ return Errno(-ret)
+ }
+}
-// TODO(flysand): init_module
+/*
+ Load a kernel module
+ Available since Linux 2.2
+*/
+init_module :: proc "contextless" (module_image: rawptr, size: u32, param_values: cstring) -> (Errno) {
+ ret := syscall(SYS_init_module, module_image, size, cast(rawptr) param_values)
+ return Errno(-ret)
+}
-// TODO(flysand): delete_module
+/*
+ Unload a kernel module
+ Available since Linux 2.2
+*/
+delete_module :: proc "contextless" (name: cstring, flags: u32) -> (Errno) {
+ ret := syscall(SYS_delete_module, cast(rawptr) name, flags)
+ return Errno(-ret)
+}
-// TODO(flysand): quotactl
+/*
+ Manipulate disk quotas
+ Available since Linux 2.0
+*/
+quotactl :: proc "contextless" (op: i32, special: cstring, id: i32, addr: rawptr) -> (Errno) {
+ ret := syscall(SYS_quotactl, op, cast(rawptr) special, id, addr)
+ return Errno(-ret)
+}
// TODO(flysand): nfsservctl
+/// No longer present after 3.1
// TODO(flysand): getpmsg
@@ -2193,31 +2338,122 @@ gettid :: proc "contextless" () -> Pid {
return cast(Pid) syscall(SYS_gettid)
}
-// TODO(flysand): readahead
+/*
+ Initiate a file readahead into page cache
+ Available since Linux 2.1
+*/
+readahead :: proc "contextless" (fd: Fd, offset: int, count: uint) -> (Errno) {
+ ret := syscall(SYS_readahead, fd, offset, count)
+ return Errno(-ret)
+}
-// TODO(flysand): setxattr
+/*
+ Set an extended attribute value
+ Available since Linux 2.6.25
+*/
+setxattr :: proc "contextless" (path: cstring, name: cstring, value: rawptr, size: uint, flags: i32) -> (Errno) {
+ ret := syscall(SYS_setxattr, cast(rawptr) path, cast(rawptr) name, value, size, flags)
+ return Errno(-ret)
+}
-// TODO(flysand): lsetxattr
+/*
+ Set an extended attribute value
+ Available since Linux 2.6.25
+*/
+lsetxattr :: proc "contextless" (path: cstring, name: cstring, value: rawptr, size: uint, flags: i32) -> (Errno) {
+ ret := syscall(SYS_lsetxattr, cast(rawptr) path, cast(rawptr) name, value, size, flags)
+ return Errno(-ret)
+}
-// TODO(flysand): fsetxattr
+/*
+ Set an extended attribute value
+ Available since Linux 2.6.25
+*/
+fsetxattr :: proc "contextless" (fd: Fd, name: cstring, value: rawptr, size: uint, flags: i32) -> (Errno) {
+ ret := syscall(SYS_fsetxattr, fd, cast(rawptr) name, value, size, flags)
+ return Errno(-ret)
+}
-// TODO(flysand): getxattr
+/*
+ Retrieve an extended attribute
+ Available since Linux 2.6.25
+*/
+getxattr :: proc "contextless" (path: cstring, name: cstring, value: rawptr, size: uint) -> (Errno) {
+ ret := syscall(SYS_getxattr, cast(rawptr) path, cast(rawptr) name, value, size)
+ return Errno(-ret)
+}
-// TODO(flysand): lgetxattr
+/*
+ Retrieve an extended attribute
+ Available since Linux 2.6.25
+*/
+lgetxattr :: proc "contextless" (path: cstring, name: cstring, value: rawptr, size: uint) -> (Errno) {
+ ret := syscall(SYS_lgetxattr, cast(rawptr) path, cast(rawptr) name, value, size)
+ return Errno(-ret)
+}
-// TODO(flysand): fgetxattr
+/*
+ Retrieve an extended attribute
+ Available since Linux 2.6.25
+*/
+fgetxattr :: proc "contextless" (fd: Fd, name: cstring, value: rawptr, size: uint) -> (Errno) {
+ ret := syscall(SYS_fgetxattr, fd, cast(rawptr) name, value, size)
+ return Errno(-ret)
+}
-// TODO(flysand): listxattr
+/*
+ List extended attribute names
+ Available since Linux 2.6.25
+*/
+listxattr :: proc "contextless" (path: cstring, list: cstring, size: uint) -> (Errno) {
+ ret := syscall(SYS_listxattr, cast(rawptr) path, cast(rawptr) list, size)
+ return Errno(-ret)
+}
-// TODO(flysand): llistxattr
+/*
+ List extended attribute names
+ Available since Linux 2.6.25
+*/
+llistxattr :: proc "contextless" (path: cstring, list: cstring, size: uint) -> (Errno) {
+ ret := syscall(SYS_llistxattr, cast(rawptr) path, cast(rawptr) list, size)
+ return Errno(-ret)
+}
-// TODO(flysand): flistxattr
+/*
+ List extended attribute names
+ Available since Linux 2.6.25
+*/
+flistxattr :: proc "contextless" (fd: Fd, list: cstring, size: uint) -> (Errno) {
+ ret := syscall(SYS_flistxattr, fd, cast(rawptr) list, size)
+ return Errno(-ret)
+}
-// TODO(flysand): removexattr
+/*
+ Remove an extended attribute
+ Available since Linux 2.6.25
+*/
+removexattr :: proc "contextless" (path: cstring, name: cstring) -> (Errno) {
+ ret := syscall(SYS_removexattr, cast(rawptr) path, cast(rawptr) name)
+ return Errno(-ret)
+}
-// TODO(flysand): lremovexattr
+/*
+ Remove an extended attribute
+ Available since Linux 2.6
+*/
+lremovexattr :: proc "contextless" (path: cstring, name: cstring) -> (Errno) {
+ ret := syscall(SYS_lremovexattr, cast(rawptr) path, cast(rawptr) name)
+ return Errno(-ret)
+}
-// TODO(flysand): fremovexattr
+/*
+ Remove an extended attribute
+ Available since Linux 2.6.25
+*/
+fremovexattr :: proc "contextless" (fd: Fd, name: cstring) -> (Errno) {
+ ret := syscall(SYS_fremovexattr, fd, cast(rawptr) name)
+ return Errno(-ret)
+}
/*
Get current time in seconds.
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
index a2819803c..6a2f7cbca 100644
--- a/core/sys/linux/types.odin
+++ b/core/sys/linux/types.odin
@@ -1691,3 +1691,60 @@ IO_Uring_Accept_Flags :: bit_set[IO_Uring_Accept_Flags_Bits; u16]
IO_Uring_Send_Recv_Flags :: bit_set[IO_Uring_Send_Recv_Flags_Bits; u16]
IO_Uring_Submission_Queue_Flags :: bit_set[IO_Uring_Submission_Queue_Flags_Bits; u32]
+
+Clock_State :: enum i32 {
+ TIME_OK = 0,
+ TIME_INS = 1,
+ TIME_DEL = 2,
+ TIME_OOP = 3,
+ TIME_WAIT = 4,
+ TIME_ERROR = 5,
+}
+
+Timex :: struct {
+ modes: u32,
+ offset: int,
+ freq: int,
+ maxerror: int,
+ esterror: int,
+ status: i32,
+ constant: int,
+ precision: int,
+ tolerance: int,
+ time: Time_Val,
+ tick: int,
+ ppsfreq: int,
+ jitter: int,
+ shift: i32,
+ stabil: int,
+ jitcnt: int,
+ calcnt: int,
+ errcnt: int,
+ stbcnt: int,
+ tai: i32,
+}
+
+Reboot_Magic :: enum u64 {
+ RB_MAGIC_1 = 0xfee1dead,
+ RB_MAGIC_2 = 672274793,
+ RB_MAGIC_2A = 85072278, // Since Linux 2.1.17
+ RB_MAGIC_2B = 369367448, // Since Linux 2.1.97
+ RB_MAGIC_2C = 537993216, // Since Linux 2.5.71
+}
+
+Reboot_Operation :: enum u64 {
+ RB_DISABLE_CAD = 0,
+ RB_ENABLE_CAD = 0x89abcdef,
+ RB_HALT_SYSTEM = 0xcdef0123,
+ RB_KEXEC = 0x45584543,
+ RB_POWER_OFF = 0x4321fedc,
+ RB_AUTOBOOT = 0x01234567,
+ RB_AUTOBOOT_2 = 0xa1b2c3d4,
+ RB_SW_SUSPEND = 0xd000fce2,
+}
+
+Mount_Flags :: bit_set[Mount_Flags_Bits; uint]
+
+Umount2_Flags :: bit_set[Umount2_Flags_Bits; u32]
+
+Swap_Flags :: bit_set[Swap_Flags_Bits; u32]
diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin
index 66054dd98..ed2ad5e24 100644
--- a/core/sys/windows/ws2_32.odin
+++ b/core/sys/windows/ws2_32.odin
@@ -42,11 +42,13 @@ WSAID_GETACCEPTEXSOCKADDRS :: GUID{0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00
WSAID_CONNECTX :: GUID{0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
SIO_GET_EXTENSION_FUNCTION_POINTER :: IOC_INOUT | IOC_WS2 | 6
+SIO_UDP_CONNRESET :: IOC_IN | IOC_VENDOR | 12
-IOC_OUT :: 0x40000000
-IOC_IN :: 0x80000000
-IOC_INOUT :: (IOC_IN | IOC_OUT)
-IOC_WS2 :: 0x08000000
+IOC_OUT :: 0x40000000
+IOC_IN :: 0x80000000
+IOC_INOUT :: (IOC_IN | IOC_OUT)
+IOC_WS2 :: 0x08000000
+IOC_VENDOR :: 0x18000000
SO_UPDATE_ACCEPT_CONTEXT :: 28683