From 2e8330f78cf64fd30401f23b4552e1a3adeb770c Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sat, 13 Nov 2021 12:17:40 +0100 Subject: [PATCH] Utilities/tr: Rework squeezing to be supported during more operations --- Base/usr/share/man/man1/tr.md | 2 +- Userland/Utilities/tr.cpp | 62 +++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/Base/usr/share/man/man1/tr.md b/Base/usr/share/man/man1/tr.md index 9bc5a7bdd9..bb8deaf2a2 100644 --- a/Base/usr/share/man/man1/tr.md +++ b/Base/usr/share/man/man1/tr.md @@ -14,7 +14,7 @@ $ tr [--complement] [--delete] [--squeeze-repeats] [to] * `--version`: Print version * `-c`, `--complement`: Take the complement of the first set * `-d`, `--delete`: Delete characters instead of replacing -* `-s`, `--squeeze-repeats`: Omit repeated characters listed in the 'to' set from the output +* `-s`, `--squeeze-repeats`: Omit repeated characters listed in the last given set from the output ## Arguments: diff --git a/Userland/Utilities/tr.cpp b/Userland/Utilities/tr.cpp index 7b7cb019d3..d028e1ddd6 100644 --- a/Userland/Utilities/tr.cpp +++ b/Userland/Utilities/tr.cpp @@ -92,19 +92,34 @@ int main(int argc, char** argv) { bool complement_flag = false; bool delete_flag = false; - bool squeeze_repeats = false; + bool squeeze_flag = false; const char* from_chars = nullptr; const char* to_chars = nullptr; Core::ArgsParser args_parser; args_parser.add_option(complement_flag, "Take the complement of the first set", "complement", 'c'); args_parser.add_option(delete_flag, "Delete characters instead of replacing", "delete", 'd'); - args_parser.add_option(squeeze_repeats, "Omit repeated characters listed in the 'to' set from the output", "squeeze-repeats", 's'); + args_parser.add_option(squeeze_flag, "Omit repeated characters listed in the last given set from the output", "squeeze-repeats", 's'); args_parser.add_positional_argument(from_chars, "Set of characters to translate from", "from"); args_parser.add_positional_argument(to_chars, "Set of characters to translate to", "to", Core::ArgsParser::Required::No); args_parser.parse(argc, argv); - if (!to_chars && !delete_flag) { + bool transform_flag = to_chars && !delete_flag; + + if (!transform_flag && !delete_flag && !squeeze_flag) { + warnln("tr: Missing operand"); + args_parser.print_usage(stderr, argv[0]); + return 1; + } + + if (delete_flag && squeeze_flag && !to_chars) { + warnln("tr: Combined delete and squeeze operations need two sets of characters"); + args_parser.print_usage(stderr, argv[0]); + return 1; + } + + if (delete_flag && !squeeze_flag && to_chars) { + warnln("tr: Only one set of characters may be given when deleting without squeezing"); args_parser.print_usage(stderr, argv[0]); return 1; } @@ -119,32 +134,31 @@ int main(int argc, char** argv) from_str = complement_set.to_string(); } - if (delete_flag) { - for (;;) { - char ch = fgetc(stdin); - if (feof(stdin)) - break; - if (!from_str.contains(ch)) - putchar(ch); - } - } else { - auto to_str = build_set(to_chars); - Optional last_char; + auto to_str = build_set(to_chars); + String squeeze_string = build_set(to_chars ? to_chars : from_chars); + Optional last_char; - for (;;) { - char ch = fgetc(stdin); - if (feof(stdin)) - break; + for (;;) { + char ch = fgetc(stdin); + if (feof(stdin)) + break; + + if (delete_flag) { + if (from_str.contains(ch)) + continue; + } + + if (transform_flag) { auto match = from_str.find_last(ch); if (match.has_value()) ch = to_str[min(match.value(), to_str.length() - 1)]; - - if (squeeze_repeats && last_char.has_value() && last_char.value() == ch) - continue; - - last_char = ch; - putchar(ch); } + + if (squeeze_flag && last_char.has_value() && last_char.value() == ch && squeeze_string.contains(ch)) + continue; + + last_char = ch; + putchar(ch); } return 0;