///|
fn color_sequence(name : String) -> String? {
let code = match name {
"black" => "30"
"red" => "31"
"green" => "32"
"brown" => "33"
"blue" => "34"
"magenta" => "35"
"cyan" => "36"
"gray" => "37"
"darkgray" => "1;30"
"lightred" => "1;31"
"lightgreen" => "1;32"
"yellow" => "1;33"
"lightblue" => "1;34"
"lightmagenta" => "1;35"
"lightcyan" => "1;36"
"white" => "1;37"
"reset" => "0"
"bold" => "1"
"halfbright" => "2"
"blink" => "5"
"reverse" => "7"
_ => return None
}
Some("\u001b[" + code + "m")
}
///|
fn color_offset(
data : BytesView,
original : BytesView,
) -> Int64 raise HexdumpError {
let offset = @string.parse_int64(format_text(data)) catch {
_ => {
bad_format(original)
0L
}
}
if offset < 0 {
bad_format(original)
}
offset
}
///|
fn parse_colors(
data : BytesView,
count : Int32,
) -> Array[ColorRule] raise HexdumpError {
let rules : Array[ColorRule] = []
let mut start = 0
while start < data.length() {
let mut end = start
while end < data.length() && data[end] != b',' {
end += 1
}
let part = data[start:end]
let inverted = part.length() > 0 && part[0] == b'!'
let mut index = if inverted { 1 } else { 0 }
let name_start = index
while index < part.length() && !(part[index] is (b':' | b'@')) {
index += 1
}
let sequence = match color_sequence(format_text(part[name_start:index])) {
Some(sequence) => sequence
None => return []
}
let mut value = AnyValue
if index < part.length() && part[index] == b':' {
index += 1
let value_start = index
while index < part.length() && part[index] != b'@' {
index += 1
}
let bytes = part[value_start:index]
if bytes.length() > 0 && bytes[0] == b'0' {
let hexadecimal = bytes.length() > 1 && bytes[1] is (b'x' | b'X')
let number = @string.parse_uint64(
format_text(if hexadecimal { bytes[2:] } else { bytes }),
base=if hexadecimal { 16 } else { 8 },
) catch {
_ => {
bad_format(data)
0UL
}
}
value = if number.to_int() == -1 {
AnyValue
} else {
NumberValue(number.to_int())
}
} else {
value = StringBytes(bytes.to_owned())
}
}
let mut offset : Int64? = None
let mut span = count
if index < part.length() && part[index] == b'@' {
index += 1
let offset_start = index
while index < part.length() && part[index] != b'-' {
index += 1
}
let first = color_offset(part[offset_start:index], data)
offset = Some(first)
if index < part.length() {
let last = color_offset(part[index + 1:], data)
if last < first || last - first >= 2147483647L {
bad_count("_L")
}
span = (last - first + 1).to_int()
if count == 0 && span > 0 {
bad_count("_L")
}
}
}
if value is StringBytes(bytes) {
let last_span = if count > 0 && span > count {
(span - 1) % count + 1
} else {
span
}
if bytes.length() != last_span {
bad_count("_L")
}
}
rules.push({ sequence, inverted, value, offset, span, })
start = end + 1
}
rules
}
///|
fn colored_sequence(
atom : PrintAtom,
data : BytesView,
position : Int32,
address : Int64,
) -> String? {
for rule in atom.colors {
let mut start = rule.offset.unwrap_or(address)
let mut span = rule.span
if atom.count > 0 && span > atom.count {
let skipped = if address > start {
(address - start + atom.count.to_int64() - 1) / atom.count.to_int64()
} else {
0L
}
let consumed = skipped * atom.count.to_int64()
if consumed >= span.to_int64() {
continue
}
start += consumed
span = if span.to_int64() - consumed > atom.count.to_int64() {
atom.count
} else {
(span.to_int64() - consumed).to_int()
}
}
if start < address ||
start - address > atom.count.to_int64() ||
span.to_int64() > atom.count.to_int64() - (start - address) {
continue
}
let offset = position + (start - address).to_int()
let matched = match rule.value {
AnyValue => return Some(rule.sequence)
NumberValue(value) =>
if atom.conversion is Some(Address(_, _)) {
address == value.to_int64()
} else {
input_integer(data, offset, span).to_int() == value
}
StringBytes(bytes) => {
let mut matched = true
for index in 0..