summaryrefslogtreecommitdiff
path: root/command/wc.c
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
commitd8f2c10b7108fff6b7e437291093a1cadc15ab9f (patch)
tree3fc50a19d6fbb9c94a8fe147cd2a6c4ba7f59b8d /command/wc.c
parentansii c (diff)
downloadlazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.gz
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.bz2
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.zip
refactor
Diffstat (limited to 'command/wc.c')
-rw-r--r--command/wc.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/command/wc.c b/command/wc.c
new file mode 100644
index 0000000..3150045
--- /dev/null
+++ b/command/wc.c
@@ -0,0 +1,161 @@
+#include "command.h"
+#include "lslib.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+static struct {
+ bool newlines;
+ bool words;
+ bool characters;
+ bool bytes;
+ bool longest_line;
+ bool has_flags;
+} flags;
+
+static int lines = 0;
+static int words = 0;
+static int chars = 0;
+static int bytes = 0;
+static int logst = 0;
+
+static void list(int l, int w, int c, int b, int lg) {
+ if (flags.newlines) {
+ printf("\t%d", l);
+ }
+ if (flags.words) {
+ printf("\t%d", w);
+ }
+ if (flags.characters) {
+ printf("\t%d", c);
+ }
+ if (flags.bytes) {
+ printf("\t%d", b);
+ }
+ if (flags.longest_line) {
+ printf("\t%d", lg);
+ }
+}
+
+#define BS 1024
+
+static bool is_delimiter(char c) {
+ return c == ' ' || c == '\t' || c == '\n';
+}
+
+static void run_wc(FILE* file) {
+ int l = 0, w = 0, c = 0, b = 0, lg = 0;
+
+ bool in_word = false;
+ int current_length = 0;
+
+ int read;
+ char buf[BS];
+ while ((read = fread(buf, 1, 1024, file)) > 0) {
+ int i;
+ for (i = 0; i < read; i++) {
+ char ch = buf[i];
+ b++;
+ if (ch == '\n') {
+ l++;
+ lg = lg > current_length ? lg : current_length;
+ current_length = 0;
+ } else {
+ current_length++;
+ }
+ if (isprint(ch) || is_delimiter(ch)) c++;
+ if (in_word && is_delimiter(ch)) {
+ in_word = false;
+ w++;
+ } else if (!in_word && !is_delimiter(ch) && isprint(ch)) {
+ in_word = true;
+ }
+ }
+ }
+ if (in_word) w++;
+ lg = lg > current_length ? lg : current_length;
+ list(l, w, c, b, lg);
+ lines += l;
+ words += w;
+ chars += c;
+ bytes += b;
+ logst += lg;
+ if (file != stdin)
+ fclose(file);
+}
+
+static void help(void) {
+ printf("Usage: wc [-cmlwL] [FILE]...\n\n");
+ printf("Count lines, words, and bytes for FILEs (or stdin)\n\n");
+ printf("\t-c Count bytes\n");
+ printf("\t-m Count characters\n");
+ printf("\t-l Count newlines\n");
+ printf("\t-w Count words\n");
+ printf("\t-L Print longest line length\n");
+ exit(EXIT_SUCCESS);
+}
+
+static int short_arg(char c, char* next) {
+ UNUSED(next);
+ switch (c) {
+ case 'c':
+ flags.bytes = true;
+ break;
+ case 'm':
+ flags.characters = true;
+ break;
+ case 'l':
+ flags.newlines = true;
+ break;
+ case 'w':
+ flags.words = true;
+ break;
+ case 'L':
+ flags.longest_line = true;
+ break;
+ default:
+ return ARG_INVALID;
+ }
+ flags.has_flags = true;
+ return ARG_UNUSED;
+}
+
+COMMAND(wc) {
+
+ int start, i;
+
+ flags.newlines = false;
+ flags.words = false;
+ flags.characters = false;
+ flags.bytes = false;
+ flags.longest_line = false;
+ flags.has_flags = false;
+
+
+ start = parse_args(argc, argv, help, short_arg, NULL);
+
+ if (!flags.has_flags) {
+ flags.newlines = true;
+ flags.words = true;
+ flags.characters = true;
+ }
+
+ if (argc - start < 1) {
+ run_wc(stdin);
+ printf("\n");
+ return EXIT_SUCCESS;
+ }
+
+ for (i = start; i < argc; i++) {
+ FILE* file = get_file(argv[i], "r");
+ run_wc(file);
+ printf("\t%s\n", argv[i]);
+ }
+
+ if (argc - start > 1) {
+ list(lines, words, chars, bytes, logst);
+ printf("\ttotal\n");
+ }
+
+ return EXIT_SUCCESS;
+}