///|
fn Machine::display_char(self : Machine, code : Int32) -> Unit raise Fault {
  if self.output_count >= 1048576 {
    raise Invalid("output limit exceeded; drain output between runs")
  }
  self.output_count += 1
  let w = self.window
  if w == 0 {
    self.output.write_char(code.unsafe_to_char())
  }
  if code == 10 {
    self.rows[w] += 1
    self.columns[w] = 1
  } else {
    if w == 1 && self.rows[1] <= self.split && self.columns[1] <= 80 {
      self.upper[(self.rows[1] - 1) * 80 + self.columns[1] - 1] = code
    }
    self.columns[w] += 1
    if w == 0 && self.columns[w] > 80 {
      self.columns[w] = 1
      self.rows[w] += 1
    }
  }
}

///|
/// Current upper window as fixed-width text. Lower-window output uses take_output().
pub fn Machine::upper_window(self : Machine) -> String {
  let out = StringBuilder()
  for row in 0.. Unit raise Fault {
  if height < 0 || height > 25 {
    raise Invalid("invalid split height")
  }
  self.split = height
  if self.version == 3 {
    self.upper.fill(32)
  }
  if self.rows[1] > height {
    self.rows[1] = 1
    self.columns[1] = 1
  }
  if height == 0 {
    self.window = 0
  }
}

///|
fn Machine::select_window(self : Machine, window : Int32) -> Unit raise Fault {
  if window != 0 && window != 1 {
    raise Invalid("invalid window")
  }
  self.window = window
  if window == 1 {
    self.rows[1] = 1
    self.columns[1] = 1
  }
}

///|
fn Machine::erase_window(self : Machine, window : Int32) -> Unit raise Fault {
  match signed(window) {
    -1 => {
      self.split = 0
      self.window = 0
      self.upper.fill(32)
      self.rows[0] = 1
      self.columns[0] = 1
    }
    -2 => {
      self.upper.fill(32)
      self.rows[0] = 1
      self.columns[0] = 1
    }
    0 => {
      self.rows[0] = 1
      self.columns[0] = 1
    }
    1 => {
      self.upper.fill(32)
      self.rows[1] = 1
      self.columns[1] = 1
    }
    _ => raise Invalid("invalid erase_window operand")
  }
}