Serenity Operating System
at master 78 lines 2.3 kB view raw
1/* 2 * Copyright (c) 2021, Thomas Voss <mail@thomasvoss.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibCore/ArgsParser.h> 8#include <LibCore/System.h> 9#include <LibMain/Main.h> 10#include <errno.h> 11#include <string.h> 12#include <unistd.h> 13 14ErrorOr<int> serenity_main(Main::Arguments arguments) 15{ 16 TRY(Core::System::pledge("stdio rpath"sv)); 17 18 Vector<StringView> paths; 19 Core::ArgsParser args_parser; 20 21 args_parser.set_general_help("Concatente files to stdout with each line in reverse."); 22 args_parser.add_positional_argument(paths, "File path", "path", Core::ArgsParser::Required::No); 23 args_parser.parse(arguments); 24 25 Vector<FILE*> streams; 26 auto num_paths = paths.size(); 27 streams.ensure_capacity(num_paths ? num_paths : 1); 28 29 if (!paths.is_empty()) { 30 for (auto const& path : paths) { 31 if (path == "-") { 32 streams.append(stdin); 33 } else { 34 FILE* stream = fopen(DeprecatedString(path).characters(), "r"); 35 if (!stream) { 36 warnln("Failed to open {}: {}", path, strerror(errno)); 37 continue; 38 } 39 streams.append(stream); 40 } 41 } 42 } else { 43 streams.append(stdin); 44 } 45 46 char* buffer = nullptr; 47 ScopeGuard guard = [&] { 48 free(buffer); 49 for (auto* stream : streams) { 50 // If the user passes '-' as an argument multiple times, then we will end up trying to 51 // close stdin multiple times. This will cause `fclose()` to fail but with no error, so 52 // we need to manually check errno. 53 if (fclose(stream) && errno != 0) { 54 perror("fclose"); 55 } 56 } 57 }; 58 59 TRY(Core::System::pledge("stdio"sv)); 60 61 for (auto* stream : streams) { 62 for (;;) { 63 size_t n = 0; 64 errno = 0; 65 ssize_t buflen = getline(&buffer, &n, stream); 66 if (buflen == -1) { 67 if (errno != 0) { 68 perror("getline"); 69 return 1; 70 } 71 break; 72 } 73 outln("{}", DeprecatedString { buffer, Chomp }.reverse()); 74 } 75 } 76 77 return 0; 78}