///|
fn traditional_offset(text : String) -> Int64? raise OdError {
let mut body = if text.has_prefix("+") { text[1:].to_owned() } else { text }
if body == "" || !(body[0] is ('0'..<='9')) {
return None
}
let decimal = body.has_suffix(".") ||
body.has_suffix(".b") ||
body.has_suffix(".B")
let radix = if decimal {
10
} else if body.has_prefix("0x") || body.has_prefix("0X") {
16
} else {
8
}
let mut multiplier = 1L
if radix != 16 && (body.has_suffix("b") || body.has_suffix("B")) {
multiplier = if body.has_suffix("B") { 1024L } else { 512L }
body = body[:body.length() - 1].to_owned()
}
if decimal {
body = body[:body.length() - 1].to_owned()
}
if radix == 16 {
body = body[2:].to_owned()
}
if body == "" ||
!body
.iter()
.all(character => {
if radix == 16 {
character is ('0'..<='9' | 'a'..<='f' | 'A'..<='F')
} else if radix == 10 {
character is ('0'..<='9')
} else {
character is ('0'..<='7')
}
}) {
return None
}
let value = @string.parse_int64(body, base=radix) catch {
_ => raise OdError("\{text}: Numerical result out of range")
}
if value > 9223372036854775807L / multiplier {
raise OdError("\{text}: Numerical result out of range")
}
Some(value * multiplier)
}
///|
fn traditional_operands(
parsed : @cli.ParsedArgs,
) -> (Array[String], Int64?, Int64?) raise OdError {
let traditional = parsed.contains("traditional")
let modern = [
"address-radix", "skip-bytes", "read-bytes", "strings", "format", "output-duplicates",
].any(name => parsed.contains(name))
let files = parsed.operands
if !traditional && modern {
return (files, None, None)
}
match files {
[offset] if traditional || offset.has_prefix("+") =>
if traditional_offset(offset) is Some(skip) {
return ([], Some(skip), None)
}
[file, offset] if traditional ||
offset.has_prefix("+") ||
(offset.length() > 0 && offset[0] is ('0'..<='9')) =>
if traditional_offset(offset) is Some(second) {
if traditional && traditional_offset(file) is Some(first) {
return ([], Some(first), Some(second))
}
return ([file], Some(second), None)
}
[file, offset, label] if traditional =>
if traditional_offset(offset) is Some(skip) &&
traditional_offset(label) is Some(label) {
return ([file], Some(skip), Some(label))
}
_ => ()
}
if traditional && files.length() > 1 {
raise OdError(
"extra operand '\{files[1]}'\nod: compatibility mode supports at most one file\nTry 'od --help' for more information.",
)
}
(files, None, None)
}
///|
fn labeled_address(offset : Int64, base : Int32, label : Int64?) -> String {
match label {
None => address(offset, base)
Some(delta) => {
let pseudo = "(" +
address(
if base == 0 {
offset
} else {
offset + delta
},
if base == 0 {
8
} else {
base
},
) +
")"
if base == 0 {
pseudo
} else {
address(offset, base) + " " + pseudo
}
}
}
}