#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "error.h"
#include "AVLTree.h"
#include "xargs.h"

#define NUMARGS 512

static int run(char **argv) {
	int i, status;
	pid_t pid;

	switch(pid = fork()) {
	case -1: /* error */
		perror("fork()");
		return -1;
	case 0: /* child */
		for(i = getdtablesize()-1; i>STDERR_FILENO; i--)
			fcntl(i, F_SETFD, ~0);
		execvp(argv[0], argv);
		perror_exit(255, argv[0]);
	default:
		for(i=0; i<0 ? errno==EINTR : i!=pid; i = waitpid(pid, &status, 0));
		return i<0 ? (perror(argv[0]), -1)
			: WIFEXITED(status) ? WEXITSTATUS(status)
			: WIFSIGNALED(status) ? WTERMSIG(status)+128
			: -1;
	}
	return -1;
}

int runv(char *cmd, ...) {
	return run(&cmd);
}

int xargs(AVLTree *t, const char *args) {
	char *s, *cmd, *argv[NUMARGS];
	AVLNode *c;
	int argc, i=0;

	if(!t || !t->head)
		return 0;

	s = alloca(strlen(args)+1);
	if(!s)
		return -1;
	strcpy(s, args);

	while(i<NUMARGS && s) {
		cmd = strsep(&s, " \t");
		if(!cmd)
			break;
		if(*cmd)
			argv[i++] = cmd;
	}

	argc = i;
	c = t->head;

	while(c) {
		for(i = argc; c && i<NUMARGS-1; c = c->next, i++)
			argv[i] = c->item;
		argv[i] = NULL;
		i = run(argv);
		if(i)
			return i;
	}
	return 0;
}
