oserrors.nim 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 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. var e: owned(ref OSError); new(e)
  70. e.errorCode = errorCode.int32
  71. e.msg = osErrorMsg(errorCode)
  72. if additionalInfo.len > 0:
  73. if e.msg.len > 0 and e.msg[^1] != '\n': e.msg.add '\n'
  74. e.msg.add "Additional info: "
  75. e.msg.add additionalInfo
  76. # don't add trailing `.` etc, which negatively impacts "jump to file" in IDEs.
  77. if e.msg == "":
  78. e.msg = "unknown OS error"
  79. return e
  80. proc raiseOSError*(errorCode: OSErrorCode, additionalInfo = "") {.noinline.} =
  81. ## Raises an `OSError exception <system.html#OSError>`_.
  82. ##
  83. ## Read the description of the `newOSError proc`_ to learn
  84. ## how the exception object is created.
  85. raise newOSError(errorCode, additionalInfo)
  86. {.push stackTrace:off.}
  87. proc osLastError*(): OSErrorCode {.sideEffect.} =
  88. ## Retrieves the last operating system error code.
  89. ##
  90. ## This procedure is useful in the event when an OS call fails. In that case
  91. ## this procedure will return the error code describing the reason why the
  92. ## OS call failed. The `OSErrorMsg` procedure can then be used to convert
  93. ## this code into a string.
  94. ##
  95. ## .. warning:: The behaviour of this procedure varies between Windows and POSIX systems.
  96. ## On Windows some OS calls can reset the error code to `0` causing this
  97. ## procedure to return `0`. It is therefore advised to call this procedure
  98. ## immediately after an OS call fails. On POSIX systems this is not a problem.
  99. ##
  100. ## See also:
  101. ## * `osErrorMsg proc`_
  102. ## * `raiseOSError proc`_
  103. when defined(nimscript):
  104. discard
  105. elif defined(windows):
  106. result = cast[OSErrorCode](getLastError())
  107. else:
  108. result = OSErrorCode(errno)
  109. {.pop.}