Re: OT: capturing stdout & stderr to a GtkText



>Currently, I have Perl embedded to process whatever the user types (yup,
>it's possible to enter anything that Perl digs as ok, and it will executed.)
>However, if I enter "print 2;" the Perl interpreter will print 2 but on a
>terminal. How can I capture the stdout and stderr output of an embedded
>program like Perl? If I can capture, it'll be no problem adding it to the
>GtkText.

you need to take control of exec-ing the sub-process so that you have
file descriptors corresponding to its stdin/out/err. typically, you
create a set of pipes with pipe(2) first, then you close&dup the file
descriptors for stdin, stdout, stderr. see below for an example of how
to do (most) this. 

then use gdk_input_add() to get GTK's main loop to watch the relevant
file descriptors for data to read; your callback will be invoked when
there is data there, and you can then make whatever calls you wish to
display the messages in a GTK widget of some kind.

the end result is something like this (without any required error checking).

------------------------------------------------------------

   int in[2], out[2], err[2];
   char args[2];

   pipe (in);
   pipe (out);
   pipe (err);

   args[0] = "/usr/bin/perl";
   args[1] = 0;

   gdk_input_add (out[0], GDK_INPUT_READ, stdout_data_ready, NULL);
   gdk_input_add (err[0], GDK_INPUT_READ, stderr_data_ready, NULL);

   forkexec (args, NULL, in, out, err);

------------------------------------------------------------

--p

/*
    Copyright (C) 1989/1994/1999 Paul Davis 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>

/*
  Run a program with program name and args specified by argv, in the
  environment specified by envp.

  The exec'ed program uses inpipe[READ_DESC], outpipe[WRITE_DESC]
  and errpipe[WRITE_DESC] as stdin, stdout, and stderr resp.

  You can safely leave outpipe, inpipe & errpipe unspecified (NULL) if you
  want the command to read/write from/to stdin/stdout/stderr. envp could just
  be the environ extern that all C/C++ programs have access to, or it
  could be some filtered version of it. This function doesn't care
  what it is, but the cmd might (it might try to use $HOME for
  example). I don't know if it can be a NULL pointer.  
*/

#define READ_DESC 0
#define WRITE_DESC 1

pid_t forkexec (char **argv, char **envp, 
	        int outpipe[2], 
	        int inpipe[2], 
	        int errpipe[2])

{
	pid_t pid;

	if ((pid = fork ()) == 0) {

		/* In the child process */

		if (inpipe) {
			if (inpipe[READ_DESC] != 0) {
				close (0);
				if (dup (inpipe[READ_DESC]) < 0) {
					return (-1);
				}
			}
			if (inpipe[WRITE_DESC]) {
				close (inpipe[WRITE_DESC]);
			}
		}

		if (outpipe) {
			if (outpipe[WRITE_DESC] != 1) {
				close (1);
				if (dup (outpipe[WRITE_DESC]) < 0) {
					return (-2);
				}
			}
			if (!errpipe) {
				close(2);
				if (dup (outpipe[WRITE_DESC]) < 0) {
					return (-3);
				}
			}
			if (outpipe[READ_DESC]) {
				close (outpipe[READ_DESC]);
			}
		}

		if (errpipe) {
			if (errpipe[WRITE_DESC] != 1) {
				close (2);
				if (dup (errpipe[WRITE_DESC]) < 0) {
					return (-4);
				}
			}
			if (errpipe[READ_DESC]) {
				close (errpipe[READ_DESC]);
			}
		}

		/* do it */

		execvp (argv[0], argv);
		return (-3);
	
	} else if (pid == -1) {
		return (-5);

	} else {
		/* In the parent process */
	
		if (outpipe && outpipe[WRITE_DESC]) {
			close (outpipe[WRITE_DESC]);
			outpipe[WRITE_DESC] = -1;
		}

		if (errpipe && errpipe[WRITE_DESC]) {
			close (errpipe[WRITE_DESC]);
			errpipe[WRITE_DESC] = -1;
		}
	}

	return (pid);
}




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