aboutsummaryrefslogtreecommitdiff
path: root/user/usr/bin/wc.c
blob: f6226149f6b144adc389412183e6695f9b9e3e3d (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 1024

typedef struct count_results
{
    unsigned long long n_chars;
    unsigned long long n_words;
    unsigned long long n_lines;
} count_results_t;

char buf[BUFFER_SIZE];

void print_counts(count_results_t *results, char *name)
{
    if (name)
    {
        printf("%10llu %10llu %10llu %10s\n", results->n_lines,
               results->n_words, results->n_chars, name);
    }
    else
    {
        printf("%10llu %10llu %10llu\n", results->n_lines, results->n_words,
               results->n_chars);
    }
}

void count(int fd, char *name, count_results_t *results)
{
    size_t bytes_read;
    unsigned int in_word, i;

    in_word = 0;
    while ((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0)
    {
        for (i = 0; i < bytes_read; ++i)
        {
            if (isspace(buf[i]))
            {
                if (in_word)
                {
                    results->n_words++;
                    in_word = 0;
                }
            }
            else
            {
                in_word = 1;
            }

            if (buf[i] == '\n')
            {
                results->n_lines++;
            }
        }

        results->n_chars += bytes_read;
    }

    print_counts(results, name);
}

int main(int argc, char **argv)
{
    int f, fd;
    count_results_t total_counts = {.n_chars = 0, .n_words = 0, .n_lines = 0};
    count_results_t local_counts = {.n_chars = 0, .n_words = 0, .n_lines = 0};

    if (argc == 1)
    {
        /* Reading from standard input. */
        count(0, 0, &total_counts);
    }
    else
    {
        /* Reading files, not standard input. */
        for (f = 1; f < argc; ++f)
        {
            fd = open(argv[f], O_RDONLY, 0);
            if (fd < 0)
            {
                /* Error opening file. */
                fprintf(stderr, "wc: %s: open: %s\n", argv[f], strerror(errno));
            }
            else
            {
                /* Opened the file. */
                count(fd, argv[f], &local_counts);

                total_counts.n_chars += local_counts.n_chars;
                total_counts.n_words += local_counts.n_words;
                total_counts.n_lines += local_counts.n_lines;

                /* Reset the local counts. */
                local_counts.n_chars = local_counts.n_words =
                    local_counts.n_lines = 0;

                close(fd);
            }
        }

        if (argc > 2)
        {
            /* They provided multiple files. We should print the total too. */
            print_counts(&total_counts, "total");
        }
    }

    return 0;
}