diff options
Diffstat (limited to 'core/os/errors.odin')
| -rw-r--r-- | core/os/errors.odin | 255 |
1 files changed, 42 insertions, 213 deletions
diff --git a/core/os/errors.odin b/core/os/errors.odin index fcf70ec74..a60233f09 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -1,13 +1,12 @@ package os -import "base:intrinsics" -import "base:runtime" import "core:io" +import "base:runtime" -Platform_Error :: _Platform_Error -#assert(size_of(Platform_Error) <= 4) -#assert(intrinsics.type_has_nil(Platform_Error)) - +/* + General errors that are common within this package which cannot + be categorized by `io.Error` nor `runtime.Allocator_Error`. +*/ General_Error :: enum u32 { None, @@ -22,39 +21,43 @@ General_Error :: enum u32 { Invalid_Dir, Invalid_Path, Invalid_Callback, + Invalid_Command, Pattern_Has_Separator, + Pattern_Syntax_Error, // Indicates an error in `glob` or `match` pattern. - File_Is_Pipe, - Not_Dir, - - // Environment variable not found. + No_HOME_Variable, Env_Var_Not_Found, } +// A platform specific error +Platform_Error :: _Platform_Error -Errno :: Error // alias for legacy use - +/* + `Error` is a union of different classes of errors that could be returned from procedures in this package. +*/ Error :: union #shared_nil { General_Error, io.Error, runtime.Allocator_Error, Platform_Error, } -#assert(size_of(Error) == 8) +#assert(size_of(Error) == size_of(u64)) ERROR_NONE :: Error{} -ERROR_EOF :: io.Error.EOF +// Attempts to convert an `Error` into a platform specific error as an integer. `ok` is false if not possible @(require_results) -is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) { +is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } + +// Attempts to return the error `ferr` as a string without any allocation @(require_results) -error_string :: proc "contextless" (ferr: Error) -> string { +error_string :: proc(ferr: Error) -> string { if ferr == nil { return "" } @@ -62,18 +65,19 @@ error_string :: proc "contextless" (ferr: Error) -> string { case General_Error: switch e { case .None: return "" - case .Exist: return "file already exists" - case .Not_Exist: return "file does not exist" - case .Timeout: return "i/o timeout" - case .Broken_Pipe: return "Broken pipe" - case .Invalid_File: return "invalid file" - case .Invalid_Dir: return "invalid directory" - case .Invalid_Path: return "invalid path" - case .Invalid_Callback: return "invalid callback" - case .Pattern_Has_Separator: return "pattern has separator" - case .File_Is_Pipe: return "file is pipe" - case .Not_Dir: return "file is not directory" - case .Env_Var_Not_Found: return "environment variable not found" + case .Exist: return "file already exists" + case .Not_Exist: return "file does not exist" + case .Timeout: return "i/o timeout" + case .Broken_Pipe: return "Broken pipe" + case .Invalid_File: return "invalid file" + case .Invalid_Dir: return "invalid directory" + case .Invalid_Path: return "invalid path" + case .Invalid_Callback: return "invalid callback" + case .Invalid_Command: return "invalid command" + case .Pattern_Has_Separator: return "pattern has separator" + case .Pattern_Syntax_Error: return "glob pattern syntax error" + case .No_HOME_Variable: return "no $HOME variable" + case .Env_Var_Not_Found: return "environment variable not found" } case io.Error: switch e { @@ -106,210 +110,35 @@ error_string :: proc "contextless" (ferr: Error) -> string { case .Mode_Not_Implemented: return "allocator mode not implemented" } case Platform_Error: - return _error_string(e) + return _error_string(i32(e)) } return "unknown error" } -print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) { +/* + `print_error` is a utility procedure which will print an error `ferr` to a specified file `f`. +*/ +print_error :: proc(f: ^File, ferr: Error, msg: string) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) err_str := error_string(ferr) // msg + ": " + err_str + '\n' length := len(msg) + 2 + len(err_str) + 1 - buf_ := intrinsics.alloca(length, 1) - buf := buf_[:length] + buf := make([]u8, length, temp_allocator) copy(buf, msg) buf[len(msg)] = ':' buf[len(msg) + 1] = ' ' copy(buf[len(msg) + 2:], err_str) buf[length - 1] = '\n' - return write(f, buf) + write(f, buf) } -@(require_results, private) -_error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) { - if e == nil { - return "" - } - - when ODIN_OS == .Darwin { - if s := string(_darwin_string_error(i32(e))); s != "" { - return s - } - } - - when ODIN_OS != .Linux { - @(require_results) - binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check { - n := len(array) - left, right := 0, n - for left < right { - mid := int(uint(left+right) >> 1) - if array[mid] < key { - left = mid+1 - } else { - // equal or greater - right = mid - } - } - return left, left < n && array[left] == key - } - - err := runtime.Type_Info_Enum_Value(e) - - ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum) - if idx, ok := binary_search(ti.values, err); ok { - return ti.names[idx] - } - } else { - @(rodata, static) - pe_strings := [Platform_Error]string{ - .NONE = "", - .EPERM = "Operation not permitted", - .ENOENT = "No such file or directory", - .ESRCH = "No such process", - .EINTR = "Interrupted system call", - .EIO = "Input/output error", - .ENXIO = "No such device or address", - .E2BIG = "Argument list too long", - .ENOEXEC = "Exec format error", - .EBADF = "Bad file descriptor", - .ECHILD = "No child processes", - .EAGAIN = "Resource temporarily unavailable", - .ENOMEM = "Cannot allocate memory", - .EACCES = "Permission denied", - .EFAULT = "Bad address", - .ENOTBLK = "Block device required", - .EBUSY = "Device or resource busy", - .EEXIST = "File exists", - .EXDEV = "Invalid cross-device link", - .ENODEV = "No such device", - .ENOTDIR = "Not a directory", - .EISDIR = "Is a directory", - .EINVAL = "Invalid argument", - .ENFILE = "Too many open files in system", - .EMFILE = "Too many open files", - .ENOTTY = "Inappropriate ioctl for device", - .ETXTBSY = "Text file busy", - .EFBIG = "File too large", - .ENOSPC = "No space left on device", - .ESPIPE = "Illegal seek", - .EROFS = "Read-only file system", - .EMLINK = "Too many links", - .EPIPE = "Broken pipe", - .EDOM = "Numerical argument out of domain", - .ERANGE = "Numerical result out of range", - .EDEADLK = "Resource deadlock avoided", - .ENAMETOOLONG = "File name too long", - .ENOLCK = "No locks available", - .ENOSYS = "Function not implemented", - .ENOTEMPTY = "Directory not empty", - .ELOOP = "Too many levels of symbolic links", - .EUNKNOWN_41 = "Unknown Error (41)", - .ENOMSG = "No message of desired type", - .EIDRM = "Identifier removed", - .ECHRNG = "Channel number out of range", - .EL2NSYNC = "Level 2 not synchronized", - .EL3HLT = "Level 3 halted", - .EL3RST = "Level 3 reset", - .ELNRNG = "Link number out of range", - .EUNATCH = "Protocol driver not attached", - .ENOCSI = "No CSI structure available", - .EL2HLT = "Level 2 halted", - .EBADE = "Invalid exchange", - .EBADR = "Invalid request descriptor", - .EXFULL = "Exchange full", - .ENOANO = "No anode", - .EBADRQC = "Invalid request code", - .EBADSLT = "Invalid slot", - .EUNKNOWN_58 = "Unknown Error (58)", - .EBFONT = "Bad font file format", - .ENOSTR = "Device not a stream", - .ENODATA = "No data available", - .ETIME = "Timer expired", - .ENOSR = "Out of streams resources", - .ENONET = "Machine is not on the network", - .ENOPKG = "Package not installed", - .EREMOTE = "Object is remote", - .ENOLINK = "Link has been severed", - .EADV = "Advertise error", - .ESRMNT = "Srmount error", - .ECOMM = "Communication error on send", - .EPROTO = "Protocol error", - .EMULTIHOP = "Multihop attempted", - .EDOTDOT = "RFS specific error", - .EBADMSG = "Bad message", - .EOVERFLOW = "Value too large for defined data type", - .ENOTUNIQ = "Name not unique on network", - .EBADFD = "File descriptor in bad state", - .EREMCHG = "Remote address changed", - .ELIBACC = "Can not access a needed shared library", - .ELIBBAD = "Accessing a corrupted shared library", - .ELIBSCN = ".lib section in a.out corrupted", - .ELIBMAX = "Attempting to link in too many shared libraries", - .ELIBEXEC = "Cannot exec a shared library directly", - .EILSEQ = "Invalid or incomplete multibyte or wide character", - .ERESTART = "Interrupted system call should be restarted", - .ESTRPIPE = "Streams pipe error", - .EUSERS = "Too many users", - .ENOTSOCK = "Socket operation on non-socket", - .EDESTADDRREQ = "Destination address required", - .EMSGSIZE = "Message too long", - .EPROTOTYPE = "Protocol wrong type for socket", - .ENOPROTOOPT = "Protocol not available", - .EPROTONOSUPPORT = "Protocol not supported", - .ESOCKTNOSUPPORT = "Socket type not supported", - .EOPNOTSUPP = "Operation not supported", - .EPFNOSUPPORT = "Protocol family not supported", - .EAFNOSUPPORT = "Address family not supported by protocol", - .EADDRINUSE = "Address already in use", - .EADDRNOTAVAIL = "Cannot assign requested address", - .ENETDOWN = "Network is down", - .ENETUNREACH = "Network is unreachable", - .ENETRESET = "Network dropped connection on reset", - .ECONNABORTED = "Software caused connection abort", - .ECONNRESET = "Connection reset by peer", - .ENOBUFS = "No buffer space available", - .EISCONN = "Transport endpoint is already connected", - .ENOTCONN = "Transport endpoint is not connected", - .ESHUTDOWN = "Cannot send after transport endpoint shutdown", - .ETOOMANYREFS = "Too many references: cannot splice", - .ETIMEDOUT = "Connection timed out", - .ECONNREFUSED = "Connection refused", - .EHOSTDOWN = "Host is down", - .EHOSTUNREACH = "No route to host", - .EALREADY = "Operation already in progress", - .EINPROGRESS = "Operation now in progress", - .ESTALE = "Stale file handle", - .EUCLEAN = "Structure needs cleaning", - .ENOTNAM = "Not a XENIX named type file", - .ENAVAIL = "No XENIX semaphores available", - .EISNAM = "Is a named type file", - .EREMOTEIO = "Remote I/O error", - .EDQUOT = "Disk quota exceeded", - .ENOMEDIUM = "No medium found", - .EMEDIUMTYPE = "Wrong medium type", - .ECANCELED = "Operation canceled", - .ENOKEY = "Required key not available", - .EKEYEXPIRED = "Key has expired", - .EKEYREVOKED = "Key has been revoked", - .EKEYREJECTED = "Key was rejected by service", - .EOWNERDEAD = "Owner died", - .ENOTRECOVERABLE = "State not recoverable", - .ERFKILL = "Operation not possible due to RF-kill", - .EHWPOISON = "Memory page has hardware error", - } - if Platform_Error.NONE <= e && e <= max(Platform_Error) { - return pe_strings[e] - } - } - return "<unknown platform error>" -} -@(private, require_results) +// Attempts to convert an `Error` `ferr` into an `io.Error` +@(private) error_to_io_error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None |