///|
fn valid_linux_number(raw : String, kind : Kind) -> Bool {
  if raw.is_empty() {
    return false
  }
  let mut i = 0
  if kind == Integer && raw[0] == 45 {
    i = 1
  }
  if kind == Hex && (raw.has_prefix("0x") || raw.has_prefix("0X")) {
    i = 2
  }
  if i == raw.length() {
    return false
  }
  if kind == Integer && raw[i] == 48 && i + 1 < raw.length() {
    return false
  }
  for j in i..= 48 && c <= 57) ||
      (kind == Hex && ((c >= 65 && c <= 70) || (c >= 97 && c <= 102)))) {
      return false
    }
  }
  true
}

///|
fn linux_initial(kind : Kind) -> Value {
  match kind {
    Integer => RawNumber("0", Integer)
    Hex => RawNumber("0x0", Hex)
    _ => kind.initial()
  }
}

///|
// Parse the C oracle's numeric comparison domain with explicit overflow checks.
// The result carries unsigned bits; signed conversion is deferred until both
// operands are known. Unknown constants use C base-0 (including octal).
fn linux_digits(raw : String, kind : Kind?) -> (UInt64, Bool)? {
  if kind == Some(Boolean) || kind == Some(Tristate) {
    return match raw {
      "n" => Some((0UL, false))
      "m" => Some((1UL, false))
      "y" => Some((2UL, false))
      _ => None
    }
  }
  if raw.is_empty() {
    return None
  }
  let mut i = 0
  let negative = raw[0] == 45
  if negative || raw[0] == 43 {
    i += 1
  }
  let unsigned = kind == Some(Hex)
  let mut base = if unsigned { 16 } else { 10 }
  if kind == None && i < raw.length() && raw[i] == 48 {
    base = 8
  }
  if i + 1 < raw.length() &&
    raw[i] == 48 &&
    (raw[i + 1] == 120 || raw[i + 1] == 88) &&
    (unsigned || kind == None) {
    base = 16
    i += 2
  }
  if i >= raw.length() {
    return None
  }
  let limit : UInt64 = if unsigned {
    18446744073709551615UL
  } else if negative {
    9223372036854775808UL
  } else {
    9223372036854775807UL
  }
  let mut n = 0UL
  for j in i..= 48 && c <= 57 {
      c - 48
    } else if c >= 65 && c <= 70 {
      c - 55
    } else if c >= 97 && c <= 102 {
      c - 87
    } else {
      return None
    }
    if digit >= base {
      return None
    }
    let d = digit.to_uint64()
    let b = base.to_uint64()
    if n > (limit - d) / b {
      return None
    }
    n = n * b + d
  }
  Some((if negative { 0UL - n } else { n }, unsigned))
}

///|
fn linux_operand(
  expr : Expr,
  values : Map[String, Value],
) -> (String, Kind?, Bool) {
  match expr {
    NumericLiteral(raw, _) => (raw, None, false)
    SymbolRef(name) =>
      match values.get(name) {
        Some(RawNumber(raw, kind)) => (raw, Some(kind), false)
        Some(Text(raw)) => (raw, Some(StringType), false)
        Some(Logic(t)) => (t.text(), Some(Tristate), false)
        Some(v) => (v.text(), Some(Integer), false)
        None => (name, None, false)
      }
    Constant(Text(raw)) => (raw, None, false)
    Constant(Logic(t)) => (t.text(), Some(Tristate), false)
    _ => (expr.evaluate(values, linux612=true).text(), None, false)
  }
}

///|
fn linux_compare(a : Expr, b : Expr, values : Map[String, Value]) -> Int32 {
  let (x, xkind, _) = linux_operand(a, values)
  let (y, ykind, _) = linux_operand(b, values)
  if xkind == Some(StringType) && ykind == Some(StringType) {
    return x.lexical_compare(y)
  }
  match (linux_digits(x, xkind), linux_digits(y, ykind)) {
    (Some((n, u)), Some((m, v))) =>
      if u || v {
        n.compare(m)
      } else {
        n.reinterpret_as_int64().compare(m.reinterpret_as_int64())
      }
    _ => x.lexical_compare(y)
  }
}

///|
fn linux_range_number(raw : String, kind : Kind) -> Int64 {
  // strtoll with an explicit radix accepts a prefix and saturates on overflow.
  let mut i = 0
  while i < raw.length() &&
        (raw[i] == 32 || raw[i] == 9 || raw[i] == 10 || raw[i] == 13) {
    i += 1
  }
  let negative = i < raw.length() && raw[i] == 45
  if i < raw.length() && (raw[i] == 45 || raw[i] == 43) {
    i += 1
  }
  let base = if kind == Hex { 16UL } else { 10UL }
  if kind == Hex &&
    i + 2 < raw.length() &&
    raw[i] == 48 &&
    (raw[i + 1] == 120 || raw[i + 1] == 88) {
    i += 2
  }
  let limit = if negative {
    9223372036854775808UL
  } else {
    9223372036854775807UL
  }
  let mut n = 0UL
  while i < raw.length() {
    let c = raw[i].to_int()
    let digit = if c >= 48 && c <= 57 {
      c - 48
    } else if c >= 65 && c <= 70 {
      c - 55
    } else if c >= 97 && c <= 102 {
      c - 87
    } else {
      break
    }
    let d = digit.to_uint64()
    if d >= base {
      break
    }
    if n > (limit - d) / base {
      return if negative {
        -9223372036854775807L - 1L
      } else {
        9223372036854775807L
      }
    }
    n = n * base + d
    i += 1
  }
  (if negative { 0UL - n } else { n }).reinterpret_as_int64()
}