diff options
author | Eli Youngs <eli.m.youngs@gmail.com> | 2022-12-18 22:29:10 -0800 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2023-01-06 13:52:21 -0700 |
commit | 0dc65cd835a3232aa0220675eb7e107b9ab89a8d (patch) | |
tree | 72431521741aef4edf02becce49aef3f97b25369 /Userland/Utilities | |
parent | 0ecbc5c02a5a91c5c92b479d4f9fce45149a3426 (diff) | |
download | serenity-0dc65cd835a3232aa0220675eb7e107b9ab89a8d.zip |
sed: Write substitution output to a file with "/w"
A substitution command like "s/x/y/wabc" will now write all substituted
lines to a file called "abc". Note that this is in addition to writing
to stdout.
Diffstat (limited to 'Userland/Utilities')
-rw-r--r-- | Userland/Utilities/sed.cpp | 60 |
1 files changed, 53 insertions, 7 deletions
diff --git a/Userland/Utilities/sed.cpp b/Userland/Utilities/sed.cpp index ebb814bd52..c481139161 100644 --- a/Userland/Utilities/sed.cpp +++ b/Userland/Utilities/sed.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/CharacterTypes.h> #include <AK/GenericLexer.h> #include <AK/Vector.h> #include <LibCore/ArgsParser.h> @@ -17,8 +18,31 @@ struct SubstitutionCommand { Regex<PosixExtended> regex; StringView replacement; PosixOptions options; + Optional<StringView> output_filepath; }; +static Vector<StringView> split_flags(StringView const& input) +{ + Vector<StringView> flags; + + auto lexer = GenericLexer(input); + while (!lexer.is_eof()) { + StringView flag; + + if (lexer.next_is(is_ascii_digit)) { + flag = lexer.consume_while(is_ascii_digit); + } else if (lexer.peek() == 'w') { + flag = lexer.consume_all(); + } else { + flag = lexer.consume(1); + } + + flags.append(flag); + } + + return flags; +} + static ErrorOr<SubstitutionCommand> parse_command(StringView command) { auto generic_error_message = "Incomplete substitution command"sv; @@ -53,18 +77,30 @@ static ErrorOr<SubstitutionCommand> parse_command(StringView command) if (!lexer.consume_specific(delimiter)) return Error::from_string_literal("The substitution command was not properly terminated."); - PosixOptions const options = PosixOptions(PosixFlags::Global | PosixFlags::SingleMatch); - - auto flags = lexer.consume_all(); - if (!flags.is_empty()) - warnln("sed: Flags are currently ignored"); + PosixOptions options = PosixOptions(PosixFlags::Global | PosixFlags::SingleMatch); + Optional<StringView> output_filepath; + + auto flags = split_flags(lexer.consume_all()); + for (auto const& flag : flags) { + if (flag.starts_with('w')) { + auto flag_filepath = flag.substring_view(1).trim_whitespace(); + if (flag_filepath.is_empty()) + return Error::from_string_literal("No filepath was provided for the 'w' flag."); + output_filepath = flag_filepath; + } else if (flag == "g"sv) { + // Allow multiple matches per line by un-setting the SingleMatch flag + options &= ~PosixFlags::SingleMatch; + } else { + warnln("sed: Unsupported flag: {}", flag); + } + } - return SubstitutionCommand { Regex<PosixExtended> { pattern }, replacement, options }; + return SubstitutionCommand { Regex<PosixExtended> { pattern }, replacement, options, output_filepath }; } ErrorOr<int> serenity_main(Main::Arguments args) { - TRY(Core::System::pledge("stdio rpath")); + TRY(Core::System::pledge("stdio cpath rpath wpath")); Core::ArgsParser args_parser; @@ -78,6 +114,10 @@ ErrorOr<int> serenity_main(Main::Arguments args) auto command = TRY(parse_command(command_input)); + Optional<NonnullOwnPtr<Core::Stream::File>> maybe_output_file; + if (command.output_filepath.has_value()) + maybe_output_file = TRY(Core::Stream::File::open_file_or_standard_stream(command.output_filepath.release_value(), Core::Stream::OpenMode::Write)); + if (filepaths.is_empty()) filepaths = { "-"sv }; @@ -96,6 +136,12 @@ ErrorOr<int> serenity_main(Main::Arguments args) auto result = command.regex.replace(line, command.replacement, command.options); outln(result); + + if (maybe_output_file.has_value()) { + auto const& output_file = maybe_output_file.value(); + TRY(output_file->write(result.bytes())); + TRY(output_file->write("\n"sv.bytes())); + } } } |