SeekIfElse(isize),
SeekIfElsePercent(isize),
SeekIfEnd(isize),
- SeekIfEndPercent(isize)
+ SeekIfEndPercent(isize),
}
#[derive(Copy, Clone, PartialEq)]
enum FormatState {
FormatStateFlags,
FormatStateWidth,
- FormatStatePrecision
+ FormatStatePrecision,
}
/// Types of parameters a capability can use
#[derive(Clone)]
pub enum Param {
Words(String),
- Number(isize)
+ Number(isize),
}
/// Container for static and dynamic variable arrays
/// Static variables A-Z
sta: [Param; 26],
/// Dynamic variables a-z
- dyn: [Param; 26]
+ dyn: [Param; 26],
}
impl Variables {
/// Return a new zero-initialized Variables
pub fn new() -> Variables {
Variables {
- sta: [
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0),
- ],
- dyn: [
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0),
- ],
+ sta: [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0)],
+ dyn: [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0), Number(0), Number(0)],
}
}
}
///
/// To be compatible with ncurses, `vars` should be the same between calls to `expand` for
/// multiple capabilities for the same terminal.
-pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
- -> Result<Vec<u8> , String> {
+pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<u8>, String> {
let mut state = Nothing;
// expanded cap will only rarely be larger than the cap itself
let mut stack: Vec<Param> = Vec::new();
// Copy parameters into a local vector for mutability
- let mut mparams = [
- Number(0), Number(0), Number(0), Number(0), Number(0),
- Number(0), Number(0), Number(0), Number(0),
- ];
+ let mut mparams = [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
+ Number(0), Number(0), Number(0)];
for (dst, src) in mparams.iter_mut().zip(params) {
*dst = (*src).clone();
}
} else {
output.push(c);
}
- },
+ }
Percent => {
match cur {
- '%' => { output.push(c); state = Nothing },
- 'c' => if !stack.is_empty() {
- 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
- })
+ '%' => {
+ output.push(c);
+ state = Nothing
+ }
+ 'c' => {
+ if !stack.is_empty() {
+ 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_owned())
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
+ }
'p' => state = PushParam,
'P' => state = SetVar,
'g' => state = GetVar,
'\'' => state = CharConstant,
'{' => state = IntConstant(0),
- 'l' => if !stack.is_empty() {
- match stack.pop().unwrap() {
- Words(s) => stack.push(Number(s.len() as isize)),
- _ => return Err("a non-str was used with %l".to_owned())
+ 'l' => {
+ if !stack.is_empty() {
+ match stack.pop().unwrap() {
+ Words(s) => stack.push(Number(s.len() as isize)),
+ _ => return Err("a non-str was used with %l".to_owned()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '+' => 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())
+ }
+ '+' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '-' => 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())
+ }
+ '-' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '*' => 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())
+ }
+ '*' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '/' => 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())
+ }
+ '/' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '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())
+ }
+ '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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '&' => 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())
+ }
+ '&' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '|' => 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())
+ }
+ '|' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '^' => 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())
+ }
+ '^' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '=' => 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())
+ }
+ '=' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '>' => 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())
+ }
+ '>' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '<' => 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())
+ }
+ '<' => {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '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())
+ }
+ '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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '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())
+ }
+ '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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '!' => if !stack.is_empty() {
- 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())
+ }
+ '!' => {
+ if !stack.is_empty() {
+ 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()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
+ }
+ }
+ '~' => {
+ if !stack.is_empty() {
+ match stack.pop().unwrap() {
+ Number(x) => stack.push(Number(!x)),
+ _ => return Err("non-number on stack with %~".to_owned()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
- '~' => if !stack.is_empty() {
- match stack.pop().unwrap() {
- Number(x) => stack.push(Number(!x)),
- _ => return Err("non-number on stack with %~".to_owned())
+ }
+ '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()),
}
- } else { return Err("stack is empty".to_owned()) },
- '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())
- },
+ }
// printf-style support for %doxXs
- 'd'|'o'|'x'|'X'|'s' => if !stack.is_empty() {
- let flags = Flags::new();
- let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
- if res.is_err() { return res }
- output.push_all(&res.unwrap())
- } else { return Err("stack is empty".to_owned()) },
- ':'|'#'|' '|'.'|'0'...'9' => {
+ 'd' | 'o' | 'x' | 'X' | 's' => {
+ if !stack.is_empty() {
+ let flags = Flags::new();
+ let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
+ if res.is_err() {
+ return res;
+ }
+ output.push_all(&res.unwrap())
+ } else {
+ return Err("stack is empty".to_owned());
+ }
+ }
+ ':' | '#' | ' ' | '.' | '0'...'9' => {
let mut flags = Flags::new();
let mut fstate = FormatStateFlags;
match cur {
flags.width = cur as usize - '0' as usize;
fstate = FormatStateWidth;
}
- _ => unreachable!()
+ _ => unreachable!(),
}
state = FormatPattern(flags, fstate);
}
// conditionals
'?' => (),
- 't' => if !stack.is_empty() {
- match stack.pop().unwrap() {
- Number(0) => state = SeekIfElse(0),
- Number(_) => (),
- _ => return Err("non-number on stack \
- with conditional".to_owned())
+ 't' => {
+ if !stack.is_empty() {
+ match stack.pop().unwrap() {
+ Number(0) => state = SeekIfElse(0),
+ Number(_) => (),
+ _ => return Err("non-number on stack with conditional".to_owned()),
+ }
+ } else {
+ return Err("stack is empty".to_owned());
}
- } else { return Err("stack is empty".to_owned()) },
+ }
'e' => state = SeekIfEnd(0),
';' => (),
- _ => {
- return Err(format!("unrecognized format option {:?}", cur))
- }
+ _ => return Err(format!("unrecognized format option {:?}", cur)),
}
- },
+ }
PushParam => {
// params are 1-indexed
stack.push(mparams[match cur.to_digit(10) {
- Some(d) => d as usize - 1,
- None => return Err("bad param number".to_owned())
- }].clone());
- },
+ Some(d) => d as usize - 1,
+ None => return Err("bad param number".to_owned()),
+ }]
+ .clone());
+ }
SetVar => {
if cur >= 'A' && cur <= 'Z' {
if !stack.is_empty() {
let idx = (cur as u8) - b'A';
vars.sta[idx as usize] = stack.pop().unwrap();
- } else { return Err("stack is empty".to_owned()) }
+ } else {
+ return Err("stack is empty".to_owned());
+ }
} else if cur >= 'a' && cur <= 'z' {
if !stack.is_empty() {
let idx = (cur as u8) - b'a';
vars.dyn[idx as usize] = stack.pop().unwrap();
- } else { return Err("stack is empty".to_owned()) }
+ } else {
+ return Err("stack is empty".to_owned());
+ }
} else {
return Err("bad variable name in %P".to_owned());
}
- },
+ }
GetVar => {
if cur >= 'A' && cur <= 'Z' {
let idx = (cur as u8) - b'A';
} else {
return Err("bad variable name in %g".to_owned());
}
- },
+ }
CharConstant => {
stack.push(Number(c as isize));
state = CharClose;
- },
+ }
CharClose => {
if cur != '\'' {
return Err("malformed character constant".to_owned());
}
- },
+ }
IntConstant(i) => {
match cur {
'}' => {
state = Nothing;
}
'0'...'9' => {
- state = IntConstant(i*10 + (cur as isize - '0' as isize));
+ state = IntConstant(i * 10 + (cur as isize - '0' as isize));
old_state = Nothing;
}
- _ => return Err("bad isize constant".to_owned())
+ _ => return Err("bad isize constant".to_owned()),
}
}
FormatPattern(ref mut flags, ref mut fstate) => {
old_state = Nothing;
match (*fstate, cur) {
- (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if !stack.is_empty() {
- let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), *flags);
- if res.is_err() { return res }
- output.push_all(&res.unwrap());
- // will cause state to go to Nothing
- old_state = FormatPattern(*flags, *fstate);
- } else { return Err("stack is empty".to_owned()) },
- (FormatStateFlags,'#') => {
+ (_, 'd') | (_, 'o') | (_, 'x') | (_, 'X') | (_, 's') => {
+ if !stack.is_empty() {
+ let res = format(stack.pop().unwrap(),
+ FormatOp::from_char(cur),
+ *flags);
+ if res.is_err() {
+ return res;
+ }
+ output.push_all(&res.unwrap());
+ // will cause state to go to Nothing
+ old_state = FormatPattern(*flags, *fstate);
+ } else {
+ return Err("stack is empty".to_owned());
+ }
+ }
+ (FormatStateFlags, '#') => {
flags.alternate = true;
}
- (FormatStateFlags,'-') => {
+ (FormatStateFlags, '-') => {
flags.left = true;
}
- (FormatStateFlags,'+') => {
+ (FormatStateFlags, '+') => {
flags.sign = true;
}
- (FormatStateFlags,' ') => {
+ (FormatStateFlags, ' ') => {
flags.space = true;
}
- (FormatStateFlags,'0'...'9') => {
+ (FormatStateFlags, '0'...'9') => {
flags.width = cur as usize - '0' as usize;
*fstate = FormatStateWidth;
}
- (FormatStateFlags,'.') => {
+ (FormatStateFlags, '.') => {
*fstate = FormatStatePrecision;
}
- (FormatStateWidth,'0'...'9') => {
+ (FormatStateWidth, '0'...'9') => {
let old = flags.width;
flags.width = flags.width * 10 + (cur as usize - '0' as usize);
- if flags.width < old { return Err("format width overflow".to_owned()) }
+ if flags.width < old {
+ return Err("format width overflow".to_owned());
+ }
}
- (FormatStateWidth,'.') => {
+ (FormatStateWidth, '.') => {
*fstate = FormatStatePrecision;
}
- (FormatStatePrecision,'0'...'9') => {
+ (FormatStatePrecision, '0'...'9') => {
let old = flags.precision;
flags.precision = flags.precision * 10 + (cur as usize - '0' as usize);
if flags.precision < old {
- return Err("format precision overflow".to_owned())
+ return Err("format precision overflow".to_owned());
}
}
- _ => return Err("invalid format specifier".to_owned())
+ _ => return Err("invalid format specifier".to_owned()),
}
}
SeekIfElse(level) => {
if level == 0 {
state = Nothing;
} else {
- state = SeekIfElse(level-1);
+ state = SeekIfElse(level - 1);
}
} else if cur == 'e' && level == 0 {
state = Nothing;
} else if cur == '?' {
- state = SeekIfElse(level+1);
+ state = SeekIfElse(level + 1);
} else {
state = SeekIfElse(level);
}
if level == 0 {
state = Nothing;
} else {
- state = SeekIfEnd(level-1);
+ state = SeekIfEnd(level - 1);
}
} else if cur == '?' {
- state = SeekIfEnd(level+1);
+ state = SeekIfEnd(level + 1);
} else {
state = SeekIfEnd(level);
}
alternate: bool,
left: bool,
sign: bool,
- space: bool
+ space: bool,
}
impl Flags {
fn new() -> Flags {
- Flags{ width: 0, precision: 0, alternate: false,
- left: false, sign: false, space: false }
+ Flags {
+ width: 0,
+ precision: 0,
+ alternate: false,
+ left: false,
+ sign: false,
+ space: false,
+ }
}
}
FormatOctal,
FormatHex,
FormatHEX,
- FormatString
+ FormatString,
}
impl FormatOp {
'x' => FormatHex,
'X' => FormatHEX,
's' => FormatString,
- _ => panic!("bad FormatOp char")
+ _ => panic!("bad FormatOp char"),
}
}
fn to_char(self) -> char {
FormatOctal => 'o',
FormatHex => 'x',
FormatHEX => 'X',
- FormatString => 's'
+ FormatString => 's',
}
}
}
-fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
+fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
let mut s = match val {
Number(d) => {
let s = match (op, flags.sign) {
- (FormatDigit, true) => format!("{:+}", d).into_bytes(),
+ (FormatDigit, true) => format!("{:+}", d).into_bytes(),
(FormatDigit, false) => format!("{}", d).into_bytes(),
- (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())
- }
+ (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()),
};
let mut s: Vec<u8> = s.into_iter().collect();
if flags.precision > s.len() {
assert!(!s.is_empty(), "string conversion produced empty result");
match op {
FormatDigit => {
- if flags.space && !(s[0] == b'-' || s[0] == b'+' ) {
+ if flags.space && !(s[0] == b'-' || s[0] == b'+') {
s.insert(0, b' ');
}
}
}
FormatHex => {
if flags.alternate {
- let s_ = replace(&mut s, vec!(b'0', b'x'));
+ let s_ = replace(&mut s, vec![b'0', b'x']);
s.extend(s_);
}
}
FormatHEX => {
s = s.to_ascii_uppercase();
if flags.alternate {
- let s_ = replace(&mut s, vec!(b'0', b'X'));
+ let s_ = replace(&mut s, vec![b'0', b'X']);
s.extend(s_);
}
}
- FormatString => unreachable!()
+ FormatString => unreachable!(),
}
s
}
}
s
}
- _ => {
- return Err(format!("non-string on stack with %{:?}",
- op.to_char()))
- }
+ _ => return Err(format!("non-string on stack with %{:?}", op.to_char())),
}
}
};
#[cfg(test)]
mod tests {
- use super::{expand,Param,Words,Variables,Number};
+ use super::{expand, Param, Words, Variables, Number};
use std::result::Result::Ok;
#[test]
fn test_op_i() {
let mut vars = Variables::new();
assert_eq!(expand(b"%p1%d%p2%d%p3%d%i%p1%d%p2%d%p3%d",
- &[Number(1),Number(2),Number(3)], &mut vars),
+ &[Number(1), Number(2), Number(3)],
+ &mut vars),
Ok("123233".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%d%p2%d%i%p1%d%p2%d", &[], &mut vars),
Ok("0011".bytes().collect::<Vec<_>>()));
fn test_param_stack_failure_conditions() {
let mut varstruct = Variables::new();
let vars = &mut varstruct;
- fn get_res(fmt: &str, cap: &str, params: &[Param], vars: &mut Variables) ->
- Result<Vec<u8>, String>
- {
+ fn get_res(fmt: &str,
+ cap: &str,
+ params: &[Param],
+ vars: &mut Variables)
+ -> Result<Vec<u8>, String> {
let mut u8v: Vec<_> = fmt.bytes().collect();
u8v.extend(cap.bytes());
expand(&u8v, params, vars)
for &cap in &caps {
let res = get_res("", cap, &[], vars);
assert!(res.is_err(),
- "Op {} succeeded incorrectly with 0 stack entries", cap);
+ "Op {} succeeded incorrectly with 0 stack entries",
+ cap);
let p = if cap == "%s" || cap == "%l" {
Words("foo".to_string())
} else {
};
let res = get_res("%p1", cap, &[p], vars);
assert!(res.is_ok(),
- "Op {} failed with 1 stack entry: {}", cap, res.err().unwrap());
+ "Op {} failed with 1 stack entry: {}",
+ cap,
+ res.err().unwrap());
}
let caps = ["%+", "%-", "%*", "%/", "%m", "%&", "%|", "%A", "%O"];
for &cap in &caps {
let res = expand(cap.as_bytes(), &[], vars);
assert!(res.is_err(),
- "Binop {} succeeded incorrectly with 0 stack entries", cap);
+ "Binop {} succeeded incorrectly with 0 stack entries",
+ cap);
let res = get_res("%{1}", cap, &[], vars);
assert!(res.is_err(),
- "Binop {} succeeded incorrectly with 1 stack entry", cap);
+ "Binop {} succeeded incorrectly with 1 stack entry",
+ cap);
let res = get_res("%{1}%{2}", cap, &[], vars);
assert!(res.is_ok(),
- "Binop {} failed with 2 stack entries: {:?}", cap, res.err().unwrap());
+ "Binop {} failed with 2 stack entries: {:?}",
+ cap,
+ res.err().unwrap());
}
}
let s = b"\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m";
let res = expand(s, &[Number(1)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(),
- "\\E[31m".bytes().collect::<Vec<_>>());
+ assert_eq!(res.unwrap(), "\\E[31m".bytes().collect::<Vec<_>>());
let res = expand(s, &[Number(8)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(),
- "\\E[90m".bytes().collect::<Vec<_>>());
+ assert_eq!(res.unwrap(), "\\E[90m".bytes().collect::<Vec<_>>());
let res = expand(s, &[Number(42)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
- assert_eq!(res.unwrap(),
- "\\E[38;5;42m".bytes().collect::<Vec<_>>());
+ assert_eq!(res.unwrap(), "\\E[38;5;42m".bytes().collect::<Vec<_>>());
}
#[test]
&[Words("foo".to_string()),
Words("foo".to_string()),
Words("f".to_string()),
- Words("foo".to_string())], vars),
+ Words("foo".to_string())],
+ vars),
Ok("foofoo ffo".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%:-4.2s", &[Words("foo".to_owned())], vars),
Ok("fo ".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars),
Ok("1001 1+1".bytes().collect::<Vec<_>>()));
- assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X", &[Number(15), Number(27)], vars),
+ assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X",
+ &[Number(15), Number(27)],
+ vars),
Ok("17017 001b0X001B".bytes().collect::<Vec<_>>()));
}
}
// These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable.
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static boolfnames: &'static[&'static str] = &["auto_left_margin", "auto_right_margin",
"no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type",
"no_correctly_working_cr", "gnu_has_meta_key", "linefeed_is_newline", "has_hardware_tabs",
"return_does_clr_eol"];
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static boolnames: &'static[&'static str] = &["bw", "am", "xsb", "xhp", "xenl", "eo",
"gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon",
"nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy",
"xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"];
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static numfnames: &'static[&'static str] = &[ "columns", "init_tabs", "lines",
"lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal",
"bit_image_entwining", "bit_image_type", "magic_cookie_glitch_ul", "carriage_return_delay",
"new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"];
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static numnames: &'static[&'static str] = &[ "cols", "it", "lines", "lm", "xmc", "pb",
"vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv",
"spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs",
"btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"];
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static stringfnames: &'static[&'static str] = &[ "back_tab", "bell", "carriage_return",
"change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos",
"acs_lrcorner", "acs_ltee", "acs_rtee", "acs_btee", "acs_ttee", "acs_hline", "acs_vline",
"acs_plus", "memory_lock", "memory_unlock", "box_chars_1"];
+#[rustfmt_skip]
#[allow(missing_docs)]
pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear",
"_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1",
"box1"];
/// Parse a compiled terminfo entry, using long capability names if `longnames` is true
-pub fn parse(file: &mut Read, longnames: bool)
- -> Result<Box<TermInfo>, String> {
+pub fn parse(file: &mut Read, longnames: bool) -> Result<Box<TermInfo>, String> {
macro_rules! try { ($e:expr) => (
match $e {
Ok(e) => e,
let magic = try!(read_le_u16(file));
if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x}, found {:x}",
- 0x011A_usize, magic as usize));
+ 0x011A_usize,
+ magic as usize));
}
- let names_bytes = try!(read_le_u16(file)) as isize;
- let bools_bytes = try!(read_le_u16(file)) as isize;
- let numbers_count = try!(read_le_u16(file)) as isize;
+ let names_bytes = try!(read_le_u16(file)) as isize;
+ let bools_bytes = try!(read_le_u16(file)) as isize;
+ let numbers_count = try!(read_le_u16(file)) as isize;
let string_offsets_count = try!(read_le_u16(file)) as isize;
- let string_table_bytes = try!(read_le_u16(file)) as isize;
+ let string_table_bytes = try!(read_le_u16(file)) as isize;
- assert!(names_bytes > 0);
+ assert!(names_bytes > 0);
if (bools_bytes as usize) > boolnames.len() {
- return Err("incompatible file: more booleans than \
- expected".to_owned());
+ return Err("incompatible file: more booleans than expected".to_owned());
}
if (numbers_count as usize) > numnames.len() {
- return Err("incompatible file: more numbers than \
- expected".to_owned());
+ return Err("incompatible file: more numbers than expected".to_owned());
}
if (string_offsets_count as usize) > stringnames.len() {
- return Err("incompatible file: more string offsets than \
- expected".to_owned());
+ return Err("incompatible file: more string offsets than expected".to_owned());
}
// don't read NUL
let bytes = try!(read_exact(file, names_bytes as usize - 1));
let names_str = match String::from_utf8(bytes) {
- Ok(s) => s,
+ Ok(s) => s,
Err(_) => return Err("input not utf-8".to_owned()),
};
let string_table = try!(read_exact(file, string_table_bytes as usize));
if string_table.len() != string_table_bytes as usize {
- return Err("error: hit EOF before end of string \
- table".to_owned());
+ return Err("error: hit EOF before end of string table".to_owned());
}
for (i, v) in string_offsets.iter().enumerate() {
let offset = *v;
- if offset == 0xFFFF { // non-entry
+ if offset == 0xFFFF {
+ // non-entry
continue;
}
// Find the offset of the NUL we want to go to
- let nulpos = string_table[offset as usize .. string_table_bytes as usize]
- .iter().position(|&b| b == 0);
+ let nulpos = string_table[offset as usize..string_table_bytes as usize]
+ .iter()
+ .position(|&b| b == 0);
match nulpos {
Some(len) => {
string_map.insert(name.to_string(),
- string_table[offset as usize ..
- (offset as usize + len)].to_vec())
- },
+ string_table[offset as usize..(offset as usize + len)]
+ .to_vec())
+ }
None => {
- return Err("invalid file: missing NUL in \
- string_table".to_owned());
+ return Err("invalid file: missing NUL in string_table".to_owned());
}
};
}
names: term_names,
bools: bools_map,
numbers: numbers_map,
- strings: string_map
+ strings: string_map,
})
}
strings.insert("setaf".to_owned(), b"\x1B[3%p1%dm".to_vec());
strings.insert("setab".to_owned(), b"\x1B[4%p1%dm".to_vec());
box TermInfo {
- names: vec!("cygwin".to_owned()), // msys is a fork of an older cygwin version
+ names: vec!["cygwin".to_owned()], // msys is a fork of an older cygwin version
bools: HashMap::new(),
numbers: HashMap::new(),
- strings: strings
+ strings: strings,
}
}