提交 ded860c0 编写于 作者: P Patrick Walton

libterm: Remove all uses of `~str` from `libterm`

上级 93499b1e
......@@ -126,10 +126,12 @@ impl<T: Writer> Terminal<T> {
/// Returns `Err()` on failure to open the terminfo database correctly.
/// Also, in the event that the individual terminfo database entry can not
/// be parsed.
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
pub fn new(out: T) -> Result<Terminal<T>, StrBuf> {
let term = match os::getenv("TERM") {
Some(t) => t,
None => return Err("TERM environment variable undefined".to_owned())
None => {
return Err("TERM environment variable undefined".to_strbuf())
}
};
let mut file = match open(term) {
......@@ -251,7 +253,8 @@ pub fn reset(&mut self) -> io::IoResult<()> {
cap = self.ti.strings.find_equiv(&("op"));
}
}
let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_owned()), |op| {
let s = cap.map_or(Err("can't find terminfo capability \
`sgr0`".to_strbuf()), |op| {
expand(op.as_slice(), [], &mut Variables::new())
});
if s.is_ok() {
......
......@@ -15,13 +15,13 @@
/// A parsed terminfo database entry.
pub struct TermInfo {
/// Names for the terminal
pub names: Vec<~str> ,
pub names: Vec<StrBuf> ,
/// Map of capability name to boolean value
pub bools: HashMap<~str, bool>,
pub bools: HashMap<StrBuf, bool>,
/// Map of capability name to numeric value
pub numbers: HashMap<~str, u16>,
pub numbers: HashMap<StrBuf, u16>,
/// Map of capability name to raw (unexpanded) string
pub strings: HashMap<~str, Vec<u8> >
pub strings: HashMap<StrBuf, Vec<u8> >
}
pub mod searcher;
......
......@@ -41,7 +41,7 @@ enum FormatState {
#[allow(missing_doc)]
#[deriving(Clone)]
pub enum Param {
String(~str),
String(StrBuf),
Number(int)
}
......@@ -89,7 +89,7 @@ pub fn new() -> Variables {
multiple capabilities for the same terminal.
*/
pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
-> Result<Vec<u8> , ~str> {
-> Result<Vec<u8> , StrBuf> {
let mut state = Nothing;
// expanded cap will only rarely be larger than the cap itself
......@@ -124,9 +124,9 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
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())
_ => return Err("a non-char was used with %c".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'p' => state = PushParam,
'P' => state = SetVar,
'g' => state = GetVar,
......@@ -135,112 +135,112 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
'l' => if stack.len() > 0 {
match stack.pop().unwrap() {
String(s) => stack.push(Number(s.len() as int)),
_ => return Err("a non-str was used with %l".to_owned())
_ => return Err("a non-str was used with %l".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'+' => 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())
_ => return Err("non-numbers on stack with +".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'-' => 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())
_ => return Err("non-numbers on stack with -".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'*' => 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())
_ => return Err("non-numbers on stack with *".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'/' => 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())
_ => return Err("non-numbers on stack with /".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'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())
_ => return Err("non-numbers on stack with %".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'&' => 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())
_ => return Err("non-numbers on stack with &".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'|' => 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())
_ => return Err("non-numbers on stack with |".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'^' => 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())
_ => return Err("non-numbers on stack with ^".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'=' => 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())
_ => return Err("non-numbers on stack with =".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'>' => 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())
_ => return Err("non-numbers on stack with >".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'<' => 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())
_ => return Err("non-numbers on stack with <".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'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())
_ => return Err("non-numbers on stack with logical and".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'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())
_ => return Err("non-numbers on stack with logical or".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'!' => if stack.len() > 0 {
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())
_ => return Err("non-number on stack with logical not".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'~' => if stack.len() > 0 {
match stack.pop().unwrap() {
Number(x) => stack.push(Number(!x)),
_ => return Err("non-number on stack with %~".to_owned())
_ => return Err("non-number on stack with %~".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'i' => match (mparams[0].clone(), mparams[1].clone()) {
(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_strbuf())
},
// printf-style support for %doxXs
......@@ -249,7 +249,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
if res.is_err() { return res }
output.push_all(res.unwrap().as_slice())
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
':'|'#'|' '|'.'|'0'..'9' => {
let mut flags = Flags::new();
let mut fstate = FormatStateFlags;
......@@ -274,20 +274,24 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
Number(0) => state = SeekIfElse(0),
Number(_) => (),
_ => return Err("non-number on stack \
with conditional".to_owned())
with conditional".to_strbuf())
}
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
'e' => state = SeekIfEnd(0),
';' => (),
_ => return Err(format!("unrecognized format option {}", cur))
_ => {
return Err(format_strbuf!("unrecognized format \
option {}",
cur))
}
}
},
PushParam => {
// params are 1-indexed
stack.push(mparams[match char::to_digit(cur, 10) {
Some(d) => d - 1,
None => return Err("bad param number".to_owned())
None => return Err("bad param number".to_strbuf())
}].clone());
},
SetVar => {
......@@ -295,14 +299,14 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
if stack.len() > 0 {
let idx = (cur as u8) - ('A' as u8);
vars.sta[idx as uint] = stack.pop().unwrap();
} else { return Err("stack is empty".to_owned()) }
} else { return Err("stack is empty".to_strbuf()) }
} else if cur >= 'a' && cur <= 'z' {
if stack.len() > 0 {
let idx = (cur as u8) - ('a' as u8);
vars.dyn[idx as uint] = stack.pop().unwrap();
} else { return Err("stack is empty".to_owned()) }
} else { return Err("stack is empty".to_strbuf()) }
} else {
return Err("bad variable name in %P".to_owned());
return Err("bad variable name in %P".to_strbuf());
}
},
GetVar => {
......@@ -313,7 +317,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
let idx = (cur as u8) - ('a' as u8);
stack.push(vars.dyn[idx as uint].clone());
} else {
return Err("bad variable name in %g".to_owned());
return Err("bad variable name in %g".to_strbuf());
}
},
CharConstant => {
......@@ -322,7 +326,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
},
CharClose => {
if cur != '\'' {
return Err("malformed character constant".to_owned());
return Err("malformed character constant".to_strbuf());
}
},
IntConstant(i) => {
......@@ -335,7 +339,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
state = IntConstant(i*10 + (cur as int - '0' as int));
old_state = Nothing;
}
_ => return Err("bad int constant".to_owned())
_ => return Err("bad int constant".to_strbuf())
}
}
FormatPattern(ref mut flags, ref mut fstate) => {
......@@ -346,7 +350,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
if res.is_err() { return res }
output.push_all(res.unwrap().as_slice());
old_state = state; // will cause state to go to Nothing
} else { return Err("stack is empty".to_owned()) },
} else { return Err("stack is empty".to_strbuf()) },
(FormatStateFlags,'#') => {
flags.alternate = true;
}
......@@ -369,7 +373,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
(FormatStateWidth,'0'..'9') => {
let old = flags.width;
flags.width = flags.width * 10 + (cur as uint - '0' as uint);
if flags.width < old { return Err("format width overflow".to_owned()) }
if flags.width < old { return Err("format width overflow".to_strbuf()) }
}
(FormatStateWidth,'.') => {
*fstate = FormatStatePrecision;
......@@ -378,10 +382,10 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
let old = flags.precision;
flags.precision = flags.precision * 10 + (cur as uint - '0' as uint);
if flags.precision < old {
return Err("format precision overflow".to_owned())
return Err("format precision overflow".to_strbuf())
}
}
_ => return Err("invalid format specifier".to_owned())
_ => return Err("invalid format specifier".to_strbuf())
}
}
SeekIfElse(level) => {
......@@ -479,7 +483,7 @@ fn to_char(self) -> char {
}
}
fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,~str> {
fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,StrBuf> {
let mut s = match val {
Number(d) => {
let s = match (op, flags.sign) {
......@@ -488,7 +492,9 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,~str> {
(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()),
(FormatString, _) => {
return Err("non-number on stack with %s".to_strbuf())
}
};
let mut s: Vec<u8> = s.move_iter().collect();
if flags.precision > s.len() {
......@@ -543,7 +549,8 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,~str> {
s
}
_ => {
return Err(format!("non-string on stack with %{}", op.to_char()))
return Err(format_strbuf!("non-string on stack with %{}",
op.to_char()))
}
}
}
......@@ -600,7 +607,7 @@ fn test_param_stack_failure_conditions() {
assert!(res.is_err(),
"Op {} succeeded incorrectly with 0 stack entries", *cap);
let p = if *cap == "%s" || *cap == "%l" {
String("foo".to_owned())
String("foo".to_strbuf())
} else {
Number(97)
};
......@@ -678,10 +685,12 @@ fn test_format() {
let mut varstruct = Variables::new();
let vars = &mut varstruct;
assert_eq!(expand(bytes!("%p1%s%p2%2s%p3%2s%p4%.2s"),
[String("foo".to_owned()), String("foo".to_owned()),
String("f".to_owned()), String("foo".to_owned())], vars),
[String("foo".to_strbuf()),
String("foo".to_strbuf()),
String("f".to_strbuf()),
String("foo".to_strbuf())], vars),
Ok(bytes!("foofoo ffo").iter().map(|x| *x).collect()));
assert_eq!(expand(bytes!("%p1%:-4.2s"), [String("foo".to_owned())], vars),
assert_eq!(expand(bytes!("%p1%:-4.2s"), [String("foo".to_strbuf())], vars),
Ok(bytes!("fo ").iter().map(|x| *x).collect()));
assert_eq!(expand(bytes!("%p1%d%p1%.3d%p1%5d%p1%:+d"), [Number(1)], vars),
......
......@@ -160,9 +160,12 @@
/// Parse a compiled terminfo entry, using long capability names if `longnames` is true
pub fn parse(file: &mut io::Reader, longnames: bool)
-> Result<Box<TermInfo>, ~str> {
-> Result<Box<TermInfo>, StrBuf> {
macro_rules! try( ($e:expr) => (
match $e { Ok(e) => e, Err(e) => return Err(format!("{}", e)) }
match $e {
Ok(e) => e,
Err(e) => return Err(format_strbuf!("{}", e))
}
) )
let bnames;
......@@ -182,8 +185,10 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
// Check magic number
let magic = try!(file.read_le_u16());
if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x} but found {:x}",
0x011A, magic as uint));
return Err(format_strbuf!("invalid magic number: expected {:x} but \
found {:x}",
0x011A,
magic as uint));
}
let names_bytes = try!(file.read_le_i16()) as int;
......@@ -195,24 +200,30 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
assert!(names_bytes > 0);
if (bools_bytes as uint) > boolnames.len() {
return Err("incompatible file: more booleans than expected".to_owned());
return Err("incompatible file: more booleans than \
expected".to_strbuf());
}
if (numbers_count as uint) > numnames.len() {
return Err("incompatible file: more numbers than expected".to_owned());
return Err("incompatible file: more numbers than \
expected".to_strbuf());
}
if (string_offsets_count as uint) > stringnames.len() {
return Err("incompatible file: more string offsets than expected".to_owned());
return Err("incompatible file: more string offsets than \
expected".to_strbuf());
}
// don't read NUL
let bytes = try!(file.read_exact(names_bytes as uint - 1));
let names_str = match str::from_utf8(bytes.as_slice()) {
Some(s) => s.to_owned(), None => return Err("input not utf-8".to_owned()),
Some(s) => s.to_owned(),
None => return Err("input not utf-8".to_strbuf()),
};
let term_names: Vec<~str> = names_str.split('|').map(|s| s.to_owned()).collect();
let term_names: Vec<StrBuf> = names_str.split('|')
.map(|s| s.to_strbuf())
.collect();
try!(file.read_byte()); // consume NUL
......@@ -221,7 +232,7 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
for i in range(0, bools_bytes) {
let b = try!(file.read_byte());
if b == 1 {
bools_map.insert(bnames[i as uint].to_owned(), true);
bools_map.insert(bnames[i as uint].to_strbuf(), true);
}
}
}
......@@ -235,7 +246,7 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
for i in range(0, numbers_count) {
let n = try!(file.read_le_u16());
if n != 0xFFFF {
numbers_map.insert(nnames[i as uint].to_owned(), n);
numbers_map.insert(nnames[i as uint].to_strbuf(), n);
}
}
}
......@@ -251,7 +262,8 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
let string_table = try!(file.read_exact(string_table_bytes as uint));
if string_table.len() != string_table_bytes as uint {
return Err("error: hit EOF before end of string table".to_owned());
return Err("error: hit EOF before end of string \
table".to_strbuf());
}
for (i, v) in string_offsets.iter().enumerate() {
......@@ -269,7 +281,7 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
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());
string_map.insert(name.to_strbuf(), Vec::new());
continue;
}
......@@ -279,13 +291,14 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
.iter().position(|&b| b == 0);
match nulpos {
Some(len) => {
string_map.insert(name.to_owned(),
string_map.insert(name.to_strbuf(),
Vec::from_slice(
string_table.slice(offset as uint,
offset as uint + len)))
},
None => {
return Err("invalid file: missing NUL in string_table".to_owned());
return Err("invalid file: missing NUL in \
string_table".to_strbuf());
}
};
}
......@@ -303,12 +316,12 @@ pub fn parse(file: &mut io::Reader, longnames: bool)
/// Create a dummy TermInfo struct for msys terminals
pub fn msys_terminfo() -> Box<TermInfo> {
let mut strings = HashMap::new();
strings.insert("sgr0".to_owned(), Vec::from_slice(bytes!("\x1b[0m")));
strings.insert("bold".to_owned(), Vec::from_slice(bytes!("\x1b[1m")));
strings.insert("setaf".to_owned(), Vec::from_slice(bytes!("\x1b[3%p1%dm")));
strings.insert("setab".to_owned(), Vec::from_slice(bytes!("\x1b[4%p1%dm")));
strings.insert("sgr0".to_strbuf(), Vec::from_slice(bytes!("\x1b[0m")));
strings.insert("bold".to_strbuf(), Vec::from_slice(bytes!("\x1b[1m")));
strings.insert("setaf".to_strbuf(), Vec::from_slice(bytes!("\x1b[3%p1%dm")));
strings.insert("setab".to_strbuf(), Vec::from_slice(bytes!("\x1b[4%p1%dm")));
box TermInfo {
names: vec!("cygwin".to_owned()), // msys is a fork of an older cygwin version
names: vec!("cygwin".to_strbuf()), // msys is a fork of an older cygwin version
bools: HashMap::new(),
numbers: HashMap::new(),
strings: strings
......
......@@ -76,15 +76,17 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
}
/// Return open file for `term`
pub fn open(term: &str) -> Result<File, ~str> {
pub fn open(term: &str) -> Result<File, StrBuf> {
match get_dbpath_for_term(term) {
Some(x) => {
match File::open(x) {
Ok(file) => Ok(file),
Err(e) => Err(format!("error opening file: {}", e)),
Err(e) => Err(format_strbuf!("error opening file: {}", e)),
}
}
None => Err(format!("could not find terminfo entry for {}", term))
None => {
Err(format_strbuf!("could not find terminfo entry for {}", term))
}
}
}
......@@ -95,14 +97,14 @@ fn test_get_dbpath_for_term() {
// note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
use std::os::{setenv, unsetenv};
// FIXME (#9639): This needs to handle non-utf8 paths
fn x(t: &str) -> ~str {
fn x(t: &str) -> StrBuf {
let p = get_dbpath_for_term(t).expect("no terminfo entry found");
p.as_str().unwrap().to_owned()
p.as_str().unwrap().to_strbuf()
};
assert!(x("screen") == "/usr/share/terminfo/s/screen".to_owned());
assert!(x("screen") == "/usr/share/terminfo/s/screen".to_strbuf());
assert!(get_dbpath_for_term("") == None);
setenv("TERMINFO_DIRS", ":");
assert!(x("screen") == "/usr/share/terminfo/s/screen".to_owned());
assert!(x("screen") == "/usr/share/terminfo/s/screen".to_strbuf());
unsetenv("TERMINFO_DIRS");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册