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