wc.c (1948B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <string.h> 3 4 #include "utf.h" 5 #include "util.h" 6 7 static int lflag = 0; 8 static int wflag = 0; 9 static char cmode = 0; 10 static size_t tc = 0, tl = 0, tw = 0; 11 12 static void 13 output(const char *str, size_t nc, size_t nl, size_t nw) 14 { 15 int noflags = !cmode && !lflag && !wflag; 16 int first = 1; 17 18 if (lflag || noflags) { 19 if (!first) 20 putchar(' '); 21 printf("%*.1zu", first ? (first = 0) : 6, nl); 22 } 23 if (wflag || noflags) { 24 if (!first) 25 putchar(' '); 26 printf("%*.1zu", first ? (first = 0) : 6, nw); 27 } 28 if (cmode || noflags) { 29 if (!first) 30 putchar(' '); 31 printf("%*.1zu", first ? (first = 0) : 6, nc); 32 } 33 if (str) 34 printf(" %s", str); 35 putchar('\n'); 36 } 37 38 static void 39 wc(FILE *fp, const char *str) 40 { 41 int word = 0, rlen; 42 Rune c; 43 size_t nc = 0, nl = 0, nw = 0; 44 45 while ((rlen = efgetrune(&c, fp, str))) { 46 nc += (cmode == 'c' || !cmode) ? rlen : (c != Runeerror); 47 if (c == '\n') 48 nl++; 49 if (!isspacerune(c)) 50 word = 1; 51 else if (word) { 52 word = 0; 53 nw++; 54 } 55 } 56 if (word) 57 nw++; 58 tc += nc; 59 tl += nl; 60 tw += nw; 61 output(str, nc, nl, nw); 62 } 63 64 static void 65 usage(void) 66 { 67 eprintf("usage: %s [-c | -m] [-lw] [file ...]\n", argv0); 68 } 69 70 int 71 main(int argc, char *argv[]) 72 { 73 FILE *fp; 74 int many; 75 int ret = 0; 76 77 ARGBEGIN { 78 case 'c': 79 cmode = 'c'; 80 break; 81 case 'm': 82 cmode = 'm'; 83 break; 84 case 'l': 85 lflag = 1; 86 break; 87 case 'w': 88 wflag = 1; 89 break; 90 default: 91 usage(); 92 } ARGEND 93 94 if (!argc) { 95 wc(stdin, NULL); 96 } else { 97 for (many = (argc > 1); *argv; argc--, argv++) { 98 if (!strcmp(*argv, "-")) { 99 *argv = "<stdin>"; 100 fp = stdin; 101 } else if (!(fp = fopen(*argv, "r"))) { 102 weprintf("fopen %s:", *argv); 103 ret = 1; 104 continue; 105 } 106 wc(fp, *argv); 107 if (fp != stdin && fshut(fp, *argv)) 108 ret = 1; 109 } 110 if (many) 111 output("total", tc, tl, tw); 112 } 113 114 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); 115 116 return ret; 117 }