#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

static int pline, pword, pchar;
static uintmax_t nline, nword, nchar;

static void
report(uintmax_t lines, uintmax_t words, uintmax_t bytes, const char *name)
{
    if (pline) printf("%7ju ", lines);
    if (pword) printf("%7ju ", words);
    if (pchar) printf("%7ju", bytes);
    if (name) printf(" %s", name);
    putchar('\n');
}

static int
count(int fd, const char *name)
{
    unsigned char buf[8192];
    int inword = 0;
    nline = nword = nchar = 0;
    for (;;) {
        ssize_t n = read(fd, buf, sizeof(buf));
        size_t i;
        if (n < 0 && errno == EINTR) continue;
        if (n < 0) { perror(name ? name : "wc: stdin"); return 1; }
        if (n == 0) break;
        nchar += (uintmax_t)n;
        for (i = 0; i < (size_t)n; ++i) {
            if (buf[i] == '\n') ++nline;
            if (isspace(buf[i])) inword = 0;
            else if (!inword) { ++nword; inword = 1; }
        }
    }
    report(nline, nword, nchar, name);
    return 0;
}

int
main(int argc, char **argv)
{
    uintmax_t tnline = 0, tnword = 0, tnchar = 0;
    int option, status = 0, files;
    while ((option = getopt(argc, argv, "lwc")) != -1) {
        if (option == 'l') pline = 1;
        else if (option == 'w') pword = 1;
        else if (option == 'c') pchar = 1;
        else { fprintf(stderr, "usage: %s [-lwc] [file...]\n", argv[0]); return 1; }
    }
    if (!pline && !pword && !pchar) pline = pword = pchar = 1;
    files = argc - optind;
    if (!files) status = count(STDIN_FILENO, NULL);
    for (; optind < argc; ++optind) {
        int fd = strcmp(argv[optind], "-") == 0 ? STDIN_FILENO : open(argv[optind], O_RDONLY);
        if (fd < 0) { perror(argv[optind]); status = 1; continue; }
        status |= count(fd, argv[optind]);
        tnline += nline; tnword += nword; tnchar += nchar;
        if (fd != STDIN_FILENO && close(fd) < 0) { perror(argv[optind]); status = 1; }
    }
    if (files > 1) report(tnline, tnword, tnchar, "total");
    if (fflush(stdout) == EOF || ferror(stdout)) { perror("wc: stdout"); status = 1; }
    return status;
}
