///|
fn resource_number(
value : String,
label : String,
) -> (Int64, Int32) raise CliError {
let mut start = 0
while start < value.length() &&
value[start] is (' ' | '\t' | '\n' | '\r' | '\u000b' | '\u000c') {
start += 1
}
if start < value.length() && value[start] == '+' {
start += 1
}
let mut end = start
let mut number = 0L
while end < value.length() && value[end] >= '0' && value[end] <= '9' {
let digit = (value[end].to_int() - '0'.to_int()).to_int64()
if number > (9223372036854775807L - digit) / 10L {
raise CliError("sort: \{label} argument '\{value}' too large")
}
number = number * 10L + digit
end += 1
}
if end == start {
raise CliError("sort: invalid \{label} argument '\{value}'")
}
(number, end)
}
///|
fn buffer_size(value : String) -> Int64 raise CliError {
let suffix_power = (suffix : String) => {
match suffix {
"K" | "k" => Some(1)
"M" | "m" => Some(2)
"G" | "g" => Some(3)
"T" | "t" => Some(4)
"P" => Some(5)
"E" => Some(6)
"Z" => Some(7)
"Y" => Some(8)
"R" => Some(9)
"Q" => Some(10)
_ => None
}
}
let (amount, end) = if suffix_power(value) is Some(_) {
(1L, 0)
} else {
resource_number(value, "--buffer-size")
}
let mut number = amount
let suffix = value[end:]
if suffix == "%" {
if number == 0L {
return 0L
}
raise CliError(
"sort: unsupported capability: percentage buffer size requires a public physical-memory query",
)
}
let power = match suffix {
"" => 1
"b" => 0
_ =>
match suffix_power(suffix.to_owned()) {
Some(power) => power
None =>
raise CliError("sort: invalid --buffer-size argument '\{value}'")
}
}
for _ in 0.. 9223372036854775807L / 1024L {
raise CliError("sort: --buffer-size argument '\{value}' too large")
}
number *= 1024L
}
number
}
///|
fn resource_controls(parsed : @cli.ParsedArgs) -> (Int64, Int32) raise CliError {
let sizes = parsed.values("buffer-size")
let mut budget = if sizes.is_empty() { 67108864L } else { 0L }
for value in sizes {
budget = budget.max(buffer_size(value))
}
let mut fan_in = 16
for value in parsed.values("batch-size") {
let (number, end) = resource_number(value, "--batch-size")
if end != value.length() {
raise CliError("sort: invalid --batch-size argument '\{value}'")
}
if number < 2 {
raise CliError(
"sort: invalid --batch-size argument '\{value}'\nsort: minimum --batch-size argument is '2'",
)
}
fan_in = number.min(16L).to_int()
}
(budget, fan_in)
}
///|
async fn temporary_root(parent : String) -> String {
for _ in 0..<32 {
let random = match @env.rand(16) {
Some(bytes) => @crypto.bytes_to_hex_string(bytes)
None => raise CliError("sort: secure random source is unavailable")
}
let path = parent + "/cli-sort-" + random
try @fs.mkdir(path, permission=0o700) catch {
@os_error.OSError(_) as error if error.is_EEXIST() => ()
error => raise error
} noraise {
_ => return path
}
}
raise CliError("sort: cannot create an exclusive temporary directory")
}