1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//
internal import _TestingInternals
/// A type representing an error from a C function such as `fopen()`.
///
/// This type is necessary because Foundation's `POSIXError` is not available in
/// all contexts.
///
/// This type is not part of the public interface of the testing library.
struct CError: Error, RawRepresentable {
var rawValue: CInt
}
#if os(Windows)
/// A type representing a Windows error from a Win32 API function.
///
/// Values of this type are in the domain described by Microsoft
/// [here](https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes).
///
/// This type is not part of the public interface of the testing library.
struct Win32Error: Error, RawRepresentable {
var rawValue: DWORD
}
#endif
// MARK: - CustomStringConvertible
/// Get a string describing a C error code.
///
/// - Parameters:
/// - errorCode: The error code to describe.
///
/// - Returns: A Swift string equal to the result of `strerror()` from the C
/// standard library.
func strerror(_ errorCode: CInt) -> String {
#if os(Windows)
String(unsafeUninitializedCapacity: 1024) { buffer in
_ = strerror_s(buffer.baseAddress!, buffer.count, errorCode)
return strnlen(buffer.baseAddress!, buffer.count)
}
#else
String(cString: _TestingInternals.strerror(errorCode))
#endif
}
extension CError: CustomStringConvertible {
var description: String {
strerror(rawValue)
}
}
#if os(Windows)
extension Win32Error: CustomStringConvertible {
var description: String {
let (address, count) = withUnsafeTemporaryAllocation(of: LPWSTR?.self, capacity: 1) { buffer in
// FormatMessageW() takes a wide-character buffer into which it writes the
// error message... _unless_ you pass `FORMAT_MESSAGE_ALLOCATE_BUFFER` in
// which case it takes a pointer-to-pointer that it populates with a
// heap-allocated string. However, the signature for FormatMessageW()
// still takes an LPWSTR? (Optional<UnsafeMutablePointer<wchar_t>>), so we
// need to temporarily mis-cast the pointer before we can pass it in.
let count = buffer.withMemoryRebound(to: wchar_t.self) { buffer in
FormatMessageW(
DWORD(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK),
nil,
rawValue,
DWORD(swt_MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)),
buffer.baseAddress,
0,
nil
)
}
return (buffer.moveElement(from: buffer.startIndex), count)
}
defer {
LocalFree(address)
}
if count > 0, let address, var result = String.decodeCString(address, as: UTF16.self)?.result {
// Some of the strings produced by FormatMessageW() have trailing
// whitespace we will want to remove.
while let lastCharacter = result.last, lastCharacter.isWhitespace {
result.removeLast()
}
return result
}
return "An unknown error occurred (\(rawValue))."
}
}
#endif
|