///|
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 == "" {
    return None
  }
  Some((key, pieces[1:].join("=")))
}

///|
async fn main {
  let args = @core_env.args()[1:]
  let mut ignore_environment = false
  let mut null_output = false
  let base_cwd = @core_env.current_dir().unwrap_or(".")
  let mut cwd = base_cwd
  let mut chdir_requested = 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 == "-" {
      ignore_environment = true
    } else if options && (arg == "-0" || arg == "--null") {
      null_output = true
    } else if options && (arg == "-C" || arg == "--chdir") {
      if i + 1 >= args.length() {
        @stdio.stderr.write("env: option requires an argument: \{arg}\n")
        @sys.exit(125)
        return
      }
      i += 1
      chdir_requested = true
      let directory = @path.Path(args[i])
      cwd = if directory.is_absolute() {
        directory.normalize().to_string()
      } else {
        @path.Path(base_cwd).join(directory).normalize().to_string()
      }
    } else if options && arg.has_prefix("--chdir=") {
      chdir_requested = true
      let directory = @path.Path(arg[8:].to_owned())
      cwd = if directory.is_absolute() {
        directory.normalize().to_string()
      } else {
        @path.Path(base_cwd).join(directory).normalize().to_string()
      }
    } else if options && arg.has_prefix("-C") && arg.length() > 2 {
      chdir_requested = true
      let directory = @path.Path(arg[2:].to_owned())
      cwd = if directory.is_absolute() {
        directory.normalize().to_string()
      } else {
        @path.Path(base_cwd).join(directory).normalize().to_string()
      }
    } 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))
      options = false
    } else if !options && split_assignment(arg) is Some((key, value)) {
      assignments.push((key, value))
    } else if arg.has_prefix("=") {
      @stdio.stderr.write(
        "env: invalid environment variable assignment: {arg}\n",
      )
      @sys.exit(125)
      return
    } 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}")
      }
      for line in lines {
        @stdio.stdout.write(line)
        @stdio.stdout.write(if null_output { "\u0000" } else { "\n" })
      }
    }
    Some(program) => {
      if null_output {
        @stdio.stderr.write("env: cannot specify --null (-0) with command\n")
        @sys.exit(125)
        return
      }
      if chdir_requested {
        let cwd_kind = @fs.kind(cwd) catch {
          err => {
            @stdio.stderr.write(
              "env: cannot change directory to '\{cwd}': \{err}\n",
            )
            @sys.exit(125)
            return
          }
        }
        match cwd_kind {
          Directory => ()
          _ => {
            @stdio.stderr.write(
              "env: cannot change directory to '\{cwd}': not a directory\n",
            )
            @sys.exit(125)
            return
          }
        }
      }
      let context : @process.ExecutionContext = { cwd, 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")
          let explicit_path = @path.Path(program).is_absolute() ||
            program.contains("/") ||
            program.contains("\\")
          let existing_directory = if err.is_ENOENT() && explicit_path {
            let kind = @fs.kind(program) catch { _ => Regular }
            kind == Directory
          } else {
            false
          }
          @sys.exit(
            @process.launch_failure_status(
              if err.is_ENOENT() && !existing_directory {
                CommandNotFound
              } else {
                CommandNotInvokable
              },
            ),
          )
          return
        }
        err => {
          @stdio.stderr.write("env: cannot run '\{program}': \{err}\n")
          @sys.exit(@process.launch_failure_status(CommandNotInvokable))
          return
        }
      }
      if code != 0 {
        @sys.exit(code)
      }
    }
  }
}