summaryrefslogtreecommitdiff
path: root/src/wc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wc.c')
-rw-r--r--src/wc.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/wc.c b/src/wc.c
new file mode 100644
index 0000000..3689595
--- /dev/null
+++ b/src/wc.c
@@ -0,0 +1,116 @@
+/*
+ * wc.c
+ * Implementation of SUSv3 XCU wc utility
+ * Copyright © 2007 Rich Felker
+ * Licensed under the terms of the GNU General Public License, v2 or later
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <locale.h>
+
+static int my_mbrtowc(wchar_t *wc, int b, mbstate_t *st)
+{
+ char c = b;
+ int retry = 1;
+retry:
+ switch ((int)mbrtowc(wc, &c, 1, st)) {
+ case -2:
+ return -2;
+ case -1:
+ memset(st, 0, sizeof(mbstate_t));
+ if (retry--) goto retry;
+ return retry; /* yes this is lame */
+ }
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int b;
+ int pc=0, pm=0, pw=0, pl=0;
+ unsigned long long c, m, w, l;
+ unsigned long long tc=0, tm=0, tw=0, tl=0;
+ int sp;
+ mbstate_t st;
+ wchar_t wc;
+ char *file;
+ FILE *f;
+ int err = 0;
+ int totals = 0, noname = 0;
+
+ setlocale(LC_CTYPE, "");
+
+ while ((b = getopt(argc, argv, "cmwl")) != EOF) switch(b) {
+ case 'c': pc=1; break;
+ case 'm': pm=1; break;
+ case 'w': pw=1; break;
+ case 'l': pl=1; break;
+ default: exit(1);
+ }
+ if (!(pc|pm|pw|pl)) pc=pw=pl=1;
+ if (pc&pm) {
+ fprintf(stderr, "%s: -c and -m are not valid together\n",
+ argv[0]);
+ exit(1);
+ }
+ if (optind == argc) {
+ file = "(stdin)";
+ f = stdin;
+ noname = 1;
+ goto use_stdin;
+ } else if (argc-optind > 1) totals=1;
+ for (; optind < argc; optind++) {
+ file = argv[optind];
+ f = fopen(file, "rb");
+ if (!f) {
+ fprintf(stderr, "%s: %s: ", argv[0], file);
+ perror("");
+ err = 1;
+ continue;
+ }
+use_stdin:
+ memset(&st, 0, sizeof st);
+ for (sp=1, c=m=w=l=0; (b=getc(f)) >= 0; c++) {
+ if ((pm|pw) && my_mbrtowc(&wc, b, &st) >= 0) {
+ m++;
+ if (iswspace(wc)) sp=1;
+ else if (sp) sp=0, w++;
+ }
+ if (b == '\n') l++;
+ }
+ if (ferror(f)) {
+ fprintf(stderr, "%s: %s: ", argv[0], file);
+ perror("");
+ err = 1;
+ }
+ tl += l; tw += w; tm += m; tc += c;
+totals:
+ if (pl) printf("%7llu", l);
+ if (pl&pw) putchar(' ');
+ if (pw) printf("%7llu", w);
+ if ((pl|pw)&(pc|pm)) putchar(' ');
+ if (pc|pm) printf("%7llu", pm?m:c);
+ if (!noname) printf(" %s", file);
+ putchar('\n');
+ fclose(f);
+ }
+ if (totals) {
+ l = tl;
+ w = tw;
+ m = tm;
+ c = tc;
+ file = "total";
+ f = stdin;
+ totals = 0;
+ goto totals;
+ }
+ return err;
+}