/*
 * Process Unidirectional Pipe
 * Martin Klöckner - mklockner@fi.uba.ar
 *
 * Based on example given in wait(2) man page
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdint.h>

#define LOG_ENABLE     true
#define PIPE_READ_END  0
#define PIPE_WRITE_END 1

#if true == LOG_ENABLE
#define LOG(fmt, ...) do {                                      \
        printf("[LOG] "fmt, ##__VA_ARGS__); \
    } while (0)
#define LOG_ID(fmt, ...) do {                                 \
        printf("[LOG][%ld] "fmt, proc_count, ##__VA_ARGS__); \
    } while (0)
#else
#define LOG(fmt, ...)
#define PROC_LOG(fmt, ...)
#endif

int main (void)
{
    int wstatus, cpid, proc_count;
    int pipefd[2];
    char buf;

    proc_count = 0;

    if (pipe(pipefd) == -1)
    {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid = fork();

    if (cpid == -1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if (cpid == 0)
    {
        // Child

        proc_count++;
        LOG_ID("PID is %jd\n", (intmax_t) getpid());

        if (close(pipefd[1]) == -1) {
            // Close unused write end
            perror("close");
            exit(EXIT_FAILURE);
        }

        while (read(pipefd[0], &buf, 1) > 0) {
            if (write(STDOUT_FILENO, &buf, 1) != 1)
            {
                perror("write");
                exit(EXIT_FAILURE);
            }

            if(buf == '\n')
            {
                break;
            }
        }

        exit(EXIT_SUCCESS);
    }
    else
    {
        // Parent

        if (close(pipefd[0]) == -1) {
            // Close unused read end
            perror("close");
            exit(EXIT_FAILURE);
        }

        LOG_ID("PID is %jd\n", (intmax_t) getpid());
        const char *str = "Hello, World!\n\0";
        write(pipefd[PIPE_WRITE_END], str, strlen(str));

        do
        {
            if(waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED) == -1)
            {
                perror("waitpid");
                exit(EXIT_FAILURE);
            }

            if (WIFEXITED(wstatus))
            {
                LOG_ID("Child exited with status %d\n", WEXITSTATUS(wstatus));
            }
            else if (WIFSIGNALED(wstatus))
            {
                LOG_ID("Child killed by signal %d\n", WTERMSIG(wstatus));
            }
            else if (WIFSTOPPED(wstatus))
            {
                LOG_ID("Child stopped by signal %d\n", WSTOPSIG(wstatus));
            }
            else if (WIFCONTINUED(wstatus))
            {
                LOG_ID("Child continued\n");
            }

        } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
        exit(EXIT_SUCCESS);
    }

    exit(EXIT_SUCCESS);
}
