wc.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * wc - count bytes, characters, words, lines...
  7. */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <getopt.h>
  12. #include <errno.h>
  13. #include <toaru/decodeutf8.h>
  14. int main(int argc, char * argv[]) {
  15. int show_lines = 0;
  16. int show_words = 0;
  17. int show_chars = 0;
  18. int show_bytes = 0;
  19. int opt;
  20. while ((opt = getopt(argc,argv,"cmlw")) != -1) {
  21. switch (opt) {
  22. case 'c':
  23. show_bytes = 1;
  24. break;
  25. case 'm':
  26. show_chars = 1;
  27. break;
  28. case 'l':
  29. show_lines = 1;
  30. break;
  31. case 'w':
  32. show_words = 1;
  33. break;
  34. }
  35. }
  36. int retval = 0;
  37. int total_lines = 0;
  38. int total_chars = 0;
  39. int total_words = 0;
  40. int just_stdin = 0;
  41. if (optind == argc) {
  42. argv[optind] = "";
  43. argc++;
  44. just_stdin = 1;
  45. }
  46. for (int i = optind; i < argc; ++i) {
  47. if (!*argv[i] && !just_stdin) {
  48. fprintf(stderr, "%s: invalid zero-length file name\n", argv[0]);
  49. retval = 1;
  50. continue;
  51. }
  52. FILE * f = (!strcmp(argv[i], "-") || just_stdin) ? stdin : fopen(argv[i], "r");
  53. if (!f) {
  54. fprintf(stderr, "%s: %s: %s\n", argv[0], argv[i], strerror(errno));
  55. retval = 1;
  56. continue;
  57. }
  58. int lines = 0;
  59. int chars = 0;
  60. int words = 0;
  61. int ch;
  62. uint32_t state, c;
  63. int last_was_whitespace = 0;
  64. while (!feof(f)) {
  65. ch = getc(f);
  66. if (ch < 0) break;
  67. if (show_chars) {
  68. if (!decode(&state, &c, ch)) {
  69. } else if (state == UTF8_REJECT) {
  70. state = 0;
  71. }
  72. } else {
  73. c = ch;
  74. }
  75. chars++;
  76. if (c == '\n') {
  77. last_was_whitespace = 1;
  78. lines++;
  79. words++;
  80. } else if (c == ' ') {
  81. if (last_was_whitespace) continue;
  82. last_was_whitespace = 1;
  83. words++;
  84. } else {
  85. last_was_whitespace = 0;
  86. }
  87. }
  88. if (!last_was_whitespace && chars > 0) words++;
  89. if (!show_words && !show_chars && !show_bytes && !show_lines) {
  90. fprintf(stdout, "%d %d %d %s\n", lines, words, chars, argv[i]);
  91. } else {
  92. if (show_lines) fprintf(stdout, "%d ", lines);
  93. if (show_words) fprintf(stdout, "%d ", words);
  94. if (show_bytes|show_chars) fprintf(stdout, "%d ", chars);
  95. fprintf(stdout, "%s\n", argv[i]);
  96. }
  97. total_lines += lines;
  98. total_words += words;
  99. total_chars += chars;
  100. if (f != stdin) fclose(f);
  101. if (just_stdin) return 0;
  102. }
  103. if (optind + 1 < argc) {
  104. if (!show_words && !show_chars && !show_bytes && !show_lines) {
  105. fprintf(stdout, "%d %d %d %s\n", total_lines, total_words, total_chars, "total");
  106. } else {
  107. if (show_lines) fprintf(stdout, "%d ", total_lines);
  108. if (show_words) fprintf(stdout, "%d ", total_words);
  109. if (show_bytes|show_chars) fprintf(stdout, "%d ", total_chars);
  110. fprintf(stdout, "%s\n", "total");
  111. }
  112. }
  113. return retval;
  114. }