forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIO.swift
243 lines (222 loc) · 6.21 KB
/
IO.swift
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Swift
import SwiftShims
#if os(Windows)
import CRT
import WinSDK
#else
#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(WASILibc)
import WASILibc
#endif
let (platform_read, platform_write, platform_close) = (read, write, close)
#endif
#if os(Windows)
public struct _FDInputStream {
public var handle: HANDLE = INVALID_HANDLE_VALUE
public var isEOF: Bool = false
public var isClosed: Bool { return handle == INVALID_HANDLE_VALUE }
internal var _buffer: ContiguousArray<UInt8> =
ContiguousArray<UInt8>(repeating: 0, count: 256)
internal var _offset: Int = 0
public init(handle: HANDLE) {
self.handle = handle
}
public mutating func getline() -> String? {
// FIXME(compnerd) Windows uses \r\n for the line delimiter, we should split
// on that and remove the workaround in the test harness
if let index =
_buffer[0..<_offset].firstIndex(of: UInt8(Unicode.Scalar("\n").value)) {
let result = String(decoding: _buffer[0..<index], as: UTF8.self)
_buffer.removeSubrange(0...index)
_offset -= index + 1
return result
}
if isEOF && _offset > 0 {
let result = String(decoding: _buffer[0..<_offset], as: UTF8.self)
_buffer.removeAll()
_offset = 0
return result
}
return nil
}
public mutating func read() {
var space = _buffer.count - _offset
if space < 128 {
let capacity = _buffer.count + (128 - space)
_buffer.reserveCapacity(capacity)
for _ in _buffer.count..<capacity {
_buffer.append(0)
}
space = 128
}
let read: Int = _buffer.withUnsafeMutableBufferPointer { buffer in
var read: DWORD = 0
ReadFile(handle, buffer.baseAddress! + _offset, DWORD(space), &read, nil)
return Int(read)
}
if read == 0 {
isEOF = true
} else {
_offset += read
}
}
public mutating func close() {
if isClosed { return }
CloseHandle(handle)
handle = INVALID_HANDLE_VALUE
}
}
#else
public struct _FDInputStream {
public let fd: CInt
public var isClosed: Bool = false
public var isEOF: Bool = false
internal var _buffer = [UInt8](repeating: 0, count: 256)
internal var _bufferUsed: Int = 0
public init(fd: CInt) {
self.fd = fd
}
public mutating func getline() -> String? {
if let newlineIndex =
_buffer[0..<_bufferUsed].firstIndex(of: UInt8(Unicode.Scalar("\n").value)) {
let result = String(decoding: _buffer[0..<newlineIndex], as: UTF8.self)
_buffer.removeSubrange(0...newlineIndex)
_bufferUsed -= newlineIndex + 1
return result
}
if isEOF && _bufferUsed > 0 {
let result = String(decoding: _buffer[0..<_bufferUsed], as: UTF8.self)
_buffer.removeAll()
_bufferUsed = 0
return result
}
return nil
}
public mutating func read() {
let minFree = 128
var bufferFree = _buffer.count - _bufferUsed
if bufferFree < minFree {
_buffer.reserveCapacity(minFree - bufferFree)
while bufferFree < minFree {
_buffer.append(0)
bufferFree += 1
}
}
let fd = self.fd
let readResult: Int = _buffer.withUnsafeMutableBufferPointer {
(_buffer) in
let addr = _buffer.baseAddress! + self._bufferUsed
let size = bufferFree
return platform_read(fd, addr, size)
}
if readResult == 0 {
isEOF = true
return
}
if readResult < 0 {
fatalError("read() returned error")
}
_bufferUsed += readResult
}
public mutating func close() {
if isClosed {
return
}
let result = platform_close(fd)
if result < 0 {
fatalError("close() returned an error")
}
isClosed = true
}
}
#endif
public struct _Stderr : TextOutputStream {
public init() {}
public mutating func write(_ string: String) {
for c in string.utf8 {
_swift_stdlib_putc_stderr(CInt(c))
}
}
}
#if os(Windows)
public struct _FDOutputStream : TextOutputStream {
public var handle: HANDLE
public var isClosed: Bool {
return handle == INVALID_HANDLE_VALUE
}
public init(handle: HANDLE) {
self.handle = handle
}
public mutating func write(_ string: String) {
string.utf8CString.withUnsafeBufferPointer { buffer in
let dwLength: DWORD = DWORD(buffer.count - 1)
var dwOffset: DWORD = 0
while dwOffset < dwLength {
var dwBytesWritten: DWORD = 0
if !WriteFile(handle,
UnsafeRawPointer(buffer.baseAddress! + Int(dwOffset)),
dwLength - dwOffset, &dwBytesWritten, nil) {
fatalError("WriteFile() failed")
}
dwOffset += dwBytesWritten
}
}
}
public mutating func close() {
if handle == INVALID_HANDLE_VALUE { return }
CloseHandle(handle)
handle = INVALID_HANDLE_VALUE
}
}
#else
public struct _FDOutputStream : TextOutputStream {
public let fd: CInt
public var isClosed: Bool = false
public init(fd: CInt) {
self.fd = fd
}
public mutating func write(_ string: String) {
let utf8CStr = string.utf8CString
utf8CStr.withUnsafeBufferPointer {
(utf8CStr) -> Void in
var writtenBytes = 0
let bufferSize = utf8CStr.count - 1
while writtenBytes != bufferSize {
let result = platform_write(
self.fd, UnsafeRawPointer(utf8CStr.baseAddress! + Int(writtenBytes)),
bufferSize - writtenBytes)
if result < 0 {
fatalError("write() returned an error")
}
writtenBytes += result
}
}
}
public mutating func close() {
if isClosed {
return
}
let result = platform_close(fd)
if result < 0 {
fatalError("close() returned an error")
}
isClosed = true
}
}
#endif