Skip to content

Commit

Permalink
save work
Browse files Browse the repository at this point in the history
  • Loading branch information
Ollrogge committed Jan 14, 2024
1 parent 6a8e227 commit 8ae18c9
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 80 deletions.
17 changes: 17 additions & 0 deletions Userland/Libraries/LibCore/ArgsParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,23 @@ void ArgsParser::add_option(Optional<size_t>& value, char const* help_string, ch
add_option(move(option));
}

void ArgsParser::add_option(Optional<ssize_t>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode)
{
Option option {
OptionArgumentMode::Required,
help_string,
long_name,
short_name,
value_name,
[&value](StringView s) -> ErrorOr<bool> {
value = s.to_number<ssize_t>();
return value.has_value();
},
hide_mode,
};
add_option(move(option));
}

void ArgsParser::add_option(Vector<size_t>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, char separator, OptionHideMode hide_mode)
{
Option option {
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibCore/ArgsParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class ArgsParser {
void add_option(double& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
void add_option(Optional<double>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
void add_option(Optional<size_t>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
void add_option(Optional<ssize_t>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
void add_option(Vector<size_t>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, char separator = ',', OptionHideMode hide_mode = OptionHideMode::None);
// Note: This option is being used when we expect the user to use the same option
// multiple times (e.g. "program --option=example --option=anotherexample ...").
Expand Down
158 changes: 78 additions & 80 deletions Userland/Utilities/xxd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ static void print_ascii(Bytes line)
}
}

static void print_line_hex(Bytes line, size_t line_length, size_t group_size, bool uppercase)
static void print_line_hex(Bytes line, size_t line_length_config, size_t group_size, bool uppercase)
{
for (size_t i = 0; i < line_length; ++i) {
for (size_t i = 0; i < line_length_config; ++i) {
if (i < line.size()) {
if (uppercase) {
out("{:02X}", line[i]);
Expand All @@ -56,60 +56,62 @@ static void print_line_hex(Bytes line, size_t line_length, size_t group_size, bo
}
}

out(" ");
out(" ");
print_ascii(line);
putchar('\n');
}

static void print_line_little_endian_hex(Bytes line, size_t line_length, size_t group_size, bool uppercase)
static void print_line_little_endian_hex(Bytes line, size_t line_length_config, size_t group_size, bool uppercase)
{
if (group_size < 2) {
print_line_hex(line, line_length, group_size, uppercase);
if (group_size == 1) {
print_line_hex(line, line_length_config, group_size, uppercase);
return;
}

size_t padding = (line_length - line.size()) / group_size;
line_length -= padding;
if (group_size == 0 || group_size > BYTES_PER_LINE_HEX) {
group_size = BYTES_PER_LINE_HEX;
}

for (size_t i = 0; i < line_length; i += group_size) {
size_t size = i + group_size < line.size() ? group_size : line.size() - i;
auto group = line.slice(i, size);
if (size < group_size) {
for (size_t i = 0; i < group_size - size; ++i) {
out(" ");
for (size_t i = 0; i < line_length_config; i += group_size) {
if (i < line.size()) {
size_t size = i + group_size < line.size() ? group_size : line.size() - i;
auto group = line.slice(i, size);
if (size < group_size) {
for (size_t i = 0; i < group_size - size; ++i) {
out(" ");
}
}
}
for (ssize_t i = group.size() - 1; i >= 0; --i) {
if (uppercase) {
out("{:02X}", group[i]);
} else {
for (ssize_t i = group.size() - 1; i >= 0; --i) {
if (uppercase) {
out("{:02X}", group[i]);
} else {

out("{:02x}", group[i]);
out("{:02x}", group[i]);
}
}
} else {
for (size_t i = 0; i < group_size; ++i) {
out(" ");
}
}
out(" ");
}

for (size_t i = 0; i < padding; ++i) {
for (size_t i = 0; i < group_size; ++i) {
out(" ");
}
out(" ");
}

out(" ");
out(" ");
print_ascii(line);
putchar('\n');
}

static void print_line_bits(Bytes line, size_t line_length, size_t group_size)
static void print_line_bits(Bytes line, size_t line_length_config, size_t group_size)
{
auto print_byte = [](u8 byte) {
for (ssize_t i = 7; i >= 0; --i) {
out("{}", (byte >> i) & 1 ? '1' : '0');
}
};

for (size_t i = 0; i < line_length; ++i) {
for (size_t i = 0; i < line_length_config; ++i) {
if (i < line.size()) {
print_byte(line[i]);
} else {
Expand All @@ -121,7 +123,7 @@ static void print_line_bits(Bytes line, size_t line_length, size_t group_size)
}
}

out(" ");
out(" ");
print_ascii(line);
putchar('\n');
}
Expand Down Expand Up @@ -152,7 +154,6 @@ ErrorOr<int> serenity_main(Main::Arguments args)

Core::ArgsParser args_parser;
StringView path;
StringView seek_offset_setting;
bool autoskip = false;
bool c_include_file_style = false;
bool capitalize_c_include_file_style = false;
Expand All @@ -161,10 +162,11 @@ ErrorOr<int> serenity_main(Main::Arguments args)
bool offset_in_decimal = false;
bool plain_hexdump_style = false;
bool uppercase_hex = false;
Optional<size_t> line_length_setting;
Optional<size_t> group_size_setting;
Optional<size_t> read_limit_setting;
Optional<size_t> added_file_offset_setting;
Optional<size_t> line_length_option;
Optional<size_t> group_size_option;
Optional<size_t> max_bytes;
Optional<size_t> position_offset;
Optional<ssize_t> seek_offset;
String c_include_file_style_variable_name;

args_parser.add_positional_argument(path, "Input file", "input", Core::ArgsParser::Required::No);
Expand All @@ -174,17 +176,17 @@ ErrorOr<int> serenity_main(Main::Arguments args)
args_parser.add_option(binary_digit_formatting, "Binary digit formatting", "bits", 'b');
args_parser.add_option(plain_hexdump_style, "Plain hex dump style", "plain", 'p');
args_parser.add_option(offset_in_decimal, "Show offset in decimal instead of hex", "decimal", 'd');
args_parser.add_option(line_length_setting, "Octets per line", "cols", 'c', "cols");
args_parser.add_option(line_length_option, "Octets per line", "cols", 'c', "cols");
args_parser.add_option(little_endian_hexdump, "Little-endian hex dump", nullptr, 'e');
args_parser.add_option(uppercase_hex, "Use upper case hexh letters", "uppercase", 'u');
args_parser.add_option(group_size_setting, "Octet group size", "groupsize", 'g', "groupsize");
args_parser.add_option(read_limit_setting, "Stop after writing <len> octets", "len", 'l', "octet_length");

args_parser.add_option(group_size_option, "Separate the output of every <bytes> bytes", "groupsize", 'g', "bytes");
args_parser.add_option(max_bytes, "Truncate to fixed number of bytes", "len", 'l', "bytes");
args_parser.add_option(c_include_file_style_variable_name, "Set the variable name used in C include ouput (-i)", "name", 'n', "include_style");
args_parser.add_option(added_file_offset_setting, "Add <off> to displayed file offset", "offset", 'o', "offset");
args_parser.add_option(seek_offset_setting, "start at <seek> bytes absolute infile offset", "[-]seek", 's', "seek");
args_parser.parse(args);
args_parser.add_option(position_offset, "Add <off> to displayed file offset", "offset", 'o', "offset");
args_parser.add_option(seek_offset, "start at <seek> bytes absolute infile offset", "seek", 's', "[-]offset");

outln("Test: {} {}", c_include_file_style_variable_name, c_include_file_style_variable_name.is_empty());
args_parser.parse(args);

// todo: TRY vs MUST

Expand All @@ -193,17 +195,15 @@ ErrorOr<int> serenity_main(Main::Arguments args)

size_t read_limit = SIZE_MAX;
auto display_style = DisplayStyle::Hex;
size_t line_length = BYTES_PER_LINE_HEX;
size_t line_length_config = BYTES_PER_LINE_HEX;
size_t group_size = GROUP_SIZE_HEX;
size_t added_file_offset = 0;
Optional<ssize_t> seek_offset;

// todo: put states that can appear together in an if, else if block
// todo: how to handle invalid combinations ?
// lazy approach ?

if (c_include_file_style) {
line_length = BYTES_PER_LINE_C;
line_length_config = BYTES_PER_LINE_C;
display_style = DisplayStyle::CStyle;

if (c_include_file_style_variable_name.is_empty()) {
Expand All @@ -224,13 +224,14 @@ ErrorOr<int> serenity_main(Main::Arguments args)

if (plain_hexdump_style) {
display_style = DisplayStyle::PlainHex;
line_length = BYTES_PER_LINE_PLAIN_HEX;
line_length_config = BYTES_PER_LINE_PLAIN_HEX;
group_size = GROUP_SIZE_PLAIN_HEX;
}

if (line_length_setting.has_value()) {
line_length = line_length_setting.value();
if (line_length > 256 || line_length == 0) {
if (line_length_option.has_value() && line_length_option.value() > 0) {
line_length_config = line_length_option.value();

if (line_length_config > 256) {
outln("Invalid number of columns (max is 256).");
return 1;
}
Expand All @@ -244,42 +245,31 @@ ErrorOr<int> serenity_main(Main::Arguments args)

display_style = DisplayStyle::Bits;
group_size = GROUP_SIZE_BITS;
line_length = BYTES_PER_LINE_BITS;
line_length_config = BYTES_PER_LINE_BITS;
}

if (group_size_setting.has_value()) {
group_size = group_size_setting.value();
if (group_size_option.has_value()) {
group_size = group_size_option.value();

if (little_endian_hexdump) {
if (!is_power_of_two(group_size)) {
if (group_size != 0 && !is_power_of_two(group_size)) {
outln("Group size must be a power of 2 with -e");
return 1;
}
}
}

if (read_limit_setting.has_value()) {
read_limit = read_limit_setting.value();
}

if (added_file_offset_setting.has_value()) {
added_file_offset = added_file_offset_setting.value();
}

// TODO: seek relative to current stdin file position
if (!seek_offset_setting.is_null()) {
seek_offset = AK::StringUtils::convert_to_int<ssize_t>(seek_offset_setting);
}

Array<u8, BUFSIZ> contents;
Bytes bytes;
size_t total_bytes_read = 0x0;
const size_t max_read_size = contents.size() - (contents.size() % line_length);
const size_t max_read_size = contents.size() - (contents.size() % line_length_config);
bool is_input_remaining = true;

// TODO: seek relative to current stdin file position
if (seek_offset.has_value()) {
auto offset = seek_offset.value();
total_bytes_read = offset < 0 ? file_size - offset : offset;
total_bytes_read = offset < 0 ? file_size + offset : offset;
TRY(file->seek(total_bytes_read, SeekMode::SetPosition));
}

while (is_input_remaining) {
Expand All @@ -293,45 +283,53 @@ ErrorOr<int> serenity_main(Main::Arguments args)
}

while (bytes.size() > 0) {
auto line_len = bytes.size() > line_length ? line_length : bytes.size();
auto line_length = bytes.size() > line_length_config ? line_length_config : bytes.size();

if (total_bytes_read + line_len > read_limit) {
line_len = read_limit - total_bytes_read;
if (max_bytes.has_value()) {
auto bytes_remaining = max_bytes.value() - total_bytes_read;
if (bytes_remaining < line_length) {
line_length = bytes_remaining;
}
}

auto current_line = bytes.slice(0, line_len);
bytes = bytes.slice(line_len);
auto current_line = bytes.slice(0, line_length);
bytes = bytes.slice(line_length);

if (autoskip && all_of(bytes, [](auto& b) { return b == 0x0; })) {
outln("*");
continue;
}

if (display_style != DisplayStyle::CStyle && display_style != DisplayStyle::PlainHex) {
auto offset = 0;
if (position_offset.has_value()) {
offset = position_offset.value();
}

if (offset_in_decimal) {
out("{:08}: ", total_bytes_read + added_file_offset);
out("{:08}: ", total_bytes_read + offset);
} else {
out("{:08x}: ", total_bytes_read + added_file_offset);
out("{:08x}: ", total_bytes_read + offset);
}
}

switch (display_style) {
case DisplayStyle::PlainHex:
case DisplayStyle::Hex:
print_line_hex(current_line, line_length, group_size, uppercase_hex);
print_line_hex(current_line, line_length_config, group_size, uppercase_hex);
break;
case DisplayStyle::HexLittleEndian:
print_line_little_endian_hex(current_line, line_length, group_size, uppercase_hex);
print_line_little_endian_hex(current_line, line_length_config, group_size, uppercase_hex);
break;
case DisplayStyle::Bits:
print_line_bits(current_line, line_length, group_size);
print_line_bits(current_line, line_length_config, group_size);
break;
case DisplayStyle::CStyle:
print_line_c_style(current_line);
break;
}

total_bytes_read += line_len;
total_bytes_read += line_length_config;

if (total_bytes_read >= read_limit) {
is_input_remaining = false;
Expand Down

0 comments on commit 8ae18c9

Please sign in to comment.