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