oserrors.nim 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2022 Nim contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## The `std/oserrors` module implements OS error reporting.
  10. type
  11. OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
  12. when not defined(nimscript):
  13. when defined(windows):
  14. import std/winlean
  15. when defined(nimPreviewSlimSystem):
  16. import std/widestrs
  17. else:
  18. var errno {.importc, header: "<errno.h>".}: cint
  19. proc c_strerror(errnum: cint): cstring {.
  20. importc: "strerror", header: "<string.h>".}
  21. proc `==`*(err1, err2: OSErrorCode): bool {.borrow.}
  22. proc `$`*(err: OSErrorCode): string {.borrow.}
  23. proc osErrorMsg*(errorCode: OSErrorCode): string =
  24. ## Converts an OS error code into a human readable string.
  25. ##
  26. ## The error code can be retrieved using the `osLastError proc`_.
  27. ##
  28. ## If conversion fails, or `errorCode` is `0` then `""` will be
  29. ## returned.
  30. ##
  31. ## See also:
  32. ## * `raiseOSError proc`_
  33. ## * `osLastError proc`_
  34. runnableExamples:
  35. when defined(linux):
  36. assert osErrorMsg(OSErrorCode(0)) == ""
  37. assert osErrorMsg(OSErrorCode(1)) == "Operation not permitted"
  38. assert osErrorMsg(OSErrorCode(2)) == "No such file or directory"
  39. result = ""
  40. when defined(nimscript):
  41. discard
  42. elif defined(windows):
  43. if errorCode != OSErrorCode(0'i32):
  44. var msgbuf: WideCString
  45. if formatMessageW(0x00000100 or 0x00001000 or 0x00000200,
  46. nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
  47. result = $msgbuf
  48. if msgbuf != nil: localFree(cast[pointer](msgbuf))
  49. else:
  50. if errorCode != OSErrorCode(0'i32):
  51. result = $c_strerror(errorCode.int32)
  52. proc newOSError*(
  53. errorCode: OSErrorCode, additionalInfo = ""
  54. ): owned(ref OSError) {.noinline.} =
  55. ## Creates a new `OSError exception <system.html#OSError>`_.
  56. ##
  57. ## The `errorCode` will determine the
  58. ## message, `osErrorMsg proc`_ will be used
  59. ## to get this message.
  60. ##
  61. ## The error code can be retrieved using the `osLastError proc`_.
  62. ##
  63. ## If the error code is `0` or an error message could not be retrieved,
  64. ## the message `unknown OS error` will be used.
  65. ##
  66. ## See also:
  67. ## * `osErrorMsg proc`_
  68. ## * `osLastError proc`_
  69. result = (ref OSError)(errorCode: errorCode.int32, msg: osErrorMsg(errorCode))
  70. if additionalInfo.len > 0:
  71. if result.msg.len > 0 and result.msg[^1] != '\n': result.msg.add '\n'
  72. result.msg.add "Additional info: "
  73. result.msg.add additionalInfo
  74. # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs.
  75. if result.msg == "":
  76. result.msg = "unknown OS error"
  77. proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} =
  78. ## Raises an `OSError exception <system.html#OSError>`_.
  79. ##
  80. ## Read the description of the `newOSError proc`_ to learn
  81. ## how the exception object is created.
  82. raise newOSError(errorCode, additionalInfo)
  83. {.push stackTrace:off.}
  84. proc osLastError*(): OSErrorCode {.sideEffect.} =
  85. ## Retrieves the last operating system error code.
  86. ##
  87. ## This procedure is useful in the event when an OS call fails. In that case
  88. ## this procedure will return the error code describing the reason why the
  89. ## OS call failed. The `OSErrorMsg` procedure can then be used to convert
  90. ## this code into a string.
  91. ##
  92. ## .. warning:: The behaviour of this procedure varies between Windows and POSIX systems.
  93. ## On Windows some OS calls can reset the error code to `0` causing this
  94. ## procedure to return `0`. It is therefore advised to call this procedure
  95. ## immediately after an OS call fails. On POSIX systems this is not a problem.
  96. ##
  97. ## See also:
  98. ## * `osErrorMsg proc`_
  99. ## * `raiseOSError proc`_
  100. when defined(nimscript):
  101. discard
  102. elif defined(windows):
  103. result = cast[OSErrorCode](getLastError())
  104. else:
  105. result = OSErrorCode(errno)
  106. {.pop.}