wc.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #include <AK/AKString.h>
  2. #include <AK/Vector.h>
  3. #include <LibCore/CArgsParser.h>
  4. #include <ctype.h>
  5. #include <stdio.h>
  6. bool output_chars = false;
  7. bool output_words = false;
  8. bool output_lines = false;
  9. struct Count {
  10. String file;
  11. unsigned long chars = 0;
  12. unsigned long words = 0;
  13. unsigned long lines = 0;
  14. };
  15. void report(const Count& count)
  16. {
  17. if (output_lines) {
  18. printf("%lu ", count.lines);
  19. }
  20. if (output_words) {
  21. printf("%lu ", count.words);
  22. }
  23. if (output_chars) {
  24. printf("%lu ", count.chars);
  25. }
  26. printf("%s\n", count.file.characters());
  27. }
  28. void report(const Vector<Count>& counts)
  29. {
  30. Count total { "total" };
  31. for (const auto& c : counts) {
  32. report(c);
  33. total.lines += c.lines;
  34. total.words += c.words;
  35. total.chars += c.chars;
  36. }
  37. if (counts.size() > 1) {
  38. report(total);
  39. }
  40. fflush(stdout);
  41. }
  42. int count_words(const char* s)
  43. {
  44. int n = 0;
  45. bool in_word = false;
  46. for (; *s; ++s) {
  47. if (!isspace(*s)) {
  48. if (!in_word) {
  49. in_word = true;
  50. ++n;
  51. }
  52. } else if (in_word) {
  53. in_word = false;
  54. }
  55. }
  56. return n;
  57. }
  58. int main(int argc, char** argv)
  59. {
  60. if (argc < 2) {
  61. printf("usage: wc [-c|-m] [-lw] [file...]");
  62. return 0;
  63. }
  64. CArgsParser args_parser("wc");
  65. args_parser.add_arg("l", "Include lines in count");
  66. args_parser.add_arg("c", "Include bytes in count");
  67. args_parser.add_arg("m", "Include chars in count");
  68. args_parser.add_arg("w", "Include words in count");
  69. CArgsParserResult args = args_parser.parse(argc, (const char**)argv);
  70. if (args.is_present("l")) {
  71. output_lines = true;
  72. }
  73. if (args.is_present("c")) {
  74. output_chars = true;
  75. }
  76. if (args.is_present("m")) {
  77. output_chars = true;
  78. }
  79. if (args.is_present("w")) {
  80. output_words = true;
  81. }
  82. if (!output_lines && !output_words && !output_chars) {
  83. output_lines = output_chars = output_words = true;
  84. }
  85. Vector<String> files = args.get_single_values();
  86. if (files.is_empty()) {
  87. fprintf(stderr, "wc: No files provided");
  88. return 1;
  89. }
  90. Vector<Count> counts;
  91. for (const auto& f : files) {
  92. FILE* fp = fopen(f.characters(), "r");
  93. if (fp == nullptr) {
  94. fprintf(stderr, "wc: Could not open file '%s'\n", f.characters());
  95. return 1;
  96. }
  97. Count count { f };
  98. char* line = nullptr;
  99. size_t len = 0;
  100. ssize_t n_read = 0;
  101. while ((n_read = getline(&line, &len, fp)) != -1) {
  102. count.lines++;
  103. count.words += count_words(line);
  104. count.chars += n_read;
  105. }
  106. counts.append(count);
  107. fclose(fp);
  108. if (line) {
  109. free(line);
  110. }
  111. }
  112. report(counts);
  113. return 0;
  114. }