summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wc.c115
1 files changed, 73 insertions, 42 deletions
diff --git a/wc.c b/wc.c
index 5040ec6..4f7584b 100644
--- a/wc.c
+++ b/wc.c
@@ -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;
}