mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
stat: TODO: more tests
This commit is contained in:
parent
e125118510
commit
fd652bc285
2 changed files with 93 additions and 23 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
// This file is part of the uutils coreutils package.
|
||||||
|
//
|
||||||
|
// (c) Jian Zeng <anonymousknight96@gmail.com>
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE file
|
||||||
|
// that was distributed with this source code.
|
||||||
|
//
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
|
@ -307,8 +315,7 @@ pub fn pretty_fstype<'a>(fstype: i64) -> Cow<'a, str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod test_fsext {
|
||||||
#[allow(unused_imports)]
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
105
src/stat/stat.rs
105
src/stat/stat.rs
|
@ -75,12 +75,12 @@ macro_rules! pad_and_print {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
macro_rules! print_adjusted {
|
macro_rules! print_adjusted {
|
||||||
($str: ident, $left: expr, $width: expr, $padding: expr) => (
|
($str: ident, $left: expr, $width: expr, $padding: expr) => ({
|
||||||
let field_width = cmp::max($width, $str.len());
|
let field_width = cmp::max($width, $str.len());
|
||||||
let mut result = String::with_capacity(field_width);
|
let mut result = String::with_capacity(field_width);
|
||||||
pad_and_print!(result, $str, $left, field_width, $padding);
|
pad_and_print!(result, $str, $left, field_width, $padding);
|
||||||
);
|
});
|
||||||
($str: ident, $left: expr, $need_prefix: expr, $prefix: expr, $width: expr, $padding: expr) => (
|
($str: ident, $left: expr, $need_prefix: expr, $prefix: expr, $width: expr, $padding: expr) => ({
|
||||||
let mut field_width = cmp::max($width, $str.len());
|
let mut field_width = cmp::max($width, $str.len());
|
||||||
let mut result = String::with_capacity(field_width + $prefix.len());
|
let mut result = String::with_capacity(field_width + $prefix.len());
|
||||||
if $need_prefix {
|
if $need_prefix {
|
||||||
|
@ -88,7 +88,7 @@ macro_rules! print_adjusted {
|
||||||
field_width -= $prefix.len();
|
field_width -= $prefix.len();
|
||||||
}
|
}
|
||||||
pad_and_print!(result, $str, $left, field_width, $padding);
|
pad_and_print!(result, $str, $left, field_width, $padding);
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAME: &'static str = "stat";
|
static NAME: &'static str = "stat";
|
||||||
|
@ -124,20 +124,28 @@ pub enum Token {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ScanNum {
|
pub trait ScanUtil {
|
||||||
/// Return (F, offset)
|
|
||||||
fn scan_num<F>(&self) -> Option<(F, usize)> where F: std::str::FromStr;
|
fn scan_num<F>(&self) -> Option<(F, usize)> where F: std::str::FromStr;
|
||||||
|
fn scan_char(&self, radix: u32) -> Option<(char, usize)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScanNum for str {
|
impl ScanUtil for str {
|
||||||
fn scan_num<F>(&self) -> Option<(F, usize)>
|
fn scan_num<F>(&self) -> Option<(F, usize)>
|
||||||
where F: std::str::FromStr
|
where F: std::str::FromStr
|
||||||
{
|
{
|
||||||
let mut chars = self.chars();
|
let mut chars = self.chars();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while let Some(c) = chars.next() {
|
if let Some(c) = chars.next() {
|
||||||
match c {
|
match c {
|
||||||
'-' | '+' | '0' ... '9' => i += 1,
|
'-' | '+' | '0' ... '9' => i += 1,
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
while let Some(c) = chars.next() {
|
||||||
|
match c {
|
||||||
|
'0'...'9' => i += 1,
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +155,40 @@ impl ScanNum for str {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scan_char(&self, radix: u32) -> Option<(char, usize)> {
|
||||||
|
let mut chars = self.chars();
|
||||||
|
let mut i = 0;
|
||||||
|
let count = match radix {
|
||||||
|
8 => 3_usize,
|
||||||
|
16 => 2,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let mut res = 0_u32;
|
||||||
|
while i < count {
|
||||||
|
if let Some(c) = chars.next() {
|
||||||
|
match c.to_digit(radix) {
|
||||||
|
Some(digit) => {
|
||||||
|
let tmp = res * radix + digit;
|
||||||
|
if tmp < 256 {
|
||||||
|
res = tmp;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if i > 0 {
|
||||||
|
Some((res as u8 as char, i))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Stater {
|
pub struct Stater {
|
||||||
|
@ -354,21 +396,29 @@ impl Stater {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match chars[i] {
|
match chars[i] {
|
||||||
'x' => {
|
'x' if i + 1 < bound => {
|
||||||
// TODO: parse character
|
if let Some((c, offset)) = fmtstr[i + 1..].scan_char(16) {
|
||||||
|
tokens.push(Token::Char(c));
|
||||||
|
i += offset;
|
||||||
|
} else {
|
||||||
|
show_warning!("unrecognized escape '\\x'");
|
||||||
|
tokens.push(Token::Char('x'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'0'...'7' => {
|
'0'...'7' => {
|
||||||
// TODO: parse character
|
let (c, offset) = fmtstr[i..].scan_char(8).unwrap();
|
||||||
|
tokens.push(Token::Char(c));
|
||||||
|
i += offset - 1;
|
||||||
}
|
}
|
||||||
'"' => tokens.push(Token::Char('"')),
|
'"' => tokens.push(Token::Char('"')),
|
||||||
'\\' => tokens.push(Token::Char('\\')),
|
'\\' => tokens.push(Token::Char('\\')),
|
||||||
'a' => tokens.push(Token::Char('\x07')),
|
'a' => tokens.push(Token::Char('\x07')),
|
||||||
'b' => tokens.push(Token::Char('\x08')),
|
'b' => tokens.push(Token::Char('\x08')),
|
||||||
'e' => tokens.push(Token::Char('\x1B')),
|
'e' => tokens.push(Token::Char('\x1B')),
|
||||||
'f' => tokens.push(Token::Char('\x0c')),
|
'f' => tokens.push(Token::Char('\x0C')),
|
||||||
'n' => tokens.push(Token::Char('\n')),
|
'n' => tokens.push(Token::Char('\n')),
|
||||||
'r' => tokens.push(Token::Char('\r')),
|
'r' => tokens.push(Token::Char('\r')),
|
||||||
'v' => tokens.push(Token::Char('\x0b')),
|
'v' => tokens.push(Token::Char('\x0B')),
|
||||||
c => {
|
c => {
|
||||||
show_warning!("unrecognized escape '\\{}'", c);
|
show_warning!("unrecognized escape '\\{}'", c);
|
||||||
tokens.push(Token::Char(c));
|
tokens.push(Token::Char(c));
|
||||||
|
@ -401,10 +451,7 @@ impl Stater {
|
||||||
let default_tokens = if fmtstr.is_empty() {
|
let default_tokens = if fmtstr.is_empty() {
|
||||||
Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap()
|
Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap()
|
||||||
} else {
|
} else {
|
||||||
match Stater::generate_tokens(&fmtstr, use_printf) {
|
try!(Stater::generate_tokens(&fmtstr, use_printf))
|
||||||
Ok(ts) => ts,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let default_dev_tokens = Stater::generate_tokens(&Stater::default_fmt(showfs, terse, true),
|
let default_dev_tokens = Stater::generate_tokens(&Stater::default_fmt(showfs, terse, true),
|
||||||
use_printf)
|
use_printf)
|
||||||
|
@ -417,6 +464,7 @@ impl Stater {
|
||||||
line.split_whitespace().nth(1).map(|s| s.to_owned())
|
line.split_whitespace().nth(1).map(|s| s.to_owned())
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
// Reverse sort. The longer comes first.
|
||||||
mount_list.sort_by(|a, b| b.cmp(a));
|
mount_list.sort_by(|a, b| b.cmp(a));
|
||||||
|
|
||||||
Ok(Stater {
|
Ok(Stater {
|
||||||
|
@ -619,18 +667,33 @@ impl Stater {
|
||||||
}
|
}
|
||||||
|
|
||||||
// string
|
// string
|
||||||
// FIXME:
|
|
||||||
'w' => {
|
'w' => {
|
||||||
// time of file birth, human-readable; - if unknown
|
// time of file birth, human-readable; - if unknown
|
||||||
arg = "-".to_owned();
|
arg = if let Some(elapsed) = meta.created()
|
||||||
|
.ok()
|
||||||
|
.map(|t| {
|
||||||
|
t.elapsed().unwrap()
|
||||||
|
}) {
|
||||||
|
pretty_time(elapsed.as_secs() as i64,
|
||||||
|
elapsed.subsec_nanos() as i64)
|
||||||
|
} else {
|
||||||
|
"-".to_owned()
|
||||||
|
};
|
||||||
otype = OutputType::Str;
|
otype = OutputType::Str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int
|
// int
|
||||||
// FIXME:
|
|
||||||
'W' => {
|
'W' => {
|
||||||
// time of file birth, seconds since Epoch; 0 if unknown
|
// time of file birth, seconds since Epoch; 0 if unknown
|
||||||
arg = format!("{}", 0);
|
arg = if let Some(elapsed) = meta.created()
|
||||||
|
.ok()
|
||||||
|
.map(|t| {
|
||||||
|
t.elapsed().unwrap()
|
||||||
|
}) {
|
||||||
|
format!("{}", elapsed.as_secs())
|
||||||
|
} else {
|
||||||
|
"0".to_owned()
|
||||||
|
};
|
||||||
otype = OutputType::Integer;
|
otype = OutputType::Integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue