#include "../command.h" #include struct Flags { bool newlines; bool words; bool characters; bool bytes; bool longest_line; }; 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, struct Flags* flags) { 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, struct Flags* flags) { 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) { for (int 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, flags); lines += l; words += w; chars += c; bytes += b; logst += lg; if (file != stdin) fclose(file); } static void help() { 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); } COMMAND(wc) { struct Flags flags; flags.newlines = false; flags.words = false; flags.characters = false; flags.bytes = false; flags.longest_line = false; bool has_flags = false; int start = 0; for (int i = 0; i < argc; i++) { if (!prefix("-", argv[i])) break; if (streql("--help", argv[i])) help(); start++; for (size_t j = 1; j < strlen(argv[i]); j++) { char c = argv[i][j]; 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: error("error: invald option -%c", c); } has_flags = true; } } if (!has_flags) { flags.newlines = true; flags.words = true; flags.characters = true; } if (argc - start < 1) { run_wc(stdin, &flags); printf("\n"); return EXIT_SUCCESS; } for (int i = start; i < argc; i++) { FILE* file = get_file(argv[i], "r"); run_wc(file, &flags); printf("\t%s\n", argv[i]); } if (argc - start > 1) { list(lines, words, chars, bytes, logst, &flags); printf("\ttotal\n"); } return EXIT_SUCCESS; }