/* * 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 #include #include #include #include #include #include #include #include #include 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; }