diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index 240e6ed8d..727dd1319 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -3,6 +3,7 @@ package os import "core:strings" +@(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { dirp := _fdopendir(fd) or_return defer _closedir(dirp) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 1df1c2b9e..c96ce53f5 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -4,6 +4,7 @@ import win32 "core:sys/windows" import "core:strings" import "base:runtime" +@(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) { // Ignore "." and ".." diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 04ce98638..a73687a3c 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -7,6 +7,7 @@ import "base:runtime" // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true // Otherwise the returned value will be empty and the boolean will be false // NOTE: the value will be allocated with the supplied allocator +@(require_results) lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { if key == "" { return @@ -33,6 +34,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin // It returns the value, which will be empty if the variable is not present // To distinguish between an empty value and an unset value, use lookup_env // NOTE: the value will be allocated with the supplied allocator +@(require_results) get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return @@ -60,6 +62,7 @@ unset_env :: proc(key: string) -> Errno { // environ returns a copy of strings representing the environment, in the form "key=value" // NOTE: the slice of strings and the strings with be allocated using the supplied allocator +@(require_results) environ :: proc(allocator := context.allocator) -> []string { envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW()) if envs == nil { diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 8bfd9276d..7831aa3e6 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -11,7 +11,7 @@ is_path_separator :: proc(c: byte) -> bool { open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { if len(path) == 0 { - return INVALID_HANDLE, ERROR_FILE_NOT_FOUND + return INVALID_HANDLE, General_Error.Not_Exist } access: u32 @@ -55,8 +55,7 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return handle, nil } - err := get_last_error() - return INVALID_HANDLE, err + return INVALID_HANDLE, get_last_error() } close :: proc(fd: Handle) -> Errno { diff --git a/core/os/os.odin b/core/os/os.odin index d8c0ef658..3db3c5bd7 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -19,17 +19,51 @@ Platform_Error :: _Platform_Error #assert(size_of(Platform_Error) <= 4) #assert(intrinsics.type_has_nil(Platform_Error)) +General_Error :: enum u32 { + None, + + Permission_Denied, + Exist, + Not_Exist, + Closed, + + Timeout, + + Broken_Pipe, + + // Indicates that an attempt to retrieve a file's size was made, but the + // file doesn't have a size. + No_Size, + + Invalid_File, + Invalid_Dir, + Invalid_Path, + Invalid_Callback, + + Pattern_Has_Separator, + + Unsupported, +} + + Errno :: Error // alias for legacy use Error :: union #shared_nil { + General_Error, io.Error, runtime.Allocator_Error, Platform_Error, } -#assert(size_of(Error) <= 8) +#assert(size_of(Error) == 8) ERROR_NONE :: Error{} +@(require_results) +is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { + v := ferr.(Platform_Error) or_else {} + return i32(v), i32(v) != 0 +} + write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) } diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index 2b9b3528e..bc51bb1e8 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -42,13 +42,14 @@ Error :: union #shared_nil { ERROR_NONE :: Error{} - +@(require_results) is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } +@(require_results) error_string :: proc(ferr: Error) -> string { if ferr == nil { return "" diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 3d24e2258..4d5b13930 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -521,7 +521,18 @@ _get_errno :: proc(res: int) -> Errno { // get errno from libc get_last_error :: proc "contextless" () -> Error { - return Platform_Error(__errno_location()^) + err := Platform_Error(__errno_location()^) + #partial switch err { + case .NONE: + return nil + case .EPERM: + return .Permission_Denied + case .EEXIST: + return .Exist + case .ENOENT: + return .Not_Exist + } + return err } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index afba3c3b4..99c28d880 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -64,7 +64,53 @@ ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) args := _alloc_command_line_arguments() get_last_error :: proc "contextless" () -> Error { - return Platform_Error(win32.GetLastError()) + err := win32.GetLastError() + if err == 0 { + return nil + } + switch err { + case win32.ERROR_ACCESS_DENIED, win32.ERROR_SHARING_VIOLATION: + return .Permission_Denied + + case win32.ERROR_FILE_EXISTS, win32.ERROR_ALREADY_EXISTS: + return .Exist + + case win32.ERROR_FILE_NOT_FOUND, win32.ERROR_PATH_NOT_FOUND: + return .Not_Exist + + case win32.ERROR_NO_DATA: + return .Closed + + case win32.ERROR_TIMEOUT, win32.WAIT_TIMEOUT: + return .Timeout + + case win32.ERROR_NOT_SUPPORTED: + return .Unsupported + + case win32.ERROR_HANDLE_EOF: + return .EOF + + case win32.ERROR_INVALID_HANDLE: + return .Invalid_File + + case + win32.ERROR_BAD_ARGUMENTS, + win32.ERROR_INVALID_PARAMETER, + win32.ERROR_NOT_ENOUGH_MEMORY, + win32.ERROR_NO_MORE_FILES, + win32.ERROR_LOCK_VIOLATION, + win32.ERROR_BROKEN_PIPE, + win32.ERROR_CALL_NOT_IMPLEMENTED, + win32.ERROR_INSUFFICIENT_BUFFER, + win32.ERROR_INVALID_NAME, + win32.ERROR_LOCK_FAILED, + win32.ERROR_ENVVAR_NOT_FOUND, + win32.ERROR_OPERATION_ABORTED, + win32.ERROR_IO_PENDING, + win32.ERROR_NO_UNICODE_TRANSLATION: + // fallthrough + } + return Platform_Error(err) }