Serenity Operating System
at master 122 lines 3.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Emanuele Torre <torreemanuele6@gmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/DeprecatedString.h> 9#include <AK/Vector.h> 10#include <LibCore/ArgsParser.h> 11#include <LibCore/System.h> 12#include <ctype.h> 13#include <stdio.h> 14#include <sys/stat.h> 15#include <unistd.h> 16 17struct Count { 18 DeprecatedString name; 19 bool exists { true }; 20 unsigned lines { 0 }; 21 unsigned characters { 0 }; 22 unsigned words { 0 }; 23 size_t bytes { 0 }; 24}; 25 26bool g_output_line = false; 27bool g_output_byte = false; 28bool g_output_word = false; 29 30static void wc_out(Count const& count) 31{ 32 if (g_output_line) 33 out("{:7} ", count.lines); 34 if (g_output_word) 35 out("{:7} ", count.words); 36 if (g_output_byte) 37 out("{:7} ", count.bytes); 38 39 outln("{:>14}", count.name); 40} 41 42static Count get_count(DeprecatedString const& file_specifier) 43{ 44 Count count; 45 FILE* file_pointer = nullptr; 46 if (file_specifier == "-") { 47 count.name = ""; 48 file_pointer = stdin; 49 } else { 50 count.name = file_specifier; 51 if ((file_pointer = fopen(file_specifier.characters(), "r")) == nullptr) { 52 warnln("wc: unable to open {}", file_specifier); 53 count.exists = false; 54 return count; 55 } 56 } 57 58 bool start_a_new_word = true; 59 for (int ch = fgetc(file_pointer); ch != EOF; ch = fgetc(file_pointer)) { 60 count.bytes++; 61 if (isspace(ch)) { 62 start_a_new_word = true; 63 if (ch == '\n') 64 count.lines++; 65 } else if (start_a_new_word) { 66 start_a_new_word = false; 67 count.words++; 68 } 69 } 70 71 if (file_pointer != stdin) 72 fclose(file_pointer); 73 74 return count; 75} 76 77static Count get_total_count(Vector<Count> const& counts) 78{ 79 Count total_count { "total" }; 80 for (auto& count : counts) { 81 total_count.lines += count.lines; 82 total_count.words += count.words; 83 total_count.characters += count.characters; 84 total_count.bytes += count.bytes; 85 } 86 return total_count; 87} 88 89ErrorOr<int> serenity_main(Main::Arguments arguments) 90{ 91 TRY(Core::System::pledge("stdio rpath")); 92 93 Vector<DeprecatedString> file_specifiers; 94 95 Core::ArgsParser args_parser; 96 args_parser.add_option(g_output_line, "Output line count", "lines", 'l'); 97 args_parser.add_option(g_output_byte, "Output byte count", "bytes", 'c'); 98 args_parser.add_option(g_output_word, "Output word count", "words", 'w'); 99 args_parser.add_positional_argument(file_specifiers, "File to process", "file", Core::ArgsParser::Required::No); 100 args_parser.parse(arguments); 101 102 if (!g_output_line && !g_output_byte && !g_output_word) 103 g_output_line = g_output_byte = g_output_word = true; 104 105 Vector<Count> counts; 106 for (auto const& file_specifier : file_specifiers) 107 counts.append(get_count(file_specifier)); 108 109 TRY(Core::System::pledge("stdio")); 110 111 if (file_specifiers.is_empty()) 112 counts.append(get_count("-")); 113 else if (file_specifiers.size() > 1) 114 counts.append(get_total_count(counts)); 115 116 for (auto const& count : counts) { 117 if (count.exists) 118 wc_out(count); 119 } 120 121 return 0; 122}