diff --git a/base/libc.jl b/base/libc.jl index 1d1ba0ea8bf05..5f9ac1dbab61b 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -6,6 +6,22 @@ export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, ca include("errno.jl") +## RawFD ## + +#Wrapper for an OS file descriptor (on both Unix and Windows) +immutable RawFD + fd::Int32 + RawFD(fd::Integer) = new(fd) + RawFD(fd::RawFD) = fd +end + +Base.convert(::Type{Int32}, fd::RawFD) = fd.fd + +dup(x::RawFD) = RawFD(ccall((@windows? :_dup : :dup),Int32,(Int32,),x.fd)) +dup(src::RawFD,target::RawFD) = systemerror("dup",-1== + ccall((@windows? :_dup2 : :dup2),Int32, + (Int32,Int32),src.fd,target.fd)) + ## FILE ## immutable FILE @@ -15,13 +31,21 @@ end modestr(s::IO) = modestr(isreadable(s), iswritable(s)) modestr(r::Bool, w::Bool) = r ? (w ? "r+" : "r") : (w ? "w" : throw(ArgumentError("neither readable nor writable"))) -function FILE(s::IO) - @unix_only FILEp = ccall(:fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) - @windows_only FILEp = ccall(:_fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) +function FILE(fd, mode) + @unix_only FILEp = ccall(:fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd), mode) + @windows_only FILEp = ccall(:_fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd), mode) systemerror("fdopen", FILEp == C_NULL) - seek(FILE(FILEp), position(s)) + FILE(FILEp) +end + +function FILE(s::IO) + f = FILE(dup(RawFD(fd(s))),modestr(s)) + seek(f, position(s)) + f end +Base.unsafe_convert(T::Union(Type{Ptr{Void}},Type{Ptr{FILE}}), f::FILE) = convert(T, f.ptr) +Base.close(f::FILE) = systemerror("fclose", ccall(:fclose, Cint, (Ptr{Void},), f.ptr) != 0) Base.convert(::Type{FILE}, s::IO) = FILE(s) function Base.seek(h::FILE, offset::Integer) diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index c1cde9968c437..b39ca605dd495 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -663,6 +663,13 @@ for Ti in IndexTypes finalizer(s, free!) s end + + function read_sparse(file::IO, T) + cfile = Libc.FILE(file) + try return read_sparse(cfile, T) + finally close(cfile) + end + end end end @@ -791,7 +798,7 @@ Sparse(A::Dense) = dense_to_sparse(A, Cint) Sparse(L::Factor) = factor_to_sparse!(copy(L)) function Sparse(filename::ByteString) open(filename) do f - return read_sparse(Libc.FILE(f), SuiteSparse_long) + return read_sparse(f, SuiteSparse_long) end end diff --git a/base/stream.jl b/base/stream.jl index 30155e5ae70e7..9d89e6e6124cd 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -1,6 +1,8 @@ #TODO: Move stdio detection from C to Julia (might require some Clang magic) include("uv_constants.jl") +import .Libc: RawFD, dup + ## types ## typealias Callback Union(Function,Bool) @@ -17,15 +19,6 @@ const uvhandles = ObjectIdDict() preserve_handle(x) = uvhandles[x] = get(uvhandles,x,0)+1 unpreserve_handle(x) = (v = uvhandles[x]; v == 1 ? pop!(uvhandles,x) : (uvhandles[x] = v-1); nothing) -#Wrapper for an OS file descriptor (on both Unix and Windows) -immutable RawFD - fd::Int32 - RawFD(fd::Integer) = new(fd) - RawFD(fd::RawFD) = fd -end - -convert(::Type{Int32}, fd::RawFD) = fd.fd - function uv_sizeof_handle(handle) if !(UV_UNKNOWN_HANDLE < handle < UV_HANDLE_TYPE_MAX) throw(DomainError()) @@ -944,11 +937,6 @@ end connect(path::AbstractString) = connect(Pipe(),path) -dup(x::RawFD) = RawFD(ccall((@windows? :_dup : :dup),Int32,(Int32,),x.fd)) -dup(src::RawFD,target::RawFD) = systemerror("dup",-1== - ccall((@windows? :_dup2 : :dup2),Int32, - (Int32,Int32),src.fd,target.fd)) - _fd(x::IOStream) = RawFD(fd(x)) @unix_only _fd(x::AsyncStream) = RawFD(ccall(:jl_uv_handle,Int32,(Ptr{Void},),x.handle)) @windows_only _fd(x::AsyncStream) = WindowsRawSocket( diff --git a/test/file.jl b/test/file.jl index 5db311cd5104c..0ef1586259780 100644 --- a/test/file.jl +++ b/test/file.jl @@ -386,18 +386,25 @@ rm(cfile) # FILE* interface # ################### +function test_LibcFILE(FILEp) + buf = Array(UInt8, 8) + str = ccall(:fread, Csize_t, (Ptr{Void}, Csize_t, Csize_t, Ptr{Void}), buf, 1, 8, FILEp) + @test bytestring(buf) == "Hello, w" + @test position(FILEp) == 8 + seek(FILEp, 5) + @test position(FILEp) == 5 + close(FILEp) +end + f = open(file, "w") write(f, "Hello, world!") close(f) f = open(file, "r") -FILEp = convert(Libc.FILE, f) -buf = Array(UInt8, 8) -str = ccall(:fread, Csize_t, (Ptr{Void}, Csize_t, Csize_t, Ptr{Void}), buf, 1, 8, FILEp.ptr) -@test bytestring(buf) == "Hello, w" -@test position(FILEp) == 8 -seek(FILEp, 5) -@test position(FILEp) == 5 +test_LibcFILE(convert(Libc.FILE, f)) close(f) +@unix_only f = RawFD(ccall(:open, Cint, (Ptr{Uint8}, Cint), file, Base.FS.JL_O_RDONLY)) +@windows_only f = RawFD(ccall(:_open, Cint, (Ptr{Uint8}, Cint), file, Base.FS.JL_O_RDONLY)) +test_LibcFILE(Libc.FILE(f,Libc.modestr(true,false))) ############ # Clean up #