Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 10 months ago
parent
commit
8a00d85cea
95 changed files with 1469 additions and 1638 deletions
  1. 1 13
      base/runtime/core_builtin.odin
  2. 2 2
      core/c/libc/README.md
  3. 133 0
      core/c/libc/locale.odin
  4. 5 5
      core/dynlib/lib.odin
  5. 5 3
      core/dynlib/lib_js.odin
  6. 20 10
      core/dynlib/lib_unix.odin
  7. 5 3
      core/dynlib/lib_windows.odin
  8. 1 1
      core/encoding/cbor/cbor.odin
  9. 1 1
      core/image/general.odin
  10. 1 1
      core/io/util.odin
  11. 49 0
      core/math/rand/rand.odin
  12. 1 1
      core/os/os2/process_windows.odin
  13. 1 1
      core/os/os_linux.odin
  14. 5 32
      core/path/filepath/path_unix.odin
  15. 1 0
      core/sys/posix/arpa_inet.odin
  16. 1 2
      core/sys/posix/dirent.odin
  17. 1 2
      core/sys/posix/dlfcn.odin
  18. 80 2
      core/sys/posix/errno.odin
  19. 3 4
      core/sys/posix/fcntl.odin
  20. 1 2
      core/sys/posix/fnmatch.odin
  21. 1 2
      core/sys/posix/glob.odin
  22. 1 2
      core/sys/posix/grp.odin
  23. 1 0
      core/sys/posix/iconv.odin
  24. 1 0
      core/sys/posix/langinfo.odin
  25. 8 0
      core/sys/posix/libgen.odin
  26. 1 2
      core/sys/posix/limits.odin
  27. 6 126
      core/sys/posix/locale.odin
  28. 1 0
      core/sys/posix/monetary.odin
  29. 1 2
      core/sys/posix/net_if.odin
  30. 1 2
      core/sys/posix/netdb.odin
  31. 6 2
      core/sys/posix/netinet_in.odin
  32. 1 2
      core/sys/posix/netinet_tcp.odin
  33. 1 3
      core/sys/posix/poll.odin
  34. 3 0
      core/sys/posix/posix.odin
  35. 46 7
      core/sys/posix/pthread.odin
  36. 13 2
      core/sys/posix/pwd.odin
  37. 1 2
      core/sys/posix/sched.odin
  38. 1 5
      core/sys/posix/setjmp.odin
  39. 11 0
      core/sys/posix/setjmp_libc.odin
  40. 2 109
      core/sys/posix/signal.odin
  41. 145 0
      core/sys/posix/signal_libc.odin
  42. 8 165
      core/sys/posix/stdio.odin
  43. 207 0
      core/sys/posix/stdio_libc.odin
  44. 1 78
      core/sys/posix/stdlib.odin
  45. 101 0
      core/sys/posix/stdlib_libc.odin
  46. 1 14
      core/sys/posix/string.odin
  47. 30 0
      core/sys/posix/string_libc.odin
  48. 1 2
      core/sys/posix/sys_ipc.odin
  49. 1 2
      core/sys/posix/sys_mman.odin
  50. 21 2
      core/sys/posix/sys_msg.odin
  51. 1 2
      core/sys/posix/sys_resource.odin
  52. 2 3
      core/sys/posix/sys_select.odin
  53. 1 2
      core/sys/posix/sys_sem.odin
  54. 21 2
      core/sys/posix/sys_shm.odin
  55. 5 5
      core/sys/posix/sys_socket.odin
  56. 120 67
      core/sys/posix/sys_stat.odin
  57. 24 2
      core/sys/posix/sys_statvfs.odin
  58. 1 2
      core/sys/posix/sys_time.odin
  59. 1 2
      core/sys/posix/sys_times.odin
  60. 1 2
      core/sys/posix/sys_uio.odin
  61. 1 2
      core/sys/posix/sys_un.odin
  62. 17 10
      core/sys/posix/sys_utsname.odin
  63. 51 2
      core/sys/posix/sys_wait.odin
  64. 8 9
      core/sys/posix/termios.odin
  65. 13 2
      core/sys/posix/time.odin
  66. 1 2
      core/sys/posix/ulimit.odin
  67. 2 110
      core/sys/posix/unistd.odin
  68. 153 0
      core/sys/posix/unistd_libc.odin
  69. 1 2
      core/sys/posix/utime.odin
  70. 1 2
      core/sys/posix/wordexp.odin
  71. 0 96
      core/sys/unix/pthread_darwin.odin
  72. 0 122
      core/sys/unix/pthread_freebsd.odin
  73. 0 71
      core/sys/unix/pthread_haiku.odin
  74. 0 124
      core/sys/unix/pthread_linux.odin
  75. 0 102
      core/sys/unix/pthread_netbsd.odin
  76. 0 74
      core/sys/unix/pthread_openbsd.odin
  77. 0 127
      core/sys/unix/pthread_unix.odin
  78. 8 0
      core/sys/unix/unix.odin
  79. 3 3
      core/testing/signal_handler_libc.odin
  80. 30 30
      core/thread/thread_unix.odin
  81. 1 1
      core/unicode/utf8/utf8string/string.odin
  82. 14 3
      src/big_int.cpp
  83. 4 0
      src/check_builtin.cpp
  84. 1 0
      src/exact_value.cpp
  85. 5 1
      src/gb/gb.h
  86. 1 1
      src/llvm_backend_expr.cpp
  87. 11 8
      src/llvm_backend_stmt.cpp
  88. 0 2
      src/parser.cpp
  89. 1 0
      src/string.cpp
  90. 9 4
      src/unicode.cpp
  91. 1 14
      tests/core/sys/posix/posix.odin
  92. 1 1
      tests/core/sys/posix/structs.odin
  93. 2 0
      tests/core/sys/posix/structs/structs.c
  94. 5 1
      tests/core/sys/posix/structs/structs.odin
  95. 7 7
      vendor/miniaudio/common_unix.odin

+ 1 - 13
base/runtime/core_builtin.odin

@@ -939,19 +939,7 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
 
 
 @builtin
 @builtin
 card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
 card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
-	when size_of(S) == 1 {
-		return int(intrinsics.count_ones(transmute(u8)s))
-	} else when size_of(S) == 2 {
-		return int(intrinsics.count_ones(transmute(u16)s))
-	} else when size_of(S) == 4 {
-		return int(intrinsics.count_ones(transmute(u32)s))
-	} else when size_of(S) == 8 {
-		return int(intrinsics.count_ones(transmute(u64)s))
-	} else when size_of(S) == 16 {
-		return int(intrinsics.count_ones(transmute(u128)s))
-	} else {
-		#panic("Unhandled card bit_set size")
-	}
+	return int(intrinsics.count_ones(transmute(intrinsics.type_bit_set_underlying_type(S))s))
 }
 }
 
 
 
 

+ 2 - 2
core/c/libc/README.md

@@ -14,7 +14,7 @@ The following is a mostly-complete projection of the C11 standard library as def
 | `<inttypes.h>`    | Fully projected                                    |
 | `<inttypes.h>`    | Fully projected                                    |
 | `<iso646.h>`      | Not applicable, use Odin's operators               |
 | `<iso646.h>`      | Not applicable, use Odin's operators               |
 | `<limits.h>`      | Not projected                                      |
 | `<limits.h>`      | Not projected                                      |
-| `<locale.h>`      | Not projected                                      |
+| `<locale.h>`      | Fully projected                                    |
 | `<math.h>`        | Mostly projected, see [limitations](#Limitations)  |
 | `<math.h>`        | Mostly projected, see [limitations](#Limitations)  |
 | `<setjmp.h>`      | Fully projected                                    |
 | `<setjmp.h>`      | Fully projected                                    |
 | `<signal.h>`      | Fully projected                                    |
 | `<signal.h>`      | Fully projected                                    |
@@ -70,4 +70,4 @@ with the following copyright.
 
 
 ```
 ```
 Copyright 2021 Dale Weiler <[email protected]>.
 Copyright 2021 Dale Weiler <[email protected]>.
-```
+```

+ 133 - 0
core/c/libc/locale.odin

@@ -0,0 +1,133 @@
+package libc
+
+import "core:c"
+
+when ODIN_OS == .Windows {
+	foreign import libc "system:libucrt.lib"
+} else when ODIN_OS == .Darwin {
+	foreign import libc "system:System.framework"
+} else {
+	foreign import libc "system:c"
+}
+
+// locale.h - category macros
+
+foreign libc {
+	/*
+	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 == .Windows {
+	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,
+		_W_decimal_point:     [^]u16 `fmt:"s,0"`,
+		_W_thousands_sep:     [^]u16 `fmt:"s,0"`,
+		_W_int_curr_symbol:   [^]u16 `fmt:"s,0"`,
+		_W_currency_symbol:   [^]u16 `fmt:"s,0"`,
+		_W_mon_decimal_point: [^]u16 `fmt:"s,0"`,
+		_W_mon_thousands_sep: [^]u16 `fmt:"s,0"`,
+		_W_positive_sign:     [^]u16 `fmt:"s,0"`,
+		_W_negative_sign:     [^]u16 `fmt:"s,0"`,
+	}
+} else {
+	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,
+	}
+}
+
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD  || ODIN_OS == .OpenBSD || ODIN_OS == .Windows {
+
+	LC_ALL      :: 0
+	LC_COLLATE  :: 1
+	LC_CTYPE    :: 2
+	LC_MESSAGES :: 6
+	LC_MONETARY :: 3
+	LC_NUMERIC  :: 4
+	LC_TIME     :: 5
+
+} else when ODIN_OS == .Linux {
+
+	LC_CTYPE    :: 0
+	LC_NUMERIC  :: 1
+	LC_TIME     :: 2
+	LC_COLLATE  :: 3
+	LC_MONETARY :: 4
+	LC_MESSAGES :: 5
+	LC_ALL      :: 6
+
+}

+ 5 - 5
core/dynlib/lib.odin

@@ -37,8 +37,8 @@ Example:
 		fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
 		fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
 	}
 	}
 */
 */
-load_library :: proc(path: string, global_symbols := false) -> (library: Library, did_load: bool) {
-	return _load_library(path, global_symbols)
+load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (library: Library, did_load: bool) {
+	return _load_library(path, global_symbols, allocator)
 }
 }
 
 
 /*
 /*
@@ -98,8 +98,8 @@ Example:
 		}
 		}
 	}
 	}
 */
 */
-symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok {
-	return _symbol_address(library, symbol)
+symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) #optional_ok {
+	return _symbol_address(library, symbol, allocator)
 }
 }
 
 
 /*
 /*
@@ -174,4 +174,4 @@ initialize_symbols :: proc(
 // Returns an error message for the last failed procedure call.
 // Returns an error message for the last failed procedure call.
 last_error :: proc() -> string {
 last_error :: proc() -> string {
 	return _last_error()
 	return _last_error()
-}
+}

+ 5 - 3
core/dynlib/lib_js.odin

@@ -2,7 +2,9 @@
 #+private
 #+private
 package dynlib
 package dynlib
 
 
-_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
+import "base:runtime"
+
+_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
 	return nil, false
 	return nil, false
 }
 }
 
 
@@ -10,10 +12,10 @@ _unload_library :: proc(library: Library) -> bool {
 	return false
 	return false
 }
 }
 
 
-_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
+_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) {
 	return nil, false
 	return nil, false
 }
 }
 
 
 _last_error :: proc() -> string {
 _last_error :: proc() -> string {
 	return ""
 	return ""
-}
+}

+ 20 - 10
core/dynlib/lib_unix.odin

@@ -2,28 +2,38 @@
 #+private
 #+private
 package dynlib
 package dynlib
 
 
-import "core:os"
+import "base:runtime"
 
 
-_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
-	flags := os.RTLD_NOW
+import "core:strings"
+import "core:sys/posix"
+
+_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
+	flags := posix.RTLD_Flags{.NOW}
 	if global_symbols {
 	if global_symbols {
-		flags |= os.RTLD_GLOBAL
+		flags += {.GLOBAL}
 	}
 	}
-	lib := os.dlopen(path, flags)
+
+	cpath := strings.clone_to_cstring(path, allocator)
+	defer delete(cpath, allocator)
+
+	lib := posix.dlopen(cpath, flags)
 	return Library(lib), lib != nil
 	return Library(lib), lib != nil
 }
 }
 
 
 _unload_library :: proc(library: Library) -> bool {
 _unload_library :: proc(library: Library) -> bool {
-	return os.dlclose(rawptr(library))
+	return posix.dlclose(posix.Symbol_Table(library)) == 0
 }
 }
 
 
-_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
-	ptr = os.dlsym(rawptr(library), symbol)
+_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) {
+	csymbol := strings.clone_to_cstring(symbol, allocator)
+	defer delete(csymbol, allocator)
+
+	ptr   = posix.dlsym(posix.Symbol_Table(library), csymbol)
 	found = ptr != nil
 	found = ptr != nil
 	return
 	return
 }
 }
 
 
 _last_error :: proc() -> string {
 _last_error :: proc() -> string {
-	err := os.dlerror()
+	err := string(posix.dlerror())
 	return "unknown" if err == "" else err
 	return "unknown" if err == "" else err
-}
+}

+ 5 - 3
core/dynlib/lib_windows.odin

@@ -2,11 +2,13 @@
 #+private
 #+private
 package dynlib
 package dynlib
 
 
+import "base:runtime"
+
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 import "core:strings"
 import "core:strings"
 import "core:reflect"
 import "core:reflect"
 
 
-_load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (Library, bool) {
+_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
 	// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
 	// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
 	wide_path := win32.utf8_to_wstring(path, allocator)
 	wide_path := win32.utf8_to_wstring(path, allocator)
 	defer free(wide_path, allocator)
 	defer free(wide_path, allocator)
@@ -19,7 +21,7 @@ _unload_library :: proc(library: Library) -> bool {
 	return bool(ok)
 	return bool(ok)
 }
 }
 
 
-_symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) {
+_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) {
 	c_str := strings.clone_to_cstring(symbol, allocator)
 	c_str := strings.clone_to_cstring(symbol, allocator)
 	defer delete(c_str, allocator)
 	defer delete(c_str, allocator)
 	ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
 	ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
@@ -31,4 +33,4 @@ _last_error :: proc() -> string {
 	err := win32.System_Error(win32.GetLastError())
 	err := win32.System_Error(win32.GetLastError())
 	err_msg := reflect.enum_string(err)
 	err_msg := reflect.enum_string(err)
 	return "unknown" if err_msg == "" else err_msg
 	return "unknown" if err_msg == "" else err_msg
-}
+}

+ 1 - 1
core/encoding/cbor/cbor.odin

@@ -563,7 +563,7 @@ to_json :: proc(val: Value, allocator := context.allocator) -> (json.Value, mem.
 					case: return false
 					case: return false
 					}
 					}
 				}
 				}
-				return false
+				return true
 			}
 			}
 
 
 			if keys_all_strings(v) {
 			if keys_all_strings(v) {

+ 1 - 1
core/image/general.odin

@@ -193,7 +193,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
 		return .HDR
 		return .HDR
 	case s[:4] == "\x38\x42\x50\x53":
 	case s[:4] == "\x38\x42\x50\x53":
 		return .PSD
 		return .PSD
-	case s[:4] != "\x53\x80\xF6\x34" && s[88:92] == "PICT":
+	case s[:4] == "\x53\x80\xF6\x34" && s[88:92] == "PICT":
 		return .PIC
 		return .PIC
 	case s[:4] == "\x69\x63\x6e\x73":
 	case s[:4] == "\x69\x63\x6e\x73":
 		return .ICNS
 		return .ICNS

+ 1 - 1
core/io/util.odin

@@ -225,7 +225,7 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
 			} else {
 			} else {
 				write_byte(w, '\\', &n) or_return
 				write_byte(w, '\\', &n) or_return
 				write_byte(w, 'U', &n)  or_return
 				write_byte(w, 'U', &n)  or_return
-				for s := 24; s >= 0; s -= 4 {
+				for s := 28; s >= 0; s -= 4 {
 					write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
 					write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
 				}
 				}
 			}
 			}

+ 49 - 0
core/math/rand/rand.odin

@@ -687,3 +687,52 @@ choice_enum :: proc($T: typeid, gen := context.random_generator) -> T where intr
 		return T(choice(values))
 		return T(choice(values))
 	}
 	}
 }
 }
+
+/*
+Returns a random *set* bit from the provided `bit_set`.
+
+Inputs:
+- set: The `bit_set` to choose a random set bit from
+
+Returns:
+- res: The randomly selected bit, or the zero value if `ok` is `false`
+- ok:  Whether the bit_set was not empty and thus `res` is actually a random set bit
+
+Example:
+	import "core:math/rand"
+	import "core:fmt"
+
+	choice_bit_set_example :: proc() {
+		Flags :: enum {
+			A,
+			B = 10,
+			C,
+		}
+
+		fmt.println(rand.choice_bit_set(bit_set[Flags]{}))
+		fmt.println(rand.choice_bit_set(bit_set[Flags]{.B}))
+		fmt.println(rand.choice_bit_set(bit_set[Flags]{.B, .C}))
+		fmt.println(rand.choice_bit_set(bit_set[0..<15]{5, 1, 4}))
+	}
+
+Possible Output:
+	A false
+	B true
+	C true
+	5 true
+*/
+@(require_results)
+choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, ok: bool) {
+	total_set := card(set)
+	if total_set == 0 {
+		return {}, false
+	}
+
+	core_set := transmute(intrinsics.type_bit_set_underlying_type(T))set
+
+	for target := int_max(total_set, gen); target > 0; target -= 1 {
+		core_set &= core_set - 1
+	}
+
+	return E(intrinsics.count_trailing_zeros(core_set)), true
+}

