/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
/*
		------------------------------------------
		 Remploi d'un executable (ici le 'sort').
		------------------------------------------
*/
/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

#include	<signal.h>
#include	<sys/types.h>
#include	<sys/wait.h>
#include	<unistd.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<dlfcn.h>
#include	<pthread.h>
#include	<string.h>

/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

/**
 *	Indicateur binaire production vs mise au point.
 */
int		debug	= 0;
int		environ	= 0;

/* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */

// detournement du signal de fin de processus fils
//
void		mySigChld		(int nosig)
	{
	int	status;
	wait	(&status);
	}

// detournement d'un signal de plantage
//
void		myPlantage		(int nosig)
	{
	}

// fonctions asynchrones branchees sur les E/S standards du pgm remploye */
// 
pthread_t	theThreadDevant;
pthread_t	theThreadDerriere;

// processus du pgm remploye
// 
int		thePid;

// raccords avec le pgm remploye
// 
int		tuyauDevant[2];
int		tuyauDerriere[2];

// E/S sorties banales utilisees
// 
FILE *		fileDevant;
FILE *		tubeDevant;
FILE *		fileDerriere;
FILE *		tubeDerriere;
//
char		lineIn	[100];
char		lineOut	[100];

/**
 *	Commptage des donnees echangees avec le tri.
 */
int		ctr	= 0;

/**
 *	Structure (a adapter) pour passer des parametres 
 *	aux fonctions d'entree et de sortie.
 */
typedef
struct	{
	char	message[40];
	}
	param;

param	theParamIn, theParamOut;

/* --------------------------------------------------------------------- */
/*	Alimentation asynchrone des donnees vers le tri.		 */
/* --------------------------------------------------------------------- */

void *		fInput			(void * p)
	{
	param * pp = (param *)p;
	fprintf(stderr, "Parametre recu dans fInput:\n\t%s\n",
			&pp->message[0]);
	if (debug)	fprintf(stderr, "...fInput() debute...\n");
	fileDevant	= fopen("fdevant",	"r");
	tubeDevant	= fdopen(tuyauDevant[1], "w");
	fgets	(lineIn, 100, fileDevant);
	while	(! feof(fileDevant))
		{
		ctr++;
		if (debug)	fprintf(stderr, "amont: %s\n", lineIn);
		fputs	(lineIn, tubeDevant);
		fgets	(lineIn, 100, fileDevant);
		}
	fclose	(fileDevant);
	fflush	(tubeDevant);
	fclose	(tubeDevant);
	if (debug)	fprintf(stderr, "...fInput() termine...\n");
	}

/* -------------------------------------------------------------------- */
/*	Recuperation asynchrone des donnees triees.			*/
/* -------------------------------------------------------------------- */

void *		fOutput			(void * p)
	{
	param * pp = (param *)p;
	fprintf(stderr, "Parametre recu dans fOutput:\n\t%s\n",
			&pp->message[0]);
	if (debug)	fprintf(stderr, "...fOutput() debute...\n");
	fileDerriere	= fopen("fderriere",	"w");
	tubeDerriere	= fdopen(tuyauDerriere[0], "r");
	fgets	(lineOut, 100, tubeDerriere);
	while	(! feof(tubeDerriere))
		{
		if (debug)	fprintf(stderr, "aval: %s\n", lineOut);
		fputs	(lineOut, fileDerriere);
		ctr--;
		//if (ctr <= 0) break;
		fgets	(lineOut, 100, tubeDerriere);
		}
	fflush	(fileDerriere);
	fclose	(fileDerriere);
	fclose	(tubeDerriere);
	if (debug)	fprintf(stderr, "...fOutput() termine...\n");
	}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */

/**
 *	Bibliotheque dynamique
 *	pour charger les (futures) fonctions d'E/S.
 */
void *		handle			= NULL;
void *		(*pInput)		(void * p);
void *		(*pOutput)		(void * p);

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */

int		main			(int argc, char * argv[], char * envp[])
	{
	int	w;
	//
	printf	("\n");
	printf	("----------------------------------\n");
	printf	(" Mise en place d'un tri complexe: \n");
	printf	("----------------------------------\n");
	printf	("\nB.M.G. version Hiver 2009\n");
	printf	("\nligne de commande:\n");
	for	(w = 0; w < argc; w++)
		{
		printf	("\t%d\t%s\n", w, argv[w]);
		/* */if	(! strcmp(argv[w], "-debug"))
			{
			debug	= 1;
			printf	("...debug actif...\n");
			}
		else if	(! strcmp(argv[w], "-environ"))
			{
			environ	= 1;
			}
		else if	(!strncmp(argv[w], "-lib=", 5))
			{
			handle = dlopen(&argv[w][5], RTLD_LAZY);
			if	(! handle)
				{
				printf	("\n\tNO LIBRARY ?!?!\n");
				}
			if	(handle)
				{
				pInput	= dlsym(handle, "fInput");
				if	(! pInput)
					{	printf
					("\n\tNO fInput in LIBRARY ?!?!\n");
					}
				pOutput	= dlsym(handle, "fOutput");
				if	(! pOutput)
					{	printf
					("\n\tNO fOutput in LIBRARY ?!?!\n");
					}
				}
			}
		}

	if	(environ)
		{
		for	(w = 0; envp[w]; w++)
			{
			printf	("\t%d\t%s\n", w, envp[w]);
			}
		}

	if	(debug) fprintf(stderr, "...creation des 'pipe'\n");
	pipe	(tuyauDevant);
	pipe	(tuyauDerriere);

	if	(debug) fprintf(stderr, "...lancement du processus...\n");
	signal	(SIGCHLD, mySigChld);
	thePid	= fork();
	switch	(thePid)
		{
		case	-1:	// erreur
			{
			}
		break;

		case	0:	// fils
			{
			if (debug)
			fprintf(stderr, "...raccordement amont...\n");
			close	(0);
			dup	(tuyauDevant[0]);
			close	(tuyauDevant[0]);
			close	(tuyauDevant[1]);

			if (debug)
			fprintf(stderr, "...raccordement aval...\n");
			close	(1);
			dup	(tuyauDerriere[1]);
			close	(tuyauDerriere[1]);
			close	(tuyauDerriere[0]);
			
			if (debug)
			fprintf(stderr, "...lancement du tri...\n");
			execl	("/usr/bin/sort", "sort", NULL);
			//execl	("/bin/cat", "cat", NULL);
			fprintf(stderr,
				"\n\tERREUR: PROGRAMME A LANCER !\n\n");
			}
		break;
		default	:	// pere
			{
			//sleep(5);

			close	(tuyauDevant	[0]);
			close	(tuyauDerriere	[1]);
			
			if (debug) fprintf(stderr,
				"...lancement des fonctions asynchrones...\n");

			strcpy	((char *)&(theParamIn.message[0]),
					"pour fInput...\n");
			
			strcpy	((char *)&(theParamOut.message[0]),
					"pour fOutput...\n");
			
			pthread_create	(&theThreadDevant,
						NULL, fInput,	&theParamIn);
			pthread_create	(&theThreadDerriere,
						NULL, fOutput,	&theParamOut);
			
			if (debug) fprintf(stderr,
				"...attente des fonctions asynchrones...\n");
			
			pthread_join	(theThreadDerriere,	NULL);
			if (debug) fprintf(stderr,
					"...theThreadDerriere fini !\n");

			pthread_join	(theThreadDevant,	NULL);
			if (debug) fprintf(stderr,
					"...theThreadDevant fini !\n");

			if (debug) fprintf(stderr, "...fin du travail !\n");
			exit(0);
			}
		break;
		}	

	return	0;
	}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/*
vi	Pipe.c
gcc	Pipe.c	-ldl	-oPipe
Pipe
*/