]> git.lizzy.rs Git - rust.git/blob - src/libterm/terminfo/searcher.rs
Rollup merge of #40521 - TimNN:panic-free-shift, r=alexcrichton
[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;
17 use std::path::PathBuf;
18
19 /// Return path to database entry for `term`
20 #[allow(deprecated)]
21 pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
22     let mut dirs_to_search = Vec::new();
23     let first_char = match term.chars().next() {
24         Some(c) => c,
25         None => return None,
26     };
27
28     // Find search directory
29     if let Some(dir) = env::var_os("TERMINFO") {
30         dirs_to_search.push(PathBuf::from(dir));
31     }
32
33     if let Ok(dirs) = env::var("TERMINFO_DIRS") {
34         for i in dirs.split(':') {
35             if i == "" {
36                 dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
37             } else {
38                 dirs_to_search.push(PathBuf::from(i));
39             }
40         }
41     } else {
42         // Found nothing in TERMINFO_DIRS, use the default paths:
43         // According to  /etc/terminfo/README, after looking at
44         // ~/.terminfo, ncurses will search /etc/terminfo, then
45         // /lib/terminfo, and eventually /usr/share/terminfo.
46         // On Haiku the database can be found at /boot/system/data/terminfo
47         if let Some(mut homedir) = env::home_dir() {
48             homedir.push(".terminfo");
49             dirs_to_search.push(homedir)
50         }
51
52         dirs_to_search.push(PathBuf::from("/etc/terminfo"));
53         dirs_to_search.push(PathBuf::from("/lib/terminfo"));
54         dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
55         dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo"));
56     }
57
58     // Look for the terminal in all of the search directories
59     for mut p in dirs_to_search {
60         if fs::metadata(&p).is_ok() {
61             p.push(&first_char.to_string());
62             p.push(&term);
63             if fs::metadata(&p).is_ok() {
64                 return Some(p);
65             }
66             p.pop();
67             p.pop();
68
69             // on some installations the dir is named after the hex of the char
70             // (e.g. macOS)
71             p.push(&format!("{:x}", first_char as usize));
72             p.push(term);
73             if fs::metadata(&p).is_ok() {
74                 return Some(p);
75             }
76         }
77     }
78     None
79 }
80
81 #[test]
82 #[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
83 fn test_get_dbpath_for_term() {
84     // woefully inadequate test coverage
85     // note: current tests won't work with non-standard terminfo hierarchies (e.g. macOS's)
86     use std::env;
87     // FIXME (#9639): This needs to handle non-utf8 paths
88     fn x(t: &str) -> String {
89         let p = get_dbpath_for_term(t).expect("no terminfo entry found");
90         p.to_str().unwrap().to_string()
91     }
92     assert!(x("screen") == "/usr/share/terminfo/s/screen");
93     assert!(get_dbpath_for_term("") == None);
94     env::set_var("TERMINFO_DIRS", ":");
95     assert!(x("screen") == "/usr/share/terminfo/s/screen");
96     env::remove_var("TERMINFO_DIRS");
97 }