Serenity Operating System
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}