Skip to content

Commit 393c886

Browse files
supercomputer7timschumi
authored andcommitted
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.
1 parent b91c625 commit 393c886

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

Base/usr/share/man/man1/sizefmt.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## Name
2+
3+
sizefmt - Print the size of a number with a suffix, in bytes
4+
5+
## Synopsis
6+
7+
```**sh
8+
$ sizefmt [integer-with-suffix]
9+
```
10+
11+
## Description
12+
13+
`sizefmt` prints the 'real' size of a number with a suffix (possibly).
14+
It can parse just a single character suffix (k for kilo, for example), or base 2 or 10
15+
suffixes (KB for Kilobytes, or KiB for Kibibytes, for example).
16+
17+
## Arguments
18+
19+
* `integer-with-suffix`: a number with a suffix (possibly).
20+
21+
## Examples
22+
23+
```sh
24+
# prints 10000000 for 10 million bytes
25+
$ sizefmt 10MB
26+
27+
# truncate a file /tmp/test_file with size of 10 Kibibytes
28+
$ truncate -s $(sizefmt 10KiB) /tmp/test_file
29+
30+
# truncate a file /tmp/test_file2 with size of 10 Megabytes
31+
$ truncate -s $(sizefmt 10MB) /tmp/test_file
32+
33+
# truncate a file /tmp/test_file3 with size of 2 Kibibytes
34+
$ truncate -s $(sizefmt 2KiB) /tmp/test_file3
35+
```

Userland/Utilities/sizefmt.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2024, Liav A. <[email protected]>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <AK/CharacterTypes.h>
8+
#include <AK/Checked.h>
9+
#include <AK/NumberFormat.h>
10+
#include <AK/Optional.h>
11+
#include <AK/StringView.h>
12+
#include <AK/Types.h>
13+
#include <LibCore/ArgsParser.h>
14+
#include <LibCore/System.h>
15+
#include <LibMain/Main.h>
16+
17+
static ErrorOr<u64> use_integer_with_char_suffix(StringView argument, size_t suffix_length)
18+
{
19+
if (suffix_length >= argument.length())
20+
return Error::from_string_literal("Invalid value was specified");
21+
argument = argument.substring_view(0, argument.length() - suffix_length);
22+
23+
Optional<u64> numeric_optional = argument.to_number<u64>();
24+
if (numeric_optional.has_value())
25+
return numeric_optional.release_value();
26+
return Error::from_string_literal("Invalid value was specified");
27+
}
28+
29+
static ErrorOr<u64> handle_char_suffix(char suffix, AK::HumanReadableBasedOn human_readable_based_on)
30+
{
31+
u64 suffix_multiplier = 1;
32+
switch (suffix) {
33+
case 'k':
34+
case 'K':
35+
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? KiB : KB);
36+
break;
37+
case 'M':
38+
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? MiB : MB);
39+
break;
40+
case 'G':
41+
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? GiB : GB);
42+
break;
43+
case 'T':
44+
suffix_multiplier = (human_readable_based_on == AK::HumanReadableBasedOn::Base2 ? TiB : TB);
45+
break;
46+
default:
47+
return Error::from_string_literal("Unknown size suffix");
48+
}
49+
return suffix_multiplier;
50+
}
51+
52+
static ErrorOr<u64> multiply_number_with_suffix(u64 numeric_value_without_suffix, char suffix, AK::HumanReadableBasedOn human_readable_based_on)
53+
{
54+
auto suffix_multiplier = TRY(handle_char_suffix(suffix, human_readable_based_on));
55+
if (Checked<u64>::multiplication_would_overflow(numeric_value_without_suffix, suffix_multiplier))
56+
return Error::from_string_literal("Numeric value multiplication would overflow");
57+
return numeric_value_without_suffix * suffix_multiplier;
58+
}
59+
60+
static ErrorOr<u64> handle_number(StringView argument)
61+
{
62+
if (auto number_with_no_suffix = use_integer_with_char_suffix(argument, 0); !number_with_no_suffix.is_error())
63+
return number_with_no_suffix.release_value();
64+
65+
if (argument.ends_with("iB"sv)) {
66+
auto numeric_value_without_suffix = TRY(use_integer_with_char_suffix(argument, 3));
67+
auto suffix = argument[argument.length() - 3];
68+
return multiply_number_with_suffix(numeric_value_without_suffix, suffix, AK::HumanReadableBasedOn::Base2);
69+
}
70+
71+
if (argument.ends_with("B"sv)) {
72+
auto numeric_value_without_suffix = TRY(use_integer_with_char_suffix(argument, 2));
73+
auto suffix = argument[argument.length() - 2];
74+
return multiply_number_with_suffix(numeric_value_without_suffix, suffix, AK::HumanReadableBasedOn::Base10);
75+
}
76+
77+
return Error::from_string_literal("Invalid value was specified");
78+
}
79+
80+
ErrorOr<int> serenity_main(Main::Arguments arguments)
81+
{
82+
TRY(Core::System::pledge("stdio rpath"));
83+
84+
StringView argument;
85+
86+
Core::ArgsParser args_parser;
87+
args_parser.set_general_help(
88+
"Show the 'real' size of a number with a suffix (possibly).");
89+
args_parser.add_positional_argument(argument, "Number with possibly a suffix", "number");
90+
args_parser.parse(arguments);
91+
92+
if (argument.is_null() || argument.is_empty())
93+
return Error::from_string_literal("Invalid value");
94+
95+
outln("{}", TRY(handle_number(argument)));
96+
return 0;
97+
}

0 commit comments

Comments
 (0)