Serenity Operating System
at master 78 lines 2.1 kB view raw
1/* 2 * Copyright (c) 2021-2022, Federico Guerinoni <guerinoni.federico@gmail.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")); 17 18 Vector<StringView> paths; 19 20 Core::ArgsParser args_parser; 21 args_parser.set_general_help("Concatenate files or pipes to stdout, last line first."); 22 args_parser.add_positional_argument(paths, "File path(s)", "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 FILE* stream = nullptr; 32 if (path == "-"sv) { 33 stream = stdin; 34 } else { 35 stream = fopen(DeprecatedString(path).characters(), "r"); 36 if (!stream) { 37 warnln("Failed to open {}: {}", path, strerror(errno)); 38 continue; 39 } 40 } 41 streams.append(stream); 42 } 43 } else { 44 streams.append(stdin); 45 } 46 47 char* buffer = nullptr; 48 ScopeGuard guard = [&] { 49 free(buffer); 50 for (auto* stream : streams) { 51 if (fclose(stream)) 52 perror("fclose"); 53 } 54 }; 55 56 TRY(Core::System::pledge("stdio")); 57 58 for (auto* stream : streams) { 59 Vector<DeprecatedString> lines; 60 for (;;) { 61 size_t n = 0; 62 errno = 0; 63 ssize_t buflen = getline(&buffer, &n, stream); 64 if (buflen == -1) { 65 if (errno != 0) { 66 perror("getline"); 67 return 1; 68 } 69 break; 70 } 71 lines.append({ buffer, Chomp }); 72 } 73 for (int i = lines.size() - 1; i >= 0; --i) 74 outln("{}", lines[i]); 75 } 76 77 return 0; 78}