1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

echo: handle -- correctly

This commit is contained in:
Arcterus 2014-06-19 13:05:43 -07:00
parent ca06ef6155
commit 76cf0e47ed
2 changed files with 67 additions and 46 deletions

View file

@ -20,9 +20,15 @@ use std::uint;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
mod util; mod util;
#[allow(dead_code)]
static NAME: &'static str = "echo"; static NAME: &'static str = "echo";
static VERSION: &'static str = "1.0.0"; static VERSION: &'static str = "1.0.0";
struct EchoOptions {
newline: bool,
escape: bool
}
fn print_char(c: char) { fn print_char(c: char) {
print!("{}", c); print!("{}", c);
} }
@ -70,33 +76,27 @@ fn convert_str(string: &str, index: uint, base: uint) -> (char, int) {
(to_char(&bytes, base), max_digits) (to_char(&bytes, base), max_digits)
} }
#[allow(dead_code)] fn parse_options(args: Vec<String>, options: &mut EchoOptions) -> Option<Vec<String>> {
fn main() { os::set_exit_status(uumain(os::args())); } let mut echo_args = vec!();
pub fn uumain(args: Vec<String>) -> int {
let program = args.get(0).clone(); let program = args.get(0).clone();
let opts = [ for arg in args.move_iter().skip(1) {
getopts::optflag("n", "", "do not output the trailing newline"), match arg.as_slice() {
getopts::optflag("e", "", "enable interpretation of backslash escapes"), "--help" | "-h" => {
getopts::optflag("E", "", "disable interpretation of backslash escapes (default)"), let opts = [
getopts::optflag("h", "help", "display this help and exit"), getopts::optflag("n", "", "do not output the trailing newline"),
getopts::optflag("V", "version", "output version information and exit"), getopts::optflag("e", "", "enable interpretation of backslash escapes"),
]; getopts::optflag("E", "", "disable interpretation of backslash escapes (default)"),
getopts::optflag("h", "help", "display this help and exit"),
let matches = match getopts::getopts(args.tail(), opts) { getopts::optflag("V", "version", "output version information and exit"),
Ok(m) => m, ];
Err(f) => crash!(1, "Invalid options\n{}", f) println!("echo {:s} - display a line of text", VERSION);
}; println!("");
println!("Usage:");
if matches.opt_present("help") { println!(" {0:s} [SHORT-OPTION]... [STRING]...", program);
println!("echo {:s} - display a line of text", VERSION); println!(" {0:s} LONG-OPTION", program);
println!(""); println!("");
println!("Usage:"); println(getopts::usage("Echo the STRING(s) to standard output.", opts).as_slice());
println!(" {0:s} [SHORT-OPTION]... [STRING]...", program); println("If -e is in effect, the following sequences are recognized:
println!(" {0:s} LONG-OPTION", program);
println!("");
println(getopts::usage("Echo the STRING(s) to standard output.", opts).as_slice());
println("If -e is in effect, the following sequences are recognized:
\\\\ backslash \\\\ backslash
\\a alert (BEL) \\a alert (BEL)
@ -110,17 +110,38 @@ pub fn uumain(args: Vec<String>) -> int {
\\v vertical tab \\v vertical tab
\\0NNN byte with octal value NNN (1 to 3 digits) \\0NNN byte with octal value NNN (1 to 3 digits)
\\xHH byte with hexadecimal value HH (1 to 2 digits)"); \\xHH byte with hexadecimal value HH (1 to 2 digits)");
return 0; return None;
}
"--version" | "-V" => {
println!("echo version: {:s}", VERSION);
return None;
}
"-n" => options.newline = true,
"-e" => options.escape = true,
"-E" => options.escape = false,
_ => echo_args.push(arg)
}
} }
Some(echo_args)
}
if matches.opt_present("version") { #[allow(dead_code)]
println!("echo version: {:s}", VERSION); fn main() { os::set_exit_status(uumain(os::args())); }
return 0;
}
if !matches.free.is_empty() { pub fn uumain(args: Vec<String>) -> int {
let string = matches.free.connect(" "); let mut options = EchoOptions {
if matches.opt_present("e") { newline: false,
escape: false
};
let free = match parse_options(args, &mut options) {
Some(vec) => vec,
None => return 0
};
if !free.is_empty() {
let string = free.connect(" ");
if options.escape {
let mut prev_was_slash = false; let mut prev_was_slash = false;
let mut iter = string.as_slice().chars().enumerate(); let mut iter = string.as_slice().chars().enumerate();
loop { loop {
@ -184,7 +205,7 @@ pub fn uumain(args: Vec<String>) -> int {
} }
} }
if !matches.opt_present("n") { if !options.newline {
println!("") println!("")
} }

View file

@ -117,17 +117,17 @@ fn util_map() -> HashMap<&str, fn(Vec<String>) -> int> {
} }
fn usage(cmap: &HashMap<&str, fn(Vec<String>) -> int>) { fn usage(cmap: &HashMap<&str, fn(Vec<String>) -> int>) {
println!("{} {}", NAME, VERSION); println!("{} {}", NAME, VERSION);
println!(""); println!("");
println!("Usage:"); println!("Usage:");
println!(" {} [util [arguments...]", NAME); println!(" {} [util [arguments...]", NAME);
println!("Currently defined functions:"); println!("Currently defined functions:");
let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect(); let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
utils.sort(); utils.sort();
for util in utils.iter() { for util in utils.iter() {
println!("\t{}", util); println!("\t{}", util);
} }
println!(""); println!("");
} }
fn main() { fn main() {