///|
/// Result of decoding one backslash escape sequence.
priv enum EscOut {
  Out(Array[Byte])
  Stop
  Invalid(String)
}

///|
fn hex_val(c : Char) -> Int32 {
  match c {
    '0'..<='9' => c.to_int() - 0x30
    'a'..<='f' => c.to_int() - 0x61 + 10
    'A'..<='F' => c.to_int() - 0x41 + 10
    _ => -1
  }
}

///|
fn push_char_utf8(out : Array[Byte], c : Char) -> Unit {
  if c.to_int() < 0x80 {
    out.push(c.to_int().to_byte())
  } else {
    for b in @utf8.encode(c.to_string()) {
      out.push(b)
    }
  }
}

///|
fn push_string_utf8(out : Array[Byte], s : String) -> Unit {
  for b in @utf8.encode(s) {
    out.push(b)
  }
}

///|
/// Decode the escape sequence whose backslash sits at `start`. Returns the
/// output and the number of characters consumed (including the backslash).
/// Octal accepts `\NNN` and `\0NNN`, hex `\xHH`, Unicode `\uHHHH`/`\UHHHHHHHH`,
/// and `\c` stops all output. Unknown escapes pass through literally.
fn decode_escape(
  chars : Array[Char],
  start : Int32,
  in_b~ : Bool = false,
) -> (EscOut, Int32) {
  if start + 1 >= chars.length() {
    return (Out([b'\\']), 1)
  }
  let e = chars[start + 1]
  let simple : Int32 = match e {
    'a' => 0x07
    'b' => 0x08
    'e' => 0x1B
    'f' => 0x0C
    'n' => 0x0A
    'r' => 0x0D
    't' => 0x09
    'v' => 0x0B
    '\\' => 0x5C
    '"' => 0x22
    '\'' => 0x27
    _ => -1
  }
  if simple >= 0 {
    return (Out([simple.to_byte()]), 2)
  }
  if e == 'c' {
    return (Stop, 2)
  }
  if e is ('0'..<='7') {
    // FORMAT strings take up to three octal digits total (`\101`, and `\010`
    // leaves a following digit alone). In %b arguments a leading `0` is a
    // marker followed by up to three more digits (`\0102` is one byte), while
    // `\101` still works, matching GNU printf.
    let mut i = start + 1
    if in_b && e == '0' {
      i += 1
    }
    let mut value = 0
    let mut count = 0
    while i < chars.length() && count < 3 && chars[i] is ('0'..<='7') {
      value = value * 8 + (chars[i].to_int() - 0x30)
      i += 1
      count += 1
    }
    return (Out([(value % 256).to_byte()]), i - start)
  }
  if e == 'x' {
    let mut i = start + 2
    let mut value = 0
    let mut count = 0
    while i < chars.length() && count < 2 && hex_val(chars[i]) >= 0 {
      value = value * 16 + hex_val(chars[i])
      i += 1
      count += 1
    }
    if count == 0 {
      return (Invalid("printf: missing hexadecimal number in escape"), 2)
    }
    return (Out([value.to_byte()]), 2 + count)
  }
  if e == 'u' || e == 'U' {
    let need = if e == 'u' { 4 } else { 8 }
    let mut value = 0
    for k in 0..= chars.length() || hex_val(chars[idx]) < 0 {
        return (Invalid("printf: missing hexadecimal number in escape"), 2)
      }
      value = value * 16 + hex_val(chars[idx])
    }
    if value >= 0xD800 && value <= 0xDFFF {
      // Surrogates are rejected like GNU printf...
      return (
        Invalid("printf: invalid universal character name \\\{e}"),
        2 + need,
      )
    }
    match value.to_char() {
      Some(c) => {
        let out : Array[Byte] = []
        push_char_utf8(out, c)
        (Out(out), 2 + need)
      }
      None => {
        // ...while complete but out-of-range names pass through literally.
        let out : Array[Byte] = []
        out.push(b'\\')
        push_char_utf8(out, e)
        for k in 0.. String {
  let sb = StringBuilder()
  for _ in 0.. String {
  match prec {
    Some(p) => {
      if body == "0" && p == 0 {
        return ""
      }
      if body.length() >= p {
        body
      } else {
        repeat_char('0', p - body.length()) + body
      }
    }
    None => body
  }
}

///|
/// Assemble sign/prefix + body into a field of `width` characters. With the
/// zero flag, padding zeros go between the prefix and the body.
fn pad_field(
  prefix : String,
  body : String,
  width : Int32?,
  minus : Bool,
  zero : Bool,
) -> String {
  let content = prefix + body
  match width {
    Some(w) =>
      if content.length() >= w {
        content
      } else if minus {
        content + repeat_char(' ', w - content.length())
      } else if zero {
        prefix + repeat_char('0', w - content.length()) + body
      } else {
        repeat_char(' ', w - content.length()) + content
      }
    None => content
  }
}

///|
/// Append raw bytes into `out`, space-padded to `width` bytes.
fn emit_padded_bytes(
  out : Array[Byte],
  bytes : Array[Byte],
  width : Int32?,
  minus : Bool,
) -> Unit {
  let pad = match width {
    Some(w) => if w > bytes.length() { w - bytes.length() } else { 0 }
    None => 0
  }
  if pad > 0 && !minus {
    for _ in 0.. 0 && minus {
    for _ in 0.. String {
  @quoting.shell_escape(@utf8.encode(text)[:])
}