]> git.lizzy.rs Git - rust.git/blob - src/librustuv/tty.rs
Fix usage of libuv for windows
[rust.git] / src / librustuv / tty.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::libc;
12 use std::rt::io::IoError;
13 use std::rt::local::Local;
14 use std::rt::rtio::RtioTTY;
15 use std::rt::sched::{Scheduler, SchedHandle};
16
17 use stream::StreamWatcher;
18 use super::{Loop, UvError, UvHandle, uv_error_to_io_error};
19 use uvio::HomingIO;
20 use uvll;
21
22 pub struct TtyWatcher{
23     tty: *uvll::uv_tty_t,
24     stream: StreamWatcher,
25     home: SchedHandle,
26     fd: libc::c_int,
27 }
28
29 impl TtyWatcher {
30     pub fn new(loop_: &Loop, fd: libc::c_int, readable: bool)
31         -> Result<TtyWatcher, UvError>
32     {
33         // libuv may succeed in giving us a handle (via uv_tty_init), but if the
34         // handle isn't actually connected to a terminal there are frequently
35         // many problems in using it with libuv. To get around this, always
36         // return a failure if the specified file descriptor isn't actually a
37         // TTY.
38         //
39         // Related:
40         // - https://github.com/joyent/libuv/issues/982
41         // - https://github.com/joyent/libuv/issues/988
42         if unsafe { uvll::guess_handle(fd) != uvll::UV_TTY as libc::c_int } {
43             return Err(UvError(uvll::EBADF));
44         }
45
46         // If this file descriptor is indeed guessed to be a tty, then go ahead
47         // with attempting to open it as a tty.
48         let handle = UvHandle::alloc(None::<TtyWatcher>, uvll::UV_TTY);
49         match unsafe {
50             uvll::uv_tty_init(loop_.handle, handle, fd as libc::c_int,
51                               readable as libc::c_int)
52         } {
53             0 => {
54                 Ok(TtyWatcher {
55                     tty: handle,
56                     stream: StreamWatcher::new(handle),
57                     home: get_handle_to_current_scheduler!(),
58                     fd: fd,
59                 })
60             }
61             n => {
62                 unsafe { uvll::free_handle(handle) }
63                 Err(UvError(n))
64             }
65         }
66     }
67 }
68
69 impl RtioTTY for TtyWatcher {
70     fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
71         let _m = self.fire_homing_missile();
72         self.stream.read(buf).map_err(uv_error_to_io_error)
73     }
74
75     fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
76         let _m = self.fire_homing_missile();
77         self.stream.write(buf).map_err(uv_error_to_io_error)
78     }
79
80     fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
81         let raw = raw as libc::c_int;
82         let _m = self.fire_homing_missile();
83         match unsafe { uvll::uv_tty_set_mode(self.tty, raw) } {
84             0 => Ok(()),
85             n => Err(uv_error_to_io_error(UvError(n)))
86         }
87     }
88
89     #[allow(unused_mut)]
90     fn get_winsize(&mut self) -> Result<(int, int), IoError> {
91         let mut width: libc::c_int = 0;
92         let mut height: libc::c_int = 0;
93         let widthptr: *libc::c_int = &width;
94         let heightptr: *libc::c_int = &width;
95
96         let _m = self.fire_homing_missile();
97         match unsafe { uvll::uv_tty_get_winsize(self.tty,
98                                                 widthptr, heightptr) } {
99             0 => Ok((width as int, height as int)),
100             n => Err(uv_error_to_io_error(UvError(n)))
101         }
102     }
103 }
104
105 impl UvHandle<uvll::uv_tty_t> for TtyWatcher {
106     fn uv_handle(&self) -> *uvll::uv_tty_t { self.tty }
107 }
108
109 impl HomingIO for TtyWatcher {
110     fn home<'a>(&'a mut self) -> &'a mut SchedHandle { &mut self.home }
111 }
112
113 impl Drop for TtyWatcher {
114     fn drop(&mut self) {
115         let _m = self.fire_homing_missile();
116         self.close_async_();
117     }
118 }