Skip to content

Commit c9e2e8c

Browse files
authored
Merge pull request swiftlang#21495 from compnerd/swift-private-io
stdlib: implement _FDStreams in terms of HANDLES
2 parents a7b3fcd + 7ecaeb1 commit c9e2e8c

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

stdlib/private/SwiftPrivate/IO.swift

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,73 @@
1313
import Swift
1414
import SwiftShims
1515

16+
#if os(Windows)
17+
import MSVCRT
18+
import WinSDK
19+
#endif
20+
21+
#if os(Windows)
22+
public struct _FDInputStream {
23+
public var handle: HANDLE = INVALID_HANDLE_VALUE
24+
public var isEOF: Bool = false
25+
public var isClosed: Bool { return handle == INVALID_HANDLE_VALUE }
26+
27+
internal var _buffer: ContiguousArray<UInt8> =
28+
ContiguousArray<UInt8>(repeating: 0, count: 256)
29+
internal var _offset: Int = 0
30+
31+
public init(handle: HANDLE) {
32+
self.handle = handle
33+
}
34+
35+
public mutating func getline() -> String? {
36+
// FIXME(compnerd) Windows uses \r\n for the line delimiter, we should split
37+
// on that and remove the workaround in the test harness
38+
if let index =
39+
_buffer[0..<_offset].firstIndex(of: UInt8(Unicode.Scalar("\n").value)) {
40+
let result = String(decoding: _buffer[0..<index], as: UTF8.self)
41+
_buffer.removeSubrange(0...index)
42+
_offset -= index + 1
43+
return result
44+
}
45+
if isEOF && _offset > 0 {
46+
let result = String(decoding: _buffer[0..<_offset], as: UTF8.self)
47+
_buffer.removeAll()
48+
_offset = 0
49+
return result
50+
}
51+
return nil
52+
}
53+
54+
public mutating func read() {
55+
var space = _buffer.count - _offset
56+
if space < 128 {
57+
let capacity = _buffer.count + (128 - space)
58+
_buffer.reserveCapacity(capacity)
59+
for _ in _buffer.count..<capacity {
60+
_buffer.append(0)
61+
}
62+
space = 128
63+
}
64+
let read: Int = _buffer.withUnsafeMutableBufferPointer { buffer in
65+
var read: DWORD = 0
66+
ReadFile(handle, buffer.baseAddress! + _offset, DWORD(space), &read, nil)
67+
return Int(read)
68+
}
69+
if read == 0 {
70+
isEOF = true
71+
} else {
72+
_offset += read
73+
}
74+
}
75+
76+
public mutating func close() {
77+
if isClosed { return }
78+
CloseHandle(handle)
79+
handle = INVALID_HANDLE_VALUE
80+
}
81+
}
82+
#else
1683
public struct _FDInputStream {
1784
public let fd: CInt
1885
public var isClosed: Bool = false
@@ -79,6 +146,7 @@ public struct _FDInputStream {
79146
isClosed = true
80147
}
81148
}
149+
#endif
82150

83151
public struct _Stderr : TextOutputStream {
84152
public init() {}
@@ -90,6 +158,37 @@ public struct _Stderr : TextOutputStream {
90158
}
91159
}
92160

161+
#if os(Windows)
162+
public struct _FDOutputStream : TextOutputStream {
163+
public var handle: HANDLE
164+
165+
public init(handle: HANDLE) {
166+
self.handle = handle
167+
}
168+
169+
public mutating func write(_ string: String) {
170+
string.utf8CString.withUnsafeBufferPointer { buffer in
171+
let dwLength: DWORD = DWORD(buffer.count - 1)
172+
var dwOffset: DWORD = 0
173+
while dwOffset < dwLength {
174+
var dwBytesWritten: DWORD = 0
175+
if WriteFile(handle,
176+
UnsafeRawPointer(buffer.baseAddress! + Int(dwOffset)),
177+
dwLength - dwOffset, &dwBytesWritten, nil) == FALSE {
178+
fatalError("WriteFile() failed")
179+
}
180+
dwOffset += dwBytesWritten
181+
}
182+
}
183+
}
184+
185+
public mutating func close() {
186+
if handle == INVALID_HANDLE_VALUE { return }
187+
CloseHandle(handle)
188+
handle = INVALID_HANDLE_VALUE
189+
}
190+
}
191+
#else
93192
public struct _FDOutputStream : TextOutputStream {
94193
public let fd: CInt
95194
public var isClosed: Bool = false
@@ -127,3 +226,4 @@ public struct _FDOutputStream : TextOutputStream {
127226
isClosed = true
128227
}
129228
}
229+
#endif

0 commit comments

Comments
 (0)