mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-10 04:18:11 +00:00
posix: add package
This commit is contained in:
@@ -47,8 +47,8 @@ foreign libc {
|
||||
clogf :: proc(z: complex_float) -> complex_float ---
|
||||
|
||||
// 7.3.8 Power and absolute-value functions
|
||||
cabs :: proc(z: complex_double) -> complex_double ---
|
||||
cabsf :: proc(z: complex_float) -> complex_float ---
|
||||
cabs :: proc(z: complex_double) -> double ---
|
||||
cabsf :: proc(z: complex_float) -> float ---
|
||||
cpow :: proc(x, y: complex_double) -> complex_double ---
|
||||
cpowf :: proc(x, y: complex_float) -> complex_float ---
|
||||
csqrt :: proc(z: complex_double) -> complex_double ---
|
||||
|
||||
@@ -102,6 +102,6 @@ when ODIN_OS == .Haiku {
|
||||
// read the value, or to produce an lvalue such that you can assign a different
|
||||
// error value to errno. To work around this, just expose it as a function like
|
||||
// it actually is.
|
||||
errno :: #force_inline proc() -> ^int {
|
||||
errno :: #force_inline proc "contextless" () -> ^int {
|
||||
return _get_errno()
|
||||
}
|
||||
|
||||
@@ -32,24 +32,21 @@ when ODIN_OS == .Windows {
|
||||
// the RDX register will contain zero and correctly set the flag to disable
|
||||
// stack unwinding.
|
||||
@(link_name="_setjmp")
|
||||
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---
|
||||
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---
|
||||
}
|
||||
} else {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.13.1 Save calling environment
|
||||
//
|
||||
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
|
||||
// necessarily export a symbol named setjmp but rather _setjmp in the case
|
||||
// of musl, glibc, BSD libc, and msvcrt.
|
||||
@(link_name="_setjmp")
|
||||
setjmp :: proc(env: ^jmp_buf) -> int ---
|
||||
@(link_name=LSETJMP)
|
||||
setjmp :: proc(env: ^jmp_buf) -> int ---
|
||||
}
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.13.2 Restore calling environment
|
||||
@(link_name=LLONGJMP)
|
||||
longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---
|
||||
}
|
||||
|
||||
@@ -64,3 +61,11 @@ foreign libc {
|
||||
// The choice of 4096 bytes for storage of this type is more than enough on all
|
||||
// relevant platforms.
|
||||
jmp_buf :: struct #align(16) { _: [4096]char, }
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSETJMP :: "__setjmp14"
|
||||
@(private) LLONGJMP :: "__longjmp14"
|
||||
} else {
|
||||
@(private) LSETJMP :: "setjmp"
|
||||
@(private) LLONGJMP :: "longjmp"
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ when ODIN_OS == .Windows {
|
||||
|
||||
FILE :: struct {}
|
||||
|
||||
Whence :: enum int {
|
||||
SET = SEEK_SET,
|
||||
CUR = SEEK_CUR,
|
||||
END = SEEK_END,
|
||||
}
|
||||
|
||||
// MSVCRT compatible.
|
||||
when ODIN_OS == .Windows {
|
||||
_IOFBF :: 0x0000
|
||||
@@ -101,6 +107,8 @@ when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
TMP_MAX :: 308915776
|
||||
|
||||
foreign libc {
|
||||
__sF: [3]FILE
|
||||
}
|
||||
@@ -128,6 +136,8 @@ when ODIN_OS == .FreeBSD {
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
TMP_MAX :: 308915776
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__stderrp") stderr: ^FILE
|
||||
@(link_name="__stdinp") stdin: ^FILE
|
||||
@@ -195,10 +205,21 @@ when ODIN_OS == .Haiku {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LRENAME :: "__posix_rename"
|
||||
@(private) LFGETPOS :: "__fgetpos50"
|
||||
@(private) LFSETPOS :: "__fsetpos50"
|
||||
} else {
|
||||
@(private) LRENAME :: "rename"
|
||||
@(private) LFGETPOS :: "fgetpos"
|
||||
@(private) LFSETPOS :: "fsetpos"
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.21.4 Operations on files
|
||||
remove :: proc(filename: cstring) -> int ---
|
||||
@(link_name=LRENAME)
|
||||
rename :: proc(old, new: cstring) -> int ---
|
||||
tmpfile :: proc() -> ^FILE ---
|
||||
tmpnam :: proc(s: [^]char) -> [^]char ---
|
||||
@@ -240,8 +261,10 @@ foreign libc {
|
||||
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
|
||||
// 7.21.9 File positioning functions
|
||||
@(link_name=LFGETPOS)
|
||||
fgetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
|
||||
fseek :: proc(stream: ^FILE, offset: long, whence: int) -> int ---
|
||||
fseek :: proc(stream: ^FILE, offset: long, whence: Whence) -> int ---
|
||||
@(link_name=LFSETPOS)
|
||||
fsetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
|
||||
ftell :: proc(stream: ^FILE) -> long ---
|
||||
rewind :: proc(stream: ^FILE) ---
|
||||
@@ -288,11 +311,11 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
if fseek(file, long(offset), SEEK_SET) != 0 {
|
||||
if fseek(file, long(offset), .SET) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
defer fseek(file, long(curr), SEEK_SET)
|
||||
defer fseek(file, long(curr), .SET)
|
||||
|
||||
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
@@ -307,17 +330,21 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
if fseek(file, long(offset), SEEK_SET) != 0 {
|
||||
if fseek(file, long(offset), .SET) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
defer fseek(file, long(curr), SEEK_SET)
|
||||
defer fseek(file, long(curr), .SET)
|
||||
|
||||
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
|
||||
if n == 0 { err = unknown_or_eof(file) }
|
||||
|
||||
case .Seek:
|
||||
if fseek(file, long(offset), int(whence)) != 0 {
|
||||
#assert(int(Whence.SET) == int(io.Seek_From.Start))
|
||||
#assert(int(Whence.CUR) == int(io.Seek_From.Current))
|
||||
#assert(int(Whence.END) == int(io.Seek_From.End))
|
||||
|
||||
if fseek(file, long(offset), Whence(whence)) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
@@ -326,9 +353,9 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
|
||||
if curr == -1 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
defer fseek(file, curr, SEEK_SET)
|
||||
defer fseek(file, curr, .SET)
|
||||
|
||||
if fseek(file, 0, SEEK_END) != 0 {
|
||||
if fseek(file, 0, .END) != 0 {
|
||||
return 0, unknown_or_eof(file)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,9 @@ when ODIN_OS == .Linux {
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
// GLIBC and MUSL only
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@@ -55,6 +54,20 @@ when ODIN_OS == .Darwin {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
RAND_MAX :: 0x7fffffff
|
||||
|
||||
@(private="file")
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
__mb_cur_max: size_t
|
||||
}
|
||||
|
||||
MB_CUR_MAX :: #force_inline proc() -> size_t {
|
||||
return __mb_cur_max
|
||||
}
|
||||
}
|
||||
|
||||
// C does not declare what these values should be, as an implementation is free
|
||||
// to use any two distinct values it wants to indicate success or failure.
|
||||
// However, nobody actually does and everyone appears to have agreed upon these
|
||||
@@ -99,7 +112,7 @@ foreign libc {
|
||||
at_quick_exit :: proc(func: proc "c" ()) -> int ---
|
||||
exit :: proc(status: int) -> ! ---
|
||||
_Exit :: proc(status: int) -> ! ---
|
||||
getenv :: proc(name: cstring) -> [^]char ---
|
||||
getenv :: proc(name: cstring) -> cstring ---
|
||||
quick_exit :: proc(status: int) -> ! ---
|
||||
system :: proc(cmd: cstring) -> int ---
|
||||
|
||||
@@ -150,4 +163,4 @@ aligned_free :: #force_inline proc "c" (ptr: rawptr) {
|
||||
} else {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ foreign libc {
|
||||
strtok :: proc(s1: [^]char, s2: cstring) -> [^]char ---
|
||||
|
||||
// 7.24.6 Miscellaneous functions
|
||||
strerror :: proc(errnum: int) -> [^]char ---
|
||||
strerror :: proc(errnum: int) -> cstring ---
|
||||
strlen :: proc(s: cstring) -> size_t ---
|
||||
}
|
||||
memset :: proc "c" (s: rawptr, c: int, n: size_t) -> rawptr {
|
||||
|
||||
@@ -50,30 +50,56 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS =
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
clock :: proc() -> clock_t ---
|
||||
@(link_name=LDIFFTIME)
|
||||
difftime :: proc(time1, time2: time_t) -> double ---
|
||||
@(link_name=LMKTIME)
|
||||
mktime :: proc(timeptr: ^tm) -> time_t ---
|
||||
@(link_name=LTIME)
|
||||
time :: proc(timer: ^time_t) -> time_t ---
|
||||
timespec_get :: proc(ts: ^timespec, base: int) -> int ---
|
||||
|
||||
// 7.27.3 Time conversion functions
|
||||
asctime :: proc(timeptr: ^tm) -> [^]char ---
|
||||
@(link_name=LCTIME)
|
||||
ctime :: proc(timer: ^time_t) -> [^]char ---
|
||||
@(link_name=LGMTIME)
|
||||
gmtime :: proc(timer: ^time_t) -> ^tm ---
|
||||
@(link_name=LLOCALTIME)
|
||||
localtime :: proc(timer: ^time_t) -> ^tm ---
|
||||
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LDIFFTIME :: "__difftime50"
|
||||
@(private) LMKTIME :: "__mktime50"
|
||||
@(private) LTIME :: "__time50"
|
||||
@(private) LCTIME :: "__ctime50"
|
||||
@(private) LGMTIME :: "__gmtime50"
|
||||
@(private) LLOCALTIME :: "__localtime50"
|
||||
} else {
|
||||
@(private) LDIFFTIME :: "difftime"
|
||||
@(private) LMKTIME :: "mktime"
|
||||
@(private) LTIME :: "ltime"
|
||||
@(private) LCTIME :: "ctime"
|
||||
@(private) LGMTIME :: "gmtime"
|
||||
@(private) LLOCALTIME :: "localtime"
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
CLOCKS_PER_SEC :: 100
|
||||
} else {
|
||||
CLOCKS_PER_SEC :: 1000000
|
||||
}
|
||||
|
||||
TIME_UTC :: 1
|
||||
TIME_UTC :: 1
|
||||
|
||||
time_t :: distinct i64
|
||||
time_t :: distinct i64
|
||||
|
||||
clock_t :: long
|
||||
when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
|
||||
clock_t :: distinct int32_t
|
||||
} else {
|
||||
clock_t :: distinct long
|
||||
}
|
||||
|
||||
timespec :: struct {
|
||||
tv_sec: time_t,
|
||||
|
||||
@@ -2,141 +2,45 @@
|
||||
//+private
|
||||
package mem_virtual
|
||||
|
||||
foreign import libc "system:System.framework"
|
||||
import "core:c"
|
||||
import "core:sys/posix"
|
||||
|
||||
PROT_NONE :: 0x0 /* [MC2] no permissions */
|
||||
PROT_READ :: 0x1 /* [MC2] pages can be read */
|
||||
PROT_WRITE :: 0x2 /* [MC2] pages can be written */
|
||||
PROT_EXEC :: 0x4 /* [MC2] pages can be executed */
|
||||
|
||||
// Sharing options
|
||||
MAP_SHARED :: 0x1 /* [MF|SHM] share changes */
|
||||
MAP_PRIVATE :: 0x2 /* [MF|SHM] changes are private */
|
||||
|
||||
// Other flags
|
||||
MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */
|
||||
MAP_RENAME :: 0x0020 /* Sun: rename private pages to file */
|
||||
MAP_NORESERVE :: 0x0040 /* Sun: don't reserve needed swap area */
|
||||
MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */
|
||||
MAP_NOEXTEND :: 0x0100 /* for MAP_FILE, don't change file size */
|
||||
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
|
||||
MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */
|
||||
MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */
|
||||
|
||||
// Mapping type
|
||||
MAP_FILE :: 0x0000 /* map from file (default) */
|
||||
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
|
||||
|
||||
|
||||
/*
|
||||
* The MAP_RESILIENT_* flags can be used when the caller wants to map some
|
||||
* possibly unreliable memory and be able to access it safely, possibly
|
||||
* getting the wrong contents rather than raising any exception.
|
||||
* For safety reasons, such mappings have to be read-only (PROT_READ access
|
||||
* only).
|
||||
*
|
||||
* MAP_RESILIENT_CODESIGN:
|
||||
* accessing this mapping will not generate code-signing violations,
|
||||
* even if the contents are tainted.
|
||||
* MAP_RESILIENT_MEDIA:
|
||||
* accessing this mapping will not generate an exception if the contents
|
||||
* are not available (unreachable removable or remote media, access beyond
|
||||
* end-of-file, ...). Missing contents will be replaced with zeroes.
|
||||
*/
|
||||
MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */
|
||||
MAP_RESILIENT_MEDIA :: 0x4000 /* no backing-store failures */
|
||||
|
||||
MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */
|
||||
|
||||
// Flags used to support translated processes.
|
||||
MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */
|
||||
MAP_UNIX03 :: 0x40000 /* UNIX03 compliance */
|
||||
|
||||
// Process memory locking
|
||||
MCL_CURRENT :: 0x0001 /* [ML] Lock only current memory */
|
||||
MCL_FUTURE :: 0x0002 /* [ML] Lock all future memory as well */
|
||||
|
||||
MADV_NORMAL :: 0 /* [MC1] no further special treatment */
|
||||
MADV_RANDOM :: 1 /* [MC1] expect random page refs */
|
||||
MADV_SEQUENTIAL :: 2 /* [MC1] expect sequential page refs */
|
||||
MADV_WILLNEED :: 3 /* [MC1] will need these pages */
|
||||
MADV_DONTNEED :: 4 /* [MC1] dont need these pages */
|
||||
MADV_FREE :: 5 /* pages unneeded, discard contents */
|
||||
MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */
|
||||
MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */
|
||||
MADV_FREE_REUSE :: 8 /* caller wants to reuse those pages */
|
||||
MADV_CAN_REUSE :: 9
|
||||
MADV_PAGEOUT :: 10 /* page out now (internal only) */
|
||||
|
||||
// msync() flags
|
||||
MS_ASYNC :: 0x0001 /* [MF|SIO] return immediately */
|
||||
MS_INVALIDATE :: 0x0002 /* [MF|SIO] invalidate all cached data */
|
||||
MS_SYNC :: 0x0010 /* [MF|SIO] msync synchronously */
|
||||
MS_KILLPAGES :: 0x0004 /* invalidate pages, leave mapped */
|
||||
MS_DEACTIVATE :: 0x0008 /* deactivate pages, leave mapped */
|
||||
|
||||
// Return bits from mincore
|
||||
MINCORE_INCORE :: 0x1 /* Page is incore */
|
||||
MINCORE_REFERENCED :: 0x2 /* Page has been referenced by us */
|
||||
MINCORE_MODIFIED :: 0x4 /* Page has been modified by us */
|
||||
MINCORE_REFERENCED_OTHER :: 0x8 /* Page has been referenced */
|
||||
MINCORE_MODIFIED_OTHER :: 0x10 /* Page has been modified */
|
||||
MINCORE_PAGED_OUT :: 0x20 /* Page has been paged out */
|
||||
MINCORE_COPIED :: 0x40 /* Page has been copied */
|
||||
MINCORE_ANONYMOUS :: 0x80 /* Page belongs to an anonymous object */
|
||||
|
||||
// Allocation failure result
|
||||
MAP_FAILED : rawptr = rawptr(~uintptr(0))
|
||||
|
||||
foreign libc {
|
||||
@(link_name="mlockall") _mlockall :: proc(flags: c.int) -> c.int ---
|
||||
@(link_name="munlockall") _munlockall :: proc() -> c.int ---
|
||||
@(link_name="mlock") _mlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="mmap") _mmap :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr ---
|
||||
@(link_name="mprotect") _mprotect :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int ---
|
||||
@(link_name="msync") _msync :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="munlock") _munlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="munmap") _munmap :: proc(addr: rawptr, len: c.size_t) -> c.int ---
|
||||
@(link_name="shm_open") _shm_open :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int ---
|
||||
@(link_name="shm_unlink") _shm_unlink :: proc(name: cstring) -> c.int ---
|
||||
@(link_name="posix_madvise") _posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
|
||||
@(link_name="madvise") _madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
|
||||
@(link_name="mincore") _mincore :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int ---
|
||||
@(link_name="minherit") _minherit :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int ---
|
||||
}
|
||||
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
|
||||
|
||||
MADV_FREE :: 5 /* pages unneeded, discard contents */
|
||||
|
||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
|
||||
if result == MAP_FAILED {
|
||||
flags := posix.Map_Flags{ .PRIVATE } + transmute(posix.Map_Flags)i32(MAP_ANONYMOUS)
|
||||
result := posix.mmap(nil, size, {}, flags)
|
||||
if result == posix.MAP_FAILED {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
|
||||
return ([^]byte)(uintptr(result))[:size], nil
|
||||
}
|
||||
|
||||
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := _mprotect(data, size, PROT_READ|PROT_WRITE)
|
||||
if result != 0 {
|
||||
if posix.mprotect(data, size, { .READ, .WRITE }) != .OK {
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_decommit :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_mprotect(data, size, PROT_NONE)
|
||||
_madvise(data, size, MADV_FREE)
|
||||
posix.mprotect(data, size, {})
|
||||
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
|
||||
}
|
||||
|
||||
_release :: proc "contextless" (data: rawptr, size: uint) {
|
||||
_munmap(data, size)
|
||||
posix.munmap(data, size)
|
||||
}
|
||||
|
||||
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
|
||||
pflags: c.int
|
||||
pflags = PROT_NONE
|
||||
if .Read in flags { pflags |= PROT_READ }
|
||||
if .Write in flags { pflags |= PROT_WRITE }
|
||||
if .Execute in flags { pflags |= PROT_EXEC }
|
||||
err := _mprotect(data, size, pflags)
|
||||
return err == 0
|
||||
#assert(i32(posix.Prot_Flag_Bits.READ) == i32(Protect_Flag.Read))
|
||||
#assert(i32(posix.Prot_Flag_Bits.WRITE) == i32(Protect_Flag.Write))
|
||||
#assert(i32(posix.Prot_Flag_Bits.EXEC) == i32(Protect_Flag.Execute))
|
||||
|
||||
return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK
|
||||
}
|
||||
|
||||
|
||||
@@ -149,16 +53,11 @@ _platform_memory_init :: proc() {
|
||||
|
||||
|
||||
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
|
||||
prot, mflags: c.int
|
||||
if .Read in flags {
|
||||
prot |= PROT_READ
|
||||
}
|
||||
if .Write in flags {
|
||||
prot |= PROT_WRITE
|
||||
}
|
||||
mflags |= MAP_SHARED
|
||||
addr := _mmap(nil, c.size_t(size), prot, mflags, i32(fd), 0)
|
||||
if addr == nil {
|
||||
#assert(i32(posix.Prot_Flag_Bits.READ) == i32(Map_File_Flag.Read))
|
||||
#assert(i32(posix.Prot_Flag_Bits.WRITE) == i32(Map_File_Flag.Write))
|
||||
|
||||
addr := posix.mmap(nil, uint(size), transmute(posix.Prot_Flags)flags, { .SHARED }, posix.FD(fd))
|
||||
if addr == posix.MAP_FAILED || addr == nil {
|
||||
return nil, .Map_Failure
|
||||
}
|
||||
return ([^]byte)(addr)[:size], nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//+build darwin, linux, netbsd, freebsd, openbsd
|
||||
package os
|
||||
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
|
||||
@(require_results)
|
||||
|
||||
@@ -584,7 +584,7 @@ F_GETPATH :: 50 // return the full path of the fd
|
||||
foreign libc {
|
||||
@(link_name="__error") __error :: proc() -> ^c.int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: i32, #c_vararg args: ..any) -> Handle ---
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(handle: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int ---
|
||||
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int ---
|
||||
@@ -628,23 +628,23 @@ foreign libc {
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
|
||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||
|
||||
@(link_name="socket") _unix_socket :: proc(domain: int, type: int, protocol: int) -> int ---
|
||||
@(link_name="listen") _unix_listen :: proc(socket: int, backlog: int) -> int ---
|
||||
@(link_name="accept") _unix_accept :: proc(socket: int, addr: rawptr, addr_len: rawptr) -> int ---
|
||||
@(link_name="connect") _unix_connect :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
|
||||
@(link_name="bind") _unix_bind :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int ---
|
||||
@(link_name="setsockopt") _unix_setsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
|
||||
@(link_name="getsockopt") _unix_getsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int ---
|
||||
@(link_name="recvfrom") _unix_recvfrom :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t ---
|
||||
@(link_name="recv") _unix_recv :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
|
||||
@(link_name="sendto") _unix_sendto :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t ---
|
||||
@(link_name="send") _unix_send :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
|
||||
@(link_name="shutdown") _unix_shutdown :: proc(socket: int, how: int) -> int ---
|
||||
@(link_name="socket") _unix_socket :: proc(domain: c.int, type: c.int, protocol: c.int) -> c.int ---
|
||||
@(link_name="listen") _unix_listen :: proc(socket: c.int, backlog: c.int) -> c.int ---
|
||||
@(link_name="accept") _unix_accept :: proc(socket: c.int, addr: rawptr, addr_len: rawptr) -> c.int ---
|
||||
@(link_name="connect") _unix_connect :: proc(socket: c.int, addr: rawptr, addr_len: socklen_t) -> c.int ---
|
||||
@(link_name="bind") _unix_bind :: proc(socket: c.int, addr: rawptr, addr_len: socklen_t) -> c.int ---
|
||||
@(link_name="setsockopt") _unix_setsockopt :: proc(socket: c.int, level: c.int, opt_name: c.int, opt_val: rawptr, opt_len: socklen_t) -> c.int ---
|
||||
@(link_name="getsockopt") _unix_getsockopt :: proc(socket: c.int, level: c.int, opt_name: c.int, opt_val: rawptr, opt_len: ^socklen_t) -> c.int ---
|
||||
@(link_name="recvfrom") _unix_recvfrom :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t ---
|
||||
@(link_name="recv") _unix_recv :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int) -> c.ssize_t ---
|
||||
@(link_name="sendto") _unix_sendto :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t ---
|
||||
@(link_name="send") _unix_send :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int) -> c.ssize_t ---
|
||||
@(link_name="shutdown") _unix_shutdown :: proc(socket: c.int, how: c.int) -> c.int ---
|
||||
|
||||
@(link_name="getifaddrs") _getifaddrs :: proc(ifap: ^^ifaddrs) -> (c.int) ---
|
||||
@(link_name="freeifaddrs") _freeifaddrs :: proc(ifa: ^ifaddrs) ---
|
||||
@@ -661,9 +661,9 @@ when ODIN_ARCH != .arm64 {
|
||||
}
|
||||
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||
}
|
||||
|
||||
@@ -1040,10 +1040,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) {
|
||||
if path_ptr == nil {
|
||||
return "", get_last_error()
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
path_cstr := cast(cstring)path_ptr
|
||||
path = strings.clone(string(path_cstr))
|
||||
path = strings.clone(string(path_ptr))
|
||||
|
||||
return path, nil
|
||||
}
|
||||
@@ -1154,7 +1153,7 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
dlopen :: proc(filename: string, flags: int) -> rawptr {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(filename, context.temp_allocator)
|
||||
handle := _unix_dlopen(cstr, flags)
|
||||
handle := _unix_dlopen(cstr, c.int(flags))
|
||||
return handle
|
||||
}
|
||||
@(require_results)
|
||||
@@ -1208,26 +1207,24 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
return res
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) {
|
||||
result := _unix_socket(domain, type, protocol)
|
||||
result := _unix_socket(c.int(domain), c.int(type), c.int(protocol))
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
return Socket(result), nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error {
|
||||
result := _unix_connect(int(sd), addr, len)
|
||||
result := _unix_connect(c.int(sd), addr, len)
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error {
|
||||
result := _unix_bind(int(sd), addr, len)
|
||||
bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) {
|
||||
result := _unix_bind(c.int(sd), addr, len)
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
@@ -1235,15 +1232,15 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error {
|
||||
}
|
||||
|
||||
accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) {
|
||||
result := _unix_accept(int(sd), rawptr(addr), len)
|
||||
result := _unix_accept(c.int(sd), rawptr(addr), len)
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
return Socket(result), nil
|
||||
}
|
||||
|
||||
listen :: proc(sd: Socket, backlog: int) -> Error {
|
||||
result := _unix_listen(int(sd), backlog)
|
||||
listen :: proc(sd: Socket, backlog: int) -> (Error) {
|
||||
result := _unix_listen(c.int(sd), c.int(backlog))
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
@@ -1251,7 +1248,7 @@ listen :: proc(sd: Socket, backlog: int) -> Error {
|
||||
}
|
||||
|
||||
setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error {
|
||||
result := _unix_setsockopt(int(sd), level, optname, optval, optlen)
|
||||
result := _unix_setsockopt(c.int(sd), c.int(level), c.int(optname), optval, optlen)
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
@@ -1259,7 +1256,8 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen:
|
||||
}
|
||||
|
||||
getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error {
|
||||
result := _unix_getsockopt(int(sd), level, optname, optval, optlen)
|
||||
optlen := optlen
|
||||
result := _unix_getsockopt(c.int(sd), c.int(level), c.int(optname), optval, &optlen)
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
@@ -1267,7 +1265,7 @@ getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen:
|
||||
}
|
||||
|
||||
recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Error) {
|
||||
result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size)
|
||||
result := _unix_recvfrom(c.int(sd), raw_data(data), len(data), c.int(flags), addr, addr_size)
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
@@ -1275,7 +1273,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz
|
||||
}
|
||||
|
||||
recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) {
|
||||
result := _unix_recv(int(sd), raw_data(data), len(data), flags)
|
||||
result := _unix_recv(c.int(sd), raw_data(data), len(data), c.int(flags))
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
@@ -1283,7 +1281,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) {
|
||||
}
|
||||
|
||||
sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Error) {
|
||||
result := _unix_sendto(int(sd), raw_data(data), len(data), flags, addr, addrlen)
|
||||
result := _unix_sendto(c.int(sd), raw_data(data), len(data), c.int(flags), addr, addrlen)
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
@@ -1291,15 +1289,15 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc
|
||||
}
|
||||
|
||||
send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) {
|
||||
result := _unix_send(int(sd), raw_data(data), len(data), 0)
|
||||
result := _unix_send(c.int(sd), raw_data(data), len(data), 0)
|
||||
if result < 0 {
|
||||
return 0, get_last_error()
|
||||
}
|
||||
return u32(result), nil
|
||||
}
|
||||
|
||||
shutdown :: proc(sd: Socket, how: int) -> Error {
|
||||
result := _unix_shutdown(int(sd), how)
|
||||
shutdown :: proc(sd: Socket, how: int) -> (Error) {
|
||||
result := _unix_shutdown(c.int(sd), c.int(how))
|
||||
if result < 0 {
|
||||
return get_last_error()
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ F_KINFO :: 22
|
||||
foreign libc {
|
||||
@(link_name="__error") __Error_location :: proc() -> ^c.int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.uint16_t) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@@ -402,7 +402,7 @@ foreign libc {
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
@@ -430,7 +430,7 @@ get_last_error :: proc "contextless" () -> Error {
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
handle := _unix_open(cstr, c.int(flags), u16(mode))
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, get_last_error()
|
||||
}
|
||||
@@ -786,10 +786,10 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) {
|
||||
if path_ptr == nil {
|
||||
return "", get_last_error()
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
|
||||
path = strings.clone(string(cstring(path_ptr)))
|
||||
path = strings.clone(string(path_ptr))
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ foreign libc {
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int ---
|
||||
@(link_name="setenv") _unix_setenv :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
@@ -917,9 +917,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) {
|
||||
if path_ptr == nil {
|
||||
return "", get_last_error()
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
path = strings.clone(string(cstring(path_ptr)))
|
||||
path = strings.clone(string(path_ptr))
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ dev_t :: u64
|
||||
ino_t :: u64
|
||||
nlink_t :: u32
|
||||
off_t :: i64
|
||||
mode_t :: u16
|
||||
mode_t :: u32
|
||||
pid_t :: u32
|
||||
uid_t :: u32
|
||||
gid_t :: u32
|
||||
@@ -454,7 +454,7 @@ foreign libc {
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
@@ -832,9 +832,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) {
|
||||
if path_ptr == nil {
|
||||
return "", get_last_error()
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
path = strings.clone(string(cstring(path_ptr)))
|
||||
path = strings.clone(string(path_ptr))
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ foreign libc {
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
|
||||
@@ -746,9 +746,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) {
|
||||
if path_ptr == nil {
|
||||
return "", get_last_error()
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
path = strings.clone(string(cstring(path_ptr)))
|
||||
path = strings.clone(string(path_ptr))
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
@@ -32,10 +32,9 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
if path_ptr == nil {
|
||||
return "", __error()^ == 0
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
defer _unix_free(rawptr(path_ptr))
|
||||
|
||||
path_cstr := cstring(path_ptr)
|
||||
path_str := strings.clone(string(path_cstr), allocator)
|
||||
path_str := strings.clone(string(path_ptr), allocator)
|
||||
return path_str, true
|
||||
}
|
||||
|
||||
@@ -52,7 +51,7 @@ join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
|
||||
@(private)
|
||||
foreign libc {
|
||||
realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
|
||||
}
|
||||
|
||||
@@ -5,22 +5,7 @@ package spall
|
||||
// Only for types.
|
||||
import "core:os"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
timespec :: struct {
|
||||
tv_sec: i64, // seconds
|
||||
tv_nsec: i64, // nanoseconds
|
||||
}
|
||||
|
||||
foreign libc {
|
||||
__error :: proc() -> ^i32 ---
|
||||
@(link_name="write") _unix_write :: proc(handle: os.Handle, buffer: rawptr, count: uint) -> int ---
|
||||
@(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> i32 ---
|
||||
}
|
||||
import "core:sys/posix"
|
||||
|
||||
MAX_RW :: 0x7fffffff
|
||||
|
||||
@@ -32,7 +17,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E
|
||||
|
||||
for n < len(data) {
|
||||
chunk := data[:min(len(data), MAX_RW)]
|
||||
written := _unix_write(fd, raw_data(chunk), len(chunk))
|
||||
written := posix.write(posix.FD(fd), raw_data(chunk), len(chunk))
|
||||
if written < 0 {
|
||||
return n, os.get_last_error()
|
||||
}
|
||||
@@ -42,11 +27,17 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E
|
||||
return n, nil
|
||||
}
|
||||
|
||||
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
|
||||
// NOTE(tetra): "RAW" means: Not adjusted by NTP.
|
||||
when ODIN_OS == .Darwin {
|
||||
CLOCK :: posix.Clock(4) // CLOCK_MONOTONIC_RAW
|
||||
} else {
|
||||
// It looks like the BSDs don't have a CLOCK_MONOTONIC_RAW equivalent.
|
||||
CLOCK :: posix.Clock.MONOTONIC
|
||||
}
|
||||
|
||||
@(no_instrumentation)
|
||||
_tick_now :: proc "contextless" () -> (ns: i64) {
|
||||
t: timespec
|
||||
_unix_clock_gettime(CLOCK_MONOTONIC_RAW, &t)
|
||||
return t.tv_sec*1e9 + t.tv_nsec
|
||||
t: posix.timespec
|
||||
posix.clock_gettime(CLOCK, &t)
|
||||
return i64(t.tv_sec)*1e9 + i64(t.tv_nsec)
|
||||
}
|
||||
|
||||
57
core/sys/posix/README.md
Normal file
57
core/sys/posix/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# POSIX
|
||||
|
||||
defines bindings for most posix APIs.
|
||||
|
||||
If a header is added, all of it must be implemented.
|
||||
|
||||
Each platform must define the exact same symbols, different values are allowed, even structs with different non-standard fields.
|
||||
|
||||
APIs part of extensions may be left out completely if one target doesn't implement it.
|
||||
|
||||
APIs with a direct replacement in `core` might not be implemented.
|
||||
|
||||
Macros are emulated with force inlined functions.
|
||||
|
||||
Struct fields defined by the posix standard (and thus portable) are documented with `[PSX]`.
|
||||
|
||||
|
||||
ADD A TEST FOR SIGINFO, one thread signalling and retrieving the signal out of siginfo or something.
|
||||
ADD A TEST FOR wait.h
|
||||
ADD A TEST FOR pthread.
|
||||
ADDD A test for stat.h.
|
||||
ADD A TEST FOR setjmp.h.
|
||||
HAIKU.
|
||||
|
||||
Unimplemented POSIX headers:
|
||||
|
||||
- aio.h
|
||||
- complex.h | See `core:c/libc` and our own complex types
|
||||
- cpio.h
|
||||
- ctype.h | See `core:c/libc` for most of it
|
||||
- ndbm.h | Never seen or heard of it
|
||||
- fenv.h
|
||||
- float.h
|
||||
- fmtmsg.h
|
||||
- ftw.h
|
||||
- semaphore.h | See `core:sync`
|
||||
- inttypes.h | See `core:c`
|
||||
- iso646.h | Impossible
|
||||
- math.h | See `core:c/libc`
|
||||
- mqueue.h | Targets don't seem to have implemented it
|
||||
- regex.h | See `core:regex`
|
||||
- search.h | Not useful in Odin
|
||||
- spawn.h | Use `fork`, `execve`, etc.
|
||||
- stdarg.h | See `core:c/libc`
|
||||
- stdint.h | See `core:c`
|
||||
- stropts.h
|
||||
- syslog.h
|
||||
- pthread.h | Only the actual threads API is bound, see `core:sync` for synchronization primitives
|
||||
- string.h | Most of this is not useful in Odin, only a select few symbols are bound
|
||||
- tar.h
|
||||
- tgmath.h
|
||||
- trace.h
|
||||
- wchar.h
|
||||
- wctype.h
|
||||
|
||||
TODO:
|
||||
- time.h | Docs
|
||||
58
core/sys/posix/arpa_inet.odin
Normal file
58
core/sys/posix/arpa_inet.odin
Normal file
@@ -0,0 +1,58 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// arpa/inet.h - definitions for internet operations
|
||||
|
||||
foreign lib {
|
||||
// Use Odin's native big endian types `u32be` and `u16be` instead.
|
||||
// htonl :: proc(c.uint32_t) -> c.uint32_t ---
|
||||
// htons :: proc(c.uint16_t) -> c.uint16_t ---
|
||||
// ntohl :: proc(c.uint32_t) -> c.uint32_t ---
|
||||
// ntohs :: proc(c.uint16_t) -> c.uint16_t ---
|
||||
|
||||
// Use of this function is problematic because -1 is a valid address (255.255.255.255).
|
||||
// Avoid its use in favor of inet_aton(), inet_pton(3), or getaddrinfo(3) which provide a cleaner way to indicate error return.
|
||||
// inet_addr :: proc(cstring) -> in_addr_t ---
|
||||
|
||||
// Convert the Internet host address specified by in to a string in the Internet standard dot notation.
|
||||
//
|
||||
// NOTE: returns a static string overwritten by further calls.
|
||||
//
|
||||
// [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntoa.html ]]
|
||||
inet_ntoa :: proc(in_addr) -> cstring ---
|
||||
|
||||
// Convert a numeric address into a text string suitable for presentation.
|
||||
//
|
||||
// Returns `nil` and sets `errno` on failure.
|
||||
//
|
||||
// [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html ]]
|
||||
inet_ntop :: proc(
|
||||
af: AF, // INET or INET6
|
||||
src: rawptr, // either ^in_addr or ^in_addr6
|
||||
dst: [^]byte, // use `INET_ADDRSTRLEN` or `INET6_ADDRSTRLEN` for minimum lengths
|
||||
size: socklen_t,
|
||||
) -> cstring ---
|
||||
|
||||
// Convert an address in its standard text presentation form into its numeric binary form.
|
||||
//
|
||||
// [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html ]]
|
||||
inet_pton :: proc(
|
||||
af: AF, // INET or INET6
|
||||
src: cstring,
|
||||
dst: rawptr, // either ^in_addr or ^in_addr6
|
||||
size: socklen_t, // size_of(dst^)
|
||||
) -> pton_result ---
|
||||
}
|
||||
|
||||
pton_result :: enum c.int {
|
||||
AFNOSUPPORT = -1,
|
||||
INVALID = 0,
|
||||
SUCCESS = 1,
|
||||
}
|
||||
205
core/sys/posix/dirent.odin
Normal file
205
core/sys/posix/dirent.odin
Normal file
@@ -0,0 +1,205 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// dirent.h - format of directory entries
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
can be used as the comparison function for the scandir() function to sort the directory entries, d1 and d2, into alphabetical order.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]]
|
||||
*/
|
||||
@(link_name=LALPHASORT)
|
||||
alphasort :: proc([^]^dirent, [^]^dirent) -> c.int ---
|
||||
|
||||
/*
|
||||
Scan the directory dir, calling the function referenced by sel on each directory entry.
|
||||
|
||||
Example:
|
||||
list: [^]^posix.dirent
|
||||
ret := posix.scandir(#directory, &list, nil, posix.alphasort)
|
||||
if ret < 0 {
|
||||
panic(string(posix.strerror(posix.errno())))
|
||||
}
|
||||
defer posix.free(list)
|
||||
|
||||
entries := list[:ret]
|
||||
for entry in entries {
|
||||
log.info(entry)
|
||||
posix.free(entry)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]]
|
||||
*/
|
||||
@(link_name=LSCANDIR)
|
||||
scandir :: proc(
|
||||
dir: cstring,
|
||||
sel: ^[^]^dirent,
|
||||
filter: proc "c" (^dirent) -> b32 = nil,
|
||||
compar: proc "c" ([^]^dirent, [^]^dirent) -> c.int = alphasort,
|
||||
) -> c.int ---
|
||||
|
||||
/*
|
||||
Close the directory stream referred to by the argument dirp.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/closedir.html ]]
|
||||
*/
|
||||
closedir :: proc(dirp: DIR) -> result ---
|
||||
|
||||
/*
|
||||
Return a file descriptor referring to the same directory as the dirp argument.
|
||||
|
||||
// TODO: this is a macro on NetBSD?
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]]
|
||||
*/
|
||||
dirfd :: proc(dirp: DIR) -> FD ---
|
||||
|
||||
/*
|
||||
Equivalent to the opendir() function except that the directory is specified by a file descriptor
|
||||
rather than by a name.
|
||||
The file offset associated with the file descriptor at the time of the call determines
|
||||
which entries are returned.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]]
|
||||
*/
|
||||
@(link_name="fdopendir" + INODE_SUFFIX)
|
||||
fdopendir :: proc(dirp: FD) -> DIR ---
|
||||
|
||||
/*
|
||||
Open a directory stream corresponding to the directory named by the dirname argument.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]]
|
||||
*/
|
||||
@(link_name=LOPENDIR)
|
||||
opendir :: proc(path: cstring) -> DIR ---
|
||||
|
||||
/*
|
||||
Returns a pointer to a structure representing the directory entry at the current position
|
||||
in the directory stream specified by the argument dirp, and position the directory stream at
|
||||
the next entry.
|
||||
|
||||
Returns nil when the end is reached or an error occurred (which sets errno).
|
||||
|
||||
Example:
|
||||
posix.set_errno(.NONE)
|
||||
entry := posix.readdir(dirp)
|
||||
if entry == nil {
|
||||
if errno := posix.errno(); errno != .NONE {
|
||||
panic(string(posix.strerror(errno)))
|
||||
} else {
|
||||
fmt.println("end of directory stream")
|
||||
}
|
||||
} else {
|
||||
fmt.println(entry)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html ]]
|
||||
*/
|
||||
@(link_name=LREADDIR)
|
||||
readdir :: proc(dirp: DIR) -> ^dirent ---
|
||||
|
||||
/*
|
||||
Reset the position of the directory stream to which dirp refers to the beginning of the directory.
|
||||
It shall also cause the directory stream to refer to the current state of the corresponding directory,
|
||||
as a call to opendir() would have done.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rewinddir.html ]]
|
||||
*/
|
||||
@(link_name="rewinddir" + INODE_SUFFIX)
|
||||
rewinddir :: proc(dirp: DIR) ---
|
||||
|
||||
/*
|
||||
The seekdir() function shall set the position of the next readdir() operation on the directory
|
||||
stream specified by dirp to the position specified by loc.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/seekdir.html ]]
|
||||
*/
|
||||
@(link_name="seekdir" + INODE_SUFFIX)
|
||||
seekdir :: proc(dirp: DIR, loc: dir_loc) ---
|
||||
|
||||
/*
|
||||
The telldir() function shall obtain the current location associated with the directory stream
|
||||
specified by dirp.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/telldir.html ]]
|
||||
*/
|
||||
@(link_name="telldir" + INODE_SUFFIX)
|
||||
telldir :: proc(dirp: DIR) -> dir_loc ---
|
||||
|
||||
// deprecated.
|
||||
// readdir_r :: proc(DIR, ^dirent, ^^dirent) -> c.int ---
|
||||
}
|
||||
|
||||
DIR :: distinct rawptr
|
||||
|
||||
dir_loc :: c.long
|
||||
|
||||
// NOTE: `d_type` is not a POSIX standard field, but all targets we support add it.
|
||||
D_Type :: enum c.uint8_t {
|
||||
UNKNOWN = 0,
|
||||
FIFO = 1,
|
||||
CHR = 2,
|
||||
DIR = 4,
|
||||
BLK = 6,
|
||||
REG = 8,
|
||||
LNK = 10,
|
||||
SOCK = 12,
|
||||
WHT = 14,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LALPHASORT :: "__alphasort30"
|
||||
@(private) LSCANDIR :: "__scandir30"
|
||||
@(private) LOPENDIR :: "__opendir30"
|
||||
@(private) LREADDIR :: "__readdir30"
|
||||
} else {
|
||||
@(private) LALPHASORT :: "alphasort" + INODE_SUFFIX
|
||||
@(private) LSCANDIR :: "scandir" + INODE_SUFFIX
|
||||
@(private) LOPENDIR :: "opendir" + INODE_SUFFIX
|
||||
@(private) LREADDIR :: "readdir" + INODE_SUFFIX
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
dirent :: struct {
|
||||
d_ino: ino_t, /* [PSX] file number of entry */
|
||||
d_seekoff: c.uint64_t, /* seek offset */
|
||||
d_reclen: c.uint16_t, /* length of this record */
|
||||
d_namelen: c.uint16_t, /* length of string in d_name */
|
||||
d_type: D_Type, /* file type */
|
||||
d_name: [1024]c.char `fmt:"s,0"`, /* [PSX] entry name */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
dirent :: struct {
|
||||
d_ino: ino_t, /* [PSX] file number of entry */
|
||||
d_off: off_t, /* directory offset of the next entry */
|
||||
d_reclen: c.uint16_t, /* length of this record */
|
||||
d_type: D_Type, /* file type */
|
||||
d_namelen: c.uint8_t, /* length of string in d_name */
|
||||
d_pad0: c.uint32_t,
|
||||
d_name: [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
dirent :: struct {
|
||||
d_ino: ino_t, /* [PSX] file number of entry */
|
||||
d_reclen: c.uint16_t, /* length of this record */
|
||||
d_namelen: c.uint16_t, /* length of string in d_name */
|
||||
d_type: D_Type, /* file type */
|
||||
d_name: [512]c.char `fmt:"s,0"`, /* [PSX] entry name */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
115
core/sys/posix/dlfcn.odin
Normal file
115
core/sys/posix/dlfcn.odin
Normal file
@@ -0,0 +1,115 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// dlfcn.h - dynamic linking
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
inform the system that the object referenced by a handle returned from a previous dlopen()
|
||||
invocation is no longer needed by the application.
|
||||
|
||||
Returns: 0 on success, non-zero on failure (use dlerror() for more information)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlclose.html ]]
|
||||
*/
|
||||
dlclose :: proc(handle: Symbol_Table) -> c.int ---
|
||||
|
||||
/*
|
||||
return a null-terminated character string (with no trailing <newline>) that describes
|
||||
the last error that occurred during dynamic linking processing.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlerror.html ]]
|
||||
*/
|
||||
dlerror :: proc() -> cstring ---
|
||||
|
||||
/*
|
||||
Make the symbols (function identifiers and data object identifiers) in the executable object
|
||||
file specified by file available to the calling program.
|
||||
|
||||
Returns: a reference to the symbol table on success, nil on failure (use dlerror() for more information)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html ]]
|
||||
*/
|
||||
dlopen :: proc(file: cstring, mode: RTLD_Flags) -> Symbol_Table ---
|
||||
|
||||
/*
|
||||
Obtain the address of a symbol (a function identifier or a data object identifier)
|
||||
defined in the symbol table identified by the handle argument.
|
||||
|
||||
Returns: the address of the matched symbol on success, nil on failure (use dlerror() for more information)
|
||||
|
||||
Example:
|
||||
handle := posix.dlopen("/usr/home/me/libfoo.so", posix.RTLD_LOCAL + { .RTLD_LAZY })
|
||||
defer posix.dlclose(handle)
|
||||
|
||||
if handle == nil {
|
||||
panic(string(posix.dlerror()))
|
||||
}
|
||||
|
||||
foo: proc(a, b: int) -> int
|
||||
foo = auto_cast posix.dlsym(handle, "foo")
|
||||
|
||||
if foo == nil {
|
||||
panic(string(posix.dlerror()))
|
||||
}
|
||||
|
||||
fmt.printfln("foo(%v, %v) == %v", 1, 2, foo(1, 2))
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html ]]
|
||||
*/
|
||||
dlsym :: proc(handle: Symbol_Table, name: cstring) -> rawptr ---
|
||||
}
|
||||
|
||||
RTLD_Flag_Bits :: enum c.int {
|
||||
LAZY = log2(RTLD_LAZY),
|
||||
NOW = log2(RTLD_NOW),
|
||||
GLOBAL = log2(RTLD_GLOBAL),
|
||||
|
||||
// NOTE: use with `posix.RTLD_LOCAL + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
|
||||
// this bit set enum because it is 0 on some platforms and a value on others.
|
||||
// LOCAL = RTLD_LOCAL
|
||||
|
||||
_MAX = 31,
|
||||
}
|
||||
RTLD_Flags :: bit_set[RTLD_Flag_Bits; c.int]
|
||||
|
||||
Symbol_Table :: distinct rawptr
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
RTLD_LAZY :: 0x1
|
||||
RTLD_NOW :: 0x2
|
||||
_RTLD_LOCAL :: 0x4
|
||||
RTLD_GLOBAL :: 0x8
|
||||
|
||||
RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
RTLD_LAZY :: 1
|
||||
RTLD_NOW :: 2
|
||||
_RTLD_LOCAL :: 0
|
||||
RTLD_GLOBAL :: 0x100
|
||||
|
||||
RTLD_LOCAL :: RTLD_Flags{}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
RTLD_LAZY :: 0x1
|
||||
RTLD_NOW :: 0x2
|
||||
_RTLD_LOCAL :: 0x200
|
||||
RTLD_GLOBAL :: 0x100
|
||||
|
||||
RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
|
||||
373
core/sys/posix/errno.odin
Normal file
373
core/sys/posix/errno.odin
Normal file
@@ -0,0 +1,373 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
// errno.h - system error numbers
|
||||
|
||||
EDOM :: libc.EDOM
|
||||
EILSEQ :: libc.EILSEQ
|
||||
ERANGE :: libc.ERANGE
|
||||
|
||||
@(no_instrumentation)
|
||||
get_errno :: #force_inline proc "contextless" () -> Errno {
|
||||
return (^Errno)(libc.errno())^
|
||||
}
|
||||
|
||||
set_errno :: #force_inline proc "contextless" (err: Errno) {
|
||||
libc.errno()^ = i32(err)
|
||||
}
|
||||
|
||||
errno :: proc {
|
||||
get_errno,
|
||||
set_errno,
|
||||
}
|
||||
|
||||
Errno :: enum c.int {
|
||||
NONE = 0,
|
||||
EDOM = EDOM,
|
||||
EILSEQ = EILSEQ,
|
||||
ERANGE = ERANGE,
|
||||
E2BIG = E2BIG,
|
||||
EACCES = EACCES,
|
||||
EADDRINUSE = EADDRINUSE,
|
||||
EADDRNOTAVAIL = EADDRNOTAVAIL,
|
||||
EAFNOSUPPORT = EAFNOSUPPORT,
|
||||
EAGAIN = EAGAIN,
|
||||
EALREADY = EALREADY,
|
||||
EBADF = EBADF,
|
||||
EBADMSG = EBADMSG,
|
||||
EBUSY = EBUSY,
|
||||
ECANCELED = ECANCELED,
|
||||
ECHILD = ECHILD,
|
||||
ECONNABORTED = ECONNABORTED,
|
||||
ECONNREFUSED = ECONNREFUSED,
|
||||
ECONNRESET = ECONNRESET,
|
||||
EDEADLK = EDEADLK,
|
||||
EDESTADDRREQ = EDESTADDRREQ,
|
||||
EDQUOT = EDQUOT,
|
||||
EEXIST = EEXIST,
|
||||
EFAULT = EFAULT,
|
||||
EFBIG = EFBIG,
|
||||
EHOSTUNREACH = EHOSTUNREACH,
|
||||
EIDRM = EIDRM,
|
||||
EINPROGRESS = EINPROGRESS,
|
||||
EINTR = EINTR,
|
||||
EINVAL = EINVAL,
|
||||
EIO = EIO,
|
||||
EISCONN = EISCONN,
|
||||
EISDIR = EISDIR,
|
||||
ELOOP = ELOOP,
|
||||
EMFILE = EMFILE,
|
||||
EMLINK = EMLINK,
|
||||
EMSGSIZE = EMSGSIZE,
|
||||
EMULTIHOP = EMULTIHOP,
|
||||
ENAMETOOLONG = ENAMETOOLONG,
|
||||
ENETDOWN = ENETDOWN,
|
||||
ENETRESET = ENETRESET,
|
||||
ENETUNREACH = ENETUNREACH,
|
||||
ENFILE = ENFILE,
|
||||
ENOBUFS = ENOBUFS,
|
||||
ENODATA = ENODATA,
|
||||
ENODEV = ENODEV,
|
||||
ENOENT = ENOENT,
|
||||
ENOEXEC = ENOEXEC,
|
||||
ENOLCK = ENOLCK,
|
||||
ENOLINK = ENOLINK,
|
||||
ENOMEM = ENOMEM,
|
||||
ENOMSG = ENOMSG,
|
||||
ENOPROTOOPT = ENOPROTOOPT,
|
||||
ENOSPC = ENOSPC,
|
||||
ENOSR = ENOSR,
|
||||
ENOSTR = ENOSTR,
|
||||
ENOSYS = ENOSYS,
|
||||
ENOTCONN = ENOTCONN,
|
||||
ENOTDIR = ENOTDIR,
|
||||
ENOTEMPTY = ENOTEMPTY,
|
||||
ENOTRECOVERABLE = ENOTRECOVERABLE,
|
||||
ENOTSOCK = ENOTSOCK,
|
||||
ENOTSUP = ENOTSUP,
|
||||
ENOTTY = ENOTTY,
|
||||
ENXIO = ENXIO,
|
||||
EOPNOTSUPP = EOPNOTSUPP,
|
||||
EOVERFLOW = EOVERFLOW,
|
||||
EOWNERDEAD = EOWNERDEAD,
|
||||
EPERM = EPERM,
|
||||
EPIPE = EPIPE,
|
||||
EPROTO = EPROTO,
|
||||
EPROTONOSUPPORT = EPROTONOSUPPORT,
|
||||
EPROTOTYPE = EPROTOTYPE,
|
||||
EROFS = EROFS,
|
||||
ESPIPE = ESPIPE,
|
||||
ESRCH = ESRCH,
|
||||
ESTALE = ESTALE,
|
||||
ETIME = ETIME,
|
||||
ETIMEDOUT = ETIMEDOUT,
|
||||
ETXTBSY = ETXTBSY,
|
||||
EWOULDBLOCK = EWOULDBLOCK,
|
||||
EXDEV = EXDEV,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
EPERM :: 1
|
||||
ENOENT :: 2
|
||||
ESRCH :: 3
|
||||
EINTR :: 4
|
||||
EIO :: 5
|
||||
ENXIO :: 6
|
||||
E2BIG :: 7
|
||||
ENOEXEC :: 8
|
||||
EBADF :: 9
|
||||
ECHILD :: 10
|
||||
EDEADLK :: 11
|
||||
ENOMEM :: 12
|
||||
EACCES :: 13
|
||||
EFAULT :: 14
|
||||
EBUSY :: 16
|
||||
EEXIST :: 17
|
||||
EXDEV :: 18
|
||||
ENODEV :: 19
|
||||
ENOTDIR :: 20
|
||||
EISDIR :: 21
|
||||
EINVAL :: 22
|
||||
ENFILE :: 23
|
||||
EMFILE :: 24
|
||||
ENOTTY :: 25
|
||||
ETXTBSY :: 26
|
||||
EFBIG :: 27
|
||||
ENOSPC :: 28
|
||||
ESPIPE :: 29
|
||||
EROFS :: 30
|
||||
EMLINK :: 31
|
||||
EPIPE :: 32
|
||||
EAGAIN :: 35
|
||||
EWOULDBLOCK :: 35
|
||||
EINPROGRESS :: 36
|
||||
EALREADY :: 37
|
||||
ENOTSOCK :: 38
|
||||
EDESTADDRREQ :: 39
|
||||
EMSGSIZE :: 40
|
||||
EPROTOTYPE :: 41
|
||||
ENOPROTOOPT :: 42
|
||||
EPROTONOSUPPORT :: 43
|
||||
ENOTSUP :: 45
|
||||
EOPNOTSUPP :: 45
|
||||
EAFNOSUPPORT :: 47
|
||||
EADDRINUSE :: 48
|
||||
EADDRNOTAVAIL :: 49
|
||||
ENETDOWN :: 50
|
||||
ENETUNREACH :: 51
|
||||
ENETRESET :: 52
|
||||
ECONNABORTED :: 53
|
||||
ECONNRESET :: 54
|
||||
ENOBUFS :: 55
|
||||
EISCONN :: 56
|
||||
ENOTCONN :: 57
|
||||
ETIMEDOUT :: 60
|
||||
ECONNREFUSED :: 61
|
||||
ELOOP :: 62
|
||||
ENAMETOOLONG :: 63
|
||||
EHOSTUNREACH :: 65
|
||||
ENOTEMPTY :: 66
|
||||
EDQUOT :: 69
|
||||
ESTALE :: 70
|
||||
ENOLCK :: 77
|
||||
ENOSYS :: 78
|
||||
EOVERFLOW :: 84
|
||||
ECANCELED :: 89
|
||||
EIDRM :: 90
|
||||
ENOMSG :: 91
|
||||
EBADMSG :: 94
|
||||
EMULTIHOP :: 95
|
||||
ENODATA :: 96
|
||||
ENOLINK :: 97
|
||||
ENOSR :: 98
|
||||
ENOSTR :: 99
|
||||
EPROTO :: 100
|
||||
ETIME :: 101
|
||||
ENOTRECOVERABLE :: 104
|
||||
EOWNERDEAD :: 105
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
EPERM :: 1
|
||||
ENOENT :: 2
|
||||
ESRCH :: 3
|
||||
EINTR :: 4
|
||||
EIO :: 5
|
||||
ENXIO :: 6
|
||||
E2BIG :: 7
|
||||
ENOEXEC :: 8
|
||||
EBADF :: 9
|
||||
ECHILD :: 10
|
||||
EDEADLK :: 11
|
||||
ENOMEM :: 12
|
||||
EACCES :: 13
|
||||
EFAULT :: 14
|
||||
EBUSY :: 16
|
||||
EEXIST :: 17
|
||||
EXDEV :: 18
|
||||
ENODEV :: 19
|
||||
ENOTDIR :: 20
|
||||
EISDIR :: 21
|
||||
EINVAL :: 22
|
||||
ENFILE :: 23
|
||||
EMFILE :: 24
|
||||
ENOTTY :: 25
|
||||
ETXTBSY :: 26
|
||||
EFBIG :: 27
|
||||
ENOSPC :: 28
|
||||
ESPIPE :: 29
|
||||
EROFS :: 30
|
||||
EMLINK :: 31
|
||||
EPIPE :: 32
|
||||
EAGAIN :: 35
|
||||
EWOULDBLOCK :: 35
|
||||
EINPROGRESS :: 36
|
||||
EALREADY :: 37
|
||||
ENOTSOCK :: 38
|
||||
EDESTADDRREQ :: 39
|
||||
EMSGSIZE :: 40
|
||||
EPROTOTYPE :: 41
|
||||
ENOPROTOOPT :: 42
|
||||
EPROTONOSUPPORT :: 43
|
||||
ENOTSUP :: 45
|
||||
EOPNOTSUPP :: 45
|
||||
EAFNOSUPPORT :: 47
|
||||
EADDRINUSE :: 48
|
||||
EADDRNOTAVAIL :: 49
|
||||
ENETDOWN :: 50
|
||||
ENETUNREACH :: 51
|
||||
ENETRESET :: 52
|
||||
ECONNABORTED :: 53
|
||||
ECONNRESET :: 54
|
||||
ENOBUFS :: 55
|
||||
EISCONN :: 56
|
||||
ENOTCONN :: 57
|
||||
ETIMEDOUT :: 60
|
||||
ECONNREFUSED :: 61
|
||||
ELOOP :: 62
|
||||
ENAMETOOLONG :: 63
|
||||
EHOSTUNREACH :: 65
|
||||
ENOTEMPTY :: 66
|
||||
EDQUOT :: 69
|
||||
ESTALE :: 70
|
||||
ENOLCK :: 77
|
||||
ENOSYS :: 78
|
||||
EOVERFLOW :: 84
|
||||
EIDRM :: 82
|
||||
ENOMSG :: 83
|
||||
ECANCELED :: 85
|
||||
EBADMSG :: 89
|
||||
EMULTIHOP :: 90
|
||||
ENOLINK :: 91
|
||||
EPROTO :: 92
|
||||
ENOTRECOVERABLE :: 95
|
||||
EOWNERDEAD :: 96
|
||||
|
||||
// NOTE: not defined for freebsd
|
||||
ENODATA :: -1
|
||||
ENOSR :: -1
|
||||
ENOSTR :: -1
|
||||
ETIME :: -1
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
EPERM :: 1
|
||||
ENOENT :: 2
|
||||
ESRCH :: 3
|
||||
EINTR :: 4
|
||||
EIO :: 5
|
||||
ENXIO :: 6
|
||||
E2BIG :: 7
|
||||
ENOEXEC :: 8
|
||||
EBADF :: 9
|
||||
ECHILD :: 10
|
||||
EDEADLK :: 11
|
||||
ENOMEM :: 12
|
||||
EACCES :: 13
|
||||
EFAULT :: 14
|
||||
EBUSY :: 16
|
||||
EEXIST :: 17
|
||||
EXDEV :: 18
|
||||
ENODEV :: 19
|
||||
ENOTDIR :: 20
|
||||
EISDIR :: 21
|
||||
EINVAL :: 22
|
||||
ENFILE :: 23
|
||||
EMFILE :: 24
|
||||
ENOTTY :: 25
|
||||
ETXTBSY :: 26
|
||||
EFBIG :: 27
|
||||
ENOSPC :: 28
|
||||
ESPIPE :: 29
|
||||
EROFS :: 30
|
||||
EMLINK :: 31
|
||||
EPIPE :: 32
|
||||
EAGAIN :: 35
|
||||
EWOULDBLOCK :: 35
|
||||
EINPROGRESS :: 36
|
||||
EALREADY :: 37
|
||||
ENOTSOCK :: 38
|
||||
EDESTADDRREQ :: 39
|
||||
EMSGSIZE :: 40
|
||||
EPROTOTYPE :: 41
|
||||
ENOPROTOOPT :: 42
|
||||
EPROTONOSUPPORT :: 43
|
||||
ENOTSUP :: 45
|
||||
EOPNOTSUPP :: 45
|
||||
EAFNOSUPPORT :: 47
|
||||
EADDRINUSE :: 48
|
||||
EADDRNOTAVAIL :: 49
|
||||
ENETDOWN :: 50
|
||||
ENETUNREACH :: 51
|
||||
ENETRESET :: 52
|
||||
ECONNABORTED :: 53
|
||||
ECONNRESET :: 54
|
||||
ENOBUFS :: 55
|
||||
EISCONN :: 56
|
||||
ENOTCONN :: 57
|
||||
ETIMEDOUT :: 60
|
||||
ECONNREFUSED :: 61
|
||||
ELOOP :: 62
|
||||
ENAMETOOLONG :: 63
|
||||
EHOSTUNREACH :: 65
|
||||
ENOTEMPTY :: 66
|
||||
EDQUOT :: 69
|
||||
ESTALE :: 70
|
||||
ENOLCK :: 77
|
||||
ENOSYS :: 78
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
EOVERFLOW :: 84
|
||||
EIDRM :: 82
|
||||
ENOMSG :: 83
|
||||
ECANCELED :: 87
|
||||
EBADMSG :: 88
|
||||
ENODATA :: 89
|
||||
EMULTIHOP :: 94
|
||||
ENOLINK :: 95
|
||||
EPROTO :: 96
|
||||
ENOTRECOVERABLE :: 98
|
||||
EOWNERDEAD :: 97
|
||||
ENOSR :: 90
|
||||
ENOSTR :: 91
|
||||
ETIME :: 92
|
||||
} else {
|
||||
EOVERFLOW :: 87
|
||||
EIDRM :: 89
|
||||
ENOMSG :: 90
|
||||
ECANCELED :: 88
|
||||
EBADMSG :: 92
|
||||
EPROTO :: 95
|
||||
ENOTRECOVERABLE :: 93
|
||||
EOWNERDEAD :: 94
|
||||
// NOTE: not defined for openbsd
|
||||
ENODATA :: -1
|
||||
EMULTIHOP :: -1
|
||||
ENOLINK :: -1
|
||||
ENOSR :: -1
|
||||
ENOSTR :: -1
|
||||
ETIME :: -1
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
|
||||
415
core/sys/posix/fcntl.odin
Normal file
415
core/sys/posix/fcntl.odin
Normal file
@@ -0,0 +1,415 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// fcntl.h - file control options
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Implemented as `return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);`
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/creat.html ]]
|
||||
*/
|
||||
creat :: proc(path: cstring, mode: mode_t) -> FD ---
|
||||
|
||||
/*
|
||||
Perform the operations on open files.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html ]]
|
||||
*/
|
||||
fcntl :: proc(fd: FD, cmd: FCNTL_Cmd, arg: rawptr = nil) -> c.int ---
|
||||
|
||||
/*
|
||||
Establish the connection between a file and a file descriptor.
|
||||
It shall create an open file description that refers to a file and a file descriptor that
|
||||
refers to that open file description. The file descriptor is used by other I/O functions to
|
||||
refer to that file.
|
||||
The path argument points to a pathname naming the file
|
||||
|
||||
Returns: -1 on failure (setting errno), a file descriptor on success.
|
||||
|
||||
Example:
|
||||
// The following example opens the file /tmp/file, either by creating it (if it does not already exist),
|
||||
// or by truncating its length to 0 (if it does exist). In the former case, if the call creates a new file,
|
||||
// the access permission bits in the file mode of the file are set to permit reading and writing by the owner,
|
||||
// and to permit reading only by group members and others.
|
||||
fd := posix.open("/tmp/file", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
|
||||
|
||||
// The following example uses the open() function to try to create the LOCKFILE file and open it for writing.
|
||||
// Since the open() function specifies the O_EXCL flag, the call fails if the file already exists.
|
||||
// In that case, the program assumes that someone else is updating the password file and exits.
|
||||
fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .EXCL }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
|
||||
if fd == -1 {
|
||||
fmt.println("cannot open /etc/ptmp")
|
||||
}
|
||||
|
||||
// The following example opens a file for writing, creating the file if it does not already exist.
|
||||
// If the file does exist, the system truncates the file to zero bytes.
|
||||
fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
|
||||
if fd == -1 {
|
||||
fmt.println("cannot open output file")
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]]
|
||||
*/
|
||||
open :: proc(path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD ---
|
||||
|
||||
/*
|
||||
Equivalent to the open() function except in the case where path specifies a relative path.
|
||||
In this case the file to be opened is determined relative to the directory associated with the
|
||||
file descriptor fd instead of the current working directory.
|
||||
|
||||
Returns: -1 on failure (setting errno), a file descriptor on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]]
|
||||
*/
|
||||
openat :: proc(fd: FD, path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD ---
|
||||
}
|
||||
|
||||
FCNTL_Cmd :: enum c.int {
|
||||
DUPFD = F_DUPFD,
|
||||
DUPFD_CLOEXEC = F_DUPFD_CLOEXEC,
|
||||
GETFD = F_GETFD,
|
||||
SETFD = F_SETFD,
|
||||
GETFL = F_GETFL,
|
||||
SETFL = F_SETFL,
|
||||
GETLK = F_GETLK,
|
||||
SETLK = F_SETLK,
|
||||
SETLKW = F_SETLKW,
|
||||
GETOWN = F_GETOWN,
|
||||
SETOWN = F_SETOWN,
|
||||
}
|
||||
|
||||
Lock_Type :: enum c.short {
|
||||
RDLCK = F_RDLCK,
|
||||
UNLCK = F_UNLCK,
|
||||
WRLCK = F_WRLCK,
|
||||
}
|
||||
|
||||
// Assertions made to unify this bit set.
|
||||
#assert(O_RDONLY == 0)
|
||||
|
||||
O_Flag_Bits :: enum c.int {
|
||||
// Sets FD_CLOEXEC on the file descriptor.
|
||||
CLOEXEC = log2(O_CLOEXEC),
|
||||
// If not exists, combined with DIRECTORY will cause creation of a directory, otherwise a regular file.
|
||||
CREAT = log2(O_CREAT),
|
||||
// Fails if the opened descriptor would not be a directory.
|
||||
DIRECTORY = log2(O_DIRECTORY),
|
||||
// If combined with CREAT, causes a failure if the file already exists.
|
||||
EXCL = log2(O_EXCL),
|
||||
// If terminal device, do not make it the controlling terminal for the process.
|
||||
NOCTTY = log2(O_NOCTTY),
|
||||
// Don't follow symbolic links, fail with errno ELOOP.
|
||||
NOFOLLOW = log2(O_NOFOLOW),
|
||||
// If exists and regular, truncate the length to 0.
|
||||
TRUNC = log2(O_TRUNC),
|
||||
|
||||
// NOTE: use with `posix.O_TTY_INIT + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
|
||||
// this bit set enum because it is 0 on some platforms and a value on others.
|
||||
// TTY_INIT = O_TTY_INIT,
|
||||
|
||||
// Set file offset to end of file prior to each write.
|
||||
APPEND = log2(O_APPEND),
|
||||
// Write I/O shall complete as defined by synchronized I/O data integrity completion.
|
||||
DSYNC = log2(O_DSYNC),
|
||||
// Causes nonblocking behaviour in various situations.
|
||||
NONBLOCK = log2(O_NONBLOCK),
|
||||
// Write I/O shall complete as defined by synchronized I/O file integrity completion.
|
||||
SYNC = log2(O_SYNC),
|
||||
// NOTE: use with `posix.O_RSYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
|
||||
// this bit set enum because it is 0 on some platforms and a value on others.
|
||||
// RSYNC = O_RSYNC,
|
||||
|
||||
// Execute only.
|
||||
EXEC = log2(O_EXEC),
|
||||
// Reading and writing.
|
||||
RDWR = log2(O_RDWR),
|
||||
// Writing only.
|
||||
WRONLY = log2(O_WRONLY),
|
||||
// Reading only.
|
||||
// RDONLY = 0, // Default
|
||||
|
||||
}
|
||||
O_Flags :: bit_set[O_Flag_Bits; c.int]
|
||||
|
||||
// A mask of all the access mode bits.
|
||||
O_ACCMODE :: O_Flags{ .EXEC, .RDWR, .WRONLY }
|
||||
|
||||
AT_Flag_Bits :: enum c.int {
|
||||
EACCESS = log2(AT_EACCESS),
|
||||
SYMLINK_NOFOLLOW = log2(AT_SYMLINK_NOFOLLOW),
|
||||
SYMLINK_FOLLOW = log2(AT_SYMLINK_FOLLOW),
|
||||
REMOVEDIR = log2(AT_REMOVEDIR),
|
||||
}
|
||||
AT_Flags :: bit_set[AT_Flag_Bits; c.int]
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
off_t :: distinct c.int64_t
|
||||
pid_t :: distinct c.int32_t
|
||||
|
||||
F_DUPFD :: 0
|
||||
F_DUPFD_CLOEXEC :: 67
|
||||
F_GETFD :: 1
|
||||
F_SETFD :: 2
|
||||
F_GETFL :: 3
|
||||
F_SETFL :: 4
|
||||
F_GETLK :: 7
|
||||
F_SETLK :: 8
|
||||
F_SETLKW :: 9
|
||||
F_GETOWN :: 5
|
||||
F_SETOWN :: 6
|
||||
|
||||
FD_CLOEXEC :: 1
|
||||
|
||||
F_RDLCK :: 1
|
||||
F_UNLCK :: 2
|
||||
F_WRLCK :: 3
|
||||
|
||||
O_CLOEXEC :: 0x01000000
|
||||
O_CREAT :: 0x00000200
|
||||
O_DIRECTORY :: 0x00100000
|
||||
O_EXCL :: 0x00000800
|
||||
O_NOCTTY :: 0x00020000
|
||||
O_NOFOLOW :: 0x00000100
|
||||
O_TRUNC :: 0x00000400
|
||||
|
||||
_O_TTY_INIT :: 0
|
||||
O_TTY_INIT :: O_Flags{}
|
||||
|
||||
O_APPEND :: 0x00000008
|
||||
O_DSYNC :: 0x00400000
|
||||
O_NONBLOCK :: 0x00000004
|
||||
O_SYNC :: 0x0080
|
||||
|
||||
_O_RSYNC :: 0
|
||||
O_RSYNC :: O_Flags{}
|
||||
|
||||
O_EXEC :: 0x40000000
|
||||
O_RDONLY :: 0
|
||||
O_RDWR :: 0x0002
|
||||
O_WRONLY :: 0x0001
|
||||
|
||||
_O_SEARCH :: O_EXEC | O_DIRECTORY
|
||||
O_SEARCH :: O_Flags{ .EXEC, .DIRECTORY }
|
||||
|
||||
AT_FDCWD: FD: -2
|
||||
|
||||
AT_EACCESS :: 0x0010
|
||||
AT_SYMLINK_NOFOLLOW :: 0x0020
|
||||
AT_SYMLINK_FOLLOW :: 0x0040
|
||||
AT_REMOVEDIR :: 0x0080
|
||||
|
||||
flock :: struct {
|
||||
l_start: off_t, /* [PSX] relative offset in bytes */
|
||||
l_len: off_t, /* [PSX] size; if 0 then until EOF */
|
||||
l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
|
||||
l_type: Lock_Type, /* [PSX] type of lock */
|
||||
l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
off_t :: distinct c.int64_t
|
||||
pid_t :: distinct c.int32_t
|
||||
|
||||
F_DUPFD :: 0
|
||||
F_DUPFD_CLOEXEC :: 17
|
||||
F_GETFD :: 1
|
||||
F_SETFD :: 2
|
||||
F_GETFL :: 3
|
||||
F_SETFL :: 4
|
||||
F_GETLK :: 7
|
||||
F_SETLK :: 8
|
||||
F_SETLKW :: 9
|
||||
F_GETOWN :: 5
|
||||
F_SETOWN :: 6
|
||||
|
||||
FD_CLOEXEC :: 1
|
||||
|
||||
F_RDLCK :: 1
|
||||
F_UNLCK :: 2
|
||||
F_WRLCK :: 3
|
||||
|
||||
O_CLOEXEC :: 0x00100000
|
||||
O_CREAT :: 0x0200
|
||||
O_DIRECTORY :: 0x00020000
|
||||
O_EXCL :: 0x0800
|
||||
O_NOCTTY :: 0x8000
|
||||
O_NOFOLOW :: 0x0100
|
||||
O_TRUNC :: 0x0400
|
||||
|
||||
_O_TTY_INIT :: 0x00080000
|
||||
O_TTY_INIT :: O_Flags{O_Flag_Bits(log2(_O_TTY_INIT))}
|
||||
|
||||
O_APPEND :: 0x0008
|
||||
O_DSYNC :: 0x01000000
|
||||
O_NONBLOCK :: 0x0004
|
||||
O_SYNC :: 0x0080
|
||||
_O_RSYNC :: 0
|
||||
O_RSYNC :: O_Flags{}
|
||||
|
||||
O_EXEC :: 0x00040000
|
||||
O_RDONLY :: 0
|
||||
O_RDWR :: 0x0002
|
||||
O_WRONLY :: 0x0001
|
||||
|
||||
_O_SEARCH :: O_EXEC|O_DIRECTORY
|
||||
O_SEARCH :: O_Flags{ .EXEC, .DIRECTORY }
|
||||
|
||||
AT_FDCWD: FD: -100
|
||||
|
||||
AT_EACCESS :: 0x0100
|
||||
AT_SYMLINK_NOFOLLOW :: 0x0200
|
||||
AT_SYMLINK_FOLLOW :: 0x0400
|
||||
AT_REMOVEDIR :: 0x0800
|
||||
|
||||
flock :: struct {
|
||||
l_start: off_t, /* [PSX] relative offset in bytes */
|
||||
l_len: off_t, /* [PSX] size; if 0 then until EOF */
|
||||
l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
|
||||
l_type: Lock_Type, /* [PSX] type of lock */
|
||||
l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
|
||||
l_sysid: c.int,
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
off_t :: distinct c.int64_t
|
||||
pid_t :: distinct c.int32_t
|
||||
|
||||
F_DUPFD :: 0
|
||||
F_DUPFD_CLOEXEC :: 12
|
||||
F_GETFD :: 1
|
||||
F_SETFD :: 2
|
||||
F_GETFL :: 3
|
||||
F_SETFL :: 4
|
||||
F_GETLK :: 7
|
||||
F_SETLK :: 8
|
||||
F_SETLKW :: 9
|
||||
F_GETOWN :: 5
|
||||
F_SETOWN :: 6
|
||||
|
||||
FD_CLOEXEC :: 1
|
||||
|
||||
F_RDLCK :: 1
|
||||
F_UNLCK :: 2
|
||||
F_WRLCK :: 3
|
||||
|
||||
O_CLOEXEC :: 0x00400000
|
||||
O_CREAT :: 0x0200
|
||||
O_DIRECTORY :: 0x0020000
|
||||
O_EXCL :: 0x0800
|
||||
O_NOCTTY :: 0x8000
|
||||
O_NOFOLOW :: 0x0100
|
||||
O_TRUNC :: 0x0400
|
||||
|
||||
_O_TTY_INIT :: 0
|
||||
O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers
|
||||
|
||||
O_APPEND :: 0x0008
|
||||
O_DSYNC :: 0x010000
|
||||
O_NONBLOCK :: 0x0004
|
||||
O_SYNC :: 0x0080
|
||||
|
||||
_O_RSYNC :: 0x0002
|
||||
O_RSYNC :: O_Flags{O_Flag_Bits(log2(_O_RSYNC))}
|
||||
|
||||
|
||||
O_EXEC :: 0x04000000
|
||||
O_RDONLY :: 0
|
||||
O_RDWR :: 0x0002
|
||||
O_WRONLY :: 0x0001
|
||||
|
||||
_O_SEARCH :: 0x00800000
|
||||
O_SEARCH :: O_Flags{O_Flag_Bits(log2(_O_SEARCH))}
|
||||
|
||||
AT_FDCWD: FD: -100
|
||||
|
||||
AT_EACCESS :: 0x100
|
||||
AT_SYMLINK_NOFOLLOW :: 0x200
|
||||
AT_SYMLINK_FOLLOW :: 0x400
|
||||
AT_REMOVEDIR :: 0x800
|
||||
|
||||
flock :: struct {
|
||||
l_start: off_t, /* [PSX] relative offset in bytes */
|
||||
l_len: off_t, /* [PSX] size; if 0 then until EOF */
|
||||
l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
|
||||
l_type: Lock_Type, /* [PSX] type of lock */
|
||||
l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
|
||||
}
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
off_t :: distinct c.int64_t
|
||||
pid_t :: distinct c.int32_t
|
||||
|
||||
F_DUPFD :: 0
|
||||
F_DUPFD_CLOEXEC :: 10
|
||||
F_GETFD :: 1
|
||||
F_SETFD :: 2
|
||||
F_GETFL :: 3
|
||||
F_SETFL :: 4
|
||||
F_GETLK :: 7
|
||||
F_SETLK :: 8
|
||||
F_SETLKW :: 9
|
||||
F_GETOWN :: 5
|
||||
F_SETOWN :: 6
|
||||
|
||||
FD_CLOEXEC :: 1
|
||||
|
||||
F_RDLCK :: 1
|
||||
F_UNLCK :: 2
|
||||
F_WRLCK :: 3
|
||||
|
||||
O_CLOEXEC :: 0x10000
|
||||
O_CREAT :: 0x0200
|
||||
O_DIRECTORY :: 0x20000
|
||||
O_EXCL :: 0x0800
|
||||
O_NOCTTY :: 0x8000
|
||||
O_NOFOLOW :: 0x0100
|
||||
O_TRUNC :: 0x0400
|
||||
|
||||
_O_TTY_INIT :: 0
|
||||
O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers
|
||||
|
||||
O_APPEND :: 0x0008
|
||||
O_DSYNC :: 0x010000
|
||||
O_NONBLOCK :: 0x0004
|
||||
O_SYNC :: 0x0080
|
||||
|
||||
_O_RSYNC :: O_SYNC
|
||||
O_RSYNC :: O_Flags{ .SYNC }
|
||||
|
||||
O_EXEC :: 0x04000000 // NOTE: not defined in the headers
|
||||
O_RDONLY :: 0
|
||||
O_RDWR :: 0x0002
|
||||
O_WRONLY :: 0x0001
|
||||
|
||||
_O_SEARCH :: 0
|
||||
O_SEARCH :: O_Flags{} // NOTE: not defined in the headers
|
||||
|
||||
AT_FDCWD: FD: -100
|
||||
|
||||
AT_EACCESS :: 0x01
|
||||
AT_SYMLINK_NOFOLLOW :: 0x02
|
||||
AT_SYMLINK_FOLLOW :: 0x04
|
||||
AT_REMOVEDIR :: 0x08
|
||||
|
||||
flock :: struct {
|
||||
l_start: off_t, /* [PSX] relative offset in bytes */
|
||||
l_len: off_t, /* [PSX] size; if 0 then until EOF */
|
||||
l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
|
||||
l_type: Lock_Type, /* [PSX] type of lock */
|
||||
l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
58
core/sys/posix/fnmatch.odin
Normal file
58
core/sys/posix/fnmatch.odin
Normal file
@@ -0,0 +1,58 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// fnmatch.h - filename-matching types
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Match patterns as described in XCU [[ Patterns Matching a Single Character; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01 ]]
|
||||
// and [[ Patterns Matching Multiple Characters; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_02 ]].
|
||||
It checks the string specified by the string argument to see if it matches the pattern specified by the pattern argument.
|
||||
|
||||
Returns: 0 when matched. if there is no match, fnmatch() shall return FNM_NOMATCH. Non-zero on other errors.
|
||||
|
||||
Example:
|
||||
assert(posix.fnmatch("*.odin", "foo.odin", {}) == 0)
|
||||
assert(posix.fnmatch("*.txt", "foo.odin", {}) == posix.FNM_NOMATCH)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html ]]
|
||||
*/
|
||||
fnmatch :: proc(pattern: cstring, string: cstring, flags: FNM_Flags) -> c.int ---
|
||||
}
|
||||
|
||||
FNM_Flag_Bits :: enum c.int {
|
||||
// A <slash> character ( '/' ) in string shall be explicitly matched by a <slash> in pattern;
|
||||
// it shall not be matched by either the <asterisk> or <question-mark> special characters,
|
||||
// nor by a bracket expression.
|
||||
PATHNAME = log2(FNM_PATHNAME),
|
||||
|
||||
// A leading <period> ( '.' ) in string shall match a <period> in pattern;
|
||||
// as described by rule 2 in XCU [[ Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]]
|
||||
// where the location of "leading" is indicated by the value of PATHNAME:
|
||||
// 1. If PATHNAME is set, a <period> is "leading" if it is the first character in string or if it immediately follows a <slash>.
|
||||
// 2. If PATHNAME is not set, a <period> is "leading" only if it is the first character of string.
|
||||
PERIOD = log2(FNM_PERIOD),
|
||||
|
||||
// A <backslash> character shall be treated as an ordinary character.
|
||||
NOESCAPE = log2(FNM_NOESCAPE),
|
||||
}
|
||||
FNM_Flags :: bit_set[FNM_Flag_Bits; c.int]
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
FNM_NOMATCH :: 1
|
||||
|
||||
FNM_PATHNAME :: 0x02
|
||||
FNM_PERIOD :: 0x04
|
||||
FNM_NOESCAPE :: 0x01
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
179
core/sys/posix/glob.odin
Normal file
179
core/sys/posix/glob.odin
Normal file
@@ -0,0 +1,179 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// glob.h - pathname pattern-matching types
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
The glob() function is a pathname generator that shall implement the rules defined in
|
||||
[[ XCU Pattern Matching Notation; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 ]],
|
||||
with optional support for rule 3 in XCU [[ Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]].
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html ]]
|
||||
*/
|
||||
@(link_name=LGLOB)
|
||||
glob :: proc(
|
||||
pattern: cstring,
|
||||
flags: Glob_Flags,
|
||||
errfunc: proc "c" (epath: cstring, eerrno: Errno) -> b32 = nil, // Return `true` to abort the glob().
|
||||
pglob: ^glob_t,
|
||||
) -> Glob_Result ---
|
||||
|
||||
/*
|
||||
Free the glob results.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html ]]
|
||||
*/
|
||||
@(link_name=LGLOBFREE)
|
||||
globfree :: proc(^glob_t) ---
|
||||
}
|
||||
|
||||
Glob_Flag_Bits :: enum c.int {
|
||||
// Append pathnames generated to the ones from a previous call to glob().
|
||||
APPEND = log2(GLOB_APPEND),
|
||||
// Make use of pglob->gl_offs. If this flag is set, pglob->gl_offs is used to specify how many null pointers to add to the beginning of pglob->gl_pathv.
|
||||
// In other words, pglob->gl_pathv shall point to pglob->gl_offs null pointers, followed by pglob->gl_pathc pathname pointers, followed by a null pointer.
|
||||
DOOFFS = log2(GLOB_DOOFFS),
|
||||
// Cause glob() to return when it encounters a directory that it cannot open or read. Ordinarily,
|
||||
// glob() continues to find matches.
|
||||
ERR = log2(GLOB_ERR),
|
||||
// Each pathname that is a directory that matches pattern shall have a <slash> appended.
|
||||
MARK = log2(GLOB_MARK),
|
||||
// Supports rule 3 in [[ XCU Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]].
|
||||
// If pattern does not match any pathname, then glob() shall return a list consisting of only pattern,
|
||||
// and the number of matched pathnames is 1.
|
||||
NOCHECK = log2(GLOB_NOCHECK),
|
||||
// Disable backslash escaping.
|
||||
NOESCAPE = log2(GLOB_NOESCAPE),
|
||||
// Ordinarily, glob() sorts the matching pathnames according to the current setting of the
|
||||
// LC_COLLATE category; see XBD LC_COLLATE. When this flag is used,
|
||||
// the order of pathnames returned is unspecified.
|
||||
NOSORT = log2(GLOB_NOSORT),
|
||||
}
|
||||
Glob_Flags :: bit_set[Glob_Flag_Bits; c.int]
|
||||
|
||||
Glob_Result :: enum c.int {
|
||||
SUCCESS = 0,
|
||||
ABORTED = GLOB_ABORTED,
|
||||
NOMATCH = GLOB_NOMATCH,
|
||||
NOSPACE = GLOB_NOSPACE,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LGLOB :: "__glob30"
|
||||
@(private) LGLOBFREE :: "__globfree30"
|
||||
} else {
|
||||
@(private) LGLOB :: "glob" + INODE_SUFFIX
|
||||
@(private) LGLOBFREE :: "globfree"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
glob_t :: struct {
|
||||
gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */
|
||||
gl_matchc: c.int, /* count of paths matching pattern */
|
||||
gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */
|
||||
gl_flags: Glob_Flags, /* copy of flags parameter to glob */
|
||||
gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
|
||||
|
||||
// Non-standard alternate file system access functions:
|
||||
|
||||
using _: struct #raw_union {
|
||||
gl_errfunc: proc "c" (cstring, c.int) -> c.int,
|
||||
gl_errblk: proc "c" (cstring, c.int) -> c.int,
|
||||
},
|
||||
gl_closedir: proc "c" (dirp: DIR),
|
||||
gl_readdir: proc "c" (dirp: DIR) -> ^dirent,
|
||||
gl_opendir: proc "c" (path: cstring) -> DIR,
|
||||
gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
}
|
||||
|
||||
GLOB_APPEND :: 0x0001
|
||||
GLOB_DOOFFS :: 0x0002
|
||||
GLOB_ERR :: 0x0004
|
||||
GLOB_MARK :: 0x0008
|
||||
GLOB_NOCHECK :: 0x0010
|
||||
GLOB_NOESCAPE :: 0x2000
|
||||
GLOB_NOSORT :: 0x0020
|
||||
|
||||
GLOB_ABORTED :: -2
|
||||
GLOB_NOMATCH :: -3
|
||||
GLOB_NOSPACE :: -1
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
|
||||
|
||||
glob_t :: struct {
|
||||
gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */
|
||||
gl_matchc: c.size_t, /* count of paths matching pattern */
|
||||
gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */
|
||||
gl_flags: Glob_Flags, /* copy of flags parameter to glob */
|
||||
gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
|
||||
|
||||
// Non-standard alternate file system access functions:
|
||||
|
||||
gl_errfunc: proc "c" (cstring, c.int) -> c.int,
|
||||
|
||||
gl_closedir: proc "c" (dirp: DIR),
|
||||
gl_readdir: proc "c" (dirp: DIR) -> ^dirent,
|
||||
gl_opendir: proc "c" (path: cstring) -> DIR,
|
||||
gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
}
|
||||
|
||||
GLOB_APPEND :: 0x0001
|
||||
GLOB_DOOFFS :: 0x0002
|
||||
GLOB_ERR :: 0x0004
|
||||
GLOB_MARK :: 0x0008
|
||||
GLOB_NOCHECK :: 0x0010
|
||||
GLOB_NOESCAPE :: 0x2000 when ODIN_OS == .FreeBSD else 0x0100
|
||||
GLOB_NOSORT :: 0x0020
|
||||
|
||||
GLOB_ABORTED :: -2
|
||||
GLOB_NOMATCH :: -3
|
||||
GLOB_NOSPACE :: -1
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
glob_t :: struct {
|
||||
gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */
|
||||
gl_matchc: c.size_t, /* count of paths matching pattern */
|
||||
gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */
|
||||
gl_flags: Glob_Flags, /* copy of flags parameter to glob */
|
||||
gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
|
||||
|
||||
gl_statv: [^]stat_t,
|
||||
|
||||
// Non-standard alternate file system access functions:
|
||||
|
||||
gl_errfunc: proc "c" (cstring, c.int) -> c.int,
|
||||
|
||||
gl_closedir: proc "c" (dirp: DIR),
|
||||
gl_readdir: proc "c" (dirp: DIR) -> ^dirent,
|
||||
gl_opendir: proc "c" (path: cstring) -> DIR,
|
||||
gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result,
|
||||
}
|
||||
|
||||
GLOB_APPEND :: 0x0001
|
||||
GLOB_DOOFFS :: 0x0002
|
||||
GLOB_ERR :: 0x0004
|
||||
GLOB_MARK :: 0x0008
|
||||
GLOB_NOCHECK :: 0x0010
|
||||
GLOB_NOESCAPE :: 0x1000
|
||||
GLOB_NOSORT :: 0x0020
|
||||
|
||||
GLOB_ABORTED :: -2
|
||||
GLOB_NOMATCH :: -3
|
||||
GLOB_NOSPACE :: -1
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
130
core/sys/posix/grp.odin
Normal file
130
core/sys/posix/grp.odin
Normal file
@@ -0,0 +1,130 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// grp.h - group structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Closes the group database.
|
||||
|
||||
Checking status would be done by setting errno to 0, calling this, and checking errno.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]]
|
||||
*/
|
||||
endgrent :: proc() ---
|
||||
|
||||
/*
|
||||
Rewinds the group database so getgrent() returns the first entry again.
|
||||
|
||||
Checking status would be done by setting errno to 0, calling this, and checking errno.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]]
|
||||
*/
|
||||
setgrent :: proc() ---
|
||||
|
||||
/*
|
||||
Returns a pointer to an entry of the group database.
|
||||
|
||||
Opens the group database if it isn't.
|
||||
|
||||
Returns: nil on failure (setting errno) or EOF (not setting errno), the entry otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]]
|
||||
*/
|
||||
getgrent :: proc() -> ^group ---
|
||||
|
||||
/*
|
||||
Searches for an entry with a matching gid in the group database.
|
||||
|
||||
Returns: nil (setting errno) on failure, a pointer to the entry on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrgid.html ]]
|
||||
*/
|
||||
getgrgid :: proc(gid: gid_t) -> ^group ---
|
||||
|
||||
/*
|
||||
Searches for an entry with a matching gid in the group database.
|
||||
|
||||
Updates grp with the matching entry and stores it (or a nil pointer (setting errno)) into result.
|
||||
|
||||
Strings are allocated into the given buffer, you can call `sysconf(._GETGR_R_SIZE_MAX)` for an appropriate size.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrgid.html ]]
|
||||
*/
|
||||
getgrgid_r :: proc(gid: gid_t, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno ---
|
||||
|
||||
/*
|
||||
Searches for an entry with a matching gid in the group database.
|
||||
|
||||
Returns: nil (setting errno) on failure, a pointer to the entry on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrnam.html ]]
|
||||
*/
|
||||
getgrnam :: proc(name: cstring) -> ^group ---
|
||||
|
||||
/*
|
||||
Searches for an entry with a matching gid in the group database.
|
||||
|
||||
Updates grp with the matching entry and stores it (or a nil pointer (setting errno)) into result.
|
||||
|
||||
Strings are allocated into the given buffer, you can call `sysconf(._GETGR_R_SIZE_MAX)` for an appropriate size.
|
||||
|
||||
Example:
|
||||
length := posix.sysconf(._GETGR_R_SIZE_MAX)
|
||||
if length == -1 {
|
||||
length = 1024
|
||||
}
|
||||
|
||||
result: posix.group
|
||||
resultp: ^posix.group
|
||||
|
||||
e: posix.Errno
|
||||
|
||||
buffer: [dynamic]byte
|
||||
defer delete(buffer)
|
||||
|
||||
for {
|
||||
mem_err := resize(&buffer, length)
|
||||
assert(mem_err == nil)
|
||||
|
||||
e = posix.getgrnam_r("nobody", &result, raw_data(buffer), len(buffer), &resultp)
|
||||
if e != .ERANGE {
|
||||
break
|
||||
}
|
||||
|
||||
length *= 2
|
||||
assert(length > 0)
|
||||
}
|
||||
|
||||
if e != .NONE {
|
||||
panic(string(posix.strerror(e)))
|
||||
}
|
||||
|
||||
fmt.println(result)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrnam.html ]]
|
||||
*/
|
||||
getgrnam_r :: proc(name: cstring, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
gid_t :: distinct c.uint32_t
|
||||
|
||||
group :: struct {
|
||||
gr_name: cstring, /* [PSX] group name */
|
||||
gr_passwd: cstring, /* group password */
|
||||
gr_gid: gid_t, /* [PSX] group id */
|
||||
gr_mem: [^]cstring, /* [PSX] group members */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
50
core/sys/posix/iconv.odin
Normal file
50
core/sys/posix/iconv.odin
Normal file
@@ -0,0 +1,50 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
// NOTE: iconv is in a different library
|
||||
foreign import lib "system:iconv"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// iconv.h - codeset conversion facility
|
||||
|
||||
iconv_t :: distinct rawptr
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Convert the sequence of characters from one codeset, in the array specified by inbuf,
|
||||
into a sequence of corresponding characters in another codeset, in the array specified by outbuf.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the number of non-identical conversions performed on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv.html ]]
|
||||
*/
|
||||
iconv :: proc(
|
||||
cd: iconv_t,
|
||||
inbuf: ^[^]byte,
|
||||
inbytesleft: ^c.size_t,
|
||||
outbuf: ^[^]byte,
|
||||
outbyteslen: ^c.size_t,
|
||||
) -> c.size_t ---
|
||||
|
||||
/*
|
||||
Deallocates the conversion descriptor cd and all other associated resources allocated by iconv_open().
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv_close.html ]]
|
||||
*/
|
||||
iconv_close :: proc(cd: iconv_t) -> result ---
|
||||
|
||||
/*
|
||||
Returns a conversion descriptor that describes a conversion from the codeset specified by the
|
||||
string pointed to by the fromcode argument to the codeset specified by the string pointed to by
|
||||
the tocode argument.
|
||||
|
||||
Returns: -1 (setting errno) on failure, a conversion descriptor on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv_open.html ]]
|
||||
*/
|
||||
iconv_open :: proc(tocode: cstring, fromcode: cstring) -> iconv_t ---
|
||||
}
|
||||
285
core/sys/posix/langinfo.odin
Normal file
285
core/sys/posix/langinfo.odin
Normal file
@@ -0,0 +1,285 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// langinfo.h - language information constants
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Return a pointer to a string containing information relevant to the particular language or
|
||||
cultural area defined in the current locale.
|
||||
|
||||
Returns: a string that should not be freed or modified, and that can be invalidated at any time later
|
||||
|
||||
Example:
|
||||
for item in posix.nl_item {
|
||||
fmt.printfln("%v: %q", item, posix.nl_langinfo(item))
|
||||
}
|
||||
|
||||
Possible Output:
|
||||
CODESET: "US-ASCII"
|
||||
D_T_FMT: "%a %b %e %H:%M:%S %Y"
|
||||
D_FMT: "%m/%d/%y"
|
||||
T_FMT: "%H:%M:%S"
|
||||
T_FMT_AMPM: "%I:%M:%S %p"
|
||||
AM_STR: "AM"
|
||||
PM_STR: "PM"
|
||||
DAY_1: "Sunday"
|
||||
DAY_2: "Monday"
|
||||
DAY_3: "Tuesday"
|
||||
DAY_4: "Wednesday"
|
||||
DAY_5: "Thursday"
|
||||
DAY_6: "Friday"
|
||||
DAY_7: "Saturday"
|
||||
ABDAY_1: "Sun"
|
||||
ABDAY_2: "Mon"
|
||||
ABDAY_3: "Tue"
|
||||
ABDAY_4: "Wed"
|
||||
ABDAY_5: "Thu"
|
||||
ABDAY_6: "Fri"
|
||||
ABDAY_7: "Sat"
|
||||
MON_1: "January"
|
||||
MON_2: "February"
|
||||
MON_3: "March"
|
||||
MON_4: "April"
|
||||
MON_5: "May"
|
||||
MON_6: "June"
|
||||
MON_7: "July"
|
||||
MON_8: "August"
|
||||
MON_9: "September"
|
||||
MON_10: "October"
|
||||
MON_11: "November"
|
||||
MON_12: "December"
|
||||
ABMON_1: "Jan"
|
||||
ABMON_2: "Feb"
|
||||
ABMON_3: "Mar"
|
||||
ABMON_4: "Apr"
|
||||
ABMON_5: "May"
|
||||
ABMON_6: "Jun"
|
||||
ABMON_7: "Jul"
|
||||
ABMON_8: "Aug"
|
||||
ABMON_9: "Sep"
|
||||
ABMON_10: "Oct"
|
||||
ABMON_11: "Nov"
|
||||
ABMON_12: "Dec"
|
||||
ERA: ""
|
||||
ERA_D_FMT: ""
|
||||
ERA_D_T_FMT: ""
|
||||
ERA_T_FMT: ""
|
||||
ALT_DIGITS: ""
|
||||
RADIXCHAR: "."
|
||||
THOUSEP: ""
|
||||
YESEXPR: "^[yY]"
|
||||
NOEXPR: "^[nN]"
|
||||
CRNCYSTR: ""
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/nl_langinfo.html ]]
|
||||
*/
|
||||
nl_langinfo :: proc(nl_item) -> cstring ---
|
||||
}
|
||||
|
||||
nl_item :: enum nl_item_t {
|
||||
CODESET = CODESET,
|
||||
D_T_FMT = D_T_FMT,
|
||||
D_FMT = D_FMT,
|
||||
T_FMT = T_FMT,
|
||||
T_FMT_AMPM = T_FMT_AMPM,
|
||||
AM_STR = AM_STR,
|
||||
PM_STR = PM_STR,
|
||||
DAY_1 = DAY_1,
|
||||
DAY_2 = DAY_2,
|
||||
DAY_3 = DAY_3,
|
||||
DAY_4 = DAY_4,
|
||||
DAY_5 = DAY_5,
|
||||
DAY_6 = DAY_6,
|
||||
DAY_7 = DAY_7,
|
||||
ABDAY_1 = ABDAY_1,
|
||||
ABDAY_2 = ABDAY_2,
|
||||
ABDAY_3 = ABDAY_3,
|
||||
ABDAY_4 = ABDAY_4,
|
||||
ABDAY_5 = ABDAY_5,
|
||||
ABDAY_6 = ABDAY_6,
|
||||
ABDAY_7 = ABDAY_7,
|
||||
MON_1 = MON_1,
|
||||
MON_2 = MON_2,
|
||||
MON_3 = MON_3,
|
||||
MON_4 = MON_4,
|
||||
MON_5 = MON_5,
|
||||
MON_6 = MON_6,
|
||||
MON_7 = MON_7,
|
||||
MON_8 = MON_8,
|
||||
MON_9 = MON_9,
|
||||
MON_10 = MON_10,
|
||||
MON_11 = MON_11,
|
||||
MON_12 = MON_12,
|
||||
ABMON_1 = ABMON_1,
|
||||
ABMON_2 = ABMON_2,
|
||||
ABMON_3 = ABMON_3,
|
||||
ABMON_4 = ABMON_4,
|
||||
ABMON_5 = ABMON_5,
|
||||
ABMON_6 = ABMON_6,
|
||||
ABMON_7 = ABMON_7,
|
||||
ABMON_8 = ABMON_8,
|
||||
ABMON_9 = ABMON_9,
|
||||
ABMON_10 = ABMON_10,
|
||||
ABMON_11 = ABMON_11,
|
||||
ABMON_12 = ABMON_12,
|
||||
ERA = ERA,
|
||||
ERA_D_FMT = ERA_D_FMT,
|
||||
ERA_D_T_FMT = ERA_D_T_FMT,
|
||||
ERA_T_FMT = ERA_T_FMT,
|
||||
ALT_DIGITS = ALT_DIGITS,
|
||||
RADIXCHAR = RADIXCHAR,
|
||||
THOUSEP = THOUSEP,
|
||||
YESEXPR = YESEXPR,
|
||||
NOEXPR = NOEXPR,
|
||||
CRNCYSTR = CRNCYSTR,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
||||
|
||||
// NOTE: declared with `_t` so we can enumerate the real `nl_info`.
|
||||
nl_item_t :: distinct c.int
|
||||
|
||||
CODESET :: 0
|
||||
D_T_FMT :: 1
|
||||
D_FMT :: 2
|
||||
T_FMT :: 3
|
||||
T_FMT_AMPM :: 4
|
||||
AM_STR :: 5
|
||||
PM_STR :: 6
|
||||
|
||||
DAY_1 :: 7
|
||||
DAY_2 :: 8
|
||||
DAY_3 :: 9
|
||||
DAY_4 :: 10
|
||||
DAY_5 :: 11
|
||||
DAY_6 :: 12
|
||||
DAY_7 :: 13
|
||||
|
||||
ABDAY_1 :: 14
|
||||
ABDAY_2 :: 15
|
||||
ABDAY_3 :: 16
|
||||
ABDAY_4 :: 17
|
||||
ABDAY_5 :: 18
|
||||
ABDAY_6 :: 19
|
||||
ABDAY_7 :: 20
|
||||
|
||||
MON_1 :: 21
|
||||
MON_2 :: 22
|
||||
MON_3 :: 23
|
||||
MON_4 :: 24
|
||||
MON_5 :: 25
|
||||
MON_6 :: 26
|
||||
MON_7 :: 27
|
||||
MON_8 :: 28
|
||||
MON_9 :: 29
|
||||
MON_10 :: 30
|
||||
MON_11 :: 31
|
||||
MON_12 :: 32
|
||||
|
||||
ABMON_1 :: 33
|
||||
ABMON_2 :: 34
|
||||
ABMON_3 :: 35
|
||||
ABMON_4 :: 36
|
||||
ABMON_5 :: 37
|
||||
ABMON_6 :: 38
|
||||
ABMON_7 :: 39
|
||||
ABMON_8 :: 40
|
||||
ABMON_9 :: 41
|
||||
ABMON_10 :: 42
|
||||
ABMON_11 :: 43
|
||||
ABMON_12 :: 44
|
||||
|
||||
ERA :: 45
|
||||
ERA_D_FMT :: 46
|
||||
ERA_D_T_FMT :: 47
|
||||
ERA_T_FMT :: 48
|
||||
ALT_DIGITS :: 49
|
||||
|
||||
RADIXCHAR :: 50
|
||||
THOUSEP :: 51
|
||||
|
||||
YESEXPR :: 52
|
||||
NOEXPR :: 53
|
||||
|
||||
CRNCYSTR :: 56
|
||||
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
// NOTE: declared with `_t` so we can enumerate the real `nl_info`.
|
||||
nl_item_t :: distinct c.int
|
||||
|
||||
CODESET :: 51
|
||||
D_T_FMT :: 0
|
||||
D_FMT :: 1
|
||||
T_FMT :: 2
|
||||
T_FMT_AMPM :: 3
|
||||
AM_STR :: 4
|
||||
PM_STR :: 5
|
||||
|
||||
DAY_1 :: 6
|
||||
DAY_2 :: 7
|
||||
DAY_3 :: 8
|
||||
DAY_4 :: 9
|
||||
DAY_5 :: 10
|
||||
DAY_6 :: 11
|
||||
DAY_7 :: 12
|
||||
|
||||
ABDAY_1 :: 13
|
||||
ABDAY_2 :: 14
|
||||
ABDAY_3 :: 15
|
||||
ABDAY_4 :: 16
|
||||
ABDAY_5 :: 17
|
||||
ABDAY_6 :: 18
|
||||
ABDAY_7 :: 19
|
||||
|
||||
MON_1 :: 20
|
||||
MON_2 :: 21
|
||||
MON_3 :: 22
|
||||
MON_4 :: 23
|
||||
MON_5 :: 24
|
||||
MON_6 :: 25
|
||||
MON_7 :: 26
|
||||
MON_8 :: 27
|
||||
MON_9 :: 28
|
||||
MON_10 :: 29
|
||||
MON_11 :: 30
|
||||
MON_12 :: 31
|
||||
|
||||
ABMON_1 :: 32
|
||||
ABMON_2 :: 33
|
||||
ABMON_3 :: 34
|
||||
ABMON_4 :: 35
|
||||
ABMON_5 :: 36
|
||||
ABMON_6 :: 37
|
||||
ABMON_7 :: 38
|
||||
ABMON_8 :: 39
|
||||
ABMON_9 :: 40
|
||||
ABMON_10 :: 41
|
||||
ABMON_11 :: 42
|
||||
ABMON_12 :: 43
|
||||
|
||||
ERA :: 52
|
||||
ERA_D_FMT :: 53
|
||||
ERA_D_T_FMT :: 54
|
||||
ERA_T_FMT :: 55
|
||||
ALT_DIGITS :: 56
|
||||
|
||||
RADIXCHAR :: 44
|
||||
THOUSEP :: 45
|
||||
|
||||
YESEXPR :: 47
|
||||
NOEXPR :: 49
|
||||
|
||||
CRNCYSTR :: 50
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
74
core/sys/posix/libgen.odin
Normal file
74
core/sys/posix/libgen.odin
Normal file
@@ -0,0 +1,74 @@
|
||||
package posix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// libgen.h - definitions for pattern matching functions
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Takes the pathname pointed to by path and return a pointer to the final component of the
|
||||
pathname, deleting any trailing '/' characters.
|
||||
|
||||
NOTE: may modify input, so don't give it string literals.
|
||||
|
||||
Returns: a string that might be a modification of the input string or a static string overwritten by subsequent calls
|
||||
|
||||
Example:
|
||||
tests := []string{
|
||||
"usr", "usr/", "", "/", "//", "///", "/usr/", "/usr/lib",
|
||||
"//usr//lib//", "/home//dwc//test",
|
||||
}
|
||||
|
||||
tbl: table.Table
|
||||
table.init(&tbl)
|
||||
table.header(&tbl, "input", "dirname", "basename")
|
||||
|
||||
for test in tests {
|
||||
din := strings.clone_to_cstring(test); defer delete(din)
|
||||
dir := strings.clone_from_cstring(posix.dirname(din))
|
||||
|
||||
bin := strings.clone_to_cstring(test); defer delete(bin)
|
||||
base := strings.clone_from_cstring(posix.basename(bin))
|
||||
table.row(&tbl, test, dir, base)
|
||||
}
|
||||
|
||||
table.write_plain_table(os.stream_from_handle(os.stdout), &tbl)
|
||||
|
||||
Output:
|
||||
+----------------+----------+--------+
|
||||
|input |dirname |basename|
|
||||
+----------------+----------+--------+
|
||||
|usr |. |usr |
|
||||
|usr/ |. |usr |
|
||||
| |. |. |
|
||||
|/ |/ |/ |
|
||||
|// |/ |/ |
|
||||
|/// |/ |/ |
|
||||
|/usr/ |/ |usr |
|
||||
|/usr/lib |/usr |lib |
|
||||
|//usr//lib// |//usr |lib |
|
||||
|/home//dwc//test|/home//dwc|test |
|
||||
+----------------+----------+--------+
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/basename.html ]]
|
||||
*/
|
||||
basename :: proc(path: cstring) -> cstring ---
|
||||
|
||||
/*
|
||||
Takes a string that contains a pathname, and returns a string that is a pathname of the parent
|
||||
directory of that file.
|
||||
|
||||
NOTE: may modify input, so don't give it string literals.
|
||||
|
||||
Returns: a string that might be a modification of the input string or a static string overwritten by subsequent calls
|
||||
|
||||
See example for basename().
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirname.html ]]
|
||||
*/
|
||||
dirname :: proc(path: cstring) -> cstring ---
|
||||
}
|
||||
459
core/sys/posix/limits.odin
Normal file
459
core/sys/posix/limits.odin
Normal file
@@ -0,0 +1,459 @@
|
||||
package posix
|
||||
|
||||
// limits.h - implementation-defined constants
|
||||
|
||||
// NOTE: numerical limits are left out because Odin provides `min(T)` and `max(T)`.
|
||||
|
||||
// The <limits.h> header shall define the following symbolic constants with the values shown.
|
||||
// These are the most restrictive values for certain features on an implementation.
|
||||
// A conforming implementation shall provide values no larger than these values.
|
||||
// A conforming application must not require a smaller value for correct operation.
|
||||
|
||||
_POSIX_CLOCKRES_MIN :: 20000000
|
||||
|
||||
// The <limits.h> header shall define the following symbolic constants with the values shown.
|
||||
// These are the most restrictive values for certain features on an implementation conforming to
|
||||
// this volume of POSIX.1-2017.
|
||||
// Related symbolic constants are defined elsewhere in this volume of POSIX.1-2017 which reflect
|
||||
// the actual implementation and which need not be as restrictive. For each of these limits,
|
||||
// a conforming implementation shall provide a value at least this large or shall have no limit.
|
||||
// A strictly conforming application must not require a larger value for correct operation.
|
||||
|
||||
_POSIX_AIO_LISTIO_MAX :: 2
|
||||
_POSIX_AIO_MAX :: 1
|
||||
_POSIX_ARG_MAX :: 4096
|
||||
_POSIX_CHILD_MAX :: 25
|
||||
_POSIX_DELAYTIMER_MAX :: 32
|
||||
_POSIX_HOST_NAME_MAX :: 255
|
||||
_POSIX_LINK_MAX :: 8
|
||||
_POSIX_MAX_CANON :: 255
|
||||
_POSIX_MAX_INPUT :: 255
|
||||
_POSIX_MQ_OPEN_MAX :: 8
|
||||
_POSIX_MQ_PRIO_MAX :: 32
|
||||
_POSIX_NAME_MAX :: 14
|
||||
_POSIX_NGROUPS_MAX :: 8
|
||||
_POSIX_OPEN_MAX :: 20
|
||||
_POSIX_PATH_MAX :: 256
|
||||
_POSIX_PIPE_BUF :: 512
|
||||
_POSIX_RE_DUP_MAX :: 255
|
||||
_POSIX_RTSIG_MAX :: 8
|
||||
_POSIX_SEM_NSEMS_MAX :: 256
|
||||
_POSIX_SEM_VALUE_MAX :: 32767
|
||||
_POSIX_SS_REPL_MAX :: 4
|
||||
_POSIX_STREAM_MAX :: 8
|
||||
_POSIX_SYMLINK_MAX :: 255
|
||||
_POSIX_SYMLOOP_MAX :: 8
|
||||
_POSIX_THREAD_DESTRUCTION_ITERATIONS :: 4
|
||||
_POSIX_THREAD_KEYS_MAX :: 128
|
||||
_POSIX_THREADS_THREADS_MAX :: 64
|
||||
_POSIX_TIMER_MAX :: 32
|
||||
_POSIX_TRAXE_EVENT_NAME_MAX :: 30
|
||||
_POSIX_TRACE_NAME_MAX :: 8
|
||||
_POSIX_TRACE_SYS_MAX :: 8
|
||||
_POSIX_TRACE_USER_EVENT_MAX :: 32
|
||||
_POSIX_TTY_NAME_MAX :: 9
|
||||
_POSIX_TZNAME_MAX :: 6
|
||||
_POSIX2_BC_BASE_MAX :: 99
|
||||
_POSIX2_BC_DIM_MAX :: 2048
|
||||
_POSIX2_BC_SCALE_MAX :: 99
|
||||
_POSIX2_CHARCLASS_NAME_MAX :: 14
|
||||
_POSIX2_COLL_WEIGHTS_MAX :: 2
|
||||
_POSIX2_EXPR_NEST_MAX :: 32
|
||||
_POSIX2_LINE_MAX :: 2048
|
||||
_POSIX2_RE_DUP_MAX :: 255
|
||||
_XOPEN_IOV_MAX :: 16
|
||||
_XOPEN_NAME_MAX :: 255
|
||||
_XOPEN_PATH_MAX :: 1024
|
||||
|
||||
/*
|
||||
NOTE: for full portability, usage should look something like:
|
||||
|
||||
page_size: uint
|
||||
when #defined(posix.PAGESIZE) {
|
||||
page_size = posix.PAGESIZE
|
||||
} else {
|
||||
page_size = posix.sysconf(._PAGESIZE)
|
||||
}
|
||||
*/
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from
|
||||
// <limits.h> on specific implementations where the corresponding value is equal to or greater
|
||||
// than the stated minimum, but is unspecified.
|
||||
//
|
||||
// This indetermination might depend on the amount of available memory space on a specific
|
||||
// instance of a specific implementation. The actual value supported by a specific instance shall
|
||||
// be provided by the sysconf() function.
|
||||
|
||||
// AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX)
|
||||
// AIO_MAX :: sysconf(._AIO_MAX)
|
||||
// AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX)
|
||||
ARG_MAX :: 1024 * 1024
|
||||
// ATEXIT_MAX :: sysconf(._ATEXIT_MAX)
|
||||
CHILD_MAX :: 266
|
||||
// DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX)
|
||||
// HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX)
|
||||
IOV_MAX :: 1024
|
||||
// LOGIN_NAME_MAX :: sysconf(._LOGIN_NAME_MAX)
|
||||
// MQ_OPEN_MAX :: sysconf(._MQ_OPEN_MAX)
|
||||
// MQ_PRIO_MAX :: sysconf(._MQ_PRIO_MAX)
|
||||
PAGESIZE :: PAGE_SIZE
|
||||
PAGE_SIZE :: 1 << 12
|
||||
PTHREAD_DESTRUCTOR_ITERATIONS :: 4
|
||||
PTHREAD_KEYS_MAX :: 512
|
||||
PTHREAD_STACK_MIN :: 16384 when ODIN_ARCH == .arm64 else 8192
|
||||
// RTSIG_MAX :: sysconf(._RTSIG_MAX)
|
||||
// SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX)
|
||||
// SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX)
|
||||
// SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX)
|
||||
// SS_REPL_MAX :: sysconf(._SS_REPL_MAX)
|
||||
// STREAM_MAX :: sysconf(._STREAM_MAX)
|
||||
// SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX)
|
||||
// TIMER_MAX :: sysconf(._TIMER_MAX)
|
||||
// TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX)
|
||||
// TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX)
|
||||
// TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX)
|
||||
// TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX)
|
||||
// TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX)
|
||||
// TZNAME_MAX :: sysconf(._TZNAME_MAX)
|
||||
|
||||
// The values in the following list may be constants within an implementation or may vary from
|
||||
// one pathname to another.
|
||||
// For example, file systems or directories may have different characteristics.
|
||||
//
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from the
|
||||
// <limits.h> header on specific implementations where the corresponding value is equal to or
|
||||
// greater than the stated minimum, but where the value can vary depending on the file to which
|
||||
// it is applied.
|
||||
// The actual value supported for a specific pathname shall be provided by the pathconf() function.
|
||||
|
||||
// FILESIZEBITS :: pathconf(".", ._FILESIZEBITS)
|
||||
LINK_MAX :: 32767
|
||||
MAX_CANON :: 1024
|
||||
MAX_INPUT :: 1024
|
||||
NAME_MAX :: 255
|
||||
PATH_MAX :: 1024
|
||||
PIPE_BUF :: 512
|
||||
// POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN)
|
||||
// POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE)
|
||||
// POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE)
|
||||
// POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE)
|
||||
// POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN)
|
||||
// SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX)
|
||||
|
||||
|
||||
// The magnitude limitations in the following list shall be fixed by specific implementations.
|
||||
// An application should assume that the value of the symbolic constant defined by <limits.h>
|
||||
// in a specific implementation is the minimum that pertains whenever the application is run
|
||||
// under that implementation.
|
||||
// A specific instance of a specific implementation may increase the value relative to that
|
||||
// supplied by <limits.h> for that implementation.
|
||||
// The actual value supported by a specific instance shall be provided by the sysconf() function.
|
||||
|
||||
BC_BASE_MAX :: 99
|
||||
BC_DIM_MAX :: 2048
|
||||
BC_SCALE_MAX :: 99
|
||||
BC_STRING_MAX :: 1000
|
||||
CHARCLASS_NAME_MAX :: 14
|
||||
COLL_WEIGHTS_MAX :: 2
|
||||
EXPR_NEST_MAX :: 2
|
||||
LINE_MAX :: 2048
|
||||
NGROUPS_MAX :: 16
|
||||
RE_DUP_MAX :: 255
|
||||
|
||||
// Other limits.
|
||||
|
||||
NL_ARGMAX :: 9
|
||||
NL_LANGMAX :: 14
|
||||
NL_MSGMAX :: 32767
|
||||
NL_SETMAX :: 255
|
||||
NL_TEXTMAX :: 2048
|
||||
NZERO :: 20
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from
|
||||
// <limits.h> on specific implementations where the corresponding value is equal to or greater
|
||||
// than the stated minimum, but is unspecified.
|
||||
//
|
||||
// This indetermination might depend on the amount of available memory space on a specific
|
||||
// instance of a specific implementation. The actual value supported by a specific instance shall
|
||||
// be provided by the sysconf() function.
|
||||
|
||||
// AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX)
|
||||
// AIO_MAX :: sysconf(._AIO_MAX)
|
||||
// AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX)
|
||||
ARG_MAX :: 2 * 256 * 1024
|
||||
// ATEXIT_MAX :: sysconf(._ATEXIT_MAX)
|
||||
CHILD_MAX :: 40
|
||||
// DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX)
|
||||
// HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX)
|
||||
IOV_MAX :: 1024
|
||||
// LOGIN_NAME_MAX :: sysconf(._LOGIN_NAME_MAX)
|
||||
// MQ_OPEN_MAX :: sysconf(._MQ_OPEN_MAX)
|
||||
MQ_PRIO_MAX :: 64
|
||||
PAGESIZE :: PAGE_SIZE
|
||||
PAGE_SIZE :: 1 << 12
|
||||
PTHREAD_DESTRUCTOR_ITERATIONS :: 4
|
||||
PTHREAD_KEYS_MAX :: 256
|
||||
PTHREAD_STACK_MIN :: MINSIGSTKSZ
|
||||
// RTSIG_MAX :: sysconf(._RTSIG_MAX)
|
||||
// SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX)
|
||||
// SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX)
|
||||
// SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX)
|
||||
// SS_REPL_MAX :: sysconf(._SS_REPL_MAX)
|
||||
// STREAM_MAX :: sysconf(._STREAM_MAX)
|
||||
// SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX)
|
||||
// TIMER_MAX :: sysconf(._TIMER_MAX)
|
||||
// TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX)
|
||||
// TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX)
|
||||
// TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX)
|
||||
// TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX)
|
||||
// TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX)
|
||||
// TZNAME_MAX :: sysconf(._TZNAME_MAX)
|
||||
|
||||
// The values in the following list may be constants within an implementation or may vary from
|
||||
// one pathname to another.
|
||||
// For example, file systems or directories may have different characteristics.
|
||||
//
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from the
|
||||
// <limits.h> header on specific implementations where the corresponding value is equal to or
|
||||
// greater than the stated minimum, but where the value can vary depending on the file to which
|
||||
// it is applied.
|
||||
// The actual value supported for a specific pathname shall be provided by the pathconf() function.
|
||||
|
||||
// FILESIZEBITS :: pathconf(".", ._FILESIZEBITS)
|
||||
// LINK_MAX :: pathconf(foo.txt", ._LINK_MAX)
|
||||
MAX_CANON :: 255
|
||||
MAX_INPUT :: 255
|
||||
NAME_MAX :: 255
|
||||
PATH_MAX :: 1024
|
||||
PIPE_BUF :: 512
|
||||
// POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN)
|
||||
// POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE)
|
||||
// POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE)
|
||||
// POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE)
|
||||
// POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN)
|
||||
// SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX)
|
||||
|
||||
|
||||
// The magnitude limitations in the following list shall be fixed by specific implementations.
|
||||
// An application should assume that the value of the symbolic constant defined by <limits.h>
|
||||
// in a specific implementation is the minimum that pertains whenever the application is run
|
||||
// under that implementation.
|
||||
// A specific instance of a specific implementation may increase the value relative to that
|
||||
// supplied by <limits.h> for that implementation.
|
||||
// The actual value supported by a specific instance shall be provided by the sysconf() function.
|
||||
|
||||
BC_BASE_MAX :: 99
|
||||
BC_DIM_MAX :: 2048
|
||||
BC_SCALE_MAX :: 99
|
||||
BC_STRING_MAX :: 1000
|
||||
CHARCLASS_NAME_MAX :: 14
|
||||
COLL_WEIGHTS_MAX :: 10
|
||||
EXPR_NEST_MAX :: 32
|
||||
LINE_MAX :: 2048
|
||||
NGROUPS_MAX :: 1023
|
||||
RE_DUP_MAX :: 255
|
||||
|
||||
// Other limits.
|
||||
|
||||
NL_ARGMAX :: 4096
|
||||
NL_LANGMAX :: 31
|
||||
NL_MSGMAX :: 32767
|
||||
NL_SETMAX :: 255
|
||||
NL_TEXTMAX :: 2048
|
||||
NZERO :: 0
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from
|
||||
// <limits.h> on specific implementations where the corresponding value is equal to or greater
|
||||
// than the stated minimum, but is unspecified.
|
||||
//
|
||||
// This indetermination might depend on the amount of available memory space on a specific
|
||||
// instance of a specific implementation. The actual value supported by a specific instance shall
|
||||
// be provided by the sysconf() function.
|
||||
|
||||
// AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX)
|
||||
// AIO_MAX :: sysconf(._AIO_MAX)
|
||||
// AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX)
|
||||
ARG_MAX :: 256 * 1024
|
||||
// ATEXIT_MAX :: sysconf(._ATEXIT_MAX)
|
||||
CHILD_MAX :: 160
|
||||
// DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX)
|
||||
// HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX)
|
||||
IOV_MAX :: 1024
|
||||
LOGIN_NAME_MAX :: 17
|
||||
MQ_OPEN_MAX :: 512
|
||||
MQ_PRIO_MAX :: 32
|
||||
PAGESIZE :: PAGE_SIZE
|
||||
PAGE_SIZE :: 1 << 12
|
||||
PTHREAD_DESTRUCTOR_ITERATIONS :: 4
|
||||
PTHREAD_KEYS_MAX :: 256
|
||||
// PTHREAD_STACK_MIN :: sysconf(._THREAD_STACK_MIN)
|
||||
// RTSIG_MAX :: sysconf(._RTSIG_MAX)
|
||||
// SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX)
|
||||
// SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX)
|
||||
// SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX)
|
||||
// SS_REPL_MAX :: sysconf(._SS_REPL_MAX)
|
||||
// STREAM_MAX :: sysconf(._STREAM_MAX)
|
||||
// SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX)
|
||||
// TIMER_MAX :: sysconf(._TIMER_MAX)
|
||||
// TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX)
|
||||
// TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX)
|
||||
// TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX)
|
||||
// TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX)
|
||||
// TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX)
|
||||
// TZNAME_MAX :: sysconf(._TZNAME_MAX)
|
||||
|
||||
// The values in the following list may be constants within an implementation or may vary from
|
||||
// one pathname to another.
|
||||
// For example, file systems or directories may have different characteristics.
|
||||
//
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from the
|
||||
// <limits.h> header on specific implementations where the corresponding value is equal to or
|
||||
// greater than the stated minimum, but where the value can vary depending on the file to which
|
||||
// it is applied.
|
||||
// The actual value supported for a specific pathname shall be provided by the pathconf() function.
|
||||
|
||||
// FILESIZEBITS :: pathconf(".", ._FILESIZEBITS)
|
||||
LINK_MAX :: 32767
|
||||
MAX_CANON :: 255
|
||||
MAX_INPUT :: 255
|
||||
NAME_MAX :: 511
|
||||
PATH_MAX :: 1024
|
||||
PIPE_BUF :: 512
|
||||
// POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN)
|
||||
// POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE)
|
||||
// POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE)
|
||||
// POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE)
|
||||
// POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN)
|
||||
// SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX)
|
||||
|
||||
|
||||
// The magnitude limitations in the following list shall be fixed by specific implementations.
|
||||
// An application should assume that the value of the symbolic constant defined by <limits.h>
|
||||
// in a specific implementation is the minimum that pertains whenever the application is run
|
||||
// under that implementation.
|
||||
// A specific instance of a specific implementation may increase the value relative to that
|
||||
// supplied by <limits.h> for that implementation.
|
||||
// The actual value supported by a specific instance shall be provided by the sysconf() function.
|
||||
|
||||
BC_BASE_MAX :: max(i32)
|
||||
BC_DIM_MAX :: 65535
|
||||
BC_SCALE_MAX :: max(i32)
|
||||
BC_STRING_MAX :: max(i32)
|
||||
CHARCLASS_NAME_MAX :: 14
|
||||
COLL_WEIGHTS_MAX :: 2
|
||||
EXPR_NEST_MAX :: 32
|
||||
LINE_MAX :: 2048
|
||||
NGROUPS_MAX :: 16
|
||||
RE_DUP_MAX :: 255
|
||||
|
||||
// Other limits.
|
||||
|
||||
NL_ARGMAX :: 9
|
||||
NL_LANGMAX :: 14
|
||||
NL_MSGMAX :: 32767
|
||||
NL_SETMAX :: 255
|
||||
NL_TEXTMAX :: 2048
|
||||
NZERO :: 20
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from
|
||||
// <limits.h> on specific implementations where the corresponding value is equal to or greater
|
||||
// than the stated minimum, but is unspecified.
|
||||
//
|
||||
// This indetermination might depend on the amount of available memory space on a specific
|
||||
// instance of a specific implementation. The actual value supported by a specific instance shall
|
||||
// be provided by the sysconf() function.
|
||||
|
||||
// AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX)
|
||||
// AIO_MAX :: sysconf(._AIO_MAX)
|
||||
// AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX)
|
||||
ARG_MAX :: 512 * 1024
|
||||
// ATEXIT_MAX :: sysconf(._ATEXIT_MAX)
|
||||
CHILD_MAX :: 80
|
||||
// DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX)
|
||||
// HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX)
|
||||
IOV_MAX :: 1024
|
||||
LOGIN_NAME_MAX :: 32
|
||||
MQ_OPEN_MAX :: 512
|
||||
MQ_PRIO_MAX :: 32
|
||||
PAGESIZE :: PAGE_SIZE
|
||||
PAGE_SIZE :: 1 << 12
|
||||
PTHREAD_DESTRUCTOR_ITERATIONS :: 4
|
||||
PTHREAD_KEYS_MAX :: 256
|
||||
PTHREAD_STACK_MIN :: 1 << 12
|
||||
// RTSIG_MAX :: sysconf(._RTSIG_MAX)
|
||||
// SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX)
|
||||
SEM_VALUE_MAX :: max(u32)
|
||||
// SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX)
|
||||
// SS_REPL_MAX :: sysconf(._SS_REPL_MAX)
|
||||
// STREAM_MAX :: sysconf(._STREAM_MAX)
|
||||
SYMLOOP_MAX :: 32
|
||||
// TIMER_MAX :: sysconf(._TIMER_MAX)
|
||||
// TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX)
|
||||
// TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX)
|
||||
// TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX)
|
||||
// TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX)
|
||||
// TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX)
|
||||
// TZNAME_MAX :: sysconf(._TZNAME_MAX)
|
||||
|
||||
// The values in the following list may be constants within an implementation or may vary from
|
||||
// one pathname to another.
|
||||
// For example, file systems or directories may have different characteristics.
|
||||
//
|
||||
// A definition of one of the symbolic constants in the following list shall be omitted from the
|
||||
// <limits.h> header on specific implementations where the corresponding value is equal to or
|
||||
// greater than the stated minimum, but where the value can vary depending on the file to which
|
||||
// it is applied.
|
||||
// The actual value supported for a specific pathname shall be provided by the pathconf() function.
|
||||
|
||||
// FILESIZEBITS :: pathconf(".", ._FILESIZEBITS)
|
||||
LINK_MAX :: 32767
|
||||
MAX_CANON :: 255
|
||||
MAX_INPUT :: 255
|
||||
NAME_MAX :: 255
|
||||
PATH_MAX :: 1024
|
||||
PIPE_BUF :: 512
|
||||
// POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN)
|
||||
// POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE)
|
||||
// POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE)
|
||||
// POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE)
|
||||
// POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN)
|
||||
SYMLINK_MAX :: PATH_MAX
|
||||
|
||||
|
||||
// The magnitude limitations in the following list shall be fixed by specific implementations.
|
||||
// An application should assume that the value of the symbolic constant defined by <limits.h>
|
||||
// in a specific implementation is the minimum that pertains whenever the application is run
|
||||
// under that implementation.
|
||||
// A specific instance of a specific implementation may increase the value relative to that
|
||||
// supplied by <limits.h> for that implementation.
|
||||
// The actual value supported by a specific instance shall be provided by the sysconf() function.
|
||||
|
||||
BC_BASE_MAX :: max(i32)
|
||||
BC_DIM_MAX :: 65535
|
||||
BC_SCALE_MAX :: max(i32)
|
||||
BC_STRING_MAX :: max(i32)
|
||||
CHARCLASS_NAME_MAX :: 14
|
||||
COLL_WEIGHTS_MAX :: 2
|
||||
EXPR_NEST_MAX :: 32
|
||||
LINE_MAX :: 2048
|
||||
NGROUPS_MAX :: 16
|
||||
RE_DUP_MAX :: 255
|
||||
|
||||
// Other limits.
|
||||
|
||||
NL_ARGMAX :: 9
|
||||
NL_LANGMAX :: 14
|
||||
NL_MSGMAX :: 32767
|
||||
NL_SETMAX :: 255
|
||||
NL_TEXTMAX :: 255
|
||||
NZERO :: 20
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
93
core/sys/posix/locale.odin
Normal file
93
core/sys/posix/locale.odin
Normal file
@@ -0,0 +1,93 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// locale.h - category macros
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Sets the components of an object with the type lconv with the values appropriate for the
|
||||
formatting of numeric quantities (monetary and otherwise) according to the rules of the current
|
||||
locale.
|
||||
|
||||
Returns: a pointer to the lconv structure, might be invalidated by subsequent calls to localeconv() and setlocale()
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localeconv.html ]]
|
||||
*/
|
||||
localeconv :: proc() -> ^lconv ---
|
||||
|
||||
/*
|
||||
Selects the appropriate piece of the global locale, as specified by the category and locale arguments,
|
||||
and can be used to change or query the entire global locale or portions thereof.
|
||||
|
||||
Returns: the current locale if `locale` is `nil`, the set locale otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html ]]
|
||||
*/
|
||||
@(link_name=LSETLOCALE)
|
||||
setlocale :: proc(category: Locale_Category, locale: cstring) -> cstring ---
|
||||
}
|
||||
|
||||
Locale_Category :: enum c.int {
|
||||
ALL = LC_ALL,
|
||||
COLLATE = LC_COLLATE,
|
||||
CTYPE = LC_CTYPE,
|
||||
MESSAGES = LC_MESSAGES,
|
||||
MONETARY = LC_MONETARY,
|
||||
NUMERIC = LC_NUMERIC,
|
||||
TIME = LC_TIME,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSETLOCALE :: "__setlocale50"
|
||||
} else {
|
||||
@(private) LSETLOCALE :: "setlocale"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
// NOTE: All of these fields are standard ([PSX]).
|
||||
lconv :: struct {
|
||||
decimal_point: cstring,
|
||||
thousand_sep: cstring,
|
||||
grouping: cstring,
|
||||
int_curr_symbol: cstring,
|
||||
currency_symbol: cstring,
|
||||
mon_decimal_points: cstring,
|
||||
mon_thousands_sep: cstring,
|
||||
mon_grouping: cstring,
|
||||
positive_sign: cstring,
|
||||
negative_sign: cstring,
|
||||
int_frac_digits: c.char,
|
||||
frac_digits: c.char,
|
||||
p_cs_precedes: c.char,
|
||||
p_sep_by_space: c.char,
|
||||
n_cs_precedes: c.char,
|
||||
n_sep_by_space: c.char,
|
||||
p_sign_posn: c.char,
|
||||
n_sign_posn: c.char,
|
||||
int_p_cs_precedes: c.char,
|
||||
int_n_cs_precedes: c.char,
|
||||
int_p_sep_by_space: c.char,
|
||||
int_n_sep_by_space: c.char,
|
||||
int_p_sign_posn: c.char,
|
||||
int_n_sign_posn: c.char,
|
||||
}
|
||||
|
||||
LC_ALL :: 0
|
||||
LC_COLLATE :: 1
|
||||
LC_CTYPE :: 2
|
||||
LC_MESSAGES :: 6
|
||||
LC_MONETARY :: 3
|
||||
LC_NUMERIC :: 4
|
||||
LC_TIME :: 5
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
42
core/sys/posix/monetary.odin
Normal file
42
core/sys/posix/monetary.odin
Normal file
@@ -0,0 +1,42 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// monetary.h - monetary types
|
||||
|
||||
foreign lib {
|
||||
|
||||
/*
|
||||
Places characters into the array pointed to by s as controlled by the string format.
|
||||
No more than maxsize bytes are placed into the array.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the number of bytes added to s otherwise
|
||||
|
||||
Example:
|
||||
posix.setlocale(.ALL, "en_US.UTF-8")
|
||||
value := 123456.789
|
||||
buffer: [100]byte
|
||||
size := posix.strfmon(raw_data(buffer[:]), len(buffer), "%n", value)
|
||||
if int(size) == -1 {
|
||||
fmt.panicf("strfmon failure: %s", posix.strerror(posix.errno()))
|
||||
}
|
||||
fmt.println(string(buffer[:size]))
|
||||
|
||||
Output:
|
||||
$123,456.79
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strfmon.html ]]
|
||||
*/
|
||||
strfmon :: proc(
|
||||
s: [^]byte,
|
||||
maxsize: c.size_t,
|
||||
format: cstring,
|
||||
#c_vararg args: ..any,
|
||||
) -> c.size_t ---
|
||||
}
|
||||
60
core/sys/posix/net_if.odin
Normal file
60
core/sys/posix/net_if.odin
Normal file
@@ -0,0 +1,60 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// net/if.h - sockets local interfaces
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Retrieve an array of name indexes. Where the last one has an index of 0 and name of nil.
|
||||
|
||||
Returns: nil (setting errno) on failure, an array that should be freed with if_freenameindex otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_nameindex.html ]]
|
||||
*/
|
||||
if_nameindex :: proc() -> [^]if_nameindex_t ---
|
||||
|
||||
/*
|
||||
Returns the interface index matching the name or zero.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_nametoindex.html ]]
|
||||
*/
|
||||
if_nametoindex :: proc(name: cstring) -> c.uint ---
|
||||
|
||||
/*
|
||||
Returns the name corresponding to the index.
|
||||
|
||||
ifname should be at least IF_NAMESIZE bytes in size.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_indextoname.html ]]
|
||||
*/
|
||||
if_indextoname :: proc(ifindex: c.uint, ifname: [^]byte) -> cstring ---
|
||||
|
||||
/*
|
||||
Frees memory allocated by if_nameindex.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_freenameindex.html ]]
|
||||
*/
|
||||
if_freenameindex :: proc(ptr: ^if_nameindex_t) ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
// NOTE: `_t` suffix added due to name conflict.
|
||||
|
||||
if_nameindex_t :: struct {
|
||||
if_index: c.uint, /* [PSX] 1, 2, ... */
|
||||
if_name: cstring, /* [PSX] null terminated name: "le0", ... */
|
||||
}
|
||||
|
||||
IF_NAMESIZE :: 16
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
443
core/sys/posix/netdb.odin
Normal file
443
core/sys/posix/netdb.odin
Normal file
@@ -0,0 +1,443 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// netdb.h - definitions for network database operations
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Translate node/serv name and return a set of socket addresses and associated information to be
|
||||
used in creating a socket with which to address the specified service.
|
||||
|
||||
Example:
|
||||
// The following (incomplete) program demonstrates the use of getaddrinfo() to obtain the
|
||||
// socket address structure(s) for the service named in the program's command-line argument.
|
||||
// The program then loops through each of the address structures attempting to create and bind
|
||||
// a socket to the address, until it performs a successful bind().
|
||||
|
||||
args := runtime.args__
|
||||
if len(args) != 2 {
|
||||
fmt.eprintfln("Usage: %s port", args[0])
|
||||
posix.exit(1)
|
||||
}
|
||||
|
||||
hints: posix.addrinfo
|
||||
hints.ai_socktype = .DGRAM
|
||||
hints.ai_flags = { .PASSIVE }
|
||||
|
||||
result: ^posix.addrinfo
|
||||
s := posix.getaddrinfo(nil, args[1], &hints, &result)
|
||||
if s != .NONE {
|
||||
fmt.eprintfln("getaddrinfo: %s", posix.gai_strerror(s))
|
||||
posix.exit(1)
|
||||
}
|
||||
defer posix.freeaddrinfo(result)
|
||||
|
||||
// Try each address until a successful bind().
|
||||
rp: ^posix.addrinfo
|
||||
for rp = result; rp != nil; rp = rp.ai_next {
|
||||
sfd := posix.socket(rp.ai_family, rp.ai_socktype, rp.ai_protocol)
|
||||
if sfd == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if posix.bind(sfd, rp.ai_addr, rp.ai_addrlen) == 0 {
|
||||
// Success.
|
||||
break
|
||||
}
|
||||
|
||||
posix.close(sfd)
|
||||
}
|
||||
|
||||
if rp == nil {
|
||||
fmt.eprintln("Could not bind")
|
||||
posix.exit(1)
|
||||
}
|
||||
|
||||
// Use the socket...
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html ]]
|
||||
*/
|
||||
getaddrinfo :: proc(
|
||||
nodename: cstring,
|
||||
servname: cstring,
|
||||
hints: ^addrinfo,
|
||||
res: ^^addrinfo,
|
||||
) -> Info_Errno ---
|
||||
|
||||
/*
|
||||
Frees the given address info linked list.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html ]]
|
||||
*/
|
||||
freeaddrinfo :: proc(ai: ^addrinfo) ---
|
||||
|
||||
/*
|
||||
Translate a socket address to a node name and service location.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html ]]
|
||||
*/
|
||||
getnameinfo :: proc(
|
||||
sa: ^sockaddr, salen: socklen_t,
|
||||
node: [^]byte, nodelen: socklen_t,
|
||||
service: [^]byte, servicelen: socklen_t,
|
||||
flags: Nameinfo_Flags,
|
||||
) -> Info_Errno ---
|
||||
|
||||
/*
|
||||
Get a textual description for the address info errors.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html ]]
|
||||
*/
|
||||
gai_strerror :: proc(ecode: Info_Errno) -> cstring ---
|
||||
|
||||
/*
|
||||
Opens a connection to the database and set the next entry to the first entry in the database.
|
||||
|
||||
This reads /etc/hosts on most systems.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]]
|
||||
*/
|
||||
sethostent :: proc(stayopen: b32) ---
|
||||
|
||||
/*
|
||||
Reads the next entry in the database, opening and closing a connection as necessary.
|
||||
|
||||
This reads /etc/hosts on most systems.
|
||||
|
||||
Example:
|
||||
posix.sethostent(true)
|
||||
defer posix.endhostent()
|
||||
for ent := posix.gethostent(); ent != nil; ent = posix.gethostent() {
|
||||
fmt.println(ent)
|
||||
fmt.println(ent.h_addr_list[0][:ent.h_length])
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]]
|
||||
*/
|
||||
gethostent :: proc() -> ^hostent ---
|
||||
|
||||
/*
|
||||
Closes the connection to the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]]
|
||||
*/
|
||||
endhostent :: proc() ---
|
||||
|
||||
/*
|
||||
Opens and rewinds the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]]
|
||||
*/
|
||||
setnetent :: proc(stayopen: b32) ---
|
||||
|
||||
/*
|
||||
Reads the next entry of the database.
|
||||
|
||||
Example:
|
||||
posix.setnetent(true)
|
||||
defer posix.endnetent()
|
||||
for ent := posix.getnetent(); ent != nil; ent = posix.getnetent() {
|
||||
fmt.println(ent)
|
||||
fmt.println(transmute([4]byte)ent.n_net)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]]
|
||||
*/
|
||||
getnetent :: proc() -> ^netent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]]
|
||||
*/
|
||||
getnetbyaddr :: proc(net: c.uint32_t, type: AF) -> ^netent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]]
|
||||
*/
|
||||
getnetbyname :: proc(name: cstring) -> ^netent ---
|
||||
|
||||
/*
|
||||
Closes the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]]
|
||||
*/
|
||||
endnetent :: proc() ---
|
||||
|
||||
/*
|
||||
Opens and rewinds the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]]
|
||||
*/
|
||||
setprotoent :: proc(stayopen: b32) ---
|
||||
|
||||
/*
|
||||
Reads the next entry of the database.
|
||||
|
||||
Example:
|
||||
posix.setprotoent(true)
|
||||
defer posix.endprotoent()
|
||||
for ent := posix.getprotoent(); ent != nil; ent = posix.getprotoent() {
|
||||
fmt.println(ent)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]]
|
||||
*/
|
||||
getprotoent :: proc() -> ^protoent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]]
|
||||
*/
|
||||
getprotobyname :: proc(name: cstring) -> ^protoent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]]
|
||||
*/
|
||||
getprotobynumber :: proc(proto: c.int) -> ^protoent ---
|
||||
|
||||
/*
|
||||
Closes the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]]
|
||||
*/
|
||||
endprotoent :: proc() ---
|
||||
|
||||
/*
|
||||
Opens and rewinds the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]]
|
||||
*/
|
||||
setservent :: proc(stayopen: b32) ---
|
||||
|
||||
/*
|
||||
Reads the next entry of the database.
|
||||
|
||||
Example:
|
||||
posix.setservent(true)
|
||||
defer posix.endservent()
|
||||
for ent := posix.getservent(); ent != nil; ent = posix.getservent() {
|
||||
fmt.println(ent)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]]
|
||||
*/
|
||||
getservent :: proc() -> ^servent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]]
|
||||
*/
|
||||
getservbyname :: proc(name: cstring, proto: cstring) -> ^servent ---
|
||||
|
||||
/*
|
||||
Search the database from the beginning, and find the first entry that matches.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]]
|
||||
*/
|
||||
getservbyport :: proc(port: c.int, proto: cstring) -> ^servent ---
|
||||
|
||||
/*
|
||||
Closes the database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]]
|
||||
*/
|
||||
endservent :: proc() ---
|
||||
}
|
||||
|
||||
Addrinfo_Flag_Bits :: enum c.int {
|
||||
// Socket address is intended for bind().
|
||||
PASSIVE = log2(AI_PASSIVE),
|
||||
// Request for canonical name.
|
||||
CANONNAME = log2(AI_CANONNAME),
|
||||
// Return numeric host address as name.
|
||||
NUMERICHOST = log2(AI_NUMERICHOST),
|
||||
// Inhibit service name resolution.
|
||||
NUMERICSERV = log2(AI_NUMERICSERV),
|
||||
// If no IPv6 addresses are found, query for IPv4 addresses and return them to the
|
||||
// caller as IPv4-mapped IPv6 addresses.
|
||||
V4MAPPED = log2(AI_V4MAPPED),
|
||||
// Query for both IPv4 and IPv6 addresses.
|
||||
ALL = log2(AI_ALL),
|
||||
// Query for IPv4 addresses only when an IPv4 address is configured; query for IPv6 addresses
|
||||
// only when an IPv6 address is configured.
|
||||
ADDRCONFIG = log2(AI_ADDRCONFIG),
|
||||
}
|
||||
Addrinfo_Flags :: bit_set[Addrinfo_Flag_Bits; c.int]
|
||||
|
||||
Nameinfo_Flag_Bits :: enum c.int {
|
||||
// Only the nodename portion of the FQDN is returned for local hosts.
|
||||
NOFQDN = log2(NI_NOFQDN),
|
||||
// The numeric form of the node's address is returned instead of its name.
|
||||
NUMERICHOST = log2(NI_NUMERICHOST),
|
||||
// Return an error if the node's name cannot be located in the database.
|
||||
NAMEREQD = log2(NI_NAMEREQD),
|
||||
// The numeric form of the service address is returned instead of its name.
|
||||
NUMERICSERV = log2(NI_NUMERICSERV),
|
||||
// For IPv6 addresses, the numeric form of the scope identifier is returned instead of its name.
|
||||
NUMERICSCOPE = log2(NI_NUMERICSCOPE),
|
||||
// Indicates that the service is a datagram service (SOCK_DGRAM).
|
||||
DGRAM = log2(NI_DGRAM),
|
||||
}
|
||||
Nameinfo_Flags :: bit_set[Nameinfo_Flag_Bits; c.int]
|
||||
|
||||
Info_Errno :: enum c.int {
|
||||
NONE = 0,
|
||||
// The name could not be resolved at this time. Future attempts may succeed.
|
||||
AGAIN = EAI_AGAIN,
|
||||
// The flags had an invalid value.
|
||||
BADFLAGS = EAI_BADFLAGS,
|
||||
// A non-recoverable error ocurred.
|
||||
FAIL = EAI_FAIL,
|
||||
// The address family was not recognized or the address length was invald for the specified family.
|
||||
FAMILY = EAI_FAMILY,
|
||||
// There was a memory allocation failure.
|
||||
MEMORY = EAI_MEMORY,
|
||||
// The name does not resolve for the supplied parameters.
|
||||
NONAME = EAI_NONAME,
|
||||
// The service passed was not recognized for the specified socket.
|
||||
SERVICE = EAI_SERVICE,
|
||||
// The intended socket type was not recognized.
|
||||
SOCKTYPE = EAI_SOCKTYPE,
|
||||
// A system error occurred. The error code can be found in errno.
|
||||
SYSTEM = EAI_SYSTEM,
|
||||
// An argument buffer overflowed.
|
||||
OVERFLOW = EAI_OVERFLOW,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
hostent :: struct {
|
||||
h_name: cstring, /* [PSX] official name of host */
|
||||
h_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */
|
||||
h_addrtype: AF, /* [PSX] host address type */
|
||||
h_length: c.int, /* [PSX] length of address */
|
||||
h_addr_list: [^][^]byte `fmt:"v,0"`, /* [PSX] list of addresses from name server */
|
||||
}
|
||||
|
||||
netent :: struct {
|
||||
n_name: cstring, /* [PSX] official name of net */
|
||||
n_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */
|
||||
n_addrtype: AF, /* [PSX] net address type */
|
||||
n_net: c.uint32_t, /* [PSX] network # */
|
||||
}
|
||||
|
||||
protoent :: struct {
|
||||
p_name: cstring, /* [PSX] official protocol name */
|
||||
p_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */
|
||||
p_proto: c.int, /* [PSX] protocol # */
|
||||
}
|
||||
|
||||
servent :: struct {
|
||||
s_name: cstring, /* [PSX] official service name */
|
||||
s_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */
|
||||
s_port: c.int, /* [PSX] port # */
|
||||
s_proto: cstring, /* [PSX] protocol # */
|
||||
}
|
||||
|
||||
// The highest reserved port number.
|
||||
IPPORT_RESERVED :: 1024
|
||||
|
||||
addrinfo :: struct {
|
||||
ai_flags: Addrinfo_Flags, /* [PSX] input flags */
|
||||
ai_family: AF, /* [PSX] address family of socket */
|
||||
ai_socktype: Sock, /* [PSX] socket type */
|
||||
ai_protocol: Protocol, /* [PSX] protocol of socket */
|
||||
ai_addrlen: socklen_t, /* [PSX] length of socket address */
|
||||
ai_canonname: cstring, /* [PSX] canonical name of service location */
|
||||
ai_addr: ^sockaddr, /* [PSX] binary address */
|
||||
ai_next: ^addrinfo, /* [PSX] pointer to next in list */
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
AI_PASSIVE :: 0x00000001
|
||||
AI_CANONNAME :: 0x00000002
|
||||
AI_NUMERICHOST :: 0x00000004
|
||||
AI_NUMERICSERV :: 0x00001000
|
||||
AI_V4MAPPED :: 0x00000800
|
||||
AI_ALL :: 0x00000100
|
||||
AI_ADDRCONFIG :: 0x00000400
|
||||
|
||||
NI_NOFQDN :: 0x00000001
|
||||
NI_NUMERICHOST :: 0x00000002
|
||||
NI_NAMEREQD :: 0x00000004
|
||||
NI_NUMERICSERV :: 0x00000008
|
||||
NI_NUMERICSCOPE :: 0x00000100
|
||||
NI_DGRAM :: 0x00000010
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
|
||||
|
||||
AI_PASSIVE :: 0x00000001
|
||||
AI_CANONNAME :: 0x00000002
|
||||
AI_NUMERICHOST :: 0x00000004
|
||||
AI_NUMERICSERV :: 0x00000008
|
||||
AI_V4MAPPED :: 0x00000800 // NOTE: not implemented on netbsd
|
||||
AI_ALL :: 0x00000100 // NOTE: not implemented on netbsd
|
||||
AI_ADDRCONFIG :: 0x00000400
|
||||
|
||||
NI_NOFQDN :: 0x00000001
|
||||
NI_NUMERICHOST :: 0x00000002
|
||||
NI_NAMEREQD :: 0x00000004
|
||||
NI_NUMERICSERV :: 0x00000008
|
||||
NI_NUMERICSCOPE :: 0x00000010
|
||||
NI_DGRAM :: 0x00000020
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
AI_PASSIVE :: 1
|
||||
AI_CANONNAME :: 2
|
||||
AI_NUMERICHOST :: 4
|
||||
AI_NUMERICSERV :: 16
|
||||
AI_V4MAPPED :: 0x00000800 // NOTE: not implemented
|
||||
AI_ALL :: 0x00000100 // NOTE: not implemented
|
||||
AI_ADDRCONFIG :: 64
|
||||
|
||||
NI_NOFQDN :: 4
|
||||
NI_NUMERICHOST :: 1
|
||||
NI_NAMEREQD :: 8
|
||||
NI_NUMERICSERV :: 2
|
||||
NI_NUMERICSCOPE :: 32
|
||||
NI_DGRAM :: 16
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
EAI_AGAIN :: -3
|
||||
EAI_BADFLAGS :: -1
|
||||
EAI_FAIL :: -4
|
||||
EAI_FAMILY :: -6
|
||||
EAI_MEMORY :: -10
|
||||
EAI_NONAME :: -2
|
||||
EAI_SERVICE :: -8
|
||||
EAI_SOCKTYPE :: -7
|
||||
EAI_SYSTEM :: -11
|
||||
EAI_OVERFLOW :: -14
|
||||
} else {
|
||||
EAI_AGAIN :: 2
|
||||
EAI_BADFLAGS :: 3
|
||||
EAI_FAIL :: 4
|
||||
EAI_FAMILY :: 5
|
||||
EAI_MEMORY :: 6
|
||||
EAI_NONAME :: 8
|
||||
EAI_SERVICE :: 9
|
||||
EAI_SOCKTYPE :: 10
|
||||
EAI_SYSTEM :: 11
|
||||
EAI_OVERFLOW :: 14
|
||||
}
|
||||
|
||||
}else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
199
core/sys/posix/netinet_in.odin
Normal file
199
core/sys/posix/netinet_in.odin
Normal file
@@ -0,0 +1,199 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// netinet/in.h - Internet address family
|
||||
|
||||
foreign lib {
|
||||
in6addr_any: in6_addr
|
||||
in6addr_loopback: in6_addr
|
||||
}
|
||||
|
||||
in_port_t :: u16be
|
||||
in_addr_t :: u32be
|
||||
|
||||
INET_ADDRSTRLEN :: 16
|
||||
INET6_ADDRSTRLEN :: 46
|
||||
|
||||
Protocol :: enum c.int {
|
||||
IP = IPPROTO_IP,
|
||||
ICMP = IPPROTO_ICMP,
|
||||
IPV6 = IPPROTO_IPV6,
|
||||
RAW = IPPROTO_RAW,
|
||||
TCP = IPPROTO_TCP,
|
||||
UDP = IPPROTO_UDP,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
in_addr :: struct {
|
||||
s_addr: in_addr_t, /* [PSX] big endian address */
|
||||
}
|
||||
|
||||
in6_addr :: struct {
|
||||
using _: struct #raw_union {
|
||||
s6_addr: [16]c.uint8_t, /* [PSX] big endian address */
|
||||
__u6_addr16: [8]c.uint16_t,
|
||||
__u6_addr32: [4]c.uint32_t,
|
||||
},
|
||||
}
|
||||
|
||||
sockaddr_in :: struct {
|
||||
sin_len: c.uint8_t,
|
||||
sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */
|
||||
sin_port: in_port_t, /* [PSX] port number */
|
||||
sin_addr: in_addr, /* [PSX] IP address */
|
||||
sin_zero: [8]c.char,
|
||||
}
|
||||
|
||||
sockaddr_in6 :: struct {
|
||||
sin6_len: c.uint8_t,
|
||||
sin6_family: sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */
|
||||
sin6_port: in_port_t, /* [PSX] port number */
|
||||
sin6_flowinfo: c.uint32_t, /* [PSX] IPv6 traffic class and flow information */
|
||||
sin6_addr: in6_addr, /* [PSX] IPv6 address */
|
||||
sin6_scope_id: c.uint32_t, /* [PSX] set of interfaces for a scope */
|
||||
}
|
||||
|
||||
ipv6_mreq :: struct {
|
||||
ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */
|
||||
ipv6mr_interface: c.uint, /* [PSX] interface index */
|
||||
}
|
||||
|
||||
IPPROTO_IP :: 0
|
||||
IPPROTO_ICMP :: 1
|
||||
IPPROTO_IPV6 :: 41
|
||||
IPPROTO_RAW :: 255
|
||||
IPPROTO_TCP :: 6
|
||||
IPPROTO_UDP :: 17
|
||||
|
||||
INADDR_ANY :: 0x00000000
|
||||
INADDR_BROADCAST :: 0xFFFFFFFF
|
||||
|
||||
IPV6_JOIN_GROUP :: 12
|
||||
IPV6_LEAVE_GROUP :: 13
|
||||
IPV6_MULTICAST_HOPS :: 10
|
||||
IPV6_MULTICAST_IF :: 9
|
||||
IPV6_MULTICAST_LOOP :: 11
|
||||
IPV6_UNICAST_HOPS :: 4
|
||||
IPV6_V6ONLY :: 27
|
||||
|
||||
IN6_IS_ADDR_UNSPECIFIED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return a.s6_addr == 0
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_LOOPBACK :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
a := a
|
||||
return (
|
||||
(^c.uint32_t)(&a.s6_addr[0])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[4])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[8])^ == 0 &&
|
||||
(^u32be)(&a.s6_addr[12])^ == 1 \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MULTICAST :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return a.s6_addr[0] == 0xff
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0x80
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0xc0
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_V4MAPPED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
a := a
|
||||
return (
|
||||
(^c.uint32_t)(&a.s6_addr[0])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[4])^ == 0 &&
|
||||
(^u32be)(&a.s6_addr[8])^ == 0x0000ffff \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_V4COMPAT :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
a := a
|
||||
return (
|
||||
(^c.uint32_t)(&a.s6_addr[0])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[4])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[8])^ == 0 &&
|
||||
(^c.uint32_t)(&a.s6_addr[12])^ != 0 &&
|
||||
(^u32be)(&a.s6_addr[12])^ != 1 \
|
||||
)
|
||||
}
|
||||
|
||||
@(private)
|
||||
__IPV6_ADDR_SCOPE_NODELOCAL :: 0x01
|
||||
@(private)
|
||||
__IPV6_ADDR_SCOPE_LINKLOCAL :: 0x02
|
||||
@(private)
|
||||
__IPV6_ADDR_SCOPE_SITELOCAL :: 0x05
|
||||
@(private)
|
||||
__IPV6_ADDR_SCOPE_ORGLOCAL :: 0x08
|
||||
@(private)
|
||||
__IPV6_ADDR_SCOPE_GLOBAL :: 0x0e
|
||||
|
||||
@(private)
|
||||
IPV6_ADDR_MC_FLAGS :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t {
|
||||
return a.s6_addr[1] & 0xf0
|
||||
}
|
||||
|
||||
@(private)
|
||||
IPV6_ADDR_MC_FLAGS_TRANSIENT :: 0x10
|
||||
@(private)
|
||||
IPV6_ADDR_MC_FLAGS_PREFIX :: 0x20
|
||||
@(private)
|
||||
IPV6_ADDR_MC_FLAGS_UNICAST_BASED :: IPV6_ADDR_MC_FLAGS_TRANSIENT | IPV6_ADDR_MC_FLAGS_PREFIX
|
||||
|
||||
@(private)
|
||||
__IPV6_ADDR_MC_SCOPE :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t {
|
||||
return a.s6_addr[1] & 0x0f
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MC_NODELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return (
|
||||
IN6_IS_ADDR_MULTICAST(a) &&
|
||||
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL) \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MC_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return (
|
||||
IN6_IS_ADDR_MULTICAST(a) &&
|
||||
(IPV6_ADDR_MC_FLAGS(a) != IPV6_ADDR_MC_FLAGS_UNICAST_BASED) &&
|
||||
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL) \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MC_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return (
|
||||
IN6_IS_ADDR_MULTICAST(a) &&
|
||||
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL) \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MC_ORGLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return (
|
||||
IN6_IS_ADDR_MULTICAST(a) &&
|
||||
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL) \
|
||||
)
|
||||
}
|
||||
|
||||
IN6_IS_ADDR_MC_GLOBAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
|
||||
return (
|
||||
IN6_IS_ADDR_MULTICAST(a) &&
|
||||
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL) \
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
11
core/sys/posix/netinet_tcp.odin
Normal file
11
core/sys/posix/netinet_tcp.odin
Normal file
@@ -0,0 +1,11 @@
|
||||
package posix
|
||||
|
||||
// netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
TCP_NODELAY :: 0x01
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
78
core/sys/posix/poll.odin
Normal file
78
core/sys/posix/poll.odin
Normal file
@@ -0,0 +1,78 @@
|
||||
package posix
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// poll.h - definitions for the poll() function
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
For each pointer in fds, poll() shall examine the given descriptor for the events.
|
||||
poll will identify on which descriptors writes or reads can be done.
|
||||
|
||||
Returns: -1 (setting errno) on failure, 0 on timeout, the amount of fds that have been changed on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html ]]
|
||||
*/
|
||||
poll :: proc(fds: [^]pollfd, nfds: nfds_t, timeout: c.int) -> c.int ---
|
||||
}
|
||||
|
||||
nfds_t :: c.uint
|
||||
|
||||
Poll_Event_Bits :: enum c.short {
|
||||
// Data other than high-priority data may be read without blocking.
|
||||
IN = log2(POLLIN),
|
||||
// Normal data may be read without blocking.
|
||||
RDNORM = log2(POLLRDNORM),
|
||||
// Priority data may be read without blocking.
|
||||
RDBAND = log2(POLLRDBAND),
|
||||
// High priority data may be read without blocking.
|
||||
PRI = log2(POLLPRI),
|
||||
|
||||
// Normal data may be written without blocking.
|
||||
OUT = log2(POLLOUT),
|
||||
// Equivalent to POLLOUT.
|
||||
WRNORM = log2(POLLWRNORM),
|
||||
// Priority data may be written.
|
||||
WRBAND = log2(POLLWRBAND),
|
||||
|
||||
// An error has occurred (revents only).
|
||||
ERR = log2(POLLERR),
|
||||
// Device hsa been disconnected (revents only).
|
||||
HUP = log2(POLLHUP),
|
||||
// Invalid fd member (revents only).
|
||||
NVAL = log2(POLLNVAL),
|
||||
}
|
||||
Poll_Event :: bit_set[Poll_Event_Bits; c.short]
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
pollfd :: struct {
|
||||
fd: FD, /* [PSX] the following descriptor being polled */
|
||||
events: Poll_Event, /* [PSX] the input event flags */
|
||||
revents: Poll_Event, /* [PSX] the output event flags */
|
||||
}
|
||||
|
||||
POLLIN :: 0x0001
|
||||
POLLRDNORM :: 0x0040
|
||||
POLLRDBAND :: 0x0080
|
||||
POLLPRI :: 0x0002
|
||||
POLLOUT :: 0x0004
|
||||
POLLWRNORM :: POLLOUT
|
||||
POLLWRBAND :: 0x0100
|
||||
|
||||
POLLERR :: 0x0008
|
||||
POLLHUP :: 0x0010
|
||||
POLLNVAL :: 0x0020
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
|
||||
26
core/sys/posix/posix.odin
Normal file
26
core/sys/posix/posix.odin
Normal file
@@ -0,0 +1,26 @@
|
||||
package posix
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
import "core:c"
|
||||
|
||||
result :: enum c.int {
|
||||
// Use `errno` and `strerror` for more information.
|
||||
FAIL = -1,
|
||||
// Operation succeeded.
|
||||
OK = 0,
|
||||
}
|
||||
|
||||
FD :: distinct c.int
|
||||
|
||||
@(private)
|
||||
log2 :: intrinsics.constant_log2
|
||||
|
||||
when ODIN_OS == .Darwin && ODIN_ARCH == .amd64 {
|
||||
@(private)
|
||||
INODE_SUFFIX :: "$INODE64"
|
||||
} else {
|
||||
@(private)
|
||||
INODE_SUFFIX :: ""
|
||||
}
|
||||
|
||||
518
core/sys/posix/pthread.odin
Normal file
518
core/sys/posix/pthread.odin
Normal file
@@ -0,0 +1,518 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
|
||||
foreign import lib "system:pthread"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// pthread.h - threads
|
||||
|
||||
// NOTE: mutexes, rwlock, condition variables, once and barriers are left out in favour of `core:sync`.
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Initializes a thread attributes object.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html ]]
|
||||
*/
|
||||
pthread_attr_init :: proc(attr: ^pthread_attr_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Destroys a thread attributes object.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html ]]
|
||||
*/
|
||||
pthread_attr_destroy :: proc(attr: ^pthread_attr_t) -> Errno ---
|
||||
|
||||
/*
|
||||
The detachstate attribute controls whether the thread is created in a detached state.
|
||||
If the thread is created detached, then use of the ID of the newly created thread is an error.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html ]]
|
||||
*/
|
||||
pthread_attr_getdetachstate :: proc(attr: ^pthread_attr_t, detachstate: ^Detach_State) -> Errno ---
|
||||
|
||||
/*
|
||||
The detachstate attribute controls whether the thread is created in a detached state.
|
||||
If the thread is created detached, then use of the ID of the newly created thread is an error.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html ]]
|
||||
*/
|
||||
pthread_attr_setdetachstate :: proc(attr: ^pthread_attr_t, detachstate: Detach_State) -> Errno ---
|
||||
|
||||
/*
|
||||
The guardsize attribute controls the size of the guard area for the created thread's stack.
|
||||
The guardsize attribute provides protection against overflow of the stack pointer.
|
||||
If a thread's stack is created with guard protection, the implementation allocates extra memory
|
||||
at the overflow end of the stack as a buffer against stack overflow of the stack pointer.
|
||||
If an application overflows into this buffer an error shall result (possibly in a SIGSEGV signal being delivered to the thread).
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setguardsize.html ]]
|
||||
*/
|
||||
pthread_attr_getguardsize :: proc(attr: ^pthread_attr_t, guardsize: ^c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
The guardsize attribute controls the size of the guard area for the created thread's stack.
|
||||
The guardsize attribute provides protection against overflow of the stack pointer.
|
||||
If a thread's stack is created with guard protection, the implementation allocates extra memory
|
||||
at the overflow end of the stack as a buffer against stack overflow of the stack pointer.
|
||||
If an application overflows into this buffer an error shall result (possibly in a SIGSEGV signal being delivered to the thread).
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setguardsize.html ]]
|
||||
*/
|
||||
pthread_attr_setguardsize :: proc(attr: ^pthread_attr_t, guardsize: c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
When the attributes objects are used by pthread_create(), the inheritsched attribute determines
|
||||
how the other scheduling attributes of the created thread shall be set.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setinheritsched.html ]]
|
||||
*/
|
||||
pthread_attr_getinheritsched :: proc(attr: ^pthread_attr_t, inheritsched: ^Inherit_Sched) -> Errno ---
|
||||
|
||||
/*
|
||||
When the attributes objects are used by pthread_create(), the inheritsched attribute determines
|
||||
how the other scheduling attributes of the created thread shall be set.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setinheritsched.html ]]
|
||||
*/
|
||||
pthread_attr_setinheritsched :: proc(attr: ^pthread_attr_t, inheritsched: Inherit_Sched) -> Errno ---
|
||||
|
||||
/*
|
||||
Gets the scheduling param.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html ]]
|
||||
*/
|
||||
pthread_attr_getschedparam :: proc(attr: ^pthread_attr_t, param: ^sched_param) -> Errno ---
|
||||
|
||||
/*
|
||||
Sets the scheduling param.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html ]]
|
||||
*/
|
||||
pthread_attr_setschedparam :: proc(attr: ^pthread_attr_t, param: ^sched_param) -> Errno ---
|
||||
|
||||
/*
|
||||
Gets the scheduling poicy.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedpolicy.html ]]
|
||||
*/
|
||||
pthread_attr_getschedpolicy :: proc(attr: ^pthread_attr_t, policy: ^Sched_Policy) -> Errno ---
|
||||
|
||||
/*
|
||||
Sets the scheduling poicy.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedpolicy.html ]]
|
||||
*/
|
||||
pthread_attr_setschedpolicy :: proc(attr: ^pthread_attr_t, policy: Sched_Policy) -> Errno ---
|
||||
|
||||
/*
|
||||
Gets the contention scope.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]]
|
||||
*/
|
||||
pthread_attr_getscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno ---
|
||||
|
||||
/*
|
||||
Sets the contention scope.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]]
|
||||
*/
|
||||
pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno ---
|
||||
|
||||
/*
|
||||
Get the area of storage to be used for the created thread's stack.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstack.html ]]
|
||||
*/
|
||||
pthread_attr_getstack :: proc(attr: ^pthread_attr_t, stackaddr: ^[^]byte, stacksize: ^c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Specify the area of storage to be used for the created thread's stack.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstack.html ]]
|
||||
*/
|
||||
pthread_attr_setstack :: proc(attr: ^pthread_attr_t, stackaddr: [^]byte, stacksize: c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Gets the stack size.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html ]]
|
||||
*/
|
||||
pthread_attr_getstacksize :: proc(attr: ^pthread_attr_t, stacksize: ^c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Sets the stack size.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html ]]
|
||||
*/
|
||||
pthread_attr_setstacksize :: proc(attr: ^pthread_attr_t, stacksize: c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Register fork handlers to be called before and after fork().
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html ]]
|
||||
*/
|
||||
pthread_atfork :: proc(prepare: proc "c" (), parent: proc "c" (), child: proc "c" ()) -> Errno ---
|
||||
|
||||
|
||||
/*
|
||||
Cancel the execution of a thread.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cancel.html ]]
|
||||
*/
|
||||
pthread_cancel :: proc(thread: pthread_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Creates a new thread with the given attributes.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html ]]
|
||||
*/
|
||||
pthread_create :: proc(
|
||||
thread: ^pthread_t,
|
||||
attr: ^pthread_attr_t,
|
||||
start_routine: proc "c" (arg: rawptr) -> rawptr,
|
||||
arg: rawptr,
|
||||
) -> Errno ---
|
||||
|
||||
|
||||
/*
|
||||
Indicate that storage for the thread can be reclaimed when the thread terminates.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_detach.html ]]
|
||||
*/
|
||||
pthread_detach :: proc(thread: pthread_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Compare thread IDs.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_equal.html ]]
|
||||
*/
|
||||
pthread_equal :: proc(t1: pthread_t, t2: pthread_t) -> b32 ---
|
||||
|
||||
/*
|
||||
Terminates the calling thread and make the given value available to any successfull join calls.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html ]]
|
||||
*/
|
||||
pthread_exit :: proc(value_ptr: rawptr) -> ! ---
|
||||
|
||||
/*
|
||||
Gets the current concurrency hint.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getconcurrency.html ]]
|
||||
*/
|
||||
pthread_getconcurrency :: proc() -> c.int ---
|
||||
|
||||
/*
|
||||
Sets the current desired concurrency hint.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getconcurrency.html ]]
|
||||
*/
|
||||
pthread_setconcurrency :: proc(new_level: c.int) -> Errno ---
|
||||
|
||||
/*
|
||||
Access a thread CPU-time clock.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getcpuclockid.html ]]
|
||||
*/
|
||||
pthread_getcpuclockid :: proc(thread_id: pthread_t, clock_id: ^clockid_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Gets the scheduling policy and parameters.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html ]]
|
||||
*/
|
||||
pthread_getschedparam :: proc(thread: pthread_t, policy: ^Sched_Policy, param: ^sched_param) -> Errno ---
|
||||
|
||||
/*
|
||||
Sets the scheduling policy and parameters.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html ]]
|
||||
*/
|
||||
pthread_setschedparam :: proc(thread: pthread_t, policy: Sched_Policy, param: ^sched_param) -> Errno ---
|
||||
|
||||
/*
|
||||
Creates a thread-specific data key visible to all threads in the process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_create.html ]]
|
||||
*/
|
||||
pthread_key_create :: proc(key: ^pthread_key_t, destructor: proc "c" (value: rawptr) = nil) -> Errno ---
|
||||
|
||||
/*
|
||||
Deletes a thread-specific data key visible to all threads in the process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_delete.html ]]
|
||||
*/
|
||||
pthread_key_delete :: proc(key: pthread_key_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Returns the value currently bound to the specified key on behalf of the calling thread.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getspecific.html ]]
|
||||
*/
|
||||
pthread_getspecific :: proc(key: pthread_key_t) -> rawptr ---
|
||||
|
||||
/*
|
||||
Sets the value currently bound to the specified key on behalf of the calling thread.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getspecific.html ]]
|
||||
*/
|
||||
pthread_setspecific :: proc(key: pthread_key_t, value: rawptr) -> Errno ---
|
||||
|
||||
/*
|
||||
Suspends execution of the calling thread until the target thread terminates.
|
||||
|
||||
Example:
|
||||
ar: [10_000]i32
|
||||
|
||||
sb1 := ar[:5_000]
|
||||
sb2 := ar[5_000:]
|
||||
|
||||
th1, th2: posix.pthread_t
|
||||
|
||||
posix.pthread_create(&th1, nil, incer, &sb1)
|
||||
posix.pthread_create(&th2, nil, incer, &sb2)
|
||||
|
||||
posix.pthread_join(th1)
|
||||
posix.pthread_join(th2)
|
||||
|
||||
incer :: proc "c" (arg: rawptr) -> rawptr {
|
||||
sb := (^[]i32)(arg)
|
||||
for &val in sb {
|
||||
val += 1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html ]]
|
||||
*/
|
||||
pthread_join :: proc(thread: pthread_t, value_ptr: ^rawptr = nil) -> Errno ---
|
||||
|
||||
/*
|
||||
Get the calling thread ID.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html ]]
|
||||
*/
|
||||
pthread_self :: proc() -> pthread_t ---
|
||||
|
||||
/*
|
||||
Atomically set the calling thread's cancelability and return the previous value.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html ]]
|
||||
*/
|
||||
pthread_setcancelstate :: proc(state: Cancel_State, oldstate: ^Cancel_State) -> Errno ---
|
||||
|
||||
/*
|
||||
Atomically set the calling thread's cancel type and return the previous value.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html ]]
|
||||
*/
|
||||
pthread_setcanceltype :: proc(type: Cancel_Type, oldtype: ^Cancel_Type) -> Errno ---
|
||||
|
||||
|
||||
/*
|
||||
Creates a cancellation point in the calling thread.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_testcancel.html ]]
|
||||
*/
|
||||
pthread_testcancel :: proc() ---
|
||||
|
||||
/*
|
||||
Sets the scheduling priority for the thread given.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setschedprio.html ]]
|
||||
*/
|
||||
pthread_setschedprio :: proc(thread: pthread_t, prio: c.int) -> Errno ---
|
||||
}
|
||||
|
||||
Detach_State :: enum c.int {
|
||||
// Causes all threads to be in the joinable state.
|
||||
CREATE_JOINABLE = PTHREAD_CREATE_JOINABLE,
|
||||
// Causes all threads to be in the detached state.
|
||||
CREATE_DETACHED = PTHREAD_CREATE_DETACHED,
|
||||
}
|
||||
|
||||
Inherit_Sched :: enum c.int {
|
||||
// Threads inherit from the creating thread.
|
||||
INHERIT_SCHED = PTHREAD_INHERIT_SCHED,
|
||||
// Threads scheduling shall be set to the corresponding values from the attributes object.
|
||||
EXPLICIT_SCHED = PTHREAD_EXPLICIT_SCHED,
|
||||
}
|
||||
|
||||
Thread_Scope :: enum c.int {
|
||||
// System scheduling contention scope.
|
||||
SYSTEM = PTHREAD_SCOPE_SYSTEM,
|
||||
// Process scheduling contention scope.
|
||||
PROCESS = PTHREAD_SCOPE_PROCESS,
|
||||
}
|
||||
|
||||
Cancel_State :: enum c.int {
|
||||
ENABLE = PTHREAD_CANCEL_ENABLE,
|
||||
DISABLE = PTHREAD_CANCEL_DISABLE,
|
||||
}
|
||||
|
||||
Cancel_Type :: enum c.int {
|
||||
DEFERRED = PTHREAD_CANCEL_DEFERRED,
|
||||
ASYNCHRONOUS = PTHREAD_CANCEL_ASYNCHRONOUS,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
PTHREAD_CANCEL_ASYNCHRONOUS :: 0x00
|
||||
PTHREAD_CANCEL_DEFERRED :: 0x02
|
||||
|
||||
PTHREAD_CANCEL_DISABLE :: 0x00
|
||||
PTHREAD_CANCEL_ENABLE :: 0x01
|
||||
|
||||
PTHREAD_CANCELED :: rawptr(uintptr(1))
|
||||
|
||||
PTHREAD_CREATE_DETACHED :: 2
|
||||
PTHREAD_CREATE_JOINABLE :: 1
|
||||
|
||||
PTHREAD_EXPLICIT_SCHED :: 2
|
||||
PTHREAD_INHERIT_SCHED :: 1
|
||||
|
||||
PTHREAD_PRIO_INHERIT :: 1
|
||||
PTHREAD_PRIO_NONE :: 0
|
||||
PTHREAD_PRIO_PROTECT :: 2
|
||||
|
||||
PTHREAD_PROCESS_SHARED :: 1
|
||||
PTHREAD_PROCESS_PRIVATE :: 2
|
||||
|
||||
PTHREAD_SCOPE_PROCESS :: 2
|
||||
PTHREAD_SCOPE_SYSTEM :: 1
|
||||
|
||||
pthread_t :: distinct u64
|
||||
|
||||
pthread_attr_t :: struct {
|
||||
__sig: c.long,
|
||||
__opaque: [56]c.char,
|
||||
}
|
||||
|
||||
pthread_key_t :: distinct c.ulong
|
||||
|
||||
sched_param :: struct {
|
||||
sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */
|
||||
_: [4]c.char,
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
PTHREAD_CANCEL_ASYNCHRONOUS :: 0x02
|
||||
PTHREAD_CANCEL_DEFERRED :: 0x00
|
||||
|
||||
PTHREAD_CANCEL_DISABLE :: 0x01
|
||||
PTHREAD_CANCEL_ENABLE :: 0x00
|
||||
|
||||
PTHREAD_CANCELED :: rawptr(uintptr(1))
|
||||
|
||||
PTHREAD_CREATE_DETACHED :: 1
|
||||
PTHREAD_CREATE_JOINABLE :: 0
|
||||
|
||||
PTHREAD_EXPLICIT_SCHED :: 0
|
||||
PTHREAD_INHERIT_SCHED :: 4
|
||||
|
||||
PTHREAD_PRIO_INHERIT :: 1
|
||||
PTHREAD_PRIO_NONE :: 0
|
||||
PTHREAD_PRIO_PROTECT :: 2
|
||||
|
||||
PTHREAD_PROCESS_SHARED :: 0
|
||||
PTHREAD_PROCESS_PRIVATE :: 1
|
||||
|
||||
PTHREAD_SCOPE_PROCESS :: 0
|
||||
PTHREAD_SCOPE_SYSTEM :: 2
|
||||
|
||||
pthread_t :: distinct u64
|
||||
|
||||
pthread_attr_t :: distinct rawptr
|
||||
|
||||
pthread_key_t :: distinct c.int
|
||||
|
||||
sched_param :: struct {
|
||||
sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
PTHREAD_CANCEL_ASYNCHRONOUS :: 1
|
||||
PTHREAD_CANCEL_DEFERRED :: 0
|
||||
|
||||
PTHREAD_CANCEL_DISABLE :: 1
|
||||
PTHREAD_CANCEL_ENABLE :: 0
|
||||
|
||||
PTHREAD_CANCELED :: rawptr(uintptr(1))
|
||||
|
||||
PTHREAD_CREATE_DETACHED :: 1
|
||||
PTHREAD_CREATE_JOINABLE :: 0
|
||||
|
||||
PTHREAD_EXPLICIT_SCHED :: 1
|
||||
PTHREAD_INHERIT_SCHED :: 0
|
||||
|
||||
PTHREAD_PRIO_INHERIT :: 1
|
||||
PTHREAD_PRIO_NONE :: 0
|
||||
PTHREAD_PRIO_PROTECT :: 2
|
||||
|
||||
PTHREAD_PROCESS_SHARED :: 1
|
||||
PTHREAD_PROCESS_PRIVATE :: 0
|
||||
|
||||
PTHREAD_SCOPE_PROCESS :: 0
|
||||
PTHREAD_SCOPE_SYSTEM :: 1
|
||||
|
||||
pthread_t :: distinct rawptr
|
||||
|
||||
pthread_attr_t :: struct {
|
||||
pta_magic: c.uint,
|
||||
pta_flags: c.int,
|
||||
pta_private: rawptr,
|
||||
}
|
||||
|
||||
pthread_key_t :: distinct c.int
|
||||
|
||||
sched_param :: struct {
|
||||
sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
PTHREAD_CANCEL_ASYNCHRONOUS :: 2
|
||||
PTHREAD_CANCEL_DEFERRED :: 0
|
||||
|
||||
PTHREAD_CANCEL_DISABLE :: 1
|
||||
PTHREAD_CANCEL_ENABLE :: 0
|
||||
|
||||
PTHREAD_CANCELED :: rawptr(uintptr(1))
|
||||
|
||||
PTHREAD_CREATE_DETACHED :: 0x1
|
||||
PTHREAD_CREATE_JOINABLE :: 0
|
||||
|
||||
PTHREAD_EXPLICIT_SCHED :: 0
|
||||
PTHREAD_INHERIT_SCHED :: 0x4
|
||||
|
||||
PTHREAD_PRIO_INHERIT :: 1
|
||||
PTHREAD_PRIO_NONE :: 0
|
||||
PTHREAD_PRIO_PROTECT :: 2
|
||||
|
||||
PTHREAD_PROCESS_SHARED :: 0
|
||||
PTHREAD_PROCESS_PRIVATE :: 1
|
||||
|
||||
PTHREAD_SCOPE_PROCESS :: 0
|
||||
PTHREAD_SCOPE_SYSTEM :: 0x2
|
||||
|
||||
pthread_t :: distinct rawptr
|
||||
pthread_attr_t :: distinct rawptr
|
||||
pthread_key_t :: distinct c.int
|
||||
|
||||
sched_param :: struct {
|
||||
sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
168
core/sys/posix/pwd.odin
Normal file
168
core/sys/posix/pwd.odin
Normal file
@@ -0,0 +1,168 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// pwd.h - password structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Rewinds the user database so that the next getpwent() returns the first entry.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]]
|
||||
*/
|
||||
setpwent :: proc() ---
|
||||
|
||||
/*
|
||||
Returns the current entry in the user database.
|
||||
|
||||
Returns: nil (setting errno) on error, nil (not setting errno) on success.
|
||||
|
||||
Example:
|
||||
posix.setpwent()
|
||||
defer posix.endpwent()
|
||||
for e := posix.getpwent(); e != nil; e = posix.getpwent() {
|
||||
fmt.println(e)
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]]
|
||||
*/
|
||||
@(link_name=LGETPWENT)
|
||||
getpwent :: proc() -> ^passwd ---
|
||||
|
||||
/*
|
||||
Closes the user database.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]]
|
||||
*/
|
||||
endpwent :: proc() ---
|
||||
|
||||
/*
|
||||
Searches the database for an entry with a matching name.
|
||||
|
||||
Returns: nil (setting errno) on error, nil (not setting errno) on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html ]]
|
||||
*/
|
||||
@(link_name=LGETPWNAM)
|
||||
getpwnam :: proc(name: cstring) -> ^passwd ---
|
||||
|
||||
/*
|
||||
Searches the database for an entry with a matching name.
|
||||
Populating the pwd fields and using the buffer to allocate strings into.
|
||||
Setting result to nil on failure and to the address of pwd otherwise.
|
||||
|
||||
ERANGE will be returned if there is not enough space in buffer.
|
||||
sysconf(_SC_GETPW_R_SIZE_MAX) can be called for the suggested size of this buffer, note that it could return -1.
|
||||
|
||||
Example:
|
||||
length := posix.sysconf(._GETPW_R_SIZE_MAX)
|
||||
length = length == -1 ? 1024 : length
|
||||
|
||||
buffer: [dynamic]byte
|
||||
defer delete(buffer)
|
||||
|
||||
result: posix.passwd
|
||||
resultp: ^posix.passwd
|
||||
errno: posix.Errno
|
||||
for {
|
||||
if err := resize(&buffer, length); err != nil {
|
||||
fmt.panicf("allocation failure: %v", err)
|
||||
}
|
||||
|
||||
errno = posix.getpwnam_r("root", &result, raw_data(buffer), len(buffer), &resultp)
|
||||
if errno != .ERANGE {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if errno != .NONE {
|
||||
panic(string(posix.strerror(errno)))
|
||||
}
|
||||
|
||||
fmt.println(result)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html ]]
|
||||
*/
|
||||
@(link_name=LGETPWNAMR)
|
||||
getpwnam_r :: proc(name: cstring, pwd: ^passwd, buffer: [^]byte, bufsize: c.size_t, result: ^^passwd) -> Errno ---
|
||||
|
||||
/*
|
||||
Searches the database for an entry with a matching uid.
|
||||
|
||||
Returns: nil (setting errno) on error, nil (not setting errno) on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid.html ]]
|
||||
*/
|
||||
@(link_name=LGETPWUID)
|
||||
getpwuid :: proc(uid: uid_t) -> ^passwd ---
|
||||
|
||||
/*
|
||||
Searches the database for an entry with a matching uid.
|
||||
Populating the pwd fields and using the buffer to allocate strings into.
|
||||
Setting result to nil on failure and to the address of pwd otherwise.
|
||||
|
||||
ERANGE will be returned if there is not enough space in buffer.
|
||||
sysconf(_SC_GETPW_R_SIZE_MAX) can be called for the suggested size of this buffer, note that it could return -1.
|
||||
|
||||
See the example for getpwnam_r.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html ]]
|
||||
*/
|
||||
@(link_name=LGETPWUIDR)
|
||||
getpwuid_r :: proc(uid: uid_t, pwd: ^passwd, buffer: [^]byte, bufsize: c.size_t, result: ^^passwd) -> Errno ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LGETPWENT :: "__getpwent50"
|
||||
@(private) LGETPWNAM :: "__getpwnam50"
|
||||
@(private) LGETPWNAMR :: "__getpwnam_r50"
|
||||
@(private) LGETPWUID :: "__getpwuid50"
|
||||
@(private) LGETPWUIDR :: "__getpwuid_r50"
|
||||
} else {
|
||||
@(private) LGETPWENT :: "getpwent"
|
||||
@(private) LGETPWNAM :: "getpwnam"
|
||||
@(private) LGETPWNAMR :: "getpwnam_r"
|
||||
@(private) LGETPWUID :: "getpwuid"
|
||||
@(private) LGETPWUIDR :: "getpwuid_r"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
passwd :: struct {
|
||||
pw_name: cstring, /* [PSX] user name */
|
||||
pw_passwd: cstring, /* encrypted password */
|
||||
pw_uid: uid_t, /* [PSX] user uid */
|
||||
pw_gid: gid_t, /* [PSX] user gid */
|
||||
pw_change: time_t, /* password change time */
|
||||
pw_class: cstring, /* user access class */
|
||||
pw_gecos: cstring, /* Honeywell login info */
|
||||
pw_dir: cstring, /* [PSX] home directory */
|
||||
pw_shell: cstring, /* [PSX] default shell */
|
||||
pw_expire: time_t, /* account expiration */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
passwd :: struct {
|
||||
pw_name: cstring, /* [PSX] user name */
|
||||
pw_passwd: cstring, /* encrypted password */
|
||||
pw_uid: uid_t, /* [PSX] user uid */
|
||||
pw_gid: gid_t, /* [PSX] user gid */
|
||||
pw_change: time_t, /* password change time */
|
||||
pw_class: cstring, /* user access class */
|
||||
pw_gecos: cstring, /* Honeywell login info */
|
||||
pw_dir: cstring, /* [PSX] home directory */
|
||||
pw_shell: cstring, /* [PSX] default shell */
|
||||
pw_expire: time_t, /* account expiration */
|
||||
pw_fields: c.int,
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
105
core/sys/posix/sched.odin
Normal file
105
core/sys/posix/sched.odin
Normal file
@@ -0,0 +1,105 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sched.h - execution scheduling
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Returns the minimum for the given scheduling policy.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html ]]
|
||||
*/
|
||||
sched_get_priority_max :: proc(policy: Sched_Policy) -> c.int ---
|
||||
|
||||
/*
|
||||
Returns the maximum for the given scheduling policy.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the maximum on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html ]]
|
||||
*/
|
||||
sched_get_priority_min :: proc(policy: Sched_Policy) -> c.int ---
|
||||
|
||||
/*
|
||||
Forces the running thread to relinquish the processor until it again becomes the head of its thread list.
|
||||
*/
|
||||
sched_yield :: proc() -> result ---
|
||||
|
||||
/* NOTE: unimplemented on darwin (I think?).
|
||||
/*
|
||||
Get the scheduling params of a process, pid of 0 will return that of the current process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_getparam.html ]]
|
||||
*/
|
||||
sched_getparam :: proc(pid: pid_t, param: ^sched_param) -> result ---
|
||||
/*
|
||||
Sets the scheduling parameters of the given process, pid of 0 will set that of the current process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_setparam.html ]]
|
||||
*/
|
||||
sched_setparam :: proc(pid: pid_t, param: ^sched_param) -> result ---
|
||||
|
||||
/*
|
||||
Returns the scheduling policy of a process, pid of 0 will return that of the current process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_getscheduler.html ]]
|
||||
*/
|
||||
sched_getscheduler :: proc(pid: pid_t) -> Sched_Policy ---
|
||||
|
||||
/*
|
||||
Sets the scheduling policy and parameters of the process, pid 0 will be the current process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_setscheduler.html ]]
|
||||
*/
|
||||
sched_setscheduler :: proc(pid: pid_t, policy: Sched_Policy, param: ^sched_param) -> result ---
|
||||
|
||||
/*
|
||||
Updates the timespec structure to contain the current execution time limit for the process.
|
||||
pid of 0 will return that of the current process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_rr_get_interval.html ]]
|
||||
*/
|
||||
sched_rr_get_interval :: proc(pid: pid_t, interval: ^timespec) -> result ---
|
||||
*/
|
||||
}
|
||||
|
||||
Sched_Policy :: enum c.int {
|
||||
// Error condition of sched_getscheduler.
|
||||
ERROR = -1,
|
||||
// First in-first out (FIFO) scheduling policy.
|
||||
FIFO = SCHED_FIFO,
|
||||
// Round robin scheduling policy.
|
||||
RR = SCHED_RR,
|
||||
// Another scheduling policy.
|
||||
OTHER = SCHED_OTHER,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
SCHED_FIFO :: 4
|
||||
SCHED_RR :: 2
|
||||
// SCHED_SPORADIC :: 3 NOTE: not a thing on freebsd, netbsd and probably others, leaving it out
|
||||
SCHED_OTHER :: 1
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
SCHED_FIFO :: 1
|
||||
SCHED_RR :: 3
|
||||
SCHED_OTHER :: 2
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
SCHED_OTHER :: 0
|
||||
SCHED_FIFO :: 1
|
||||
SCHED_RR :: 2
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
58
core/sys/posix/setjmp.odin
Normal file
58
core/sys/posix/setjmp.odin
Normal file
@@ -0,0 +1,58 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// setjmp.h - stack environment declarations
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Equivalent to longjmp() but must not touch signals.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_longjmp.html ]]
|
||||
*/
|
||||
_longjmp :: proc(env: ^jmp_buf, val: c.int) -> ! ---
|
||||
|
||||
/*
|
||||
Equivalent to setjmp() but must not touch signals.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_longjmp.html ]]
|
||||
*/
|
||||
_setjmp :: proc(env: ^jmp_buf) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to longjmp() but restores saved signal masks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjump.html ]]
|
||||
*/
|
||||
@(link_name=LSIGLONGJMP)
|
||||
siglongjmp :: proc(env: ^sigjmp_buf, val: c.int) -> ! ---
|
||||
|
||||
/*
|
||||
Equivalent to setjmp() but restores saved signal masks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjump.html ]]
|
||||
*/
|
||||
@(link_name=LSIGSETJMP)
|
||||
sigsetjmp :: proc(env: ^sigjmp_buf, savemask: b32) -> c.int ---
|
||||
}
|
||||
|
||||
jmp_buf :: libc.jmp_buf
|
||||
sigjmp_buf :: distinct jmp_buf
|
||||
|
||||
longjmp :: libc.longjmp
|
||||
setjmp :: libc.setjmp
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSIGSETJMP :: "__sigsetjmp14"
|
||||
@(private) LSIGLONGJMP :: "__siglongjmp14"
|
||||
} else {
|
||||
@(private) LSIGSETJMP :: "sigsetjmp"
|
||||
@(private) LSIGLONGJMP :: "siglongjmp"
|
||||
}
|
||||
1131
core/sys/posix/signal.odin
Normal file
1131
core/sys/posix/signal.odin
Normal file
File diff suppressed because it is too large
Load Diff
332
core/sys/posix/stdio.odin
Normal file
332
core/sys/posix/stdio.odin
Normal file
@@ -0,0 +1,332 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// stdio.h - standard buffered input/output
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Generates a string that, when used as a pathname,
|
||||
refers to the current controlling terminal for the current process.
|
||||
|
||||
If s is nil, the returned string might be static and overwritten by subsequent calls or other factors.
|
||||
If s is not nil, s is assumed len(s) >= L_ctermid.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctermid.html ]]
|
||||
*/
|
||||
ctermid :: proc(s: [^]byte) -> cstring ---
|
||||
|
||||
/*
|
||||
Equivalent to fprintf but output is written to the file descriptor.
|
||||
|
||||
Return: number of bytes written, negative (setting errno) on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]]
|
||||
*/
|
||||
dprintf :: proc(fildse: FD, format: cstring, #c_vararg args: ..any) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to fprintf but output is written to s, it is the user's responsibility to
|
||||
ensure there is enough space.
|
||||
|
||||
Return: number of bytes written, negative (setting errno) on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]]
|
||||
*/
|
||||
sprintf :: proc(s: [^]byte, format: cstring, #c_vararg args: ..any) -> c.int ---
|
||||
|
||||
/*
|
||||
Associate a stream with a file descriptor.
|
||||
|
||||
Returns: nil (setting errno) on failure, the stream on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopen.html ]]
|
||||
*/
|
||||
fdopen :: proc(fildes: FD, mode: cstring) -> ^FILE ---
|
||||
|
||||
/*
|
||||
Map a stream pointer to a file descriptor.
|
||||
|
||||
Returns: the file descriptor or -1 (setting errno) on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fileno.html ]]
|
||||
*/
|
||||
fileno :: proc(stream: ^FILE) -> FD ---
|
||||
|
||||
/*
|
||||
Locks a file.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]]
|
||||
*/
|
||||
flockfile :: proc(file: ^FILE) ---
|
||||
|
||||
/*
|
||||
Tries to lock a file.
|
||||
|
||||
Returns: 0 if it could be locked, non-zero if it couldn't
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]]
|
||||
*/
|
||||
ftrylockfile :: proc(file: ^FILE) -> c.int ---
|
||||
|
||||
/*
|
||||
Unlocks a file.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]]
|
||||
*/
|
||||
funlockfile :: proc(file: ^FILE) ---
|
||||
|
||||
/*
|
||||
Open a memory buffer stream.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fmemopen.html ]]
|
||||
*/
|
||||
fmemopen :: proc(buf: [^]byte, size: c.size_t, mode: cstring) -> ^FILE ---
|
||||
|
||||
/*
|
||||
Reposition a file-position indicator in a stream.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseeko.html ]]
|
||||
*/
|
||||
fseeko :: proc(stream: ^FILE, offset: off_t, whence: Whence) -> result ---
|
||||
|
||||
/*
|
||||
Return the file offset in a stream.
|
||||
|
||||
Returns: the current file offset, -1 (setting errno) on error
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftello.html ]]
|
||||
*/
|
||||
ftello :: proc(^FILE) -> off_t ---
|
||||
|
||||
/*
|
||||
Open a dynamic memory buffer stream.
|
||||
|
||||
Returns: nil (setting errno) on failure, the stream on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open_memstream.html ]]
|
||||
*/
|
||||
open_memstream :: proc(bufp: ^[^]byte, sizep: ^c.size_t) -> ^FILE ---
|
||||
|
||||
/*
|
||||
Equivalent to getc but unaffected by locks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
|
||||
*/
|
||||
getc_unlocked :: proc(stream: ^FILE) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to getchar but unaffected by locks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
|
||||
*/
|
||||
getchar_unlocked :: proc() -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to putc but unaffected by locks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
|
||||
*/
|
||||
putc_unlocked :: proc(ch: c.int, stream: ^FILE) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to putchar but unaffected by locks.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
|
||||
*/
|
||||
putchar_unlocked :: proc(ch: c.int) -> c.int ---
|
||||
|
||||
/*
|
||||
Read a delimited record from the stream.
|
||||
|
||||
Returns: the number of bytes written or -1 on failure/EOF
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html ]]
|
||||
*/
|
||||
getdelim :: proc(lineptr: ^cstring, n: ^c.size_t, delimiter: c.int, stream: ^FILE) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Read a line delimited record from the stream.
|
||||
|
||||
Returns: the number of bytes written or -1 on failure/EOF
|
||||
|
||||
Example:
|
||||
fp := posix.fopen(#file, "r")
|
||||
if fp == nil {
|
||||
posix.exit(1)
|
||||
}
|
||||
|
||||
line: cstring
|
||||
length: uint
|
||||
for {
|
||||
read := posix.getline(&line, &length, fp)
|
||||
if read == -1 do break
|
||||
posix.printf("Retrieved line of length %zu :\n", read)
|
||||
posix.printf("%s", line)
|
||||
}
|
||||
if posix.ferror(fp) != 0 {
|
||||
/* handle error */
|
||||
}
|
||||
posix.free(rawptr(line))
|
||||
posix.fclose(fp)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html ]]
|
||||
*/
|
||||
getline :: proc(lineptr: ^cstring, n: ^c.size_t, stream: ^FILE) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Get a string from the stdin stream.
|
||||
|
||||
It is up to the user to make sure s is big enough.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gets.html ]]
|
||||
*/
|
||||
gets :: proc(s: [^]byte) -> cstring ---
|
||||
|
||||
/*
|
||||
Create a name for a temporary file.
|
||||
|
||||
Returns: an allocated cstring that needs to be freed, nil on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html ]]
|
||||
*/
|
||||
tempnam :: proc(dir: cstring, pfx: cstring) -> cstring ---
|
||||
|
||||
/*
|
||||
Executes the command specified, creating a pipe and returning a pointer to a stream that can
|
||||
read or write from/to the pipe.
|
||||
|
||||
Returns: nil (setting errno) on failure or a pointer to the stream
|
||||
|
||||
Example:
|
||||
fp := posix.popen("ls *", "r")
|
||||
if fp == nil {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
path: [1024]byte
|
||||
for posix.fgets(raw_data(path[:]), len(path), fp) != nil {
|
||||
posix.printf("%s", &path)
|
||||
}
|
||||
|
||||
status := posix.pclose(fp)
|
||||
if status == -1 {
|
||||
/* Error reported by pclose() */
|
||||
} else {
|
||||
/* Use functions described under wait() to inspect `status` in order
|
||||
to determine success/failure of the command executed by popen() */
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ]]
|
||||
*/
|
||||
popen :: proc(command: cstring, mode: cstring) -> ^FILE ---
|
||||
|
||||
/*
|
||||
Closes a pipe stream to or from a process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pclose.html ]]
|
||||
*/
|
||||
pclose :: proc(stream: ^FILE) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to rename but relative directories are resolved from their respective fds.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/renameat.html ]]
|
||||
*/
|
||||
renameat :: proc(oldfd: FD, old: cstring, newfd: FD, new: cstring) -> result ---
|
||||
}
|
||||
|
||||
clearerr :: libc.clearerr
|
||||
fclose :: libc.fclose
|
||||
feof :: libc.feof
|
||||
ferror :: libc.ferror
|
||||
fflush :: libc.fflush
|
||||
fgetc :: libc.fgetc
|
||||
fgetpos :: libc.fgetpos
|
||||
fgets :: libc.fgets
|
||||
fopen :: libc.fopen
|
||||
fprintf :: libc.fprintf
|
||||
fputc :: libc.fputc
|
||||
fread :: libc.fread
|
||||
freopen :: libc.freopen
|
||||
fscanf :: libc.fscanf
|
||||
fseek :: libc.fseek
|
||||
fsetpos :: libc.fsetpos
|
||||
ftell :: libc.ftell
|
||||
fwrite :: libc.fwrite
|
||||
getc :: libc.getc
|
||||
getchar :: libc.getchar
|
||||
perror :: libc.perror
|
||||
printf :: libc.printf
|
||||
putc :: libc.puts
|
||||
putchar :: libc.putchar
|
||||
puts :: libc.puts
|
||||
remove :: libc.remove
|
||||
rename :: libc.rename
|
||||
rewind :: libc.rewind
|
||||
scanf :: libc.scanf
|
||||
setbuf :: libc.setbuf
|
||||
setvbuf :: libc.setvbuf
|
||||
snprintf :: libc.snprintf
|
||||
sscanf :: libc.sscanf
|
||||
tmpfile :: libc.tmpfile
|
||||
tmpnam :: libc.tmpnam
|
||||
vfprintf :: libc.vfprintf
|
||||
vfscanf :: libc.vfscanf
|
||||
vprintf :: libc.vprintf
|
||||
vscanf :: libc.vscanf
|
||||
vsnprintf :: libc.vsnprintf
|
||||
vsprintf :: libc.vsprintf
|
||||
vsscanf :: libc.vsscanf
|
||||
ungetc :: libc.ungetc
|
||||
|
||||
to_stream :: libc.to_stream
|
||||
|
||||
Whence :: libc.Whence
|
||||
FILE :: libc.FILE
|
||||
fpos_t :: libc.fpos_t
|
||||
|
||||
BUFSIZ :: libc.BUFSIZ
|
||||
|
||||
_IOFBF :: libc._IOFBF
|
||||
_IOLBF :: libc._IOLBF
|
||||
_IONBF :: libc._IONBF
|
||||
|
||||
SEEK_CUR :: libc.SEEK_CUR
|
||||
SEEK_END :: libc.SEEK_END
|
||||
SEEK_SET :: libc.SEEK_SET
|
||||
|
||||
FILENAME_MAX :: libc.FILENAME_MAX
|
||||
FOPEN_MAX :: libc.FOPEN_MAX
|
||||
TMP_MAX :: libc.TMP_MAX
|
||||
|
||||
EOF :: libc.EOF
|
||||
|
||||
stderr := libc.stderr
|
||||
stdin := libc.stdin
|
||||
stdout := libc.stdout
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
L_ctermid :: 1024
|
||||
L_tmpnam :: 1024
|
||||
|
||||
P_tmpdir :: "/var/tmp/"
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
L_ctermid :: 1024
|
||||
L_tmpnam :: 1024
|
||||
|
||||
P_tmpdir :: "/tmp/"
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
450
core/sys/posix/stdlib.odin
Normal file
450
core/sys/posix/stdlib.odin
Normal file
@@ -0,0 +1,450 @@
|
||||
package posix
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// stdlib.h - standard library definitions
|
||||
|
||||
atof :: libc.atof
|
||||
atoi :: libc.atoi
|
||||
atol :: libc.atol
|
||||
atoll :: libc.atoll
|
||||
strtod :: libc.strtod
|
||||
strtof :: libc.strtof
|
||||
strtol :: libc.strtol
|
||||
strtoll :: libc.strtoll
|
||||
strtoul :: libc.strtoul
|
||||
strtoull :: libc.strtoull
|
||||
|
||||
rand :: libc.rand
|
||||
srand :: libc.srand
|
||||
|
||||
calloc :: libc.calloc
|
||||
malloc :: libc.malloc
|
||||
realloc :: libc.realloc
|
||||
|
||||
abort :: libc.abort
|
||||
atexit :: libc.atexit
|
||||
at_quick_exit :: libc.at_quick_exit
|
||||
exit :: libc.exit
|
||||
_Exit :: libc._Exit
|
||||
getenv :: libc.getenv
|
||||
quick_exit :: libc.quick_exit
|
||||
system :: libc.system
|
||||
|
||||
bsearch :: libc.bsearch
|
||||
qsort :: libc.qsort
|
||||
|
||||
abs :: libc.abs
|
||||
labs :: libc.labs
|
||||
llabs :: libc.llabs
|
||||
div :: libc.div
|
||||
ldiv :: libc.ldiv
|
||||
lldiv :: libc.lldiv
|
||||
|
||||
mblen :: libc.mblen
|
||||
mbtowc :: libc.mbtowc
|
||||
wctomb :: libc.wctomb
|
||||
|
||||
mbstowcs :: libc.mbstowcs
|
||||
wcstombs :: libc.wcstombs
|
||||
|
||||
free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
|
||||
libc.free(rawptr(ptr))
|
||||
}
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Takes a pointer to a radix-64 representation, in which the first digit is the least significant,
|
||||
and return the corresponding long value.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/a64l.html ]]
|
||||
*/
|
||||
a64l :: proc(s: cstring) -> c.long ---
|
||||
|
||||
/*
|
||||
The l64a() function shall take a long argument and return a pointer to the corresponding
|
||||
radix-64 representation.
|
||||
|
||||
Returns: a string that may be invalidated by subsequent calls
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/a64l.html ]]
|
||||
*/
|
||||
l64a :: proc(value: c.long) -> cstring ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0,1.0)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
drand48 :: proc() -> c.double ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0,1.0)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
erand48 :: proc(xsubi: ^[3]c.ushort) -> c.double ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: return signed long integers uniformly distributed over the interval [-231,231)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
mrand48 :: proc() -> c.long ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: return signed long integers uniformly distributed over the interval [-231,231)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
jrand48 :: proc(xsubi: ^[3]c.ushort) -> c.long ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: non-negative, long integers, uniformly distributed over the interval [0,231)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
lrand48 :: proc() -> c.long ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
Returns: non-negative, long integers, uniformly distributed over the interval [0,231)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
nrand48 :: proc(xsubi: ^[3]c.ushort) -> c.long ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
srand48 :: proc(seedval: c.long) ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
lcong48 :: proc(param: ^[7]c.ushort) ---
|
||||
|
||||
/*
|
||||
This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic.
|
||||
|
||||
The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]]
|
||||
*/
|
||||
seed48 :: proc(seed16v: ^[3]c.ushort) -> ^[3]c.ushort ---
|
||||
|
||||
/*
|
||||
Parses suboption arguments in a flag argument.
|
||||
|
||||
Returns: the index of the matched token string, or -1 if no token strings were matched
|
||||
|
||||
Example:
|
||||
args := runtime.args__
|
||||
|
||||
Opt :: enum {
|
||||
RO,
|
||||
RW,
|
||||
NAME,
|
||||
NIL,
|
||||
}
|
||||
token := [Opt]cstring{
|
||||
.RO = "ro",
|
||||
.RW = "rw",
|
||||
.NAME = "name",
|
||||
.NIL = nil,
|
||||
}
|
||||
|
||||
Options :: struct {
|
||||
readonly, readwrite: bool,
|
||||
name: cstring,
|
||||
|
||||
}
|
||||
opts: Options
|
||||
|
||||
errfnd: bool
|
||||
for {
|
||||
opt := posix.getopt(i32(len(args)), raw_data(args), "o:")
|
||||
if opt == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
switch opt {
|
||||
case 'o':
|
||||
subopt := posix.optarg
|
||||
value: cstring
|
||||
for subopt != "" && !errfnd {
|
||||
o := posix.getsubopt(&subopt, &token[.RO], &value)
|
||||
switch Opt(o) {
|
||||
case .RO: opts.readonly = true
|
||||
case .RW: opts.readwrite = true
|
||||
case .NAME:
|
||||
if value == nil {
|
||||
fmt.eprintfln("missing value for suboption %s", token[.NAME])
|
||||
errfnd = true
|
||||
continue
|
||||
}
|
||||
|
||||
opts.name = value
|
||||
case .NIL:
|
||||
fallthrough
|
||||
case:
|
||||
fmt.eprintfln("no match found for token: %s", value)
|
||||
errfnd = true
|
||||
}
|
||||
}
|
||||
if opts.readwrite && opts.readonly {
|
||||
fmt.eprintfln("Only one of %s and %s can be specified", token[.RO], token[.RW])
|
||||
errfnd = true
|
||||
}
|
||||
case:
|
||||
errfnd = true
|
||||
}
|
||||
}
|
||||
|
||||
if errfnd || len(args) == 1 {
|
||||
fmt.eprintfln("\nUsage: %s -o <suboptstring>", args[0])
|
||||
fmt.eprintfln("suboptions are 'ro', 'rw', and 'name=<value>'")
|
||||
posix.exit(1)
|
||||
}
|
||||
|
||||
fmt.println(opts)
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html ]]
|
||||
*/
|
||||
getsubopt :: proc(optionp: ^cstring, keylistp: [^]cstring, valuep: ^cstring) -> c.int ---
|
||||
|
||||
/*
|
||||
Changes the mode and ownership of the slave pseudo-terminal device associated with its master pseudo-terminal counterpart.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html ]]
|
||||
*/
|
||||
grantpt :: proc(fildes: FD) -> result ---
|
||||
|
||||
/*
|
||||
Allows a state array, pointed to by the state argument, to be initialized for future use.
|
||||
|
||||
Returns: the previous state array or nil on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]]
|
||||
*/
|
||||
@(link_name=LINITSTATE)
|
||||
initstate :: proc(seed: c.uint, state: [^]byte, size: c.size_t) -> [^]byte ---
|
||||
|
||||
/*
|
||||
Sets the state array of the random number generator.
|
||||
|
||||
Returns: the previous state array or nil on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]]
|
||||
*/
|
||||
setstate :: proc(state: [^]byte) -> [^]byte ---
|
||||
|
||||
/*
|
||||
Use a non-linear additive feedback random-number generator employing a default state array
|
||||
size of 31 long integers to return successive pseudo-random numbers in the range from 0 to 231-1.
|
||||
The period of this random-number generator is approximately 16 x (231-1).
|
||||
The size of the state array determines the period of the random-number generator.
|
||||
Increasing the state array size shall increase the period.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]]
|
||||
*/
|
||||
random :: proc() -> c.long ---
|
||||
|
||||
/*
|
||||
Initializes the current state array using the value of seed.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]]
|
||||
*/
|
||||
@(link_name=LSRANDOM)
|
||||
srandom :: proc(seed: c.uint) ---
|
||||
|
||||
/*
|
||||
Creates a directory with a unique name derived from template.
|
||||
The application shall ensure that the string provided in template is a pathname ending
|
||||
with at least six trailing 'X' characters.
|
||||
|
||||
Returns: nil (setting errno) on failure, template on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html ]]
|
||||
*/
|
||||
mkdtemp :: proc(template: [^]byte) -> cstring ---
|
||||
|
||||
/*
|
||||
Creates a regular file with a unique name derived from template and return a file descriptor
|
||||
for the file open for reading and writing.
|
||||
The application shall ensure that the string provided in template is a pathname ending with
|
||||
at least six trailing 'X' characters.
|
||||
|
||||
Returns: -1 (setting errno) on failure, an open file descriptor on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html ]]
|
||||
*/
|
||||
mkstemp :: proc(template: cstring) -> FD ---
|
||||
|
||||
/*
|
||||
Allocates size bytes aligned on a boundary specified by alignment, and shall return a pointer
|
||||
to the allocated memory in memptr.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html ]]
|
||||
*/
|
||||
posix_memalign :: proc(memptr: ^[^]byte, alignment: c.size_t, size: c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Establishes a connection between a master device for a pseudo-terminal and a file descriptor.
|
||||
|
||||
Returns: -1 (setting errno) on failure, an open file descriptor otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html ]]
|
||||
*/
|
||||
posix_openpt :: proc(oflag: O_Flags) -> FD ---
|
||||
|
||||
/*
|
||||
Returns the name of the slave pseudo-terminal device associated with a master pseudo-terminal device.
|
||||
|
||||
Returns: nil (setting errno) on failure, the name on success, which may be invalidated on subsequent calls
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ptsname.html ]]
|
||||
*/
|
||||
ptsname :: proc(fildes: FD) -> cstring ---
|
||||
|
||||
/*
|
||||
Unlocks the slave pseudo-terminal device associated with the master to which fildes refers.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html ]]
|
||||
*/
|
||||
unlockpt :: proc(fildes: FD) -> result ---
|
||||
|
||||
/*
|
||||
Uses the string argument to set environment variable values.
|
||||
|
||||
Returns: 0 on success, non-zero (setting errno) on failure
|
||||
|
||||
Example:
|
||||
if posix.putenv("HOME=/usr/home") != 0 {
|
||||
fmt.panicf("putenv failure: %v", posix.strerror(posix.errno()))
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html ]]
|
||||
*/
|
||||
@(link_name=LPUTENV)
|
||||
putenv :: proc(string: cstring) -> c.int ---
|
||||
|
||||
/*
|
||||
Updates or add a variable in the environment of the calling process.
|
||||
|
||||
Example:
|
||||
if posix.setenv("HOME", "/usr/home") != .OK {
|
||||
fmt.panicf("putenv failure: %v", posix.strerror(posix.errno()))
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setenv.html ]]
|
||||
*/
|
||||
setenv :: proc(envname: cstring, envval: cstring, overwrite: b32) -> result ---
|
||||
|
||||
/*
|
||||
Removes an environment variable from the environment of the calling process.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unsetenv.html ]]
|
||||
*/
|
||||
@(link_name=LUNSETENV)
|
||||
unsetenv :: proc(name: cstring) -> result ---
|
||||
|
||||
/*
|
||||
Computes a sequence of pseudo-random integers in the range [0, {RAND_MAX}].
|
||||
(The value of the {RAND_MAX} macro shall be at least 32767.)
|
||||
|
||||
If rand_r() is called with the same initial value for the object pointed to by seed and that object is not modified between successive returns and calls to rand_r(), the same sequence shall be generated.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rand_r.html ]]
|
||||
*/
|
||||
rand_r :: proc(seed: ^c.uint) -> c.int ---
|
||||
|
||||
/*
|
||||
Derive, from the pathname file_name, an absolute pathname that resolves to the same directory entry,
|
||||
whose resolution does not involve '.', '..', or symbolic links.
|
||||
|
||||
If resolved_name is not `nil` it should be larger than `PATH_MAX` and the result will use it as a backing buffer.
|
||||
If resolved_name is `nil` the returned string is allocated by `malloc`.
|
||||
|
||||
Returns: `nil` (setting errno) on failure, the "real path" otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html ]]
|
||||
*/
|
||||
realpath :: proc(file_name: cstring, resolved_name: [^]byte = nil) -> cstring ---
|
||||
|
||||
/*
|
||||
Provides access to an implementation-defined encoding algorithm.
|
||||
The argument of setkey() is an array of length 64 bytes containing only the bytes with numerical
|
||||
value of 0 and 1.
|
||||
|
||||
If this string is divided into groups of 8, the low-order bit in each group is ignored; this gives a 56-bit key which is used by the algorithm.
|
||||
This is the key that shall be used with the algorithm to encode a string block passed to encrypt().
|
||||
|
||||
The setkey() function shall not change the setting of errno if successful.
|
||||
An application wishing to check for error situations should set errno to 0 before calling setkey().
|
||||
If errno is non-zero on return, an error has occurred.
|
||||
|
||||
Example:
|
||||
key: [64]byte
|
||||
// set key bytes...
|
||||
|
||||
posix.set_errno(.NONE)
|
||||
posix.setkey(raw_data(key))
|
||||
if errno := posix.errno(); errno != .NONE {
|
||||
fmt.panicf("setkey failure: %s", posix.strerror(errno))
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setkey.html ]]
|
||||
*/
|
||||
setkey :: proc(key: [^]byte) ---
|
||||
}
|
||||
|
||||
EXIT_FAILURE :: libc.EXIT_FAILURE
|
||||
EXIT_SUCCESS :: libc.EXIT_SUCCESS
|
||||
|
||||
RAND_MAX :: libc.RAND_MAX
|
||||
MB_CUR_MAX :: libc.MB_CUR_MAX
|
||||
|
||||
div_t :: libc.div_t
|
||||
ldiv_t :: libc.ldiv_t
|
||||
lldiv_t :: libc.lldiv_t
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LPUTENV :: "__putenv50"
|
||||
@(private) LINITSTATE :: "__initstate60"
|
||||
@(private) LSRANDOM :: "__srandom60"
|
||||
@(private) LUNSETENV :: "__unsetenv13"
|
||||
} else {
|
||||
@(private) LPUTENV :: "putenv"
|
||||
@(private) LINITSTATE :: "initstate"
|
||||
@(private) LSRANDOM :: "srandom"
|
||||
@(private) LUNSETENV :: "unsetenv"
|
||||
}
|
||||
47
core/sys/posix/string.odin
Normal file
47
core/sys/posix/string.odin
Normal file
@@ -0,0 +1,47 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// string.h - string operations
|
||||
|
||||
// NOTE: most of the symbols in this header are not useful in Odin and have been left out.
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Map the error number to a locale-dependent error message string.
|
||||
|
||||
Returns: a string that may be invalidated by subsequent calls
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html ]]
|
||||
*/
|
||||
@(link_name="strerror")
|
||||
_strerror :: proc(errnum: Errno) -> cstring ---
|
||||
|
||||
/*
|
||||
Map the error number to a locale-dependent error message string and put it in the buffer.
|
||||
|
||||
Returns: ERANGE if the buffer is not big enough
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror_r.html ]]
|
||||
*/
|
||||
strerror_r :: proc(errnum: Errno, strerrbuf: [^]byte, buflen: c.size_t) -> Errno ---
|
||||
|
||||
/*
|
||||
Map the signal number to an implementation-defined string.
|
||||
|
||||
Returns: a string that may be invalidated by subsequent calls
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strsignal.html ]]
|
||||
*/
|
||||
strsignal :: proc(sig: Signal) -> cstring ---
|
||||
}
|
||||
|
||||
strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring {
|
||||
return _strerror(errnum.? or_else errno())
|
||||
}
|
||||
89
core/sys/posix/sys_ipc.odin
Normal file
89
core/sys/posix/sys_ipc.odin
Normal file
@@ -0,0 +1,89 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/ipc.h = XSI interprocess communication access structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Generate an IPC key.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the key otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftok.html ]]
|
||||
*/
|
||||
ftok :: proc(path: cstring, id: c.int) -> key_t ---
|
||||
}
|
||||
|
||||
IPC_Cmd :: enum c.int {
|
||||
RMID = IPC_RMID,
|
||||
SET = IPC_SET,
|
||||
STAT = IPC_STAT,
|
||||
}
|
||||
|
||||
IPC_Flag_Bits :: enum c.int {
|
||||
CREAT = log2(IPC_CREAT),
|
||||
EXCL = log2(IPC_EXCL),
|
||||
NOWAIT = log2(IPC_NOWAIT),
|
||||
|
||||
MSG_NOERROR = log2(MSG_NOERROR),
|
||||
}
|
||||
IPC_Flags :: bit_set[IPC_Flag_Bits; c.int]
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
key_t :: distinct c.int32_t
|
||||
|
||||
ipc_perm :: struct {
|
||||
uid: uid_t, /* [PSX] owner's user ID */
|
||||
gid: gid_t, /* [PSX] owner's group ID */
|
||||
cuid: uid_t, /* [PSX] creator's user ID */
|
||||
cgid: gid_t, /* [PSX] creator's group ID */
|
||||
mode: mode_t, /* [PSX] read/write perms */
|
||||
_seq: c.ushort,
|
||||
_key: key_t,
|
||||
}
|
||||
|
||||
IPC_CREAT :: 0o01000
|
||||
IPC_EXCL :: 0o02000
|
||||
IPC_NOWAIT :: 0o04000
|
||||
|
||||
IPC_PRIVATE :: key_t(0)
|
||||
|
||||
IPC_RMID :: 0
|
||||
IPC_SET :: 1
|
||||
IPC_STAT :: 2
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
key_t :: distinct c.long
|
||||
|
||||
ipc_perm :: struct {
|
||||
cuid: uid_t, /* [PSX] creator's user ID */
|
||||
cgid: gid_t, /* [PSX] creator's group ID */
|
||||
uid: uid_t, /* [PSX] owner's user ID */
|
||||
gid: gid_t, /* [PSX] owner's group ID */
|
||||
mode: mode_t, /* [PSX] read/write perms */
|
||||
_seq: c.ushort,
|
||||
_key: key_t,
|
||||
}
|
||||
|
||||
IPC_CREAT :: 0o01000
|
||||
IPC_EXCL :: 0o02000
|
||||
IPC_NOWAIT :: 0o04000
|
||||
|
||||
IPC_PRIVATE :: key_t(0)
|
||||
|
||||
IPC_RMID :: 0
|
||||
IPC_SET :: 1
|
||||
IPC_STAT :: 2
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
229
core/sys/posix/sys_mman.odin
Normal file
229
core/sys/posix/sys_mman.odin
Normal file
@@ -0,0 +1,229 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// mman.h - memory management declarations
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Establish a mapping between an address space of a process and a memory object.
|
||||
|
||||
Returns: MAP_FAILED (setting errno) on failure, the address in memory otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html ]]
|
||||
*/
|
||||
mmap :: proc(
|
||||
addr: rawptr,
|
||||
len: c.size_t,
|
||||
prot: Prot_Flags,
|
||||
flags: Map_Flags,
|
||||
fd: FD = -1,
|
||||
off: off_t = 0,
|
||||
) -> rawptr ---
|
||||
|
||||
/*
|
||||
Unmaps pages of memory.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html ]]
|
||||
*/
|
||||
munmap :: proc(addr: rawptr, len: c.size_t) -> result ---
|
||||
|
||||
/*
|
||||
Locks a range of the process address space.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html ]]
|
||||
*/
|
||||
mlock :: proc(addr: rawptr, len: c.size_t) -> result ---
|
||||
|
||||
/*
|
||||
Unlocks a range of the process address space.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html ]]
|
||||
*/
|
||||
munlock :: proc(addr: rawptr, len: c.size_t) -> result ---
|
||||
|
||||
/*
|
||||
Locks all pages of the process address space.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html ]]
|
||||
*/
|
||||
mlockall :: proc(flags: Lock_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Unlocks all pages of the process address space.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html ]]
|
||||
*/
|
||||
munlockall :: proc() -> result ---
|
||||
|
||||
/*
|
||||
Set protection of a memory mapping.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html ]]
|
||||
*/
|
||||
mprotect :: proc(addr: rawptr, len: c.size_t, prot: Prot_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Write all modified data to permanent storage locations.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msync.html ]]
|
||||
*/
|
||||
@(link_name=LMSYNC)
|
||||
msync :: proc(addr: rawptr, len: c.size_t, flags: Sync_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Advise the implementation of expected behavior of the application.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_madvise.html ]]
|
||||
*/
|
||||
posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: MAdvice) -> Errno ---
|
||||
|
||||
/*
|
||||
Open a shared memory object.
|
||||
|
||||
Returns: -1 (setting errno) on failure, an open file descriptor otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html ]]
|
||||
*/
|
||||
shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD ---
|
||||
|
||||
/*
|
||||
Removes a shared memory object.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_unlink.html ]]
|
||||
*/
|
||||
shm_unlink :: proc(name: cstring) -> result ---
|
||||
}
|
||||
|
||||
#assert(_PROT_NONE == 0)
|
||||
PROT_NONE :: Prot_Flags{}
|
||||
|
||||
Prot_Flag_Bits :: enum c.int {
|
||||
// Data can be executed.
|
||||
EXEC = log2(PROT_EXEC),
|
||||
// Data can be read.
|
||||
READ = log2(PROT_READ),
|
||||
// Data can be written.
|
||||
WRITE = log2(PROT_WRITE),
|
||||
}
|
||||
Prot_Flags :: bit_set[Prot_Flag_Bits; c.int]
|
||||
|
||||
Map_Flag_Bits :: enum c.int {
|
||||
// Interpret addr exactly.
|
||||
FIXED = log2(MAP_FIXED),
|
||||
// Changes are private.
|
||||
PRIVATE = log2(MAP_PRIVATE),
|
||||
// Changes are shared.
|
||||
SHARED = log2(MAP_SHARED),
|
||||
}
|
||||
Map_Flags :: bit_set[Map_Flag_Bits; c.int]
|
||||
|
||||
Lock_Flag_Bits :: enum c.int {
|
||||
// Lock all pages currently mapped into the address space of the process.
|
||||
CURRENT = log2(MCL_CURRENT),
|
||||
// Lock all pages that become mapped into the address space of the process in the future,
|
||||
// when those mappings are established.
|
||||
FUTURE = log2(MCL_FUTURE),
|
||||
}
|
||||
Lock_Flags :: bit_set[Lock_Flag_Bits; c.int]
|
||||
|
||||
Sync_Flags_Bits :: enum c.int {
|
||||
// Perform asynchronous writes.
|
||||
ASYNC = log2(MS_ASYNC),
|
||||
// Invalidate cached data.
|
||||
INVALIDATE = log2(MS_INVALIDATE),
|
||||
|
||||
// Perform synchronous writes.
|
||||
// NOTE: use with `posix.MS_SYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
|
||||
// this bit set enum because it is 0 on some platforms and a value on others.
|
||||
// LOCAL = RTLD_LOCAL
|
||||
// SYNC = MS_SYNC,
|
||||
|
||||
_MAX = 31,
|
||||
}
|
||||
Sync_Flags :: bit_set[Sync_Flags_Bits; c.int]
|
||||
|
||||
MAdvice :: enum c.int {
|
||||
DONTNEED = POSIX_MADV_DONTNEED,
|
||||
NORMAL = POSIX_MADV_NORMAL,
|
||||
RANDOM = POSIX_MADV_RANDOM,
|
||||
SEQUENTIAL = POSIX_MADV_SEQUENTIAL,
|
||||
WILLNEED = POSIX_MADV_WILLNEED,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LMSYNC :: "__msync13"
|
||||
} else {
|
||||
@(private) LMSYNC :: "msync"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
PROT_EXEC :: 0x04
|
||||
_PROT_NONE :: 0x00
|
||||
PROT_READ :: 0x01
|
||||
PROT_WRITE :: 0x02
|
||||
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
MS_INVALIDATE :: 0x0002
|
||||
_MS_SYNC :: 0x0010
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
MS_INVALIDATE :: 0x0002
|
||||
_MS_SYNC :: 0x0004
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
MS_INVALIDATE :: 0x0004
|
||||
_MS_SYNC :: 0x0002
|
||||
}
|
||||
MS_ASYNC :: 0x0001
|
||||
MS_SYNC :: Sync_Flags{Sync_Flags_Bits(log2(_MS_SYNC))}
|
||||
|
||||
MCL_CURRENT :: 0x0001
|
||||
MCL_FUTURE :: 0x0002
|
||||
|
||||
MAP_FAILED :: rawptr(~uintptr(0))
|
||||
|
||||
POSIX_MADV_DONTNEED :: 4
|
||||
POSIX_MADV_NORMAL :: 0
|
||||
POSIX_MADV_RANDOM :: 1
|
||||
POSIX_MADV_SEQUENTIAL :: 2
|
||||
POSIX_MADV_WILLNEED :: 3
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
PROT_EXEC :: 0x04
|
||||
_PROT_NONE :: 0x00
|
||||
PROT_READ :: 0x01
|
||||
PROT_WRITE :: 0x02
|
||||
|
||||
MAP_FIXED :: 0x0010
|
||||
MAP_PRIVATE :: 0x0002
|
||||
MAP_SHARED :: 0x0001
|
||||
|
||||
MS_ASYNC :: 0x0001
|
||||
MS_INVALIDATE :: 0x0002
|
||||
MS_SYNC :: Sync_Flags{}
|
||||
|
||||
MCL_CURRENT :: 0x0001
|
||||
MCL_FUTURE :: 0x0002
|
||||
|
||||
MAP_FAILED :: rawptr(~uintptr(0))
|
||||
|
||||
POSIX_MADV_DONTNEED :: 4
|
||||
POSIX_MADV_NORMAL :: 0
|
||||
POSIX_MADV_RANDOM :: 1
|
||||
POSIX_MADV_SEQUENTIAL :: 2
|
||||
POSIX_MADV_WILLNEED :: 3
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
161
core/sys/posix/sys_msg.odin
Normal file
161
core/sys/posix/sys_msg.odin
Normal file
@@ -0,0 +1,161 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/msg.h = XSI message queue structures
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Provides various operation as specified by the given cmd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgctl.html ]]
|
||||
*/
|
||||
@(link_name=LMSGCTL)
|
||||
msgctl :: proc(msqid: FD, cmd: IPC_Cmd, buf: ^msqid_ds) -> result ---
|
||||
|
||||
/*
|
||||
Returns the message queue identifier associated with the argument key.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the identifier otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgget.html ]]
|
||||
*/
|
||||
msgget :: proc(key: key_t, msgflg: IPC_Flags) -> FD ---
|
||||
|
||||
/*
|
||||
Read a message from the queue.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the bytes received otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgrcv.html ]]
|
||||
*/
|
||||
msgrcv :: proc(
|
||||
msgid: FD,
|
||||
msgp: rawptr,
|
||||
msgsz: c.size_t,
|
||||
msgtyp: c.long,
|
||||
msgflg: IPC_Flags,
|
||||
) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Send a message on the queue.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgsnd.html ]]
|
||||
*/
|
||||
msgsnd :: proc(msgid: FD, msgp: rawptr, msgsz: c.size_t, msgflg: IPC_Flags) -> result ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LMSGCTL :: "__msgctl50"
|
||||
} else {
|
||||
@(private) LMSGCTL :: "msgctl"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
msgqnum_t :: distinct c.ulong
|
||||
msglen_t :: distinct c.ulong
|
||||
|
||||
MSG_NOERROR :: 0o10000
|
||||
|
||||
// NOTE: this is #pragma pack(4)
|
||||
|
||||
msqid_ds :: struct #align(4) {
|
||||
msg_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
msg_first: c.int32_t,
|
||||
msg_last: c.int32_t,
|
||||
msg_cbytes: msglen_t,
|
||||
msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */
|
||||
msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */
|
||||
msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */
|
||||
msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */
|
||||
msg_stime: time_t, /* [PSX] time of last msgsnd() */
|
||||
msg_pad1: c.int32_t,
|
||||
using _: struct #align(4) {
|
||||
msg_rtime: time_t, /* [PSX] time of last msgrcv() */
|
||||
msg_pad2: c.int32_t,
|
||||
using _: struct #align(4) {
|
||||
msg_ctime: time_t, /* [PSX] time of last change */
|
||||
msg_pad3: c.int32_t,
|
||||
msg_pad4: [4]c.int32_t,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
msgqnum_t :: distinct c.ulong
|
||||
msglen_t :: distinct c.ulong
|
||||
|
||||
MSG_NOERROR :: 0o10000
|
||||
|
||||
msqid_ds :: struct {
|
||||
msg_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
__msg_first: rawptr,
|
||||
__msg_last: rawptr,
|
||||
msg_cbytes: msglen_t,
|
||||
msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */
|
||||
msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */
|
||||
msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */
|
||||
msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */
|
||||
msg_stime: time_t, /* [PSX] time of last msgsnd() */
|
||||
msg_rtime: time_t, /* [PSX] time of last msgrcv() */
|
||||
msg_ctime: time_t, /* [PSX] time of last change */
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
msgqnum_t :: distinct c.ulong
|
||||
msglen_t :: distinct c.size_t
|
||||
|
||||
MSG_NOERROR :: 0o10000
|
||||
|
||||
msqid_ds :: struct {
|
||||
msg_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */
|
||||
msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */
|
||||
msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */
|
||||
msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */
|
||||
msg_stime: time_t, /* [PSX] time of last msgsnd() */
|
||||
msg_rtime: time_t, /* [PSX] time of last msgrcv() */
|
||||
msg_ctime: time_t, /* [PSX] time of last change */
|
||||
|
||||
_msg_first: rawptr,
|
||||
_msg_last: rawptr,
|
||||
_msg_cbytes: msglen_t,
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
msgqnum_t :: distinct c.ulong
|
||||
msglen_t :: distinct c.ulong
|
||||
|
||||
MSG_NOERROR :: 0o10000
|
||||
|
||||
msqid_ds :: struct {
|
||||
msg_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
__msg_first: rawptr,
|
||||
__msg_last: rawptr,
|
||||
msg_cbytes: msglen_t,
|
||||
msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */
|
||||
msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */
|
||||
msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */
|
||||
msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */
|
||||
msg_stime: time_t, /* [PSX] time of last msgsnd() */
|
||||
msg_pad1: c.long,
|
||||
msg_rtime: time_t, /* [PSX] time of last msgrcv() */
|
||||
msg_pad2: c.long,
|
||||
msg_ctime: time_t, /* [PSX] time of last change */
|
||||
msg_pad3: c.long,
|
||||
msg_pad4: [4]c.long,
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
152
core/sys/posix/sys_resource.odin
Normal file
152
core/sys/posix/sys_resource.odin
Normal file
@@ -0,0 +1,152 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/resource.h - definitions XSI resource operations
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Gets the nice value of the process, process group or user given.
|
||||
|
||||
Note that a nice value can be -1, so checking for an error would mean clearing errno, doing the
|
||||
call and then checking that this returns -1 and it has an errno.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the value otherwise
|
||||
|
||||
Example:
|
||||
pid := posix.getpid()
|
||||
posix.set_errno(.NONE)
|
||||
prio := posix.getpriority(.PROCESS, pid)
|
||||
if err := posix.errno(); prio == -1 && err != .NONE {
|
||||
// Handle error...
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html ]]
|
||||
*/
|
||||
getpriority :: proc(which: Which_Prio, who: id_t) -> c.int ---
|
||||
|
||||
/*
|
||||
Sets the nice value of the process, process group or user given.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html ]]
|
||||
*/
|
||||
setpriority :: proc(which: Which_Prio, who: id_t, value: c.int) -> result ---
|
||||
|
||||
/*
|
||||
Get a resource limit.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html ]]
|
||||
*/
|
||||
getrlimit :: proc(resource: Resource, rlp: ^rlimit) -> result ---
|
||||
|
||||
/*
|
||||
Set a resource limit.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html ]]
|
||||
*/
|
||||
setrlimit :: proc(resource: Resource, rlp: ^rlimit) -> result ---
|
||||
|
||||
/*
|
||||
Get resource usage.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrusage.html ]]
|
||||
*/
|
||||
@(link_name=LGETRUSAGE)
|
||||
getrusage :: proc(who: Which_Usage, rusage: ^rusage) -> result ---
|
||||
}
|
||||
|
||||
Which_Prio :: enum c.int {
|
||||
PROCESS = PRIO_PROCESS,
|
||||
PGRP = PRIO_PGRP,
|
||||
USER = PRIO_USER,
|
||||
}
|
||||
|
||||
Which_Usage :: enum c.int {
|
||||
SELF = RUSAGE_SELF,
|
||||
CHILDREN = RUSAGE_CHILDREN,
|
||||
}
|
||||
|
||||
Resource :: enum c.int {
|
||||
// Maximum byte size of a core file that may be created by a process.
|
||||
CORE = RLIMIT_CORE,
|
||||
// Maximum amount of CPU time, in seconds, used by a process.
|
||||
CPU = RLIMIT_CPU,
|
||||
// Maximum size of data segment of the process, in bytes.
|
||||
DATA = RLIMIT_DATA,
|
||||
// Maximum size of a file, in bytes, that may be created by a process.
|
||||
FSIZE = RLIMIT_FSIZE,
|
||||
// A number one greater than the maximum value that the system may assign to a newly-created descriptor.
|
||||
NOFILE = RLIMIT_NOFILE,
|
||||
// The maximum size of the initial thread's stack, in bytes.
|
||||
STACK = RLIMIT_STACK,
|
||||
// Maximum size of total available memory of the process, in bytes.
|
||||
AS = RLIMIT_AS,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LGETRUSAGE :: "__getrusage50"
|
||||
} else {
|
||||
@(private) LGETRUSAGE :: "getrusage"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
PRIO_PROCESS :: 0
|
||||
PRIO_PGRP :: 1
|
||||
PRIO_USER :: 2
|
||||
|
||||
rlim_t :: distinct c.uint64_t
|
||||
|
||||
RLIM_INFINITY :: (rlim_t(1) << 63) - 1
|
||||
RLIM_SAVED_MAX :: RLIM_INFINITY
|
||||
RLIM_SAVED_CUR :: RLIM_INFINITY
|
||||
|
||||
RUSAGE_SELF :: 0
|
||||
RUSAGE_CHILDREN :: -1
|
||||
|
||||
rlimit :: struct {
|
||||
rlim_cur: rlim_t, /* [PSX] the current (soft) limit */
|
||||
rlim_max: rlim_t, /* [PSX] the hard limit */
|
||||
}
|
||||
|
||||
rusage :: struct {
|
||||
ru_utime: timeval, /* [PSX] user time used */
|
||||
ru_stime: timeval, /* [PSX] system time used */
|
||||
|
||||
// Informational aliases for source compatibility with programs
|
||||
// that need more information than that provided by standards,
|
||||
// and which do not mind being OS-dependent.
|
||||
|
||||
ru_maxrss: c.long, /* max resident set size (PL) */
|
||||
ru_ixrss: c.long, /* integral shared memory size (NU) */
|
||||
ru_idrss: c.long, /* integral unshared data (NU) */
|
||||
ru_isrss: c.long, /* integral unshared stack (NU) */
|
||||
ru_minflt: c.long, /* page reclaims (NU) */
|
||||
ru_majflt: c.long, /* page faults (NU) */
|
||||
ru_nswap: c.long, /* swaps (NU) */
|
||||
ru_inblock: c.long, /* block input operations (atomic) */
|
||||
ru_outblock: c.long, /* block output operations (atomic) */
|
||||
ru_msgsnd: c.long, /* messages sent (atomic) */
|
||||
ru_msgrcv: c.long, /* messages received (atomic) */
|
||||
ru_nsignals: c.long, /* signals received (atomic) */
|
||||
ru_nvcsw: c.long, /* voluntary context switches (atomic) */
|
||||
ru_nivcsw: c.long, /* involuntary " */
|
||||
}
|
||||
|
||||
RLIMIT_CORE :: 4
|
||||
RLIMIT_CPU :: 0
|
||||
RLIMIT_DATA :: 2
|
||||
RLIMIT_FSIZE :: 1
|
||||
RLIMIT_NOFILE :: 8
|
||||
RLIMIT_STACK :: 3
|
||||
RLIMIT_AS :: 5 when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD else 10
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
120
core/sys/posix/sys_select.odin
Normal file
120
core/sys/posix/sys_select.odin
Normal file
@@ -0,0 +1,120 @@
|
||||
package posix
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/select.h - select types
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Examines the file descriptor sets to see whether some of their descriptors are ready for writing,
|
||||
or have an exceptional condition pending, respectively.
|
||||
|
||||
Returns: -1 (setting errno) on failure, total amount of bits set in the bit masks otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html ]]
|
||||
*/
|
||||
@(link_name=LPSELECT)
|
||||
pselect :: proc(
|
||||
nfds: c.int,
|
||||
readfds: ^fd_set,
|
||||
writefds: ^fd_set,
|
||||
errorfds: ^fd_set,
|
||||
timeout: ^timespec,
|
||||
sigmask: ^sigset_t,
|
||||
) -> c.int ---
|
||||
|
||||
/*
|
||||
Equivalent to pselect() except a more specific timeout resolution (nanoseconds),
|
||||
does not have a signal mask, and may modify the timeout.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html ]]
|
||||
*/
|
||||
@(link_name=LSELECT)
|
||||
select :: proc(
|
||||
nfds: c.int,
|
||||
readfds: ^fd_set,
|
||||
writefds: ^fd_set,
|
||||
errorfds: ^fd_set,
|
||||
timeout: ^timeval,
|
||||
) -> c.int ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
LPSELECT :: "__pselect50"
|
||||
LSELECT :: "__select50"
|
||||
} else {
|
||||
LPSELECT :: "pselect"
|
||||
LSELECT :: "select"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
suseconds_t :: distinct (c.int32_t when ODIN_OS == .Darwin || ODIN_OS == .NetBSD else c.long)
|
||||
|
||||
timeval :: struct {
|
||||
tv_sec: time_t, /* [PSX] seconds */
|
||||
tv_usec: suseconds_t, /* [PSX] microseconds */
|
||||
}
|
||||
|
||||
// Maximum number of file descriptors in the fd_set structure.
|
||||
FD_SETSIZE :: #config(POSIX_FD_SETSIZE, 256 when ODIN_OS == .NetBSD else 1024)
|
||||
|
||||
@(private)
|
||||
__NFDBITS :: size_of(c.int32_t) * 8
|
||||
|
||||
// NOTE: this seems correct for FreeBSD but they do use a set backed by the long type themselves (thus the align change).
|
||||
@(private)
|
||||
ALIGN :: align_of(c.long) when ODIN_OS == .FreeBSD else align_of(c.int32_t)
|
||||
|
||||
fd_set :: struct #align(ALIGN) {
|
||||
fds_bits: [(FD_SETSIZE / __NFDBITS) when (FD_SETSIZE % __NFDBITS) == 0 else (FD_SETSIZE / __NFDBITS) + 1]c.int32_t,
|
||||
}
|
||||
|
||||
@(private)
|
||||
__check_fd_set :: #force_inline proc "contextless" (_a: FD, _b: rawptr) -> bool {
|
||||
if _a < 0 {
|
||||
set_errno(.EINVAL)
|
||||
}
|
||||
|
||||
if _a >= FD_SETSIZE {
|
||||
set_errno(.EINVAL)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
FD_CLR :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) {
|
||||
if __check_fd_set(_fd, _p) {
|
||||
_p.fds_bits[cast(c.ulong)_fd / __NFDBITS] &= ~cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS))
|
||||
}
|
||||
}
|
||||
|
||||
FD_ISSET :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) -> bool {
|
||||
if __check_fd_set(_fd, _p) {
|
||||
return bool(_p.fds_bits[cast(c.ulong)_fd / __NFDBITS] & cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS)))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
FD_SET :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) {
|
||||
if __check_fd_set(_fd, _p) {
|
||||
_p.fds_bits[cast(c.ulong)_fd / __NFDBITS] |= cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS))
|
||||
}
|
||||
}
|
||||
|
||||
FD_ZERO :: #force_inline proc "contextless" (_p: ^fd_set) {
|
||||
intrinsics.mem_zero(_p, size_of(fd_set))
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
132
core/sys/posix/sys_sem.odin
Normal file
132
core/sys/posix/sys_sem.odin
Normal file
@@ -0,0 +1,132 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/sem.h - XSI semaphore facility
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Provides various semaphore control operation as specified by cmd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semctl.html ]]
|
||||
*/
|
||||
@(link_name=LSEMCTL)
|
||||
semctl :: proc(semid: FD, semnum: c.int, cmd: Sem_Cmd, arg: ^semun = nil) -> c.int ---
|
||||
|
||||
/*
|
||||
Returns the semaphore identifier associated with key.
|
||||
|
||||
Returns: -1 (setting errno) on failure, a semaphore file descriptor otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semget.html ]]
|
||||
*/
|
||||
semget :: proc(key: key_t, nsems: c.int, semflg: IPC_Flags) -> FD ---
|
||||
|
||||
/*
|
||||
Perform atomically a user-defined array of semaphore operations in array order on the set of
|
||||
semaphores associated with the semaphore identifier specified by the argument semid.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semop.html ]]
|
||||
*/
|
||||
semop :: proc(semid: FD, sops: [^]sembuf, nsops: c.size_t) -> result ---
|
||||
}
|
||||
|
||||
Sem_Cmd :: enum c.int {
|
||||
// Returns the value of semncnt.
|
||||
GETNCNT = GETNCNT,
|
||||
// Returns the value of sempid.
|
||||
GETPID = GETPID,
|
||||
// Return the value of semval.
|
||||
GETVAL = GETVAL,
|
||||
// Returns the value of semval for each semaphore in the semaphore set.
|
||||
GETALL = GETALL,
|
||||
// Returns the value of semzcnt.
|
||||
GETZCNT = GETZCNT,
|
||||
// Sets the value of semval to arg.val.
|
||||
SETVAL = SETVAL,
|
||||
// Sets the value of semval for each semaphore in the set.
|
||||
SETALL = SETALL,
|
||||
}
|
||||
|
||||
semun :: struct #raw_union {
|
||||
val: c.int,
|
||||
buf: ^semid_ds,
|
||||
array: [^]c.ushort,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSEMCTL :: "__semctl50"
|
||||
} else {
|
||||
@(private) LSEMCTL :: "semctl"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
SEM_UNDO :: 0o10000
|
||||
|
||||
GETNCNT :: 3
|
||||
GETPID :: 4
|
||||
GETVAL :: 5
|
||||
GETALL :: 6
|
||||
GETZCNT :: 7
|
||||
SETVAL :: 8
|
||||
SETALL :: 9
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
// NOTE: this is #pragma pack(4)
|
||||
|
||||
semid_ds :: struct #align(4) {
|
||||
sem_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
sem_base: c.int32_t, /* 32 bit base ptr for semaphore set */
|
||||
sem_nsems: c.ushort, /* [PSX] number of semaphores in set */
|
||||
sem_otime: time_t, /* [PSX] last semop() */
|
||||
sem_pad1: c.int32_t,
|
||||
using _: struct #align(4) {
|
||||
sem_ctime: time_t, /* [PSX] last time changed by semctl() */
|
||||
sem_pad2: c.int32_t,
|
||||
sem_pad3: [4]c.int32_t,
|
||||
},
|
||||
}
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
semid_ds :: struct {
|
||||
sem_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
sem_base: rawptr, /* 32 bit base ptr for semaphore set */
|
||||
sem_nsems: c.ushort, /* [PSX] number of semaphores in set */
|
||||
sem_otime: time_t, /* [PSX] last semop() */
|
||||
sem_ctime: time_t, /* [PSX] last time changed by semctl() */
|
||||
}
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
semid_ds :: struct {
|
||||
sem_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
sem_nsems: c.ushort, /* [PSX] number of semaphores in set */
|
||||
sem_otime: time_t, /* [PSX] last semop() */
|
||||
sem_ctime: time_t, /* [PSX] last time changed by semctl() */
|
||||
_sem_base: rawptr, /* 32 bit base ptr for semaphore set */
|
||||
}
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
semid_ds :: struct {
|
||||
sem_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
sem_nsems: c.ushort, /* [PSX] number of semaphores in set */
|
||||
sem_otime: time_t, /* [PSX] last semop() */
|
||||
sem_pad1: c.long,
|
||||
sem_ctime: time_t, /* [PSX] last time changed by semctl() */
|
||||
sem_pad2: c.long,
|
||||
sem_pad3: [4]c.long,
|
||||
}
|
||||
}
|
||||
|
||||
sembuf :: struct {
|
||||
sem_num: c.ushort, /* [PSX] semaphore number */
|
||||
sem_op: c.short, /* [PSX] semaphore operation */
|
||||
sem_flg: c.short, /* [PSX] operation flags */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
146
core/sys/posix/sys_shm.odin
Normal file
146
core/sys/posix/sys_shm.odin
Normal file
@@ -0,0 +1,146 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/shm.h = XSI shared memory facility
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Attaches the shared memory segment associated with the identifier
|
||||
into the address space of the calling process.
|
||||
|
||||
Returns: nil (setting errno) on failure, the address otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmat.html ]]
|
||||
*/
|
||||
shmat :: proc(shmid: FD, shmaddr: rawptr, shmflag: SHM_Flags) -> rawptr ---
|
||||
|
||||
/*
|
||||
Provides various shared memory operation as specified by the given cmd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmctl.html ]]
|
||||
*/
|
||||
@(link_name=LSHMCTL)
|
||||
shmctl :: proc(shmid: FD, cmd: IPC_Cmd, buf: ^shmid_ds) -> result ---
|
||||
|
||||
/*
|
||||
Detaches the shared memory segment located at the address specified.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmdt.html ]]
|
||||
*/
|
||||
shmdt :: proc(shmaddr: rawptr) -> result ---
|
||||
|
||||
/*
|
||||
Returns the shared memory identifier associated with key.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the shared memory ID otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html ]]
|
||||
*/
|
||||
shmget :: proc(key: key_t, size: c.size_t, shmflag: SHM_Flags) -> FD ---
|
||||
}
|
||||
|
||||
SHM_Flag_Bits :: enum c.int {
|
||||
RDONLY = log2(SHM_RDONLY),
|
||||
RND = log2(SHM_RND),
|
||||
}
|
||||
SHM_Flags :: bit_set[SHM_Flag_Bits; c.int]
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSHMCTL :: "__shmctl50"
|
||||
} else {
|
||||
@(private) LSHMCTL :: "shmctl"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
SHM_RDONLY :: 0o10000
|
||||
SHM_RND :: 0o20000
|
||||
|
||||
SHMLBA :: 16 * 1024 when ODIN_ARCH == .arm64 else 4096
|
||||
|
||||
shmatt_t :: distinct c.ushort
|
||||
|
||||
// NOTE: this is #pragma pack(4)
|
||||
|
||||
shmid_ds :: struct #align(4) {
|
||||
shm_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
shm_segsz: c.size_t, /* [PSX] size of segment in bytes */
|
||||
shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */
|
||||
shm_cpid: pid_t, /* [PSX] process ID of creator */
|
||||
shm_nattch: shmatt_t, /* [PSX] number of current attaches */
|
||||
using _: struct #align(4) {
|
||||
shm_atime: time_t, /* [PSX] time of last shmat() */
|
||||
shm_dtime: time_t, /* [PSX] time of last shmdt() */
|
||||
shm_ctime: time_t, /* [PSX] time of last change by shmctl() */
|
||||
shm_internal: rawptr,
|
||||
},
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
|
||||
|
||||
SHM_RDONLY :: 0o10000
|
||||
SHM_RND :: 0o20000
|
||||
|
||||
SHMLBA :: PAGESIZE
|
||||
|
||||
shmatt_t :: distinct c.uint
|
||||
|
||||
when ODIN_OS == .FreeBSD {
|
||||
shmid_ds :: struct {
|
||||
shm_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
shm_segsz: c.size_t, /* [PSX] size of segment in bytes */
|
||||
shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */
|
||||
shm_cpid: pid_t, /* [PSX] process ID of creator */
|
||||
shm_nattch: shmatt_t, /* [PSX] number of current attaches */
|
||||
shm_atime: time_t, /* [PSX] time of last shmat() */
|
||||
shm_dtime: time_t, /* [PSX] time of last shmdt() */
|
||||
shm_ctime: time_t, /* [PSX] time of last change by shmctl() */
|
||||
}
|
||||
} else {
|
||||
shmid_ds :: struct {
|
||||
shm_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
shm_segsz: c.size_t, /* [PSX] size of segment in bytes */
|
||||
shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */
|
||||
shm_cpid: pid_t, /* [PSX] process ID of creator */
|
||||
shm_nattch: shmatt_t, /* [PSX] number of current attaches */
|
||||
shm_atime: time_t, /* [PSX] time of last shmat() */
|
||||
shm_dtime: time_t, /* [PSX] time of last shmdt() */
|
||||
shm_ctime: time_t, /* [PSX] time of last change by shmctl() */
|
||||
_shm_internal: rawptr,
|
||||
}
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
SHM_RDONLY :: 0o10000
|
||||
SHM_RND :: 0o20000
|
||||
|
||||
SHMLBA :: 1 << 12
|
||||
|
||||
shmatt_t :: distinct c.short
|
||||
|
||||
shmid_ds :: struct {
|
||||
shm_perm: ipc_perm, /* [PSX] operation permission structure */
|
||||
shm_segsz: c.int, /* [PSX] size of segment in bytes */
|
||||
shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */
|
||||
shm_cpid: pid_t, /* [PSX] process ID of creator */
|
||||
shm_nattch: shmatt_t, /* [PSX] number of current attaches */
|
||||
shm_atime: time_t, /* [PSX] time of last shmat() */
|
||||
__shm_atimensec: c.long,
|
||||
shm_dtime: time_t, /* [PSX] time of last shmdt() */
|
||||
__shm_dtimensec: c.long,
|
||||
shm_ctime: time_t, /* [PSX] time of last change by shmctl() */
|
||||
__shm_ctimensec: c.long,
|
||||
_shm_internal: rawptr,
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
491
core/sys/posix/sys_socket.odin
Normal file
491
core/sys/posix/sys_socket.odin
Normal file
@@ -0,0 +1,491 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
// sys/socket.h - main sockets header
|
||||
|
||||
#assert(Protocol.IP == Protocol(0), "socket() assumes this")
|
||||
|
||||
foreign libc {
|
||||
/*
|
||||
Creates a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, file descriptor of socket otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html ]]
|
||||
*/
|
||||
@(link_name=LSOCKET)
|
||||
socket :: proc(domain: AF, type: Sock, protocol: Protocol = .IP) -> FD ---
|
||||
|
||||
/*
|
||||
Extracts the first connection on the queue of pending connections.
|
||||
|
||||
Blocks (if not O_NONBLOCK) if there is no pending connection.
|
||||
|
||||
Returns: -1 (setting errno) on failure, file descriptor of accepted socket otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html ]]
|
||||
*/
|
||||
accept :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> FD ---
|
||||
|
||||
/*
|
||||
Assigns a local socket address to the socket.
|
||||
|
||||
Example:
|
||||
sfd := posix.socket(.UNIX, .STREAM)
|
||||
if sfd == -1 {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
addr: posix.sockaddr_un
|
||||
addr.sun_family = .UNIX
|
||||
copy(addr.sun_path[:], "/somepath\x00")
|
||||
|
||||
if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html ]]
|
||||
*/
|
||||
bind :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Attempt to make a connection.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html ]]
|
||||
*/
|
||||
connect :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Get the peer address of the specified socket.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html ]]
|
||||
*/
|
||||
getpeername :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Get the socket name.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html ]]
|
||||
*/
|
||||
getsockname :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Retrieves the value for the option specified by option_name.
|
||||
|
||||
level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
|
||||
to specify the socket local level.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html ]]
|
||||
*/
|
||||
getsockopt :: proc(
|
||||
socket: FD,
|
||||
level: c.int,
|
||||
option_name: Sock_Option,
|
||||
option_value: rawptr,
|
||||
option_len: ^socklen_t,
|
||||
) -> result ---
|
||||
|
||||
/*
|
||||
Sets the specified option.
|
||||
|
||||
level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
|
||||
to specify the socket local level.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html ]]
|
||||
*/
|
||||
setsockopt :: proc(
|
||||
socket: FD,
|
||||
level: c.int,
|
||||
option_name: Sock_Option,
|
||||
option_value: rawptr,
|
||||
option_len: socklen_t,
|
||||
) -> result ---
|
||||
|
||||
/*
|
||||
Mark the socket as a socket accepting connections.
|
||||
|
||||
backlog provides a hint to limit the number of connections on the listen queue.
|
||||
Implementation may silently reduce the backlog, additionally `SOMAXCONN` specifies the maximum
|
||||
an implementation has to support.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html ]]
|
||||
*/
|
||||
listen :: proc(socket: FD, backlog: c.int) -> result ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Blocks (besides with O_NONBLOCK) if there is nothing to receive.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html ]]
|
||||
*/
|
||||
recv :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Equivalent to recv() but retrieves the source address too.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html ]]
|
||||
*/
|
||||
recvfrom :: proc(
|
||||
socket: FD,
|
||||
buffer: rawptr,
|
||||
length: c.size_t,
|
||||
flags: Msg_Flags,
|
||||
address: ^sockaddr,
|
||||
address_len: ^socklen_t,
|
||||
) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html ]]
|
||||
*/
|
||||
recvmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html ]]
|
||||
*/
|
||||
send :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html ]]
|
||||
*/
|
||||
sendmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
If the socket is connectionless, the dest_addr is used to send to.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html ]]
|
||||
*/
|
||||
sendto :: proc(
|
||||
socket: FD,
|
||||
message: rawptr,
|
||||
length: c.size_t,
|
||||
flags: Msg_Flags,
|
||||
dest_addr: ^sockaddr,
|
||||
dest_len: socklen_t,
|
||||
) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Shuts down a socket end or both.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html ]]
|
||||
*/
|
||||
shutdown :: proc(socket: FD, how: Shut) -> result ---
|
||||
|
||||
/*
|
||||
Determine wheter a socket is at the out-of-band mark.
|
||||
|
||||
Returns: -1 (setting errno) on failure, 0 if not at the mark, 1 if it is
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sockatmark.html ]]
|
||||
*/
|
||||
sockatmark :: proc(socket: FD) -> c.int ---
|
||||
|
||||
/*
|
||||
Create a pair of connected sockets.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html ]]
|
||||
*/
|
||||
socketpair :: proc(domain: AF, type: Sock, protocol: Protocol, socket_vector: ^[2]FD) -> result ---
|
||||
}
|
||||
|
||||
AF_UNSPEC :: 0
|
||||
|
||||
AF :: enum c.int {
|
||||
// Unspecified.
|
||||
UNSPEC = AF_UNSPEC,
|
||||
// Internet domain sockets for use with IPv4 addresses.
|
||||
INET = AF_INET,
|
||||
// Internet domain sockets for use with IPv6 addresses.
|
||||
INET6 = AF_INET6,
|
||||
// UNIX domain sockets.
|
||||
UNIX = AF_UNIX,
|
||||
}
|
||||
|
||||
sa_family_t :: enum _sa_family_t {
|
||||
// Unspecified.
|
||||
UNSPEC = AF_UNSPEC,
|
||||
// Internet domain sockets for use with IPv4 addresses.
|
||||
INET = AF_INET,
|
||||
// Internet domain sockets for use with IPv6 addresses.
|
||||
INET6 = AF_INET6,
|
||||
// UNIX domain sockets.
|
||||
UNIX = AF_UNIX,
|
||||
}
|
||||
|
||||
Sock :: enum c.int {
|
||||
// Datagram socket.
|
||||
DGRAM = SOCK_DGRAM,
|
||||
// Raw Protocol Interface.
|
||||
RAW = SOCK_RAW,
|
||||
// Sequenced-packet socket.
|
||||
SEQPACKET = SOCK_SEQPACKET,
|
||||
// Byte-stream socket.
|
||||
STREAM = SOCK_STREAM,
|
||||
}
|
||||
|
||||
Shut :: enum c.int {
|
||||
// Disables further receive operations.
|
||||
RD = SHUT_RD,
|
||||
// Disables further send and receive operations.
|
||||
RDWR = SHUT_RDWR,
|
||||
// Disables further send operations.
|
||||
WR = SHUT_WR,
|
||||
}
|
||||
|
||||
Msg_Flag_Bits :: enum c.int {
|
||||
// Control data truncated.
|
||||
CTRUNC = log2(MSG_CTRUNC),
|
||||
// Send without using routing table.
|
||||
DONTROUTE = log2(MSG_DONTROUTE),
|
||||
// Terminates a record (if supported by protocol).
|
||||
EOR = log2(MSG_EOR),
|
||||
// Out-of-band data.
|
||||
OOB = log2(MSG_OOB),
|
||||
// No SIGPIPE is generated when an attempt to send is made on a stream-oriented socket that is
|
||||
// no longer connected.
|
||||
NOSIGNAL = log2(MSG_NOSIGNAL),
|
||||
// Leave received data in queue.
|
||||
PEEK = log2(MSG_PEEK),
|
||||
// Normal data truncated.
|
||||
TRUNC = log2(MSG_TRUNC),
|
||||
// Attempt to fill the read buffer.
|
||||
WAITALL = log2(MSG_WAITALL),
|
||||
}
|
||||
Msg_Flags :: bit_set[Msg_Flag_Bits; c.int]
|
||||
|
||||
Sock_Option :: enum c.int {
|
||||
// Transmission of broadcast message is supported.
|
||||
BROADCAST = SO_BROADCAST,
|
||||
// Debugging information is being recorded.
|
||||
DEBUG = SO_DEBUG,
|
||||
// Bypass normal routing.
|
||||
DONTROUTE = SO_DONTROUTE,
|
||||
// Socket error status.
|
||||
ERROR = SO_ERROR,
|
||||
// Connections are kept alive with periodic messages.
|
||||
KEEPALIVE = SO_KEEPALIVE,
|
||||
// Socket lingers on close.
|
||||
LINGER = SO_LINGER,
|
||||
// Out-of-band data is transmitted in line.
|
||||
OOBINLINE = SO_OOBINLINE,
|
||||
// Receive buffer size.
|
||||
RCVBUF = SO_RCVBUF,
|
||||
// Receive low water mark.
|
||||
RCVLOWAT = SO_RCVLOWAT,
|
||||
// Receive timeout.
|
||||
RCVTIMEO = SO_RCVTIMEO,
|
||||
// Reuse of local addresses is supported.
|
||||
REUSEADDR = SO_REUSEADDR,
|
||||
// Send buffer size.
|
||||
SNDBUF = SO_SNDBUF,
|
||||
// Send low water mark.
|
||||
SNDLOWAT = SO_SNDLOWAT,
|
||||
// Send timeout.
|
||||
SNDTIMEO = SO_SNDTIMEO,
|
||||
// Socket type.
|
||||
TYPE = SO_TYPE,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSOCKET :: "__socket30"
|
||||
} else {
|
||||
@(private) LSOCKET :: "socket"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
socklen_t :: distinct c.uint
|
||||
|
||||
_sa_family_t :: distinct c.uint8_t
|
||||
|
||||
sockaddr :: struct {
|
||||
sa_len: c.uint8_t, /* total length */
|
||||
sa_family: sa_family_t, /* [PSX] address family */
|
||||
sa_data: [14]c.char, /* [PSX] socket address */
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
@(private)
|
||||
_SS_PAD1SIZE :: 6
|
||||
@(private)
|
||||
_SS_PAD2SIZE :: 240
|
||||
} else {
|
||||
@(private)
|
||||
_SS_MAXSIZE :: 128
|
||||
@(private)
|
||||
_SS_ALIGNSIZE :: size_of(c.int64_t)
|
||||
@(private)
|
||||
_SS_PAD1SIZE :: _SS_ALIGNSIZE - size_of(c.uint8_t) - size_of(sa_family_t)
|
||||
@(private)
|
||||
_SS_PAD2SIZE :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE
|
||||
}
|
||||
|
||||
sockaddr_storage :: struct {
|
||||
ss_len: c.uint8_t, /* address length */
|
||||
ss_family: sa_family_t, /* [PSX] address family */
|
||||
__ss_pad1: [_SS_PAD1SIZE]c.char,
|
||||
__ss_align: c.int64_t, /* force structure storage alignment */
|
||||
__ss_pad2: [_SS_PAD2SIZE]c.char,
|
||||
}
|
||||
|
||||
msghdr :: struct {
|
||||
msg_name: rawptr, /* [PSX] optional address */
|
||||
msg_namelen: socklen_t, /* [PSX] size of address */
|
||||
msg_iov: [^]iovec, /* [PSX] scatter/gather array */
|
||||
msg_iovlen: c.int, /* [PSX] members in msg_iov */
|
||||
msg_control: rawptr, /* [PSX] ancillary data */
|
||||
msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */
|
||||
msg_flags: Msg_Flags, /* [PSX] flags on received message */
|
||||
}
|
||||
|
||||
cmsghdr :: struct {
|
||||
cmsg_len: socklen_t, /* [PSX] data byte count, including cmsghdr */
|
||||
cmsg_level: c.int, /* [PSX] originating protocol */
|
||||
cmsg_type: c.int, /* [PSX] protocol-specific type */
|
||||
}
|
||||
|
||||
SCM_RIGHTS :: 0x01
|
||||
|
||||
@(private)
|
||||
__ALIGN32 :: #force_inline proc "contextless" (p: uintptr) -> uintptr {
|
||||
__ALIGNBYTES32 :: size_of(c.uint32_t) - 1
|
||||
return (p + __ALIGNBYTES32) &~ __ALIGNBYTES32
|
||||
}
|
||||
|
||||
// Returns a pointer to the data array.
|
||||
CMSG_DATA :: #force_inline proc "contextless" (cmsg: ^cmsghdr) -> [^]c.uchar {
|
||||
return ([^]c.uchar)(uintptr(cmsg) + __ALIGN32(size_of(cmsghdr)))
|
||||
}
|
||||
|
||||
// Returns a pointer to the next cmsghdr or nil.
|
||||
CMSG_NXTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr, cmsg: ^cmsghdr) -> ^cmsghdr {
|
||||
if cmsg == nil {
|
||||
return CMSG_FIRSTHDR(mhdr)
|
||||
}
|
||||
|
||||
ptr := uintptr(cmsg) + __ALIGN32(uintptr(cmsg.cmsg_len))
|
||||
if ptr + __ALIGN32(size_of(cmsghdr)) > uintptr(mhdr.msg_control) + uintptr(mhdr.msg_controllen) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (^cmsghdr)(ptr)
|
||||
}
|
||||
|
||||
// Returns a pointer to the first cmsghdr or nil.
|
||||
CMSG_FIRSTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr) -> ^cmsghdr {
|
||||
if mhdr.msg_controllen >= size_of(cmsghdr) {
|
||||
return (^cmsghdr)(mhdr.msg_control)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
linger :: struct {
|
||||
l_onoff: c.int, /* [PSX] indicates whether linger option is enabled */
|
||||
l_linger: c.int, /* [PSX] linger time in seconds */
|
||||
}
|
||||
|
||||
SOCK_DGRAM :: 2
|
||||
SOCK_RAW :: 3
|
||||
SOCK_SEQPACKET :: 5
|
||||
SOCK_STREAM :: 1
|
||||
|
||||
// Options to be accessed at socket level, not protocol level.
|
||||
SOL_SOCKET :: 0xffff
|
||||
|
||||
SO_ACCEPTCONN :: 0x0002
|
||||
SO_BROADCAST :: 0x0020
|
||||
SO_DEBUG :: 0x0001
|
||||
SO_DONTROUTE :: 0x0010
|
||||
SO_ERROR :: 0x1007
|
||||
SO_KEEPALIVE :: 0x0008
|
||||
SO_OOBINLINE :: 0x0100
|
||||
SO_RCVBUF :: 0x1002
|
||||
SO_RCVLOWAT :: 0x1004
|
||||
SO_REUSEADDR :: 0x0004
|
||||
SO_SNDBUF :: 0x1001
|
||||
SO_SNDLOWAT :: 0x1003
|
||||
SO_TYPE :: 0x1008
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
||||
SO_LINGER :: 0x1080
|
||||
SO_RCVTIMEO :: 0x1006
|
||||
SO_SNDTIMEO :: 0x1005
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
SO_LINGER :: 0x0080
|
||||
SO_RCVTIMEO :: 0x100c
|
||||
SO_SNDTIMEO :: 0x100b
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
SO_LINGER :: 0x0080
|
||||
SO_RCVTIMEO :: 0x1006
|
||||
SO_SNDTIMEO :: 0x1005
|
||||
}
|
||||
|
||||
// The maximum backlog queue length for listen().
|
||||
SOMAXCONN :: 128
|
||||
|
||||
MSG_CTRUNC :: 0x20
|
||||
MSG_DONTROUTE :: 0x4
|
||||
MSG_EOR :: 0x8
|
||||
MSG_OOB :: 0x1
|
||||
MSG_PEEK :: 0x2
|
||||
MSG_TRUNC :: 0x10
|
||||
MSG_WAITALL :: 0x40
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
MSG_NOSIGNAL :: 0x80000
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
MSG_NOSIGNAL :: 0x00020000
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
MSG_NOSIGNAL :: 0x0400
|
||||
}
|
||||
|
||||
AF_INET :: 2
|
||||
AF_UNIX :: 1
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
AF_INET6 :: 30
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
AF_INET6 :: 28
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
AF_INET6 :: 24
|
||||
}
|
||||
|
||||
SHUT_RD :: 0
|
||||
SHUT_RDWR :: 2
|
||||
SHUT_WR :: 1
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
|
||||
540
core/sys/posix/sys_stat.odin
Normal file
540
core/sys/posix/sys_stat.odin
Normal file
@@ -0,0 +1,540 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/stat.h - data returned by the stat() function
|
||||
|
||||
foreign lib {
|
||||
|
||||
/*
|
||||
Equivalent to either stat or lstat (based on the SYMLINK_NOFOLLOW bit in flags)
|
||||
but resolves relative paths based on the given fd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]]
|
||||
*/
|
||||
@(link_name="fstatat" + INODE_SUFFIX)
|
||||
fstatat :: proc(fd: FD, path: cstring, buf: ^stat_t, flag: AT_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Obtain information about a "file" at the given path.
|
||||
|
||||
Follows symbolic links.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]]
|
||||
*/
|
||||
@(link_name=LSTAT)
|
||||
stat :: proc(path: cstring, buf: ^stat_t) -> result ---
|
||||
|
||||
/*
|
||||
Obtain information about an open file.
|
||||
|
||||
Follows symbol links.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstat.html ]]
|
||||
*/
|
||||
@(link_name=LFSTAT)
|
||||
fstat :: proc(fildes: FD, buf: ^stat_t) -> result ---
|
||||
|
||||
/*
|
||||
Obtain information about a "file" at the given path.
|
||||
|
||||
Does not follow symlinks (will stat the symlink itself).
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]]
|
||||
*/
|
||||
@(link_name=LLSTAT)
|
||||
lstat :: proc(path: cstring, buf: ^stat_t) -> result ---
|
||||
|
||||
/*
|
||||
Change the mode of a file.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html ]]
|
||||
*/
|
||||
chmod :: proc(path: cstring, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to chmod but takes an open file descriptor.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html ]]
|
||||
*/
|
||||
fchmod :: proc(fd: FD, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to chmod but follows (or doesn't) symlinks based on the flag and resolves
|
||||
relative paths from the given fd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html ]]
|
||||
*/
|
||||
fchmodat :: proc(fd: FD, path: cstring, mode: mode_t, flag: AT_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Make a directory.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html ]]
|
||||
*/
|
||||
mkdir :: proc(path: cstring, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to mkdir but relative paths are relative to fd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html ]]
|
||||
*/
|
||||
mkdirat :: proc(fd: FD, path: cstring, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Make a FIFO special file.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html ]]
|
||||
*/
|
||||
mkfifo :: proc(path: cstring, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to mkfifo but relative paths are relative to fd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html ]]
|
||||
*/
|
||||
mkfifoat :: proc(fd: FD, path: cstring, mode: mode_t) -> result ---
|
||||
|
||||
/*
|
||||
Make directory, special file, or regular file.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html ]]
|
||||
*/
|
||||
@(link_name=LMKNOD)
|
||||
mknod :: proc(path: cstring, mode: mode_t, dev: dev_t) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to mknod but relative paths are relative to fd.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html ]]
|
||||
*/
|
||||
mknodat :: proc(fd: FD, path: cstring, mode: mode_t, dev: dev_t) -> result ---
|
||||
|
||||
/*
|
||||
Sets the file access and modification time of the given file descriptor.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html ]]
|
||||
*/
|
||||
futimens :: proc(fd: FD, times: ^[2]timespec) -> result ---
|
||||
|
||||
/*
|
||||
Equivalent to futimens.
|
||||
Relative directories are based on fd.
|
||||
Symlinks may or may not be followed based on the flags.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html ]]
|
||||
*/
|
||||
utimensat :: proc(fd: FD, path: cstring, times: ^[2]timespec, flag: AT_Flags) -> result ---
|
||||
|
||||
/*
|
||||
Set and get the file mode creation flags.
|
||||
|
||||
Makes the file mode permissions bits in cmask the new default for the process.
|
||||
|
||||
Returns: the previous value
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/umask.html ]]
|
||||
*/
|
||||
umask :: proc(cmask: mode_t) -> mode_t ---
|
||||
}
|
||||
|
||||
// Read, write, execute user.
|
||||
S_IRWXU :: mode_t{ .IRUSR, .IWUSR, .IXUSR }
|
||||
// Read, write, execute group.
|
||||
S_IRWXG :: mode_t{ .IRGRP, .IWGRP, .IXGRP }
|
||||
// Read, write, execute other.
|
||||
S_IRWXO :: mode_t{ .IROTH, .IWOTH, .IXOTH }
|
||||
|
||||
Mode_Bits :: enum c.int {
|
||||
// File type:
|
||||
|
||||
IFBLK = log2(S_IFBLK), /* Block special */
|
||||
IFCHR = log2(S_IFCHR), /* Character special */
|
||||
IFIFO = log2(S_IFIFO), /* FIFO special */
|
||||
IFREG = log2(S_IFREG), /* Regular */
|
||||
IFDIR = log2(S_IFDIR), /* Directory */
|
||||
IFLNK = log2(S_IFLNK), /* Symbolic link */
|
||||
IFSOCK = log2(S_IFSOCK), /* Socket */
|
||||
|
||||
// Permissions:
|
||||
|
||||
IRUSR = log2(_S_IRUSR), /* R for owner */
|
||||
IWUSR = log2(_S_IWUSR), /* W for owner */
|
||||
IXUSR = log2(_S_IXUSR), /* X for owner */
|
||||
|
||||
IRGRP = log2(_S_IRGRP), /* R for group */
|
||||
IWGRP = log2(_S_IWGRP), /* W for group */
|
||||
IXGRP = log2(_S_IXGRP), /* X for group */
|
||||
|
||||
IROTH = log2(_S_IROTH), /* R for other */
|
||||
IWOTH = log2(_S_IWOTH), /* W for other */
|
||||
IXOTH = log2(_S_IXOTH), /* X for other */
|
||||
|
||||
ISUID = log2(_S_ISUID), /* Set user ID on execution */
|
||||
ISGID = log2(_S_ISGID), /* Set group ID on execution */
|
||||
ISVXT = log2(_S_ISVTX), /* On directories, restricted deletion flag */
|
||||
}
|
||||
mode_t :: bit_set[Mode_Bits; _mode_t]
|
||||
#assert(size_of(mode_t) == size_of(_mode_t))
|
||||
|
||||
// NOTE: making these `.IFREG in m` would probably be fine too,
|
||||
// but implementations make this an exclusive check so lets stick to it.
|
||||
|
||||
_S_IFMT :: mode_t{ .IFBLK, .IFCHR, .IFIFO, .IFREG, .IFDIR, .IFLNK, .IFSOCK }
|
||||
|
||||
// Test for a block special file.
|
||||
S_ISBLK :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFBLK }
|
||||
}
|
||||
|
||||
// Test for a character special file.
|
||||
S_ISCHR :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFCHR }
|
||||
}
|
||||
|
||||
// Test for a pipe or FIFO special file.
|
||||
S_ISFIFO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFIFO }
|
||||
}
|
||||
|
||||
// Test for a regular file.
|
||||
S_ISREG :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFREG }
|
||||
}
|
||||
|
||||
// Test for a directory.
|
||||
S_ISDIR :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFDIR }
|
||||
}
|
||||
|
||||
// Test for a symbolic link.
|
||||
S_ISLNK :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFLNK }
|
||||
}
|
||||
|
||||
// Test for a socket.
|
||||
S_ISSOCK :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return (m & _S_IFMT) == { .IFSOCK }
|
||||
}
|
||||
|
||||
// Test for a message queue.
|
||||
S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return _S_TYPEISMQ(m)
|
||||
}
|
||||
|
||||
// Test for a semaphore.
|
||||
S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return _S_TYPEISSEM(m)
|
||||
}
|
||||
|
||||
// Test for a shared memory object.
|
||||
S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return _S_TYPEISSHM(m)
|
||||
}
|
||||
|
||||
// Test macro for a typed memory object.
|
||||
S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return _S_TYPEISTMO(m)
|
||||
}
|
||||
|
||||
_S_IRWXU :: 0o000700
|
||||
_S_IRUSR :: 0o000400
|
||||
_S_IWUSR :: 0o000200
|
||||
_S_IXUSR :: 0o000100
|
||||
|
||||
_S_IRWXG :: 0o000070
|
||||
_S_IRGRP :: 0o000040
|
||||
_S_IWGRP :: 0o000020
|
||||
_S_IXGRP :: 0o000010
|
||||
|
||||
_S_IRWXO :: 0o000007
|
||||
_S_IROTH :: 0o000004
|
||||
_S_IWOTH :: 0o000002
|
||||
_S_IXOTH :: 0o000001
|
||||
|
||||
_S_ISUID :: 0o004000
|
||||
_S_ISGID :: 0o002000
|
||||
_S_ISVTX :: 0o001000
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSTAT :: "__stat50"
|
||||
@(private) LFSTAT :: "__fstat50"
|
||||
@(private) LLSTAT :: "__lstat50"
|
||||
@(private) LMKNOD :: "__mknod50"
|
||||
} else {
|
||||
@(private) LSTAT :: "stat" + INODE_SUFFIX
|
||||
@(private) LFSTAT :: "fstat" + INODE_SUFFIX
|
||||
@(private) LLSTAT :: "lstat" + INODE_SUFFIX
|
||||
@(private) LMKNOD :: "mknod"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
dev_t :: distinct c.int32_t
|
||||
nlink_t :: distinct c.uint16_t
|
||||
_mode_t :: distinct c.uint16_t
|
||||
blkcnt_t :: distinct c.int64_t
|
||||
blksize_t :: distinct c.int32_t
|
||||
ino_t :: distinct c.uint64_t
|
||||
|
||||
stat_t :: struct {
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_mode: mode_t, /* [XSI] mode of file */
|
||||
st_nlink: nlink_t, /* [XSI] number of hard links */
|
||||
st_ino: ino_t, /* [XSI] file serial number */
|
||||
st_uid: uid_t, /* [XSI] user ID of the file */
|
||||
st_gid: gid_t, /* [XSI] group ID of the file */
|
||||
st_rdev: dev_t, /* [XSI] device ID */
|
||||
st_atim: timespec, /* [XSI] time of last access */
|
||||
st_mtim: timespec, /* [XSI] time of last data modification */
|
||||
st_ctim: timespec, /* [XSI] time of last status change */
|
||||
st_birthtimespec: timespec, /* time of file creation(birth) */
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: c.uint32_t, /* user defined flags for file */
|
||||
st_gen: c.uint32_t, /* file generation number */
|
||||
st_lspare: c.int32_t, /* RESERVED */
|
||||
st_qspare: [2]c.int64_t, /* RESERVED */
|
||||
}
|
||||
|
||||
S_IFBLK :: 0o060000
|
||||
S_IFCHR :: 0o020000
|
||||
S_IFIFO :: 0o010000
|
||||
S_IFREG :: 0o100000
|
||||
S_IFDIR :: 0o040000
|
||||
S_IFLNK :: 0o120000
|
||||
S_IFSOCK :: 0o140000
|
||||
|
||||
__S_IFMT :: 0o170000
|
||||
|
||||
_S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
UTIME_NOW :: -1
|
||||
UTIME_OMIT :: -2
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
dev_t :: distinct c.uint64_t
|
||||
nlink_t :: distinct c.uint64_t
|
||||
_mode_t :: distinct c.uint16_t
|
||||
blkcnt_t :: distinct c.int64_t
|
||||
blksize_t :: distinct c.int32_t
|
||||
ino_t :: distinct c.uint64_t
|
||||
|
||||
when ODIN_ARCH == .i386 {
|
||||
stat_t :: struct {
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_ino: ino_t, /* [XSI] file serial number */
|
||||
st_nlink: nlink_t, /* [XSI] number of hard links */
|
||||
st_mode: mode_t, /* [XSI] mode of file */
|
||||
st_padding0: c.int16_t,
|
||||
st_uid: uid_t, /* [XSI] user ID of the file */
|
||||
st_gid: gid_t, /* [XSI] group ID of the file */
|
||||
st_padding1: c.int32_t,
|
||||
st_rdev: dev_t, /* [XSI] device ID */
|
||||
st_atim_ext: c.int32_t,
|
||||
st_atim: timespec, /* [XSI] time of last access */
|
||||
st_mtim_ext: c.int32_t,
|
||||
st_mtim: timespec, /* [XSI] time of last data modification */
|
||||
st_ctim_ext: c.int32_t,
|
||||
st_ctim: timespec, /* [XSI] time of last status change */
|
||||
st_birthtimespec: timespec, /* time of file creation(birth) */
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: c.uint32_t, /* user defined flags for file */
|
||||
st_gen: c.uint64_t,
|
||||
st_spare: [10]c.uint64_t,
|
||||
}
|
||||
} else {
|
||||
stat_t :: struct {
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_ino: ino_t, /* [XSI] file serial number */
|
||||
st_nlink: nlink_t, /* [XSI] number of hard links */
|
||||
st_mode: mode_t, /* [XSI] mode of file */
|
||||
st_padding0: c.int16_t,
|
||||
st_uid: uid_t, /* [XSI] user ID of the file */
|
||||
st_gid: gid_t, /* [XSI] group ID of the file */
|
||||
st_padding1: c.int32_t,
|
||||
st_rdev: dev_t, /* [XSI] device ID */
|
||||
st_atim: timespec, /* [XSI] time of last access */
|
||||
st_mtim: timespec, /* [XSI] time of last data modification */
|
||||
st_ctim: timespec, /* [XSI] time of last status change */
|
||||
st_birthtimespec: timespec, /* time of file creation(birth) */
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: c.uint32_t, /* user defined flags for file */
|
||||
st_gen: c.uint64_t,
|
||||
st_spare: [10]c.uint64_t,
|
||||
}
|
||||
}
|
||||
|
||||
S_IFBLK :: 0o060000
|
||||
S_IFCHR :: 0o020000
|
||||
S_IFIFO :: 0o010000
|
||||
S_IFREG :: 0o100000
|
||||
S_IFDIR :: 0o040000
|
||||
S_IFLNK :: 0o120000
|
||||
S_IFSOCK :: 0o140000
|
||||
|
||||
__S_IFMT :: 0o170000
|
||||
|
||||
_S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
UTIME_NOW :: -1
|
||||
UTIME_OMIT :: -2
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
dev_t :: distinct c.uint64_t
|
||||
nlink_t :: distinct c.uint32_t
|
||||
_mode_t :: distinct c.uint32_t
|
||||
blkcnt_t :: distinct c.int64_t
|
||||
blksize_t :: distinct c.int32_t
|
||||
ino_t :: distinct c.uint64_t
|
||||
|
||||
stat_t :: struct {
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_mode: mode_t, /* [XSI] mode of file */
|
||||
st_ino: ino_t, /* [XSI] file serial number */
|
||||
st_nlink: nlink_t, /* [XSI] number of hard links */
|
||||
st_uid: uid_t, /* [XSI] user ID of the file */
|
||||
st_gid: gid_t, /* [XSI] group ID of the file */
|
||||
st_rdev: dev_t, /* [XSI] device ID */
|
||||
st_atim: timespec, /* [XSI] time of last access */
|
||||
st_mtim: timespec, /* [XSI] time of last data modification */
|
||||
st_ctim: timespec, /* [XSI] time of last status change */
|
||||
st_birthtimespec: timespec, /* time of file creation(birth) */
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: c.uint32_t, /* user defined flags for file */
|
||||
st_gen: c.uint64_t,
|
||||
st_spare: [2]c.uint32_t,
|
||||
}
|
||||
|
||||
S_IFBLK :: 0o060000
|
||||
S_IFCHR :: 0o020000
|
||||
S_IFIFO :: 0o010000
|
||||
S_IFREG :: 0o100000
|
||||
S_IFDIR :: 0o040000
|
||||
S_IFLNK :: 0o120000
|
||||
S_IFSOCK :: 0o140000
|
||||
|
||||
__S_IFMT :: 0o170000
|
||||
|
||||
_S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
UTIME_NOW :: (1 << 30) - 1
|
||||
UTIME_OMIT :: (1 << 30) - 2
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
dev_t :: distinct c.int32_t
|
||||
nlink_t :: distinct c.uint32_t
|
||||
_mode_t :: distinct c.uint32_t
|
||||
blkcnt_t :: distinct c.int64_t
|
||||
blksize_t :: distinct c.int32_t
|
||||
ino_t :: distinct c.uint64_t
|
||||
|
||||
stat_t :: struct {
|
||||
st_mode: mode_t, /* [XSI] mode of file */
|
||||
st_dev: dev_t, /* [XSI] ID of device containing file */
|
||||
st_ino: ino_t, /* [XSI] file serial number */
|
||||
st_nlink: nlink_t, /* [XSI] number of hard links */
|
||||
st_uid: uid_t, /* [XSI] user ID of the file */
|
||||
st_gid: gid_t, /* [XSI] group ID of the file */
|
||||
st_rdev: dev_t, /* [XSI] device ID */
|
||||
st_atim: timespec, /* [XSI] time of last access */
|
||||
st_mtim: timespec, /* [XSI] time of last data modification */
|
||||
st_ctim: timespec, /* [XSI] time of last status change */
|
||||
st_size: off_t, /* [XSI] file size, in bytes */
|
||||
st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */
|
||||
st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */
|
||||
st_flags: c.uint32_t, /* user defined flags for file */
|
||||
st_gen: c.int32_t,
|
||||
st_birthtimespec: timespec,
|
||||
}
|
||||
|
||||
S_IFBLK :: 0o060000
|
||||
S_IFCHR :: 0o020000
|
||||
S_IFIFO :: 0o010000
|
||||
S_IFREG :: 0o100000
|
||||
S_IFDIR :: 0o040000
|
||||
S_IFLNK :: 0o120000
|
||||
S_IFSOCK :: 0o140000
|
||||
|
||||
__S_IFMT :: 0o170000
|
||||
|
||||
_S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
_S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
UTIME_NOW :: -2
|
||||
UTIME_OMIT :: -1
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
135
core/sys/posix/sys_statvfs.odin
Normal file
135
core/sys/posix/sys_statvfs.odin
Normal file
@@ -0,0 +1,135 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/statvfs.h - VFS File System information structure
|
||||
|
||||
foreign lib {
|
||||
|
||||
/*
|
||||
Obtains information about the file system containing the fildes.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html ]]
|
||||
*/
|
||||
@(link_name=LFSTATVFS)
|
||||
fstatvfs :: proc(fildes: FD, buf: ^statvfs_t) -> result ---
|
||||
|
||||
/*
|
||||
Obtains information about the file system containing the file named by path.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html ]]
|
||||
*/
|
||||
@(link_name=LSTATVFS)
|
||||
statvfs :: proc(path: cstring, buf: ^statvfs_t) -> result ---
|
||||
}
|
||||
|
||||
VFS_Flag_Bits :: enum c.ulong {
|
||||
// Read-only file system.
|
||||
RDONLY = log2(ST_RDONLY),
|
||||
// Does not support the semantics of the ST_ISUID and ST_ISGID file mode bits.
|
||||
NOSUID = log2(ST_NOSUID),
|
||||
}
|
||||
VFS_Flags :: bit_set[VFS_Flag_Bits; c.ulong]
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LFSTATVFS :: "__fstatvfs90"
|
||||
@(private) LSTATVFS :: "__statvfs90"
|
||||
} else {
|
||||
@(private) LFSTATVFS :: "fstatvfs"
|
||||
@(private) LSTATVFS :: "statvfs"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||
|
||||
fsblkcnt_t :: distinct c.uint
|
||||
|
||||
statvfs_t :: struct {
|
||||
f_bsize: c.ulong, /* [PSX] file system block size */
|
||||
f_frsize: c.ulong, /* [PSX] fundamental file system block size */
|
||||
f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */
|
||||
f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */
|
||||
f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */
|
||||
f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */
|
||||
f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */
|
||||
f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */
|
||||
f_fsid: c.ulong, /* [PSX] file system ID */
|
||||
f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */
|
||||
f_namemax: c.ulong, /* [PSX] maximum filename length */
|
||||
}
|
||||
|
||||
ST_RDONLY :: 0x00000001
|
||||
ST_NOSUID :: 0x00000002
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
fsblkcnt_t :: distinct c.uint64_t
|
||||
|
||||
statvfs_t :: struct {
|
||||
f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */
|
||||
f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */
|
||||
f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */
|
||||
f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */
|
||||
f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */
|
||||
f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */
|
||||
f_bsize: c.ulong, /* [PSX] file system block size */
|
||||
f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */
|
||||
f_frsize: c.ulong, /* [PSX] fundamental file system block size */
|
||||
f_fsid: c.ulong, /* [PSX] file system ID */
|
||||
f_namemax: c.ulong, /* [PSX] maximum filename length */
|
||||
}
|
||||
|
||||
ST_RDONLY :: 0x00000001
|
||||
ST_NOSUID :: 0x00000002
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
fsblkcnt_t :: distinct c.uint64_t
|
||||
|
||||
@(private)
|
||||
_VFS_NAMELEN :: 1024
|
||||
|
||||
@(private)
|
||||
fsid_t :: struct {
|
||||
__fsid_val: [2]c.int,
|
||||
}
|
||||
|
||||
statvfs_t :: struct {
|
||||
f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */
|
||||
f_bsize: c.ulong, /* [PSX] file system block size */
|
||||
f_frsize: c.ulong, /* [PSX] fundamental file system block size */
|
||||
f_iosize: c.ulong,
|
||||
f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */
|
||||
f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */
|
||||
f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */
|
||||
f_bresvd: fsblkcnt_t,
|
||||
f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */
|
||||
f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */
|
||||
f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */
|
||||
f_fresvd: fsblkcnt_t,
|
||||
f_syncreads: c.uint64_t,
|
||||
f_syncwrites: c.uint64_t,
|
||||
f_asyncreads: c.uint64_t,
|
||||
f_asyncwrites: c.uint64_t,
|
||||
f_fsidx: fsid_t,
|
||||
f_fsid: c.ulong, /* [PSX] file system ID */
|
||||
f_namemax: c.ulong, /* [PSX] maximum filename length */
|
||||
f_owner: uid_t,
|
||||
f_spare: [4]c.uint64_t,
|
||||
f_fstypename: [_VFS_NAMELEN]c.char `fmt:"s,0"`,
|
||||
f_mntonname: [_VFS_NAMELEN]c.char `fmt:"s,0"`,
|
||||
f_mntfromname: [_VFS_NAMELEN]c.char `fmt:"s,0"`,
|
||||
f_mntfromlabel: [_VFS_NAMELEN]c.char `fmt:"s,0"`,
|
||||
}
|
||||
|
||||
ST_RDONLY :: 0x00000001
|
||||
ST_NOSUID :: 0x00000008
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
82
core/sys/posix/sys_time.odin
Normal file
82
core/sys/posix/sys_time.odin
Normal file
@@ -0,0 +1,82 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/time.h - time types
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Store the current value of timer into value.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getitimer.html ]]
|
||||
*/
|
||||
@(link_name=LGETITIMER)
|
||||
getitimer :: proc(which: ITimer, value: ^itimerval) -> result ---
|
||||
|
||||
/*
|
||||
Set the timer to the value given, and store the previous value in ovalue if it is not nil.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getitimer.html ]]
|
||||
*/
|
||||
@(link_name=LSETITIMER)
|
||||
setitimer :: proc(which: ITimer, value: ^itimerval, ovalue: ^itimerval) -> result ---
|
||||
|
||||
/*
|
||||
Obtains the current time.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html ]]
|
||||
*/
|
||||
@(link_name=LGETTIMEOFDAY)
|
||||
gettimeofday :: proc(tp: ^timeval, tzp: rawptr = nil) -> result ---
|
||||
|
||||
/*
|
||||
Sets the access and modification times of the file at the given path.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html ]]
|
||||
*/
|
||||
@(link_name=LUTIMES)
|
||||
utimes :: proc(path: cstring, times: ^[2]timeval) -> result ---
|
||||
}
|
||||
|
||||
ITimer :: enum c.int {
|
||||
// Decrements in real time.
|
||||
REAL = ITIMER_REAL,
|
||||
// Decrements in process virtual time, only when the process is executing.
|
||||
VIRTUAL = ITIMER_VIRTUAL,
|
||||
// Decrements both in process virtual time and when the system is running on
|
||||
// behalf of the process.
|
||||
PROF = ITIMER_PROF,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LGETITIMER :: "__getitimer50"
|
||||
@(private) LSETITIMER :: "__setitimer50"
|
||||
@(private) LGETTIMEOFDAY :: "__gettimeofday50"
|
||||
@(private) LUTIMES :: "__utimes50"
|
||||
} else {
|
||||
@(private) LGETITIMER :: "getitimer"
|
||||
@(private) LSETITIMER :: "setitimer"
|
||||
@(private) LGETTIMEOFDAY :: "gettimeofday"
|
||||
@(private) LUTIMES :: "utimes"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
itimerval :: struct {
|
||||
it_interval: timeval, /* [PSX] timer interval */
|
||||
it_value: timeval, /* [PSX] current value */
|
||||
}
|
||||
|
||||
ITIMER_REAL :: 0
|
||||
ITIMER_VIRTUAL :: 1
|
||||
ITIMER_PROF :: 2
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
38
core/sys/posix/sys_times.odin
Normal file
38
core/sys/posix/sys_times.odin
Normal file
@@ -0,0 +1,38 @@
|
||||
package posix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/times.h - file access and modification times structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Get time accounting information.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the elapsed real time, since an arbitrary point in the past
|
||||
*/
|
||||
@(link_name=LTIMES)
|
||||
times :: proc(buffer: ^tms) -> clock_t ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LTIMES :: "__times13"
|
||||
} else {
|
||||
@(private) LTIMES :: "times"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
tms :: struct {
|
||||
tms_utime: clock_t, /* [PSX] user CPU time */
|
||||
tms_stime: clock_t, /* [PSX] system CPU time */
|
||||
tms_cutime: clock_t, /* [PSX] terminated children user CPU time */
|
||||
tms_cstime: clock_t, /* [PSX] terminated children system CPU time */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
42
core/sys/posix/sys_uio.odin
Normal file
42
core/sys/posix/sys_uio.odin
Normal file
@@ -0,0 +1,42 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
// sys/uio.h - definitions for vector I/O operations
|
||||
|
||||
foreign libc {
|
||||
/*
|
||||
Equivalent to read() but takes a vector of inputs.
|
||||
|
||||
iovcnt can be 0..=IOV_MAX in length.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html ]]
|
||||
*/
|
||||
readv :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Equivalent to write() but takes a vector of inputs.
|
||||
|
||||
iovcnt can be 0..=IOV_MAX in length.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html ]]
|
||||
*/
|
||||
writev :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
iovec :: struct {
|
||||
iov_base: rawptr, /* [PSX] base address of I/O memory region */
|
||||
iov_len: c.size_t, /* [PSX] size of the region iov_base points to */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
17
core/sys/posix/sys_un.odin
Normal file
17
core/sys/posix/sys_un.odin
Normal file
@@ -0,0 +1,17 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
// sys/un.h = definitions for UNIX domain sockets
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
sockaddr_un :: struct {
|
||||
sun_len: c.uchar, /* sockaddr len including nil */
|
||||
sun_family: sa_family_t, /* [PSX] address family */
|
||||
sun_path: [104]c.char, /* [PSX] socket pathname */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
55
core/sys/posix/sys_utsname.odin
Normal file
55
core/sys/posix/sys_utsname.odin
Normal file
@@ -0,0 +1,55 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/utsname.h = system name structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Stores information identifying the current system in the given structure.
|
||||
|
||||
Returns: non-negative on success, -1 (setting errno) on failure
|
||||
|
||||
NOTE: have a look at `core:sys/info` for similar/better system information.
|
||||
|
||||
Example:
|
||||
uname: posix.utsname
|
||||
posix.uname(&uname)
|
||||
fmt.printfln("%#v", uname)
|
||||
|
||||
Possible Output:
|
||||
utsname{
|
||||
sysname = Darwin,
|
||||
nodename = Laytans-MacBook-Pro.local,
|
||||
release = 23.5.0,
|
||||
version = Darwin Kernel Version 23.5.0: Wed May 1 20:16:51 PDT 2024; root:xnu-11331.111.3~1/RELEASE_ARM64_T8103,
|
||||
machine = arm64,
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html ]]
|
||||
*/
|
||||
uname :: proc(uname: ^utsname) -> c.int ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
@(private)
|
||||
_SYS_NAMELEN :: 256
|
||||
|
||||
utsname :: struct {
|
||||
sysname: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */
|
||||
nodename: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of this network node */
|
||||
release: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] release level */
|
||||
version: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] version level */
|
||||
machine: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
380
core/sys/posix/sys_wait.odin
Normal file
380
core/sys/posix/sys_wait.odin
Normal file
@@ -0,0 +1,380 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// sys/wait.h - declarations for waiting
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Obtains status information pertaining to one of the caller's child processes.
|
||||
|
||||
Returns: -1 (setting errno) on failure or signal on calling process, the pid of the process that caused the return otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]]
|
||||
*/
|
||||
wait :: proc(stat_loc: ^c.int) -> pid_t ---
|
||||
|
||||
/*
|
||||
Obtains status information pertaining to the given pid specifier.
|
||||
|
||||
If pid is -1, status is requested for any child process.
|
||||
If pid is greater than 0, it specifies the process ID of a single child process.
|
||||
If pid is 0, it specifies any child process whose process group ID is equal to that of the call.
|
||||
If pid is < -1, status is requested for any child whose process group ID is the absolute value of pid.
|
||||
|
||||
Returns: -1 (setting errno) on failure or signal on calling process, 0 if NOHANG and status is not available, the pid of the process that caused the return otherwise
|
||||
|
||||
Example:
|
||||
// The following example demonstrates the use of waitpid(), fork(), and the macros used to
|
||||
// interpret the status value returned by waitpid() (and wait()). The code segment creates a
|
||||
// child process which does some unspecified work. Meanwhile the parent loops performing calls
|
||||
// to waitpid() to monitor the status of the child. The loop terminates when child termination
|
||||
// is detected.
|
||||
|
||||
child_pid := posix.fork(); switch child_pid {
|
||||
case -1: // `fork` failed.
|
||||
panic("fork failed")
|
||||
|
||||
case 0: // This is the child.
|
||||
|
||||
// Do some work...
|
||||
|
||||
case:
|
||||
for {
|
||||
status: i32
|
||||
wpid := posix.waitpid(child_pid, &status, { .UNTRACED, .CONTINUED })
|
||||
if wpid == -1 {
|
||||
panic("waitpid failure")
|
||||
}
|
||||
|
||||
switch {
|
||||
case posix.WIFEXITED(status):
|
||||
fmt.printfln("child exited, status=%v", posix.WEXITSTATUS(status))
|
||||
case posix.WIFSIGNALED(status):
|
||||
fmt.printfln("child killed (signal %v)", posix.WTERMSIG(status))
|
||||
case posix.WIFSTOPPED(status):
|
||||
fmt.printfln("child stopped (signal %v", posix.WSTOPSIG(status))
|
||||
case posix.WIFCONTINUED(status):
|
||||
fmt.println("child continued")
|
||||
case:
|
||||
// Should never happen.
|
||||
fmt.println("unexpected status (%x)", status)
|
||||
}
|
||||
|
||||
if posix.WIFEXITED(status) || posix.WIFSIGNALED(status) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]]
|
||||
*/
|
||||
waitpid :: proc(pid: pid_t, stat_loc: ^c.int, options: Wait_Flags) -> pid_t ---
|
||||
|
||||
/*
|
||||
Obtains status information pertaining to the given idtype_t and id specifier.
|
||||
|
||||
Returns: 0 if WNOHANG and no status available, 0 if child changed state, -1 (setting errno) on failure
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html ]]
|
||||
*/
|
||||
waitid :: proc(idtype: idtype_t, id: id_t, infop: ^siginfo_t, options: Wait_Flags) -> c.int ---
|
||||
}
|
||||
|
||||
// If terminated normally.
|
||||
WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WIFEXITED(x)
|
||||
}
|
||||
|
||||
// If WIFEXITED is true, returns the exit status.
|
||||
WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return _WEXITSTATUS(x)
|
||||
}
|
||||
|
||||
// If terminated due to an uncaught signal.
|
||||
WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WIFSIGNALED(x)
|
||||
}
|
||||
|
||||
// If WIFSIGNALED is true, returns the signal.
|
||||
WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return _WTERMSIG(x)
|
||||
}
|
||||
|
||||
// If status was returned for a child process that is currently stopped.
|
||||
WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WIFSTOPPED(x)
|
||||
}
|
||||
|
||||
// If WIFSTOPPED, the signal that caused the child process to stop.
|
||||
WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return _WSTOPSIG(x)
|
||||
}
|
||||
|
||||
// If status was returned for a child process that has continued from a job control stop.
|
||||
WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WIFCONTINUED(x)
|
||||
}
|
||||
|
||||
idtype_t :: enum c.int {
|
||||
// Wait for any children and `id` is ignored.
|
||||
P_ALL,
|
||||
// Wait for any child wiith a process group ID equal to `id`.
|
||||
P_PID,
|
||||
// Wait for any child with a process group ID equal to `id`.
|
||||
P_PGID,
|
||||
}
|
||||
|
||||
Wait_Flag_Bits :: enum c.int {
|
||||
// Report the status of any continued child process specified by pid whose status has not been
|
||||
// reported since it continued from a job control stop.
|
||||
CONTINUED = log2(WCONTINUED),
|
||||
// Don't suspend execution of the calling thread if status is not immediately available for one
|
||||
// of the child processes specified by pid.
|
||||
NOHANG = log2(WNOHANG),
|
||||
// The status of any child process specified by pid that are stopped, and whose status has not
|
||||
// yet been reported since they stopped, shall also be reported to the requesting process.
|
||||
UNTRACED = log2(WUNTRACED),
|
||||
|
||||
// Following are only available on `waitid`, not `waitpid`.
|
||||
|
||||
// Wait for processes that have exited.
|
||||
EXITED = log2(WEXITED),
|
||||
// Keep the process whose status is returned in a waitable state, so it may be waited on again.
|
||||
NOWAIT = log2(WNOWAIT),
|
||||
// Children that have stopped upon receipt of a signal, and whose status either hasn't been reported
|
||||
// or has been reported but that report was called with NOWAIT.
|
||||
STOPPED = log2(WSTOPPED),
|
||||
}
|
||||
Wait_Flags :: bit_set[Wait_Flag_Bits; c.int]
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
id_t :: distinct c.uint
|
||||
|
||||
WCONTINUED :: 0x00000010
|
||||
WNOHANG :: 0x00000001
|
||||
WUNTRACED :: 0x00000002
|
||||
|
||||
WEXITED :: 0x00000004
|
||||
WNOWAIT :: 0x00000020
|
||||
WSTOPPED :: 0x00000008
|
||||
|
||||
@(private)
|
||||
_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x & 0o177
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPPED :: 0o177
|
||||
|
||||
@(private)
|
||||
_WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x >> 8
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(_WSTATUS(x))
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) != .SIGCONT
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(x >> 8)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) == .SIGCONT
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
id_t :: distinct c.int64_t
|
||||
|
||||
WCONTINUED :: 4
|
||||
WNOHANG :: 1
|
||||
WUNTRACED :: 2
|
||||
|
||||
WEXITED :: 16
|
||||
WNOWAIT :: 8
|
||||
WSTOPPED :: 2
|
||||
|
||||
@(private)
|
||||
_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x & 0o177
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPPED :: 0o177
|
||||
|
||||
@(private)
|
||||
_WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x >> 8
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 && x != c.int(Signal.SIGCONT)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(_WSTATUS(x))
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == _WSTOPPED
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(x >> 8)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return x == c.int(Signal.SIGCONT)
|
||||
}
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
id_t :: distinct c.uint32_t
|
||||
|
||||
WCONTINUED :: 0x00000010
|
||||
WNOHANG :: 0x00000001
|
||||
WUNTRACED :: 0x00000002
|
||||
|
||||
WEXITED :: 0x00000020
|
||||
WNOWAIT :: 0x00010000
|
||||
WSTOPPED :: 0x00000002
|
||||
|
||||
@(private)
|
||||
_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x & 0o177
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPPED :: 0o177
|
||||
|
||||
@(private)
|
||||
_WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return (x >> 8) & 0x000000ff
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return !WIFSTOPPED(x) && !WIFCONTINUED(x) && !WIFEXITED(x)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(_WSTATUS(x))
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == _WSTOPPED && !WIFCONTINUED(x)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal((x >> 8) & 0xff)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return x == 0xffff
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
id_t :: distinct c.uint32_t
|
||||
|
||||
WCONTINUED :: 0x00000010
|
||||
WNOHANG :: 0x00000001
|
||||
WUNTRACED :: 0x00000002
|
||||
|
||||
WEXITED :: 0x00000020
|
||||
WNOWAIT :: 0x00010000
|
||||
WSTOPPED :: 0x00000002
|
||||
|
||||
@(private)
|
||||
_WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return x & 0o177
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPPED :: 0o177
|
||||
@(private)
|
||||
_WCONTINUED :: 0o177777
|
||||
|
||||
@(private)
|
||||
_WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
|
||||
return (x >> 8) & 0x000000ff
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal(_WSTATUS(x))
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return (x & 0xff) == _WSTOPPED
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
|
||||
return Signal((x >> 8) & 0xff)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
|
||||
return (x & _WCONTINUED) == _WCONTINUED
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
475
core/sys/posix/termios.odin
Normal file
475
core/sys/posix/termios.odin
Normal file
@@ -0,0 +1,475 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// termios.h - define values for termios
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Get the input baud rate.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html ]]
|
||||
*/
|
||||
cfgetispeed :: proc(termios_p: ^termios) -> speed_t ---
|
||||
|
||||
/*
|
||||
Set the input baud rate.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html ]]
|
||||
*/
|
||||
cfsetispeed :: proc(termios_p: ^termios, rate: speed_t) -> result ---
|
||||
|
||||
/*
|
||||
Get the output baud rate.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html ]]
|
||||
*/
|
||||
cfgetospeed :: proc(termios_p: ^termios) -> speed_t ---
|
||||
|
||||
/*
|
||||
Set the output baud rate.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html ]]
|
||||
*/
|
||||
cfsetospeed :: proc(termios_p: ^termios, rate: speed_t) -> result ---
|
||||
|
||||
/*
|
||||
Wait for transmission of output.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html ]]
|
||||
*/
|
||||
tcdrain :: proc(fildes: FD) -> result ---
|
||||
|
||||
/*
|
||||
Suspend or restart the transmission or reception of data.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html ]]
|
||||
*/
|
||||
tcflow :: proc(fildes: FD, action: TC_Action) -> result ---
|
||||
|
||||
/*
|
||||
Flush non-transmitted output data, non-read input data, or both.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html ]]
|
||||
*/
|
||||
tcflush :: proc(fildes: FD, queue_selector: TC_Queue) -> result ---
|
||||
|
||||
/*
|
||||
Get the parameters associated with the terminal.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html ]]
|
||||
*/
|
||||
tcgetattr :: proc(fildes: FD, termios_p: ^termios) -> result ---
|
||||
|
||||
/*
|
||||
Get the process group ID for the session leader for the controlling terminal.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the pid otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html ]]
|
||||
*/
|
||||
tcgetsid :: proc(fildes: FD) -> pid_t ---
|
||||
|
||||
/*
|
||||
Send a break for a specific duration.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html ]]
|
||||
*/
|
||||
tcsendbreak :: proc(fildes: FD, duration: c.int) -> result ---
|
||||
|
||||
/*
|
||||
Set the parameters associated with the terminal.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html ]]
|
||||
*/
|
||||
tcsetattr :: proc(fildes: FD, optional_actions: c.int, termios_p: ^termios) -> result ---
|
||||
}
|
||||
|
||||
Control_Char :: enum c.int {
|
||||
VEOF = VEOF,
|
||||
VEOL = VEOL,
|
||||
VERASE = VERASE,
|
||||
VINTR = VINTR,
|
||||
VKILL = VKILL,
|
||||
VMIN = VMIN,
|
||||
VQUIT = VQUIT,
|
||||
VSTART = VSTART,
|
||||
VSTOP = VSTOP,
|
||||
VSUSP = VSUSP,
|
||||
VTIME = VTIME,
|
||||
|
||||
NCCS = NCCS-1,
|
||||
}
|
||||
#assert(len(#sparse [Control_Char]cc_t) == NCCS)
|
||||
|
||||
CInput_Flag_Bits :: enum tcflag_t {
|
||||
IGNBRK = log2(IGNBRK), /* ignore BREAK condition */
|
||||
BRKINT = log2(BRKINT), /* map BREAK to SIGINTR */
|
||||
IGNPAR = log2(IGNPAR), /* ignore (discard) parity errors */
|
||||
PARMRK = log2(PARMRK), /* mark parity and framing errors */
|
||||
INPCK = log2(INPCK), /* enable checking of parity errors */
|
||||
ISTRIP = log2(ISTRIP), /* strip 8th bit off chars */
|
||||
INLCR = log2(INLCR), /* map NL into CR */
|
||||
IGNCR = log2(IGNCR), /* ignore CR */
|
||||
ICRNL = log2(ICRNL), /* map CR to NL (ala CRMOD) */
|
||||
IXON = log2(IXON), /* enable output flow control */
|
||||
IXOFF = log2(IXOFF), /* enable input flow control */
|
||||
IXANY = log2(IXANY), /* any char will restart after stop */
|
||||
}
|
||||
CInput_Flags :: bit_set[CInput_Flag_Bits; tcflag_t]
|
||||
|
||||
CLocal_Flag_Bits :: enum tcflag_t {
|
||||
ECHO = log2(ECHO), /* visual erase for line kill */
|
||||
ECHOE = log2(ECHOE), /* visually erase chars */
|
||||
ECHOK = log2(ECHOK), /* echo NL after line kill */
|
||||
ECHONL = log2(ECHONL), /* echo NL even if ECHO is off */
|
||||
ICANON = log2(ICANON), /* canonicalize input lines */
|
||||
IEXTEN = log2(IEXTEN), /* enable DISCARD and LNEXT */
|
||||
ISIG = log2(ISIG), /* enable signals INTR, QUIT, [D]SUSP */
|
||||
NOFLSH = log2(NOFLSH), /* don't flush after interrupt */
|
||||
TOSTOP = log2(TOSTOP), /* stop background jobs from output */
|
||||
}
|
||||
CLocal_Flags :: bit_set[CLocal_Flag_Bits; tcflag_t]
|
||||
|
||||
CControl_Flag_Bits :: enum tcflag_t {
|
||||
// CS5 = log2(CS5), /* 5 bits (pseudo) (default) */
|
||||
CS6 = log2(CS6), /* 6 bits */
|
||||
CS7 = log2(CS7), /* 7 bits */
|
||||
CS8 = log2(CS8), /* 8 bits */
|
||||
CSTOPB = log2(CSTOPB), /* send 2 stop bits */
|
||||
CREAD = log2(CREAD), /* enable receiver */
|
||||
PARENB = log2(PARENB), /* parity enable */
|
||||
PARODD = log2(PARODD), /* odd parity, else even */
|
||||
HUPCL = log2(HUPCL), /* hang up on last close */
|
||||
CLOCAL = log2(CLOCAL), /* ignore modem status lines */
|
||||
}
|
||||
CControl_Flags :: bit_set[CControl_Flag_Bits; tcflag_t]
|
||||
|
||||
// character size mask
|
||||
CSIZE :: CControl_Flags{ .CS6, .CS7, .CS8 }
|
||||
|
||||
COutput_Flag_Bits :: enum tcflag_t {
|
||||
OPOST = log2(OPOST), /* enable following output processing */
|
||||
ONLCR = log2(ONLCR), /* map NL to CR-NL (ala CRMOD) */
|
||||
OCRNL = log2(OCRNL), /* map CR to NL on output */
|
||||
ONOCR = log2(ONOCR), /* no CR output at column 0 */
|
||||
ONLRET = log2(ONLRET), /* NL performs CR function */
|
||||
OFDEL = log2(OFDEL), /* fill is DEL, else NUL */
|
||||
OFILL = log2(OFILL), /* use fill characters for delay */
|
||||
// NL0 = log2(NL0), /* \n delay 0 (default) */
|
||||
NL1 = log2(NL1), /* \n delay 1 */
|
||||
// CR0 = log2(CR0), /* \r delay 0 (default) */
|
||||
CR1 = log2(CR1), /* \r delay 1 */
|
||||
CR2 = log2(CR2), /* \r delay 2 */
|
||||
CR3 = log2(CR3), /* \r delay 3 */
|
||||
// TAB0 = log2(TAB0),/* horizontal tab delay 0 (default) */
|
||||
TAB1 = log2(TAB1), /* horizontal tab delay 1 */
|
||||
TAB3 = log2(TAB3), /* horizontal tab delay 3 */
|
||||
// BS0 = log2(BS0), /* \b delay 0 (default) */
|
||||
BS1 = log2(BS1), /* \b delay 1 */
|
||||
// VT0 = log2(VT0), /* vertical tab delay 0 (default) */
|
||||
VT1 = log2(VT1), /* vertical tab delay 1 */
|
||||
// FF0 = log2(FF0), /* form feed delay 0 (default) */
|
||||
FF1 = log2(FF1), /* form feed delay 1 */
|
||||
}
|
||||
COutput_Flags :: bit_set[COutput_Flag_Bits; tcflag_t]
|
||||
|
||||
// \n delay mask
|
||||
NLDLY :: COutput_Flags{ .NL1, COutput_Flag_Bits(9) }
|
||||
// \r delay mask
|
||||
CRDLY :: COutput_Flags{ .CR1, .CR2, .CR3 }
|
||||
// horizontal tab delay mask
|
||||
TABDLY :: COutput_Flags{ .TAB1, .TAB3, COutput_Flag_Bits(2) }
|
||||
// \b delay mask
|
||||
BSDLY :: COutput_Flags{ .BS1 }
|
||||
// vertical tab delay mask
|
||||
VTDLY :: COutput_Flags{ .VT1 }
|
||||
// form feed delay mask
|
||||
FFDLY :: COutput_Flags{ .FF1 }
|
||||
|
||||
speed_t :: enum _speed_t {
|
||||
B0 = B0,
|
||||
B50 = B50,
|
||||
B75 = B75,
|
||||
B110 = B110,
|
||||
B134 = B134,
|
||||
B150 = B150,
|
||||
B200 = B200,
|
||||
B300 = B300,
|
||||
B600 = B600,
|
||||
B1200 = B1200,
|
||||
B1800 = B1800,
|
||||
B2400 = B2400,
|
||||
B4800 = B4800,
|
||||
B9600 = B9600,
|
||||
B19200 = B19200,
|
||||
B38400 = B38400,
|
||||
}
|
||||
|
||||
TC_Action :: enum c.int {
|
||||
TCIOFF = TCIOFF,
|
||||
TCION = TCION,
|
||||
TCOOFF = TCOOFF,
|
||||
TCOON = TCOON,
|
||||
}
|
||||
|
||||
TC_Queue :: enum c.int {
|
||||
TCIFLUSH = TCIFLUSH,
|
||||
TCOFLUSH = TCOFLUSH,
|
||||
TCIOFLUSH = TCIOFLUSH,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
cc_t :: distinct c.uchar
|
||||
_speed_t :: distinct c.ulong
|
||||
tcflag_t :: distinct c.ulong
|
||||
|
||||
termios :: struct {
|
||||
c_iflag: CInput_Flags, /* [XBD] input flags */
|
||||
c_oflag: COutput_Flags, /* [XBD] output flags */
|
||||
c_cflag: CControl_Flags, /* [XBD] control flags */
|
||||
c_lflag: CLocal_Flags, /* [XBD] local flag */
|
||||
c_cc: #sparse [Control_Char]cc_t, /* [XBD] control chars */
|
||||
c_ispeed: speed_t, /* input speed */
|
||||
c_ospeed: speed_t, /* output speed */
|
||||
}
|
||||
|
||||
NCCS :: 20
|
||||
|
||||
VEOF :: 0
|
||||
VEOL :: 1
|
||||
VERASE :: 3
|
||||
VINTR :: 8
|
||||
VKILL :: 5
|
||||
VMIN :: 16
|
||||
VQUIT :: 9
|
||||
VSTART :: 12
|
||||
VSTOP :: 13
|
||||
VSUSP :: 10
|
||||
VTIME :: 17
|
||||
|
||||
IGNBRK :: 0x00000001
|
||||
BRKINT :: 0x00000002
|
||||
IGNPAR :: 0x00000004
|
||||
PARMRK :: 0x00000008
|
||||
INPCK :: 0x00000010
|
||||
ISTRIP :: 0x00000020
|
||||
INLCR :: 0x00000040
|
||||
IGNCR :: 0x00000080
|
||||
ICRNL :: 0x00000100
|
||||
IXON :: 0x00000200
|
||||
IXOFF :: 0x00000400
|
||||
IXANY :: 0x00000800
|
||||
|
||||
OPOST :: 0x00000001
|
||||
ONLCR :: 0x00000002
|
||||
OCRNL :: 0x00000010
|
||||
ONOCR :: 0x00000020
|
||||
ONLRET :: 0x00000040
|
||||
OFDEL :: 0x00020000
|
||||
OFILL :: 0x00000080
|
||||
_NLDLY :: 0x00000300
|
||||
NL0 :: 0x00000000
|
||||
NL1 :: 0x00000100
|
||||
_CRDLY :: 0x00003000
|
||||
CR0 :: 0x00000000
|
||||
CR1 :: 0x00001000
|
||||
CR2 :: 0x00002000
|
||||
CR3 :: 0x00003000
|
||||
_TABDLY :: 0x00000c04
|
||||
TAB0 :: 0x00000000
|
||||
TAB1 :: 0x00000400
|
||||
TAB3 :: 0x00000800
|
||||
_BSDLY :: 0x00008000
|
||||
BS0 :: 0x00000000
|
||||
BS1 :: 0x00008000
|
||||
_VTDLY :: 0x00010000
|
||||
VT0 :: 0x00000000
|
||||
VT1 :: 0x00010000
|
||||
_FFDLY :: 0x00004000
|
||||
FF0 :: 0x00000000
|
||||
FF1 :: 0x00004000
|
||||
|
||||
B0 :: 0
|
||||
B50 :: 50
|
||||
B75 :: 75
|
||||
B110 :: 110
|
||||
B134 :: 134
|
||||
B150 :: 150
|
||||
B200 :: 200
|
||||
B300 :: 300
|
||||
B600 :: 600
|
||||
B1200 :: 1200
|
||||
B1800 :: 1800
|
||||
B2400 :: 2400
|
||||
B4800 :: 4800
|
||||
B9600 :: 9600
|
||||
B19200 :: 19200
|
||||
B38400 :: 38400
|
||||
|
||||
_CSIZE :: 0x00000300
|
||||
CS5 :: 0x00000000
|
||||
CS6 :: 0x00000100
|
||||
CS7 :: 0x00000200
|
||||
CS8 :: 0x00000300
|
||||
CSTOPB :: 0x00000400
|
||||
CREAD :: 0x00000800
|
||||
PARENB :: 0x00001000
|
||||
PARODD :: 0x00002000
|
||||
HUPCL :: 0x00004000
|
||||
CLOCAL :: 0x00008000
|
||||
|
||||
ECHO :: 0x00000008
|
||||
ECHOE :: 0x00000002
|
||||
ECHOK :: 0x00000004
|
||||
ECHONL :: 0x00000010
|
||||
ICANON :: 0x00000100
|
||||
IEXTEN :: 0x00000400
|
||||
ISIG :: 0x00000080
|
||||
NOFLSH :: 0x80000000
|
||||
TOSTOP :: 0x00400000
|
||||
|
||||
TCIFLUSH :: 1
|
||||
TCOFLUSH :: 2
|
||||
TCIOFLUSH :: 3
|
||||
|
||||
TCIOFF :: 3
|
||||
TCION :: 4
|
||||
TCOOFF :: 1
|
||||
TCOON :: 2
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
cc_t :: distinct c.uchar
|
||||
_speed_t :: distinct c.uint
|
||||
tcflag_t :: distinct c.uint
|
||||
|
||||
termios :: struct {
|
||||
c_iflag: CInput_Flags, /* [XBD] input flags */
|
||||
c_oflag: COutput_Flags, /* [XBD] output flags */
|
||||
c_cflag: CControl_Flags, /* [XBD] control flags */
|
||||
c_lflag: CLocal_Flags, /* [XBD] local flag */
|
||||
c_cc: #sparse [Control_Char]cc_t, /* [XBD] control chars */
|
||||
c_ispeed: speed_t, /* input speed */
|
||||
c_ospeed: speed_t, /* output speed */
|
||||
}
|
||||
|
||||
NCCS :: 20
|
||||
|
||||
VEOF :: 0
|
||||
VEOL :: 1
|
||||
VERASE :: 3
|
||||
VINTR :: 8
|
||||
VKILL :: 5
|
||||
VMIN :: 16
|
||||
VQUIT :: 9
|
||||
VSTART :: 12
|
||||
VSTOP :: 13
|
||||
VSUSP :: 10
|
||||
VTIME :: 17
|
||||
|
||||
IGNBRK :: 0x00000001
|
||||
BRKINT :: 0x00000002
|
||||
IGNPAR :: 0x00000004
|
||||
PARMRK :: 0x00000008
|
||||
INPCK :: 0x00000010
|
||||
ISTRIP :: 0x00000020
|
||||
INLCR :: 0x00000040
|
||||
IGNCR :: 0x00000080
|
||||
ICRNL :: 0x00000100
|
||||
IXON :: 0x00000200
|
||||
IXOFF :: 0x00000400
|
||||
IXANY :: 0x00000800
|
||||
|
||||
OPOST :: 0x00000001
|
||||
ONLCR :: 0x00000002
|
||||
OCRNL :: 0x00000010
|
||||
when ODIN_OS == .OpenBSD {
|
||||
ONOCR :: 0x00000040
|
||||
ONLRET :: 0x00000080
|
||||
} else {
|
||||
ONOCR :: 0x00000020
|
||||
ONLRET :: 0x00000040
|
||||
}
|
||||
OFDEL :: 0x00020000 // NOTE: not in headers
|
||||
OFILL :: 0x00000080 // NOTE: not in headers
|
||||
_NLDLY :: 0x00000300 // NOTE: not in headers
|
||||
NL0 :: 0x00000000 // NOTE: not in headers
|
||||
NL1 :: 0x00000100 // NOTE: not in headers
|
||||
_CRDLY :: 0x00003000 // NOTE: not in headers
|
||||
CR0 :: 0x00000000 // NOTE: not in headers
|
||||
CR1 :: 0x00001000 // NOTE: not in headers
|
||||
CR2 :: 0x00002000 // NOTE: not in headers
|
||||
CR3 :: 0x00003000 // NOTE: not in headers
|
||||
_TABDLY :: 0x00000004 // NOTE: not in headers (netbsd)
|
||||
TAB0 :: 0x00000000 // NOTE: not in headers (netbsd)
|
||||
TAB1 :: 0x00000004 // NOTE: not in headers
|
||||
TAB3 :: 0x00000004 // NOTE: not in headers (netbsd)
|
||||
_BSDLY :: 0x00008000 // NOTE: not in headers
|
||||
BS0 :: 0x00000000 // NOTE: not in headers
|
||||
BS1 :: 0x00008000 // NOTE: not in headers
|
||||
_VTDLY :: 0x00010000 // NOTE: not in headers
|
||||
VT0 :: 0x00000000 // NOTE: not in headers
|
||||
VT1 :: 0x00010000 // NOTE: not in headers
|
||||
_FFDLY :: 0x00004000 // NOTE: not in headers
|
||||
FF0 :: 0x00000000 // NOTE: not in headers
|
||||
FF1 :: 0x00004000 // NOTE: not in headers
|
||||
|
||||
B0 :: 0
|
||||
B50 :: 50
|
||||
B75 :: 75
|
||||
B110 :: 110
|
||||
B134 :: 134
|
||||
B150 :: 150
|
||||
B200 :: 200
|
||||
B300 :: 300
|
||||
B600 :: 600
|
||||
B1200 :: 1200
|
||||
B1800 :: 1800
|
||||
B2400 :: 2400
|
||||
B4800 :: 4800
|
||||
B9600 :: 9600
|
||||
B19200 :: 19200
|
||||
B38400 :: 38400
|
||||
|
||||
_CSIZE :: 0x00000300
|
||||
CS5 :: 0x00000000
|
||||
CS6 :: 0x00000100
|
||||
CS7 :: 0x00000200
|
||||
CS8 :: 0x00000300
|
||||
CSTOPB :: 0x00000400
|
||||
CREAD :: 0x00000800
|
||||
PARENB :: 0x00001000
|
||||
PARODD :: 0x00002000
|
||||
HUPCL :: 0x00004000
|
||||
CLOCAL :: 0x00008000
|
||||
|
||||
ECHO :: 0x00000008
|
||||
ECHOE :: 0x00000002
|
||||
ECHOK :: 0x00000004
|
||||
ECHONL :: 0x00000010
|
||||
ICANON :: 0x00000100
|
||||
IEXTEN :: 0x00000400
|
||||
ISIG :: 0x00000080
|
||||
NOFLSH :: 0x80000000
|
||||
TOSTOP :: 0x00400000
|
||||
|
||||
TCIFLUSH :: 1
|
||||
TCOFLUSH :: 2
|
||||
TCIOFLUSH :: 3
|
||||
|
||||
TCIOFF :: 3
|
||||
TCION :: 4
|
||||
TCOOFF :: 1
|
||||
TCOON :: 2
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
234
core/sys/posix/time.odin
Normal file
234
core/sys/posix/time.odin
Normal file
@@ -0,0 +1,234 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
import "core:c/libc"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// time.h - time types
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973\n\0
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime_r.html ]]
|
||||
*/
|
||||
asctime_r :: proc(tm: ^tm, buf: [^]c.char) -> cstring ---
|
||||
|
||||
/*
|
||||
Convert a time value to a date and time string in the same format as asctime().
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime_r.html ]]
|
||||
*/
|
||||
@(link_name=LCTIMER)
|
||||
ctime_r :: proc(clock: ^time_t, buf: [^]c.char) -> cstring ---
|
||||
|
||||
/*
|
||||
Converts the time in seconds since epoch to a broken-down tm struct.
|
||||
|
||||
Returns: nil (setting errno) on failure, the result pointer on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime_r.html ]]
|
||||
*/
|
||||
@(link_name=LGMTIMER)
|
||||
gmtime_r :: proc(timer: ^time_t, result: ^tm) -> ^tm ---
|
||||
|
||||
/*
|
||||
Convert the time in seconds since epoch to a broken-down tm struct in local time.
|
||||
|
||||
Returns: nil (setting errno) on failure, the result pointer on success.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime_r.html ]]
|
||||
*/
|
||||
@(link_name=LLOCALTIMER)
|
||||
localtime_r :: proc(timer: ^time_t, result: ^tm) -> ^tm ---
|
||||
|
||||
/*
|
||||
Returns the resolution of any clock.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]]
|
||||
*/
|
||||
@(link_name=LCLOCKGETRES)
|
||||
clock_getres :: proc(clock_id: Clock, res: ^timespec) -> result ---
|
||||
|
||||
/*
|
||||
Returns the current value tp for the specified clock, clock_id.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]]
|
||||
*/
|
||||
@(link_name=LCLOCKGETTIME)
|
||||
clock_gettime :: proc(clock_id: Clock, tp: ^timespec) -> result ---
|
||||
|
||||
/*
|
||||
Sets the specified clock's time.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]]
|
||||
*/
|
||||
@(link_name=LCLOCKSETTIME)
|
||||
clock_settime :: proc(clock_id: Clock, tp: ^timespec) -> result ---
|
||||
|
||||
/*
|
||||
Converts a string representation of a date or time into a broken-down time.
|
||||
|
||||
Returns: nil (setting getdate_err) on failure, the broken-down time otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdate.html ]]
|
||||
*/
|
||||
getdate :: proc(string: cstring) -> ^tm ---
|
||||
|
||||
/*
|
||||
Causes the current thread to be suspended from execution until either the time interval
|
||||
specified by rqtp has elapsed or a signal is delivered.
|
||||
|
||||
Returns: -1 on failure (setting errno), if it was due to a signal, rmtp will be filled with the
|
||||
remaining time, 0 if all time has been slept
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html ]]
|
||||
*/
|
||||
@(link_name=LNANOSLEEP)
|
||||
nanosleep :: proc(rqtp: ^timespec, rmtp: ^timespec) -> result ---
|
||||
|
||||
/*
|
||||
Converts the character string to values which are stored in tm, using the specified format.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html ]]
|
||||
*/
|
||||
strptime :: proc(buf: [^]c.char, format: cstring, tm: ^tm) -> cstring ---
|
||||
|
||||
/*
|
||||
Uses the value of the environment variable TZ (or default) to set time conversion info.
|
||||
|
||||
`daylight` is set to whether daylight saving time conversion should be done.
|
||||
`timezone` is set to the difference, in seconds, between UTC and local standard time.
|
||||
`tzname` is set by `tzname[0] = "std"` and `tzname[1] = "dst"`
|
||||
|
||||
Example:
|
||||
posix.tzset()
|
||||
fmt.println(posix.tzname)
|
||||
fmt.println(posix.daylight)
|
||||
fmt.println(posix.timezone)
|
||||
|
||||
Possible Output:
|
||||
["CET", "CEST"]
|
||||
true
|
||||
-3600
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tzset.html ]]
|
||||
*/
|
||||
tzset :: proc() ---
|
||||
|
||||
// Whether daylight saving conversion should be done.
|
||||
daylight: b32
|
||||
// The time in seconds between UTC and local standard time.
|
||||
@(link_name=LTIMEZONE)
|
||||
timezone: c.long
|
||||
tzname: [2]cstring
|
||||
}
|
||||
|
||||
time_t :: libc.time_t
|
||||
clock_t :: libc.clock_t
|
||||
|
||||
tm :: libc.tm
|
||||
timespec :: libc.timespec
|
||||
|
||||
CLOCKS_PER_SEC :: libc.CLOCKS_PER_SEC
|
||||
|
||||
asctime :: libc.asctime
|
||||
clock :: libc.clock
|
||||
ctime :: libc.ctime
|
||||
difftime :: libc.difftime
|
||||
gmtime :: libc.gmtime
|
||||
localtime :: libc.localtime
|
||||
mktime :: libc.mktime
|
||||
strftime :: libc.strftime
|
||||
time :: libc.time
|
||||
|
||||
Clock :: enum clockid_t {
|
||||
// system-wide monotonic clock, defined as clock measuring real time,
|
||||
// can be set with clock_settime() and cannot have negative clock jumps.
|
||||
MONOTONIC = CLOCK_MONOTONIC,
|
||||
// CPU-time clock associated with the process making a clock() function call.
|
||||
PROCESS_CPUTIME_ID = CLOCK_PROCESS_CPUTIME_ID,
|
||||
// system-wide clock measuring real time.
|
||||
REALTIME = CLOCK_REALTIME,
|
||||
// CPU-time clock associated with the thread making a clock() function call.
|
||||
THREAD_CPUTIME_ID = CLOCK_THREAD_CPUTIME_ID,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LCTIMER :: "__ctime_r50"
|
||||
@(private) LGMTIMER :: "__gmtime_r50"
|
||||
@(private) LLOCALTIMER :: "__localtime_r50"
|
||||
@(private) LCLOCKGETRES :: "__clock_getres50"
|
||||
@(private) LCLOCKGETTIME :: "__clock_gettime50"
|
||||
@(private) LCLOCKSETTIME :: "__clock_settime50"
|
||||
@(private) LNANOSLEEP :: "__nanosleep50"
|
||||
@(private) LTIMEZONE :: "__timezone13"
|
||||
} else {
|
||||
@(private) LCTIMER :: "ctime_r"
|
||||
@(private) LGMTIMER :: "gmtime_r"
|
||||
@(private) LLOCALTIMER :: "localtime_r"
|
||||
@(private) LCLOCKGETRES :: "clock_getres"
|
||||
@(private) LCLOCKGETTIME :: "clock_gettime"
|
||||
@(private) LCLOCKSETTIME :: "clock_settime"
|
||||
@(private) LNANOSLEEP :: "nanosleep"
|
||||
@(private) LTIMEZONE :: "timezone"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
clockid_t :: distinct c.int
|
||||
|
||||
CLOCK_MONOTONIC :: 6
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 12
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_THREAD_CPUTIME_ID :: 16
|
||||
|
||||
foreign lib {
|
||||
getdate_err: Errno
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
|
||||
clockid_t :: distinct c.int
|
||||
|
||||
CLOCK_MONOTONIC :: 4
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 15
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_THREAD_CPUTIME_ID :: 14
|
||||
|
||||
foreign lib {
|
||||
getdate_err: Errno
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
|
||||
clockid_t :: distinct c.uint
|
||||
|
||||
CLOCK_MONOTONIC :: 3
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 0x40000000
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_THREAD_CPUTIME_ID :: 0x20000000
|
||||
|
||||
foreign lib {
|
||||
getdate_err: Errno
|
||||
}
|
||||
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
|
||||
clockid_t :: distinct c.uint
|
||||
|
||||
CLOCK_MONOTONIC :: 3
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_THREAD_CPUTIME_ID :: 4
|
||||
|
||||
getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD.
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
43
core/sys/posix/ulimit.odin
Normal file
43
core/sys/posix/ulimit.odin
Normal file
@@ -0,0 +1,43 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// ulimit.h - ulimit commands
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Control process limits.
|
||||
|
||||
Note that -1 is a valid return value, applications should clear errno, do this call and then
|
||||
check both -1 and the errno to determine status.
|
||||
|
||||
Returns: -1 (setting errno) on failure.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ulimit.html ]]
|
||||
*/
|
||||
ulimit :: proc(i: c.int, #c_vararg arg: ..c.long) -> c.long ---
|
||||
}
|
||||
|
||||
Ulimit_Cmd :: enum c.int {
|
||||
// Returns the file size limit of the process in units of 512-byte blocks inherited by children.
|
||||
GETFSIZE = UL_GETFSIZE,
|
||||
// Set the file size limit for output operations, taken as a long, multiplied by 512.
|
||||
SETFSIZE = UL_SETFSIZE,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
UL_GETFSIZE :: 1
|
||||
UL_SETFSIZE :: 2
|
||||
|
||||
// NOTE: I don't think OpenBSD implements this API.
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
1914
core/sys/posix/unistd.odin
Normal file
1914
core/sys/posix/unistd.odin
Normal file
File diff suppressed because it is too large
Load Diff
36
core/sys/posix/utime.odin
Normal file
36
core/sys/posix/utime.odin
Normal file
@@ -0,0 +1,36 @@
|
||||
package posix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// utime.h - access and modification time structure
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Set file access and modification times.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/utime.html ]]
|
||||
*/
|
||||
@(link_name=LUTIME)
|
||||
utime :: proc(path: cstring, times: ^utimbuf) -> result ---
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LUTIME :: "__utime50"
|
||||
} else {
|
||||
@(private) LUTIME :: "utime"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
utimbuf :: struct {
|
||||
actime: time_t, /* [PSX] access time (seconds since epoch) */
|
||||
modtime: time_t, /* [PSX] modification time (seconds since epoch) */
|
||||
}
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
107
core/sys/posix/wordexp.odin
Normal file
107
core/sys/posix/wordexp.odin
Normal file
@@ -0,0 +1,107 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:System.framework"
|
||||
} else {
|
||||
foreign import lib "system:c"
|
||||
}
|
||||
|
||||
// wordexp.h - word-expansion type
|
||||
|
||||
foreign lib {
|
||||
/*
|
||||
Perform word expansion.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html ]]
|
||||
*/
|
||||
wordexp :: proc(words: cstring, pwordexp: ^wordexp_t, flags: WRDE_Flags) -> WRDE_Errno ---
|
||||
|
||||
/*
|
||||
Free the space allocated during word expansion.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html ]]
|
||||
*/
|
||||
wordfree :: proc(pwordexp: ^wordexp_t) ---
|
||||
}
|
||||
|
||||
WRDE_Flag_Bits :: enum c.int {
|
||||
// Appends words to those previously generated.
|
||||
APPEND = log2(WRDE_APPEND),
|
||||
// Number of null pointers to prepend to we_wordv.
|
||||
DOOFFS = log2(WRDE_DOOFFS),
|
||||
// Fail if command substitution is requested.
|
||||
NOCMD = log2(WRDE_NOCMD),
|
||||
// The pwordexp argument was passed to a previous successful call to wordexp(),
|
||||
// and has not been passed to wordfree().
|
||||
REUSE = log2(WRDE_REUSE),
|
||||
// Do not redirect stderr to /dev/null.
|
||||
SHOWERR = log2(WRDE_SHOWERR),
|
||||
// Report error on attempt to expand an undefined shell variable.
|
||||
UNDEF = log2(WRDE_UNDEF),
|
||||
}
|
||||
WRDE_Flags :: bit_set[WRDE_Flag_Bits; c.int]
|
||||
|
||||
WRDE_Errno :: enum c.int {
|
||||
OK = 0,
|
||||
// One of the unquoted characters- <newline>, '|', '&', ';', '<', '>', '(', ')', '{', '}' -
|
||||
// appears in words in an inappropriate context.
|
||||
BADCHAR = WRDE_BADCHAR,
|
||||
// Reference to undefined shell variable when WRDE_UNDEF is set in flags.
|
||||
BADVAL = WRDE_BADVAL,
|
||||
// Command substitution requested when WRDE_NOCMD was set in flags.
|
||||
CMDSUB = WRDE_CMDSUB,
|
||||
// Attempt to allocate memory failed.
|
||||
NOSPACE = WRDE_NOSPACE,
|
||||
// Shell syntax error, such as unbalanced parentheses or an unterminated string.
|
||||
SYNTAX = WRDE_SYNTAX,
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
wordexp_t :: struct {
|
||||
we_wordc: c.size_t, /* [PSX] count of words matched by words */
|
||||
we_wordv: [^]cstring, /* [PSX] pointer to list of expanded words */
|
||||
we_offs: c.size_t, /* [PSX] slots to reserve at the beginning of we_wordv */
|
||||
}
|
||||
|
||||
WRDE_APPEND :: 0x01
|
||||
WRDE_DOOFFS :: 0x02
|
||||
WRDE_NOCMD :: 0x04
|
||||
WRDE_REUSE :: 0x08
|
||||
WRDE_SHOWERR :: 0x10
|
||||
WRDE_UNDEF :: 0x20
|
||||
|
||||
WRDE_BADCHAR :: 1
|
||||
WRDE_BADVAL :: 2
|
||||
WRDE_CMDSUB :: 3
|
||||
WRDE_NOSPACE :: 4
|
||||
WRDE_SYNTAX :: 6
|
||||
|
||||
} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
wordexp_t :: struct {
|
||||
we_wordc: c.size_t, /* [PSX] count of words matched by words */
|
||||
we_wordv: [^]cstring, /* [PSX] pointer to list of expanded words */
|
||||
we_offs: c.size_t, /* [PSX] slots to reserve at the beginning of we_wordv */
|
||||
we_strings: [^]byte, /* storage for wordv strings */
|
||||
we_nbytes: c.size_t, /* size of we_strings */
|
||||
}
|
||||
|
||||
WRDE_APPEND :: 0x01
|
||||
WRDE_DOOFFS :: 0x02
|
||||
WRDE_NOCMD :: 0x04
|
||||
WRDE_REUSE :: 0x08
|
||||
WRDE_SHOWERR :: 0x10
|
||||
WRDE_UNDEF :: 0x20
|
||||
|
||||
WRDE_BADCHAR :: 1
|
||||
WRDE_BADVAL :: 2
|
||||
WRDE_CMDSUB :: 3
|
||||
WRDE_NOSPACE :: 4
|
||||
WRDE_SYNTAX :: 6
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package unix
|
||||
|
||||
import "core:c"
|
||||
|
||||
pthread_t :: distinct u64
|
||||
pthread_t :: distinct rawptr
|
||||
|
||||
SEM_T_SIZE :: 8
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@ foreign import "system:pthread"
|
||||
|
||||
import "core:c"
|
||||
|
||||
timespec :: struct {
|
||||
tv_sec: i64,
|
||||
tv_nsec: i64,
|
||||
}
|
||||
|
||||
//
|
||||
// On success, these functions return 0.
|
||||
//
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
//+build linux, darwin, freebsd, openbsd, netbsd, haiku
|
||||
package unix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="__clock_gettime50") clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> c.int ---
|
||||
@(link_name="__nanosleep50") nanosleep :: proc(requested, remaining: ^timespec) -> c.int ---
|
||||
@(link_name="sleep") sleep :: proc(seconds: c.uint) -> c.int ---
|
||||
}
|
||||
} else {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> c.int ---
|
||||
sleep :: proc(seconds: c.uint) -> c.int ---
|
||||
nanosleep :: proc(requested, remaining: ^timespec) -> c.int ---
|
||||
}
|
||||
}
|
||||
|
||||
timespec :: struct {
|
||||
tv_sec: i64, // seconds
|
||||
tv_nsec: i64, // nanoseconds
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
CLOCK_REALTIME :: 0
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_MONOTONIC :: 3
|
||||
CLOCK_THREAD_CPUTIME_ID :: 4
|
||||
CLOCK_UPTIME :: 5
|
||||
CLOCK_BOOTTIME :: 6
|
||||
|
||||
// CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC
|
||||
CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC
|
||||
} else {
|
||||
CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
|
||||
CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
|
||||
CLOCK_PROCESS_CPUTIME_ID :: 2
|
||||
CLOCK_THREAD_CPUTIME_ID :: 3
|
||||
CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
|
||||
CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
|
||||
CLOCK_MONOTONIC_COARSE :: 6
|
||||
CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
|
||||
CLOCK_REALTIME_ALARM :: 8
|
||||
CLOCK_BOOTTIME_ALARM :: 9
|
||||
}
|
||||
|
||||
// TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
|
||||
// I do not know if Darwin programmers are used to the existance of these constants or not, so
|
||||
// I'm leaving aliases to them for now.
|
||||
CLOCK_SYSTEM :: CLOCK_REALTIME
|
||||
CLOCK_CALENDAR :: CLOCK_MONOTONIC
|
||||
|
||||
boot_time_in_nanoseconds :: proc "c" () -> i64 {
|
||||
ts_now, ts_boottime: timespec
|
||||
clock_gettime(CLOCK_REALTIME, &ts_now)
|
||||
clock_gettime(CLOCK_BOOTTIME, &ts_boottime)
|
||||
|
||||
ns := (ts_now.tv_sec - ts_boottime.tv_sec) * 1e9 + ts_now.tv_nsec - ts_boottime.tv_nsec
|
||||
return i64(ns)
|
||||
}
|
||||
|
||||
seconds_since_boot :: proc "c" () -> f64 {
|
||||
ts_boottime: timespec
|
||||
clock_gettime(CLOCK_BOOTTIME, &ts_boottime)
|
||||
return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9
|
||||
}
|
||||
|
||||
inline_nanosleep :: proc "c" (nanoseconds: i64) -> (remaining: timespec, res: i32) {
|
||||
s, ns := nanoseconds / 1e9, nanoseconds % 1e9
|
||||
requested := timespec{tv_sec=s, tv_nsec=ns}
|
||||
res = nanosleep(&requested, &remaining)
|
||||
return
|
||||
}
|
||||
|
||||
38
core/time/time_linux.odin
Normal file
38
core/time/time_linux.odin
Normal file
@@ -0,0 +1,38 @@
|
||||
package time
|
||||
|
||||
import "core:sys/linux"
|
||||
|
||||
_IS_SUPPORTED :: true
|
||||
|
||||
_now :: proc "contextless" () -> Time {
|
||||
time_spec_now, _ := linux.clock_gettime(.REALTIME)
|
||||
ns := time_spec_now.time_sec * 1e9 + time_spec_now.time_nsec
|
||||
return Time{_nsec=i64(ns)}
|
||||
}
|
||||
|
||||
_sleep :: proc "contextless" (d: Duration) {
|
||||
ds := duration_seconds(d)
|
||||
seconds := uint(ds)
|
||||
nanoseconds := uint((ds - f64(seconds)) * 1e9)
|
||||
|
||||
ts := linux.Time_Spec{
|
||||
time_sec = seconds,
|
||||
time_nsec = nanoseconds,
|
||||
}
|
||||
|
||||
for {
|
||||
if linux.nanosleep(&ts, &ts) != .EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_tick_now :: proc "contextless" () -> Tick {
|
||||
t, _ := linux.clock_gettime(.MONOTONIC_RAW)
|
||||
return Tick{_nsec = i64(t.time_sec*1e9 + t.time_nsec)}
|
||||
}
|
||||
|
||||
_yield :: proc "contextless" () {
|
||||
linux.sched_yield()
|
||||
}
|
||||
|
||||
@@ -1,34 +1,50 @@
|
||||
//+private
|
||||
//+build linux, darwin, freebsd, openbsd, netbsd, haiku
|
||||
//+build darwin, freebsd, openbsd, netbsd, haiku
|
||||
package time
|
||||
|
||||
import "core:sys/unix"
|
||||
import "core:sys/posix"
|
||||
|
||||
_IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC.
|
||||
_IS_SUPPORTED :: true
|
||||
|
||||
_now :: proc "contextless" () -> Time {
|
||||
time_spec_now: unix.timespec
|
||||
unix.clock_gettime(unix.CLOCK_REALTIME, &time_spec_now)
|
||||
ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec
|
||||
time_spec_now: posix.timespec
|
||||
posix.clock_gettime(.REALTIME, &time_spec_now)
|
||||
ns := i64(time_spec_now.tv_sec) * 1e9 + time_spec_now.tv_nsec
|
||||
return Time{_nsec=ns}
|
||||
}
|
||||
|
||||
_sleep :: proc "contextless" (d: Duration) {
|
||||
ds := duration_seconds(d)
|
||||
seconds := u32(ds)
|
||||
seconds := posix.time_t(ds)
|
||||
nanoseconds := i64((ds - f64(seconds)) * 1e9)
|
||||
|
||||
if seconds > 0 { unix.sleep(seconds) }
|
||||
if nanoseconds > 0 { unix.inline_nanosleep(nanoseconds) }
|
||||
ts := posix.timespec{
|
||||
tv_sec = seconds,
|
||||
tv_nsec = nanoseconds,
|
||||
}
|
||||
|
||||
for {
|
||||
res := posix.nanosleep(&ts, &ts)
|
||||
if res == .OK || posix.errno() != .EINTR {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
TICK_CLOCK :: posix.Clock(4) // CLOCK_MONOTONIC_RAW
|
||||
} else {
|
||||
// It looks like the BSDs don't have a CLOCK_MONOTONIC_RAW equivalent.
|
||||
TICK_CLOCK :: posix.Clock.MONOTONIC
|
||||
}
|
||||
|
||||
_tick_now :: proc "contextless" () -> Tick {
|
||||
t: unix.timespec
|
||||
unix.clock_gettime(unix.CLOCK_MONOTONIC_RAW, &t)
|
||||
return Tick{_nsec = t.tv_sec*1e9 + t.tv_nsec}
|
||||
t: posix.timespec
|
||||
posix.clock_gettime(TICK_CLOCK, &t)
|
||||
return Tick{_nsec = i64(t.tv_sec)*1e9 + t.tv_nsec}
|
||||
}
|
||||
|
||||
_yield :: proc "contextless" () {
|
||||
unix.sched_yield()
|
||||
posix.sched_yield()
|
||||
}
|
||||
|
||||
|
||||
6
examples/all/all_posix.odin
Normal file
6
examples/all/all_posix.odin
Normal file
@@ -0,0 +1,6 @@
|
||||
//+build darwin, openbsd, freebsd, netbsd
|
||||
package all
|
||||
|
||||
import posix "core:sys/posix"
|
||||
|
||||
_ :: posix
|
||||
@@ -621,3 +621,7 @@ gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64
|
||||
}
|
||||
return make_string(cast(u8 *)buf.data, buf.count);
|
||||
}
|
||||
|
||||
gb_internal int big_int_log2(BigInt const *x) {
|
||||
return mp_count_bits(x) - 1;
|
||||
}
|
||||
|
||||
@@ -3979,6 +3979,23 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_constant_log2: {
|
||||
Operand o = {};
|
||||
check_expr(c, &o, ce->args[0]);
|
||||
|
||||
if (!is_type_integer(o.type) && (o.mode != Addressing_Constant)) {
|
||||
error(ce->args[0], "Expected a constant integer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
int log2 = big_int_log2(&o.value.value_integer);
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = exact_value_i64(cast(i64)log2);
|
||||
operand->type = t_untyped_integer;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_soa_struct: {
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
|
||||
@@ -756,13 +756,29 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
for (isize i = 0; i < a->param_count; i++) {
|
||||
Type *x = core_type(a->params->Tuple.variables[i]->type);
|
||||
Type *y = core_type(b->params->Tuple.variables[i]->type);
|
||||
|
||||
if (x->kind == Type_BitSet && x->BitSet.underlying) {
|
||||
x = core_type(x->BitSet.underlying);
|
||||
}
|
||||
if (y->kind == Type_BitSet && y->BitSet.underlying) {
|
||||
y = core_type(y->BitSet.underlying);
|
||||
}
|
||||
|
||||
if (!signature_parameter_similar_enough(x, y)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < a->result_count; i++) {
|
||||
Type *x = base_type(a->results->Tuple.variables[i]->type);
|
||||
Type *y = base_type(b->results->Tuple.variables[i]->type);
|
||||
Type *x = core_type(a->results->Tuple.variables[i]->type);
|
||||
Type *y = core_type(b->results->Tuple.variables[i]->type);
|
||||
|
||||
if (x->kind == Type_BitSet && x->BitSet.underlying) {
|
||||
x = core_type(x->BitSet.underlying);
|
||||
}
|
||||
if (y->kind == Type_BitSet && y->BitSet.underlying) {
|
||||
y = core_type(y->BitSet.underlying);
|
||||
}
|
||||
|
||||
if (!signature_parameter_similar_enough(x, y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ enum BuiltinProcId {
|
||||
|
||||
BuiltinProc_has_target_feature,
|
||||
|
||||
BuiltinProc_constant_log2,
|
||||
|
||||
BuiltinProc_transpose,
|
||||
BuiltinProc_outer_product,
|
||||
BuiltinProc_hadamard_product,
|
||||
@@ -380,6 +382,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT("has_target_feature"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("constant_log2"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("transpose"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
@@ -38,6 +38,7 @@ download_assets :: proc() {
|
||||
@(require) import "slice"
|
||||
@(require) import "strconv"
|
||||
@(require) import "strings"
|
||||
@(require) import "sys/posix"
|
||||
@(require) import "sys/windows"
|
||||
@(require) import "text/i18n"
|
||||
@(require) import "text/match"
|
||||
|
||||
211
tests/core/sys/posix/posix.odin
Normal file
211
tests/core/sys/posix/posix.odin
Normal file
@@ -0,0 +1,211 @@
|
||||
//+build darwin, freebsd, openbsd, netbsd
|
||||
package tests_core_posix
|
||||
|
||||
import "core:sys/posix"
|
||||
import "core:testing"
|
||||
import "core:log"
|
||||
import "core:strings"
|
||||
import "core:path/filepath"
|
||||
|
||||
@(test)
|
||||
test_arpa_inet :: proc(t: ^testing.T) {
|
||||
|
||||
check :: proc(t: ^testing.T, $af: posix.AF, src: cstring, expect: posix.pton_result, loc := #caller_location) {
|
||||
when af == .INET {
|
||||
addr: posix.in_addr
|
||||
dst: [posix.INET_ADDRSTRLEN]byte
|
||||
} else {
|
||||
addr: posix.in6_addr
|
||||
dst: [posix.INET6_ADDRSTRLEN]byte
|
||||
}
|
||||
|
||||
res := posix.inet_pton(af, src, &addr, size_of(addr))
|
||||
testing.expect_value(t, res, expect, loc)
|
||||
|
||||
if expect == .SUCCESS {
|
||||
back := posix.inet_ntop(af, &addr, raw_data(dst[:]), len(dst))
|
||||
testing.expect_value(t, back, src, loc)
|
||||
|
||||
when af == .INET {
|
||||
back = posix.inet_ntoa(addr)
|
||||
testing.expect_value(t, back, src, loc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check(t, .INET, "127.0.0.1", .SUCCESS)
|
||||
check(t, .INET, "blah", .INVALID)
|
||||
check(t, .INET6, "::1", .SUCCESS)
|
||||
check(t, .INET6, "L", .INVALID)
|
||||
check(t, .UNIX, "127.0.0.1", .AFNOSUPPORT)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dirent :: proc(t: ^testing.T) {
|
||||
test := #load_directory(#directory)
|
||||
test_map: map[string]struct{}
|
||||
defer delete(test_map)
|
||||
|
||||
test_map[".."] = {}
|
||||
test_map["."] = {}
|
||||
|
||||
for file in test {
|
||||
test_map[filepath.base(file.name)] = {}
|
||||
}
|
||||
|
||||
{
|
||||
list: [^]^posix.dirent
|
||||
ret := posix.scandir(#directory, &list)
|
||||
testing.expectf(t, ret >= 0, "%v >= 0: %v", ret, posix.strerror(posix.errno()))
|
||||
defer posix.free(list)
|
||||
|
||||
entries := list[:ret]
|
||||
for entry in entries {
|
||||
defer posix.free(entry)
|
||||
|
||||
if entry.d_type != .REG {
|
||||
continue
|
||||
}
|
||||
|
||||
name := string(cstring(raw_data(entry.d_name[:])))
|
||||
testing.expectf(t, name in test_map, "%v in %v", name, test_map)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
dir := posix.opendir(#directory)
|
||||
defer posix.closedir(dir)
|
||||
|
||||
for {
|
||||
posix.set_errno(.NONE)
|
||||
entry := posix.readdir(dir)
|
||||
if entry == nil {
|
||||
testing.expect_value(t, posix.errno(), posix.Errno.NONE)
|
||||
break
|
||||
}
|
||||
|
||||
if entry.d_type != .REG {
|
||||
continue
|
||||
}
|
||||
|
||||
name := string(cstring(raw_data(entry.d_name[:])))
|
||||
testing.expectf(t, name in test_map, "%v in %v", name, test_map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_errno :: proc(t: ^testing.T) {
|
||||
posix.errno(posix.Errno.ENOMEM)
|
||||
testing.expect_value(t, posix.errno(), posix.Errno.ENOMEM)
|
||||
|
||||
res := posix.open("", {})
|
||||
testing.expect_value(t, res, -1)
|
||||
testing.expect_value(t, posix.errno(), posix.Errno.ENOENT)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_fcntl :: proc(t: ^testing.T) {
|
||||
res := posix.open(#file, { .WRONLY, .CREAT, .EXCL })
|
||||
testing.expect_value(t, res, -1)
|
||||
testing.expect_value(t, posix.errno(), posix.Errno.EEXIST)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_fnmatch :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, posix.fnmatch("*.odin", #file, {}), 0)
|
||||
testing.expect_value(t, posix.fnmatch("*.txt", #file, {}), posix.FNM_NOMATCH)
|
||||
testing.expect_value(t, posix.fnmatch("**/*.odin", #file, {}), 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_glob :: proc(t: ^testing.T) {
|
||||
glob: posix.glob_t
|
||||
res := posix.glob(#directory + ":)))))))", {}, nil, &glob)
|
||||
testing.expect_value(t, res, posix.Glob_Result.NOMATCH)
|
||||
posix.globfree(&glob)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_langinfo :: proc(t: ^testing.T) {
|
||||
locale := posix.setlocale(.TIME, nil)
|
||||
testing.expectf(t, locale == "POSIX" || locale == "C", "invalid locale for test: %v", locale)
|
||||
|
||||
day1 := posix.nl_langinfo(.DAY_1)
|
||||
testing.expect_value(t, day1, "Sunday")
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_libgen :: proc(t: ^testing.T) {
|
||||
tests := [][3]cstring{
|
||||
{ "usr", ".", "usr" },
|
||||
{ "usr/", ".", "usr" },
|
||||
{ "", ".", "." },
|
||||
{ "/", "/", "/" },
|
||||
{ "//", "/", "/" },
|
||||
{ "///", "/", "/" },
|
||||
{ "/usr/", "/", "usr" },
|
||||
{ "/usr/lib", "/usr", "lib" },
|
||||
{ "//usr//lib//", "//usr", "lib" },
|
||||
{ "/home//dwc//test", "/home//dwc", "test" },
|
||||
}
|
||||
|
||||
for test in tests {
|
||||
// NOTE: dir/basename can change their input so they can't be literals.
|
||||
|
||||
dinput := strings.clone_to_cstring(string(test[0]))
|
||||
defer delete(dinput)
|
||||
|
||||
dir := posix.dirname(dinput)
|
||||
testing.expectf(t, dir == test[1], "dirname(%q) == %q, expected %q", test[0], dir, test[1])
|
||||
|
||||
binput := strings.clone_to_cstring(string(test[0]))
|
||||
defer delete(binput)
|
||||
|
||||
base := posix.basename(binput)
|
||||
testing.expectf(t, base == test[2], "basename(%q) == %q, expected %q", test[0], base, test[2])
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_locale :: proc(t: ^testing.T) {
|
||||
lconv := posix.localeconv()
|
||||
testing.expect(t, lconv != nil)
|
||||
|
||||
locale := posix.setlocale(.ALL, nil)
|
||||
testing.expectf(t, locale == "POSIX" || locale == "C", "%q is not POSIX or C", locale)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_monetary :: proc(t: ^testing.T) {
|
||||
when ODIN_OS == .Darwin && .Address in ODIN_SANITIZER_FLAGS {
|
||||
log.warn("skipping on darwin with -sanitize:address, this fails inside macOS (also from C/clang)")
|
||||
return
|
||||
}
|
||||
|
||||
value := 123456.789
|
||||
buf: [128]byte
|
||||
size := posix.strfmon(raw_data(buf[:]), len(buf), "%n", value)
|
||||
testing.expectf(t, int(size) != -1, "strfmon failure: %v", posix.strerror(posix.errno()))
|
||||
log.debug(string(buf[:size]))
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_stat :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, posix.S_IRWXU, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXU))
|
||||
testing.expect_value(t, posix.S_IRWXG, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXG))
|
||||
testing.expect_value(t, posix.S_IRWXO, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXO))
|
||||
testing.expect_value(t, posix._S_IFMT, transmute(posix.mode_t)posix._mode_t(posix.__S_IFMT))
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_termios :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, transmute(posix.CControl_Flags)posix.tcflag_t(posix._CSIZE), posix.CSIZE)
|
||||
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._NLDLY), posix.NLDLY)
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._CRDLY), posix.CRDLY)
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._TABDLY), posix.TABDLY)
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._BSDLY), posix.BSDLY)
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._VTDLY), posix.VTDLY)
|
||||
testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._FFDLY), posix.FFDLY)
|
||||
}
|
||||
127
tests/core/sys/posix/structs.odin
Normal file
127
tests/core/sys/posix/structs.odin
Normal file
@@ -0,0 +1,127 @@
|
||||
//+build darwin, freebsd, openbsd, netbsd
|
||||
package tests_core_posix
|
||||
|
||||
import "core:log"
|
||||
import "core:testing"
|
||||
import "core:sys/posix"
|
||||
|
||||
// This test tests some of the process APIs of posix while also double checking size and alignment
|
||||
// of the structs we bound.
|
||||
|
||||
@(test)
|
||||
execute_struct_checks :: proc(t: ^testing.T) {
|
||||
log.debug("compiling C project")
|
||||
{
|
||||
switch pid := posix.fork(); pid {
|
||||
case -1:
|
||||
log.errorf("fork() failed: %s", posix.strerror())
|
||||
case 0:
|
||||
c_compiler := posix.getenv("CC")
|
||||
if c_compiler == nil {
|
||||
c_compiler = "clang"
|
||||
}
|
||||
|
||||
posix.execlp(c_compiler,
|
||||
c_compiler, #directory + "/structs/structs.c", "-o", #directory + "/structs/c_structs", nil)
|
||||
posix.exit(69)
|
||||
case:
|
||||
if !wait_for(t, pid) { return }
|
||||
log.debug("C code has been compiled!")
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("compiling Odin project")
|
||||
{
|
||||
switch pid := posix.fork(); pid {
|
||||
case -1:
|
||||
log.errorf("fork() failed: %s", posix.strerror())
|
||||
case 0:
|
||||
posix.execlp(ODIN_ROOT + "/odin",
|
||||
ODIN_ROOT + "/odin", "build", #directory + "/structs/structs.odin", "-out:" + #directory + "/structs/odin_structs", "-file", nil)
|
||||
posix.exit(69)
|
||||
case:
|
||||
if !wait_for(t, pid) { return }
|
||||
log.debug("Odin code has been compiled!")
|
||||
}
|
||||
}
|
||||
|
||||
c_buf: [dynamic]byte
|
||||
defer delete(c_buf)
|
||||
c_out := get_output(t, &c_buf, #directory + "/structs/c_structs", nil)
|
||||
|
||||
odin_buf: [dynamic]byte
|
||||
defer delete(odin_buf)
|
||||
odin_out := get_output(t, &odin_buf, #directory + "/structs/odin_structs", nil)
|
||||
|
||||
testing.expectf(t, c_out == odin_out, "The C output and Odin output differ!\nC output:\n%s\n\n\n\nOdin Output:\n%s", c_out, odin_out)
|
||||
|
||||
/* ----------- HELPERS ----------- */
|
||||
|
||||
wait_for :: proc(t: ^testing.T, pid: posix.pid_t) -> (ok: bool) {
|
||||
log.debugf("waiting on pid %v", pid)
|
||||
|
||||
waiting: for {
|
||||
status: i32
|
||||
wpid := posix.waitpid(pid, &status, {})
|
||||
if !testing.expectf(t, wpid != -1, "waitpid() failure: %v", posix.strerror()) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch {
|
||||
case posix.WIFEXITED(status):
|
||||
ok = testing.expect_value(t, posix.WEXITSTATUS(status), 0)
|
||||
break waiting
|
||||
case posix.WIFSIGNALED(status):
|
||||
log.errorf("child process raised: %v", posix.strsignal(posix.WTERMSIG(status)))
|
||||
ok = false
|
||||
break waiting
|
||||
case:
|
||||
log.errorf("unexpected status (this should never happen): %v", status)
|
||||
ok = false
|
||||
break waiting
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
get_output :: proc(t: ^testing.T, output: ^[dynamic]byte, cmd: ..cstring) -> (out_str: string) {
|
||||
log.debugf("capturing output of: %v", cmd)
|
||||
|
||||
pipe: [2]posix.FD
|
||||
if !testing.expect_value(t, posix.pipe(&pipe), posix.result.OK) {
|
||||
return
|
||||
}
|
||||
|
||||
switch pid := posix.fork(); pid {
|
||||
case -1:
|
||||
log.errorf("fork() failed: %s", posix.strerror())
|
||||
return
|
||||
case 0:
|
||||
posix.close(pipe[0])
|
||||
posix.dup2(pipe[1], 1)
|
||||
posix.execv(cmd[0], raw_data(cmd[:]))
|
||||
panic(string(posix.strerror()))
|
||||
case:
|
||||
posix.close(pipe[1])
|
||||
log.debugf("waiting on pid %v", pid)
|
||||
|
||||
reader: for {
|
||||
buf: [256]byte
|
||||
switch read := posix.read(pipe[0], &buf[0], 256); {
|
||||
case read < 0:
|
||||
log.errorf("read output failed: %v", posix.strerror())
|
||||
return
|
||||
case read == 0:
|
||||
break reader
|
||||
case:
|
||||
append(output, ..buf[:read])
|
||||
}
|
||||
}
|
||||
|
||||
wait_for(t, pid)
|
||||
|
||||
return string(output[:])
|
||||
}
|
||||
}
|
||||
}
|
||||
2
tests/core/sys/posix/structs/.gitignore
vendored
Normal file
2
tests/core/sys/posix/structs/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
c_structs
|
||||
odin_structs
|
||||
103
tests/core/sys/posix/structs/structs.c
Normal file
103
tests/core/sys/posix/structs/structs.c
Normal file
@@ -0,0 +1,103 @@
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <glob.h>
|
||||
#include <grp.h>
|
||||
#include <locale.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/times.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <wordexp.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("dirent %zu %zu\n", sizeof(struct dirent), _Alignof(struct dirent));
|
||||
printf("flock %zu %zu\n", sizeof(struct flock), _Alignof(struct flock));
|
||||
printf("glob_t %zu %zu\n", sizeof(glob_t), _Alignof(glob_t));
|
||||
printf("group %zu %zu\n", sizeof(struct group), _Alignof(struct group));
|
||||
printf("lconv %zu %zu\n", sizeof(struct lconv), _Alignof(struct lconv));
|
||||
|
||||
printf("pthread_t %zu %zu\n", sizeof(pthread_t), _Alignof(pthread_t));
|
||||
printf("pthread_attr_t %zu %zu\n", sizeof(pthread_attr_t), _Alignof(pthread_attr_t));
|
||||
printf("pthread_key_t %zu %zu\n", sizeof(pthread_key_t), _Alignof(pthread_key_t));
|
||||
|
||||
printf("sched_param %zu %zu\n", sizeof(struct sched_param), _Alignof(struct sched_param));
|
||||
|
||||
printf("termios %zu %zu\n", sizeof(struct termios), _Alignof(struct termios));
|
||||
|
||||
printf("in_addr %zu %zu\n", sizeof(struct in_addr), _Alignof(struct in_addr));
|
||||
printf("in6_addr %zu %zu\n", sizeof(struct in6_addr), _Alignof(struct in6_addr));
|
||||
printf("sockaddr_in %zu %zu\n", sizeof(struct sockaddr_in), _Alignof(struct sockaddr_in));
|
||||
printf("sockaddr_in6 %zu %zu\n", sizeof(struct sockaddr_in6), _Alignof(struct sockaddr_in6));
|
||||
printf("ipv6_mreq %zu %zu\n", sizeof(struct ipv6_mreq), _Alignof(struct ipv6_mreq));
|
||||
|
||||
printf("sockaddr_storage %zu %zu\n", sizeof(struct sockaddr_storage), _Alignof(struct sockaddr_storage));
|
||||
printf("msghdr %zu %zu\n", sizeof(struct msghdr), _Alignof(struct msghdr));
|
||||
printf("cmsghdr %zu %zu\n", sizeof(struct cmsghdr), _Alignof(struct cmsghdr));
|
||||
printf("linger %zu %zu\n", sizeof(struct linger), _Alignof(struct linger));
|
||||
|
||||
printf("hostent %zu %zu\n", sizeof(struct hostent), _Alignof(struct hostent));
|
||||
printf("netent %zu %zu\n", sizeof(struct netent), _Alignof(struct netent));
|
||||
printf("protoent %zu %zu\n", sizeof(struct protoent), _Alignof(struct protoent));
|
||||
printf("servent %zu %zu\n", sizeof(struct servent), _Alignof(struct servent));
|
||||
printf("addrinfo %zu %zu\n", sizeof(struct addrinfo), _Alignof(struct addrinfo));
|
||||
|
||||
printf("pollfd %zu %zu\n", sizeof(struct pollfd), _Alignof(struct pollfd));
|
||||
|
||||
printf("passwd %zu %zu\n", sizeof(struct passwd), _Alignof(struct passwd));
|
||||
|
||||
printf("shmid_ds %zu %zu\n", sizeof(struct shmid_ds), _Alignof(struct shmid_ds));
|
||||
printf("ipc_perm %zu %zu\n", sizeof(struct ipc_perm), _Alignof(struct ipc_perm));
|
||||
printf("msqid_ds %zu %zu\n", sizeof(struct msqid_ds), _Alignof(struct msqid_ds));
|
||||
|
||||
printf("rlimit %zu %zu\n", sizeof(struct rlimit), _Alignof(struct rlimit));
|
||||
printf("rusage %zu %zu\n", sizeof(struct rusage), _Alignof(struct rusage));
|
||||
|
||||
printf("sockaddr_un %zu %zu\n", sizeof(struct sockaddr_un), _Alignof(struct sockaddr_un));
|
||||
|
||||
printf("utsname %zu %zu\n", sizeof(struct utsname), _Alignof(struct utsname));
|
||||
|
||||
printf("tms %zu %zu\n", sizeof(struct tms), _Alignof(struct tms));
|
||||
|
||||
printf("sigaction %zu %zu\n", sizeof(struct sigaction), _Alignof(struct sigaction));
|
||||
printf("stack_t %zu %zu\n", sizeof(stack_t), _Alignof(stack_t));
|
||||
printf("siginfo_t %zu %zu\n", sizeof(siginfo_t), _Alignof(siginfo_t));
|
||||
|
||||
printf("fd_set %zu %zu\n", sizeof(fd_set), _Alignof(fd_set));
|
||||
|
||||
printf("iovec %zu %zu\n", sizeof(struct iovec), _Alignof(struct iovec));
|
||||
|
||||
printf("semid_ds %zu %zu\n", sizeof(struct semid_ds), _Alignof(struct semid_ds));
|
||||
printf("sembuf %zu %zu\n", sizeof(struct sembuf), _Alignof(struct sembuf));
|
||||
|
||||
printf("itimerval %zu %zu\n", sizeof(struct itimerval), _Alignof(struct itimerval));
|
||||
|
||||
printf("utimbuf %zu %zu\n", sizeof(struct utimbuf), _Alignof(struct utimbuf));
|
||||
|
||||
printf("wordexp_t %zu %zu\n", sizeof(wordexp_t), _Alignof(wordexp_t));
|
||||
|
||||
printf("time_t %zu %zu\n", sizeof(time_t), _Alignof(time_t));
|
||||
printf("timespec %zu %zu\n", sizeof(struct timespec), _Alignof(struct timespec));
|
||||
printf("clock_t %zu %zu\n", sizeof(clock_t), _Alignof(clock_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
74
tests/core/sys/posix/structs/structs.odin
Normal file
74
tests/core/sys/posix/structs/structs.odin
Normal file
@@ -0,0 +1,74 @@
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:sys/posix"
|
||||
|
||||
main :: proc() {
|
||||
fmt.println("dirent", size_of(posix.dirent), align_of(posix.dirent))
|
||||
fmt.println("flock", size_of(posix.flock), align_of(posix.flock))
|
||||
fmt.println("glob_t", size_of(posix.glob_t), align_of(posix.glob_t))
|
||||
fmt.println("group", size_of(posix.group), align_of(posix.group))
|
||||
fmt.println("lconv", size_of(posix.lconv), align_of(posix.lconv))
|
||||
|
||||
fmt.println("pthread_t", size_of(posix.pthread_t), align_of(posix.pthread_t))
|
||||
fmt.println("pthread_attr_t", size_of(posix.pthread_attr_t), align_of(posix.pthread_attr_t))
|
||||
fmt.println("pthread_key_t", size_of(posix.pthread_key_t), align_of(posix.pthread_key_t))
|
||||
|
||||
fmt.println("sched_param", size_of(posix.sched_param), align_of(posix.sched_param))
|
||||
|
||||
fmt.println("termios", size_of(posix.termios), align_of(posix.termios))
|
||||
|
||||
fmt.println("in_addr", size_of(posix.in_addr), align_of(posix.in_addr))
|
||||
fmt.println("in6_addr", size_of(posix.in6_addr), align_of(posix.in6_addr))
|
||||
fmt.println("sockaddr_in", size_of(posix.sockaddr_in), align_of(posix.sockaddr_in))
|
||||
fmt.println("sockaddr_in6", size_of(posix.sockaddr_in6), align_of(posix.sockaddr_in6))
|
||||
fmt.println("ipv6_mreq", size_of(posix.ipv6_mreq), align_of(posix.ipv6_mreq))
|
||||
|
||||
fmt.println("sockaddr_storage", size_of(posix.sockaddr_storage), align_of(posix.sockaddr_storage))
|
||||
fmt.println("msghdr", size_of(posix.msghdr), align_of(posix.msghdr))
|
||||
fmt.println("cmsghdr", size_of(posix.cmsghdr), align_of(posix.cmsghdr))
|
||||
fmt.println("linger", size_of(posix.linger), align_of(posix.linger))
|
||||
|
||||
fmt.println("hostent", size_of(posix.hostent), align_of(posix.hostent))
|
||||
fmt.println("netent", size_of(posix.netent), align_of(posix.netent))
|
||||
fmt.println("protoent", size_of(posix.protoent), align_of(posix.protoent))
|
||||
fmt.println("servent", size_of(posix.servent), align_of(posix.servent))
|
||||
fmt.println("addrinfo", size_of(posix.addrinfo), align_of(posix.addrinfo))
|
||||
|
||||
fmt.println("pollfd", size_of(posix.pollfd), align_of(posix.pollfd))
|
||||
fmt.println("passwd", size_of(posix.passwd), align_of(posix.passwd))
|
||||
|
||||
fmt.println("shmid_ds", size_of(posix.shmid_ds), align_of(posix.shmid_ds))
|
||||
fmt.println("ipc_perm", size_of(posix.ipc_perm), align_of(posix.ipc_perm))
|
||||
fmt.println("msqid_ds", size_of(posix.msqid_ds), align_of(posix.msqid_ds))
|
||||
|
||||
fmt.println("rlimit", size_of(posix.rlimit), align_of(posix.rlimit))
|
||||
fmt.println("rusage", size_of(posix.rusage), align_of(posix.rusage))
|
||||
|
||||
fmt.println("sockaddr_un", size_of(posix.sockaddr_un), align_of(posix.sockaddr_un))
|
||||
|
||||
fmt.println("utsname", size_of(posix.utsname), align_of(posix.utsname))
|
||||
|
||||
fmt.println("tms", size_of(posix.tms), align_of(posix.tms))
|
||||
|
||||
fmt.println("sigaction", size_of(posix.sigaction_t), align_of(posix.sigaction_t))
|
||||
fmt.println("stack_t", size_of(posix.stack_t), align_of(posix.stack_t))
|
||||
fmt.println("siginfo_t", size_of(posix.siginfo_t), align_of(posix.siginfo_t))
|
||||
|
||||
fmt.println("fd_set", size_of(posix.fd_set), align_of(posix.fd_set))
|
||||
|
||||
fmt.println("iovec", size_of(posix.iovec), align_of(posix.iovec))
|
||||
|
||||
fmt.println("semid_ds", size_of(posix.semid_ds), align_of(posix.semid_ds))
|
||||
fmt.println("sembuf", size_of(posix.sembuf), align_of(posix.sembuf))
|
||||
|
||||
fmt.println("itimerval", size_of(posix.itimerval), align_of(posix.itimerval))
|
||||
|
||||
fmt.println("utimbuf", size_of(posix.utimbuf), align_of(posix.utimbuf))
|
||||
|
||||
fmt.println("wordexp_t", size_of(posix.wordexp_t), align_of(posix.wordexp_t))
|
||||
|
||||
fmt.println("time_t", size_of(posix.time_t), align_of(posix.time_t))
|
||||
fmt.println("timespec", size_of(posix.timespec), align_of(posix.timespec))
|
||||
fmt.println("clock_t", size_of(posix.clock_t), align_of(posix.clock_t))
|
||||
}
|
||||
Reference in New Issue
Block a user