[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [MiNT] STDIN and STDOUT are on a boat...



On Mon, Mar 13, 2000 at 06:26:36PM +0100, Remi Villatel wrote:
> ...And the boat is sinking with me on board.  ;-)  Any way...
> 
> Hello everybody,
> 
> Could someone explain to me (and to everyone interested around here) the 
> mysteries of STDIN and STDOUT?
> 
> What I'd like to know is how a program could catch the STDOUT output of another 
> program... and how a program can satisfy the STDIN needs of another program.
> 
> The project behind the questions is to do something like...
> 
> $ program1 | my_program | program2
> 
> ...as it could be done with 'bash' or any shell. So 'my_program' catches the 
> STDOUT output of 'program1', does some computations and send the results to 
> 'program2' as STDIN for further computations.

That's usually called IPC (interprocess communication).

Solution #1:

	FILE* mypipe = popen ("otherprg.tos", "w");
	
	fprintf (mypipe, "This is your stdin, otherprg.tos\n");
	pclose (mypipe);

The above example would search for "otherprg.tos" in $PATH, start it and
connect stdin of that prg with the stream MYPIPE.  The program's stdout is
the same as yours.  You can also use popen with a mode argument of "r", in
that case the stream would be read-only instead of write-only and you
could read the program's stdout from MYPIPE.  Since pipes are
uni-directional you cannot connect to the program's stdin and stdout at
once.  Unless ...

Solution #2:

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

char buf[] = "Message to cat.";
char buf2[sizeof buf];

int
main (int argc, char* argv[])
{
	int mypipes[2];
	pid_t childpid;
	int status;
	
	/* Create a pipe, the reading end is in mypipes[0], the
	   writing end in mypipes[1].  */
	if (pipe (mypipes) != 0) {
		perror ("pipe");
		return 1;
	}
	
	childpid = fork ();
	
	if (childpid == 0) {
		/* This is the child process.  Close standard streams
		   and connect them to the pipe but in reverse order.
		   In other words: The pipe's reading end is the child's
		   stdout/stderr; the pipe's writing end is the child's
		   stdin.  */
		char* childargv[] = { "cat", NULL };
		
		dup2 (mypipes[1], 0);
		dup2 (mypipes[0], 1);
		dup2 (mypipes[0], 2);
		
		execvp ("cat", childargv);
		
		/* If execvp returns, there is an error.  */
		perror ("can't execvp cat");
		exit (EXIT_FAILURE);
	} else if (childpid < 0) {
		perror ("fork");
		return EXIT_FAILURE;;
	}
	
	/* Since childpid is >= zero, that means parent side.  Say something
	   to the child and get an answer.  */
	
	write (mypipes[1], buf, sizeof buf - 1);
	buf2[sizeof buf2 - 1] = '\0';
	read (mypipes[0], buf2, sizeof buf2 - 1);
	
	if (strcmp (buf, buf2)) {
		fflush (stdout);
		fprintf (stderr, 
			 "Transmission error. Expected `%s', got `%s'\n",
			 buf, buf2);
		fflush (stderr);
		status = EXIT_FAILURE;
	} else
		printf ("child sent: `%s'\n", buf2);
	
	/* Wait for child to terminate.  */
	if (close (mypipes[1]) != 0) {
		perror ("close error");
		return EXIT_FAILURE;
	}
	
	/* Wait for child to terminate.  */
	{
		int childstatus;
		int pid = waitpid (childpid, &childstatus, 0);
		
		if (childpid != pid) {
			perror ("waitpid");
			return EXIT_FAILURE;
		}
		
		if (WIFEXITED (childstatus)) {
			printf ("child terminated with exit code %d\n",
				WEXITSTATUS (childstatus));
		} else if (WIFSIGNALED (childstatus)) {
			printf ("child got killed by signal %d\n",
			 	WTERMSIG (childstatus));
		} else {
			fflush (stdout);
			fprintf (stderr, "Ooops\n");
			return EXIT_FAILURE;
		}
	}
	
	(void) close (mypipes[0]);

	return status;
}
	
That's it basically.  Hope it compiles and runs.

If this is not enough try to get the manpages popen(2), pipe(2),
waitpid(2) from a Unix system.

Ciao

Guido
-- 
http://stud.uni-sb.de/~gufl0000/
mailto:guido@freemint.de