oserr.nim 4.4 KB

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