diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 870dea02212d1..b854a2f2a0a17 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -20,7 +20,7 @@ use std::cell::{RefCell, Cell};
 use std::{cmp, error, fmt};
 use std::io::prelude::*;
 use std::io;
-use term::{self, WriterWrapper};
+use term;
 
 /// maximum number of lines we will print for each error; arbitrary.
 const MAX_LINES: usize = 6;
@@ -318,7 +318,7 @@ pub struct EmitterWriter {
 }
 
 enum Destination {
-    Terminal(Box<term::Terminal<WriterWrapper> + Send>),
+    Terminal(Box<term::StderrTerminal>),
     Raw(Box<Write + Send>),
 }
 
@@ -365,7 +365,7 @@ impl EmitterWriter {
 
     fn print_maybe_styled(&mut self,
                           args: fmt::Arguments,
-                          color: term::attr::Attr,
+                          color: term::Attr,
                           print_newline_at_end: bool) -> io::Result<()> {
         match self.dst {
             Terminal(ref mut t) => {
@@ -408,13 +408,13 @@ impl EmitterWriter {
             try!(write!(&mut self.dst, "{} ", topic));
         }
 
-        try!(print_maybe_styled!(self, term::attr::ForegroundColor(lvl.color()),
+        try!(print_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
                                  "{}: ", lvl.to_string()));
-        try!(print_maybe_styled!(self, term::attr::Bold, "{}", msg));
+        try!(print_maybe_styled!(self, term::Attr::Bold, "{}", msg));
 
         match code {
             Some(code) => {
-                let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
+                let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
                 try!(print_maybe_styled!(self, style, " [{}]", code.clone()));
             }
             None => ()
@@ -646,7 +646,7 @@ impl EmitterWriter {
                     s.pop();
                 }
 
-                try!(println_maybe_styled!(self, term::attr::ForegroundColor(lvl.color()),
+                try!(println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
                                            "{}", s));
             }
         }
@@ -719,7 +719,7 @@ impl EmitterWriter {
             }
         }
         s.push('^');
-        println_maybe_styled!(self, term::attr::ForegroundColor(lvl.color()),
+        println_maybe_styled!(self, term::Attr::ForegroundColor(lvl.color()),
                               "{}", s)
     }
 
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index 478b0b846edda..69ad55d790899 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -11,9 +11,9 @@
 //! Terminal formatting library.
 //!
 //! This crate provides the `Terminal` trait, which abstracts over an [ANSI
-//! Terminal][ansi] to provide color printing, among other things. There are two implementations,
-//! the `TerminfoTerminal`, which uses control characters from a
-//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
+//! Terminal][ansi] to provide color printing, among other things. There are two
+//! implementations, the `TerminfoTerminal`, which uses control characters from
+//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
 //! API][win].
 //!
 //! # Examples
@@ -21,19 +21,18 @@
 //! ```no_run
 //! # #![feature(rustc_private)]
 //! extern crate term;
-//!
 //! use std::io::prelude::*;
 //!
 //! fn main() {
 //!     let mut t = term::stdout().unwrap();
 //!
 //!     t.fg(term::color::GREEN).unwrap();
-//!     (write!(t, "hello, ")).unwrap();
+//!     write!(t, "hello, ").unwrap();
 //!
 //!     t.fg(term::color::RED).unwrap();
-//!     (writeln!(t, "world!")).unwrap();
+//!     writeln!(t, "world!").unwrap();
 //!
-//!     t.reset().unwrap();
+//!     assert!(t.reset().unwrap());
 //! }
 //! ```
 //!
@@ -58,84 +57,60 @@
 #![deny(missing_docs)]
 
 #![feature(box_syntax)]
-#![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(str_char)]
-#![feature(vec_push_all)]
 #![cfg_attr(windows, feature(libc))]
 // Handle rustfmt skips
 #![feature(custom_attribute)]
 #![allow(unused_attributes)]
 
-#[macro_use]
-extern crate log;
+use std::io::prelude::*;
 
 pub use terminfo::TerminfoTerminal;
 #[cfg(windows)]
 pub use win::WinConsole;
 
-use std::io::prelude::*;
-use std::io;
+use std::io::{self, Stdout, Stderr};
 
 pub mod terminfo;
 
 #[cfg(windows)]
 mod win;
 
-/// A hack to work around the fact that `Box<Write + Send>` does not
-/// currently implement `Write`.
-pub struct WriterWrapper {
-    wrapped: Box<Write + Send>,
-}
-
-impl Write for WriterWrapper {
-    #[inline]
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.wrapped.write(buf)
-    }
-
-    #[inline]
-    fn flush(&mut self) -> io::Result<()> {
-        self.wrapped.flush()
-    }
-}
+/// Alias for stdout terminals.
+pub type StdoutTerminal = Terminal<Output=Stdout> + Send;
+/// Alias for stderr terminals.
+pub type StderrTerminal = Terminal<Output=Stderr> + Send;
 
 #[cfg(not(windows))]
 /// Return a Terminal wrapping stdout, or None if a terminal couldn't be
 /// opened.
-pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
-    TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stdout() })
+pub fn stdout() -> Option<Box<StdoutTerminal>> {
+    TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
 }
 
 #[cfg(windows)]
 /// Return a Terminal wrapping stdout, or None if a terminal couldn't be
 /// opened.
-pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
-    let ti = TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stdout() });
-
-    match ti {
-        Some(t) => Some(t),
-        None => WinConsole::new(WriterWrapper { wrapped: box std::io::stdout() }),
-    }
+pub fn stdout() -> Option<Box<StdoutTerminal>> {
+    TerminfoTerminal::new(io::stdout())
+        .map(|t| Box::new(t) as Box<StdoutTerminal>)
+        .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
 }
 
 #[cfg(not(windows))]
 /// Return a Terminal wrapping stderr, or None if a terminal couldn't be
 /// opened.
-pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
-    TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stderr() })
+pub fn stderr() -> Option<Box<StderrTerminal>> {
+    TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
 }
 
 #[cfg(windows)]
 /// Return a Terminal wrapping stderr, or None if a terminal couldn't be
 /// opened.
-pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
-    let ti = TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stderr() });
-
-    match ti {
-        Some(t) => Some(t),
-        None => WinConsole::new(WriterWrapper { wrapped: box std::io::stderr() }),
-    }
+pub fn stderr() -> Option<Box<StderrTerminal>> {
+    TerminfoTerminal::new(io::stderr())
+        .map(|t| Box::new(t) as Box<StderrTerminal>)
+        .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
 }
 
 
@@ -164,43 +139,41 @@ pub mod color {
     pub const BRIGHT_WHITE: Color = 15;
 }
 