+ 1 - 1
core/os/os2/process_windows.odin

@@ -442,7 +442,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 		stderr_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd)
 		stderr_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd)
 	}
 	}
 	if desc.stdin != nil {
 	if desc.stdin != nil {
-		stdin_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd)
+		stdin_handle = win32.HANDLE((^File_Impl)(desc.stdin.impl).fd)
 	}
 	}
 
 
 	working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil
 	working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil

+ 1 - 1
core/os/os_linux.odin

@@ -490,7 +490,7 @@ foreign libc {
 	@(link_name="free")             _unix_free          :: proc(ptr: rawptr) ---
 	@(link_name="free")             _unix_free          :: proc(ptr: rawptr) ---
 	@(link_name="realloc")          _unix_realloc       :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
 	@(link_name="realloc")          _unix_realloc       :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
 
 
-	@(link_name="execvp")           _unix_execvp       :: proc(path: cstring, argv: [^]cstring) -> int ---
+	@(link_name="execvp")           _unix_execvp       :: proc(path: cstring, argv: [^]cstring) -> c.int ---
 	@(link_name="getenv")           _unix_getenv        :: proc(cstring) -> cstring ---
 	@(link_name="getenv")           _unix_getenv        :: proc(cstring) -> cstring ---
 	@(link_name="putenv")           _unix_putenv        :: proc(cstring) -> c.int ---
 	@(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="setenv")           _unix_setenv        :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int ---

+ 5 - 32
core/path/filepath/path_unix.odin

@@ -1,14 +1,10 @@
 #+build linux, darwin, freebsd, openbsd, netbsd
 #+build linux, darwin, freebsd, openbsd, netbsd
 package filepath
 package filepath
 
 
-when ODIN_OS == .Darwin {
-	foreign import libc "system:System.framework"
-} else {
-	foreign import libc "system:c"
-}
-
 import "base:runtime"
 import "base:runtime"
+
 import "core:strings"
 import "core:strings"
+import "core:sys/posix"
 
 
 SEPARATOR :: '/'
 SEPARATOR :: '/'
 SEPARATOR_STRING :: `/`
 SEPARATOR_STRING :: `/`
@@ -28,11 +24,11 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
 		rel = "."
 		rel = "."
 	}
 	}
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
 	rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
-	path_ptr := realpath(rel_cstr, nil)
+	path_ptr := posix.realpath(rel_cstr, nil)
 	if path_ptr == nil {
 	if path_ptr == nil {
-		return "", __error()^ == 0
+		return "", posix.errno() == nil
 	}
 	}
-	defer _unix_free(rawptr(path_ptr))
+	defer posix.free(path_ptr)
 
 
 	path_str := strings.clone(string(path_ptr), allocator)
 	path_str := strings.clone(string(path_ptr), allocator)
 	return path_str, true
 	return path_str, true
@@ -48,26 +44,3 @@ join :: proc(elems: []string, allocator := context.allocator) -> (joined: string
 	}
 	}
 	return "", nil
 	return "", nil
 }
 }
-
-@(private)
-foreign libc {
-	realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring ---
-	@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
-
-}
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
-	@(private)
-	foreign libc {
-		@(link_name="__error")          __error :: proc() -> ^i32 ---
-	}
-} else when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
-	@(private)
-	foreign libc {
-		@(link_name="__errno")		__error :: proc() -> ^i32 ---
-	}
-} else {
-	@(private)
-	foreign libc {
-		@(link_name="__errno_location") __error :: proc() -> ^i32 ---
-	}
-}

+ 1 - 0
core/sys/posix/arpa_inet.odin

@@ -1,3 +1,4 @@
+#+build darwin, linux, freebsd, openbsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"

+ 1 - 2
core/sys/posix/dirent.odin

@@ -1,3 +1,4 @@
+#+build darwin, linux, freebsd, openbsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -210,6 +211,4 @@ when ODIN_OS == .Darwin {
 			d_name:   [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
 			d_name:   [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
 		}
 		}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/dlfcn.odin

@@ -1,3 +1,4 @@
+#+build darwin, linux, freebsd, openbsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -120,7 +121,5 @@ when ODIN_OS == .Darwin {
 	_RTLD_LOCAL  :: 0
 	_RTLD_LOCAL  :: 0
 	RTLD_LOCAL   :: RTLD_Flags{}
 	RTLD_LOCAL   :: RTLD_Flags{}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }
 
 

+ 80 - 2
core/sys/posix/errno.odin

@@ -1,3 +1,4 @@
+#+build windows, darwin, linux, freebsd, openbsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -456,7 +457,84 @@ when ODIN_OS == .Darwin {
 
 
 	EOWNERDEAD      :: 130
 	EOWNERDEAD      :: 130
 	ENOTRECOVERABLE :: 131
 	ENOTRECOVERABLE :: 131
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Windows {
+	E2BIG           :: 7
+	EACCES          :: 13
+	EADDRINUSE      :: 100
+	EADDRNOTAVAIL   :: 101
+	EAFNOSUPPORT    :: 102
+	EAGAIN          :: 11
+	EALREADY        :: 103
+	EBADF           :: 9
+	EBADMSG         :: 104
+	EBUSY           :: 16
+	ECANCELED       :: 105
+	ECHILD          :: 10
+	ECONNABORTED    :: 106
+	ECONNREFUSED    :: 107
+	ECONNRESET      :: 108
+	EDEADLK         :: 36
+	EDESTADDRREQ    :: 109
+	EDQUOT          :: -1 // NOTE: not defined
+	EEXIST          :: 17
+	EFAULT          :: 14
+	EFBIG           :: 27
+	EHOSTUNREACH    :: 110
+	EIDRM           :: 111
+	EINPROGRESS     :: 112
+	EINTR           :: 4
+	EINVAL          :: 22
+	EIO             :: 5
+	EISCONN         :: 113
+	EISDIR          :: 21
+	ELOOP           :: 114
+	EMFILE          :: 24
+	EMLINK          :: 31
+	EMSGSIZE        :: 115
+	EMULTIHOP       :: -1 // NOTE: not defined
+	ENAMETOOLONG    :: 38
+	ENETDOWN        :: 116
+	ENETRESET       :: 117
+	ENETUNREACH     :: 118
+	ENFILE          :: 23
+	ENOBUFS         :: 119
+	ENODATA         :: 120
+	ENODEV          :: 19
+	ENOENT          :: 2
+	ENOEXEC         :: 8
+	ENOLCK          :: 39
+	ENOLINK         :: 121
+	ENOMEM          :: 12
+	ENOMSG          :: 122
+	ENOPROTOOPT     :: 123
+	ENOSPC          :: 28
+	ENOSR           :: 124
+	ENOSTR          :: 125
+	ENOSYS          :: 40
+	ENOTCONN        :: 126
+	ENOTDIR         :: 20
+	ENOTEMPTY       :: 41
+	ENOTRECOVERABLE :: 127
+	ENOTSOCK        :: 128
+	ENOTSUP         :: 129
+	ENOTTY          :: 25
+	ENXIO           :: 6
+	EOPNOTSUPP      :: 130
+	EOVERFLOW       :: 132
+	EOWNERDEAD      :: 133
+	EPERM           :: 1
+	EPIPE           :: 32
+	EPROTO          :: 134
+	EPROTONOSUPPORT :: 135
+	EPROTOTYPE      :: 136
+	EROFS           :: 30
+	ESPIPE          :: 29
+	ESRCH           :: 3
+	ESTALE          :: -1 // NOTE: not defined
+	ETIME           :: 137
+	ETIMEDOUT       :: 138
+	ETXTBSY         :: 139
+	EWOULDBLOCK     :: 140
+	EXDEV           :: 18
 }
 }
 
 

+ 3 - 4
core/sys/posix/fcntl.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, openbsd, freebsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -466,13 +467,11 @@ when ODIN_OS == .Darwin {
 	AT_REMOVEDIR        :: 0x200
 	AT_REMOVEDIR        :: 0x200
 
 
 	flock :: struct {
 	flock :: struct {
+		l_type:   Lock_Type, /* [PSX] type of lock. */
+		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset. */
 		l_start:  off_t,     /* [PSX] relative offset in bytes. */
 		l_start:  off_t,     /* [PSX] relative offset in bytes. */
 		l_len:    off_t,     /* [PSX] size; if 0 then until EOF. */
 		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_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")
 }
 }

+ 1 - 2
core/sys/posix/fnmatch.odin

@@ -1,3 +1,4 @@
+#+build darwin, linux, openbsd, freebsd, netbsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -61,6 +62,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	FNM_NOESCAPE :: 0x02
 	FNM_NOESCAPE :: 0x02
 	FNM_PERIOD   :: 0x04
 	FNM_PERIOD   :: 0x04
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/glob.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -203,6 +204,4 @@ when ODIN_OS == .Darwin {
 	GLOB_ABORTED :: 2
 	GLOB_ABORTED :: 2
 	GLOB_NOMATCH :: 3
 	GLOB_NOMATCH :: 3
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/grp.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -125,6 +126,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		gr_mem:    [^]cstring, /* [PSX] group members */
 		gr_mem:    [^]cstring, /* [PSX] group members */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 0
core/sys/posix/iconv.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"

+ 1 - 0
core/sys/posix/langinfo.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"

+ 8 - 0
core/sys/posix/libgen.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
@@ -56,6 +57,7 @@ foreign lib {
 
 
 	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/basename.html ]]
 	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/basename.html ]]
 	*/
 	*/
+	@(link_name=LBASENAME)
 	basename :: proc(path: cstring) -> cstring ---
 	basename :: proc(path: cstring) -> cstring ---
 
 
 	/*
 	/*
@@ -72,3 +74,9 @@ foreign lib {
 	*/
 	*/
 	dirname :: proc(path: cstring) -> cstring ---
 	dirname :: proc(path: cstring) -> cstring ---
 }
 }
+
+when ODIN_OS == .Linux {
+	@(private) LBASENAME :: "__xpg_basename"
+} else {
+	@(private) LBASENAME :: "basename"
+}

+ 1 - 2
core/sys/posix/limits.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 // limits.h - implementation-defined constants
 // limits.h - implementation-defined constants
@@ -549,6 +550,4 @@ when ODIN_OS == .Darwin {
 	NL_TEXTMAX :: 2048 // 255 on glibc, 2048 on musl
 	NL_TEXTMAX :: 2048 // 255 on glibc, 2048 on musl
 	NZERO      :: 20
 	NZERO      :: 20
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 6 - 126
core/sys/posix/locale.odin

@@ -1,131 +1,11 @@
+#+build windows, linux, darwin, netbsd, openbsd, freebsd
 package posix
 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"
-}
+localeconv      :: libc.localeconv
+setlocale       :: libc.setlocale
 
 
-// locale.h - category macros
+lconv           :: libc.lconv
 
 
-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 when ODIN_OS == .Linux {
-
-	// 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_CTYPE    :: 0
-	LC_NUMERIC  :: 1
-	LC_TIME     :: 2
-	LC_COLLATE  :: 3
-	LC_MONETARY :: 4
-	LC_MESSAGES :: 5
-	LC_ALL      :: 6
-
-} else {
-	#panic("posix is unimplemented for the current target")
-}
+Locale_Category :: libc.Locale_Category

+ 1 - 0
core/sys/posix/monetary.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"

+ 1 - 2
core/sys/posix/net_if.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -55,6 +56,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	IF_NAMESIZE :: 16
 	IF_NAMESIZE :: 16
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/netdb.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -472,6 +473,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		EAI_OVERFLOW :: 14
 		EAI_OVERFLOW :: 14
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 6 - 2
core/sys/posix/netinet_in.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -61,6 +62,11 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 			sin6_scope_id: c.uint32_t,  /* [PSX] set of interfaces for a scope */
 			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 */
+		}
+
 		IPV6_MULTICAST_IF   :: 17
 		IPV6_MULTICAST_IF   :: 17
 		IPV6_UNICAST_HOPS   :: 16
 		IPV6_UNICAST_HOPS   :: 16
 		IPV6_MULTICAST_HOPS :: 18
 		IPV6_MULTICAST_HOPS :: 18
@@ -223,6 +229,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		)
 		)
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/netinet_tcp.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
@@ -6,6 +7,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	TCP_NODELAY :: 0x01
 	TCP_NODELAY :: 0x01
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 3
core/sys/posix/poll.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "base:intrinsics"
 import "base:intrinsics"
@@ -92,7 +93,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	POLLHUP    :: 0x0010
 	POLLHUP    :: 0x0010
 	POLLNVAL   :: 0x0020
 	POLLNVAL   :: 0x0020
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }
-

+ 3 - 0
core/sys/posix/posix.odin

@@ -11,6 +11,9 @@ The struct fields that are cross-platform are documented with `[PSX]`.
 Accessing these fields on one target should be the same on others.
 Accessing these fields on one target should be the same on others.
 Other fields are implementation specific.
 Other fields are implementation specific.
 
 
+The parts of POSIX that Windows implements are also supported here, but
+other symbols are undefined on Windows targets.
+
 Most macros have been reimplemented in Odin with inlined functions.
 Most macros have been reimplemented in Odin with inlined functions.
 
 
 Unimplemented headers:
 Unimplemented headers:

+ 46 - 7
core/sys/posix/pthread.odin

@@ -1,10 +1,11 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 	foreign import lib "system:System.framework"
 	foreign import lib "system:System.framework"
-} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
+} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux {
 	foreign import lib "system:pthread"
 	foreign import lib "system:pthread"
 } else {
 } else {
 	foreign import lib "system:c"
 	foreign import lib "system:c"
@@ -398,6 +399,16 @@ when ODIN_OS == .Darwin {
 
 
 	pthread_key_t :: distinct c.ulong
 	pthread_key_t :: distinct c.ulong
 
 
+	pthread_mutex_t :: struct {
+		__sig:    c.long,
+		__opaque: [56]c.char,
+	}
+
+	pthread_cond_t :: struct {
+		__sig:    c.long,
+		__opaque: [40]c.char,
+	}
+
 	sched_param :: struct {
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		_:              [4]c.char,
 		_:              [4]c.char,
@@ -431,10 +442,20 @@ when ODIN_OS == .Darwin {
 
 
 	pthread_t :: distinct u64
 	pthread_t :: distinct u64
 
 
-	pthread_attr_t :: distinct rawptr
+	pthread_attr_t :: struct #align(8) {
+		_: [8]byte,
+	}
 
 
 	pthread_key_t :: distinct c.int
 	pthread_key_t :: distinct c.int
 
 
+	pthread_mutex_t :: struct #align(8) {
+		_: [8]byte,
+	}
+
+	pthread_cond_t  :: struct #align(8) {
+		_: [8]byte,
+	}
+
 	sched_param :: struct {
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 	}
 	}
@@ -475,6 +496,14 @@ when ODIN_OS == .Darwin {
 
 
 	pthread_key_t :: distinct c.int
 	pthread_key_t :: distinct c.int
 
 
+	pthread_cond_t :: struct #align(8) {
+		_: [40]byte,
+	}
+
+	pthread_mutex_t :: struct #align(8) {
+		_: [48]byte,
+	}
+
 	sched_param :: struct {
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 	}
 	}
