]> git.lizzy.rs Git - rust.git/blob - src/libterm/terminfo/searcher.rs
0e05ac53bc8780536cfec774d30d74a3269ef963
[rust.git] / src / libterm / terminfo / searcher.rs
1 // Copyright 2012 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 //! ncurses-compatible database discovery
12 //!
13 //! Does not support hashed database, only filesystem!
14
15 use std::env;
16 use std::fs::File;
17 use std::io::prelude::*;
18 use std::path::PathBuf;
19
20 /// Return path to database entry for `term`
21 #[allow(deprecated)]
22 pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
23     if term.is_empty() {
24         return None;
25     }
26
27     let homedir = env::home_dir();
28
29     let mut dirs_to_search = Vec::new();
30     let first_char = term.char_at(0);
31
32     // Find search directory
33     match env::var_os("TERMINFO") {
34         Some(dir) => dirs_to_search.push(PathBuf::from(dir)),
35         None => {
36             if homedir.is_some() {
37                 // ncurses compatibility;
38                 dirs_to_search.push(homedir.unwrap().join(".terminfo"))
39             }
40             match env::var("TERMINFO_DIRS") {
41                 Ok(dirs) => for i in dirs.split(':') {
42                     if i == "" {
43                         dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
44                     } else {
45                         dirs_to_search.push(PathBuf::from(i));
46                     }
47                 },
48                 // Found nothing in TERMINFO_DIRS, use the default paths:
49                 // According to  /etc/terminfo/README, after looking at
50                 // ~/.terminfo, ncurses will search /etc/terminfo, then
51                 // /lib/terminfo, and eventually /usr/share/terminfo.
52                 Err(..) => {
53                     dirs_to_search.push(PathBuf::from("/etc/terminfo"));
54                     dirs_to_search.push(PathBuf::from("/lib/terminfo"));
55                     dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
56                 }
57             }
58         }
59     };
60
61     // Look for the terminal in all of the search directories
62     for p in &dirs_to_search {
63         if p.exists() {
64             let f = first_char.to_string();
65             let newp = p.join(&f).join(term);
66             if newp.exists() {
67                 return Some(box newp);
68             }
69             // on some installations the dir is named after the hex of the char (e.g. OS X)
70             let f = format!("{:x}", first_char as usize);
71             let newp = p.join(&f).join(term);
72             if newp.exists() {
73                 return Some(box newp);
74             }
75         }
76     }
77     None
78 }
79
80 /// Return open file for `term`
81 pub fn open(term: &str) -> Result<File, String> {
82     match get_dbpath_for_term(term) {
83         Some(x) => {
84             match File::open(&*x) {
85                 Ok(file) => Ok(file),
86                 Err(e) => Err(format!("error opening file: {:?}", e)),
87             }
88         }
89         None => {
90             Err(format!("could not find terminfo entry for {:?}", term))
91         }
92     }
93 }
94
95 #[test]
96 #[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
97 fn test_get_dbpath_for_term() {
98     // woefully inadequate test coverage
99     // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
100     use std::env;
101     // FIXME (#9639): This needs to handle non-utf8 paths
102     fn x(t: &str) -> String {
103         let p = get_dbpath_for_term(t).expect("no terminfo entry found");
104         p.to_str().unwrap().to_string()
105     }
106     assert!(x("screen") == "/usr/share/terminfo/s/screen");
107     assert!(get_dbpath_for_term("") == None);
108     env::set_var("TERMINFO_DIRS", ":");
109     assert!(x("screen") == "/usr/share/terminfo/s/screen");
110     env::remove_var("TERMINFO_DIRS");
111 }
112
113 #[test]
114 #[ignore(reason = "see test_get_dbpath_for_term")]
115 fn test_open() {
116     open("screen").unwrap();
117     let t = open("nonexistent terminal that hopefully does not exist");
118     assert!(t.is_err());
119 }