1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
/* Track whether we are inside or outside a word */
typedef enum _state {IN,OUT} state;
/* true if c is a 'word' character (not a blank, space, or a tab) */
static bool is_word(char c) {
return c != ' ' && c != '\t' && c != '\n';
}
struct res {
uint32_t cc;
uint32_t lc;
uint32_t wc;
};
struct res_internal {
struct res res;
state s;
};
static struct res_internal nri(void) {
struct res_internal res = {
.s = OUT,
.res = {
.cc = 0,
.lc = 0,
.wc = 0,
}
};
return res;
}
static struct res_internal do_count_internal(FILE* fin, struct res_internal res) {
int c = fgetc(fin);
if (c == EOF) {
return res;
}
res.res.cc++;
if (c == '\n') {
res.res.lc++;
}
if (!is_word(c)) {
res.s = OUT;
} else if (res.s == OUT) {
res.s = IN;
res.res.wc++;
}
__attribute__((musttail))
return do_count_internal(fin, res);
}
struct res do_count() {
struct res_internal ri = do_count_internal(stdin, nri());
return ri.res;
}
/* Counts characters, lines, and words from stdin.
'characters' are single byte characters. No handling for encodings in c standard lib.
'lines' are newline characters.
'words' are contiguous sequences of characters other than space, tab, newline */
int main(void) {
struct res res = do_count();
printf("cc=%d lc=%d wc=%d\n", res.cc, res.lc, res.wc);
return 0;
}
|