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

static void die(const char message[]) {
	perror(message);
	exit(EXIT_FAILURE);
}

// DESCRIPTION:
//   printStatus() examines the termination of a child process and
//   prints the source of the exit (signal or exit) and the
//   exit code or signal number, respectively.
//
// PARAMETER:
//   pid:    PID of the exited child process
//   status: Status bits as retrieved from waitpid(2)
//
// RETURN VALUE:
//   void:   -
static void printStatus(pid_t pid, int status) {
	// TODO IMPLEMENT
}

// DESCRIPTION:
//   parseCommandLine() gets one line as read from stdin and parses
//   the command and its arguments.
//
// PARAMETER:
//   buffer:     pointer to the line as read from stdin
//   argv:       pointer to an array to store the command (argv[0])
//               and all of its arguments (argv[1] - argv[n-1]). The
//               last argument (argv[n]) must be a NULL pointer
//   background: pointer to an int value indicating if this command
//               is a foreground process (background = 0) or a
//               background process (backgroud = 1). Can be ignored
//               for subexercise a) and b).
//
// RETURN VALUE:
//   int:        number of parsed entries (command and arguments) excluding
//               the NULL pointer
static int parseCommandLine(char *buffer, char **argv, int *background) {
	// TODO IMPLEMENT
	return 1;
}

// DESCRIPTION:
//  Signal handler to handle SIGCHLD events.
//
// TODO IMPLEMENT

// DESCRIPTION:
// Subexercise a)
//   handleTerminatedChild() is called when the program waits for a child
//   to terminate with waitpid(2) (blocking).
// Subexercise b+c)
//   handleTerminatedChild() is called when a child process has potentially
//   been terminated. It is collected with waitpid(2) (non-blocking).
//
// If a child process is collected it's exit status is printed
// (see printStatus()).
//
// PARAMETER:
//   void: -
//
// RETURN VALUE:
//   pid_t: PID of the handled child process
//
static pid_t handleTerminatedChild(void) {
	// TODO IMPLEMENT
	return 0;
}

// DESCRIPTION:
// executeCommand() forks the current process to execute argv. If it is
// a background process the parent process prints the PID of the child
// process to stdout.
//
// In the child process the program in argv is loaded and executed.
//
// PARAMETER:
//   argv:       The program to execute (argv[0]) and its arguments
//               (argv[1] - argv[n-1]) and a terminating NULL pointer
//               (argv[n]).
//   background: int value indicating if the program should be executed
//               as a foreground process (background = 0) or as a
//               background process (background = 1)
//
// RETURN VALUE:
//   pid_t:      PID of the started child
//
static pid_t executeCommand(char **argv, int background) {
	// TODO IMPLEMENT
	return 0;
}

// DESCRIPTION:
// in the main() function necessary initialization work is done, the prompt
// is printed, the user input is read and the corresponding functions
// are called to parse the user input and execute the entered commands.
//
// Furthermore, the code to collect child processes and, if necessary, wait
// for them is located in the main().
// Starting with subexercise b) waiting on child processes shall be
// implemented using the sigsuspend() method. Be aware of the correct
// synchronization to prevent lost-wakeup or other synchronization problems.
int main(void) {
	// TODO IMPLEMENT
	return EXIT_SUCCESS;
}
