# This file is a part of Julia. License is MIT: https://julialang.org/license # Generic IO stubs -- all subtypes should implement these (if meaningful) lock(::IO) = nothing unlock(::IO) = nothing reseteof(x::IO) = nothing const SZ_UNBUFFERED_IO = 65536 buffer_writes(x::IO, bufsize=SZ_UNBUFFERED_IO) = x """ isopen(object) -> Bool Determine whether an object - such as a stream, timer, or mmap -- is not yet closed. Once an object is closed, it will never produce a new event. However, a closed stream may still have data to read in its buffer, use [`eof`](@ref) to check for the ability to read data. Use [`poll_fd`](@ref) to be notified when a stream might be writable or readable. """ function isopen end """ close(stream) Close an I/O stream. Performs a [`flush`](@ref) first. """ function close end function flush end function wait_connected end function wait_readnb end function wait_readbyte end function wait_close end function nb_available end function readavailable end """ isreadable(io) -> Bool Returns `true` if the specified IO object is readable (if that can be determined). """ function isreadable end """ iswritable(io) -> Bool Returns `true` if the specified IO object is writable (if that can be determined). """ function iswritable end function copy end function eof end """ write(stream::IO, x) write(filename::AbstractString, x) Write the canonical binary representation of a value to the given I/O stream or file. Returns the number of bytes written into the stream. You can write multiple values with the same `write` call. i.e. the following are equivalent: write(stream, x, y...) write(stream, x) + write(stream, y...) """ function write end read(s::IO, ::Type{UInt8}) = error(typeof(s)," does not support byte I/O") write(s::IO, x::UInt8) = error(typeof(s)," does not support byte I/O") """ unsafe_write(io::IO, ref, nbytes::UInt) Copy `nbytes` from `ref` (converted to a pointer) into the `IO` object. It is recommended that subtypes `T<:IO` override the following method signature to provide more efficient implementations: `unsafe_write(s::T, p::Ptr{UInt8}, n::UInt)` """ function unsafe_write(s::IO, p::Ptr{UInt8}, n::UInt) local written::Int = 0 for i = 1:n written += write(s, unsafe_load(p, i)) end return written end """ unsafe_read(io::IO, ref, nbytes::UInt) Copy `nbytes` from the `IO` stream object into `ref` (converted to a pointer). It is recommended that subtypes `T<:IO` override the following method signature to provide more efficient implementations: `unsafe_read(s::T, p::Ptr{UInt8}, n::UInt)` """ function unsafe_read(s::IO, p::Ptr{UInt8}, n::UInt) for i = 1:n unsafe_store!(p, read(s, UInt8)::UInt8, i) end nothing end # Generic wrappers around other IO objects abstract type AbstractPipe <: IO end function pipe_reader end function pipe_writer end write(io::AbstractPipe, byte::UInt8) = write(pipe_writer(io), byte) unsafe_write(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_write(pipe_writer(io), p, nb) buffer_writes(io::AbstractPipe, args...) = buffer_writes(pipe_writer(io), args...) flush(io::AbstractPipe) = flush(pipe_writer(io)) read(io::AbstractPipe, byte::Type{UInt8}) = read(pipe_reader(io), byte) unsafe_read(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_read(pipe_reader(io), p, nb) read(io::AbstractPipe) = read(pipe_reader(io)) readuntil(io::AbstractPipe, arg::UInt8) = readuntil(pipe_reader(io), arg) readuntil(io::AbstractPipe, arg::Char) = readuntil(pipe_reader(io), arg) readuntil(io::AbstractPipe, arg::AbstractString) = readuntil(pipe_reader(io), arg) readuntil(io::AbstractPipe, arg) = readuntil(pipe_reader(io), arg) readavailable(io::AbstractPipe) = readavailable(pipe_reader(io)) isreadable(io::AbstractPipe) = isreadable(pipe_reader(io)) iswritable(io::AbstractPipe) = iswritable(pipe_writer(io)) isopen(io::AbstractPipe) = isopen(pipe_writer(io)) || isopen(pipe_reader(io)) close(io::AbstractPipe) = (close(pipe_writer(io)); close(pipe_reader(io))) wait_readnb(io::AbstractPipe, nb::Int) = wait_readnb(pipe_reader(io), nb) wait_readbyte(io::AbstractPipe, byte::UInt8) = wait_readbyte(pipe_reader(io), byte) wait_close(io::AbstractPipe) = (wait_close(pipe_writer(io)); wait_close(pipe_reader(io))) """ nb_available(stream) Returns the number of bytes available for reading before a read from this stream or buffer will block. """ nb_available(io::AbstractPipe) = nb_available(pipe_reader(io)) """ eof(stream) -> Bool Tests whether an I/O stream is at end-of-file. If the stream is not yet exhausted, this function will block to wait for more data if necessary, and then return `false`. Therefore it is always safe to read one byte after seeing `eof` return `false`. `eof` will return `false` as long as buffered data is still available, even if the remote end of a connection is closed. """ eof(io::AbstractPipe) = eof(pipe_reader(io)) reseteof(io::AbstractPipe) = reseteof(pipe_reader(io)) # Exception-safe wrappers (io = open(); try f(io) finally close(io)) write(filename::AbstractString, args...) = open(io->write(io, args...), filename, "w") """ read(filename::AbstractString, args...) Open a file and read its contents. `args` is passed to `read`: this is equivalent to `open(io->read(io, args...), filename)`. """ read(filename::AbstractString, args...) = open(io->read(io, args...), filename) read!(filename::AbstractString, a) = open(io->read!(io, a), filename) """ readuntil(stream::IO, delim) readuntil(filename::AbstractString, delim) Read a string from an I/O stream or a file, up to and including the given delimiter byte. The text is assumed to be encoded in UTF-8. """ readuntil(filename::AbstractString, args...) = open(io->readuntil(io, args...), filename) """ readline(stream::IO=STDIN; chomp::Bool=true) readline(filename::AbstractString; chomp::Bool=true) Read a single line of text from the given I/O stream or file (defaults to `STDIN`). When reading from a file, the text is assumed to be encoded in UTF-8. Lines in the input end with `'\\n'` or `"\\r\\n"` or the end of an input stream. When `chomp` is true (as it is by default), these trailing newline characters are removed from the line before it is returned. When `chomp` is false, they are returned as part of the line. """ function readline(filename::AbstractString; chomp::Bool=true) open(filename) do f readline(f, chomp=chomp) end end function readline(s::IO=STDIN; chomp::Bool=true) line = readuntil(s, 0x0a) i = length(line) if !chomp || i == 0 || line[i] != 0x0a return String(line) elseif i < 2 || line[i-1] != 0x0d return String(resize!(line,i-1)) else return String(resize!(line,i-2)) end end """ readlines(stream::IO=STDIN; chomp::Bool=true) readlines(filename::AbstractString; chomp::Bool=true) Read all lines of an I/O stream or a file as a vector of strings. Behavior is equivalent to saving the result of reading `readline` repeatedly with the same arguments and saving the resulting lines as a vector of strings. """ function readlines(filename::AbstractString; chomp::Bool=true) open(filename) do f readlines(f, chomp=chomp) end end readlines(s=STDIN; chomp::Bool=true) = collect(eachline(s, chomp=chomp)) ## byte-order mark, ntoh & hton ## let endian_boms = reinterpret(UInt8, UInt32[0x01020304]) global ntoh, hton, ltoh, htol if endian_boms == UInt8[1:4;] ntoh(x) = x hton(x) = x ltoh(x) = bswap(x) htol(x) = bswap(x) const global ENDIAN_BOM = 0x01020304 elseif endian_boms == UInt8[4:-1:1;] ntoh(x) = bswap(x) hton(x) = bswap(x) ltoh(x) = x htol(x) = x const global ENDIAN_BOM = 0x04030201 else error("seriously? what is this machine?") end end """ ENDIAN_BOM The 32-bit byte-order-mark indicates the native byte order of the host machine. Little-endian machines will contain the value `0x04030201`. Big-endian machines will contain the value `0x01020304`. """ ENDIAN_BOM """ ntoh(x) Converts the endianness of a value from Network byte order (big-endian) to that used by the Host. """ ntoh(x) """ hton(x) Converts the endianness of a value from that used by the Host to Network byte order (big-endian). """ hton(x) """ ltoh(x) Converts the endianness of a value from Little-endian to that used by the Host. """ ltoh(x) """ htol(x) Converts the endianness of a value from that used by the Host to Little-endian. """ htol(x) """ isreadonly(stream) -> Bool Determine whether a stream is read-only. """ isreadonly(s) = isreadable(s) && !iswritable(s) ## binary I/O ## write(io::IO, x) = throw(MethodError(write, (io, x))) function write(io::IO, xs...) local written::Int = 0 for x in xs written += write(io, x) end return written end @noinline unsafe_write{T}(s::IO, p::Ref{T}, n::Integer) = unsafe_write(s, unsafe_convert(Ref{T}, p)::Ptr, n) # mark noinline to ensure ref is gc-rooted somewhere (by the caller) unsafe_write(s::IO, p::Ptr, n::Integer) = unsafe_write(s, convert(Ptr{UInt8}, p), convert(UInt, n)) write{T}(s::IO, x::Ref{T}) = unsafe_write(s, x, Core.sizeof(T)) write(s::IO, x::Int8) = write(s, reinterpret(UInt8, x)) function write(s::IO, x::Union{Int16,UInt16,Int32,UInt32,Int64,UInt64,Int128,UInt128,Float16,Float32,Float64}) return write(s, Ref(x)) end write(s::IO, x::Bool) = write(s, UInt8(x)) write(to::IO, p::Ptr) = write(to, convert(UInt, p)) function write(s::IO, A::AbstractArray) nb = 0 for a in A nb += write(s, a) end return nb end @noinline function write(s::IO, a::Array{UInt8}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller) return unsafe_write(s, pointer(a), sizeof(a)) end @noinline function write{T}(s::IO, a::Array{T}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller) if isbits(T) return unsafe_write(s, pointer(a), sizeof(a)) else nb = 0 for b in a nb += write(s, b) end return nb end end function write(s::IO, ch::Char) c = reinterpret(UInt32, ch) if c < 0x80 return write(s, c%UInt8) elseif c < 0x800 return (write(s, (( c >> 6 ) | 0xC0)%UInt8)) + (write(s, (( c & 0x3F ) | 0x80)%UInt8)) elseif c < 0x10000 return (write(s, (( c >> 12 ) | 0xE0)%UInt8)) + (write(s, (((c >> 6) & 0x3F ) | 0x80)%UInt8)) + (write(s, (( c & 0x3F ) | 0x80)%UInt8)) elseif c < 0x110000 return (write(s, (( c >> 18 ) | 0xF0)%UInt8)) + (write(s, (((c >> 12) & 0x3F ) | 0x80)%UInt8)) + (write(s, (((c >> 6) & 0x3F ) | 0x80)%UInt8)) + (write(s, (( c & 0x3F ) | 0x80)%UInt8)) else return write(s, '\ufffd') end end function write(io::IO, s::Symbol) pname = unsafe_convert(Ptr{UInt8}, s) return unsafe_write(io, pname, Int(ccall(:strlen, Csize_t, (Cstring,), pname))) end function write(to::IO, from::IO) while !eof(from) write(to, readavailable(from)) end end @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) unsafe_read(s::IO, p::Ptr, n::Integer) = unsafe_read(s, convert(Ptr{UInt8}, p), convert(UInt, n)) read(s::IO, x::Ref{T}) where {T} = (unsafe_read(s, x, Core.sizeof(T)); x) read(s::IO, ::Type{Int8}) = reinterpret(Int8, read(s, UInt8)) 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}}) return read(s, Ref{T}(0))[]::T end read(s::IO, ::Type{Bool}) = (read(s, UInt8) != 0) read(s::IO, ::Type{Ptr{T}}) where {T} = convert(Ptr{T}, read(s, UInt)) read(s::IO, t::Type{T}, d1::Int, dims::Int...) where {T} = read(s, t, tuple(d1,dims...)) read(s::IO, t::Type{T}, d1::Integer, dims::Integer...) where {T} = read(s, t, convert(Tuple{Vararg{Int}},tuple(d1,dims...))) """ read(stream::IO, T, dims) Read a series of values of type `T` from `stream`, in canonical binary representation. `dims` is either a tuple or a series of integer arguments specifying the size of the `Array{T}` to return. """ read(s::IO, ::Type{T}, dims::Dims) where {T} = read!(s, Array{T}(dims)) @noinline function read!(s::IO, a::Array{UInt8}) # mark noinline to ensure the array is gc-rooted somewhere (by the caller) unsafe_read(s, pointer(a), sizeof(a)) return a end @noinline function read!(s::IO, a::Array{T}) where T # mark noinline to ensure the array is gc-rooted somewhere (by the caller) if isbits(T) unsafe_read(s, pointer(a), sizeof(a)) else for i in eachindex(a) a[i] = read(s, T) end end return a end function read(s::IO, ::Type{Char}) ch = read(s, UInt8) if ch < 0x80 return Char(ch) end # mimic utf8.next function trailing = Base.utf8_trailing[ch+1] c::UInt32 = 0 for j = 1:trailing c += ch c <<= 6 ch = read(s, UInt8) end c += ch c -= Base.utf8_offset[trailing+1] return Char(c) end # readuntil_string is useful below since it has # an optimized method for s::IOStream readuntil_string(s::IO, delim::UInt8) = String(readuntil(s, delim)) function readuntil(s::IO, delim::Char) if delim < Char(0x80) return readuntil_string(s, delim % UInt8) end out = IOBuffer() while !eof(s) c = read(s, Char) write(out, c) if c == delim break end end return String(take!(out)) end function readuntil{T}(s::IO, delim::T) out = T[] while !eof(s) c = read(s, T) push!(out, c) if c == delim break end end return out end # based on code by Glen Hertz function readuntil(s::IO, t::AbstractString) l = length(t) if l == 0 return "" end if l > 40 warn("readuntil(IO,AbstractString) will perform poorly with a long string") end out = IOBuffer() m = Vector{Char}(l) # last part of stream to match t = collect(t) i = 0 while !eof(s) i += 1 c = read(s, Char) write(out, c) if i <= l m[i] = c else # shift to last part of s for j = 2:l m[j-1] = m[j] end m[l] = c end if i >= l && m == t break end end return String(take!(out)) end """ readchomp(x) Read the entirety of `x` as a string and remove a single trailing newline. Equivalent to `chomp!(readstring(x))`. """ readchomp(x) = chomp!(readstring(x)) # read up to nb bytes into nb, returning # bytes read """ readbytes!(stream::IO, b::AbstractVector{UInt8}, nb=length(b)) Read at most `nb` bytes from `stream` into `b`, returning the number of bytes read. The size of `b` will be increased if needed (i.e. if `nb` is greater than `length(b)` and enough bytes could be read), but it will never be decreased. """ function readbytes!(s::IO, b::AbstractArray{UInt8}, nb=length(b)) olb = lb = length(b) nr = 0 while nr < nb && !eof(s) a = read(s, UInt8) nr += 1 if nr > lb lb = nr * 2 resize!(b, lb) end b[nr] = a end if lb > olb resize!(b, nr) # shrink to just contain input data if was resized end return nr end """ read(s::IO, nb=typemax(Int)) Read at most `nb` bytes from `s`, returning a `Vector{UInt8}` of the bytes read. """ function read(s::IO, nb=typemax(Int)) # Let readbytes! grow the array progressively by default # instead of taking of risk of over-allocating b = Vector{UInt8}(nb == typemax(Int) ? 1024 : nb) nr = readbytes!(s, b, nb) return resize!(b, nr) end """ readstring(stream::IO) readstring(filename::AbstractString) Read the entire contents of an I/O stream or a file as a string. The text is assumed to be encoded in UTF-8. """ readstring(s::IO) = String(read(s)) readstring(filename::AbstractString) = open(readstring, filename) ## high-level iterator interfaces ## mutable struct EachLine stream::IO ondone::Function chomp::Bool EachLine(stream::IO=STDIN; ondone::Function=()->nothing, chomp::Bool=true) = new(stream, ondone, chomp) end """ eachline(stream::IO=STDIN; chomp::Bool=true) eachline(filename::AbstractString; chomp::Bool=true) Create an iterable `EachLine` object that will yield each line from an I/O stream or a file. Iteration calls `readline` on the stream argument repeatedly with `chomp` passed through, determining whether trailing end-of-line characters are removed. When called with a file name, the file is opened once at the beginning of iteration and closed at the end. If iteration is interrupted, the file will be closed when the `EachLine` object is garbage collected. """ eachline(stream::IO=STDIN; chomp::Bool=true) = EachLine(stream, chomp=chomp)::EachLine function eachline(filename::AbstractString; chomp::Bool=true) s = open(filename) EachLine(s, ondone=()->close(s), chomp=chomp)::EachLine end start(itr::EachLine) = nothing function done(itr::EachLine, ::Void) eof(itr.stream) || return false itr.ondone() true end next(itr::EachLine, ::Void) = (readline(itr.stream, chomp=itr.chomp), nothing) eltype(::Type{EachLine}) = String iteratorsize(::Type{EachLine}) = SizeUnknown() # IOStream Marking # Note that these functions expect that io.mark exists for # the concrete IO type. This may not be true for IO types # not in base. """ mark(s) Add a mark at the current position of stream `s`. Returns the marked position. See also [`unmark`](@ref), [`reset`](@ref), [`ismarked`](@ref). """ function mark(io::IO) io.mark = position(io) end """ unmark(s) Remove a mark from stream `s`. Returns `true` if the stream was marked, `false` otherwise. See also [`mark`](@ref), [`reset`](@ref), [`ismarked`](@ref). """ function unmark(io::IO) !ismarked(io) && return false io.mark = -1 return true end """ reset(s) Reset a stream `s` to a previously marked position, and remove the mark. Returns the previously marked position. Throws an error if the stream is not marked. See also [`mark`](@ref), [`unmark`](@ref), [`ismarked`](@ref). """ function reset(io::T) where T<:IO ismarked(io) || throw(ArgumentError("$(T) not marked")) m = io.mark seek(io, m) io.mark = -1 # must be after seek, or seek may fail return m end """ ismarked(s) Returns `true` if stream `s` is marked. See also [`mark`](@ref), [`unmark`](@ref), [`reset`](@ref). """ ismarked(io::IO) = io.mark >= 0 # Make sure all IO streams support flush, even if only as a no-op, # to make it easier to write generic I/O code. """ flush(stream) Commit all currently buffered writes to the given stream. """ flush(io::IO) = nothing