-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Utilities: Introduce the sizefmt utility
This utility takes a human-readable size and converts it into a raw integer that can be used on commandline utilities.
- Loading branch information
1 parent
b91c625
commit 393c886
Showing
2 changed files
with
132 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
## Name | ||
|
||
sizefmt - Print the size of a number with a suffix, in bytes | ||
|
||
## Synopsis | ||
|
||
```**sh | ||
$ sizefmt [integer-with-suffix] | ||
``` | ||
|
||
## Description | ||
|
||
`sizefmt` prints the 'real' size of a number with a suffix (possibly). | ||
It can parse just a single character suffix (k for kilo, for example), or base 2 or 10 | ||
suffixes (KB for Kilobytes, or KiB for Kibibytes, for example). | ||
|
||
## Arguments | ||
|
||
* `integer-with-suffix`: a number with a suffix (possibly). | ||
|
||
## Examples | ||
|
||
```sh | ||
# prints 10000000 for 10 million bytes | ||
$ sizefmt 10MB | ||
|
||
# truncate a file /tmp/test_file with size of 10 Kibibytes | ||
$ truncate -s $(sizefmt 10KiB) /tmp/test_file | ||
|
||
# truncate a file /tmp/test_file2 with size of 10 Megabytes | ||
$ truncate -s $(sizefmt 10MB) /tmp/test_file | ||
|
||
# truncate a file /tmp/test_file3 with size of 2 Kibibytes | ||
$ truncate -s $(sizefmt 2KiB) /tmp/test_file3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright (c) 2024, Liav A. <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
||
#include <AK/CharacterTypes.h> | ||
#include <AK/Checked.h> | ||
#include <AK/NumberFormat.h> | ||
#include <AK/Optional.h> | ||
#include <AK/StringView.h> | ||
#include <AK/Types.h> | ||
#include <LibCore/ArgsParser.h> | ||
#include <LibCore/System.h> | ||
#include <LibMain/Main.h> | ||
|
||
static ErrorOr<u64> use_integer_with_char_suffix(StringView argument, size_t suffix_length) | ||
{ | ||
if (suffix_length >= argument.length()) | ||
return Error::from_string_literal("Invalid value was specified"); | ||
argument = argument.substring_view(0, argument.length() - suffix_length); | ||
|
||
Optional<u64> numeric_optional = argument.to_number<u64>(); | ||
if (numeric_optional.has_value()) | ||
return numeric_optional.release_value(); | ||
return Error::from_string_literal("Invalid value was specified"); | ||
} | ||
|
||
static ErrorOr<u64> handle_char_suffix(char suffix, AK::HumanReadableBasedOn human_readable_based_on) | ||
{ | ||
u64 suffix_multiplier = 1; | ||
switch (suffix) { | ||
case 'k': | ||
case 'K': | ||
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? KiB : KB); | ||
break; | ||
case 'M': | ||
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? MiB : MB); | ||
break; | ||
case 'G': | ||
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? GiB : GB); | ||
break; | ||
case 'T': | ||
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? TiB : TB); | ||
break; | ||
default: | ||
return Error::from_string_literal("Unknown size suffix"); | ||
} | ||
return suffix_multiplier; | ||
} | ||
|
||
static ErrorOr<u64> multiply_number_with_suffix(u64 numeric_value_without_suffix, char suffix, AK::HumanReadableBasedOn human_readable_based_on) | ||
{ | ||
auto suffix_multiplier = TRY(handle_char_suffix(suffix, human_readable_based_on)); | ||
if (Checked<u64>::multiplication_would_overflow(numeric_value_without_suffix, suffix_multiplier)) | ||
return Error::from_string_literal("Numeric value multiplication would overflow"); | ||
return numeric_value_without_suffix * suffix_multiplier; | ||
} | ||
|
||
static ErrorOr<u64> handle_number(StringView argument) | ||
{ | ||
if (auto number_with_no_suffix = use_integer_with_char_suffix(argument, 0); !number_with_no_suffix.is_error()) | ||
return number_with_no_suffix.release_value(); | ||
|
||
if (argument.ends_with("iB"sv)) { | ||
auto numeric_value_without_suffix = TRY(use_integer_with_char_suffix(argument, 3)); | ||
auto suffix = argument[argument.length() - 3]; | ||
return multiply_number_with_suffix(numeric_value_without_suffix, suffix, AK::HumanReadableBasedOn::Base2); | ||
} | ||
|
||
if (argument.ends_with("B"sv)) { | ||
auto numeric_value_without_suffix = TRY(use_integer_with_char_suffix(argument, 2)); | ||
auto suffix = argument[argument.length() - 2]; | ||
return multiply_number_with_suffix(numeric_value_without_suffix, suffix, AK::HumanReadableBasedOn::Base10); | ||
} | ||
|
||
return Error::from_string_literal("Invalid value was specified"); | ||
} | ||
|
||
ErrorOr<int> serenity_main(Main::Arguments arguments) | ||
{ | ||
TRY(Core::System::pledge("stdio rpath")); | ||
|
||
StringView argument; | ||
|
||
Core::ArgsParser args_parser; | ||
args_parser.set_general_help( | ||
"Show the 'real' size of a number with a suffix (possibly)."); | ||
args_parser.add_positional_argument(argument, "Number with possibly a suffix", "number"); | ||
args_parser.parse(arguments); | ||
|
||
if (argument.is_null() || argument.is_empty()) | ||
return Error::from_string_literal("Invalid value"); | ||
|
||
outln("{}", TRY(handle_number(argument))); | ||
return 0; | ||
} |