@@ -505,9 +534,11 @@ when ODIN_OS == .Darwin {
 	PTHREAD_SCOPE_PROCESS   :: 0
 	PTHREAD_SCOPE_PROCESS   :: 0
 	PTHREAD_SCOPE_SYSTEM    :: 0x2
 	PTHREAD_SCOPE_SYSTEM    :: 0x2
 
 
-	pthread_t      :: distinct rawptr
-	pthread_attr_t :: distinct rawptr
-	pthread_key_t  :: distinct c.int
+	pthread_t       :: distinct rawptr
+	pthread_attr_t  :: distinct rawptr
+	pthread_key_t   :: distinct c.int
+	pthread_mutex_t :: distinct rawptr
+	pthread_cond_t  :: distinct rawptr
 
 
 	sched_param :: struct {
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
@@ -548,6 +579,16 @@ when ODIN_OS == .Darwin {
 
 
 	pthread_key_t :: distinct c.uint
 	pthread_key_t :: distinct c.uint
 
 
+	pthread_cond_t :: struct {
+		__size: [40]c.char, // NOTE: may be smaller depending on libc or arch, but never larger.
+		__align: c.long,
+	}
+
+	pthread_mutex_t :: struct {
+		__size: [32]c.char, // NOTE: may be smaller depending on libc or arch, but never larger.
+		__align: c.long,
+	}
+
 	sched_param :: struct {
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 
 
@@ -557,6 +598,4 @@ when ODIN_OS == .Darwin {
 		__reserved3: c.int,
 		__reserved3: c.int,
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 13 - 2
core/sys/posix/pwd.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -163,6 +164,16 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 		pw_fields: c.int,
 		pw_fields: c.int,
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	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_gecos:  cstring, /* Real name.  */
+		pw_dir:    cstring, /* Home directory.  */
+		pw_shell:  cstring, /* Shell program.  */
+	}
+
 }
 }

+ 1 - 2
core/sys/posix/sched.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -100,6 +101,4 @@ when ODIN_OS == .Darwin {
 	SCHED_FIFO     :: 1
 	SCHED_FIFO     :: 1
 	SCHED_RR       :: 2
 	SCHED_RR       :: 2
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 5
core/sys/posix/setjmp.odin

@@ -1,7 +1,7 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
-import "core:c/libc"
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 	foreign import lib "system:System.framework"
 	foreign import lib "system:System.framework"
@@ -43,12 +43,8 @@ foreign lib {
 	sigsetjmp :: proc(env: ^sigjmp_buf, savemask: b32) -> c.int ---
 	sigsetjmp :: proc(env: ^sigjmp_buf, savemask: b32) -> c.int ---
 }
 }
 
 
-jmp_buf    :: libc.jmp_buf
 sigjmp_buf :: distinct jmp_buf
 sigjmp_buf :: distinct jmp_buf
 
 
-longjmp :: libc.longjmp
-setjmp  :: libc.setjmp
-
 when ODIN_OS == .NetBSD {
 when ODIN_OS == .NetBSD {
 	@(private) LSIGSETJMP  :: "__sigsetjmp14"
 	@(private) LSIGSETJMP  :: "__sigsetjmp14"
 	@(private) LSIGLONGJMP :: "__siglongjmp14"
 	@(private) LSIGLONGJMP :: "__siglongjmp14"

+ 11 - 0
core/sys/posix/setjmp_libc.odin

@@ -0,0 +1,11 @@
+#+build windows, linux, darwin, netbsd, openbsd, freebsd
+package posix
+
+import "core:c/libc"
+
+// setjmp.h - stack environment declarations
+
+jmp_buf :: libc.jmp_buf
+
+longjmp :: libc.longjmp
+setjmp  :: libc.setjmp

+ 2 - 109
core/sys/posix/signal.odin

@@ -1,9 +1,9 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "base:intrinsics"
 import "base:intrinsics"
 
 
 import "core:c"
 import "core:c"
-import "core:c/libc"
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 	foreign import lib "system:System.framework"
 	foreign import lib "system:System.framework"
@@ -14,31 +14,6 @@ when ODIN_OS == .Darwin {
 // signal.h - signals
 // signal.h - signals
 
 
 foreign lib {
 foreign lib {
-	// LIBC:
-
-	/*
-	Set a signal handler.
-
-	func can either be:
-	- `auto_cast posix.SIG_DFL` setting the default handler for that specific signal
-	- `auto_cast posix.SIG_IGN` causing the specific signal to be ignored
-	- a custom signal handler
-
-	Returns: SIG_ERR (setting errno), the last value of func on success
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html ]]
-	*/
-	signal :: proc(sig: Signal, func: proc "c" (Signal)) -> proc "c" (Signal) ---
-
-	/*
-	Raises a signal, calling its handler and then returning.
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html ]]
-	*/
-	raise :: proc(sig: Signal) -> result ---
-
-	// POSIX:
-
 	/*
 	/*
 	Raise a signal to the process/group specified by pid.
 	Raise a signal to the process/group specified by pid.
 
 
@@ -227,72 +202,6 @@ sigval :: struct #raw_union {
 	sigval_ptr: rawptr, /* [PSX] pointer signal value */
 	sigval_ptr: rawptr, /* [PSX] pointer signal value */
 }
 }
 
 
-Signal :: enum c.int {
-	NONE,
-
-	// LIBC:
-
-	// Process abort signal.
-	SIGABRT   = SIGABRT,
-	// Erronous arithemtic operation.
-	SIGFPE    = SIGFPE,
-	// Illegal instruction.
-	SIGILL    = SIGILL,
-	// Terminal interrupt signal.
-	SIGINT    = SIGINT,
-	// Invalid memory reference.
-	SIGSEGV   = SIGSEGV,
-	// Termination signal.
-	SIGTERM   = SIGTERM,
-
-	// POSIX:
-
-	// Process abort signal.
-	SIGALRM   = SIGALRM,
-	// Access to an undefined portion of a memory object.
-	SIGBUS    = SIGBUS,
-	// Child process terminated, stopped, or continued.
-	SIGCHLD   = SIGCHLD,
-	// Continue execution, if stopped.
-	SIGCONT   = SIGCONT,
-	// Hangup.
-	SIGHUP    = SIGHUP,
-	// Kill (cannot be caught or ignored).
-	SIGKILL   = SIGKILL,
-	// Write on a pipe with no one to read it.
-	SIGPIPE   = SIGPIPE,
-	// Terminal quit signal.
-	SIGQUIT   = SIGQUIT,
-	// Stop executing (cannot be caught or ignored).
-	SIGSTOP   = SIGSTOP,
-	// Terminal stop process.
-	SIGTSTP   = SIGTSTP,
-	// Background process attempting read.
-	SIGTTIN   = SIGTTIN,
-	// Background process attempting write.
-	SIGTTOU   = SIGTTOU,
-	// User-defined signal 1.
-	SIGUSR1   = SIGUSR1,
-	// User-defined signal 2.
-	SIGUSR2   = SIGUSR2,
-	// Pollable event.
-	SIGPOLL   = SIGPOLL,
-	// Profiling timer expired.
-	SIGPROF   = SIGPROF,
-	// Bad system call.
-	SIGSYS    = SIGSYS,
-	// Trace/breakpoint trap.
-	SIGTRAP   = SIGTRAP,
-	// High bandwidth data is available at a socket.
-	SIGURG    = SIGURG,
-	// Virtual timer expired.
-	SIGVTALRM = SIGVTALRM,
-	// CPU time limit exceeded.
-	SIGXCPU   = SIGXCPU,
-	// File size limit exceeded.
-	SIGXFSZ   = SIGXFSZ,
-}
-
 ILL_Code :: enum c.int {
 ILL_Code :: enum c.int {
 	// Illegal opcode.
 	// Illegal opcode.
 	ILLOPC = ILL_ILLOPC,
 	ILLOPC = ILL_ILLOPC,
@@ -434,20 +343,6 @@ Sig :: enum c.int {
 	SETMASK = SIG_SETMASK,
 	SETMASK = SIG_SETMASK,
 }
 }
 
 
-// Request for default signal handling.
-SIG_DFL :: libc.SIG_DFL
-// Return value from signal() in case of error.
-SIG_ERR :: libc.SIG_ERR
-// Request that signal be ignored.
-SIG_IGN :: libc.SIG_IGN
-
-SIGABRT :: libc.SIGABRT
-SIGFPE  :: libc.SIGFPE
-SIGILL  :: libc.SIGILL
-SIGINT  :: libc.SIGINT
-SIGSEGV :: libc.SIGSEGV
-SIGTERM :: libc.SIGTERM
-
 when ODIN_OS == .NetBSD {
 when ODIN_OS == .NetBSD {
 	@(private) LSIGPROCMASK :: "__sigprocmask14"
 	@(private) LSIGPROCMASK :: "__sigprocmask14"
 	@(private) LSIGACTION   :: "__sigaction_siginfo"
 	@(private) LSIGACTION   :: "__sigaction_siginfo"
@@ -1118,7 +1013,7 @@ when ODIN_OS == .Darwin {
 
 
 	uid_t :: distinct c.uint32_t
 	uid_t :: distinct c.uint32_t
 	sigset_t :: struct {
 	sigset_t :: struct {
-		[1024/(8 * size_of(c.ulong))]val,
+		__val: [1024/(8 * size_of(c.ulong))]c.ulong,
 	}
 	}
 
 
 	SIGHUP    :: 1
 	SIGHUP    :: 1
@@ -1285,6 +1180,4 @@ when ODIN_OS == .Darwin {
 	SI_TIMER   :: -2
 	SI_TIMER   :: -2
 	SI_MESGQ   :: -3
 	SI_MESGQ   :: -3
 	SI_ASYNCIO :: -4
 	SI_ASYNCIO :: -4
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 145 - 0
core/sys/posix/signal_libc.odin

@@ -0,0 +1,145 @@
+#+build linux, windows, darwin, netbsd, openbsd, freebsd
+package posix
+
+import "base:intrinsics"
+
+import "core:c"
+import "core:c/libc"
+
+when ODIN_OS == .Windows {
+	foreign import lib "system:libucrt.lib"
+} else when ODIN_OS == .Darwin {
+	foreign import lib "system:System.framework"
+} else {
+	foreign import lib "system:c"
+}
+
+// signal.h - signals
+
+foreign lib {
+	/*
+	Set a signal handler.
+
+	func can either be:
+	- `auto_cast posix.SIG_DFL` setting the default handler for that specific signal
+	- `auto_cast posix.SIG_IGN` causing the specific signal to be ignored
+	- a custom signal handler
+
+	Returns: SIG_ERR (setting errno), the last value of func on success
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html ]]
+	*/
+	signal :: proc(sig: Signal, func: proc "c" (Signal)) -> proc "c" (Signal) ---
+
+	/*
+	Raises a signal, calling its handler and then returning.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html ]]
+	*/
+	raise :: proc(sig: Signal) -> result ---
+}
+
+Signal :: enum c.int {
+	NONE,
+
+	// LIBC:
+
+	// Process abort signal.
+	SIGABRT   = SIGABRT,
+	// Erronous arithemtic operation.
+	SIGFPE    = SIGFPE,
+	// Illegal instruction.
+	SIGILL    = SIGILL,
+	// Terminal interrupt signal.
+	SIGINT    = SIGINT,
+	// Invalid memory reference.
+	SIGSEGV   = SIGSEGV,
+	// Termination signal.
+	SIGTERM   = SIGTERM,
+
+	// POSIX:
+
+	// Process abort signal.
+	SIGALRM   = SIGALRM,
+	// Access to an undefined portion of a memory object.
+	SIGBUS    = SIGBUS,
+	// Child process terminated, stopped, or continued.
+	SIGCHLD   = SIGCHLD,
+	// Continue execution, if stopped.
+	SIGCONT   = SIGCONT,
+	// Hangup.
+	SIGHUP    = SIGHUP,
+	// Kill (cannot be caught or ignored).
+	SIGKILL   = SIGKILL,
+	// Write on a pipe with no one to read it.
+	SIGPIPE   = SIGPIPE,
+	// Terminal quit signal.
+	SIGQUIT   = SIGQUIT,
+	// Stop executing (cannot be caught or ignored).
+	SIGSTOP   = SIGSTOP,
+	// Terminal stop process.
+	SIGTSTP   = SIGTSTP,
+	// Background process attempting read.
+	SIGTTIN   = SIGTTIN,
+	// Background process attempting write.
+	SIGTTOU   = SIGTTOU,
+	// User-defined signal 1.
+	SIGUSR1   = SIGUSR1,
+	// User-defined signal 2.
+	SIGUSR2   = SIGUSR2,
+	// Pollable event.
+	SIGPOLL   = SIGPOLL,
+	// Profiling timer expired.
+	SIGPROF   = SIGPROF,
+	// Bad system call.
+	SIGSYS    = SIGSYS,
+	// Trace/breakpoint trap.
+	SIGTRAP   = SIGTRAP,
+	// High bandwidth data is available at a socket.
+	SIGURG    = SIGURG,
+	// Virtual timer expired.
+	SIGVTALRM = SIGVTALRM,
+	// CPU time limit exceeded.
+	SIGXCPU   = SIGXCPU,
+	// File size limit exceeded.
+	SIGXFSZ   = SIGXFSZ,
+}
+
+// Request for default signal handling.
+SIG_DFL :: libc.SIG_DFL
+// Return value from signal() in case of error.
+SIG_ERR :: libc.SIG_ERR
+// Request that signal be ignored.
+SIG_IGN :: libc.SIG_IGN
+
+SIGABRT :: libc.SIGABRT
+SIGFPE  :: libc.SIGFPE
+SIGILL  :: libc.SIGILL
+SIGINT  :: libc.SIGINT
+SIGSEGV :: libc.SIGSEGV
+SIGTERM :: libc.SIGTERM
+
+when ODIN_OS == .Windows {
+	SIGALRM   :: -1
+	SIGBUS    :: -1
+	SIGCHLD   :: -1
+	SIGCONT   :: -1
+	SIGHUP    :: -1
+	SIGKILL   :: -1
+	SIGPIPE   :: -1
+	SIGQUIT   :: -1
+	SIGSTOP   :: -1
+	SIGTSTP   :: -1
+	SIGTTIN   :: -1
+	SIGTTOU   :: -1
+	SIGUSR1   :: -1
+	SIGUSR2   :: -1
+	SIGPOLL   :: -1
+	SIGPROF   :: -1
+	SIGSYS    :: -1
+	SIGTRAP   :: -1
+	SIGURG    :: -1
+	SIGVTALRM :: -1
+	SIGXCPU   :: -1
+	SIGXFSZ   :: -1
+}

+ 8 - 165
core/sys/posix/stdio.odin

@@ -1,7 +1,7 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
-import "core:c/libc"
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 	foreign import lib "system:System.framework"
 	foreign import lib "system:System.framework"
@@ -32,16 +32,6 @@ foreign lib {
 	*/
 	*/
 	dprintf :: proc(fildse: FD, format: cstring, #c_vararg args: ..any) -> c.int ---
 	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.
 	Associate a stream with a file descriptor.
 
 
@@ -115,34 +105,6 @@ foreign lib {
 	*/
 	*/
 	open_memstream :: proc(bufp: ^[^]byte, sizep: ^c.size_t) -> ^FILE ---
 	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.
 	Read a delimited record from the stream.
 
 
@@ -181,60 +143,6 @@ foreign lib {
 	*/
 	*/
 	getline :: proc(lineptr: ^cstring, n: ^c.size_t, stream: ^FILE) -> c.ssize_t ---
 	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.
 	Equivalent to rename but relative directories are resolved from their respective fds.
 
 
@@ -243,76 +151,6 @@ foreign lib {
 	renameat :: proc(oldfd: FD, old: cstring, newfd: FD, new: cstring) -> result ---
 	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 {
 when ODIN_OS == .Darwin {
 
 
 	L_ctermid :: 1024
 	L_ctermid :: 1024
@@ -327,6 +165,11 @@ when ODIN_OS == .Darwin {
 
 
 	P_tmpdir :: "/tmp/"
 	P_tmpdir :: "/tmp/"
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	L_ctermid :: 20 // 20 on musl, 9 on glibc
+	L_tmpnam  :: 20
+
+	P_tmpdir :: "/tmp/"
+
 }
 }

+ 207 - 0
core/sys/posix/stdio_libc.odin

@@ -0,0 +1,207 @@
+#+build linux, windows, linux, darwin, netbsd, openbsd, freebsd
+package posix
+
+import "core:c"
+import "core:c/libc"
+
+when ODIN_OS == .Windows {
+	foreign import lib {
+		"system:libucrt.lib",
+		"system:legacy_stdio_definitions.lib",
+	}
+} else when ODIN_OS == .Darwin {
+	foreign import lib "system:System.framework"
+} else {
+	foreign import lib "system:c"
+}
+
+// stdio.h - standard buffered input/output
+
+when ODIN_OS == .Windows {
+	@(private) LGETC_UNLOCKED    :: "_getc_nolock"
+	@(private) LGETCHAR_UNLOCKED :: "_getchar_nolock"
+	@(private) LPUTC_UNLOCKED    :: "_putc_nolock"
+	@(private) LPUTCHAR_UNLOCKED :: "_putchar_nolock"
+	@(private) LTEMPNAM          :: "_tempnam"
+	@(private) LPOPEN            :: "_popen"
+	@(private) LPCLOSE           :: "_pclose"
+} else {
+	@(private) LGETC_UNLOCKED    :: "getc_unlocked"
+	@(private) LGETCHAR_UNLOCKED :: "getchar_unlocked"
+	@(private) LPUTC_UNLOCKED    :: "putc_unlocked"
+	@(private) LPUTCHAR_UNLOCKED :: "putchar_unlocked"
+	@(private) LTEMPNAM          :: "tempnam"
+	@(private) LPOPEN            :: "popen"
+	@(private) LPCLOSE           :: "pclose"
+}
+
+foreign lib {
+	/*
+	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 ---
+
+	/*
+	Equivalent to getc but unaffected by locks.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
+	*/
+	@(link_name=LGETC_UNLOCKED)
+	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 ]]
+	*/
+	@(link_name=LGETCHAR_UNLOCKED)
+	getchar_unlocked :: proc() -> c.int ---
+
+	/*
+	Equivalent to putc but unaffected by locks.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]]
+	*/
+	@(link_name=LPUTC_UNLOCKED)
+	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 ]]
+	*/
+	@(link_name=LPUTCHAR_UNLOCKED)
+	putchar_unlocked :: proc(ch: c.int) -> c.int ---
+
+	/*
+	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 ]]
+	*/
+	@(link_name=LTEMPNAM)
+	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 ]]
+	*/
+	@(link_name=LPOPEN)
+	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 ]]	
+	*/
+	@(link_name=LPCLOSE)
+	pclose :: proc(stream: ^FILE) -> c.int ---
+}
+
+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

+ 1 - 78
core/sys/posix/stdlib.odin

@@ -1,9 +1,9 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "base:intrinsics"
 import "base:intrinsics"
 
 
 import "core:c"
 import "core:c"
-import "core:c/libc"
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 	foreign import lib "system:System.framework"
 	foreign import lib "system:System.framework"
@@ -11,56 +11,6 @@ when ODIN_OS == .Darwin {
 	foreign import lib "system:c"
 	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 {
 foreign lib {
 	/*
 	/*
 	Takes a pointer to a radix-64 representation, in which the first digit is the least significant,
 	Takes a pointer to a radix-64 representation, in which the first digit is the least significant,
@@ -342,21 +292,6 @@ foreign lib {
 	*/
 	*/
 	unlockpt :: proc(fildes: FD) -> result ---
 	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.
 	Updates or add a variable in the environment of the calling process.
 
 
@@ -427,23 +362,11 @@ foreign lib {
 	setkey :: proc(key: [^]byte) ---
 	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 {
 when ODIN_OS == .NetBSD {
-	@(private) LPUTENV    :: "__putenv50"
 	@(private) LINITSTATE :: "__initstate60"
 	@(private) LINITSTATE :: "__initstate60"
 	@(private) LSRANDOM   :: "__srandom60"
 	@(private) LSRANDOM   :: "__srandom60"
 	@(private) LUNSETENV  :: "__unsetenv13"
 	@(private) LUNSETENV  :: "__unsetenv13"
 } else {
 } else {
-	@(private) LPUTENV    :: "putenv"
 	@(private) LINITSTATE :: "initstate"
 	@(private) LINITSTATE :: "initstate"
 	@(private) LSRANDOM   :: "srandom"
 	@(private) LSRANDOM   :: "srandom"
 	@(private) LUNSETENV  :: "unsetenv"
 	@(private) LUNSETENV  :: "unsetenv"

+ 101 - 0
core/sys/posix/stdlib_libc.odin

@@ -0,0 +1,101 @@
+#+build linux, windows, darwin, netbsd, openbsd, freebsd
+package posix
+
+import "base:intrinsics"
+
+import "core:c"
+import "core:c/libc"
+
+when ODIN_OS == .Windows {
+	foreign import lib "system:libucrt.lib"
+} else 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 {
+
+	/*
+	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 ---
+}
+
+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 == .Windows {
+	@(private) LPUTENV :: "_putenv"
+} else when ODIN_OS == .NetBSD {
+	@(private) LPUTENV :: "__putenv50"
+} else {
+	@(private) LPUTENV :: "putenv"
+}

+ 1 - 14
core/sys/posix/string.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -13,16 +14,6 @@ when ODIN_OS == .Darwin {
 // NOTE: most of the symbols in this header are not useful in Odin and have been left out.
 // NOTE: most of the symbols in this header are not useful in Odin and have been left out.
 
 
 foreign lib {
 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.
 	Map the error number to a locale-dependent error message string and put it in the buffer.
 
 
@@ -41,7 +32,3 @@ foreign lib {
 	*/
 	*/
 	strsignal :: proc(sig: Signal) -> cstring ---
 	strsignal :: proc(sig: Signal) -> cstring ---
 }
 }
-
-strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring {
-	return _strerror(errnum.? or_else errno())
-}

+ 30 - 0
core/sys/posix/string_libc.odin

@@ -0,0 +1,30 @@
+#+build linux, windows, darwin, netbsd, openbsd, freebsd
+package posix
+
+when ODIN_OS == .Windows {
+	foreign import lib "system:libucrt.lib"
+} else 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 ---
+}
+
+strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring {
+	return _strerror(errnum.? or_else errno())
+}

+ 1 - 2
core/sys/posix/sys_ipc.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -110,6 +111,4 @@ when ODIN_OS == .Darwin {
 	IPC_SET  :: 1
 	IPC_SET  :: 1
 	IPC_STAT :: 2
 	IPC_STAT :: 2
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/sys_mman.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -225,6 +226,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS
 	POSIX_MADV_SEQUENTIAL :: 2
 	POSIX_MADV_SEQUENTIAL :: 2
 	POSIX_MADV_WILLNEED   :: 3
 	POSIX_MADV_WILLNEED   :: 3
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 21 - 2
core/sys/posix/sys_msg.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -150,6 +151,24 @@ when ODIN_OS == .Darwin {
 		msg_pad4:    [4]c.long,
 		msg_pad4:    [4]c.long,
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	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_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_cbytes:  c.ulong,
+		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() */
+		__unused:    [2]c.ulong,
+	}
+
 }
 }

+ 1 - 2
core/sys/posix/sys_resource.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -154,6 +155,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		RLIMIT_AS :: 10
 		RLIMIT_AS :: 10
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 2 - 3
core/sys/posix/sys_select.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "base:intrinsics"
 import "base:intrinsics"
@@ -72,7 +73,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	// NOTE: this seems correct for FreeBSD but they do use a set backed by the long type themselves (thus the align change).
 	// NOTE: this seems correct for FreeBSD but they do use a set backed by the long type themselves (thus the align change).
 	@(private)
 	@(private)
-	ALIGN ::  align_of(c.long) when ODIN_OS == .FreeBSD else align_of(c.int32_t)
+	ALIGN ::  align_of(c.long) when ODIN_OS == .FreeBSD || ODIN_OS == .Linux else align_of(c.int32_t)
 
 
 	fd_set :: struct #align(ALIGN) {
 	fd_set :: struct #align(ALIGN) {
 		fds_bits: [(FD_SETSIZE / __NFDBITS) when (FD_SETSIZE % __NFDBITS) == 0 else (FD_SETSIZE / __NFDBITS) + 1]c.int32_t,
 		fds_bits: [(FD_SETSIZE / __NFDBITS) when (FD_SETSIZE % __NFDBITS) == 0 else (FD_SETSIZE / __NFDBITS) + 1]c.int32_t,
@@ -115,6 +116,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		intrinsics.mem_zero(_p, size_of(fd_set))
 		intrinsics.mem_zero(_p, size_of(fd_set))
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/sys_sem.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -153,6 +154,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		sem_flg: c.short,  /* [PSX] operation flags */
 		sem_flg: c.short,  /* [PSX] operation flags */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 21 - 2
core/sys/posix/sys_shm.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -137,6 +138,24 @@ when ODIN_OS == .Darwin {
 		_shm_internal:   rawptr,
 		_shm_internal:   rawptr,
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	SHM_RDONLY :: 0o10000
+	SHM_RND    :: 0o20000
+
+	SHMLBA     :: 4096
+
+	shmatt_t :: distinct c.ulong
+
+	shmid_ds :: struct {
+		shm_perm:        ipc_perm, /* [PSX] operation permission structure */
+		shm_segsz:       c.size_t, /* [PSX] size of segment in bytes */
+		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_cpid:        pid_t,    /* [PSX] process ID of creator */
+		shm_lpid:        pid_t,    /* [PSX] process ID of last shared memory operation */
+		shm_nattch:      shmatt_t, /* [PSX] number of current attaches */
+		_:               [2]c.ulong,
+	}
 }
 }

+ 5 - 5
core/sys/posix/sys_socket.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -325,14 +326,16 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	socklen_t :: distinct c.uint
 	socklen_t :: distinct c.uint
 
 
-	_sa_family_t :: distinct c.uint8_t
-
 	when ODIN_OS == .Linux {
 	when ODIN_OS == .Linux {
+		_sa_family_t :: distinct c.ushort
+
 		sockaddr :: struct {
 		sockaddr :: struct {
 			sa_family: sa_family_t, /* [PSX] address family */
 			sa_family: sa_family_t, /* [PSX] address family */
 			sa_data:   [14]c.char,  /* [PSX] socket address */
 			sa_data:   [14]c.char,  /* [PSX] socket address */
 		}
 		}
 	} else {
 	} else {
+		_sa_family_t :: distinct c.uint8_t
+
 		sockaddr :: struct {
 		sockaddr :: struct {
 			sa_len:    c.uint8_t,   /* total length */
 			sa_len:    c.uint8_t,   /* total length */
 			sa_family: sa_family_t, /* [PSX] address family */
 			sa_family: sa_family_t, /* [PSX] address family */
@@ -560,7 +563,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	SHUT_RDWR :: 2
 	SHUT_RDWR :: 2
 	SHUT_WR   :: 1
 	SHUT_WR   :: 1
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }
-

+ 120 - 67
core/sys/posix/sys_stat.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -280,20 +281,20 @@ when ODIN_OS == .Darwin {
 	ino_t      :: distinct c.uint64_t
 	ino_t      :: distinct c.uint64_t
 
 
 	stat_t :: struct {
 	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_dev:           dev_t,        /* [PSX] ID of device containing file */
+		st_mode:          mode_t,       /* [PSX] mode of file */
+		st_nlink:         nlink_t,      /* [PSX] number of hard links */
+		st_ino:           ino_t,        /* [PSX] file serial number */
+		st_uid:           uid_t,        /* [PSX] user ID of the file */
+		st_gid:           gid_t,        /* [PSX] group ID of the file */
+		st_rdev:          dev_t,        /* [PSX] device ID */
+		st_atim:          timespec,     /* [PSX] time of last access */
+		st_mtim:          timespec,     /* [PSX] time of last data modification */
+		st_ctim:          timespec,     /* [PSX] time of last status change */
 		st_birthtimespec: timespec,     /* time of file creation(birth) */
 		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_size:          off_t,        /* [PSX] file size, in bytes */
+		st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+		st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_gen:           c.uint32_t,   /* file generation number */
 		st_gen:           c.uint32_t,   /* file generation number */
 		st_lspare:        c.int32_t,    /* RESERVED */
 		st_lspare:        c.int32_t,    /* RESERVED */
@@ -314,47 +315,47 @@ when ODIN_OS == .Darwin {
 
 
 	when ODIN_ARCH == .i386 {
 	when ODIN_ARCH == .i386 {
 		stat_t :: struct {
 		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_dev:           dev_t,        /* [PSX] ID of device containing file */
+			st_ino:           ino_t,        /* [PSX] file serial number */
+			st_nlink:         nlink_t,      /* [PSX] number of hard links */
+			st_mode:          mode_t,       /* [PSX] mode of file */
 			st_padding0:      c.int16_t,
 			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_uid:           uid_t,        /* [PSX] user ID of the file */
+			st_gid:           gid_t,        /* [PSX] group ID of the file */
 			st_padding1:      c.int32_t,
 			st_padding1:      c.int32_t,
-			st_rdev:          dev_t,        /* [XSI] device ID */
+			st_rdev:          dev_t,        /* [PSX] device ID */
 			st_atim_ext:      c.int32_t,
 			st_atim_ext:      c.int32_t,
-			st_atim:          timespec,     /* [XSI] time of last access */
+			st_atim:          timespec,     /* [PSX] time of last access */
 			st_mtim_ext:      c.int32_t,
 			st_mtim_ext:      c.int32_t,
-			st_mtim:          timespec,     /* [XSI] time of last data modification */
+			st_mtim:          timespec,     /* [PSX] time of last data modification */
 			st_ctim_ext:      c.int32_t,
 			st_ctim_ext:      c.int32_t,
-			st_ctim:          timespec,     /* [XSI] time of last status change */
+			st_ctim:          timespec,     /* [PSX] time of last status change */
 			st_birthtimespec: timespec,     /* time of file creation(birth) */
 			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_size:          off_t,        /* [PSX] file size, in bytes */
+			st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+			st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
 			st_flags:         c.uint32_t,   /* user defined flags for file */
 			st_flags:         c.uint32_t,   /* user defined flags for file */
 			st_gen:           c.uint64_t,
 			st_gen:           c.uint64_t,
 			st_spare:         [10]c.uint64_t,
 			st_spare:         [10]c.uint64_t,
 		}
 		}
 	} else {
 	} else {
 		stat_t :: struct {
 		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_dev:           dev_t,        /* [PSX] ID of device containing file */
+			st_ino:           ino_t,        /* [PSX] file serial number */
+			st_nlink:         nlink_t,      /* [PSX] number of hard links */
+			st_mode:          mode_t,       /* [PSX] mode of file */
 			st_padding0:      c.int16_t,
 			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_uid:           uid_t,        /* [PSX] user ID of the file */
+			st_gid:           gid_t,        /* [PSX] group ID of the file */
 			st_padding1:      c.int32_t,
 			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_rdev:          dev_t,        /* [PSX] device ID */
+			st_atim:          timespec,     /* [PSX] time of last access */
+			st_mtim:          timespec,     /* [PSX] time of last data modification */
+			st_ctim:          timespec,     /* [PSX] time of last status change */
 			st_birthtimespec: timespec,     /* time of file creation(birth) */
 			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_size:          off_t,        /* [PSX] file size, in bytes */
+			st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+			st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
 			st_flags:         c.uint32_t,   /* user defined flags for file */
 			st_flags:         c.uint32_t,   /* user defined flags for file */
 			st_gen:           c.uint64_t,
 			st_gen:           c.uint64_t,
 			st_spare:         [10]c.uint64_t,
 			st_spare:         [10]c.uint64_t,
@@ -374,20 +375,20 @@ when ODIN_OS == .Darwin {
 	ino_t      :: distinct c.uint64_t
 	ino_t      :: distinct c.uint64_t
 
 
 	stat_t :: struct {
 	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_dev:           dev_t,        /* [PSX] ID of device containing file */
+		st_mode:          mode_t,       /* [PSX] mode of file */
+		st_ino:           ino_t,        /* [PSX] file serial number */
+		st_nlink:         nlink_t,      /* [PSX] number of hard links */
+		st_uid:           uid_t,        /* [PSX] user ID of the file */
+		st_gid:           gid_t,        /* [PSX] group ID of the file */
+		st_rdev:          dev_t,        /* [PSX] device ID */
+		st_atim:          timespec,     /* [PSX] time of last access */
+		st_mtim:          timespec,     /* [PSX] time of last data modification */
+		st_ctim:          timespec,     /* [PSX] time of last status change */
 		st_birthtimespec: timespec,     /* time of file creation(birth) */
 		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_size:          off_t,        /* [PSX] file size, in bytes */
+		st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+		st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_gen:           c.uint64_t,
 		st_gen:           c.uint64_t,
 		st_spare:         [2]c.uint32_t,
 		st_spare:         [2]c.uint32_t,
@@ -406,19 +407,19 @@ when ODIN_OS == .Darwin {
 	ino_t      :: distinct c.uint64_t
 	ino_t      :: distinct c.uint64_t
 
 
 	stat_t :: struct {
 	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_mode:          mode_t,       /* [PSX] mode of file */
+		st_dev:           dev_t,        /* [PSX] ID of device containing file */
+		st_ino:           ino_t,        /* [PSX] file serial number */
+		st_nlink:         nlink_t,      /* [PSX] number of hard links */
+		st_uid:           uid_t,        /* [PSX] user ID of the file */
+		st_gid:           gid_t,        /* [PSX] group ID of the file */
+		st_rdev:          dev_t,        /* [PSX] device ID */
+		st_atim:          timespec,     /* [PSX] time of last access */
+		st_mtim:          timespec,     /* [PSX] time of last data modification */
+		st_ctim:          timespec,     /* [PSX] time of last status change */
+		st_size:          off_t,        /* [PSX] file size, in bytes */
+		st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+		st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_flags:         c.uint32_t,   /* user defined flags for file */
 		st_gen:           c.int32_t,
 		st_gen:           c.int32_t,
 		st_birthtimespec: timespec,
 		st_birthtimespec: timespec,
@@ -427,6 +428,58 @@ when ODIN_OS == .Darwin {
 	UTIME_NOW  :: -2
 	UTIME_NOW  :: -2
 	UTIME_OMIT :: -1
 	UTIME_OMIT :: -1
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	dev_t     :: distinct u64
+	_mode_t   :: distinct c.uint 
+	blkcnt_t  :: distinct i64
+
+	when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 {
+		nlink_t   :: distinct c.uint
+		blksize_t :: distinct c.int
+	} else {
+		nlink_t   :: distinct c.size_t
+		blksize_t :: distinct c.long
+	}
+
+	ino_t :: distinct u64
+
+	when ODIN_ARCH == .amd64 {
+		stat_t :: struct {
+			st_dev:           dev_t,        /* [PSX] ID of device containing file */
+			st_ino:           ino_t,        /* [PSX] file serial number */
+			st_nlink:         nlink_t,      /* [PSX] number of hard links */
+			st_mode:          mode_t,       /* [PSX] mode of file */
+			st_uid:           uid_t,        /* [PSX] user ID of the file */
+			st_gid:           gid_t,        /* [PSX] group ID of the file */
+			_pad0:            c.uint,
+			st_rdev:          dev_t,        /* [PSX] device ID */
+			st_size:          off_t,        /* [PSX] file size, in bytes */
+			st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
+			st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+			st_atim:          timespec,     /* [PSX] time of last access */
+			st_mtim:          timespec,     /* [PSX] time of last data modification */
+			st_ctim:          timespec,     /* [PSX] time of last status change */
+			__unused:         [3]c.long,
+		}
+	} else {
+		stat_t :: struct {
+			st_dev:           dev_t,        /* [PSX] ID of device containing file */
+			st_ino:           ino_t,        /* [PSX] file serial number */
+			st_mode:          mode_t,       /* [PSX] mode of file */
+			st_nlink:         nlink_t,      /* [PSX] number of hard links */
+			st_uid:           uid_t,        /* [PSX] user ID of the file */
+			st_gid:           gid_t,        /* [PSX] group ID of the file */
+			st_rdev:          dev_t,        /* [PSX] device ID */
+			__pad:            c.ulonglong,
+			st_size:          off_t,        /* [PSX] file size, in bytes */
+			st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
+			__pad2:           c.int,
+			st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+			st_atim:          timespec,     /* [PSX] time of last access */
+			st_mtim:          timespec,     /* [PSX] time of last data modification */
+			st_ctim:          timespec,     /* [PSX] time of last status change */
+			__unused:         [2]c.uint,
+		}
+	}
 }
 }

+ 24 - 2
core/sys/posix/sys_statvfs.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -130,6 +131,27 @@ when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
 	ST_RDONLY :: 0x00000001
 	ST_RDONLY :: 0x00000001
 	ST_NOSUID :: 0x00000008
 	ST_NOSUID :: 0x00000008
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	fsblkcnt_t :: distinct c.uint64_t
+
+	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 */
+		_:          [2*size_of(c.int)-size_of(c.long)]byte,
+		f_flag:     VFS_Flags,  /* [PSX] bit mask of f_flag values */
+		f_namemax:  c.ulong,    /* [PSX] maximum filename length */
+		f_type:     c.uint,
+		__reserved: [5]c.int,
+	}
+
+	ST_RDONLY :: 0x00000001
+	ST_NOSUID :: 0x00000002
 }
 }

+ 1 - 2
core/sys/posix/sys_time.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -77,6 +78,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	ITIMER_VIRTUAL :: 1
 	ITIMER_VIRTUAL :: 1
 	ITIMER_PROF    :: 2
 	ITIMER_PROF    :: 2
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/sys_times.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
@@ -33,6 +34,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		tms_cstime: clock_t, /* [PSX] terminated children system CPU time */
 		tms_cstime: clock_t, /* [PSX] terminated children system CPU time */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/sys_uio.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -37,6 +38,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		iov_len:  c.size_t, /* [PSX] size of the region iov_base points to */
 		iov_len:  c.size_t, /* [PSX] size of the region iov_base points to */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/sys_un.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -19,6 +20,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		sun_path:   [108]c.char, /* [PSX] socket pathname */
 		sun_path:   [108]c.char, /* [PSX] socket pathname */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 17 - 10
core/sys/posix/sys_utsname.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -37,15 +38,10 @@ foreign lib {
 	uname :: proc(uname: ^utsname) -> c.int ---
 	uname :: proc(uname: ^utsname) -> c.int ---
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 
 
-	when ODIN_OS == .Linux {
-		@(private)
-		_SYS_NAMELEN :: 65
-	} else {
-		@(private)
-		_SYS_NAMELEN :: 256
-	}
+	@(private)
+	_SYS_NAMELEN :: 256
 
 
 	utsname :: struct {
 	utsname :: struct {
 		sysname:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */
 		sysname:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */
@@ -55,6 +51,17 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		machine:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */
 		machine:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	@(private)
+	_SYS_NAMELEN :: 65
+
+	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 */
+		__domainname: [_SYS_NAMELEN]c.char `fmt:"s,0"`,
+	}
 }
 }

+ 51 - 2
core/sys/posix/sys_wait.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -391,6 +392,54 @@ when ODIN_OS == .Darwin {
 		return (x & _WCONTINUED) == _WCONTINUED
 		return (x & _WCONTINUED) == _WCONTINUED
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	id_t :: distinct c.uint
+
+	WCONTINUED :: 8
+	WNOHANG    :: 1
+	WUNTRACED  :: 2
+
+	WEXITED  :: 4
+	WNOWAIT  :: 0x1000000
+	WSTOPPED :: 2
+
+	_P_ALL  :: 0
+	_P_PID  :: 1
+	_P_PGID :: 2
+
+	@(private)
+	_WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool {
+		return _WTERMSIG(x) == nil
+	}
+
+	@(private)
+	_WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int {
+		return (x & 0xff00) >> 8
+	}
+
+	@(private)
+	_WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool {
+		return (x & 0xffff) - 1 < 0xff
+	}
+
+	@(private)
+	_WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
+		return Signal(x & 0x7f)
+	}
+
+	@(private)
+	_WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool {
+		return ((x & 0xffff) * 0x10001) >> 8 > 0x7f00
+	}
+
+	@(private)
+	_WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal {
+		return Signal(_WEXITSTATUS(x))
+	}
+
+	@(private)
+	_WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool {
+		return x == 0xffff
+	}
 }
 }

+ 8 - 9
core/sys/posix/termios.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -152,7 +153,7 @@ CControl_Flag_Bits :: enum tcflag_t {
 CControl_Flags :: bit_set[CControl_Flag_Bits; tcflag_t]
 CControl_Flags :: bit_set[CControl_Flag_Bits; tcflag_t]
 
 
 // character size mask
 // character size mask
-CSIZE :: CControl_Flags{ .CS6, .CS7, .CS8 }
+CSIZE :: transmute(CControl_Flags)tcflag_t(_CSIZE)
 
 
 COutput_Flag_Bits :: enum tcflag_t {
 COutput_Flag_Bits :: enum tcflag_t {
 	OPOST  = log2(OPOST),  /* enable following output processing */
 	OPOST  = log2(OPOST),  /* enable following output processing */
@@ -181,17 +182,17 @@ COutput_Flag_Bits :: enum tcflag_t {
 COutput_Flags :: bit_set[COutput_Flag_Bits; tcflag_t]
 COutput_Flags :: bit_set[COutput_Flag_Bits; tcflag_t]
 
 
 // \n delay mask
 // \n delay mask
-NLDLY  :: COutput_Flags{ .NL1, COutput_Flag_Bits(9) }
+NLDLY  :: transmute(COutput_Flags)tcflag_t(_NLDLY)
 // \r delay mask
 // \r delay mask
-CRDLY  :: COutput_Flags{ .CR1, .CR2, .CR3 }
+CRDLY  :: transmute(COutput_Flags)tcflag_t(_CRDLY)
 // horizontal tab delay mask
 // horizontal tab delay mask
-TABDLY :: COutput_Flags{ .TAB1, .TAB3, COutput_Flag_Bits(2) }
+TABDLY :: transmute(COutput_Flags)tcflag_t(_TABDLY)
 // \b delay mask
 // \b delay mask
-BSDLY  :: COutput_Flags{ .BS1 }
+BSDLY  :: transmute(COutput_Flags)tcflag_t(_BSDLY)
 // vertical tab delay mask
 // vertical tab delay mask
-VTDLY  :: COutput_Flags{ .VT1 }
+VTDLY  :: transmute(COutput_Flags)tcflag_t(_VTDLY)
 // form feed delay mask
 // form feed delay mask
-FFDLY  :: COutput_Flags{ .FF1 }
+FFDLY  :: transmute(COutput_Flags)tcflag_t(_FFDLY)
 
 
 speed_t :: enum _speed_t {
 speed_t :: enum _speed_t {
 	B0     = B0,
 	B0     = B0,
@@ -596,6 +597,4 @@ when ODIN_OS == .Darwin {
 	TCOOFF :: 0
 	TCOOFF :: 0
 	TCOON  :: 1
 	TCOON  :: 1
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 13 - 2
core/sys/posix/time.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -229,6 +230,16 @@ when ODIN_OS == .Darwin {
 
 
 	getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD.
 	getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD.
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
+} else when ODIN_OS == .Linux {
+
+	clockid_t :: distinct c.int
+
+	CLOCK_MONOTONIC          :: 1
+	CLOCK_PROCESS_CPUTIME_ID :: 2
+	CLOCK_REALTIME           :: 0
+	CLOCK_THREAD_CPUTIME_ID  :: 3
+
+	foreign lib {
+		getdate_err: Errno
+	}
 }
 }

+ 1 - 2
core/sys/posix/ulimit.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -38,6 +39,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	// NOTE: I don't think OpenBSD implements this API.
 	// NOTE: I don't think OpenBSD implements this API.
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 2 - 110
core/sys/posix/unistd.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -11,19 +12,6 @@ when ODIN_OS == .Darwin {
 // unistd.h - standard symbolic constants and types
 // unistd.h - standard symbolic constants and types
 
 
 foreign lib {
 foreign lib {
-	/*
-	Checks the file named by the pathname pointed to by the path argument for
-	accessibility according to the bit pattern contained in amode. 
-
-	Example:
-		if (posix.access("/tmp/myfile", posix.F_OK) != .OK) {
-			fmt.printfln("/tmp/myfile access check failed: %v", posix.strerror(posix.errno()))
-		}
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]]
-	*/
-	access :: proc(path: cstring, amode: Mode_Flags = F_OK) -> result ---
-
 	/*
 	/*
 	Equivalent to `access` but relative paths are resolved based on `fd`.
 	Equivalent to `access` but relative paths are resolved based on `fd`.
 
 
@@ -42,18 +30,6 @@ foreign lib {
 	*/
 	*/
 	alarm :: proc(seconds: c.uint) -> c.uint ---
 	alarm :: proc(seconds: c.uint) -> c.uint ---
 
 
-	/*
-	Causes the directory named by path to become the current working directory.
-
-	Example:
-		if (posix.chdir("/tmp") == .OK) {
-			fmt.println("changed current directory to /tmp")
-		}
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html ]]
-	*/
-	chdir :: proc(path: cstring) -> result ---
-
 	/*
 	/*
 	Equivalent to chdir but instead of a path the fildes is resolved to a directory.
 	Equivalent to chdir but instead of a path the fildes is resolved to a directory.
 
 
@@ -204,15 +180,6 @@ foreign lib {
 	*/
 	*/
 	dup2 :: proc(fildes, fildes2: FD) -> FD ---
 	dup2 :: proc(fildes, fildes2: FD) -> FD ---
 
 
-	/*
-	Exits but, shall not call functions registered with atexit() nor any registered signal handlers.
-	Open streams shall not be flushed.
-	Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below.
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ]]
-	*/
-	_exit :: proc(status: c.int) -> ! ---
-
 	/*
 	/*
 	The exec family of functions shall replace the current process image with a new process image.
 	The exec family of functions shall replace the current process image with a new process image.
 	The new image shall be constructed from a regular, executable file called the new process image file.
 	The new image shall be constructed from a regular, executable file called the new process image file.
@@ -392,44 +359,6 @@ foreign lib {
 	*/
 	*/
 	ftruncate :: proc(fildes: FD, length: off_t) -> result ---
 	ftruncate :: proc(fildes: FD, length: off_t) -> result ---
 
 
-	/*
-	Places an absolute pathname of the current working directory into buf.
-
-	Returns: buf as a cstring on success, nil (setting errno) on failure
-
-	Example:
-		size: int
-		path_max := posix.pathconf(".", ._PATH_MAX)
-		if path_max == -1 {
-			size = 1024
-		} else if path_max > 10240 {
-			size = 10240
-		} else {
-			size = int(path_max)
-		}
-
-		buf: [dynamic]byte
-		cwd: cstring
-		for ; cwd == nil; size *= 2 {
-			if err := resize(&buf, size); err != nil {
-				fmt.panicf("allocation failure: %v", err)
-			}
-
-			cwd = posix.getcwd(raw_data(buf), len(buf))
-			if cwd == nil {
-				errno := posix.errno()
-				if errno != .ERANGE {
-					fmt.panicf("getcwd failure: %v", posix.strerror(errno))
-				}
-			}
-		}
-
-		fmt.println(path_max, cwd)
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html ]]
-	*/
-	getcwd :: proc(buf: [^]c.char, size: c.size_t) -> cstring ---
-
 	/*
 	/*
 	Returns the effective group ID of the calling process.
 	Returns the effective group ID of the calling process.
 
 
@@ -829,13 +758,6 @@ foreign lib {
 	*/
 	*/
 	readlinkat :: proc(fd: FD, path: cstring, buf: [^]byte, bufsize: c.size_t) -> c.ssize_t ---
 	readlinkat :: proc(fd: FD, path: cstring, buf: [^]byte, bufsize: c.size_t) -> c.ssize_t ---
 
 
-	/*
-	Remove an (empty) directory.
-
-	]] More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ]]
-	*/
-	rmdir :: proc(path: cstring) -> result ---
-
 	/*
 	/*
 	Set the effective group ID.
 	Set the effective group ID.
 
 
@@ -912,13 +834,6 @@ foreign lib {
 	*/
 	*/
 	sleep :: proc(seconds: c.uint) -> c.uint ---
 	sleep :: proc(seconds: c.uint) -> c.uint ---
 
 
-	/*
-	Copy nbyte bytes, from src, to dest, exchanging adjecent bytes.
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/swab.html ]]
-	*/
-	swab :: proc(src: [^]byte, dest: [^]byte, nbytes: c.ssize_t) ---
-
 	/*
 	/*
 	Schedule file system updates.
 	Schedule file system updates.
 
 
@@ -958,13 +873,6 @@ foreign lib {
 	*/
 	*/
 	ttyname_r :: proc(fildes: FD, name: [^]byte, namesize: c.size_t) -> Errno ---
 	ttyname_r :: proc(fildes: FD, name: [^]byte, namesize: c.size_t) -> Errno ---
 
 
-	/*
-	Remove a directory entry.
-
-	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]]
-	*/
-	unlink :: proc(path: cstring) -> result ---
-
 	/*
 	/*
 	Equivalent to unlink or rmdir (if flag is .REMOVEDIR) but relative paths are relative to the dir fd.
 	Equivalent to unlink or rmdir (if flag is .REMOVEDIR) but relative paths are relative to the dir fd.
 
 
@@ -973,20 +881,6 @@ foreign lib {
 	unlinkat :: proc(fd: FD, path: cstring, flag: AT_Flags) -> result ---
 	unlinkat :: proc(fd: FD, path: cstring, flag: AT_Flags) -> result ---
 }
 }
 
 
-STDERR_FILENO :: 2
-STDIN_FILENO  :: 0
-STDOUT_FILENO :: 1
-
-Mode_Flag_Bits :: enum c.int {
-	X_OK = log2(X_OK),
-	W_OK = log2(W_OK),
-	R_OK = log2(R_OK),
-}
-Mode_Flags :: bit_set[Mode_Flag_Bits; c.int]
-
-#assert(_F_OK == 0)
-F_OK :: Mode_Flags{}
-
 CS :: enum c.int {
 CS :: enum c.int {
 	_PATH                           = _CS_PATH,
 	_PATH                           = _CS_PATH,
 	_POSIX_V6_ILP32_OFF32_CFLAGS    = _CS_POSIX_V6_ILP32_OFF32_CFLAGS,
 	_POSIX_V6_ILP32_OFF32_CFLAGS    = _CS_POSIX_V6_ILP32_OFF32_CFLAGS,
@@ -2063,6 +1957,7 @@ when ODIN_OS == .Darwin {
 	_SC_TYPED_MEMORY_OBJECTS   :: 165
 	_SC_TYPED_MEMORY_OBJECTS   :: 165
 	_SC_2_PBS                  :: 168
 	_SC_2_PBS                  :: 168
 	_SC_2_PBS_ACCOUNTING       :: 169
 	_SC_2_PBS_ACCOUNTING       :: 169
+	_SC_2_PBS_LOCATE           :: 170
 	_SC_2_PBS_MESSAGE          :: 171
 	_SC_2_PBS_MESSAGE          :: 171
 	_SC_2_PBS_TRACK            :: 172
 	_SC_2_PBS_TRACK            :: 172
 	_SC_SYMLOOP_MAX            :: 173
 	_SC_SYMLOOP_MAX            :: 173
@@ -2097,7 +1992,4 @@ when ODIN_OS == .Darwin {
 	// NOTE: Not implemented.
 	// NOTE: Not implemented.
 	_POSIX_VDISABLE :: 0
 	_POSIX_VDISABLE :: 0
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }
-

+ 153 - 0
core/sys/posix/unistd_libc.odin

@@ -0,0 +1,153 @@
+#+build linux, windows, darwin, netbsd, openbsd, freebsd
+package posix
+
+import "core:c"
+
+when ODIN_OS == .Windows {
+	foreign import lib "system:libucrt.lib"
+} else when ODIN_OS == .Darwin {
+	foreign import lib "system:System.framework"
+} else {
+	foreign import lib "system:c"
+}
+
+// unistd.h - standard symbolic constants and types
+
+foreign lib {
+	/*
+	Checks the file named by the pathname pointed to by the path argument for
+	accessibility according to the bit pattern contained in amode. 
+
+	Example:
+		if (posix.access("/tmp/myfile", posix.F_OK) != .OK) {
+			fmt.printfln("/tmp/myfile access check failed: %v", posix.strerror(posix.errno()))
+		}
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]]
+	*/
+	@(link_name=LACCESS)
+	access :: proc(path: cstring, amode: Mode_Flags = F_OK) -> result ---
+
+	/*
+	Causes the directory named by path to become the current working directory.
+
+	Example:
+		if (posix.chdir("/tmp") == .OK) {
+			fmt.println("changed current directory to /tmp")
+		}
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html ]]
+	*/
+	@(link_name=LCHDIR)
+	chdir :: proc(path: cstring) -> result ---
+
+	/*
+	Exits but, shall not call functions registered with atexit() nor any registered signal handlers.
+	Open streams shall not be flushed.
+	Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ]]
+	*/
+	_exit :: proc(status: c.int) -> ! ---
+
+	/*
+	Places an absolute pathname of the current working directory into buf.
+
+	Returns: buf as a cstring on success, nil (setting errno) on failure
+
+	Example:
+		size: int
+		path_max := posix.pathconf(".", ._PATH_MAX)
+		if path_max == -1 {
+			size = 1024
+		} else if path_max > 10240 {
+			size = 10240
+		} else {
+			size = int(path_max)
+		}
+
+		buf: [dynamic]byte
+		cwd: cstring
+		for ; cwd == nil; size *= 2 {
+			if err := resize(&buf, size); err != nil {
+				fmt.panicf("allocation failure: %v", err)
+			}
+
+			cwd = posix.getcwd(raw_data(buf), len(buf))
+			if cwd == nil {
+				errno := posix.errno()
+				if errno != .ERANGE {
+					fmt.panicf("getcwd failure: %v", posix.strerror(errno))
+				}
+			}
+		}
+
+		fmt.println(path_max, cwd)
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html ]]
+	*/
+	@(link_name=LGETCWD)
+	getcwd :: proc(buf: [^]c.char, size: c.size_t) -> cstring ---
+
+	/*
+	Remove an (empty) directory.
+
+	]] More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ]]
+	*/
+	@(link_name=LRMDIR)
+	rmdir :: proc(path: cstring) -> result ---
+
+	/*
+	Copy nbyte bytes, from src, to dest, exchanging adjecent bytes.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/swab.html ]]
+	*/
+	@(link_name=LSWAB)
+	swab :: proc(src: [^]byte, dest: [^]byte, nbytes: c.ssize_t) ---
+
+	/*
+	Remove a directory entry.
+
+	[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]]
+	*/
+	@(link_name=LUNLINK)
+	unlink :: proc(path: cstring) -> result ---
+}
+
+when ODIN_OS == .Windows {
+	@(private) LACCESS :: "_access"
+	@(private) LCHDIR  :: "_chdir"
+	@(private) LGETCWD :: "_getcwd"
+	@(private) LRMDIR  :: "_rmdir"
+	@(private) LSWAB   :: "_swab"
+	@(private) LUNLINK :: "_unlink"
+} else {
+	@(private) LACCESS :: "access"
+	@(private) LCHDIR  :: "chdir"
+	@(private) LGETCWD :: "getcwd"
+	@(private) LRMDIR  :: "rmdir"
+	@(private) LSWAB   :: "swab"
+	@(private) LUNLINK :: "unlink"
+}
+
+STDERR_FILENO :: 2
+STDIN_FILENO  :: 0
+STDOUT_FILENO :: 1
+
+Mode_Flag_Bits :: enum c.int {
+	X_OK = log2(X_OK),
+	W_OK = log2(W_OK),
+	R_OK = log2(R_OK),
+}
+Mode_Flags :: bit_set[Mode_Flag_Bits; c.int]
+
+#assert(_F_OK == 0)
+F_OK :: Mode_Flags{}
+
+when ODIN_OS == .Windows {
+	_F_OK :: 0
+	X_OK  :: 1
+	W_OK  :: 2
+	R_OK  :: 4
+	#assert(W_OK|R_OK == 6)
+}

+ 1 - 2
core/sys/posix/utime.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
@@ -31,6 +32,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		modtime: time_t, /* [PSX] modification time (seconds since epoch) */
 		modtime: time_t, /* [PSX] modification time (seconds since epoch) */
 	}
 	}
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 2
core/sys/posix/wordexp.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 package posix
 
 
 import "core:c"
 import "core:c"
@@ -123,6 +124,4 @@ when ODIN_OS == .Darwin {
 	WRDE_CMDSUB  :: 4
 	WRDE_CMDSUB  :: 4
 	WRDE_SYNTAX  :: 5
 	WRDE_SYNTAX  :: 5
 
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }
 }

+ 0 - 96
core/sys/unix/pthread_darwin.odin

@@ -1,96 +0,0 @@
-#+build darwin
-package unix
-
-import "core:c"
-
-// NOTE(tetra): No 32-bit Macs.
-// Source: _pthread_types.h on my Mac.
-PTHREAD_SIZE           :: 8176
-PTHREAD_ATTR_SIZE      :: 56
-PTHREAD_MUTEXATTR_SIZE :: 8
-PTHREAD_MUTEX_SIZE     :: 56
-PTHREAD_CONDATTR_SIZE  :: 8
-PTHREAD_COND_SIZE      :: 40
-PTHREAD_ONCE_SIZE      :: 8
-PTHREAD_RWLOCK_SIZE    :: 192
-PTHREAD_RWLOCKATTR_SIZE :: 16
-
-pthread_t :: distinct u64
-
-pthread_attr_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_ATTR_SIZE] c.char,
-}
-
-pthread_cond_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_COND_SIZE] c.char,
-}
-
-pthread_condattr_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_CONDATTR_SIZE] c.char,
-}
-
-pthread_mutex_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_MUTEX_SIZE] c.char,
-}
-
-pthread_mutexattr_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_MUTEXATTR_SIZE] c.char,
-}
-
-pthread_once_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_ONCE_SIZE] c.char,
-}
-
-pthread_rwlock_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_RWLOCK_SIZE] c.char,
-}
-
-pthread_rwlockattr_t :: struct {
-	sig: c.long,
-	_: [PTHREAD_RWLOCKATTR_SIZE] c.char,
-}
-
-SCHED_OTHER :: 1 // Avoid if you are writing portable software.
-SCHED_FIFO  :: 4
-SCHED_RR :: 2 // Round robin.
-
-SCHED_PARAM_SIZE :: 4
-
-sched_param :: struct {
-	sched_priority: c.int,
-	_: [SCHED_PARAM_SIZE] c.char,
-}
-
-// Source: https://github.com/apple/darwin-libpthread/blob/03c4628c8940cca6fd6a82957f683af804f62e7f/pthread/pthread.h#L138
-PTHREAD_CREATE_JOINABLE :: 1
-PTHREAD_CREATE_DETACHED :: 2
-PTHREAD_INHERIT_SCHED :: 1
-PTHREAD_EXPLICIT_SCHED :: 2
-PTHREAD_PROCESS_SHARED :: 1
-PTHREAD_PROCESS_PRIVATE :: 2
-
-
-PTHREAD_MUTEX_NORMAL :: 0
-PTHREAD_MUTEX_RECURSIVE :: 1
-PTHREAD_MUTEX_ERRORCHECK :: 2
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 1
-
-foreign import pthread "system:System.framework"
-
-@(default_calling_convention="c")
-foreign pthread {
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 122
core/sys/unix/pthread_freebsd.odin

@@ -1,122 +0,0 @@
-#+build freebsd
-package unix
-
-import "core:c"
-
-pthread_t :: distinct u64
-// pthread_t :: struct #align(16) { x: u64 }
-
-PTHREAD_COND_T_SIZE :: 8
-
-PTHREAD_MUTEXATTR_T_SIZE :: 8
-PTHREAD_CONDATTR_T_SIZE  :: 8
-PTHREAD_RWLOCKATTR_T_SIZE  :: 8
-PTHREAD_BARRIERATTR_T_SIZE :: 8
-
-// WARNING: The sizes of these things are different yet again
-// on non-X86!
-when size_of(int) == 8 {
-	PTHREAD_ATTR_T_SIZE  :: 8
-	PTHREAD_MUTEX_T_SIZE :: 8
-	PTHREAD_RWLOCK_T_SIZE  :: 8
-	PTHREAD_BARRIER_T_SIZE :: 8
-} else when size_of(int) == 4 { // TODO
-	PTHREAD_ATTR_T_SIZE  :: 32
-	PTHREAD_MUTEX_T_SIZE :: 32
-	PTHREAD_RWLOCK_T_SIZE  :: 44
-	PTHREAD_BARRIER_T_SIZE :: 20
-}
-
-pthread_cond_t :: struct #align(16) {
-	_: [PTHREAD_COND_T_SIZE] c.char,
-}
-pthread_mutex_t :: struct #align(16) {
-	_: [PTHREAD_MUTEX_T_SIZE] c.char,
-}
-pthread_rwlock_t :: struct #align(16) {
-	_: [PTHREAD_RWLOCK_T_SIZE] c.char,
-}
-pthread_barrier_t :: struct #align(16) {
-	_: [PTHREAD_BARRIER_T_SIZE] c.char,
-}
-
-pthread_attr_t :: struct #align(16) {
-	_: [PTHREAD_ATTR_T_SIZE] c.char,
-}
-pthread_condattr_t :: struct #align(16) {
-	_: [PTHREAD_CONDATTR_T_SIZE] c.char,
-}
-pthread_mutexattr_t :: struct #align(16) {
-	_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
-}
-pthread_rwlockattr_t :: struct #align(16) {
-	_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
-}
-pthread_barrierattr_t :: struct #align(16) {
-	_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
-}
-
-PTHREAD_MUTEX_ERRORCHECK :: 1
-PTHREAD_MUTEX_RECURSIVE :: 2
-PTHREAD_MUTEX_NORMAL :: 3
-
-
-PTHREAD_CREATE_JOINABLE :: 0
-PTHREAD_CREATE_DETACHED :: 1
-PTHREAD_INHERIT_SCHED :: 4
-PTHREAD_EXPLICIT_SCHED :: 0
-PTHREAD_PROCESS_PRIVATE :: 0
-PTHREAD_PROCESS_SHARED :: 1
-
-SCHED_FIFO  :: 1
-SCHED_OTHER :: 2
-SCHED_RR :: 3 // Round robin.
-
-
-sched_param :: struct {
-	sched_priority: c.int,
-}
-
-_usem :: struct {
-	_has_waiters: u32,
-	_count: u32,
-	_flags: u32,
-}
-_usem2 :: struct {
-	_count: u32,
-	_flags: u32,
-}
-sem_t :: struct {
-	_magic: u32,
-	_kern: _usem2,
-	_padding: u32,
-}
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 2
-
-foreign import "system:pthread"
-
-@(default_calling_convention="c")
-foreign pthread {
-	// create named semaphore.
-	// used in process-shared semaphores.
-	sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
-
-	sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
-	sem_destroy :: proc(sem: ^sem_t) -> c.int ---
-	sem_post :: proc(sem: ^sem_t) -> c.int ---
-	sem_wait :: proc(sem: ^sem_t) -> c.int ---
-	sem_trywait :: proc(sem: ^sem_t) -> c.int ---
-	// sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---
-
-	// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
-	// see https://linux.die.net/man/3/pthread_yield
-	pthread_yield :: proc() ---
-
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 71
core/sys/unix/pthread_haiku.odin

@@ -1,71 +0,0 @@
-package unix
-
-import "core:c"
-
-pthread_t             :: distinct rawptr
-pthread_attr_t        :: distinct rawptr
-pthread_mutex_t       :: distinct rawptr
-pthread_mutexattr_t   :: distinct rawptr
-pthread_cond_t        :: distinct rawptr
-pthread_condattr_t    :: distinct rawptr
-pthread_rwlock_t      :: distinct rawptr
-pthread_rwlockattr_t  :: distinct rawptr
-pthread_barrier_t     :: distinct rawptr
-pthread_barrierattr_t :: distinct rawptr
-pthread_spinlock_t    :: distinct rawptr
-
-pthread_key_t  :: distinct c.int
-pthread_once_t :: struct {
-	state: c.int,
-	mutex: pthread_mutex_t,
-}
-
-PTHREAD_MUTEX_DEFAULT    :: 0
-PTHREAD_MUTEX_NORMAL     :: 1
-PTHREAD_MUTEX_ERRORCHECK :: 2
-PTHREAD_MUTEX_RECURSIVE  :: 3
-
-PTHREAD_DETACHED      :: 0x1
-PTHREAD_SCOPE_SYSTEM  :: 0x2
-PTHREAD_INHERIT_SCHED :: 0x4
-PTHREAD_NOFLOAT       :: 0x8
-
-PTHREAD_CREATE_DETACHED :: PTHREAD_DETACHED
-PTHREAD_CREATE_JOINABLE :: 0
-PTHREAD_SCOPE_PROCESS   :: 0
-PTHREAD_EXPLICIT_SCHED  :: 0
-
-SCHED_FIFO     :: 1
-SCHED_RR       :: 2
-SCHED_SPORADIC :: 3
-SCHED_OTHER    :: 4
-
-sched_param :: struct {
-	sched_priority: c.int,
-}
-
-sem_t :: distinct rawptr
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 2
-
-foreign import libc "system:c"
-
-@(default_calling_convention="c")
-foreign libc {
-	sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
-
-	sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
-	sem_destroy :: proc(sem: ^sem_t) -> c.int ---
-	sem_post :: proc(sem: ^sem_t) -> c.int ---
-	sem_wait :: proc(sem: ^sem_t) -> c.int ---
-	sem_trywait :: proc(sem: ^sem_t) -> c.int ---
-	
-	pthread_yield :: proc() ---
-
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 124
core/sys/unix/pthread_linux.odin

@@ -1,124 +0,0 @@
-#+build linux
-package unix
-
-import "core:c"
-
-// TODO(tetra): For robustness, I'd like to mark this with align 16.
-// I cannot currently do this.
-// And at the time of writing there is a bug with putting it
-// as the only field in a struct.
-pthread_t :: distinct u64
-// pthread_t :: struct #align(16) { x: u64 };
-
-// NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my
-// Linux machine.
-
-PTHREAD_COND_T_SIZE :: 48
-
-PTHREAD_MUTEXATTR_T_SIZE :: 4
-PTHREAD_CONDATTR_T_SIZE  :: 4
-PTHREAD_RWLOCKATTR_T_SIZE  :: 8
-PTHREAD_BARRIERATTR_T_SIZE :: 4
-
-// WARNING: The sizes of these things are different yet again
-// on non-X86!
-when size_of(int) == 8 {
-	PTHREAD_ATTR_T_SIZE  :: 56
-	PTHREAD_MUTEX_T_SIZE :: 40
-	PTHREAD_RWLOCK_T_SIZE  :: 56
-	PTHREAD_BARRIER_T_SIZE :: 32
-} else when size_of(int) == 4 {
-	PTHREAD_ATTR_T_SIZE  :: 32
-	PTHREAD_MUTEX_T_SIZE :: 32
-	PTHREAD_RWLOCK_T_SIZE  :: 44
-	PTHREAD_BARRIER_T_SIZE :: 20
-}
-
-pthread_cond_t :: struct #align(16) {
-	_: [PTHREAD_COND_T_SIZE] c.char,
-}
-pthread_mutex_t :: struct #align(16) {
-	_: [PTHREAD_MUTEX_T_SIZE] c.char,
-}
-pthread_rwlock_t :: struct #align(16) {
-	_: [PTHREAD_RWLOCK_T_SIZE] c.char,
-}
-pthread_barrier_t :: struct #align(16) {
-	_: [PTHREAD_BARRIER_T_SIZE] c.char,
-}
-
-pthread_attr_t :: struct #align(16) {
-	_: [PTHREAD_ATTR_T_SIZE] c.char,
-}
-pthread_condattr_t :: struct #align(16) {
-	_: [PTHREAD_CONDATTR_T_SIZE] c.char,
-}
-pthread_mutexattr_t :: struct #align(16) {
-	_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
-}
-pthread_rwlockattr_t :: struct #align(16) {
-	_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
-}
-pthread_barrierattr_t :: struct #align(16) {
-	_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
-}
-
-PTHREAD_MUTEX_NORMAL :: 0
-PTHREAD_MUTEX_RECURSIVE :: 1
-PTHREAD_MUTEX_ERRORCHECK :: 2
-
-
-// TODO(tetra, 2019-11-01): Maybe make `enum c.int`s for these?
-PTHREAD_CREATE_JOINABLE :: 0
-PTHREAD_CREATE_DETACHED :: 1
-PTHREAD_INHERIT_SCHED :: 0
-PTHREAD_EXPLICIT_SCHED :: 1
-PTHREAD_PROCESS_PRIVATE :: 0
-PTHREAD_PROCESS_SHARED :: 1
-
-SCHED_OTHER :: 0
-SCHED_FIFO  :: 1
-SCHED_RR :: 2 // Round robin.
-
-sched_param :: struct {
-	sched_priority: c.int,
-}
-
-sem_t :: struct #align(16) {
-	_: [SEM_T_SIZE] c.char,
-}
-
-when size_of(int) == 8 {
-	SEM_T_SIZE :: 32
-} else when size_of(int) == 4 {
-	SEM_T_SIZE :: 16
-}
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 1
-
-foreign import "system:pthread"
-
-@(default_calling_convention="c")
-foreign pthread {
-	// create named semaphore.
-	// used in process-shared semaphores.
-	sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
-
-	sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
-	sem_destroy :: proc(sem: ^sem_t) -> c.int ---
-	sem_post :: proc(sem: ^sem_t) -> c.int ---
-	sem_wait :: proc(sem: ^sem_t) -> c.int ---
-	sem_trywait :: proc(sem: ^sem_t) -> c.int ---
-	// sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---;
-
-	// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
-	// see https://linux.die.net/man/3/pthread_yield
-	pthread_yield :: proc() -> c.int ---
-
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 102
core/sys/unix/pthread_netbsd.odin

@@ -1,102 +0,0 @@
-package unix
-
-import "core:c"
-
-pthread_t :: distinct rawptr
-
-SEM_T_SIZE :: 8
-
-PTHREAD_CONDATTR_T_SIZE    :: 16
-PTHREAD_MUTEXATTR_T_SIZE   :: 16
-PTHREAD_RWLOCKATTR_T_SIZE  :: 16
-PTHREAD_BARRIERATTR_T_SIZE :: 16
-
-PTHREAD_COND_T_SIZE    :: 40
-PTHREAD_MUTEX_T_SIZE   :: 48
-PTHREAD_RWLOCK_T_SIZE  :: 64
-PTHREAD_BARRIER_T_SIZE :: 48
-PTHREAD_ATTR_T_SIZE    :: 16
-
-pthread_cond_t :: struct #align(8) {
-	_: [PTHREAD_COND_T_SIZE] c.char,
-}
-
-pthread_mutex_t :: struct #align(8) {
-	_: [PTHREAD_MUTEX_T_SIZE] c.char,
-}
-
-pthread_rwlock_t :: struct #align(8) {
-	_: [PTHREAD_RWLOCK_T_SIZE] c.char,
-}
-
-pthread_barrier_t :: struct #align(8) {
-	_: [PTHREAD_BARRIER_T_SIZE] c.char,
-}
-
-pthread_attr_t :: struct #align(8) {
-	_: [PTHREAD_ATTR_T_SIZE] c.char,
-}
-
-pthread_condattr_t :: struct #align(8) {
-	_: [PTHREAD_CONDATTR_T_SIZE] c.char,
-}
-
-pthread_mutexattr_t :: struct #align(8) {
-	_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
-}
-
-pthread_rwlockattr_t :: struct #align(8) {
-	_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
-}
-
-pthread_barrierattr_t :: struct #align(8) {
-	_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
-}
-
-PTHREAD_MUTEX_NORMAL     :: 0
-PTHREAD_MUTEX_ERRORCHECK :: 1
-PTHREAD_MUTEX_RECURSIVE  :: 2
-
-PTHREAD_CREATE_JOINABLE :: 0
-PTHREAD_CREATE_DETACHED :: 1
-PTHREAD_INHERIT_SCHED   :: 0
-PTHREAD_EXPLICIT_SCHED  :: 1
-PTHREAD_PROCESS_PRIVATE :: 0
-PTHREAD_PROCESS_SHARED  :: 1
-
-SCHED_NONE  :: -1
-SCHED_OTHER :: 0
-SCHED_FIFO  :: 1
-SCHED_RR    :: 3
-
-sched_param :: struct {
-	sched_priority: c.int,
-}
-
-sem_t :: struct #align(16) {
-	_: [SEM_T_SIZE] c.char,
-}
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 1
-
-foreign import "system:pthread"
-
-@(default_calling_convention="c")
-foreign pthread {
-	sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
-
-	sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
-	sem_destroy :: proc(sem: ^sem_t) -> c.int ---
-	sem_post :: proc(sem: ^sem_t) -> c.int ---
-	sem_wait :: proc(sem: ^sem_t) -> c.int ---
-	sem_trywait :: proc(sem: ^sem_t) -> c.int ---
-
-	pthread_yield :: proc() ---
-
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 74
core/sys/unix/pthread_openbsd.odin

@@ -1,74 +0,0 @@
-#+build openbsd
-package unix
-
-import "core:c"
-
-pthread_t             :: distinct rawptr
-pthread_attr_t        :: distinct rawptr
-pthread_mutex_t       :: distinct rawptr
-pthread_mutexattr_t   :: distinct rawptr
-pthread_cond_t        :: distinct rawptr
-pthread_condattr_t    :: distinct rawptr
-pthread_rwlock_t      :: distinct rawptr
-pthread_rwlockattr_t  :: distinct rawptr
-pthread_barrier_t     :: distinct rawptr
-pthread_barrierattr_t :: distinct rawptr
-pthread_spinlock_t    :: distinct rawptr
-
-pthread_key_t  :: distinct c.int
-pthread_once_t :: struct {
-	state: c.int,
-	mutex: pthread_mutex_t,
-}
-
-PTHREAD_MUTEX_ERRORCHECK :: 1
-PTHREAD_MUTEX_RECURSIVE  :: 2
-PTHREAD_MUTEX_NORMAL     :: 3
-PTHREAD_MUTEX_STRICT_NP  :: 4
-
-PTHREAD_DETACHED      :: 0x1
-PTHREAD_SCOPE_SYSTEM  :: 0x2
-PTHREAD_INHERIT_SCHED :: 0x4
-PTHREAD_NOFLOAT       :: 0x8
-
-PTHREAD_CREATE_DETACHED :: PTHREAD_DETACHED
-PTHREAD_CREATE_JOINABLE :: 0
-PTHREAD_SCOPE_PROCESS   :: 0
-PTHREAD_EXPLICIT_SCHED  :: 0
-
-SCHED_FIFO  :: 1
-SCHED_OTHER :: 2
-SCHED_RR    :: 3
-
-sched_param :: struct {
-	sched_priority: c.int,
-}
-
-sem_t :: distinct rawptr
-
-PTHREAD_CANCEL_ENABLE       :: 0
-PTHREAD_CANCEL_DISABLE      :: 1
-PTHREAD_CANCEL_DEFERRED     :: 0
-PTHREAD_CANCEL_ASYNCHRONOUS :: 2
-
-foreign import libc "system:c"
-
-@(default_calling_convention="c")
-foreign libc {
-	sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
-
-	sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
-	sem_destroy :: proc(sem: ^sem_t) -> c.int ---
-	sem_post :: proc(sem: ^sem_t) -> c.int ---
-	sem_wait :: proc(sem: ^sem_t) -> c.int ---
-	sem_trywait :: proc(sem: ^sem_t) -> c.int ---
-	//sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---
-
-	// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
-	// see https://linux.die.net/man/3/pthread_yield
-	pthread_yield :: proc() ---
-
-	pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
-	pthread_setcanceltype  :: proc (type:  c.int, old_type:  ^c.int) -> c.int ---
-	pthread_cancel         :: proc (thread: pthread_t) -> c.int ---
-}

+ 0 - 127
core/sys/unix/pthread_unix.odin

@@ -1,127 +0,0 @@
-#+build linux, darwin, freebsd, openbsd, netbsd, haiku
-package unix
-
-foreign import "system:pthread"
-
-import "core:c"
-
-timespec :: struct {
-	tv_sec:  i64,
-	tv_nsec: i64,
-}
-
-//
-// On success, these functions return 0.
-//
-
-@(default_calling_convention="c")
-foreign pthread {
-	pthread_create :: proc(t: ^pthread_t, attrs: ^pthread_attr_t, routine: proc(data: rawptr) -> rawptr, arg: rawptr) -> c.int ---
-
-	// retval is a pointer to a location to put the return value of the thread proc.
-	pthread_join :: proc(t: pthread_t, retval: ^rawptr) -> c.int ---
-
-	pthread_kill :: proc(t: pthread_t, sig: c.int) -> c.int ---
-
-	pthread_self :: proc() -> pthread_t ---
-
-	pthread_equal :: proc(a, b: pthread_t) -> b32 ---
-
-	pthread_detach :: proc(t: pthread_t) -> c.int ---
-
-	sched_get_priority_min :: proc(policy: c.int) -> c.int ---
-	sched_get_priority_max :: proc(policy: c.int) -> c.int ---
-
-	// NOTE: POSIX says this can fail with OOM.
-	pthread_attr_init :: proc(attrs: ^pthread_attr_t) -> c.int ---
-
-	pthread_attr_destroy :: proc(attrs: ^pthread_attr_t) -> c.int ---
-
-	pthread_attr_getschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int ---
-	pthread_attr_setschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int ---
-
-	// states: PTHREAD_CREATE_DETACHED, PTHREAD_CREATE_JOINABLE
-	pthread_attr_setdetachstate :: proc(attrs: ^pthread_attr_t, detach_state: c.int) -> c.int ---
-	
-	// NOTE(tetra, 2019-11-06): WARNING: Different systems have different alignment requirements.
-	// For maximum usefulness, use the OS's page size.
-	// ALSO VERY MAJOR WARNING: `stack_ptr` must be the LAST byte of the stack on systems
-	// where the stack grows downwards, which is the common case, so far as I know.
-	// On systems where it grows upwards, give the FIRST byte instead.
-	// ALSO SLIGHTLY LESS MAJOR WARNING: Using this procedure DISABLES automatically-provided
-	// guard pages. If you are using this procedure, YOU must set them up manually.
-	// If you forget to do this, you WILL get stack corruption bugs if you do not EXTREMELY
-	// know what you are doing!
-	pthread_attr_setstack :: proc(attrs: ^pthread_attr_t, stack_ptr: rawptr, stack_size: u64) -> c.int ---
-	pthread_attr_getstack :: proc(attrs: ^pthread_attr_t, stack_ptr: ^rawptr, stack_size: ^u64) -> c.int ---
-
-	pthread_sigmask :: proc(how: c.int, set: rawptr, oldset: rawptr) -> c.int ---
-
-	sched_yield :: proc() -> c.int ---
-}
-
-// NOTE: Unimplemented in Haiku.
-when ODIN_OS != .Haiku {
-	foreign pthread {
-		// scheds: PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED
-		pthread_attr_setinheritsched :: proc(attrs: ^pthread_attr_t, sched: c.int) -> c.int ---
-
-		pthread_attr_getschedpolicy :: proc(t: ^pthread_attr_t, policy: ^c.int) -> c.int ---
-		pthread_attr_setschedpolicy :: proc(t: ^pthread_attr_t, policy: c.int) -> c.int ---
-	}
-}
-
-@(default_calling_convention="c")
-foreign pthread {
-	// NOTE: POSIX says this can fail with OOM.
-	pthread_cond_init :: proc(cond: ^pthread_cond_t, attrs: ^pthread_condattr_t) -> c.int ---
-
-	pthread_cond_destroy :: proc(cond: ^pthread_cond_t) -> c.int ---
-
-	pthread_cond_signal :: proc(cond: ^pthread_cond_t) -> c.int ---
-
-	// same as signal, but wakes up _all_ threads that are waiting
-	pthread_cond_broadcast :: proc(cond: ^pthread_cond_t) -> c.int ---
-
-
-	// assumes the mutex is pre-locked
-	pthread_cond_wait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t) -> c.int ---
-	pthread_cond_timedwait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t, timeout: ^timespec) -> c.int ---
-
-	pthread_condattr_init :: proc(attrs: ^pthread_condattr_t) -> c.int ---
-	pthread_condattr_destroy :: proc(attrs: ^pthread_condattr_t) -> c.int ---
-
-	// p-shared = "process-shared" - i.e: is this condition shared among multiple processes?
-	// values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED
-	pthread_condattr_setpshared :: proc(attrs: ^pthread_condattr_t, value: c.int) -> c.int ---
-	pthread_condattr_getpshared :: proc(attrs: ^pthread_condattr_t, result: ^c.int) -> c.int ---
-
-}
-
-@(default_calling_convention="c")
-foreign pthread {
-	// NOTE: POSIX says this can fail with OOM.
-	pthread_mutex_init :: proc(mutex: ^pthread_mutex_t, attrs: ^pthread_mutexattr_t) -> c.int ---
-
-	pthread_mutex_destroy :: proc(mutex: ^pthread_mutex_t) -> c.int ---
-
-	pthread_mutex_trylock :: proc(mutex: ^pthread_mutex_t) -> c.int ---
-
-	pthread_mutex_lock :: proc(mutex: ^pthread_mutex_t) -> c.int ---
-
-	pthread_mutex_timedlock :: proc(mutex: ^pthread_mutex_t, timeout: ^timespec) -> c.int ---
-
-	pthread_mutex_unlock :: proc(mutex: ^pthread_mutex_t) -> c.int ---
-
-
-	pthread_mutexattr_init :: proc(attrs: ^pthread_mutexattr_t) -> c.int ---
-	pthread_mutexattr_destroy :: proc(attrs: ^pthread_mutexattr_t) -> c.int ---
-	pthread_mutexattr_settype :: proc(attrs: ^pthread_mutexattr_t, type: c.int) -> c.int ---
-
-	// p-shared = "process-shared" - i.e: is this mutex shared among multiple processes?
-	// values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED
-	pthread_mutexattr_setpshared :: proc(attrs: ^pthread_mutexattr_t, value: c.int) -> c.int ---
-	pthread_mutexattr_getpshared :: proc(attrs: ^pthread_mutexattr_t, result: ^c.int) -> c.int ---
-
-	pthread_testcancel :: proc () ---
-}

