(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  }