Line | Exclusive | Inclusive | Code |
---|---|---|---|
1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
2 | |||
3 | # Generic IO stubs -- all subtypes should implement these (if meaningful) | ||
4 | |||
5 | """ | ||
6 | EOFError() | ||
7 | |||
8 | No more data was available to read from a file or stream. | ||
9 | """ | ||
10 | struct EOFError <: Exception end | ||
11 | |||
12 | """ | ||
13 | SystemError(prefix::AbstractString, [errno::Int32]) | ||
14 | |||
15 | A system call failed with an error code (in the `errno` global variable). | ||
16 | """ | ||
17 | struct SystemError <: Exception | ||
18 | prefix::AbstractString | ||
19 | errnum::Int32 | ||
20 | extrainfo | ||
21 | SystemError(p::AbstractString, e::Integer, extrainfo) = new(p, e, extrainfo) | ||
22 | SystemError(p::AbstractString, e::Integer) = new(p, e, nothing) | ||
23 | SystemError(p::AbstractString) = new(p, Libc.errno()) | ||
24 | end | ||
25 | |||
26 | lock(::IO) = nothing | ||
27 | unlock(::IO) = nothing | ||
28 | reseteof(x::IO) = nothing | ||
29 | |||
30 | const SZ_UNBUFFERED_IO = 65536 | ||
31 | buffer_writes(x::IO, bufsize=SZ_UNBUFFERED_IO) = x | ||
32 | |||
33 | """ | ||
34 | isopen(object) -> Bool | ||
35 | |||
36 | Determine whether an object - such as a stream or timer | ||
37 | -- is not yet closed. Once an object is closed, it will never produce a new event. | ||
38 | However, since a closed stream may still have data to read in its buffer, | ||
39 | use [`eof`](@ref) to check for the ability to read data. | ||
40 | Use the `FileWatching` package to be notified when a stream might be writable or readable. | ||
41 | |||
42 | # Examples | ||
43 | ```jldoctest | ||
44 | julia> io = open("my_file.txt", "w+"); | ||
45 | |||
46 | julia> isopen(io) | ||
47 | true | ||
48 | |||
49 | julia> close(io) | ||
50 | |||
51 | julia> isopen(io) | ||
52 | false | ||
53 | ``` | ||
54 | """ | ||
55 | function isopen end | ||
56 | |||
57 | """ | ||
58 | close(stream) | ||
59 | |||
60 | Close an I/O stream. Performs a [`flush`](@ref) first. | ||
61 | """ | ||
62 | function close end | ||
63 | function flush end | ||
64 | function wait_connected end | ||
65 | function wait_readnb end | ||
66 | function wait_readbyte end | ||
67 | function wait_close end | ||
68 | function bytesavailable end | ||
69 | |||
70 | """ | ||
71 | readavailable(stream) | ||
72 | |||
73 | Read all available data on the stream, blocking the task only if no data is available. The | ||
74 | result is a `Vector{UInt8,1}`. | ||
75 | """ | ||
76 | function readavailable end | ||
77 | |||
78 | """ | ||
79 | isreadable(io) -> Bool | ||
80 | |||
81 | Return `true` if the specified IO object is readable (if that can be determined). | ||
82 | |||
83 | # Examples | ||
84 | ```jldoctest | ||
85 | julia> open("myfile.txt", "w") do io | ||
86 | print(io, "Hello world!"); | ||
87 | isreadable(io) | ||
88 | end | ||
89 | false | ||
90 | |||
91 | julia> open("myfile.txt", "r") do io | ||
92 | isreadable(io) | ||
93 | end | ||
94 | true | ||
95 | |||
96 | julia> rm("myfile.txt") | ||
97 | ``` | ||
98 | """ | ||
99 | function isreadable end | ||
100 | |||
101 | """ | ||
102 | iswritable(io) -> Bool | ||
103 | |||
104 | Return `true` if the specified IO object is writable (if that can be determined). | ||
105 | |||
106 | # Examples | ||
107 | ```jldoctest | ||
108 | julia> open("myfile.txt", "w") do io | ||
109 | print(io, "Hello world!"); | ||
110 | iswritable(io) | ||
111 | end | ||
112 | true | ||
113 | |||
114 | julia> open("myfile.txt", "r") do io | ||
115 | iswritable(io) | ||
116 | end | ||
117 | false | ||
118 | |||
119 | julia> rm("myfile.txt") | ||
120 | ``` | ||
121 | """ | ||
122 | function iswritable end | ||
123 | function copy end | ||
124 | function eof end | ||
125 | |||
126 | """ | ||
127 | read(io::IO, T) | ||
128 | |||
129 | Read a single value of type `T` from `io`, in canonical binary representation. | ||
130 | |||
131 | read(io::IO, String) | ||
132 | |||
133 | Read the entirety of `io`, as a `String`. | ||
134 | |||
135 | # Examples | ||
136 | ```jldoctest | ||
137 | julia> io = IOBuffer("JuliaLang is a GitHub organization"); | ||
138 | |||
139 | julia> read(io, Char) | ||
140 | 'J': ASCII/Unicode U+004a (category Lu: Letter, uppercase) | ||
141 | |||
142 | julia> io = IOBuffer("JuliaLang is a GitHub organization"); | ||
143 | |||
144 | julia> read(io, String) | ||
145 | "JuliaLang is a GitHub organization" | ||
146 | ``` | ||
147 | """ | ||
148 | read(stream, t) | ||
149 | |||
150 | """ | ||
151 | write(io::IO, x) | ||
152 | write(filename::AbstractString, x) | ||
153 | |||
154 | Write the canonical binary representation of a value to the given I/O stream or file. | ||
155 | Return the number of bytes written into the stream. See also [`print`](@ref) to | ||
156 | write a text representation (with an encoding that may depend upon `io`). | ||
157 | |||
158 | You can write multiple values with the same `write` call. i.e. the following are equivalent: | ||
159 | |||
160 | write(io, x, y...) | ||
161 | write(io, x) + write(io, y...) | ||
162 | |||
163 | # Examples | ||
164 | ```jldoctest | ||
165 | julia> io = IOBuffer(); | ||
166 | |||
167 | julia> write(io, "JuliaLang is a GitHub organization.", " It has many members.") | ||
168 | 56 | ||
169 | |||
170 | julia> String(take!(io)) | ||
171 | "JuliaLang is a GitHub organization. It has many members." | ||
172 | |||
173 | julia> write(io, "Sometimes those members") + write(io, " write documentation.") | ||
174 | 44 | ||
175 | |||
176 | julia> String(take!(io)) | ||
177 | "Sometimes those members write documentation." | ||
178 | ``` | ||
179 | """ | ||
180 | function write end | ||
181 | |||
182 | read(s::IO, ::Type{UInt8}) = error(typeof(s)," does not support byte I/O") | ||
183 | write(s::IO, x::UInt8) = error(typeof(s)," does not support byte I/O") | ||
184 | |||
185 | """ | ||
186 | unsafe_write(io::IO, ref, nbytes::UInt) | ||
187 | |||
188 | Copy `nbytes` from `ref` (converted to a pointer) into the `IO` object. | ||
189 | |||
190 | It is recommended that subtypes `T<:IO` override the following method signature | ||
191 | to provide more efficient implementations: | ||
192 | `unsafe_write(s::T, p::Ptr{UInt8}, n::UInt)` | ||
193 | """ | ||
194 | function unsafe_write(s::IO, p::Ptr{UInt8}, n::UInt) | ||
195 | written::Int = 0 | ||
196 | for i = 1:n | ||
197 | written += write(s, unsafe_load(p, i)) | ||
198 | end | ||
199 | return written | ||
200 | end | ||
201 | |||
202 | """ | ||
203 | unsafe_read(io::IO, ref, nbytes::UInt) | ||
204 | |||
205 | Copy `nbytes` from the `IO` stream object into `ref` (converted to a pointer). | ||
206 | |||
207 | It is recommended that subtypes `T<:IO` override the following method signature | ||
208 | to provide more efficient implementations: | ||
209 | `unsafe_read(s::T, p::Ptr{UInt8}, n::UInt)` | ||
210 | """ | ||
211 | function unsafe_read(s::IO, p::Ptr{UInt8}, n::UInt) | ||
212 | for i = 1:n | ||
213 | unsafe_store!(p, read(s, UInt8)::UInt8, i) | ||
214 | end | ||
215 | nothing | ||
216 | end | ||
217 | |||
218 | |||
219 | # Generic wrappers around other IO objects | ||
220 | abstract type AbstractPipe <: IO end | ||
221 | function pipe_reader end | ||
222 | function pipe_writer end | ||
223 | |||
224 | write(io::AbstractPipe, byte::UInt8) = write(pipe_writer(io), byte) | ||
225 | unsafe_write(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_write(pipe_writer(io), p, nb) | ||
226 | buffer_writes(io::AbstractPipe, args...) = buffer_writes(pipe_writer(io), args...) | ||
227 | flush(io::AbstractPipe) = flush(pipe_writer(io)) | ||
228 | |||
229 | read(io::AbstractPipe, byte::Type{UInt8}) = read(pipe_reader(io), byte) | ||
230 | unsafe_read(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_read(pipe_reader(io), p, nb) | ||
231 | read(io::AbstractPipe) = read(pipe_reader(io)) | ||
232 | readuntil(io::AbstractPipe, arg::UInt8; kw...) = readuntil(pipe_reader(io), arg; kw...) | ||
233 | readuntil(io::AbstractPipe, arg::AbstractChar; kw...) = readuntil(pipe_reader(io), arg; kw...) | ||
234 | readuntil(io::AbstractPipe, arg::AbstractString; kw...) = readuntil(pipe_reader(io), arg; kw...) | ||
235 | readuntil(io::AbstractPipe, arg::AbstractVector; kw...) = readuntil(pipe_reader(io), arg; kw...) | ||
236 | readuntil_vector!(io::AbstractPipe, target::AbstractVector, keep::Bool, out) = readuntil_vector!(pipe_reader(io), target, keep, out) | ||
237 | |||
238 | for f in ( | ||
239 | # peek/mark interface | ||
240 | :peek, :mark, :unmark, :reset, :ismarked, | ||
241 | # Simple reader functions | ||
242 | :readavailable, :isreadable) | ||
243 | @eval $(f)(io::AbstractPipe) = $(f)(pipe_reader(io)) | ||
244 | end | ||
245 | |||
246 | iswritable(io::AbstractPipe) = iswritable(pipe_writer(io)) | ||
247 | isopen(io::AbstractPipe) = isopen(pipe_writer(io)) || isopen(pipe_reader(io)) | ||
248 | close(io::AbstractPipe) = (close(pipe_writer(io)); close(pipe_reader(io))) | ||
249 | wait_readnb(io::AbstractPipe, nb::Int) = wait_readnb(pipe_reader(io), nb) | ||
250 | wait_readbyte(io::AbstractPipe, byte::UInt8) = wait_readbyte(pipe_reader(io), byte) | ||
251 | wait_close(io::AbstractPipe) = (wait_close(pipe_writer(io)); wait_close(pipe_reader(io))) | ||
252 | |||
253 | """ | ||
254 | bytesavailable(io) | ||
255 | |||
256 | Return the number of bytes available for reading before a read from this stream or buffer will block. | ||
257 | |||
258 | # Examples | ||
259 | ```jldoctest | ||
260 | julia> io = IOBuffer("JuliaLang is a GitHub organization"); | ||
261 | |||
262 | julia> bytesavailable(io) | ||
263 | 34 | ||
264 | ``` | ||
265 | """ | ||
266 | bytesavailable(io::AbstractPipe) = bytesavailable(pipe_reader(io)) | ||
267 | |||
268 | """ | ||
269 | eof(stream) -> Bool | ||
270 | |||
271 | Test whether an I/O stream is at end-of-file. If the stream is not yet exhausted, this | ||
272 | function will block to wait for more data if necessary, and then return `false`. Therefore | ||
273 | it is always safe to read one byte after seeing `eof` return `false`. `eof` will return | ||
274 | `false` as long as buffered data is still available, even if the remote end of a connection | ||
275 | is closed. | ||
276 | """ | ||
277 | eof(io::AbstractPipe) = eof(pipe_reader(io)) | ||
278 | reseteof(io::AbstractPipe) = reseteof(pipe_reader(io)) | ||
279 | |||
280 | |||
281 | # Exception-safe wrappers (io = open(); try f(io) finally close(io)) | ||
282 | |||
283 | write(filename::AbstractString, a1, args...) = open(io->write(io, a1, args...), filename, "w") | ||
284 | |||
285 | """ | ||
286 | read(filename::AbstractString, args...) | ||
287 | |||
288 | Open a file and read its contents. `args` is passed to `read`: this is equivalent to | ||
289 | `open(io->read(io, args...), filename)`. | ||
290 | |||
291 | read(filename::AbstractString, String) | ||
292 | |||
293 | Read the entire contents of a file as a string. | ||
294 | """ | ||
295 | read(filename::AbstractString, args...) = open(io->read(io, args...), filename) | ||
296 | |||
297 | read(filename::AbstractString, ::Type{T}) where {T} = open(io->read(io, T), filename) | ||
298 | |||
299 | """ | ||
300 | read!(stream::IO, array::Union{Array, BitArray}) | ||
301 | read!(filename::AbstractString, array::Union{Array, BitArray}) | ||
302 | |||
303 | Read binary data from an I/O stream or file, filling in `array`. | ||
304 | """ | ||
305 | function read! end | ||
306 | |||
307 | read!(filename::AbstractString, a) = open(io->read!(io, a), filename) | ||
308 | |||
309 | """ | ||
310 | readuntil(stream::IO, delim; keep::Bool = false) | ||
311 | readuntil(filename::AbstractString, delim; keep::Bool = false) | ||
312 | |||
313 | Read a string from an I/O stream or a file, up to the given delimiter. | ||
314 | The delimiter can be a `UInt8`, `AbstractChar`, string, or vector. | ||
315 | Keyword argument `keep` controls whether the delimiter is included in the result. | ||
316 | The text is assumed to be encoded in UTF-8. | ||
317 | |||
318 | # Examples | ||
319 | ```jldoctest | ||
320 | julia> open("my_file.txt", "w") do io | ||
321 | write(io, "JuliaLang is a GitHub organization.\\nIt has many members.\\n"); | ||
322 | end | ||
323 | 57 | ||
324 | |||
325 | julia> readuntil("my_file.txt", 'L') | ||
326 | "Julia" | ||
327 | |||
328 | julia> readuntil("my_file.txt", '.', keep = true) | ||
329 | "JuliaLang is a GitHub organization." | ||
330 | |||
331 | julia> rm("my_file.txt") | ||
332 | ``` | ||
333 | """ | ||
334 | readuntil(filename::AbstractString, args...; kw...) = open(io->readuntil(io, args...; kw...), filename) | ||
335 | |||
336 | """ | ||
337 | readline(io::IO=stdin; keep::Bool=false) | ||
338 | readline(filename::AbstractString; keep::Bool=false) | ||
339 | |||
340 | Read a single line of text from the given I/O stream or file (defaults to `stdin`). | ||
341 | When reading from a file, the text is assumed to be encoded in UTF-8. Lines in the | ||
342 | input end with `'\\n'` or `"\\r\\n"` or the end of an input stream. When `keep` is | ||
343 | false (as it is by default), these trailing newline characters are removed from the | ||
344 | line before it is returned. When `keep` is true, they are returned as part of the | ||
345 | line. | ||
346 | |||
347 | # Examples | ||
348 | ```jldoctest | ||
349 | julia> open("my_file.txt", "w") do io | ||
350 | write(io, "JuliaLang is a GitHub organization.\\nIt has many members.\\n"); | ||
351 | end | ||
352 | 57 | ||
353 | |||
354 | julia> readline("my_file.txt") | ||
355 | "JuliaLang is a GitHub organization." | ||
356 | |||
357 | julia> readline("my_file.txt", keep=true) | ||
358 | "JuliaLang is a GitHub organization.\\n" | ||
359 | |||
360 | julia> rm("my_file.txt") | ||
361 | ``` | ||
362 | """ | ||
363 | function readline(filename::AbstractString; keep::Bool=false) | ||
364 | open(filename) do f | ||
365 | readline(f, keep=keep) | ||
366 | end | ||
367 | end | ||
368 | |||
369 | function readline(s::IO=stdin; keep::Bool=false) | ||
370 | line = readuntil(s, 0x0a, keep=true) | ||
371 | i = length(line) | ||
372 | if keep || i == 0 || line[i] != 0x0a | ||
373 | return String(line) | ||
374 | elseif i < 2 || line[i-1] != 0x0d | ||
375 | return String(resize!(line,i-1)) | ||
376 | else | ||
377 | return String(resize!(line,i-2)) | ||
378 | end | ||
379 | end | ||
380 | |||
381 | """ | ||
382 | readlines(io::IO=stdin; keep::Bool=false) | ||
383 | readlines(filename::AbstractString; keep::Bool=false) | ||
384 | |||
385 | Read all lines of an I/O stream or a file as a vector of strings. Behavior is | ||
386 | equivalent to saving the result of reading [`readline`](@ref) repeatedly with the same | ||
387 | arguments and saving the resulting lines as a vector of strings. | ||
388 | |||
389 | # Examples | ||
390 | ```jldoctest | ||
391 | julia> open("my_file.txt", "w") do io | ||
392 | write(io, "JuliaLang is a GitHub organization.\\nIt has many members.\\n"); | ||
393 | end | ||
394 | 57 | ||
395 | |||
396 | julia> readlines("my_file.txt") | ||
397 | 2-element Array{String,1}: | ||
398 | "JuliaLang is a GitHub organization." | ||
399 | "It has many members." | ||
400 | |||
401 | julia> readlines("my_file.txt", keep=true) | ||
402 | 2-element Array{String,1}: | ||
403 | "JuliaLang is a GitHub organization.\\n" | ||
404 | "It has many members.\\n" | ||
405 | |||
406 | julia> rm("my_file.txt") | ||
407 | ``` | ||
408 | """ | ||
409 | function readlines(filename::AbstractString; kw...) | ||
410 | open(filename) do f | ||
411 | readlines(f; kw...) | ||
412 | end | ||
413 | end | ||
414 | readlines(s=stdin; kw...) = collect(eachline(s; kw...)) | ||
415 | |||
416 | ## byte-order mark, ntoh & hton ## | ||
417 | |||
418 | let a = UInt32[0x01020304] | ||
419 | endian_bom = GC.@preserve a unsafe_load(convert(Ptr{UInt8}, pointer(a))) | ||
420 | global ntoh, hton, ltoh, htol | ||
421 | if endian_bom == 0x01 | ||
422 | ntoh(x) = x | ||
423 | hton(x) = x | ||
424 | ltoh(x) = bswap(x) | ||
425 | htol(x) = bswap(x) | ||
426 | const global ENDIAN_BOM = 0x01020304 | ||
427 | elseif endian_bom == 0x04 | ||
428 | ntoh(x) = bswap(x) | ||
429 | hton(x) = bswap(x) | ||
430 | ltoh(x) = x | ||
431 | htol(x) = x | ||
432 | const global ENDIAN_BOM = 0x04030201 | ||
433 | else | ||
434 | error("seriously? what is this machine?") | ||
435 | end | ||
436 | end | ||
437 | |||
438 | """ | ||
439 | ENDIAN_BOM | ||
440 | |||
441 | The 32-bit byte-order-mark indicates the native byte order of the host machine. | ||
442 | Little-endian machines will contain the value `0x04030201`. Big-endian machines will contain | ||
443 | the value `0x01020304`. | ||
444 | """ | ||
445 | ENDIAN_BOM | ||
446 | |||
447 | """ | ||
448 | ntoh(x) | ||
449 | |||
450 | Convert the endianness of a value from Network byte order (big-endian) to that used by the Host. | ||
451 | """ | ||
452 | ntoh(x) | ||
453 | |||
454 | """ | ||
455 | hton(x) | ||
456 | |||
457 | Convert the endianness of a value from that used by the Host to Network byte order (big-endian). | ||
458 | """ | ||
459 | hton(x) | ||
460 | |||
461 | """ | ||
462 | ltoh(x) | ||
463 | |||
464 | Convert the endianness of a value from Little-endian to that used by the Host. | ||
465 | """ | ||
466 | ltoh(x) | ||
467 | |||
468 | """ | ||
469 | htol(x) | ||
470 | |||
471 | Convert the endianness of a value from that used by the Host to Little-endian. | ||
472 | """ | ||
473 | htol(x) | ||
474 | |||
475 | |||
476 | """ | ||
477 | isreadonly(io) -> Bool | ||
478 | |||
479 | Determine whether a stream is read-only. | ||
480 | |||
481 | # Examples | ||
482 | ```jldoctest | ||
483 | julia> io = IOBuffer("JuliaLang is a GitHub organization"); | ||
484 | |||
485 | julia> isreadonly(io) | ||
486 | true | ||
487 | |||
488 | julia> io = IOBuffer(); | ||
489 | |||
490 | julia> isreadonly(io) | ||
491 | false | ||
492 | ``` | ||
493 | """ | ||
494 | isreadonly(s) = isreadable(s) && !iswritable(s) | ||
495 | |||
496 | ## binary I/O ## | ||
497 | |||
498 | write(io::IO, x) = throw(MethodError(write, (io, x))) | ||
499 | function write(io::IO, x1, xs...) | ||
500 | written::Int = write(io, x1) | ||
501 | for x in xs | ||
502 | written += write(io, x) | ||
503 | end | ||
504 | return written | ||
505 | end | ||
506 | |||
507 | @noinline unsafe_write(s::IO, p::Ref{T}, n::Integer) where {T} = | ||
508 | unsafe_write(s, unsafe_convert(Ref{T}, p)::Ptr, n) # mark noinline to ensure ref is gc-rooted somewhere (by the caller) | ||
509 | 1 (2.38%) |
1 (2.38%) samples spent in unsafe_write
0 (ex.), 1 (100.00%) (incl.) when called from _show line 128
1 (100.00%)
samples spent calling
unsafe_write
unsafe_write(s::IO, p::Ptr, n::Integer) = unsafe_write(s, convert(Ptr{UInt8}, p), convert(UInt, n))
|
|
510 | write(s::IO, x::Ref{T}) where {T} = unsafe_write(s, x, Core.sizeof(T)) | ||
511 | write(s::IO, x::Int8) = write(s, reinterpret(UInt8, x)) | ||
512 | function write(s::IO, x::Union{Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128,Float16,Float32,Float64}) | ||
513 | return write(s, Ref(x)) | ||
514 | end | ||
515 | |||
516 | write(s::IO, x::Bool) = write(s, UInt8(x)) | ||
517 | write(to::IO, p::Ptr) = write(to, convert(UInt, p)) | ||
518 | |||
519 | function write(s::IO, A::AbstractArray) | ||
520 | if !isbitstype(eltype(A)) | ||
521 | error("`write` is not supported on non-isbits arrays") | ||
522 | end | ||
523 | nb = 0 | ||
524 | for a in A | ||
525 | nb += write(s, a) | ||
526 | end | ||
527 | return nb | ||
528 | end | ||
529 | |||
530 | function write(s::IO, a::Array) | ||
531 | if isbitstype(eltype(a)) | ||
532 | return GC.@preserve a unsafe_write(s, pointer(a), sizeof(a)) | ||
533 | else | ||
534 | error("`write` is not supported on non-isbits arrays") | ||
535 | end | ||
536 | end | ||
537 | |||
538 | function write(s::IO, a::SubArray{T,N,<:Array}) where {T,N} | ||
539 | if !isbitstype(T) || !isa(a, StridedArray) | ||
540 | return invoke(write, Tuple{IO, AbstractArray}, s, a) | ||
541 | end | ||
542 | elsz = sizeof(T) | ||
543 | colsz = size(a,1) * elsz | ||
544 | GC.@preserve a if stride(a,1) != 1 | ||
545 | for idxs in CartesianIndices(size(a)) | ||
546 | unsafe_write(s, pointer(a, idxs.I), elsz) | ||
547 | end | ||
548 | return elsz * length(a) | ||
549 | elseif N <= 1 | ||
550 | return unsafe_write(s, pointer(a, 1), colsz) | ||
551 | else | ||
552 | for idxs in CartesianIndices((1, size(a)[2:end]...)) | ||
553 | unsafe_write(s, pointer(a, idxs.I), colsz) | ||
554 | end | ||
555 | return colsz * trailingsize(a,2) | ||
556 | end | ||
557 | end | ||
558 | |||
559 | function write(io::IO, c::Char) | ||
560 | u = bswap(reinterpret(UInt32, c)) | ||
561 | n = 1 | ||
562 | while true | ||
563 | write(io, u % UInt8) | ||
564 | (u >>= 8) == 0 && return n | ||
565 | n += 1 | ||
566 | end | ||
567 | end | ||
568 | # write(io, ::AbstractChar) is not defined: implementations | ||
569 | # must provide their own encoding-specific method. | ||
570 | |||
571 | function write(io::IO, s::Symbol) | ||
572 | pname = unsafe_convert(Ptr{UInt8}, s) | ||
573 | return unsafe_write(io, pname, Int(ccall(:strlen, Csize_t, (Cstring,), pname))) | ||
574 | end | ||
575 | |||
576 | function write(to::IO, from::IO) | ||
577 | n = 0 | ||
578 | while !eof(from) | ||
579 | n += write(to, readavailable(from)) | ||
580 | end | ||
581 | return n | ||
582 | end | ||
583 | |||
584 | @noinline unsafe_read(s::IO, p::Ref{T}, n::Integer) where {T} = unsafe_read(s, unsafe_convert(Ref{T}, p)::Ptr, n) # mark noinline to ensure ref is gc-rooted somewhere (by the caller) | ||
585 | unsafe_read(s::IO, p::Ptr, n::Integer) = unsafe_read(s, convert(Ptr{UInt8}, p), convert(UInt, n)) | ||
586 | read!(s::IO, x::Ref{T}) where {T} = (unsafe_read(s, x, Core.sizeof(T)); x) | ||
587 | |||
588 | read(s::IO, ::Type{Int8}) = reinterpret(Int8, read(s, UInt8)) | ||
589 | function read(s::IO, T::Union{Type{Int16},Type{UInt16},Type{Int32},Type{UInt32},Type{Int64},Type{UInt64},Type{Int128},Type{UInt128},Type{Float16},Type{Float32},Type{Float64}}) | ||
590 | return read!(s, Ref{T}(0))[]::T | ||
591 | end | ||
592 | |||
593 | read(s::IO, ::Type{Bool}) = (read(s, UInt8) != 0) | ||
594 | read(s::IO, ::Type{Ptr{T}}) where {T} = convert(Ptr{T}, read(s, UInt)) | ||
595 | |||
596 | function read!(s::IO, a::Array{UInt8}) | ||
597 | GC.@preserve a unsafe_read(s, pointer(a), sizeof(a)) | ||
598 | return a | ||
599 | end | ||
600 | |||
601 | function read!(s::IO, a::Array{T}) where T | ||
602 | if isbitstype(T) | ||
603 | GC.@preserve a unsafe_read(s, pointer(a), sizeof(a)) | ||
604 | else | ||
605 | for i in eachindex(a) | ||
606 | a[i] = read(s, T) | ||
607 | end | ||
608 | end | ||
609 | return a | ||
610 | end | ||
611 | |||
612 | function read(io::IO, ::Type{Char}) | ||
613 | b0 = read(io, UInt8) | ||
614 | l = 8(4-leading_ones(b0)) | ||
615 | c = UInt32(b0) << 24 | ||
616 | if l < 24 | ||
617 | s = 16 | ||
618 | while s ≥ l && !eof(io) | ||
619 | peek(io) & 0xc0 == 0x80 || break | ||
620 | b = read(io, UInt8) | ||
621 | c |= UInt32(b) << s | ||
622 | s -= 8 | ||
623 | end | ||
624 | end | ||
625 | return reinterpret(Char, c) | ||
626 | end | ||
627 | # read(io, T) is not defined for other AbstractChar: implementations | ||
628 | # must provide their own encoding-specific method. | ||
629 | |||
630 | # readuntil_string is useful below since it has | ||
631 | # an optimized method for s::IOStream | ||
632 | readuntil_string(s::IO, delim::UInt8, keep::Bool) = String(readuntil(s, delim, keep=keep)) | ||
633 | |||
634 | function readuntil(s::IO, delim::AbstractChar; keep::Bool=false) | ||
635 | if delim ≤ '\x7f' | ||
636 | return readuntil_string(s, delim % UInt8, keep) | ||
637 | end | ||
638 | out = IOBuffer() | ||
639 | while !eof(s) | ||
640 | c = read(s, Char) | ||
641 | if c == delim | ||
642 | keep && write(out, c) | ||
643 | break | ||
644 | end | ||
645 | write(out, c) | ||
646 | end | ||
647 | return String(take!(out)) | ||
648 | end | ||
649 | |||
650 | function readuntil(s::IO, delim::T; keep::Bool=false) where T | ||
651 | out = (T === UInt8 ? StringVector(0) : Vector{T}()) | ||
652 | while !eof(s) | ||
653 | c = read(s, T) | ||
654 | if c == delim | ||
655 | keep && push!(out, c) | ||
656 | break | ||
657 | end | ||
658 | push!(out, c) | ||
659 | end | ||
660 | return out | ||
661 | end | ||
662 | |||
663 | # requires that indices for target are the integer unit range from firstindex to lastindex | ||
664 | # returns whether the delimiter was matched | ||
665 | # uses the Knuth–Morris–Pratt_algorithm, with the first and second cache entries unrolled | ||
666 | # For longer targets, the cache improves the big-O efficiency of scanning of sequences | ||
667 | # with repeated patterns | ||
668 | # Each cache entry tells us which index we should start the search at. | ||
669 | # We assume this is unlikely, so we only lazy-initialize as much of the cache as we need to use | ||
670 | # When we allocate the cache, we initialize it to 0 (and offset by the first index afterwards). | ||
671 | # Suppose target is: | ||
672 | # Index: 1245689 | ||
673 | # Value: "aδcaδcx" | ||
674 | # We would set the cache to | ||
675 | # 0 0 0 1 2 3 4 0 | ||
676 | # So after if we mismatch after the second aδc sequence, | ||
677 | # we can immediately jump back to index 5 (4 + 1). | ||
678 | function readuntil_vector!(io::IO, target::AbstractVector{T}, keep::Bool, out) where {T} | ||
679 | first = firstindex(target) | ||
680 | last = lastindex(target) | ||
681 | len = last - first + 1 | ||
682 | if len < 1 | ||
683 | return true | ||
684 | end | ||
685 | pos = 0 # array-offset | ||
686 | max_pos = 1 # array-offset in cache | ||
687 | local cache # will be lazy initialized when needed | ||
688 | output! = (isa(out, IO) ? write : push!) | ||
689 | while !eof(io) | ||
690 | c = read(io, T) | ||
691 | # Backtrack until the next target character matches what was found | ||
692 | while true | ||
693 | c1 = target[pos + first] | ||
694 | if c == c1 | ||
695 | pos += 1 | ||
696 | break | ||
697 | elseif pos == 0 | ||
698 | break | ||
699 | elseif pos == 1 | ||
700 | if !keep | ||
701 | output!(out, target[first]) | ||
702 | end | ||
703 | pos = 0 | ||
704 | else | ||
705 | # grow cache to contain up to `pos` | ||
706 | if !@isdefined(cache) | ||
707 | cache = zeros(Int, len) | ||
708 | end | ||
709 | while max_pos < pos | ||
710 | ci = target[max_pos + first] | ||
711 | b = max_pos | ||
712 | max_pos += 1 | ||
713 | while b != 0 | ||
714 | b = cache[b] | ||
715 | cb = target[b + first] | ||
716 | if ci == cb | ||
717 | cache[max_pos] = b + 1 | ||
718 | break | ||
719 | end | ||
720 | end | ||
721 | end | ||
722 | # read new position from cache | ||
723 | pos1 = cache[pos] | ||
724 | if !keep | ||
725 | # and add the removed prefix from the target to the output | ||
726 | # if not always keeping the match | ||
727 | for b in 1:(pos - pos1) | ||
728 | output!(out, target[b - 1 + first]) | ||
729 | end | ||
730 | end | ||
731 | pos = pos1 | ||
732 | end | ||
733 | end | ||
734 | if keep || pos == 0 | ||
735 | output!(out, c) | ||
736 | end | ||
737 | pos == len && return true | ||
738 | end | ||
739 | if !keep | ||
740 | # failed early without finishing the match, | ||
741 | # add the partial match to the output | ||
742 | # if not always keeping the match | ||
743 | for b in 1:pos | ||
744 | output!(out, target[b - 1 + first]) | ||
745 | end | ||
746 | end | ||
747 | return false | ||
748 | end | ||
749 | |||
750 | function readuntil(io::IO, target::AbstractString; keep::Bool=false) | ||
751 | # small-string target optimizations | ||
752 | isempty(target) && return "" | ||
753 | c, rest = Iterators.peel(target) | ||
754 | if isempty(rest) && c <= '\x7f' | ||
755 | return readuntil_string(io, c % UInt8, keep) | ||
756 | end | ||
757 | # convert String to a utf8-byte-iterator | ||
758 | if !(target isa String) && !(target isa SubString{String}) | ||
759 | target = String(target) | ||
760 | end | ||
761 | target = codeunits(target)::AbstractVector | ||
762 | return String(readuntil(io, target, keep=keep)) | ||
763 | end | ||
764 | |||
765 | function readuntil(io::IO, target::AbstractVector{T}; keep::Bool=false) where T | ||
766 | out = (T === UInt8 ? StringVector(0) : Vector{T}()) | ||
767 | readuntil_vector!(io, target, keep, out) | ||
768 | return out | ||
769 | end | ||
770 | |||
771 | """ | ||
772 | readchomp(x) | ||
773 | |||
774 | Read the entirety of `x` as a string and remove a single trailing newline | ||
775 | if there is one. Equivalent to `chomp(read(x, String))`. | ||
776 | |||
777 | # Examples | ||
778 | ```jldoctest | ||
779 | julia> open("my_file.txt", "w") do io | ||
780 | write(io, "JuliaLang is a GitHub organization.\\nIt has many members.\\n"); | ||
781 | end; | ||
782 | |||
783 | julia> readchomp("my_file.txt") | ||
784 | "JuliaLang is a GitHub organization.\\nIt has many members." | ||
785 | |||
786 | julia> rm("my_file.txt"); | ||
787 | ``` | ||
788 | """ | ||
789 | readchomp(x) = chomp(read(x, String)) | ||
790 | |||
791 | # read up to nb bytes into nb, returning # bytes read | ||
792 | |||
793 | """ | ||
794 | readbytes!(stream::IO, b::AbstractVector{UInt8}, nb=length(b)) | ||
795 | |||
796 | Read at most `nb` bytes from `stream` into `b`, returning the number of bytes read. | ||
797 | The size of `b` will be increased if needed (i.e. if `nb` is greater than `length(b)` | ||
798 | and enough bytes could be read), but it will never be decreased. | ||
799 | """ | ||
800 | function readbytes!(s::IO, b::AbstractArray{UInt8}, nb=length(b)) | ||
801 | @assert !has_offset_axes(b) | ||
802 | olb = lb = length(b) | ||
803 | nr = 0 | ||
804 | while nr < nb && !eof(s) | ||
805 | a = read(s, UInt8) | ||
806 | nr += 1 | ||
807 | if nr > lb | ||
808 | lb = nr * 2 | ||
809 | resize!(b, lb) | ||
810 | end | ||
811 | b[nr] = a | ||
812 | end | ||
813 | if lb > olb | ||
814 | resize!(b, nr) # shrink to just contain input data if was resized | ||
815 | end | ||
816 | return nr | ||
817 | end | ||
818 | |||
819 | """ | ||
820 | read(s::IO, nb=typemax(Int)) | ||
821 | |||
822 | Read at most `nb` bytes from `s`, returning a `Vector{UInt8}` of the bytes read. | ||
823 | """ | ||
824 | function read(s::IO, nb::Integer = typemax(Int)) | ||
825 | # Let readbytes! grow the array progressively by default | ||
826 | # instead of taking of risk of over-allocating | ||
827 | b = Vector{UInt8}(undef, nb == typemax(Int) ? 1024 : nb) | ||
828 | nr = readbytes!(s, b, nb) | ||
829 | return resize!(b, nr) | ||
830 | end | ||
831 | |||
832 | read(s::IO, ::Type{String}) = String(read(s)) | ||
833 | read(s::IO, T::Type) = error("The IO stream does not support reading objects of type $T.") | ||
834 | |||
835 | ## high-level iterator interfaces ## | ||
836 | |||
837 | struct EachLine{IOT <: IO} | ||
838 | stream::IOT | ||
839 | ondone::Function | ||
840 | keep::Bool | ||
841 | EachLine(stream::IO=stdin; ondone::Function=()->nothing, keep::Bool=false) = | ||
842 | new{typeof(stream)}(stream, ondone, keep) | ||
843 | end | ||
844 | |||
845 | """ | ||
846 | eachline(io::IO=stdin; keep::Bool=false) | ||
847 | eachline(filename::AbstractString; keep::Bool=false) | ||
848 | |||
849 | Create an iterable `EachLine` object that will yield each line from an I/O stream | ||
850 | or a file. Iteration calls [`readline`](@ref) on the stream argument repeatedly with | ||
851 | `keep` passed through, determining whether trailing end-of-line characters are | ||
852 | retained. When called with a file name, the file is opened once at the beginning of | ||
853 | iteration and closed at the end. If iteration is interrupted, the file will be | ||
854 | closed when the `EachLine` object is garbage collected. | ||
855 | |||
856 | # Examples | ||
857 | ```jldoctest | ||
858 | julia> open("my_file.txt", "w") do io | ||
859 | write(io, "JuliaLang is a GitHub organization.\\n It has many members.\\n"); | ||
860 | end; | ||
861 | |||
862 | julia> for line in eachline("my_file.txt") | ||
863 | print(line) | ||
864 | end | ||
865 | JuliaLang is a GitHub organization. It has many members. | ||
866 | |||
867 | julia> rm("my_file.txt"); | ||
868 | ``` | ||
869 | """ | ||
870 | function eachline(stream::IO=stdin; keep::Bool=false) | ||
871 | EachLine(stream, keep=keep)::EachLine | ||
872 | end | ||
873 | |||
874 | function eachline(filename::AbstractString; keep::Bool=false) | ||
875 | s = open(filename) | ||
876 | EachLine(s, ondone=()->close(s), keep=keep)::EachLine | ||
877 | end | ||
878 | |||
879 | function iterate(itr::EachLine, state=nothing) | ||
880 | eof(itr.stream) && return (itr.ondone(); nothing) | ||
881 | (readline(itr.stream, keep=itr.keep), nothing) | ||
882 | end | ||
883 | |||
884 | eltype(::Type{<:EachLine}) = String | ||
885 | |||
886 | IteratorSize(::Type{<:EachLine}) = SizeUnknown() | ||
887 | |||
888 | # IOStream Marking | ||
889 | # Note that these functions expect that io.mark exists for | ||
890 | # the concrete IO type. This may not be true for IO types | ||
891 | # not in base. | ||
892 | |||
893 | """ | ||
894 | mark(s) | ||
895 | |||
896 | Add a mark at the current position of stream `s`. Return the marked position. | ||
897 | |||
898 | See also [`unmark`](@ref), [`reset`](@ref), [`ismarked`](@ref). | ||
899 | """ | ||
900 | function mark(io::IO) | ||
901 | io.mark = position(io) | ||
902 | end | ||
903 | |||
904 | """ | ||
905 | unmark(s) | ||
906 | |||
907 | Remove a mark from stream `s`. Return `true` if the stream was marked, `false` otherwise. | ||
908 | |||
909 | See also [`mark`](@ref), [`reset`](@ref), [`ismarked`](@ref). | ||
910 | """ | ||
911 | function unmark(io::IO) | ||
912 | !ismarked(io) && return false | ||
913 | io.mark = -1 | ||
914 | return true | ||
915 | end | ||
916 | |||
917 | """ | ||
918 | reset(s) | ||
919 | |||
920 | Reset a stream `s` to a previously marked position, and remove the mark. Return the | ||
921 | previously marked position. Throw an error if the stream is not marked. | ||
922 | |||
923 | See also [`mark`](@ref), [`unmark`](@ref), [`ismarked`](@ref). | ||
924 | """ | ||
925 | function reset(io::T) where T<:IO | ||
926 | ismarked(io) || throw(ArgumentError("$(T) not marked")) | ||
927 | m = io.mark | ||
928 | seek(io, m) | ||
929 | io.mark = -1 # must be after seek, or seek may fail | ||
930 | return m | ||
931 | end | ||
932 | |||
933 | """ | ||
934 | ismarked(s) | ||
935 | |||
936 | Return `true` if stream `s` is marked. | ||
937 | |||
938 | See also [`mark`](@ref), [`unmark`](@ref), [`reset`](@ref). | ||
939 | """ | ||
940 | ismarked(io::IO) = io.mark >= 0 | ||
941 | |||
942 | # Make sure all IO streams support flush, even if only as a no-op, | ||
943 | # to make it easier to write generic I/O code. | ||
944 | |||
945 | """ | ||
946 | flush(stream) | ||
947 | |||
948 | Commit all currently buffered writes to the given stream. | ||
949 | """ | ||
950 | flush(io::IO) = nothing | ||
951 | |||
952 | """ | ||
953 | skipchars(predicate, io::IO; linecomment=nothing) | ||
954 | |||
955 | Advance the stream `io` such that the next-read character will be the first remaining for | ||
956 | which `predicate` returns `false`. If the keyword argument `linecomment` is specified, all | ||
957 | characters from that character until the start of the next line are ignored. | ||
958 | |||
959 | # Examples | ||
960 | ```jldoctest | ||
961 | julia> buf = IOBuffer(" text") | ||
962 | IOBuffer(data=UInt8[...], readable=true, writable=false, seekable=true, append=false, size=8, maxsize=Inf, ptr=1, mark=-1) | ||
963 | |||
964 | julia> skipchars(isspace, buf) | ||
965 | IOBuffer(data=UInt8[...], readable=true, writable=false, seekable=true, append=false, size=8, maxsize=Inf, ptr=5, mark=-1) | ||
966 | |||
967 | julia> String(readavailable(buf)) | ||
968 | "text" | ||
969 | ``` | ||
970 | """ | ||
971 | function skipchars(predicate, io::IO; linecomment=nothing) | ||
972 | while !eof(io) | ||
973 | c = read(io, Char) | ||
974 | if c === linecomment | ||
975 | readline(io) | ||
976 | elseif !predicate(c) | ||
977 | skip(io, -codelen(c)) | ||
978 | break | ||
979 | end | ||
980 | end | ||
981 | return io | ||
982 | end | ||
983 | |||
984 | """ | ||
985 | countlines(io::IO; eol::AbstractChar = '\\n') | ||
986 | |||
987 | Read `io` until the end of the stream/file and count the number of lines. To specify a file | ||
988 | pass the filename as the first argument. EOL markers other than `'\\n'` are supported by | ||
989 | passing them as the second argument. The last non-empty line of `io` is counted even if it does not | ||
990 | end with the EOL, matching the length returned by [`eachline`](@ref) and [`readlines`](@ref). | ||
991 | |||
992 | # Examples | ||
993 | ```jldoctest | ||
994 | julia> io = IOBuffer("JuliaLang is a GitHub organization.\\n"); | ||
995 | |||
996 | julia> countlines(io) | ||
997 | 1 | ||
998 | |||
999 | julia> io = IOBuffer("JuliaLang is a GitHub organization."); | ||
1000 | |||
1001 | julia> countlines(io) | ||
1002 | 1 | ||
1003 | |||
1004 | julia> countlines(io, eol = '.') | ||
1005 | 0 | ||
1006 | ``` | ||
1007 | """ | ||
1008 | function countlines(io::IO; eol::AbstractChar='\n') | ||
1009 | isascii(eol) || throw(ArgumentError("only ASCII line terminators are supported")) | ||
1010 | aeol = UInt8(eol) | ||
1011 | a = Vector{UInt8}(undef, 8192) | ||
1012 | nl = nb = 0 | ||
1013 | while !eof(io) | ||
1014 | nb = readbytes!(io, a) | ||
1015 | @simd for i=1:nb | ||
1016 | @inbounds nl += a[i] == aeol | ||
1017 | end | ||
1018 | end | ||
1019 | if nb > 0 && a[nb] != aeol | ||
1020 | nl += 1 # final line is not terminated with eol | ||
1021 | end | ||
1022 | nl | ||
1023 | end | ||
1024 | |||
1025 | countlines(f::AbstractString; eol::AbstractChar = '\n') = open(io->countlines(io, eol = eol), f)::Int |