1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

fix option parsing

This commit is contained in:
Léo Testard 2013-10-23 18:25:45 +02:00
parent 4f7b7c80a5
commit cd32db7afa

121
env/env.rs vendored
View file

@ -8,18 +8,32 @@ struct options {
fn usage(prog: &str) { fn usage(prog: &str) {
println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog); println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog);
println!("Sets each NAME as VALUE in the environment, then run COMMAND\n"); println!("Set each NAME to VALUE in the environment and run COMMAND\n");
println!("Possible options are:"); println!("Possible options are:");
println!(" -i, --ignore-environment starts with an empty environment"); println!(" -i, --ignore-environment\t start with an empty environment");
println!(" -0, --null end each line with a 0 byte instead of a \\\\n\n"); println!(" -0, --null \t end each output line with a 0 byte rather than newline");
println!(" -u, --unset NAME \t remove variable from the environment");
println!(" --help \t display this help and exit");
println!(" --version \t output version information and exit\n");
println!("A mere - implies -i. If no COMMAND, print the resulting environment");
} }
fn version() { fn version() {
println!("env (Rust Coreutils) 1.0"); println!("env 1.0.0");
} }
// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) { fn print_env(null: bool) {
println!("env!") let env = std::os::env();
for &(ref n, ref v) in env.iter() {
print!("{:s}={:s}{:c}",
n.as_slice(),
v.as_slice(),
if null { '\0' } else { '\n' }
);
}
} }
fn main() { fn main() {
@ -40,8 +54,14 @@ fn main() {
let mut wait_cmd = false; let mut wait_cmd = false;
let mut iter = args.iter(); let mut iter = args.iter();
iter.next(); // skip program iter.next(); // skip program
let mut item = iter.next();
// the for loop doesn't work here,
// because we need sometines to read 2 items forward,
// and the iter can't be borrowed twice
while item != None {
let opt = item.unwrap();
for opt in iter {
if wait_cmd { if wait_cmd {
// we still accept NAME=VAL here but not other options // we still accept NAME=VAL here but not other options
let mut sp = opt.splitn_iter('=', 1); let mut sp = opt.splitn_iter('=', 1);
@ -66,12 +86,15 @@ fn main() {
~"--help" => { usage(prog); return } ~"--help" => { usage(prog); return }
~"--version" => { version(); return } ~"--version" => { version(); return }
~"--ignore-environment" => { ~"--ignore-environment" => opts.ignore_env = true,
opts.ignore_env = true; ~"--null" => opts.null = true,
} ~"--unset" => {
let var = iter.next();
~"--null" => { match var {
opts.null = true; None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
Some(s) => opts.unsets.push(s.to_owned())
}
} }
_ => { _ => {
@ -82,39 +105,57 @@ fn main() {
} }
} }
else { else if opt.starts_with("-") {
match *opt { if opt.len() == 0 {
~"-" => { // implies -i and stop parsing opts
// implies -i and stop parsing opts wait_cmd = true;
wait_cmd = true; opts.ignore_env = true;
opts.ignore_env = true; continue;
} }
_ => { let mut chars = opt.iter();
// is it a NAME=VALUE like opt ? chars.next();
let mut sp = opt.splitn_iter('=', 1);
let name = sp.next();
let value = sp.next();
match (name, value) { for c in chars {
(Some(n), Some(v)) => { // short versions of options
// yes match c {
opts.sets.push((n.into_owned(), v.into_owned())); 'i' => opts.ignore_env = true,
wait_cmd = true; '0' => opts.null = true,
} _ => {
// no, its a program-like opt println!("{:s}: illegal option -- {:c}", prog, c);
_ => { println!("Type \"{:s} --help\" for detailed informations", prog);
opts.program.push(opt.to_owned()); return
break;
}
} }
} }
} }
} }
else {
// is it a NAME=VALUE like opt ?
let mut sp = opt.splitn_iter('=', 1);
let name = sp.next();
let value = sp.next();
match (name, value) {
(Some(n), Some(v)) => {
// yes
opts.sets.push((n.into_owned(), v.into_owned()));
wait_cmd = true;
}
// no, its a program-like opt
_ => {
opts.program.push(opt.to_owned());
break;
}
}
}
} }
item = iter.next();
} }
// read program arguments now // read program arguments now
for opt in iter { for opt in iter {
opts.program.push(opt.to_owned()); opts.program.push(opt.to_owned());
} }
@ -127,15 +168,23 @@ fn main() {
} }
} }
for ref name in opts.unsets.iter() {
std::os::unsetenv(name.as_slice())
}
for &(ref name, ref val) in opts.sets.iter() { for &(ref name, ref val) in opts.sets.iter() {
std::os::setenv(name.as_slice(), val.as_slice()) std::os::setenv(name.as_slice(), val.as_slice())
} }
match opts.program { match opts.program {
[ref prog, ..args] => { [ref prog, ..args] => {
let status = std::run::process_status(prog.as_slice(), args); let status = std::run::process_status(prog.as_slice(), args.as_slice());
std::os::set_exit_status(status) std::os::set_exit_status(status)
} }
[] => { print_env(opts.null); }
[] => {
// no program providen
print_env(opts.null);
}
} }
} }