+ 8 - 0
core/sys/unix/unix.odin

@@ -0,0 +1,8 @@
+package unix
+
+import "core:c"
+
+timespec :: struct {
+	secs:  i64,
+	nsecs: c.long,
+}

+ 3 - 3
core/testing/signal_handler_libc.odin

@@ -15,7 +15,7 @@ import "core:c/libc"
 import "core:encoding/ansi"
 import "core:encoding/ansi"
 import "core:sync"
 import "core:sync"
 import "core:os"
 import "core:os"
-@require import "core:sys/unix"
+@require import "core:sys/posix"
 
 
 @(private="file") stop_runner_flag: libc.sig_atomic_t
 @(private="file") stop_runner_flag: libc.sig_atomic_t
 
 
@@ -114,8 +114,8 @@ This is a dire bug and should be reported to the Odin developers.
 				// properly set to PTHREAD_CANCEL_ASYNCHRONOUS.
 				// properly set to PTHREAD_CANCEL_ASYNCHRONOUS.
 				//
 				//
 				// The runner would stall after returning from `pthread_cancel`.
 				// The runner would stall after returning from `pthread_cancel`.
-			
-				unix.pthread_testcancel()
+
+				posix.pthread_testcancel()
 			}
 			}
 		}
 		}
 	}
 	}

