(index<- ) ./libextra/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 /// Implement ncurses-compatible database discovery
12 /// Does not support hashed database, only filesystem!
13
14 use std::{os, str};
15 use std::os::getenv;
16 use std::io::{file_reader, Reader};
17 use path = std::path::Path;
18
19 /// Return path to database entry for `term`
20 pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
21 if term.len() == 0 {
22 return None;
23 }
24
25 let homedir = os::homedir();
26
27 let mut dirs_to_search = ~[];
28 let first_char = term.char_at(0);
29
30 // Find search directory
31 match getenv("TERMINFO") {
32 Some(dir) => dirs_to_search.push(path(dir)),
33 None => {
34 if homedir.is_some() {
35 dirs_to_search.push(homedir.unwrap().push(".terminfo")); // ncurses compatability
36 }
37 match getenv("TERMINFO_DIRS") {
38 Some(dirs) => for i in dirs.split_iter(':') {
39 if i == "" {
40 dirs_to_search.push(path("/usr/share/terminfo"));
41 } else {
42 dirs_to_search.push(path(i.to_owned()));
43 }
44 },
45 // Found nothing, use the default paths
46 // /usr/share/terminfo is the de facto location, but it seems
47 // Ubuntu puts it in /lib/terminfo
48 None => {
49 dirs_to_search.push(path("/usr/share/terminfo"));
50 dirs_to_search.push(path("/lib/terminfo"));
51 }
52 }
53 }
54 };
55
56 // Look for the terminal in all of the search directories
57 for p in dirs_to_search.iter() {
58 let newp = ~p.push_many(&[str::from_char(first_char), term.to_owned()]);
59 if os::path_exists(p) && os::path_exists(newp) {
60 return Some(newp);
61 }
62 // on some installations the dir is named after the hex of the char (e.g. OS X)
63 let newp = ~p.push_many(&[fmt!("%x", first_char as uint), term.to_owned()]);
64 if os::path_exists(p) && os::path_exists(newp) {
65 return Some(newp);
66 }
67 }
68 None
69 }
70
71 /// Return open file for `term`
72 pub fn open(term: &str) -> Result<@Reader, ~str> {
73 match get_dbpath_for_term(term) {
74 Some(x) => file_reader(x),
75 None => Err(fmt!("could not find terminfo entry for %s", term))
76 }
77 }
78
79 #[test]
80 #[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
81 fn test_get_dbpath_for_term() {
82 // woefully inadequate test coverage
83 // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
84 use std::os::{setenv, unsetenv};
85 fn x(t: &str) -> ~str { get_dbpath_for_term(t).expect("no terminfo entry found").to_str() };
86 assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
87 assert!(get_dbpath_for_term("") == None);
88 setenv("TERMINFO_DIRS", ":");
89 assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
90 unsetenv("TERMINFO_DIRS");
91 }
92
93 #[test]
94 #[ignore(reason = "see test_get_dbpath_for_term")]
95 fn test_open() {
96 open("screen");
97 let t = open("nonexistent terminal that hopefully does not exist");
98 assert!(t.is_err());
99 }