]> git.lizzy.rs Git - rust.git/blob - src/librustuv/tty.rs
Rename all raw pointers as necessary
[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 libc;
12 use std::ptr;
13 use std::rt::rtio::{RtioTTY, IoResult};
14
15 use homing::{HomingIO, HomeHandle};
16 use stream::StreamWatcher;
17 use super::{UvError, UvHandle, uv_error_to_io_error};
18 use uvio::UvIoFactory;
19 use uvll;
20
21 pub struct TtyWatcher{
22     tty: *mut uvll::uv_tty_t,
23     stream: StreamWatcher,
24     home: HomeHandle,
25     fd: libc::c_int,
26 }
27
28 impl TtyWatcher {
29     pub fn new(io: &mut UvIoFactory, fd: libc::c_int, readable: bool)
30         -> Result<TtyWatcher, UvError>
31     {
32         // libuv may succeed in giving us a handle (via uv_tty_init), but if the
33         // handle isn't actually connected to a terminal there are frequently
34         // many problems in using it with libuv. To get around this, always
35         // return a failure if the specified file descriptor isn't actually a
36         // TTY.
37         //
38         // Related:
39         // - https://github.com/joyent/libuv/issues/982
40         // - https://github.com/joyent/libuv/issues/988
41         let guess = unsafe { uvll::guess_handle(fd) };
42         if guess != uvll::UV_TTY as libc::c_int {
43             return Err(UvError(uvll::EBADF));
44         }
45
46         // libuv was recently changed to not close the stdio file descriptors,
47         // but it did not change the behavior for windows. Until this issue is
48         // fixed, we need to dup the stdio file descriptors because otherwise
49         // uv_close will close them
50         let fd = if cfg!(windows) && fd <= libc::STDERR_FILENO {
51             unsafe { libc::dup(fd) }
52         } else { fd };
53
54         // If this file descriptor is indeed guessed to be a tty, then go ahead
55         // with attempting to open it as a tty.
56         let handle = UvHandle::alloc(None::<TtyWatcher>, uvll::UV_TTY);
57         let mut watcher = TtyWatcher {
58             tty: handle,
59             stream: StreamWatcher::new(handle),
60             home: io.make_handle(),
61             fd: fd,
62         };
63         match unsafe {
64             uvll::uv_tty_init(io.uv_loop(), handle, fd as libc::c_int,
65                               readable as libc::c_int)
66         } {
67             0 => Ok(watcher),
68             n => {
69                 // On windows, libuv returns errors before initializing the
70                 // handle, so our only cleanup is to free the handle itself
71                 if cfg!(windows) {
72                     unsafe { uvll::free_handle(handle); }
73                     watcher.tty = ptr::mut_null();
74                 }
75                 Err(UvError(n))
76             }
77         }
78     }
79 }
80
81 impl RtioTTY for TtyWatcher {
82     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
83         let _m = self.fire_homing_missile();
84         self.stream.read(buf).map_err(uv_error_to_io_error)
85     }
86
87     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
88         let _m = self.fire_homing_missile();
89         self.stream.write(buf, false).map_err(uv_error_to_io_error)
90     }
91
92     fn set_raw(&mut self, raw: bool) -> IoResult<()> {
93         let raw = raw as libc::c_int;
94         let _m = self.fire_homing_missile();
95         match unsafe { uvll::uv_tty_set_mode(self.tty, raw) } {
96             0 => Ok(()),
97             n => Err(uv_error_to_io_error(UvError(n)))
98         }
99     }
100
101     #[allow(unused_mut)]
102     fn get_winsize(&mut self) -> IoResult<(int, int)> {
103         let mut width: libc::c_int = 0;
104         let mut height: libc::c_int = 0;
105         let widthptr: *mut libc::c_int = &mut width;
106         let heightptr: *mut libc::c_int = &mut width;
107
108         let _m = self.fire_homing_missile();
109         match unsafe { uvll::uv_tty_get_winsize(self.tty,
110                                                 widthptr, heightptr) } {
111             0 => Ok((width as int, height as int)),
112             n => Err(uv_error_to_io_error(UvError(n)))
113         }
114     }
115
116     fn isatty(&self) -> bool {
117         unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY as libc::c_int }
118     }
119 }
120
121 impl UvHandle<uvll::uv_tty_t> for TtyWatcher {
122     fn uv_handle(&self) -> *mut uvll::uv_tty_t { self.tty }
123 }
124
125 impl HomingIO for TtyWatcher {
126     fn home<'a>(&'a mut self) -> &'a mut HomeHandle { &mut self.home }
127 }
128
129 impl Drop for TtyWatcher {
130     fn drop(&mut self) {
131         if !self.tty.is_null() {
132             let _m = self.fire_homing_missile();
133             self.close_async_();
134         }
135     }
136 }