@@ -1127,105 +1127,119 @@ function _fd(x::Union{LibuvStream, LibuvServer})
11271127 return fd[]
11281128end
11291129
1130- for (x, writable, unix_fd, c_symbol) in
1131- ((:stdin , false , 0 , :jl_uv_stdin ),
1132- (:stdout , true , 1 , :jl_uv_stdout ),
1133- (:stderr , true , 2 , :jl_uv_stderr ))
1134- f = Symbol (" redirect_" , lowercase (string (x)))
1135- _f = Symbol (" _" , f)
1136- @eval begin
1137- function ($ _f)(stream)
1138- global $ x
1139- posix_fd = _fd (stream)
1140- @static if Sys. iswindows ()
1141- ccall (:SetStdHandle , stdcall, Int32, (Int32, OS_HANDLE),
1142- $ (- 10 - unix_fd), Libc. _get_osfhandle (posix_fd))
1143- end
1144- dup (posix_fd, RawFD ($ unix_fd))
1145- $ x = stream
1146- nothing
1147- end
1148- function ($ f)(handle:: Union{LibuvStream, IOStream} )
1149- $ (_f)(handle)
1150- unsafe_store! (cglobal ($ (Expr (:quote , c_symbol)), Ptr{Cvoid}),
1151- handle. handle)
1152- return handle
1153- end
1154- function ($ f)()
1155- p = link_pipe! (Pipe ())
1156- read, write = p. out, p. in
1157- ($ f)($ (writable ? :write : :read ))
1158- return (read, write)
1159- end
1160- function ($ f)(:: DevNull )
1161- global $ x
1162- nulldev = @static Sys. iswindows () ? " NUL" : " /dev/null"
1163- handle = open (nulldev, write= $ writable)
1164- $ (_f)(handle)
1165- close (handle) # handle has been dup'ed in $(_f)
1166- $ x = devnull
1167- return devnull
1168- end
1169- function ($ f)(io:: IOContext )
1170- io2, _dict = unwrapcontext (io)
1171- ($ f)(io2)
1172- global $ x = io
1173- return io
1130+ struct redirect_stdio <: Function
1131+ unix_fd:: Int
1132+ writable:: Bool
1133+ end
1134+ for (f, writable, unix_fd) in
1135+ ((:redirect_stdin , false , 0 ),
1136+ (:redirect_stdout , true , 1 ),
1137+ (:redirect_stderr , true , 2 ))
1138+ @eval const ($ f) = redirect_stdio ($ unix_fd, $ writable)
1139+ end
1140+ function _redirect_io_libc (stream, unix_fd:: Int )
1141+ posix_fd = _fd (stream)
1142+ @static if Sys. iswindows ()
1143+ if 0 <= unix_fd <= 2
1144+ ccall (:SetStdHandle , stdcall, Int32, (Int32, OS_HANDLE),
1145+ - 10 - unix_fd, Libc. _get_osfhandle (posix_fd))
11741146 end
11751147 end
1148+ dup (posix_fd, RawFD (unix_fd))
1149+ nothing
1150+ end
1151+ function _redirect_io_global (io, unix_fd:: Int )
1152+ unix_fd == 0 && (global stdin = io)
1153+ unix_fd == 1 && (global stdout = io)
1154+ unix_fd == 2 && (global stderr = io)
1155+ nothing
1156+ end
1157+ function (f:: redirect_stdio )(handle:: Union{LibuvStream, IOStream} )
1158+ _redirect_io_libc (handle, f. unix_fd)
1159+ c_sym = f. unix_fd == 0 ? cglobal (:jl_uv_stdin , Ptr{Cvoid}) :
1160+ f. unix_fd == 1 ? cglobal (:jl_uv_stdout , Ptr{Cvoid}) :
1161+ f. unix_fd == 2 ? cglobal (:jl_uv_stderr , Ptr{Cvoid}) :
1162+ C_NULL
1163+ c_sym == C_NULL || unsafe_store! (c_sym, handle. handle)
1164+ _redirect_io_global (handle, f. unix_fd)
1165+ return handle
1166+ end
1167+ function (f:: redirect_stdio )(:: DevNull )
1168+ nulldev = @static Sys. iswindows () ? " NUL" : " /dev/null"
1169+ handle = open (nulldev, write= f. writable)
1170+ _redirect_io_libc (handle, f. unix_fd)
1171+ close (handle) # handle has been dup'ed in _redirect_io_libc
1172+ _redirect_io_global (devnull , f. unix_fd)
1173+ return devnull
1174+ end
1175+ function (f:: redirect_stdio )(io:: AbstractPipe )
1176+ io2 = (f. writable ? pipe_writer : pipe_reader)(io)
1177+ f (io2)
1178+ _redirect_io_global (io, f. unix_fd)
1179+ return io
1180+ end
1181+ function (f:: redirect_stdio )(p:: Pipe )
1182+ if p. in. status == StatusInit && p. out. status == StatusInit
1183+ link_pipe! (p)
1184+ end
1185+ io2 = getfield (p, f. writable ? :in : :out )
1186+ f (io2)
1187+ return p
11761188end
1189+ (f:: redirect_stdio )() = f (Pipe ())
1190+
1191+ # Deprecate these in v2 (redirect_stdio support)
1192+ iterate (p:: Pipe ) = (p. out, 1 )
1193+ iterate (p:: Pipe , i:: Int ) = i == 1 ? (p. in, 2 ) : nothing
1194+ getindex (p:: Pipe , key:: Int ) = key == 1 ? p. out : key == 2 ? p. in : throw (KeyError (key))
11771195
11781196"""
1179- redirect_stdout([stream]) -> (rd, wr)
1197+ redirect_stdout([stream]) -> stream
11801198
11811199Create a pipe to which all C and Julia level [`stdout`](@ref) output
1182- will be redirected.
1183- Returns a tuple `(rd, wr)` representing the pipe ends.
1200+ will be redirected. Return a stream representing the pipe ends.
11841201Data written to [`stdout`](@ref) may now be read from the `rd` end of
1185- the pipe. The `wr` end is given for convenience in case the old
1186- [`stdout`](@ref) object was cached by the user and needs to be replaced
1187- elsewhere.
1188-
1189- If called with the optional `stream` argument, then returns `stream` itself.
1202+ the pipe.
11901203
11911204!!! note
1192- `stream` must be an `IOStream`, a `TTY`, a `Pipe`, a socket, or `devnull`.
1205+ `stream` must be a compatible objects, such as an `IOStream`, `TTY`,
1206+ `Pipe`, socket, or `devnull`.
11931207"""
11941208redirect_stdout
11951209
11961210"""
1197- redirect_stderr([stream]) -> (rd, wr)
1211+ redirect_stderr([stream]) -> stream
11981212
11991213Like [`redirect_stdout`](@ref), but for [`stderr`](@ref).
12001214
12011215!!! note
1202- `stream` must be an `IOStream`, a `TTY`, a `Pipe`, a socket, or `devnull`.
1216+ `stream` must be a compatible objects, such as an `IOStream`, `TTY`,
1217+ `Pipe`, socket, or `devnull`.
12031218"""
12041219redirect_stderr
12051220
12061221"""
1207- redirect_stdin([stream]) -> (rd, wr)
1222+ redirect_stdin([stream]) -> stream
12081223
12091224Like [`redirect_stdout`](@ref), but for [`stdin`](@ref).
1210- Note that the order of the return tuple is still `(rd, wr)`,
1211- i.e. data to be read from [`stdin`](@ref) may be written to `wr`.
1225+ Note that the direction of the stream is reversed.
12121226
12131227!!! note
1214- `stream` must be an `IOStream`, a `TTY`, a `Pipe`, a socket, or `devnull`.
1228+ `stream` must be a compatible objects, such as an `IOStream`, `TTY`,
1229+ `Pipe`, socket, or `devnull`.
12151230"""
12161231redirect_stdin
12171232
1218- for (F,S) in ((:redirect_stdin , :stdin ), (:redirect_stdout , :stdout ), (:redirect_stderr , :stderr ))
1219- @eval function $F (f:: Function , stream)
1220- STDOLD = $ S
1221- local ret
1222- $ F (stream)
1223- try
1224- ret = f ()
1225- finally
1226- $ F (STDOLD)
1227- end
1228- ret
1233+ function (f:: redirect_stdio )(thunk:: Function , stream)
1234+ stdold = f. unix_fd == 0 ? stdin :
1235+ f. unix_fd == 1 ? stdout :
1236+ f. unix_fd == 2 ? stderr :
1237+ throw (ArgumentError (" Not implemented to get old handle of fd except for stdio" ))
1238+ f (stream)
1239+ try
1240+ return thunk ()
1241+ finally
1242+ f (stdold)
12291243 end
12301244end
12311245
@@ -1234,9 +1248,6 @@ end
12341248
12351249Run the function `f` while redirecting [`stdout`](@ref) to `stream`.
12361250Upon completion, [`stdout`](@ref) is restored to its prior setting.
1237-
1238- !!! note
1239- `stream` must be a `TTY`, a `Pipe`, or a socket.
12401251"""
12411252redirect_stdout (f:: Function , stream)
12421253
@@ -1245,9 +1256,6 @@ redirect_stdout(f::Function, stream)
12451256
12461257Run the function `f` while redirecting [`stderr`](@ref) to `stream`.
12471258Upon completion, [`stderr`](@ref) is restored to its prior setting.
1248-
1249- !!! note
1250- `stream` must be a `TTY`, a `Pipe`, or a socket.
12511259"""
12521260redirect_stderr (f:: Function , stream)
12531261
@@ -1256,9 +1264,6 @@ redirect_stderr(f::Function, stream)
12561264
12571265Run the function `f` while redirecting [`stdin`](@ref) to `stream`.
12581266Upon completion, [`stdin`](@ref) is restored to its prior setting.
1259-
1260- !!! note
1261- `stream` must be a `TTY`, a `Pipe`, or a socket.
12621267"""
12631268redirect_stdin (f:: Function , stream)
12641269
0 commit comments