On Tue, May 13, 2003 at 09:48:53AM +0900, Simon Strandgaard wrote:
> I want users of the editor to be able to use thier own favorite ruby
> snippets within the editor... *unmodified* ...they don't have to do popen
> or Open3 or other ackward things for executing their favorite scripts.
> All Ruby output should go to a text-buffer.

You mean like irb?

Maybe you should have a look at the source for FreeRIDE and see how it
handles this. I haven't installed it, but it sounds like exactly the sort of
integrated environment you're talking about, so they must have dealt with
the problem you have encountered.

> > In the general
> > case, this is simply not possible whilst the Sandbox is in the same process
> > as you, because it shares fd0/1/2 with the the main program (because both
> > Ruby and C *are* part of the same program), and therefore the program has a
> > way to write to fd0/1/2.
> 
> Not agree.. I think this *is* possible. 
> Everytime Ruby spawns a child it should do like this:
> 
> void system(command) {
>     pid=fork();
>     if(pid != 0) {
>          stdout = rb_stdout;  /* what im asking for */
>          stderr = rb_stderr;  /* what im asking for */
>          stdin = rb_stdin;    /* what im asking for */
>          execv(command);
>     }
> }

What you have written cannot work:
1. stdout is a malloc'd FILE* object in the parent's memory space, which is
   destroyed immediately on exec. You need to modify the file descriptor
   table using dup2() instead
2. rb_stdout is a VALUE and stdout is a FILE* anyway. Two different things.
3. the file descriptor table holds Unix file descriptors. It cannot point
   to a Ruby object. If rb_stdout were a StringIO object, you could not
   possibly insert it into the FD table. You would have to put three pipes
   into the FD table instead, and the parent would talk down them. Or else
   a temporary file.

But anyway, I wrote "in the general case", not "in the specific case of
system() and backtick"

In the general case, your Ruby program could do lots of things which force
a direct output to stdout/stderr. Here is one small valid Ruby program:

        pid = fork do
          exec("ls /nonexistent")
        end
        Process.waitpid(pid)

How are you going to modify Ruby so that the output of those four lines are
captured in the sandbox?

Another example would be

        require 'ext/someobj'
        a = Someobj.new.dosomething

where ext/someobj is a C extension which writes directly to stdout. If your
editor environment is going to be general-purpose then it better handle that
case too.

Modifying certain Ruby commands like 'system' is not the solution to the
general problem.

> OK.. again assignment to stdout is illegal. freopen should be used instead.
> Admitted.. I havn't yet tried reopen'ing stdout/stderr :-)

freopen only lets you associate the FD with a file.

It would certainly be possible to do
        STDOUT.reopen("/tmp/capture.out")

before calling the snippet you are interested in. Then you can close it and
read the file.

This sounds like it might be a good solution for your particular problem
domain (i.e. an environment for running Ruby interactively). Of course you
lose the STDOUT/STDERR given to the main program when it started, so it had
better be a graphical environment.

But that solution is specific to your problem. I don't think it warrants a
modification to Ruby, the general-purpose programming language, itself.

Cheers,

Brian.