#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>

#define BUFSIZE 1024

int *allocateFds(int nfiles, char **argv);
void cleanUp(int *fds);

int openFlags = O_WRONLY | O_CREAT | O_TRUNC;

int
main(int argc, char *argv[])
{
    int nread, nfiles, fd, i, c;
    int *fds;
    char buf[BUFSIZE];

    while ((c = getopt(argc, argv, "a")) != -1) {
        switch (c) {
        case 'a':
            openFlags |= O_APPEND;
            openFlags &= ~O_TRUNC;
            break;

        default:
            break;
        }
    }

    argc -= optind;
    argv += optind;

    if (argc > FOPEN_MAX - 3)
        errx(EXIT_FAILURE, "%s", strerror(EMFILE));
    fds = allocateFds(argc, argv);

    while ((nread = read(STDIN_FILENO, buf, sizeof(buf))) > 0)
        for (i = 0; fds[i] != -1; i++)
            if (write(fds[i], buf, nread) != nread)
                err(EXIT_FAILURE, "write");

    if (nread == -1)
        err(EXIT_FAILURE, "read");

    cleanUp(fds);
    exit(EXIT_SUCCESS);
}

// cleanUp: close file descriptors and free descriptors array
void
cleanUp(int *fds)
{
    int i;

    for (i = 1; fds[i] != -1; i++)
        if (close(fds[i]) == -1)
            warn("close error fd=%d\n", fds[i]);

    free(fds);
}

// allocateFds: create file descriptors array and open files
int *
allocateFds(int nfiles, char **argv)
{
    int *fds;
    int i;

    //nfiles+2 (STDOUT_FILENO and -1 invalid file descriptor)
    fds = (int *) malloc((nfiles + 2) * sizeof(int));
    if (fds == NULL)
        err(EXIT_FAILURE, "malloc");

    fds[0]          = STDOUT_FILENO;    // first file descriptor = STDOUT_FILENO
    fds[nfiles + 1] = -1;               // last file descriptor = -1

    for (i = 0; i < nfiles; i++)
        if ((fds[i + 1] = open(argv[i], openFlags, 0755)) == -1)
            err(EXIT_FAILURE, "open %s", argv[i]);

    return fds;
}
