summaryrefslogtreecommitdiff
path: root/ex1-10.c
blob: f17e7487facd03eb442a7e6c6dcd62bd8796ecfe (plain)
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;
}