#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <errno.h>

#if HAVE_FCNTL_H
#include <fcntl.h>
#endif

#include "libhdr.h"

#define	STDIN	0
#define	STDOUT	1
#define   READ	     0
#define   WRITE	1

static pid_t childpid = 0;

static void dupto (const int from,const int to,const char *msg)
{
	int err;

	if(from!=to) {
		if(errno) perror("aa:");
		err=close(to);
		if (err<0 && errno != EBADF) {
			perror("dupto(): Cannot close file descriptor");
			exit(EXIT_FAILURE);
		}
		if(errno) perror("AA:");
		err=dup(from);
		if(errno) perror("BB:");
		if (err!=to)	{
			(void)fprintf(stderr,"dupto(): Cannot dup %s\n",msg);
			exit(EXIT_FAILURE);
		}
		if(close(from)<0) {
			(void)fprintf(stderr,"dupto(): cannot close file descriptor\n");
			exit(EXIT_FAILURE);
		}
		if(errno) perror("CC:");
	}
}

int child_open1(const int read_flag,const char *fname,const char *filterprog,const char *arg)
{
	int ppipe[2]={-1,-1},fd= -1,fd1;
	struct stat sbuf;
	
	if(!fname) return fd;
	if(read_flag==READ) if(stat(fname,&sbuf)) return fd;
	if(pipe(ppipe)<0)	{
		(void)fprintf(stderr,"child_open(): Can't open pipe\n");
		return fd;
	}
	childpid=fork();
	if(childpid<0)	{
		(void)fprintf(stderr, "child_open(): cannot fork\n");
		return fd;
	}
	if(childpid>0)	{
		if(read_flag==READ)	{
			fd=ppipe[READ];
			if(close(ppipe[WRITE])<0) {
				(void)fprintf(stderr, "child_open(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		} else {
			fd=ppipe[WRITE];
			if(close(ppipe[READ])<0) {
				(void)fprintf(stderr, "child_open(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		}
	} else {
		if(read_flag==READ)	{
			dupto(ppipe[WRITE], STDOUT,"(child) pipr to stdout");
			if(close(ppipe[READ])<0) {
				(void)fprintf(stderr, "child_open(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
			if(fname) {
				fd1=open(fname,O_RDONLY,0666);
				if(fd1<0) {
					(void)fprintf(stderr, "child_open(): cannot open file %s\n",fname);
					exit(EXIT_FAILURE);
				}
				dupto(fd1,STDIN,"file to stdin");
			}
		} else {
			dupto (ppipe[READ], STDIN, "(child) pipe to stdin");
			if(close(ppipe[WRITE])<0) {
				(void)fprintf(stderr, "child_open(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
			if(fname) {
				fd1=creat(fname,0666);
				if(fd1<0) {
					(void)fprintf(stderr, "child_open(): cannot open file %s\n",fname);
					exit(EXIT_FAILURE);
				}
				dupto(fd1,STDOUT,"file to stdout");
			}
		}
		if(read_flag==READ) (void)execlp(filterprog,filterprog,arg,(char *)0);
		else (void)execlp(filterprog,filterprog,arg,(char *) 0);
		(void)fprintf(stderr, "child_open(): cannot exec %s\n",filterprog);
		_exit(EXIT_FAILURE);
	}
	return fd;
}

int child_open(const int read_flag,const char *fname,const char *filterprog)
{
	int fd;
	
	if(read_flag==READ) fd=child_open1(read_flag,fname,filterprog,"-d");
	else fd=child_open1(read_flag,fname,filterprog,0);
	return fd;
}

#if !HAVE_POPEN
FILE *popen(const char *command,const char *type)
{
	int ppipe[2]={-1,-1},read_flag,fd;
	FILE *fptr=0;
	
	if(!command) return fptr;
	if(!strcmp("r",type)) read_flag=READ;
	else if(!strcmp("w",type)) read_flag=WRITE;
	else return fptr;
	if(pipe(ppipe)<0)	{
		(void)fprintf(stderr,"lk_popen(): Can't open pipe\n");
		return fptr;
	}
	childpid=fork();
	if(childpid<0)	{
		(void)fprintf(stderr, "lk_popen(): cannot fork\n");
		return fptr;
	}
	if(childpid>0)	{
		if (read_flag==READ)	{
			fd = ppipe[READ];
			if(close(ppipe[WRITE])<0) {
				(void)fprintf(stderr, "lk_popen(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		} else {
			fd = ppipe[WRITE];
			if(close(ppipe[READ])<0) {
				(void)fprintf(stderr, "lk_popen(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		}
		fptr=fdopen(fd,type);
		if(!fptr) {
			(void)fprintf(stderr, "lk_popen(): fdopen() failed\n");
			exit(EXIT_FAILURE);
		}
	} else {
		if(read_flag==READ) {
			dupto (ppipe[WRITE], STDOUT, "(child) pipe to stdout");
			if(close(ppipe[READ])<0) {
				(void)fprintf(stderr, "lk_popen(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		} else {
			dupto (ppipe[READ], STDIN, "(child) pipe to stdin");
			if(close(ppipe[WRITE])<0) {
				(void)fprintf(stderr, "lk_popen(): cannot close pipe\n");
				exit(EXIT_FAILURE);
			}
		}
		(int)execl("/bin/sh","sh","-c",command,(char *)0);
		(void)fprintf(stderr, "lk_popen(): cannot exec %s\n",command);
		_exit(EXIT_FAILURE);
	}
	return fptr;
}

#endif