-/// Terminal attributes
-pub mod attr {
-    pub use self::Attr::*;
-
-    /// Terminal attributes for use with term.attr().
-    ///
-    /// Most attributes can only be turned on and must be turned off with term.reset().
-    /// The ones that can be turned off explicitly take a boolean value.
-    /// Color is also represented as an attribute for convenience.
-    #[derive(Copy, Clone)]
-    pub enum Attr {
-        /// Bold (or possibly bright) mode
-        Bold,
-        /// Dim mode, also called faint or half-bright. Often not supported
-        Dim,
-        /// Italics mode. Often not supported
-        Italic(bool),
-        /// Underline mode
-        Underline(bool),
-        /// Blink mode
-        Blink,
-        /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
-        Standout(bool),
-        /// Reverse mode, inverts the foreground and background colors
-        Reverse,
-        /// Secure mode, also called invis mode. Hides the printed text
-        Secure,
-        /// Convenience attribute to set the foreground color
-        ForegroundColor(super::color::Color),
-        /// Convenience attribute to set the background color
-        BackgroundColor(super::color::Color),
-    }
+/// Terminal attributes for use with term.attr().
+///
+/// Most attributes can only be turned on and must be turned off with term.reset().
+/// The ones that can be turned off explicitly take a boolean value.
+/// Color is also represented as an attribute for convenience.
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+pub enum Attr {
+    /// Bold (or possibly bright) mode
+    Bold,
+    /// Dim mode, also called faint or half-bright. Often not supported
+    Dim,
+    /// Italics mode. Often not supported
+    Italic(bool),
+    /// Underline mode
+    Underline(bool),
+    /// Blink mode
+    Blink,
+    /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
+    Standout(bool),
+    /// Reverse mode, inverts the foreground and background colors
+    Reverse,
+    /// Secure mode, also called invis mode. Hides the printed text
+    Secure,
+    /// Convenience attribute to set the foreground color
+    ForegroundColor(color::Color),
+    /// Convenience attribute to set the background color
+    BackgroundColor(color::Color),
 }
 
 /// A terminal with similar capabilities to an ANSI Terminal
 /// (foreground/background colors etc).
-pub trait Terminal<T: Write>: Write {
+pub trait Terminal: Write {
+    /// The terminal's output writer type.
+    type Output: Write;
+
     /// Sets the foreground color to the given color.
     ///
     /// If the color is a bright color, but the terminal only supports 8 colors,
@@ -222,24 +195,29 @@ pub trait Terminal<T: Write>: Write {
     /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
     /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
     /// there was an I/O error.
-    fn attr(&mut self, attr: attr::Attr) -> io::Result<bool>;
+    fn attr(&mut self, attr: Attr) -> io::Result<bool>;
 
     /// Returns whether the given terminal attribute is supported.
-    fn supports_attr(&self, attr: attr::Attr) -> bool;
+    fn supports_attr(&self, attr: Attr) -> bool;
 
-    /// Resets all terminal attributes and color to the default.
-    /// Returns `Ok()`.
-    fn reset(&mut self) -> io::Result<()>;
+    /// Resets all terminal attributes and colors to their defaults.
+    ///
+    /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
+    /// was an I/O error.
+    ///
+    /// *Note: This does not flush.*
+    ///
+    /// That means the reset command may get buffered so, if you aren't planning on doing anything
+    /// else that might flush stdout's buffer (e.g. writing a line of text), you should flush after
+    /// calling reset.
+    fn reset(&mut self) -> io::Result<bool>;
 
     /// Gets an immutable reference to the stream inside
-    fn get_ref<'a>(&'a self) -> &'a T;
+    fn get_ref<'a>(&'a self) -> &'a Self::Output;
 
     /// Gets a mutable reference to the stream inside
-    fn get_mut<'a>(&'a mut self) -> &'a mut T;
-}
+    fn get_mut<'a>(&'a mut self) -> &'a mut Self::Output;
 
-/// A terminal which can be unwrapped.
-pub trait UnwrappableTerminal<T: Write>: Terminal<T> {
     /// Returns the contained stream, destroying the `Terminal`
-    fn unwrap(self) -> T;
+    fn into_inner(self) -> Self::Output where Self: Sized;
 }
diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs
index 89c22e555ca95..a4e5d00ee7a77 100644
--- a/src/libterm/terminfo/mod.rs
+++ b/src/libterm/terminfo/mod.rs
@@ -12,16 +12,20 @@
 
 use std::collections::HashMap;
 use std::env;
+use std::error;
+use std::fmt;
+use std::fs::File;
 use std::io::prelude::*;
 use std::io;
+use std::io::BufReader;
+use std::path::Path;
 
-use attr;
+use Attr;
 use color;
 use Terminal;
-use UnwrappableTerminal;
-use self::searcher::open;
+use self::searcher::get_dbpath_for_term;
 use self::parser::compiled::{parse, msys_terminfo};
-use self::parm::{expand, Number, Variables};
+use self::parm::{expand, Variables, Param};
 
 
 /// A parsed terminfo database entry.
@@ -37,6 +41,80 @@ pub struct TermInfo {
     pub strings: HashMap<String, Vec<u8>>,
 }
 
+/// A terminfo creation error.
+#[derive(Debug)]
+pub enum Error {
+    /// TermUnset Indicates that the environment doesn't include enough information to find
+    /// the terminfo entry.
+    TermUnset,
+    /// MalformedTerminfo indicates that parsing the terminfo entry failed.
+    MalformedTerminfo(String),
+    /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry.
+    IoError(io::Error),
+}
+
+impl error::Error for Error {
+    fn description(&self) -> &str {
+        "failed to create TermInfo"
+    }
+
+    fn cause(&self) -> Option<&error::Error> {
+        use self::Error::*;
+        match self {
+            &IoError(ref e) => Some(e),
+            _ => None,
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+        match self {
+            &TermUnset => Ok(()),
+            &MalformedTerminfo(ref e) => e.fmt(f),
+            &IoError(ref e) => e.fmt(f),
+        }
+    }
+}
+
+impl TermInfo {
+    /// Create a TermInfo based on current environment.
+    pub fn from_env() -> Result<TermInfo, Error> {
+        let term = match env::var("TERM") {
+            Ok(name) => TermInfo::from_name(&name),
+            Err(..) => return Err(Error::TermUnset),
+        };
+
+        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
+            // msys terminal
+            Ok(msys_terminfo())
+        } else {
+            term
+        }
+    }
+
+    /// Create a TermInfo for the named terminal.
+    pub fn from_name(name: &str) -> Result<TermInfo, Error> {
+        get_dbpath_for_term(name)
+            .ok_or_else(|| {
+                Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
+            })
+            .and_then(|p| TermInfo::from_path(&(*p)))
+    }
+
+    /// Parse the given TermInfo.
+    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> {
+        Self::_from_path(path.as_ref())
+    }
+    // Keep the metadata small
+    fn _from_path(path: &Path) -> Result<TermInfo, Error> {
+        let file = try!(File::open(path).map_err(|e| Error::IoError(e)));
+        let mut reader = BufReader::new(file);
+        parse(&mut reader, false).map_err(|e| Error::MalformedTerminfo(e))
+    }
+}
+
 pub mod searcher;
 
 /// TermInfo format parsing.
@@ -47,21 +125,21 @@ pub mod parser {
 pub mod parm;
 
 
-fn cap_for_attr(attr: attr::Attr) -> &'static str {
+fn cap_for_attr(attr: Attr) -> &'static str {
     match attr {
-        attr::Bold => "bold",
-        attr::Dim => "dim",
-        attr::Italic(true) => "sitm",
-        attr::Italic(false) => "ritm",
-        attr::Underline(true) => "smul",
-        attr::Underline(false) => "rmul",
-        attr::Blink => "blink",
-        attr::Standout(true) => "smso",
-        attr::Standout(false) => "rmso",
-        attr::Reverse => "rev",
-        attr::Secure => "invis",
-        attr::ForegroundColor(_) => "setaf",
-        attr::BackgroundColor(_) => "setab",
+        Attr::Bold => "bold",
+        Attr::Dim => "dim",
+        Attr::Italic(true) => "sitm",
+        Attr::Italic(false) => "ritm",
+        Attr::Underline(true) => "smul",
+        Attr::Underline(false) => "rmul",
+        Attr::Blink => "blink",
+        Attr::Standout(true) => "smso",
+        Attr::Standout(false) => "rmso",
+        Attr::Reverse => "rev",
+        Attr::Secure => "invis",
+        Attr::ForegroundColor(_) => "setaf",
+        Attr::BackgroundColor(_) => "setab",
     }
 }
 
@@ -70,23 +148,15 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
 pub struct TerminfoTerminal<T> {
     num_colors: u16,
     out: T,
-    ti: Box<TermInfo>,
+    ti: TermInfo,
 }
 
-impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
+impl<T: Write+Send> Terminal for TerminfoTerminal<T> {
+    type Output = T;
     fn fg(&mut self, color: color::Color) -> io::Result<bool> {
         let color = self.dim_if_necessary(color);
         if self.num_colors > color {
-            let s = expand(self.ti
-                               .strings
-                               .get("setaf")
-                               .unwrap(),
-                           &[Number(color as isize)],
-                           &mut Variables::new());
-            if s.is_ok() {
-                try!(self.out.write_all(&s.unwrap()));
-                return Ok(true);
-            }
+            return self.apply_cap("setaf", &[Param::Number(color as i32)]);
         }
         Ok(false)
     }
@@ -94,42 +164,22 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
     fn bg(&mut self, color: color::Color) -> io::Result<bool> {
         let color = self.dim_if_necessary(color);
         if self.num_colors > color {
-            let s = expand(self.ti
-                               .strings
-                               .get("setab")
-                               .unwrap(),
-                           &[Number(color as isize)],
-                           &mut Variables::new());
-            if s.is_ok() {
-                try!(self.out.write_all(&s.unwrap()));
-                return Ok(true);
-            }
+            return self.apply_cap("setab", &[Param::Number(color as i32)]);
         }
         Ok(false)
     }
 
-    fn attr(&mut self, attr: attr::Attr) -> io::Result<bool> {
+    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
         match attr {
-            attr::ForegroundColor(c) => self.fg(c),
-            attr::BackgroundColor(c) => self.bg(c),
-            _ => {
-                let cap = cap_for_attr(attr);
-                let parm = self.ti.strings.get(cap);
-                if parm.is_some() {
-                    let s = expand(parm.unwrap(), &[], &mut Variables::new());
-                    if s.is_ok() {
-                        try!(self.out.write_all(&s.unwrap()));
-                        return Ok(true);
-                    }
-                }
-                Ok(false)
-            }
+            Attr::ForegroundColor(c) => self.fg(c),
+            Attr::BackgroundColor(c) => self.bg(c),
+            _ => self.apply_cap(cap_for_attr(attr), &[]),
         }
     }
 
-    fn supports_attr(&self, attr: attr::Attr) -> bool {
+    fn supports_attr(&self, attr: Attr) -> bool {
         match attr {
-            attr::ForegroundColor(_) | attr::BackgroundColor(_) => self.num_colors > 0,
+            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0,
             _ => {
                 let cap = cap_for_attr(attr);
                 self.ti.strings.get(cap).is_some()
@@ -137,22 +187,22 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
         }
     }
 
-    fn reset(&mut self) -> io::Result<()> {
-        let mut cap = self.ti.strings.get("sgr0");
-        if cap.is_none() {
-            // are there any terminals that have color/attrs and not sgr0?
-            // Try falling back to sgr, then op
-            cap = self.ti.strings.get("sgr");
-            if cap.is_none() {
-                cap = self.ti.strings.get("op");
+    fn reset(&mut self) -> io::Result<bool> {
+        // are there any terminals that have color/attrs and not sgr0?
+        // Try falling back to sgr, then op
+        let cmd = match ["sg0", "sgr", "op"]
+                            .iter()
+                            .filter_map(|cap| self.ti.strings.get(*cap))
+                            .next() {
+            Some(op) => {
+                match expand(&op, &[], &mut Variables::new()) {
+                    Ok(cmd) => cmd,
+                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
+                }
             }
-        }
-        let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_owned()),
-                           |op| expand(op, &[], &mut Variables::new()));
-        if s.is_ok() {
-            return self.out.write_all(&s.unwrap());
-        }
-        Ok(())
+            None => return Ok(false),
+        };
+        self.out.write_all(&cmd).and(Ok(true))
     }
 
     fn get_ref<'a>(&'a self) -> &'a T {
@@ -162,64 +212,36 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
     fn get_mut<'a>(&'a mut self) -> &'a mut T {
         &mut self.out
     }
-}
 
-impl<T: Write+Send+'static> UnwrappableTerminal<T> for TerminfoTerminal<T> {
-    fn unwrap(self) -> T {
+    fn into_inner(self) -> T
+        where Self: Sized
+    {
         self.out
     }
 }
 
-impl<T: Write+Send+'static> TerminfoTerminal<T> {
-    /// Returns `None` whenever the terminal cannot be created for some
-    /// reason.
-    pub fn new(out: T) -> Option<Box<Terminal<T> + Send + 'static>> {
-        let term = match env::var("TERM") {
-            Ok(t) => t,
-            Err(..) => {
-                debug!("TERM environment variable not defined");
-                return None;
-            }
-        };
-
-        let mut file = match open(&term[..]) {
-            Ok(f) => f,
-            Err(err) => {
-                return match env::var("MSYSCON") {
-                    Ok(ref val) if &val[..] == "mintty.exe" => {
-                        // msys terminal
-                        Some(box TerminfoTerminal {
-                            out: out,
-                            ti: msys_terminfo(),
-                            num_colors: 8,
-                        })
-                    }
-                    _ => {
-                        debug!("error finding terminfo entry: {:?}", err);
-                        None
-                    }
-                };
-            }
-        };
-
-        let ti = parse(&mut file, false);
-        if ti.is_err() {
-            debug!("error parsing terminfo entry: {:?}", ti.err().unwrap());
-            return None;
-        }
-
-        let inf = ti.unwrap();
-        let nc = if inf.strings.get("setaf").is_some() && inf.strings.get("setab").is_some() {
-            inf.numbers.get("colors").map_or(0, |&n| n)
+impl<T: Write+Send> TerminfoTerminal<T> {
+    /// Create a new TerminfoTerminal with the given TermInfo and Write.
+    pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
+        let nc = if terminfo.strings.contains_key("setaf") &&
+                    terminfo.strings.contains_key("setab") {
+            terminfo.numbers.get("colors").map_or(0, |&n| n)
         } else {
             0
         };
 
-        Some(box TerminfoTerminal {
+        TerminfoTerminal {
             out: out,
-            ti: inf,
+            ti: terminfo,
             num_colors: nc,
-        })
+        }
+    }
+
+    /// Create a new TerminfoTerminal for the current environment with the given Write.
+    ///
+    /// Returns `None` when the terminfo cannot be found or parsed.
+    pub fn new(out: T) -> Option<TerminfoTerminal<T>> {
+        TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
     }
 
     fn dim_if_necessary(&self, color: color::Color) -> color::Color {
@@ -229,6 +251,18 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
             color
         }
     }
+
+    fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> {
+        match self.ti.strings.get(cmd) {
+            Some(cmd) => {
+                match expand(&cmd, params, &mut Variables::new()) {
+                    Ok(s) => self.out.write_all(&s).and(Ok(true)),
+                    Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
+                }
+            }
+            None => Ok(false),
+        }
+    }
 }
 
 
diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs
index 49db096ce7332..aceaa0c10bcce 100644
--- a/src/libterm/terminfo/parm.rs
+++ b/src/libterm/terminfo/parm.rs
@@ -10,15 +10,14 @@
 
 //! Parameterized string expansion
 
-pub use self::Param::*;
+use self::Param::*;
 use self::States::*;
 use self::FormatState::*;
 use self::FormatOp::*;
