mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 03:57:44 +00:00
echo: refactor slightly
This commit is contained in:
parent
26ad240572
commit
ec543508bc
1 changed files with 49 additions and 59 deletions
108
src/echo/echo.rs
108
src/echo/echo.rs
|
@ -16,9 +16,9 @@ use std::io::{Write, stdout};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
static SYNTAX: &'static str = "[OPTIONS]... [STRING]...";
|
static SYNTAX: &str = "[OPTIONS]... [STRING]...";
|
||||||
static SUMMARY: &'static str = "display a line of text";
|
static SUMMARY: &str = "display a line of text";
|
||||||
static LONG_HELP: &'static str = r#"
|
static HELP: &str = r#"
|
||||||
Echo the STRING(s) to standard output.
|
Echo the STRING(s) to standard output.
|
||||||
If -e is in effect, the following sequences are recognized:
|
If -e is in effect, the following sequences are recognized:
|
||||||
|
|
||||||
|
@ -36,26 +36,24 @@ static LONG_HELP: &'static str = r#"
|
||||||
\\xHH byte with hexadecimal value HH (1 to 2 digits)
|
\\xHH byte with hexadecimal value HH (1 to 2 digits)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[derive(Clone)]
|
enum Base {
|
||||||
struct EchoOptions {
|
B8 = 8,
|
||||||
|
B16 = 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Opts {
|
||||||
newline: bool,
|
newline: bool,
|
||||||
escape: bool
|
escape: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
fn convert_str(string: &[u8], index: usize, base: Base) -> (char, usize) {
|
||||||
fn to_char(bytes: &[u8], base: u32) -> char {
|
let (max_digits, is_legal_digit): (usize, fn(u8) -> bool) = match base {
|
||||||
usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
|
Base::B8 => (3, |c| { (c as char).is_digit(8) }),
|
||||||
}
|
Base::B16 => (2, |c| { (c as char).is_digit(16) }),
|
||||||
|
|
||||||
fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
|
|
||||||
let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
|
|
||||||
8 => (3, |c| { (c as char).is_digit(8) }),
|
|
||||||
16 => (2, |c| { (c as char).is_digit(16) }),
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = vec!();
|
let mut bytes = vec![];
|
||||||
for offset in 0usize .. max_digits {
|
for offset in 0..max_digits {
|
||||||
if string.len() <= index + offset as usize {
|
if string.len() <= index + offset as usize {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -70,39 +68,39 @@ fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
|
||||||
if bytes.is_empty() {
|
if bytes.is_empty() {
|
||||||
(' ', 0)
|
(' ', 0)
|
||||||
} else {
|
} else {
|
||||||
(to_char(&bytes, base), bytes.len())
|
(usize::from_str_radix(
|
||||||
|
from_utf8(bytes.as_ref()).unwrap(),
|
||||||
|
base as u32
|
||||||
|
).unwrap() as u8 as char, bytes.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: Vec<String>) -> i32 {
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
let mut options = EchoOptions {
|
let matches = new_coreopts!(SYNTAX, SUMMARY, HELP)
|
||||||
newline: false,
|
|
||||||
escape: false
|
|
||||||
};
|
|
||||||
|
|
||||||
let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP)
|
|
||||||
.optflag("n", "", "do not output the trailing newline")
|
.optflag("n", "", "do not output the trailing newline")
|
||||||
.optflag("e", "", "enable interpretation of backslash escapes")
|
.optflag("e", "", "enable interpretation of backslash escapes")
|
||||||
.optflag("E", "", "disable interpretation of backslash escapes (default)")
|
.optflag("E", "", "disable interpretation of backslash escapes (default)")
|
||||||
.parse(args);
|
.parse(args);
|
||||||
|
|
||||||
options.newline = matches.opt_present("n");
|
let options = Opts {
|
||||||
options.escape = matches.opt_present("e");
|
newline: matches.opt_present("n"),
|
||||||
|
escape: matches.opt_present("e"),
|
||||||
|
};
|
||||||
let free = matches.free;
|
let free = matches.free;
|
||||||
if !free.is_empty() {
|
if !free.is_empty() {
|
||||||
let string = free.join(" ");
|
let string = free.join(" ");
|
||||||
if options.escape {
|
if options.escape {
|
||||||
let mut prev_was_slash = false;
|
let mut prev_was_slash = false;
|
||||||
let mut iter = string.chars().enumerate();
|
let mut iter = string.chars().enumerate();
|
||||||
while let Some((index, c)) = iter.next() {
|
while let Some((mut idx, c)) = iter.next() {
|
||||||
if !prev_was_slash {
|
prev_was_slash = if !prev_was_slash {
|
||||||
if c != '\\' {
|
if c != '\\' {
|
||||||
print!("{}", c);
|
print!("{}", c);
|
||||||
|
false
|
||||||
} else {
|
} else {
|
||||||
prev_was_slash = true;
|
true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prev_was_slash = false;
|
|
||||||
match c {
|
match c {
|
||||||
'\\' => print!("\\"),
|
'\\' => print!("\\"),
|
||||||
'n' => print!("\n"),
|
'n' => print!("\n"),
|
||||||
|
@ -114,40 +112,32 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
'c' => break,
|
'c' => break,
|
||||||
'e' => print!("\x1B"),
|
'e' => print!("\x1B"),
|
||||||
'f' => print!("\x0C"),
|
'f' => print!("\x0C"),
|
||||||
'x' => {
|
ch => { // 'x' or '0' or _
|
||||||
let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
|
idx = if ch == 'x' || ch == '0' {
|
||||||
if num_char_used == 0 {
|
idx + 1
|
||||||
print!("\\x");
|
|
||||||
} else {
|
} else {
|
||||||
print!("{}", c);
|
idx
|
||||||
for _ in 0 .. num_char_used {
|
};
|
||||||
iter.next(); // consume used characters
|
let base = if ch == 'x' { Base::B16 } else { Base::B8 };
|
||||||
}
|
match convert_str(string.as_bytes(), idx, base) {
|
||||||
}
|
(_, 0) => {
|
||||||
},
|
match ch {
|
||||||
'0' => {
|
'x' => print!("\\x"),
|
||||||
let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
|
'0' => print!("\0"),
|
||||||
if num_char_used == 0 {
|
_ => print!("\\{}", c),
|
||||||
print!("\0");
|
}
|
||||||
} else {
|
},
|
||||||
print!("{}", c);
|
(c, num_char_used) => {
|
||||||
for _ in 0 .. num_char_used {
|
print!("{}", c);
|
||||||
iter.next(); // consume used characters
|
let beg = if ch == 'x' || ch == '0' { 0 } else { 1 };
|
||||||
}
|
for _ in beg..num_char_used {
|
||||||
}
|
iter.next(); // consume used characters
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
|
|
||||||
if num_char_used == 0 {
|
|
||||||
print!("\\{}", c);
|
|
||||||
} else {
|
|
||||||
print!("{}", esc_c);
|
|
||||||
for _ in 1 .. num_char_used {
|
|
||||||
iter.next(); // consume used characters
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue