oserr.nim 4.2 KB

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