-use std::ascii::AsciiExt;
-use std::mem::replace;
+
 use std::iter::repeat;
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Clone, Copy, PartialEq)]
 enum States {
     Nothing,
     Percent,
@@ -27,15 +26,15 @@ enum States {
     PushParam,
     CharConstant,
     CharClose,
-    IntConstant(isize),
+    IntConstant(i32),
     FormatPattern(Flags, FormatState),
-    SeekIfElse(isize),
-    SeekIfElsePercent(isize),
-    SeekIfEnd(isize),
-    SeekIfEndPercent(isize),
+    SeekIfElse(usize),
+    SeekIfElsePercent(usize),
+    SeekIfEnd(usize),
+    SeekIfEndPercent(usize),
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, PartialEq, Clone)]
 enum FormatState {
     FormatStateFlags,
     FormatStateWidth,
@@ -47,7 +46,7 @@ enum FormatState {
 #[derive(Clone)]
 pub enum Param {
     Words(String),
-    Number(isize),
+    Number(i32),
 }
 
 /// Container for static and dynamic variable arrays
@@ -94,11 +93,11 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
     // Copy parameters into a local vector for mutability
     let mut mparams = [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
                        Number(0), Number(0), Number(0)];
-    for (dst, src) in mparams.iter_mut().zip(params) {
+    for (dst, src) in mparams.iter_mut().zip(params.iter()) {
         *dst = (*src).clone();
     }
 
-    for &c in cap {
+    for &c in cap.iter() {
         let cur = c as char;
         let mut old_state = state;
         match state {
@@ -116,20 +115,13 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                         state = Nothing
                     }
                     'c' => {
-                        if !stack.is_empty() {
-                            match stack.pop().unwrap() {
-                                // if c is 0, use 0200 (128) for ncurses compatibility
-                                Number(c) => {
-                                    output.push(if c == 0 {
-                                        128
-                                    } else {
-                                        c as u8
-                                    })
-                                }
-                                _ => return Err("a non-char was used with %c".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                        match stack.pop() {
+                            // if c is 0, use 0200 (128) for ncurses compatibility
+                            Some(Number(0)) => output.push(128u8),
+                            // Don't check bounds. ncurses just casts and truncates.
+                            Some(Number(c)) => output.push(c as u8),
+                            Some(_) => return Err("a non-char was used with %c".to_string()),
+                            None => return Err("stack is empty".to_string()),
                         }
                     }
                     'p' => state = PushParam,
@@ -138,208 +130,89 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                     '\'' => state = CharConstant,
                     '{' => state = IntConstant(0),
                     'l' => {
-                        if !stack.is_empty() {
-                            match stack.pop().unwrap() {
-                                Words(s) => stack.push(Number(s.len() as isize)),
-                                _ => return Err("a non-str was used with %l".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '+' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x + y)),
-                                _ => return Err("non-numbers on stack with +".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '-' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x - y)),
-                                _ => return Err("non-numbers on stack with -".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '*' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x * y)),
-                                _ => return Err("non-numbers on stack with *".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '/' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x / y)),
-                                _ => return Err("non-numbers on stack with /".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    'm' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x % y)),
-                                _ => return Err("non-numbers on stack with %".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '&' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x & y)),
-                                _ => return Err("non-numbers on stack with &".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '|' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x | y)),
-                                _ => return Err("non-numbers on stack with |".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '^' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => stack.push(Number(x ^ y)),
-                                _ => return Err("non-numbers on stack with ^".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                        match stack.pop() {
+                            Some(Words(s)) => stack.push(Number(s.len() as i32)),
+                            Some(_) => return Err("a non-str was used with %l".to_string()),
+                            None => return Err("stack is empty".to_string()),
                         }
                     }
-                    '=' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => {
-                                    stack.push(Number(if x == y {
-                                        1
-                                    } else {
-                                        0
-                                    }))
-                                }
-                                _ => return Err("non-numbers on stack with =".to_owned()),
+                    '+' | '-' | '/' | '*' | '^' | '&' | '|' | 'm' => {
+                        match (stack.pop(), stack.pop()) {
+                            (Some(Number(y)), Some(Number(x))) => {
+                                stack.push(Number(match cur {
+                                    '+' => x + y,
+                                    '-' => x - y,
+                                    '*' => x * y,
+                                    '/' => x / y,
+                                    '|' => x | y,
+                                    '&' => x & y,
+                                    '^' => x ^ y,
+                                    'm' => x % y,
+                                    _ => unreachable!("All cases handled"),
+                                }))
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '>' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => {
-                                    stack.push(Number(if x > y {
-                                        1
-                                    } else {
-                                        0
-                                    }))
-                                }
-                                _ => return Err("non-numbers on stack with >".to_owned()),
+                            (Some(_), Some(_)) => {
+                                return Err(format!("non-numbers on stack with {}", cur))
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                            _ => return Err("stack is empty".to_string()),
                         }
                     }
-                    '<' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(y), Number(x)) => {
-                                    stack.push(Number(if x < y {
-                                        1
-                                    } else {
-                                        0
-                                    }))
-                                }
-                                _ => return Err("non-numbers on stack with <".to_owned()),
+                    '=' | '>' | '<' | 'A' | 'O' => {
+                        match (stack.pop(), stack.pop()) {
+                            (Some(Number(y)), Some(Number(x))) => {
+                                stack.push(Number(if match cur {
+                                    '=' => x == y,
+                                    '<' => x < y,
+                                    '>' => x > y,
+                                    'A' => x > 0 && y > 0,
+                                    'O' => x > 0 || y > 0,
+                                    _ => unreachable!(),
+                                } {
+                                    1
+                                } else {
+                                    0
+                                }))
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    'A' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(0), Number(_)) => stack.push(Number(0)),
-                                (Number(_), Number(0)) => stack.push(Number(0)),
-                                (Number(_), Number(_)) => stack.push(Number(1)),
-                                _ => return Err("non-numbers on stack with logical and".to_owned()),
+                            (Some(_), Some(_)) => {
+                                return Err(format!("non-numbers on stack with {}", cur))
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                            _ => return Err("stack is empty".to_string()),
                         }
                     }
-                    'O' => {
-                        if stack.len() > 1 {
-                            match (stack.pop().unwrap(), stack.pop().unwrap()) {
-                                (Number(0), Number(0)) => stack.push(Number(0)),
-                                (Number(_), Number(_)) => stack.push(Number(1)),
-                                _ => return Err("non-numbers on stack with logical or".to_owned()),
+                    '!' | '~' => {
+                        match stack.pop() {
+                            Some(Number(x)) => {
+                                stack.push(Number(match cur {
+                                    '!' if x > 0 => 0,
+                                    '!' => 1,
+                                    '~' => !x,
+                                    _ => unreachable!(),
+                                }))
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '!' => {
-                        if !stack.is_empty() {
-                            match stack.pop().unwrap() {
-                                Number(0) => stack.push(Number(1)),
-                                Number(_) => stack.push(Number(0)),
-                                _ => return Err("non-number on stack with logical not".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
-                        }
-                    }
-                    '~' => {
-                        if !stack.is_empty() {
-                            match stack.pop().unwrap() {
-                                Number(x) => stack.push(Number(!x)),
-                                _ => return Err("non-number on stack with %~".to_owned()),
-                            }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                            Some(_) => return Err(format!("non-numbers on stack with {}", cur)),
+                            None => return Err("stack is empty".to_string()),
                         }
                     }
                     'i' => {
-                        match (mparams[0].clone(), mparams[1].clone()) {
-                            (Number(x), Number(y)) => {
+                        match (&mparams[0], &mparams[1]) {
+                            (&Number(x), &Number(y)) => {
                                 mparams[0] = Number(x + 1);
                                 mparams[1] = Number(y + 1);
                             }
-                            (_, _) => return Err("first two params not numbers with %i".to_owned()),
+                            (_, _) => {
+                                return Err("first two params not numbers with %i".to_string())
+                            }
                         }
                     }
 
                     // printf-style support for %doxXs
                     'd' | 'o' | 'x' | 'X' | 's' => {
-                        if !stack.is_empty() {
+                        if let Some(arg) = stack.pop() {
                             let flags = Flags::new();
-                            let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
-                            if res.is_err() {
-                                return res;
-                            }
-                            output.push_all(&res.unwrap())
+                            let res = try!(format(arg, FormatOp::from_char(cur), flags));
+                            output.extend(res.iter().map(|x| *x));
                         } else {
-                            return Err("stack is empty".to_owned());
+                            return Err("stack is empty".to_string());
                         }
                     }
                     ':' | '#' | ' ' | '.' | '0'...'9' => {
@@ -362,47 +235,45 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                     // conditionals
                     '?' => (),
                     't' => {
-                        if !stack.is_empty() {
-                            match stack.pop().unwrap() {
-                                Number(0) => state = SeekIfElse(0),
-                                Number(_) => (),
-                                _ => return Err("non-number on stack with conditional".to_owned()),
+                        match stack.pop() {
+                            Some(Number(0)) => state = SeekIfElse(0),
+                            Some(Number(_)) => (),
+                            Some(_) => {
+                                return Err("non-number on stack with conditional".to_string())
                             }
-                        } else {
-                            return Err("stack is empty".to_owned());
+                            None => return Err("stack is empty".to_string()),
                         }
                     }
                     'e' => state = SeekIfEnd(0),
                     ';' => (),
-
-                    _ => return Err(format!("unrecognized format option {:?}", cur)),
+                    _ => return Err(format!("unrecognized format option {}", cur)),
                 }
             }
             PushParam => {
                 // params are 1-indexed
                 stack.push(mparams[match cur.to_digit(10) {
                                Some(d) => d as usize - 1,
-                               None => return Err("bad param number".to_owned()),
+                               None => return Err("bad param number".to_string()),
                            }]
                            .clone());
             }
             SetVar => {
                 if cur >= 'A' && cur <= 'Z' {
-                    if !stack.is_empty() {
+                    if let Some(arg) = stack.pop() {
                         let idx = (cur as u8) - b'A';
-                        vars.sta[idx as usize] = stack.pop().unwrap();
+                        vars.sta[idx as usize] = arg;
                     } else {
-                        return Err("stack is empty".to_owned());
+                        return Err("stack is empty".to_string());
                     }
                 } else if cur >= 'a' && cur <= 'z' {
-                    if !stack.is_empty() {
+                    if let Some(arg) = stack.pop() {
                         let idx = (cur as u8) - b'a';
-                        vars.dyn[idx as usize] = stack.pop().unwrap();
+                        vars.dyn[idx as usize] = arg;
                     } else {
-                        return Err("stack is empty".to_owned());
+                        return Err("stack is empty".to_string());
                     }
                 } else {
-                    return Err("bad variable name in %P".to_owned());
+                    return Err("bad variable name in %P".to_string());
                 }
             }
             GetVar => {
@@ -413,47 +284,45 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                     let idx = (cur as u8) - b'a';
                     stack.push(vars.dyn[idx as usize].clone());
                 } else {
-                    return Err("bad variable name in %g".to_owned());
+                    return Err("bad variable name in %g".to_string());
                 }
             }
             CharConstant => {
-                stack.push(Number(c as isize));
+                stack.push(Number(c as i32));
                 state = CharClose;
             }
             CharClose => {
                 if cur != '\'' {
-                    return Err("malformed character constant".to_owned());
+                    return Err("malformed character constant".to_string());
                 }
             }
             IntConstant(i) => {
-                match cur {
-                    '}' => {
-                        stack.push(Number(i));
-                        state = Nothing;
-                    }
-                    '0'...'9' => {
-                        state = IntConstant(i * 10 + (cur as isize - '0' as isize));
-                        old_state = Nothing;
+                if cur == '}' {
+                    stack.push(Number(i));
+                    state = Nothing;
+                } else if let Some(digit) = cur.to_digit(10) {
+                    match i.checked_mul(10).and_then(|i_ten| i_ten.checked_add(digit as i32)) {
+                        Some(i) => {
+                            state = IntConstant(i);
+                            old_state = Nothing;
+                        }
+                        None => return Err("int constant too large".to_string()),
                     }
-                    _ => return Err("bad isize constant".to_owned()),
+                } else {
+                    return Err("bad int constant".to_string());
                 }
             }
             FormatPattern(ref mut flags, ref mut fstate) => {
                 old_state = Nothing;
                 match (*fstate, cur) {
                     (_, 'd') | (_, 'o') | (_, 'x') | (_, 'X') | (_, 's') => {
-                        if !stack.is_empty() {
-                            let res = format(stack.pop().unwrap(),
-                                             FormatOp::from_char(cur),
-                                             *flags);
-                            if res.is_err() {
-                                return res;
-                            }
-                            output.push_all(&res.unwrap());
+                        if let Some(arg) = stack.pop() {
+                            let res = try!(format(arg, FormatOp::from_char(cur), *flags));
+                            output.extend(res.iter().map(|x| *x));
                             // will cause state to go to Nothing
                             old_state = FormatPattern(*flags, *fstate);
                         } else {
-                            return Err("stack is empty".to_owned());
+                            return Err("stack is empty".to_string());
                         }
                     }
                     (FormatStateFlags, '#') => {
@@ -479,7 +348,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                         let old = flags.width;
                         flags.width = flags.width * 10 + (cur as usize - '0' as usize);
                         if flags.width < old {
-                            return Err("format width overflow".to_owned());
+                            return Err("format width overflow".to_string());
                         }
                     }
                     (FormatStateWidth, '.') => {
@@ -489,10 +358,10 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
                         let old = flags.precision;
                         flags.precision = flags.precision * 10 + (cur as usize - '0' as usize);
                         if flags.precision < old {
-                            return Err("format precision overflow".to_owned());
+                            return Err("format precision overflow".to_string());
                         }
                     }
-                    _ => return Err("invalid format specifier".to_owned()),
+                    _ => return Err("invalid format specifier".to_string()),
                 }
             }
             SeekIfElse(level) => {
@@ -543,7 +412,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
     Ok(output)
 }
 
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, PartialEq, Clone)]
 struct Flags {
     width: usize,
     precision: usize,
@@ -600,61 +469,55 @@ impl FormatOp {
 fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
     let mut s = match val {
         Number(d) => {
-            let s = match (op, flags.sign) {
-                (FormatDigit, true) => format!("{:+}", d).into_bytes(),
-                (FormatDigit, false) => format!("{}", d).into_bytes(),
-                (FormatOctal, _) => format!("{:o}", d).into_bytes(),
-                (FormatHex, _) => format!("{:x}", d).into_bytes(),
-                (FormatHEX, _) => format!("{:X}", d).into_bytes(),
-                (FormatString, _) => return Err("non-number on stack with %s".to_owned()),
-            };
-            let mut s: Vec<u8> = s.into_iter().collect();
-            if flags.precision > s.len() {
-                let mut s_ = Vec::with_capacity(flags.precision);
-                let n = flags.precision - s.len();
-                s_.extend(repeat(b'0').take(n));
-                s_.extend(s);
-                s = s_;
-            }
-            assert!(!s.is_empty(), "string conversion produced empty result");
             match op {
                 FormatDigit => {
-                    if flags.space && !(s[0] == b'-' || s[0] == b'+') {
-                        s.insert(0, b' ');
+                    if flags.sign {
+                        format!("{:+01$}", d, flags.precision)
+                    } else if d < 0 {
+                        // C doesn't take sign into account in precision calculation.
+                        format!("{:01$}", d, flags.precision + 1)
+                    } else if flags.space {
+                        format!(" {:01$}", d, flags.precision)
+                    } else {
+                        format!("{:01$}", d, flags.precision)
                     }
                 }
                 FormatOctal => {
-                    if flags.alternate && s[0] != b'0' {
-                        s.insert(0, b'0');
+                    if flags.alternate {
+                        // Leading octal zero counts against precision.
+                        format!("0{:01$o}", d, flags.precision.saturating_sub(1))
+                    } else {
+                        format!("{:01$o}", d, flags.precision)
                     }
                 }
                 FormatHex => {
-                    if flags.alternate {
-                        let s_ = replace(&mut s, vec![b'0', b'x']);
-                        s.extend(s_);
+                    if flags.alternate && d != 0 {
+                        format!("0x{:01$x}", d, flags.precision)
+                    } else {
+                        format!("{:01$x}", d, flags.precision)
                     }
                 }
                 FormatHEX => {
-                    s = s.to_ascii_uppercase();
-                    if flags.alternate {
-                        let s_ = replace(&mut s, vec![b'0', b'X']);
-                        s.extend(s_);
+                    if flags.alternate && d != 0 {
+                        format!("0X{:01$X}", d, flags.precision)
+                    } else {
+                        format!("{:01$X}", d, flags.precision)
                     }
                 }
-                FormatString => unreachable!(),
+                FormatString => return Err("non-number on stack with %s".to_string()),
             }
-            s
+            .into_bytes()
         }
         Words(s) => {
             match op {
                 FormatString => {
-                    let mut s = s.as_bytes().to_vec();
+                    let mut s = s.into_bytes();
                     if flags.precision > 0 && flags.precision < s.len() {
                         s.truncate(flags.precision);
                     }
                     s
                 }
-                _ => return Err(format!("non-string on stack with %{:?}", op.to_char())),
+                _ => return Err(format!("non-string on stack with %{}", op.to_char())),
             }
         }
     };
@@ -665,7 +528,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
         } else {
             let mut s_ = Vec::with_capacity(flags.width);
             s_.extend(repeat(b' ').take(n));
-            s_.extend(s);
+            s_.extend(s.into_iter());
             s = s_;
         }
     }
@@ -673,8 +536,9 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
 }
 
 #[cfg(test)]
-mod tests {
-    use super::{expand, Param, Words, Variables, Number};
+mod test {
+    use super::{expand, Variables};
+    use super::Param::{self, Words, Number};
     use std::result::Result::Ok;
 
     #[test]
@@ -711,12 +575,12 @@ mod tests {
                    vars: &mut Variables)
                    -> Result<Vec<u8>, String> {
             let mut u8v: Vec<_> = fmt.bytes().collect();
-            u8v.extend(cap.bytes());
+            u8v.extend(cap.as_bytes().iter().map(|&b| b));
             expand(&u8v, params, vars)
         }
 
         let caps = ["%d", "%c", "%s", "%Pa", "%l", "%!", "%~"];
-        for &cap in &caps {
+        for &cap in caps.iter() {
             let res = get_res("", cap, &[], vars);
             assert!(res.is_err(),
                     "Op {} succeeded incorrectly with 0 stack entries",
@@ -733,7 +597,7 @@ mod tests {
                     res.err().unwrap());
         }
         let caps = ["%+", "%-", "%*", "%/", "%m", "%&", "%|", "%A", "%O"];
-        for &cap in &caps {
+        for &cap in caps.iter() {
             let res = expand(cap.as_bytes(), &[], vars);
             assert!(res.is_err(),
                     "Binop {} succeeded incorrectly with 0 stack entries",
@@ -744,7 +608,7 @@ mod tests {
                     cap);
             let res = get_res("%{1}%{2}", cap, &[], vars);
             assert!(res.is_ok(),
-                    "Binop {} failed with 2 stack entries: {:?}",
+                    "Binop {} failed with 2 stack entries: {}",
                     cap,
                     res.err().unwrap());
         }
@@ -757,20 +621,20 @@ mod tests {
 
     #[test]
     fn test_comparison_ops() {
-        let v = [('<', [1, 0, 0]), ('=', [0, 1, 0]), ('>', [0, 0, 1])];
-        for &(op, bs) in &v {
+        let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])];
+        for &(op, bs) in v.iter() {
             let s = format!("%{{1}}%{{2}}%{}%d", op);
             let res = expand(s.as_bytes(), &[], &mut Variables::new());
             assert!(res.is_ok(), res.err().unwrap());
-            assert_eq!(res.unwrap(), [b'0' + bs[0]]);
+            assert_eq!(res.unwrap(), vec![b'0' + bs[0]]);
             let s = format!("%{{1}}%{{1}}%{}%d", op);
             let res = expand(s.as_bytes(), &[], &mut Variables::new());
             assert!(res.is_ok(), res.err().unwrap());
-            assert_eq!(res.unwrap(), [b'0' + bs[1]]);
+            assert_eq!(res.unwrap(), vec![b'0' + bs[1]]);
             let s = format!("%{{2}}%{{1}}%{}%d", op);
             let res = expand(s.as_bytes(), &[], &mut Variables::new());
             assert!(res.is_ok(), res.err().unwrap());
-            assert_eq!(res.unwrap(), [b'0' + bs[2]]);
+            assert_eq!(res.unwrap(), vec![b'0' + bs[2]]);
         }
     }
 
@@ -800,7 +664,7 @@ mod tests {
                             Words("foo".to_string())],
                           vars),
                    Ok("foofoo ffo".bytes().collect::<Vec<_>>()));
-        assert_eq!(expand(b"%p1%:-4.2s", &[Words("foo".to_owned())], vars),
+        assert_eq!(expand(b"%p1%:-4.2s", &[Words("foo".to_string())], vars),
                    Ok("fo  ".bytes().collect::<Vec<_>>()));
 
         assert_eq!(expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars),
diff --git a/src/libterm/terminfo/parser/compiled.rs b/src/libterm/terminfo/parser/compiled.rs
index 7c8d9983e78f5..558d35c2ae27b 100644
--- a/src/libterm/terminfo/parser/compiled.rs
+++ b/src/libterm/terminfo/parser/compiled.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(non_upper_case_globals)]
+#![allow(non_upper_case_globals, missing_docs)]
 
 //! ncurses-compatible compiled terminfo format parsing (term(5))
 
@@ -20,7 +20,6 @@ use super::super::TermInfo;
 // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable.
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static boolfnames: &'static[&'static str] = &["auto_left_margin", "auto_right_margin",
     "no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type",
     "hard_copy", "has_meta_key", "has_status_line", "insert_null_glitch", "memory_above",
@@ -34,14 +33,12 @@ pub static boolfnames: &'static[&'static str] = &["auto_left_margin", "auto_righ
     "return_does_clr_eol"];
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static boolnames: &'static[&'static str] = &["bw", "am", "xsb", "xhp", "xenl", "eo",
     "gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon",
     "nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy",
     "xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"];
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static numfnames: &'static[&'static str] = &[ "columns", "init_tabs", "lines",
     "lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal",
     "width_status_line", "num_labels", "label_height", "label_width", "max_attributes",
@@ -53,14 +50,12 @@ pub static numfnames: &'static[&'static str] = &[ "columns", "init_tabs", "lines
     "new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"];
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static numnames: &'static[&'static str] = &[ "cols", "it", "lines", "lm", "xmc", "pb",
     "vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv",
     "spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs",
     "btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"];
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static stringfnames: &'static[&'static str] = &[ "back_tab", "bell", "carriage_return",
     "change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos",
     "column_address", "command_character", "cursor_address", "cursor_down", "cursor_home",
@@ -135,7 +130,6 @@ pub static stringfnames: &'static[&'static str] = &[ "back_tab", "bell", "carria
     "acs_plus", "memory_lock", "memory_unlock", "box_chars_1"];
 
 #[rustfmt_skip]
-#[allow(missing_docs)]
 pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear",
     "_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1",
     "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl", "hd", "smacs", "blink", "bold", "smcup", "smdc",
@@ -170,114 +164,132 @@ pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tb
     "OTG3", "OTG1", "OTG4", "OTGR", "OTGL", "OTGU", "OTGD", "OTGH", "OTGV", "OTGC", "meml", "memu",
     "box1"];
 
-/// Parse a compiled terminfo entry, using long capability names if `longnames` is true
-pub fn parse(file: &mut Read, longnames: bool) -> Result<Box<TermInfo>, String> {
-    macro_rules! try { ($e:expr) => (
+fn read_le_u16(r: &mut io::Read) -> io::Result<u16> {
+    let mut b = [0; 2];
+    let mut amt = 0;
+    while amt < b.len() {
+        match try!(r.read(&mut b[amt..])) {
+            0 => return Err(io::Error::new(io::ErrorKind::Other, "end of file")),
+            n => amt += n,
+        }
+    }
+    Ok((b[0] as u16) | ((b[1] as u16) << 8))
+}
+
+fn read_byte(r: &mut io::Read) -> io::Result<u8> {
+    match r.bytes().next() {
+        Some(s) => s,
+        None => Err(io::Error::new(io::ErrorKind::Other, "end of file")),
+    }
+}
+
+/// Parse a compiled terminfo entry, using long capability names if `longnames`
+/// is true
+pub fn parse(file: &mut io::Read, longnames: bool) -> Result<TermInfo, String> {
+    macro_rules! try( ($e:expr) => (
         match $e {
             Ok(e) => e,
-            Err(e) => return Err(format!("{:?}", e))
+            Err(e) => return Err(format!("{}", e))
         }
-    ) }
+    ) );
 
-    let bnames;
-    let snames;
-    let nnames;
-
-    if longnames {
-        bnames = boolfnames;
-        snames = stringfnames;
-        nnames = numfnames;
+    let (bnames, snames, nnames) = if longnames {
+        (boolfnames, stringfnames, numfnames)
     } else {
-        bnames = boolnames;
-        snames = stringnames;
-        nnames = numnames;
-    }
+        (boolnames, stringnames, numnames)
+    };
 
     // Check magic number
     let magic = try!(read_le_u16(file));
     if magic != 0x011A {
         return Err(format!("invalid magic number: expected {:x}, found {:x}",
-                           0x011A_usize,
-                           magic as usize));
+                           0x011A,
+                           magic));
     }
 
-    let names_bytes = try!(read_le_u16(file)) as isize;
-    let bools_bytes = try!(read_le_u16(file)) as isize;
-    let numbers_count = try!(read_le_u16(file)) as isize;
-    let string_offsets_count = try!(read_le_u16(file)) as isize;
-    let string_table_bytes = try!(read_le_u16(file)) as isize;
+    // According to the spec, these fields must be >= -1 where -1 means that the feature is not
+    // supported. Using 0 instead of -1 works because we skip sections with length 0.
+    macro_rules! read_nonneg {
+        () => {{
+            match try!(read_le_u16(file)) as i16 {
+                n if n >= 0 => n as usize,
+                -1 => 0,
+                _ => return Err("incompatible file: length fields must be  >= -1".to_string()),
+            }
+        }}
+    }
+
+    let names_bytes = read_nonneg!();
+    let bools_bytes = read_nonneg!();
+    let numbers_count = read_nonneg!();
+    let string_offsets_count = read_nonneg!();
+    let string_table_bytes = read_nonneg!();
 
-    assert!(names_bytes > 0);
+    if names_bytes == 0 {
+        return Err("incompatible file: names field must be at least 1 byte wide".to_string());
+    }
 
-    if (bools_bytes as usize) > boolnames.len() {
-        return Err("incompatible file: more booleans than expected".to_owned());
+    if bools_bytes > boolnames.len() {
+        return Err("incompatible file: more booleans than expected".to_string());
     }
 
-    if (numbers_count as usize) > numnames.len() {
-        return Err("incompatible file: more numbers than expected".to_owned());
+    if numbers_count > numnames.len() {
+        return Err("incompatible file: more numbers than expected".to_string());
     }
 
-    if (string_offsets_count as usize) > stringnames.len() {
-        return Err("incompatible file: more string offsets than expected".to_owned());
+    if string_offsets_count > stringnames.len() {
+        return Err("incompatible file: more string offsets than expected".to_string());
     }
 
     // don't read NUL
-    let bytes = try!(read_exact(file, names_bytes as usize - 1));
+    let mut bytes = Vec::new();
+    try!(file.take((names_bytes - 1) as u64).read_to_end(&mut bytes));
     let names_str = match String::from_utf8(bytes) {
         Ok(s) => s,
-        Err(_) => return Err("input not utf-8".to_owned()),
+        Err(_) => return Err("input not utf-8".to_string()),
     };
 
     let term_names: Vec<String> = names_str.split('|')
-                                           .map(str::to_owned)
+                                           .map(|s| s.to_string())
                                            .collect();
-
-    try!(read_byte(file)); // consume NUL
-
-    let mut bools_map = HashMap::new();
-    if bools_bytes != 0 {
-        for i in 0..bools_bytes {
-            let b = try!(read_byte(file));
-            if b == 1 {
-                bools_map.insert(bnames[i as usize].to_owned(), true);
-            }
-        }
+    // consume NUL
+    if try!(read_byte(file)) != b'\0' {
+        return Err("incompatible file: missing null terminator for names section".to_string());
     }
 
+    let bools_map: HashMap<String, bool> = try! {
+        (0..bools_bytes).filter_map(|i| match read_byte(file) {
+            Err(e) => Some(Err(e)),
+            Ok(1) => Some(Ok((bnames[i].to_string(), true))),
+            Ok(_) => None
+        }).collect()
+    };
+
     if (bools_bytes + names_bytes) % 2 == 1 {
         try!(read_byte(file)); // compensate for padding
     }
 
-    let mut numbers_map = HashMap::new();
-    if numbers_count != 0 {
-        for i in 0..numbers_count {
-            let n = try!(read_le_u16(file));
-            if n != 0xFFFF {
-                numbers_map.insert(nnames[i as usize].to_owned(), n);
-            }
-        }
-    }
-
-    let mut string_map = HashMap::new();
-
-    if string_offsets_count != 0 {
-        let mut string_offsets = Vec::with_capacity(10);
-        for _ in 0..string_offsets_count {
-            string_offsets.push(try!(read_le_u16(file)));
-        }
+    let numbers_map: HashMap<String, u16> = try! {
+        (0..numbers_count).filter_map(|i| match read_le_u16(file) {
+            Ok(0xFFFF) => None,
+            Ok(n) => Some(Ok((nnames[i].to_string(), n))),
+            Err(e) => Some(Err(e))
+        }).collect()
+    };
 
-        let string_table = try!(read_exact(file, string_table_bytes as usize));
+    let string_map: HashMap<String, Vec<u8>> = if string_offsets_count > 0 {
+        let string_offsets: Vec<u16> = try!((0..string_offsets_count)
+                                                .map(|_| read_le_u16(file))
+                                                .collect());
 
-        if string_table.len() != string_table_bytes as usize {
-            return Err("error: hit EOF before end of string table".to_owned());
-        }
+        let mut string_table = Vec::new();
+        try!(file.take(string_table_bytes as u64).read_to_end(&mut string_table));
 
-        for (i, v) in string_offsets.iter().enumerate() {
-            let offset = *v;
-            if offset == 0xFFFF {
-                // non-entry
-                continue;
-            }
+        try!(string_offsets.into_iter().enumerate().filter(|&(_, offset)| {
+            // non-entry
+            offset != 0xFFFF
+        }).map(|(i, offset)| {
+            let offset = offset as usize;
 
             let name = if snames[i] == "_" {
                 stringfnames[i]
@@ -288,30 +300,22 @@ pub fn parse(file: &mut Read, longnames: bool) -> Result<Box<TermInfo>, String>
             if offset == 0xFFFE {
                 // undocumented: FFFE indicates cap@, which means the capability is not present
                 // unsure if the handling for this is correct
-                string_map.insert(name.to_owned(), Vec::new());
-                continue;
+                return Ok((name.to_string(), Vec::new()));
             }
 
-
             // Find the offset of the NUL we want to go to
-            let nulpos = string_table[offset as usize..string_table_bytes as usize]
-                             .iter()
-                             .position(|&b| b == 0);
+            let nulpos = string_table[offset..string_table_bytes].iter().position(|&b| b == 0);
             match nulpos {
-                Some(len) => {
-                    string_map.insert(name.to_string(),
-                                      string_table[offset as usize..(offset as usize + len)]
-                                          .to_vec())
-                }
-                None => {
-                    return Err("invalid file: missing NUL in string_table".to_owned());
-                }
-            };
-        }
-    }
+                Some(len) => Ok((name.to_string(), string_table[offset..offset + len].to_vec())),
+                None => Err("invalid file: missing NUL in string_table".to_string()),
+            }
+        }).collect())
+    } else {
+        HashMap::new()
+    };
 
     // And that's all there is to it
-    Ok(box TermInfo {
+    Ok(TermInfo {
         names: term_names,
         bools: bools_map,
         numbers: numbers_map,
@@ -319,42 +323,27 @@ pub fn parse(file: &mut Read, longnames: bool) -> Result<Box<TermInfo>, String>
     })
 }
 
-fn read_le_u16<R: Read + ?Sized>(r: &mut R) -> io::Result<u16> {
-    let mut b = [0; 2];
-    assert_eq!(try!(r.read(&mut b)), 2);
-    Ok((b[0] as u16) | ((b[1] as u16) << 8))
-}
-
-fn read_byte<R: Read + ?Sized>(r: &mut R) -> io::Result<u8> {
-    let mut b = [0; 1];
-    assert_eq!(try!(r.read(&mut b)), 1);
-    Ok(b[0])
-}
-
-fn read_exact<R: Read + ?Sized>(r: &mut R, sz: usize) -> io::Result<Vec<u8>> {
-    let mut v = Vec::with_capacity(sz);
-    try!(r.take(sz as u64).read_to_end(&mut v));
-    assert_eq!(v.len(), sz);
-    Ok(v)
-}
-
 /// Create a dummy TermInfo struct for msys terminals
-pub fn msys_terminfo() -> Box<TermInfo> {
+pub fn msys_terminfo() -> TermInfo {
     let mut strings = HashMap::new();
-    strings.insert("sgr0".to_owned(), b"\x1B[0m".to_vec());
-    strings.insert("bold".to_owned(), b"\x1B[1m".to_vec());
-    strings.insert("setaf".to_owned(), b"\x1B[3%p1%dm".to_vec());
-    strings.insert("setab".to_owned(), b"\x1B[4%p1%dm".to_vec());
-    box TermInfo {
-        names: vec!["cygwin".to_owned()], // msys is a fork of an older cygwin version
+    strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec());
+    strings.insert("bold".to_string(), b"\x1B[1m".to_vec());
+    strings.insert("setaf".to_string(), b"\x1B[3%p1%dm".to_vec());
+    strings.insert("setab".to_string(), b"\x1B[4%p1%dm".to_vec());
+
+    let mut numbers = HashMap::new();
+    numbers.insert("colors".to_string(), 8u16);
+
+    TermInfo {
+        names: vec!["cygwin".to_string()], // msys is a fork of an older cygwin version
         bools: HashMap::new(),
-        numbers: HashMap::new(),
+        numbers: numbers,
         strings: strings,
     }
 }
 
 #[cfg(test)]
-mod tests {
+mod test {
 
     use super::{boolnames, boolfnames, numnames, numfnames, stringnames, stringfnames};
 
diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs
index 397e7aa22546c..e869c5083373c 100644
--- a/src/libterm/terminfo/searcher.rs
+++ b/src/libterm/terminfo/searcher.rs
@@ -13,29 +13,26 @@
 //! Does not support hashed database, only filesystem!
 
 use std::env;
-use std::fs::File;
-use std::io::prelude::*;
+use std::fs;
 use std::path::PathBuf;
 
 /// Return path to database entry for `term`
 #[allow(deprecated)]
-pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
-    if term.is_empty() {
-        return None;
-    }
-
-    let homedir = env::home_dir();
-
+pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
     let mut dirs_to_search = Vec::new();
-    let first_char = term.char_at(0);
+    let first_char = match term.chars().next() {
+        Some(c) => c,
+        None => return None,
+    };
 
     // Find search directory
     match env::var_os("TERMINFO") {
         Some(dir) => dirs_to_search.push(PathBuf::from(dir)),
         None => {
-            if homedir.is_some() {
+            if let Some(mut homedir) = env::home_dir() {
                 // ncurses compatibility;
-                dirs_to_search.push(homedir.unwrap().join(".terminfo"))
+                homedir.push(".terminfo");
+                dirs_to_search.push(homedir)
             }
             match env::var("TERMINFO_DIRS") {
                 Ok(dirs) => {
@@ -61,35 +58,26 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
     };
 
     // Look for the terminal in all of the search directories
-    for p in &dirs_to_search {
-        if p.exists() {
-            let f = first_char.to_string();
-            let newp = p.join(&f).join(term);
-            if newp.exists() {
-                return Some(box newp);
+    for mut p in dirs_to_search {
+        if fs::metadata(&p).is_ok() {
+            p.push(&first_char.to_string());
+            p.push(&term);
+            if fs::metadata(&p).is_ok() {
+                return Some(p);
             }
-            // on some installations the dir is named after the hex of the char (e.g. OS X)
-            let f = format!("{:x}", first_char as usize);
-            let newp = p.join(&f).join(term);
-            if newp.exists() {
-                return Some(box newp);
-            }
-        }
-    }
-    None
-}
+            p.pop();
+            p.pop();
 
-/// Return open file for `term`
-pub fn open(term: &str) -> Result<File, String> {
-    match get_dbpath_for_term(term) {
-        Some(x) => {
-            match File::open(&*x) {
-                Ok(file) => Ok(file),
-                Err(e) => Err(format!("error opening file: {:?}", e)),
+            // on some installations the dir is named after the hex of the char
+            // (e.g. OS X)
+            p.push(&format!("{:x}", first_char as usize));
+            p.push(term);
+            if fs::metadata(&p).is_ok() {
+                return Some(p);
             }
         }
-        None => Err(format!("could not find terminfo entry for {:?}", term)),
     }
+    None
 }
 
 #[test]
@@ -109,11 +97,3 @@ fn test_get_dbpath_for_term() {
     assert!(x("screen") == "/usr/share/terminfo/s/screen");
     env::remove_var("TERMINFO_DIRS");
 }
-
-#[test]
-#[ignore(reason = "see test_get_dbpath_for_term")]
-fn test_open() {
-    open("screen").unwrap();
-    let t = open("nonexistent terminal that hopefully does not exist");
-    assert!(t.is_err());
-}
diff --git a/src/libterm/win.rs b/src/libterm/win.rs
index fa53d783194c8..2cb7018669d3d 100644
--- a/src/libterm/win.rs
+++ b/src/libterm/win.rs
@@ -17,9 +17,9 @@ extern crate libc;
 use std::io;
 use std::io::prelude::*;
 
-use attr;
+use Attr;
 use color;
-use {Terminal, UnwrappableTerminal};
+use Terminal;
 
 /// A Terminal implementation which uses the Win32 Console API.
 pub struct WinConsole<T> {
@@ -115,7 +115,7 @@ impl<T: Write+Send+'static> WinConsole<T> {
 
     /// Returns `None` whenever the terminal cannot be created for some
     /// reason.
-    pub fn new(out: T) -> Option<Box<Terminal<T> + Send + 'static>> {
+    pub fn new(out: T) -> io::Result<WinConsole<T>> {
         let fg;
         let bg;
         unsafe {
@@ -128,7 +128,7 @@ impl<T: Write+Send+'static> WinConsole<T> {
                 bg = color::BLACK;
             }
         }
-        Some(box WinConsole {
+        Ok(WinConsole {
             buf: out,
             def_foreground: fg,
             def_background: bg,
@@ -148,7 +148,9 @@ impl<T: Write> Write for WinConsole<T> {
     }
 }
 
-impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
+impl<T: Write+Send+'static> Terminal for WinConsole<T> {
+    type Output = T;
+
     fn fg(&mut self, color: color::Color) -> io::Result<bool> {
         self.foreground = color;
         self.apply();
@@ -163,14 +165,14 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
         Ok(true)
     }
 
-    fn attr(&mut self, attr: attr::Attr) -> io::Result<bool> {
+    fn attr(&mut self, attr: Attr) -> io::Result<bool> {
         match attr {
-            attr::ForegroundColor(f) => {
+            Attr::ForegroundColor(f) => {
                 self.foreground = f;
                 self.apply();
                 Ok(true)
             }
-            attr::BackgroundColor(b) => {
+            Attr::BackgroundColor(b) => {
                 self.background = b;
                 self.apply();
                 Ok(true)
@@ -179,21 +181,21 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
         }
     }
 
-    fn supports_attr(&self, attr: attr::Attr) -> bool {
+    fn supports_attr(&self, attr: Attr) -> bool {
         // it claims support for underscore and reverse video, but I can't get
         // it to do anything -cmr
         match attr {
-            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
+            Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
             _ => false,
         }
     }
 
-    fn reset(&mut self) -> io::Result<()> {
+    fn reset(&mut self) -> io::Result<bool> {
         self.foreground = self.def_foreground;
         self.background = self.def_background;
         self.apply();
 
-        Ok(())
+        Ok(true)
     }
 
     fn get_ref<'a>(&'a self) -> &'a T {
@@ -203,10 +205,10 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
     fn get_mut<'a>(&'a mut self) -> &'a mut T {
         &mut self.buf
     }
-}
 
-impl<T: Write+Send+'static> UnwrappableTerminal<T> for WinConsole<T> {
-    fn unwrap(self) -> T {
+    fn into_inner(self) -> T
+        where Self: Sized
+    {
         self.buf
     }
 }
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 125677dc9321c..71eddd80c74c8 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -428,7 +428,7 @@ pub enum TestResult {
 unsafe impl Send for TestResult {}
 
 enum OutputLocation<T> {
-    Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
+    Pretty(Box<term::StdoutTerminal>),
     Raw(T),
 }