///|
fn split_assignment(value : String) -> (String, String)? {
let pieces : Array[String] = value.split("=").map(v => v.to_owned()).collect()
if pieces.length() < 2 {
return None
}
let key = pieces[0]
if key == "" || !is_valid_name(key) {
return None
}
Some((key, pieces[1:].join("=")))
}
///|
fn is_valid_name(value : String) -> Bool {
let chars : Array[Char] = value.iter().collect()
if chars.is_empty() {
return false
}
if !(chars[0] == '_' || chars[0] is ('a'..='z' | 'A'..='Z')) {
return false
}
for char in chars[1:] {
if !(char == '_' || char is ('a'..='z' | 'A'..='Z' | '0'..='9')) {
return false
}
}
true
}
///|
async fn main {
let args = @core_env.args()[1:]
let mut ignore_environment = false
let unset : Array[String] = []
let assignments : Array[(String, String)] = []
let command_args : Array[String] = []
let mut command : String? = None
let mut options = true
let mut i = 0
while i < args.length() {
let arg = args[i]
if command is Some(_) {
command_args.push(arg)
} else if options && arg == "--" {
options = false
} else if options && (arg == "-i" || arg == "--ignore-environment") {
ignore_environment = true
} else if options && (arg == "-u" || arg == "--unset") {
if i + 1 >= args.length() {
@stdio.stderr.write("env: option requires an argument: \{arg}\n")
@sys.exit(125)
return
}
i += 1
unset.push(args[i])
} else if options && arg.has_prefix("--unset=") {
unset.push(arg[8:].to_owned())
} else if options && split_assignment(arg) is Some((key, value)) {
assignments.push((key, value))
} else if arg.has_prefix("-") && options {
@stdio.stderr.write("env: unsupported option: \{arg}\n")
@sys.exit(125)
return
} else {
command = Some(arg)
}
i += 1
}
let variables : Map[String, String] = if ignore_environment {
Map([])
} else {
@process.default_environment()
}
for name in unset {
variables.remove(name)
}
for index in 0.. {
let lines : Array[String] = []
for key, value in variables {
lines.push("\{key}=\{value}")
}
lines.sort()
for line in lines {
@stdio.stdout.write("\{line}\n")
}
}
Some(program) => {
let context : @process.ExecutionContext = {
cwd: @core_env.current_dir().unwrap_or("."),
env: variables,
}
let code = @process.run(@process.child(program, command_args, context~)) catch {
@os_error.OSError(_) as err => {
@stdio.stderr.write("env: cannot run '\{program}': \{err}\n")
@sys.exit(if err.is_ENOENT() { 127 } else { 126 })
return
}
err => {
@stdio.stderr.write("env: cannot run '\{program}': \{err}\n")
@sys.exit(126)
return
}
}
if code != 0 {
@sys.exit(code)
}
}
}
}