File: CError.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (98 lines) | stat: -rw-r--r-- 3,360 bytes parent folder | download
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