/* popen(): open a file handle to a process. Works only under MiNT.
 * Written by Eric R. Smith, based on the TOS version by Kai-Uwe Bloem.
 */

#include	<stdio.h>
#include	<stdlib.h>
#include	<process.h>
#include	<fcntl.h>
#include	<string.h>
#include	<errno.h>
#include	<unistd.h>

__EXTERN int wait __PROTO((int *));

struct _pipe {
	int	pid;		/* process id of child			*/
	FILE	*pfile;		/* created file descriptor		*/
	struct _pipe	*pnext;	/* next pipe in the list.		*/
};

static struct _pipe	*__pipes = NULL;	/* head of pipe list	*/

FILE *popen(command, type)
const char	*command, *type;
{
	struct _pipe *p;	/* the new pipe's list entry	*/
	int pipfd[2];		/* pipe file handles */
	int savefd;		/* saved file descriptor for parent */
	int kidfd;		/* file descriptor changed in child */
				/* 1 for "r", 0 for "w" */	

	char *shell;
	FILE *pipefile = 0;
	extern int __mint;

	if (__mint == 0) {
		errno = EINVAL;
		return (FILE *)0;
	}

	shell = getenv("SHELL");
	if (!shell)
		shell = "sh";

	/* get space for the new pipe. If we can't get it then that's that */
	p = (struct _pipe *) malloc(sizeof(struct _pipe));
	if (p == NULL) return (FILE *)0;

	/* initialize the new pipe entry */
	kidfd = (*type == 'r') ? 1 : 0;

	savefd = dup(kidfd);

	if (savefd < 0 || pipe(pipfd) != 0) {	/* can't create pipe?? */
		free(p);
		return (FILE *)0;
	}

	dup2(pipfd[kidfd], kidfd);
	close(pipfd[kidfd]);
	p->pid = spawnlp(P_NOWAIT, shell, shell, "-c", command, (char *)0);
	dup2(savefd, kidfd);
	close(savefd);

	if (p->pid > 0) {	/* command ran all right */
	/* note: 1-kidfd tells us which handle to use in the parent */
		pipefile = fdopen(pipfd[1 - kidfd], type);
	}

	if (pipefile) {
		p->pfile = pipefile;
		p->pnext = __pipes;
		__pipes = p;
	}
	else {
		free(p);
	}
	return pipefile;
}

/* close a pipe created by popen().
 */
int pclose(fp)
FILE	*fp;
{
	struct _pipe	*p,		/* the pipe's list element	*/
			*q;		/* predecessor of p in the list	*/
	int	status = -1;		/* return status of the command	*/
	int	pid;

	/* search the pipe list for a pipe matching the FILE descriptor	*/
	for (p = __pipes, q = NULL;  p && p->pfile != fp;  q = p, p = p->pnext);
	if (p == NULL)		/* Never had a popen() for this file...	*/
		return status;	/* this pclose call makes no sense !	*/

	fclose(p->pfile);	/* close the connection		*/

/* now wait for the command to finish */

	do {
		pid = wait(&status);
	} while (pid >= 0 && pid != p->pid);

	/* remove the pipe from the list */
	if (q)	/* not the first in the list, unlink it from previous pipe */
		q->pnext = p->pnext;
	else	/* first in the list, set new list head	*/
		__pipes = __pipes->pnext;

	/* Now free the pipe entry */
	free(p);

	return status;
}