+ 30 - 30
core/thread/thread_unix.odin

@@ -4,14 +4,14 @@ package thread
 
 
 import "base:runtime"
 import "base:runtime"
 import "core:sync"
 import "core:sync"
-import "core:sys/unix"
+import "core:sys/posix"
 
 
 _IS_SUPPORTED :: true
 _IS_SUPPORTED :: true
 
 
 // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t.
 // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t.
 // Also see core/sys/darwin/mach_darwin.odin/semaphore_t.
 // Also see core/sys/darwin/mach_darwin.odin/semaphore_t.
 Thread_Os_Specific :: struct #align(16) {
 Thread_Os_Specific :: struct #align(16) {
-	unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux.
+	unix_thread: posix.pthread_t, // NOTE: very large on Darwin, small on Linux.
 	start_ok:    sync.Sema,
 	start_ok:    sync.Sema,
 }
 }
 //
 //
@@ -23,7 +23,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 		t := (^Thread)(t)
 		t := (^Thread)(t)
 
 
 		// We need to give the thread a moment to start up before we enable cancellation.
 		// We need to give the thread a moment to start up before we enable cancellation.
-		can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0
+		can_set_thread_cancel_state := posix.pthread_setcancelstate(.ENABLE, nil) == nil
 
 
 		t.id = sync.current_thread_id()
 		t.id = sync.current_thread_id()
 
 
@@ -37,8 +37,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 
 
 		// Enable thread's cancelability.
 		// Enable thread's cancelability.
 		if can_set_thread_cancel_state {
 		if can_set_thread_cancel_state {
-			unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil)
-			unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE,       nil)
+			posix.pthread_setcanceltype (.ASYNCHRONOUS, nil)
+			posix.pthread_setcancelstate(.ENABLE,       nil)
 		}
 		}
 
 
 		{
 		{
@@ -59,8 +59,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 		sync.atomic_or(&t.flags, { .Done })
 		sync.atomic_or(&t.flags, { .Done })
 
 
 		if .Self_Cleanup in sync.atomic_load(&t.flags) {
 		if .Self_Cleanup in sync.atomic_load(&t.flags) {
-			res := unix.pthread_detach(t.unix_thread)
-			assert_contextless(res == 0)
+			res := posix.pthread_detach(t.unix_thread)
+			assert_contextless(res == nil)
 
 
 			t.unix_thread = {}
 			t.unix_thread = {}
 			// NOTE(ftphikari): It doesn't matter which context 'free' received, right?
 			// NOTE(ftphikari): It doesn't matter which context 'free' received, right?
@@ -71,19 +71,19 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 		return nil
 		return nil
 	}
 	}
 
 
-	attrs: unix.pthread_attr_t
-	if unix.pthread_attr_init(&attrs) != 0 {
+	attrs: posix.pthread_attr_t
+	if posix.pthread_attr_init(&attrs) != nil {
 		return nil // NOTE(tetra, 2019-11-01): POSIX OOM.
 		return nil // NOTE(tetra, 2019-11-01): POSIX OOM.
 	}
 	}
-	defer unix.pthread_attr_destroy(&attrs)
+	defer posix.pthread_attr_destroy(&attrs)
 
 
 	// NOTE(tetra, 2019-11-01): These only fail if their argument is invalid.
 	// NOTE(tetra, 2019-11-01): These only fail if their argument is invalid.
-	res: i32
-	res = unix.pthread_attr_setdetachstate(&attrs, unix.PTHREAD_CREATE_JOINABLE)
-	assert(res == 0)
+	res: posix.Errno
+	res = posix.pthread_attr_setdetachstate(&attrs, .CREATE_JOINABLE)
+	assert(res == nil)
 	when ODIN_OS != .Haiku && ODIN_OS != .NetBSD {
 	when ODIN_OS != .Haiku && ODIN_OS != .NetBSD {
-		res = unix.pthread_attr_setinheritsched(&attrs, unix.PTHREAD_EXPLICIT_SCHED)
-		assert(res == 0)
+		res = posix.pthread_attr_setinheritsched(&attrs, .EXPLICIT_SCHED)
+		assert(res == nil)
 	}
 	}
 
 
 	thread := new(Thread)
 	thread := new(Thread)
@@ -93,26 +93,26 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 	thread.creation_allocator = context.allocator
 	thread.creation_allocator = context.allocator
 
 
 	// Set thread priority.
 	// Set thread priority.
-	policy: i32
+	policy: posix.Sched_Policy
 	when ODIN_OS != .Haiku && ODIN_OS != .NetBSD {
 	when ODIN_OS != .Haiku && ODIN_OS != .NetBSD {
-		res = unix.pthread_attr_getschedpolicy(&attrs, &policy)
-		assert(res == 0)
+		res = posix.pthread_attr_getschedpolicy(&attrs, &policy)
+		assert(res == nil)
 	}
 	}
-	params: unix.sched_param
-	res = unix.pthread_attr_getschedparam(&attrs, &params)
-	assert(res == 0)
-	low := unix.sched_get_priority_min(policy)
-	high := unix.sched_get_priority_max(policy)
+	params: posix.sched_param
+	res = posix.pthread_attr_getschedparam(&attrs, &params)
+	assert(res == nil)
+	low := posix.sched_get_priority_min(policy)
+	high := posix.sched_get_priority_max(policy)
 	switch priority {
 	switch priority {
 	case .Normal: // Okay
 	case .Normal: // Okay
 	case .Low:  params.sched_priority = low + 1
 	case .Low:  params.sched_priority = low + 1
 	case .High: params.sched_priority = high
 	case .High: params.sched_priority = high
 	}
 	}
-	res = unix.pthread_attr_setschedparam(&attrs, &params)
-	assert(res == 0)
+	res = posix.pthread_attr_setschedparam(&attrs, &params)
+	assert(res == nil)
 
 
 	thread.procedure = procedure
 	thread.procedure = procedure
-	if unix.pthread_create(&thread.unix_thread, &attrs, __unix_thread_entry_proc, thread) != 0 {
+	if posix.pthread_create(&thread.unix_thread, &attrs, __unix_thread_entry_proc, thread) != nil {
 		free(thread, thread.creation_allocator)
 		free(thread, thread.creation_allocator)
 		return nil
 		return nil
 	}
 	}
@@ -130,7 +130,7 @@ _is_done :: proc(t: ^Thread) -> bool {
 }
 }
 
 
 _join :: proc(t: ^Thread) {
 _join :: proc(t: ^Thread) {
-	if unix.pthread_equal(unix.pthread_self(), t.unix_thread) {
+	if posix.pthread_equal(posix.pthread_self(), t.unix_thread) {
 		return
 		return
 	}
 	}
 
 
@@ -144,7 +144,7 @@ _join :: proc(t: ^Thread) {
 	if .Started not_in sync.atomic_load(&t.flags) {
 	if .Started not_in sync.atomic_load(&t.flags) {
 		_start(t)
 		_start(t)
 	}
 	}
-	unix.pthread_join(t.unix_thread, nil)
+	posix.pthread_join(t.unix_thread, nil)
 }
 }
 
 
 _join_multiple :: proc(threads: ..^Thread) {
 _join_multiple :: proc(threads: ..^Thread) {
@@ -170,9 +170,9 @@ _terminate :: proc(t: ^Thread, exit_code: int) {
 	//
 	//
 	// This is in contrast to behavior I have seen on Linux where the thread is
 	// This is in contrast to behavior I have seen on Linux where the thread is
 	// just terminated.
 	// just terminated.
-	unix.pthread_cancel(t.unix_thread)
+	posix.pthread_cancel(t.unix_thread)
 }
 }
 
 
 _yield :: proc() {
 _yield :: proc() {
-	unix.sched_yield()
+	posix.sched_yield()
 }
 }

+ 1 - 1
core/unicode/utf8/utf8string/string.odin

@@ -66,7 +66,7 @@ at :: proc(s: ^String, i: int, loc := #caller_location) -> (r: rune) {
 		return
 		return
 
 
 	case s.rune_count-1:
 	case s.rune_count-1:
-		r, s.width = utf8.decode_rune_in_string(s.contents)
+		r, s.width = utf8.decode_last_rune(s.contents)
 		s.rune_pos = i
 		s.rune_pos = i
 		s.byte_pos = _len(s.contents) - s.width
 		s.byte_pos = _len(s.contents) - s.width
 		return
 		return

+ 14 - 3
src/big_int.cpp

@@ -62,6 +62,7 @@ gb_internal void big_int_shl    (BigInt *dst, BigInt const *x, BigInt const *y);
 gb_internal void big_int_shr    (BigInt *dst, BigInt const *x, BigInt const *y);
 gb_internal void big_int_shr    (BigInt *dst, BigInt const *x, BigInt const *y);
 gb_internal void big_int_mul    (BigInt *dst, BigInt const *x, BigInt const *y);
 gb_internal void big_int_mul    (BigInt *dst, BigInt const *x, BigInt const *y);
 gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
 gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
+gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success);
 
 
 gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
 gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
 gb_internal void big_int_quo    (BigInt *z, BigInt const *x, BigInt const *y);
 gb_internal void big_int_quo    (BigInt *z, BigInt const *x, BigInt const *y);
@@ -250,9 +251,7 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success
 			exp *= 10;
 			exp *= 10;
 			exp += v;
 			exp += v;
 		}
 		}
-		for (u64 x = 0; x < exp; x++) {
-			big_int_mul_eq(dst, &b);
-		}
+		big_int_exp_u64(dst, &b, exp, success);
 	}
 	}
 
 
 	if (is_negative) {
 	if (is_negative) {
@@ -328,6 +327,18 @@ gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
 	big_int_dealloc(&d);
 	big_int_dealloc(&d);
 }
 }
 
 
+gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success) {
+	if (y > INT_MAX) {
+		*success = false;
+		return;
+	}
+
+	// Note: The cutoff for square-multiply being faster than the naive
+	// for loop is when exp > 4, but it probably isn't worth adding
+	// a fast path.
+	mp_err err = mp_expt_n(x, int(y), dst);
+	*success = err == MP_OKAY;
+}
 
 
 gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
 gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
 	mp_mul(x, y, dst);
 	mp_mul(x, y, dst);

+ 4 - 0
src/check_builtin.cpp

@@ -1533,6 +1533,10 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
 
 
 		for (FileInfo fi : list) {
 		for (FileInfo fi : list) {
 			LoadFileCache *cache = nullptr;
 			LoadFileCache *cache = nullptr;
+			if (fi.is_dir) {
+				continue;
+			}
+
 			if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) {
 			if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) {
 				array_add(&file_caches, cache);
 				array_add(&file_caches, cache);
 			} else {
 			} else {

+ 1 - 0
src/exact_value.cpp

@@ -687,6 +687,7 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
 	case ExactValue_String:
 	case ExactValue_String:
 	case ExactValue_Quaternion:
 	case ExactValue_Quaternion:
 	case ExactValue_Pointer:
 	case ExactValue_Pointer:
+	case ExactValue_Compound:
 	case ExactValue_Procedure:
 	case ExactValue_Procedure:
 	case ExactValue_Typeid:
 	case ExactValue_Typeid:
 		return;
 		return;

+ 5 - 1
src/gb/gb.h

@@ -2541,7 +2541,11 @@ gb_inline void const *gb_pointer_add_const(void const *ptr, isize bytes)       {
 gb_inline void const *gb_pointer_sub_const(void const *ptr, isize bytes)       { return cast(void const *)(cast(u8 const *)ptr - bytes); }
 gb_inline void const *gb_pointer_sub_const(void const *ptr, isize bytes)       { return cast(void const *)(cast(u8 const *)ptr - bytes); }
 gb_inline isize       gb_pointer_diff     (void const *begin, void const *end) { return cast(isize)(cast(u8 const *)end - cast(u8 const *)begin); }
 gb_inline isize       gb_pointer_diff     (void const *begin, void const *end) { return cast(isize)(cast(u8 const *)end - cast(u8 const *)begin); }
 
 
-gb_inline void gb_zero_size(void *ptr, isize size) { memset(ptr, 0, size); }
+gb_inline void gb_zero_size(void *ptr, isize size) {
+	if (size != 0) {
+		memset(ptr, 0, size);
+	}
+}
 
 
 
 
 #if defined(_MSC_VER) && !defined(__clang__)
 #if defined(_MSC_VER) && !defined(__clang__)

+ 1 - 1
src/llvm_backend_expr.cpp

@@ -1647,7 +1647,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 			lb_emit_store(p, a1, id);
 			lb_emit_store(p, a1, id);
 			return lb_addr_load(p, res);
 			return lb_addr_load(p, res);
 		} else if (dst->kind == Type_Basic) {
 		} else if (dst->kind == Type_Basic) {
-			if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) {
+			if (src->kind == Type_Basic && src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) {
 				String str = lb_get_const_string(m, value);
 				String str = lb_get_const_string(m, value);
 				lbValue res = {};
 				lbValue res = {};
 				res.type = t;
 				res.type = t;

+ 11 - 8
src/llvm_backend_stmt.cpp

@@ -2018,14 +2018,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
 gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
 gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
 	lb_ensure_abi_function_type(p->module, p);
 	lb_ensure_abi_function_type(p->module, p);
 
 
-	lbValue res = {};
-
-	TypeTuple *tuple  = &p->type->Proc.results->Tuple;
 	isize return_count = p->type->Proc.result_count;
 	isize return_count = p->type->Proc.result_count;
-	isize res_count = return_results.count;
-
-	lbFunctionType *ft = lb_get_function_type(p->module, p->type);
-	bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
 
 
 	if (return_count == 0) {
 	if (return_count == 0) {
 		// No return values
 		// No return values
@@ -2038,7 +2031,17 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
 			LLVMBuildRetVoid(p->builder);
 			LLVMBuildRetVoid(p->builder);
 		}
 		}
 		return;
 		return;
-	} else if (return_count == 1) {
+	}
+
+	lbValue res = {};
+
+	TypeTuple *tuple = &p->type->Proc.results->Tuple;
+	isize res_count = return_results.count;
+
+	lbFunctionType *ft = lb_get_function_type(p->module, p->type);
+	bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
+
+	if (return_count == 1) {
 		Entity *e = tuple->variables[0];
 		Entity *e = tuple->variables[0];
 		if (res_count == 0) {
 		if (res_count == 0) {
 			rw_mutex_shared_lock(&p->module->values_mutex);
 			rw_mutex_shared_lock(&p->module->values_mutex);

+ 0 - 2
src/parser.cpp

@@ -4262,8 +4262,6 @@ gb_internal bool allow_field_separator(AstFile *f) {
 gb_internal Ast *parse_struct_field_list(AstFile *f, isize *name_count_) {
 gb_internal Ast *parse_struct_field_list(AstFile *f, isize *name_count_) {
 	Token start_token = f->curr_token;
 	Token start_token = f->curr_token;
 
 
-	auto decls = array_make<Ast *>(ast_allocator(f));
-
 	isize total_name_count = 0;
 	isize total_name_count = 0;
 
 
 	Ast *params = parse_field_list(f, &total_name_count, FieldFlag_Struct, Token_CloseBrace, false, false);
 	Ast *params = parse_field_list(f, &total_name_count, FieldFlag_Struct, Token_CloseBrace, false, false);

+ 1 - 0
src/string.cpp

@@ -156,6 +156,7 @@ gb_internal isize string_index_byte(String const &s, u8 x) {
 
 
 gb_internal gb_inline bool str_eq(String const &a, String const &b) {
 gb_internal gb_inline bool str_eq(String const &a, String const &b) {
 	if (a.len != b.len) return false;
 	if (a.len != b.len) return false;
+	if (a.len == 0) return true;
 	return memcmp(a.text, b.text, a.len) == 0;
 	return memcmp(a.text, b.text, a.len) == 0;
 }
 }
 gb_internal gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b);                }
 gb_internal gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b);                }

+ 9 - 4
src/unicode.cpp

@@ -1,10 +1,15 @@
-#pragma warning(push)
-#pragma warning(disable: 4245)
+#if defined(GB_SYSTEM_WINDOWS)
+	#pragma warning(push)
+	#pragma warning(disable: 4245)
+#endif
 
 
 extern "C" {
 extern "C" {
 #include "utf8proc/utf8proc.c"
 #include "utf8proc/utf8proc.c"
 }
 }
-#pragma warning(pop)
+
+#if defined(GB_SYSTEM_WINDOWS)
+	#pragma warning(pop)
+#endif
 
 
 
 
 gb_internal bool rune_is_letter(Rune r) {
 gb_internal bool rune_is_letter(Rune r) {
@@ -109,7 +114,7 @@ gb_internal isize utf8_decode(u8 const *str, isize str_len, Rune *codepoint_out)
 		u8 b1, b2, b3;
 		u8 b1, b2, b3;
 		Utf8AcceptRange accept;
 		Utf8AcceptRange accept;
 		if (x >= 0xf0) {
 		if (x >= 0xf0) {
-			Rune mask = (cast(Rune)x << 31) >> 31;
+			Rune mask = -cast(Rune)(x & 1);
 			codepoint = (cast(Rune)s0 & (~mask)) | (GB_RUNE_INVALID & mask);
 			codepoint = (cast(Rune)s0 & (~mask)) | (GB_RUNE_INVALID & mask);
 			width = 1;
 			width = 1;
 			goto end;
 			goto end;

+ 1 - 14
tests/core/sys/posix/posix.odin

@@ -1,4 +1,4 @@
-#+build darwin, freebsd, openbsd, netbsd
+#+build linux, darwin, freebsd, openbsd, netbsd
 package tests_core_posix
 package tests_core_posix
 
 
 import "core:log"
 import "core:log"
@@ -144,7 +144,6 @@ test_libgen :: proc(t: ^testing.T) {
 		{ "usr/",             ".",          "usr" },
 		{ "usr/",             ".",          "usr" },
 		{ "",                 ".",          "." },
 		{ "",                 ".",          "." },
 		{ "/",                "/",          "/" },
 		{ "/",                "/",          "/" },
-		{ "//",               "/",          "/" },
 		{ "///",              "/",          "/" },
 		{ "///",              "/",          "/" },
 		{ "/usr/",            "/",          "usr" },
 		{ "/usr/",            "/",          "usr" },
 		{ "/usr/lib",         "/usr",       "lib" },
 		{ "/usr/lib",         "/usr",       "lib" },
@@ -203,18 +202,6 @@ test_stat :: proc(t: ^testing.T) {
 	testing.expect_value(t, stat.st_size, posix.off_t(len(CONTENT)))
 	testing.expect_value(t, stat.st_size, posix.off_t(len(CONTENT)))
 }
 }
 
 
-@(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)
-}
-
 @(test)
 @(test)
 test_pthreads :: proc(t: ^testing.T) {
 test_pthreads :: proc(t: ^testing.T) {
 	testing.set_fail_timeout(t, time.Second)
 	testing.set_fail_timeout(t, time.Second)

+ 1 - 1
tests/core/sys/posix/structs.odin

@@ -1,4 +1,4 @@
-#+build darwin, freebsd, openbsd, netbsd
+#+build linux, darwin, freebsd, openbsd, netbsd
 package tests_core_posix
 package tests_core_posix
 
 
 import "core:log"
 import "core:log"

+ 2 - 0
tests/core/sys/posix/structs/structs.c

@@ -40,7 +40,9 @@ int main(int argc, char *argv[])
     printf("pthread_attr_t %zu %zu\n", sizeof(pthread_attr_t), _Alignof(pthread_attr_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("pthread_key_t %zu %zu\n", sizeof(pthread_key_t), _Alignof(pthread_key_t));
 
 
+#ifndef __linux__
     printf("sched_param %zu %zu\n", sizeof(struct sched_param), _Alignof(struct sched_param));
     printf("sched_param %zu %zu\n", sizeof(struct sched_param), _Alignof(struct sched_param));
+#endif
 
 
 	printf("termios %zu %zu\n", sizeof(struct termios), _Alignof(struct termios));
 	printf("termios %zu %zu\n", sizeof(struct termios), _Alignof(struct termios));
 
 

+ 5 - 1
tests/core/sys/posix/structs/structs.odin

@@ -14,7 +14,11 @@ main :: proc() {
 	fmt.println("pthread_attr_t", size_of(posix.pthread_attr_t), align_of(posix.pthread_attr_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("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))
+	// NOTE: On Linux, differences between libc may mean the Odin side is larger than the other side,
+	// this is fine in practice.
+	when ODIN_OS != .Linux {
+		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("termios", size_of(posix.termios), align_of(posix.termios))
 	
 	

+ 7 - 7
vendor/miniaudio/common_unix.odin

@@ -1,18 +1,18 @@
 #+build !windows
 #+build !windows
 package miniaudio
 package miniaudio
 
 
-import "core:sys/unix"
+import "core:sys/posix"
 import "core:c"
 import "core:c"
 
 
-thread :: unix.pthread_t
-mutex :: unix.pthread_mutex_t
+thread :: posix.pthread_t
+mutex :: posix.pthread_mutex_t
 event :: struct {
 event :: struct {
 	value: u32,
 	value: u32,
-	lock: unix.pthread_mutex_t,
-	cond: unix.pthread_cond_t,
+	lock: posix.pthread_mutex_t,
+	cond: posix.pthread_cond_t,
 }
 }
 semaphore :: struct {
 semaphore :: struct {
 	value: c.int,
 	value: c.int,
-	lock: unix.pthread_mutex_t,
-	cond: unix.pthread_cond_t,
+	lock: posix.pthread_mutex_t,
+	cond: posix.pthread_cond_t,
 }
 }