-
Notifications
You must be signed in to change notification settings - Fork 8
/
StringIO.swift
136 lines (112 loc) · 3.55 KB
/
StringIO.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
//
// StringIO.swift
// SwiftRuby
//
// Created by John Holdsworth on 28/09/2015.
// Copyright © 2015 John Holdsworth. All rights reserved.
//
// $Id: //depot/SwiftRuby/StringIO.swift#10 $
//
// Repo: https://github.com/RubyNative/SwiftRuby
//
// See: http://ruby-doc.org/stdlib-2.2.3/libdoc/stringio/rdoc/StringIO.html
//
import Darwin
public var LINE_SEPARATOR = "\n"
open class StringIO: IO {
public let data: Data
open var offset = 0
open override var pos: Int {
get {
return offset
}
set {
offset = newValue
}
}
public init(_ string: data_like = "", file: StaticString = #file, line: UInt = #line) {
data = string.to_d
super.init(what: nil, unixFILE: nil)
}
open class func new(_ string: data_like, _ mode: string_like = "r", _ perm: Int? = nil, file: StaticString = #file, line: UInt = #line) -> StringIO {
return StringIO(string, file: file, line: line)
}
open class func open(_ string: data_like, _ mode: string_like = "r", _ perm: Int? = nil, file: StaticString = #file, line: UInt = #line) -> StringIO {
return new(string, mode, perm, file: file, line: line)
}
open override func each_byte(_ block: (CChar) -> ()) -> IO {
while !eof {
block(data.bytes[offset])
offset += 1
}
return self
}
open override var eof: Bool {
return offset >= data.length
}
open override var getc: String? {
let ret: String? = !eof ? String(data.bytes[offset]) : nil
offset += 1
return ret
}
override func gets(_ sep: string_like = LINE_SEPARATOR) -> String? {
if eof {
return nil
}
let sepchar = sep.to_s.ord
let endOfLine = memchr(data.bytes+offset, Int32(sepchar), Int(data.length-offset))?.assumingMemoryBound(to: Int8.self)
if endOfLine != nil {
endOfLine!.pointee = 0
}
let out = String(validatingUTF8: data.bytes+offset)
if endOfLine != nil {
endOfLine!.pointee = Int8(sepchar)
offset = endOfLine! - data.bytes + 1
}
else {
offset = data.length
}
return out
}
open override func print(_ string: string_like) -> Int {
return write(string.to_s)
}
override func putc(_ obj: Int) -> Int {
if data.capacity < data.length + 1 {
data.capacity += 10_000 ////
}
data.bytes[data.length] = Int8(obj)
data.length += 1
return 1
}
open override func read(_ length: Int?, _ outbuf: Data?) -> Data? {
return data
}
@discardableResult
open override func rewind(_ file: StaticString = #file, line: UInt = #line) -> IO {
_ = seek(0, Int(SEEK_SET))
return self
}
@discardableResult
open override func seek(_ amount: Int, _ whence: Int, file: StaticString = #file, line: UInt = #line) -> Bool {
switch Int32(whence) {
case SEEK_SET:
offset = amount
case SEEK_CUR:
offset += amount
case SEEK_END:
offset = data.length + amount
default:
return false
}
if offset < 0 || offset > data.length {
SRLog("Invalid StringIO.seek \(amount), \(whence) -> \(offset) outside 0-\(data.length)", file: file, line: line)
return false
}
return true
}
@discardableResult
open override func write(_ string: data_like) -> fixnum {
return data.append(string)
}
}