diff options
Diffstat (limited to 'src/wc.c')
-rw-r--r-- | src/wc.c | 116 |
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; +} |