diff options
-rw-r--r-- | wc.c | 115 |
1 files changed, 73 insertions, 42 deletions
@@ -18,21 +18,25 @@ */ #define _XOPEN_SOURCE 700 +#include <errno.h> #include <inttypes.h> #include <stdio.h> +#include <string.h> #include <ctype.h> +#include <wchar.h> +#include <wctype.h> #include <unistd.h> -#define BYTES 1 << 0 -#define CHARS 1 << 1 -#define LINES 1 << 2 -#define WORDS 1 << 3 +#define BYTES (1 << 0) +#define CHARS (1 << 1) +#define LINES (1 << 2) +#define WORDS (1 << 3) static uintmax_t total_n = 0; static uintmax_t total_w = 0; static uintmax_t total_c = 0; -void flagprint (uintmax_t n, uintmax_t w, uintmax_t c, char *f, int flags) +void flagprint(uintmax_t n, uintmax_t w, uintmax_t c, char *f, int flags) { if (flags == 0) { flags = LINES | WORDS | CHARS; @@ -43,78 +47,110 @@ void flagprint (uintmax_t n, uintmax_t w, uintmax_t c, char *f, int flags) } if (flags & WORDS) { - printf ("%ju%s", w, flags ^ (LINES | WORDS) ? " " : ""); + printf("%ju%s", w, flags ^ (LINES | WORDS) ? " " : ""); } if (flags & CHARS || flags & BYTES) { - printf ("%lu", c); + printf("%lu", c); } - // FIXME: What an ass-pain if (f != NULL) { - printf ("%s%s", flags & CHARS || flags & BYTES ? " " : "", f); + printf("%s%s", flags & CHARS || flags & BYTES ? " " : "", f); } - printf ("\n"); + printf("\n"); } -int wc(FILE *f, int flags, char *name) +wint_t get_char_or_byte(FILE *f, int flags) +{ + if (flags & CHARS) { + return fgetwc(f); + } + int c = fgetc(f); + if (c == EOF) { + return WEOF; + } + return c; +} + +int is_space(wint_t c, int flags) +{ + if (flags & CHARS) { + return iswspace(c); + } + return isspace(c); +} + +int is_newline(wint_t c, int flags) +{ + if (flags & CHARS) { + return c == L'\n'; + } + return c == '\n'; +} + +int wc(char *path, int flags) { uintmax_t newlines = 0; uintmax_t words = 0; uintmax_t charbytes = 0; int wasword = 0; - int n, i; - char buf[BUFSIZ]; - while (!feof(f)) { - n = fread (buf, sizeof(char), BUFSIZ, f); + FILE *f = stdin; - if (flags & CHARS) { - charbytes += n; // FIXME: wrong, convert to wc_type or mb_char - } else { - charbytes += n; + if (path && strcmp(path, "-") != 0) { + f = fopen(path, "r"); + if (f == NULL) { + fprintf(stderr, "wc:couldn't open %s:%s\n", path, + strerror(errno)); + return 1; } + } + + wint_t c; + while ((c = get_char_or_byte(f, flags)) != WEOF) { + charbytes++; - for (i = 0; i < n; i++) { - if (buf[i] == '\n') { + if (is_space(c, flags)) { + if (is_newline(c, flags)) { newlines++; - if (wasword == 0) { - wasword = 1; - words++; - } - } else if (wasword == 0 && isspace(buf[i])) { - wasword = 1; + } + if (wasword == 0) { words++; - } else { - wasword = 0; } + wasword = 1; + } else { + wasword = 0; } } + if (f != stdin) { + fclose(f); + } + total_n += newlines; total_w += words; total_c += charbytes; - flagprint (newlines, words, charbytes, name, flags); + flagprint (newlines, words, charbytes, path, flags); return 0; } int main(int argc, char *argv[]) { + int ret = 0; int flags = 0; int total = 0; int c; - while ((c = getopt(argc, argv, ":cmlw")) != -1) { + while ((c = getopt(argc, argv, "cmlw")) != -1) { switch (c) { case 'c': - if (flags & CHARS) { return 1; } flags |= BYTES; + flags &= ~CHARS; break; case 'm': - if (flags & BYTES) { return 1; } flags |= CHARS; break; @@ -135,18 +171,13 @@ int main(int argc, char *argv[]) total = 1; } - if (optind >= argc) { - wc(stdin, flags, NULL); - } else while (optind < argc) { - FILE *in = fopen(argv[optind], "r"); - wc(in, flags, argv[optind]); - fclose(in); - optind++; - } + do { + ret |= wc(argv[optind++], flags); + } while (argv[optind]); if (total) { flagprint(total_n, total_w, total_c, "total", flags); } - return 0; + return ret; } |