This is the mail archive of the guile@sourceware.cygnus.com mailing list for the Guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: popen behavior - interactive processes


> Date: Tue, 21 Mar 2000 18:57:02 -0500
> From: Allister MacLeod <listopad@mv3d.com>
> 
> How come (ice-9 popen) only does one-way pipes?  I'm interested in
> using the guile interpreter as a replacement for expect/Tcl, so I'd
> like to be able to set up a background process with ports for both
> input and output (or possibly a bidirectional port, if such a thing
> exists)

The current situation is more or less:

The popen module is a stop-gap measure: it emulates C stdio facilities
which were previously (together with "system") the only relatively
high-level facilities in guile-core for running other processes.  The
C stdio support went away when Guile stopped using C stdio.

It's not a good interface because a) it uses /bin/sh, which introduces
overhead and unwanted Bourne Shell syntax.  b) it hides away the
process pid so that close-pipe can return the status, but the process
can also be closed with close-port.  this makes cleanup messy -- it
actually installs a hook that gets run at every garbage collection.
c) it can't do bidirectional pipes.

There is existing code that solves these problems, although buried
in larger, external modules, and possibly requiring minor updating for
the latest Guile: guile-scsh and goosh from ftp.red-bean.com (also, 
people do reimplement it every so often).

Bidirectional ports are supported,
(open-file "lkjdf" "w+") for example.

The problem with running interactive processes like /bin/sh is they
often want to interact over a pty, not a pipe.  guile-core doesn't
currently have pty support (an old version guile-iii, circa 1995, 
did have it, based on Emacs code.  greg, from ftp.gnu.org,
has added pty support for its own purposes.

If that's the problem, perhaps running /bin/sh with additional options
would allow it to interact over a pipe, e.g., -i.

> So, I've been able to get close to what I want by looking at popen.scm
> and modifying it a little.. something like
> 
> (define (open-two-way)
>   (define (pipe-nobuf) (let ((p (pipe))) (setvbuf (cdr p) _IONBF) p))
>   (define (shutoff in out) (map close-port (list (cdr in) (car out))))
>   (let ((c2p (pipe-nobuf)) (p2c (pipe-nobuf)))
>     (let ((pid (primitive-fork)))
>       (cond ((= pid 0)
>              (set-batch-mode?! #t) ;blindly copied from popen.scm
> 	     (shutoff p2c c2p)
> 	     (let loop ((x (read-char (car p2c))))
> 	       (write-char (if (char=? x #\space) #\. x) (cdr c2p))
> 	       (loop (read-char (car p2c)))))
>             (else
> 	     (shutoff c2p p2c)
> 	     (cons (cons (car c2p) (cdr p2c)) pid))))))
> 
> This works just fine..  I can feed in characters and they come out the
> same except for spaces which turn into dots.  What I can't figure out
> how to do is make the same thing work with a couple of move->fdes
> calls and an execle instead of the loop (which, btw, is there a better
> way to write that kind of loop whose argument is always the same
> expression?)
> I just keep ending up with zombies to feed to waitpid.  Maybe I'm
> misunderstanding the way move->fdes works, but when I replace the loop
> with : 
> 
> (move->fdes (car p2c) 0)
> (move->fdes (cdr c2p) 1)
> (apply execlp "/bin/sh" "/bin/sh" ())
> 
> sh seems to die before writing any characters to the port.  On the
> other hand, when I substitute /bin/date for /bin/sh, I'm able to pull
> characters from it.
> 
> I guess the real question is, am I even looking in the right place?
> Is it conceivable that an interactive process can be spawned this way?
> If not, is there some other way that's better?
> 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]