errors.odin 11 KB

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