@@ -31,57 +31,35 @@ use libc;
31
31
use option:: { Option , Some , None } ;
32
32
use result:: { Ok , Err } ;
33
33
use rt:: io:: buffered:: LineBufferedWriter ;
34
- use rt:: rtio:: { IoFactory , RtioTTY , RtioFileStream , with_local_io,
35
- CloseAsynchronously } ;
36
- use super :: { Reader , Writer , io_error , IoError , OtherIoError } ;
34
+ use rt:: rtio:: { IoFactory , RtioTTY , RtioFileStream , with_local_io, DontClose } ;
35
+ use super :: { Reader , Writer , io_error , IoError , OtherIoError ,
36
+ standard_error , EndOfFile } ;
37
37
38
- // And so begins the tale of acquiring a uv handle to a stdio stream on all
39
- // platforms in all situations. Our story begins by splitting the world into two
40
- // categories, windows and unix. Then one day the creators of unix said let
41
- // there be redirection! And henceforth there was redirection away from the
42
- // console for standard I/O streams.
38
+ // A stdio source is frequently connected to a terminal (tty), but it's also
39
+ // commonly redirected elsewhere. Right now libuv has questionable support for
40
+ // using a stdio source as a tty handle when it's actually piped elsewhere, so
41
+ // we have this enum for delegating what the underlying handle is being used as.
43
42
//
44
- // After this day, the world split into four factions:
43
+ // For now this is fine, as the only real reason for having a tty distinction is
44
+ // to provide some nice extra features (like terminal dimensions), and piped
45
+ // streams don't have that anyway.
45
46
//
46
- // 1. Unix with stdout on a terminal.
47
- // 2. Unix with stdout redirected.
48
- // 3. Windows with stdout on a terminal.
49
- // 4. Windows with stdout redirected.
50
- //
51
- // Many years passed, and then one day the nation of libuv decided to unify this
52
- // world. After months of toiling, uv created three ideas: TTY, Pipe, File.
53
- // These three ideas propagated throughout the lands and the four great factions
54
- // decided to settle among them.
55
- //
56
- // The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
57
- // doing so, they even enhanced themselves further then their Pipe/File
58
- // brethren, becoming the dominant powers.
59
- //
60
- // The group of 4, however, decided to work independently. They abandoned the
61
- // common TTY belief throughout, and even abandoned the fledgling Pipe belief.
62
- // The members of the 4th faction decided to only align themselves with File.
63
- //
64
- // tl;dr; TTY works on everything but when windows stdout is redirected, in that
65
- // case pipe also doesn't work, but magically file does!
47
+ // The good news is that if stdio is on a terminal, tty always works. If stdio
48
+ // is not on a terminal, then a file stream always works. Yay!
66
49
enum StdSource {
67
50
TTY ( ~RtioTTY ) ,
68
51
File ( ~RtioFileStream ) ,
69
52
}
70
53
71
- #[ fixed_stack_segment] #[ inline( never) ]
72
54
fn src < T > ( fd : libc:: c_int , readable : bool , f : & fn ( StdSource ) -> T ) -> T {
55
+ // it's understood that the file descriptor passed to these functions will
56
+ // *not* be closed when these I/O objects go out of scope. Otherwise, only
57
+ // sadness would ensue.
73
58
do with_local_io |io| {
74
- let fd = unsafe { libc:: dup ( fd) } ;
75
59
match io. tty_open ( fd, readable) {
76
60
Ok ( tty) => Some ( f ( TTY ( tty) ) ) ,
77
61
Err ( _) => {
78
- // It's not really that desirable if these handles are closed
79
- // synchronously, and because they're squirreled away in a task
80
- // structure the destructors will be run when the task is
81
- // attempted to get destroyed. This means that if we run a
82
- // synchronous destructor we'll attempt to do some scheduling
83
- // operations which will just result in sadness.
84
- Some ( f ( File ( io. fs_from_raw_fd ( fd, CloseAsynchronously ) ) ) )
62
+ Some ( f ( File ( io. fs_from_raw_fd ( fd, DontClose ) ) ) )
85
63
}
86
64
}
87
65
} . unwrap ( )
@@ -203,6 +181,17 @@ impl Reader for StdReader {
203
181
File ( ref mut file) => file. read ( buf) . map ( |i| i as uint ) ,
204
182
} ;
205
183
match ret {
184
+ // It appears that libuv will return 0-length reads for a stdio file
185
+ // handle when the file is positioned at EOF. When we open normal
186
+ // files, this doesn't happen, so it probably has to do with the
187
+ // handle being more of a pipe rather than something else.
188
+ // Regardless, translate 0-length reads of a stdio handle to an EOF
189
+ // notice rather than returning 0. Returning 0 will simply
190
+ // infinitely return 0 until the end of time (not good).
191
+ Ok ( 0 ) => {
192
+ io_error:: cond. raise ( standard_error ( EndOfFile ) ) ;
193
+ None
194
+ }
206
195
Ok ( amt) => Some ( amt as uint ) ,
207
196
Err ( e) => {
208
197
io_error:: cond. raise ( e) ;
0 commit comments