coreutils/env/env.rs

214 lines
6.6 KiB
Rust
Raw Normal View History

2014-03-31 16:40:21 +00:00
#![crate_id(name="env", vers="1.0.0", author="LeoTestard")]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* last synced with: env (GNU coreutils) 8.13 */
2014-03-31 16:40:21 +00:00
#![allow(non_camel_case_types)]
2014-02-23 21:31:51 +00:00
2014-05-28 11:43:37 +00:00
use std::os;
2013-10-22 18:25:38 +00:00
struct options {
ignore_env: bool,
null: bool,
2014-05-25 09:20:52 +00:00
unsets: Vec<String>,
sets: Vec<(String, String)>,
program: Vec<String>
2013-10-22 18:25:38 +00:00
}
fn usage(prog: &str) {
println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog);
2013-10-23 16:25:45 +00:00
println!("Set each NAME to VALUE in the environment and run COMMAND\n");
2013-10-22 18:25:38 +00:00
println!("Possible options are:");
println!(" -i --ignore-environment\t start with an empty environment");
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!(" -h --help \t display this help and exit");
println!(" -V --version \t output version information and exit\n");
2013-10-23 16:25:45 +00:00
println!("A mere - implies -i. If no COMMAND, print the resulting environment");
2013-10-22 18:25:38 +00:00
}
fn version() {
2013-10-23 16:25:45 +00:00
println!("env 1.0.0");
2013-10-22 18:25:38 +00:00
}
2013-10-23 16:25:45 +00:00
// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
2013-10-22 18:25:38 +00:00
fn print_env(null: bool) {
2013-10-23 16:25:45 +00:00
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' }
);
}
2013-10-22 18:25:38 +00:00
}
#[allow(dead_code)]
2014-05-28 11:43:37 +00:00
fn main() { uumain(os::args()); }
pub fn uumain(args: Vec<String>) {
2014-05-16 10:03:46 +00:00
let prog = args.get(0).as_slice();
2013-10-22 18:25:38 +00:00
// to handle arguments the same way than GNU env, we can't use getopts
2014-05-09 00:12:57 +00:00
let mut opts = box options {
2013-10-22 18:25:38 +00:00
ignore_env: false,
null: false,
unsets: vec!(),
sets: vec!(),
program: vec!()
2013-10-22 18:25:38 +00:00
};
let mut wait_cmd = false;
let mut iter = args.iter();
iter.next(); // skip program
2013-10-23 16:25:45 +00:00
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();
2013-10-22 18:25:38 +00:00
if wait_cmd {
// we still accept NAME=VAL here but not other options
2014-05-23 12:28:40 +00:00
let mut sp = opt.as_slice().splitn('=', 1);
2013-10-22 18:25:38 +00:00
let name = sp.next();
let value = sp.next();
match (name, value) {
2013-10-23 16:25:45 +00:00
(Some(n), Some(v)) => {
opts.sets.push((n.into_owned(), v.into_owned()));
2013-10-22 18:25:38 +00:00
}
_ => {
// read the program now
2014-05-28 06:33:39 +00:00
opts.program.push(opt.to_string());
2013-10-22 18:25:38 +00:00
break;
}
}
2014-05-23 12:28:40 +00:00
} else if opt.as_slice().starts_with("--") {
match opt.as_slice() {
"--help" => { usage(prog); return }
"--version" => { version(); return }
"--ignore-environment" => opts.ignore_env = true,
"--null" => opts.null = true,
"--unset" => {
let var = iter.next();
match var {
None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
2014-05-28 06:33:39 +00:00
Some(s) => opts.unsets.push(s.to_string())
}
}
2013-10-22 18:25:38 +00:00
_ => {
println!("{:s}: invalid option \"{:s}\"", prog, *opt);
println!("Type \"{:s} --help\" for detailed informations", prog);
return
}
}
2014-05-23 12:28:40 +00:00
} else if opt.as_slice().starts_with("-") {
if opt.len() == 0 {
// implies -i and stop parsing opts
wait_cmd = true;
opts.ignore_env = true;
continue;
}
2013-10-22 18:25:38 +00:00
2014-05-23 12:28:40 +00:00
let mut chars = opt.as_slice().chars();
chars.next();
for c in chars {
// short versions of options
match c {
'h' => { usage(prog); return }
'V' => { version(); return }
'i' => opts.ignore_env = true,
'0' => opts.null = true,
'u' => {
2013-10-23 16:25:45 +00:00
let var = iter.next();
2013-10-22 18:25:38 +00:00
2013-10-23 16:25:45 +00:00
match var {
None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
2014-05-28 06:33:39 +00:00
Some(s) => opts.unsets.push(s.to_string())
2013-10-23 16:25:45 +00:00
}
2013-10-22 18:25:38 +00:00
}
_ => {
println!("{:s}: illegal option -- {:c}", prog, c);
2013-10-22 18:25:38 +00:00
println!("Type \"{:s} --help\" for detailed informations", prog);
return
}
}
}
} else {
// is it a NAME=VALUE like opt ?
2014-05-23 12:28:40 +00:00
let mut sp = opt.as_slice().splitn('=', 1);
let name = sp.next();
let value = sp.next();
2013-10-22 18:25:38 +00:00
match (name, value) {
(Some(n), Some(v)) => {
// yes
opts.sets.push((n.into_owned(), v.into_owned()));
2013-10-23 16:25:45 +00:00
wait_cmd = true;
}
// no, its a program-like opt
_ => {
2014-05-28 06:33:39 +00:00
opts.program.push(opt.to_string());
break;
2013-10-22 18:25:38 +00:00
}
}
}
2013-10-23 16:25:45 +00:00
item = iter.next();
2013-10-22 18:25:38 +00:00
}
// read program arguments
2013-10-22 18:25:38 +00:00
for opt in iter {
2014-05-28 06:33:39 +00:00
opts.program.push(opt.to_string());
2013-10-22 18:25:38 +00:00
}
let env = std::os::env();
if opts.ignore_env {
for &(ref name, _) in env.iter() {
std::os::unsetenv(name.as_slice())
}
}
2013-10-23 16:25:45 +00:00
for ref name in opts.unsets.iter() {
std::os::unsetenv(name.as_slice())
}
2013-10-22 18:25:38 +00:00
for &(ref name, ref val) in opts.sets.iter() {
std::os::setenv(name.as_slice(), val.as_slice())
}
2014-02-23 21:31:51 +00:00
if opts.program.len() >= 1 {
2014-05-16 10:04:03 +00:00
use std::io::process::{Command, InheritFd};
let prog = opts.program.get(0).clone();
let args = opts.program.slice_from(1);
match Command::new(prog).args(args).stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
2014-02-23 21:31:51 +00:00
Ok(exit) =>
std::os::set_exit_status(match exit {
std::io::process::ExitStatus(s) => s,
_ => 1
}),
Err(_) => std::os::set_exit_status(1)
2013-10-23 16:25:45 +00:00
}
2014-02-23 21:31:51 +00:00
} else {
// no program provided
print_env(opts.null);
2013-10-22 18:25:38 +00:00
}
}