errors.odin 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package os
  2. import "base:intrinsics"
  3. import "base:runtime"
  4. import "core:io"
  5. Platform_Error :: _Platform_Error
  6. #assert(size_of(Platform_Error) <= 4)
  7. #assert(intrinsics.type_has_nil(Platform_Error))
  8. General_Error :: enum u32 {
  9. None,
  10. Permission_Denied,
  11. Exist,
  12. Not_Exist,
  13. Closed,
  14. Timeout,
  15. Broken_Pipe,
  16. // Indicates that an attempt to retrieve a file's size was made, but the
  17. // file doesn't have a size.
  18. No_Size,
  19. Invalid_File,
  20. Invalid_Dir,
  21. Invalid_Path,
  22. Invalid_Callback,
  23. Pattern_Has_Separator,
  24. Unsupported,
  25. File_Is_Pipe,
  26. Not_Dir,
  27. // Environment variable not found.
  28. Env_Var_Not_Found,
  29. }
  30. Errno :: Error // alias for legacy use
  31. Error :: union #shared_nil {
  32. General_Error,
  33. io.Error,
  34. runtime.Allocator_Error,
  35. Platform_Error,
  36. }
  37. #assert(size_of(Error) == 8)
  38. ERROR_NONE :: Error{}
  39. ERROR_EOF :: io.Error.EOF
  40. @(require_results)
  41. is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) {
  42. v := ferr.(Platform_Error) or_else {}
  43. return i32(v), i32(v) != 0
  44. }
  45. @(require_results)
  46. error_string :: proc "contextless" (ferr: Error) -> string {
  47. if ferr == nil {
  48. return ""
  49. }
  50. switch e in ferr {
  51. case General_Error:
  52. switch e {
  53. case .None: return ""
  54. case .Permission_Denied: return "permission denied"
  55. case .Exist: return "file already exists"
  56. case .Not_Exist: return "file does not exist"
  57. case .Closed: return "file already closed"
  58. case .Timeout: return "i/o timeout"
  59. case .Broken_Pipe: return "Broken pipe"
  60. case .No_Size: return "file has no definite size"
  61. case .Invalid_File: return "invalid file"
  62. case .Invalid_Dir: return "invalid directory"
  63. case .Invalid_Path: return "invalid path"
  64. case .Invalid_Callback: return "invalid callback"
  65. case .Unsupported: return "unsupported"
  66. case .Pattern_Has_Separator: return "pattern has separator"
  67. case .File_Is_Pipe: return "file is pipe"
  68. case .Not_Dir: return "file is not directory"
  69. case .Env_Var_Not_Found: return "environment variable not found"
  70. }
  71. case io.Error:
  72. switch e {
  73. case .None: return ""
  74. case .EOF: return "eof"
  75. case .Unexpected_EOF: return "unexpected eof"
  76. case .Short_Write: return "short write"
  77. case .Invalid_Write: return "invalid write result"
  78. case .Short_Buffer: return "short buffer"
  79. case .No_Progress: return "multiple read calls return no data or error"
  80. case .Invalid_Whence: return "invalid whence"
  81. case .Invalid_Offset: return "invalid offset"
  82. case .Invalid_Unread: return "invalid unread"
  83. case .Negative_Read: return "negative read"
  84. case .Negative_Write: return "negative write"
  85. case .Negative_Count: return "negative count"
  86. case .Buffer_Full: return "buffer full"
  87. case .Unknown, .Empty: //
  88. }
  89. case runtime.Allocator_Error:
  90. switch e {
  91. case .None: return ""
  92. case .Out_Of_Memory: return "out of memory"
  93. case .Invalid_Pointer: return "invalid allocator pointer"
  94. case .Invalid_Argument: return "invalid allocator argument"
  95. case .Mode_Not_Implemented: return "allocator mode not implemented"
  96. }
  97. case Platform_Error:
  98. return _error_string(e)
  99. }
  100. return "unknown error"
  101. }
  102. print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) {
  103. err_str := error_string(ferr)
  104. // msg + ": " + err_str + '\n'
  105. length := len(msg) + 2 + len(err_str) + 1
  106. buf_ := intrinsics.alloca(length, 1)
  107. buf := buf_[:length]
  108. copy(buf, msg)
  109. buf[len(msg)] = ':'
  110. buf[len(msg) + 1] = ' '
  111. copy(buf[len(msg) + 2:], err_str)
  112. buf[length - 1] = '\n'
  113. return write(f, buf)
  114. }
  115. @(require_results, private)
  116. _error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) {
  117. if e == nil {
  118. return ""
  119. }
  120. when ODIN_OS == .Darwin {
  121. if s := string(_darwin_string_error(i32(e))); s != "" {
  122. return s
  123. }
  124. }
  125. when ODIN_OS != .Linux {
  126. @(require_results)
  127. binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check {
  128. n := len(array)
  129. left, right := 0, n
  130. for left < right {
  131. mid := int(uint(left+right) >> 1)
  132. if array[mid] < key {
  133. left = mid+1
  134. } else {
  135. // equal or greater
  136. right = mid
  137. }
  138. }
  139. return left, left < n && array[left] == key
  140. }
  141. err := runtime.Type_Info_Enum_Value(e)
  142. ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum)
  143. if idx, ok := binary_search(ti.values, err); ok {
  144. return ti.names[idx]
  145. }
  146. } else {
  147. @(rodata, static)
  148. pe_strings := [Platform_Error]string{
  149. .NONE = "",
  150. .EPERM = "Operation not permitted",
  151. .ENOENT = "No such file or directory",
  152. .ESRCH = "No such process",
  153. .EINTR = "Interrupted system call",
  154. .EIO = "Input/output error",
  155. .ENXIO = "No such device or address",
  156. .E2BIG = "Argument list too long",
  157. .ENOEXEC = "Exec format error",
  158. .EBADF = "Bad file descriptor",
  159. .ECHILD = "No child processes",
  160. .EAGAIN = "Resource temporarily unavailable",
  161. .ENOMEM = "Cannot allocate memory",
  162. .EACCES = "Permission denied",
  163. .EFAULT = "Bad address",
  164. .ENOTBLK = "Block device required",
  165. .EBUSY = "Device or resource busy",
  166. .EEXIST = "File exists",
  167. .EXDEV = "Invalid cross-device link",
  168. .ENODEV = "No such device",
  169. .ENOTDIR = "Not a directory",
  170. .EISDIR = "Is a directory",
  171. .EINVAL = "Invalid argument",
  172. .ENFILE = "Too many open files in system",
  173. .EMFILE = "Too many open files",
  174. .ENOTTY = "Inappropriate ioctl for device",
  175. .ETXTBSY = "Text file busy",
  176. .EFBIG = "File too large",
  177. .ENOSPC = "No space left on device",
  178. .ESPIPE = "Illegal seek",
  179. .EROFS = "Read-only file system",
  180. .EMLINK = "Too many links",
  181. .EPIPE = "Broken pipe",
  182. .EDOM = "Numerical argument out of domain",
  183. .ERANGE = "Numerical result out of range",
  184. .EDEADLK = "Resource deadlock avoided",
  185. .ENAMETOOLONG = "File name too long",
  186. .ENOLCK = "No locks available",
  187. .ENOSYS = "Function not implemented",
  188. .ENOTEMPTY = "Directory not empty",
  189. .ELOOP = "Too many levels of symbolic links",
  190. .EUNKNOWN_41 = "Unknown Error (41)",
  191. .ENOMSG = "No message of desired type",
  192. .EIDRM = "Identifier removed",
  193. .ECHRNG = "Channel number out of range",
  194. .EL2NSYNC = "Level 2 not synchronized",
  195. .EL3HLT = "Level 3 halted",
  196. .EL3RST = "Level 3 reset",
  197. .ELNRNG = "Link number out of range",
  198. .EUNATCH = "Protocol driver not attached",
  199. .ENOCSI = "No CSI structure available",
  200. .EL2HLT = "Level 2 halted",
  201. .EBADE = "Invalid exchange",
  202. .EBADR = "Invalid request descriptor",
  203. .EXFULL = "Exchange full",
  204. .ENOANO = "No anode",
  205. .EBADRQC = "Invalid request code",
  206. .EBADSLT = "Invalid slot",
  207. .EUNKNOWN_58 = "Unknown Error (58)",
  208. .EBFONT = "Bad font file format",
  209. .ENOSTR = "Device not a stream",
  210. .ENODATA = "No data available",
  211. .ETIME = "Timer expired",
  212. .ENOSR = "Out of streams resources",
  213. .ENONET = "Machine is not on the network",
  214. .ENOPKG = "Package not installed",
  215. .EREMOTE = "Object is remote",
  216. .ENOLINK = "Link has been severed",
  217. .EADV = "Advertise error",
  218. .ESRMNT = "Srmount error",
  219. .ECOMM = "Communication error on send",
  220. .EPROTO = "Protocol error",
  221. .EMULTIHOP = "Multihop attempted",
  222. .EDOTDOT = "RFS specific error",
  223. .EBADMSG = "Bad message",
  224. .EOVERFLOW = "Value too large for defined data type",
  225. .ENOTUNIQ = "Name not unique on network",
  226. .EBADFD = "File descriptor in bad state",
  227. .EREMCHG = "Remote address changed",
  228. .ELIBACC = "Can not access a needed shared library",
  229. .ELIBBAD = "Accessing a corrupted shared library",
  230. .ELIBSCN = ".lib section in a.out corrupted",
  231. .ELIBMAX = "Attempting to link in too many shared libraries",
  232. .ELIBEXEC = "Cannot exec a shared library directly",
  233. .EILSEQ = "Invalid or incomplete multibyte or wide character",
  234. .ERESTART = "Interrupted system call should be restarted",
  235. .ESTRPIPE = "Streams pipe error",
  236. .EUSERS = "Too many users",
  237. .ENOTSOCK = "Socket operation on non-socket",
  238. .EDESTADDRREQ = "Destination address required",
  239. .EMSGSIZE = "Message too long",
  240. .EPROTOTYPE = "Protocol wrong type for socket",
  241. .ENOPROTOOPT = "Protocol not available",
  242. .EPROTONOSUPPORT = "Protocol not supported",
  243. .ESOCKTNOSUPPORT = "Socket type not supported",
  244. .EOPNOTSUPP = "Operation not supported",
  245. .EPFNOSUPPORT = "Protocol family not supported",
  246. .EAFNOSUPPORT = "Address family not supported by protocol",
  247. .EADDRINUSE = "Address already in use",
  248. .EADDRNOTAVAIL = "Cannot assign requested address",
  249. .ENETDOWN = "Network is down",
  250. .ENETUNREACH = "Network is unreachable",
  251. .ENETRESET = "Network dropped connection on reset",
  252. .ECONNABORTED = "Software caused connection abort",
  253. .ECONNRESET = "Connection reset by peer",
  254. .ENOBUFS = "No buffer space available",
  255. .EISCONN = "Transport endpoint is already connected",
  256. .ENOTCONN = "Transport endpoint is not connected",
  257. .ESHUTDOWN = "Cannot send after transport endpoint shutdown",
  258. .ETOOMANYREFS = "Too many references: cannot splice",
  259. .ETIMEDOUT = "Connection timed out",
  260. .ECONNREFUSED = "Connection refused",
  261. .EHOSTDOWN = "Host is down",
  262. .EHOSTUNREACH = "No route to host",
  263. .EALREADY = "Operation already in progress",
  264. .EINPROGRESS = "Operation now in progress",
  265. .ESTALE = "Stale file handle",
  266. .EUCLEAN = "Structure needs cleaning",
  267. .ENOTNAM = "Not a XENIX named type file",
  268. .ENAVAIL = "No XENIX semaphores available",
  269. .EISNAM = "Is a named type file",
  270. .EREMOTEIO = "Remote I/O error",
  271. .EDQUOT = "Disk quota exceeded",
  272. .ENOMEDIUM = "No medium found",
  273. .EMEDIUMTYPE = "Wrong medium type",
  274. .ECANCELED = "Operation canceled",
  275. .ENOKEY = "Required key not available",
  276. .EKEYEXPIRED = "Key has expired",
  277. .EKEYREVOKED = "Key has been revoked",
  278. .EKEYREJECTED = "Key was rejected by service",
  279. .EOWNERDEAD = "Owner died",
  280. .ENOTRECOVERABLE = "State not recoverable",
  281. .ERFKILL = "Operation not possible due to RF-kill",
  282. .EHWPOISON = "Memory page has hardware error",
  283. }
  284. if Platform_Error.NONE <= e && e <= max(Platform_Error) {
  285. return pe_strings[e]
  286. }
  287. }
  288. return "<unknown platform error>"
  289. }
  290. @(private, require_results)
  291. error_to_io_error :: proc(ferr: Error) -> io.Error {
  292. if ferr == nil {
  293. return .None
  294. }
  295. return ferr.(io.Error) or_else .Unknown
  296. }