leftmike / foment

Foment is an implementation of R7RS Scheme.
MIT License
67 stars 4 forks source link

No way to call external programs -- and pipe into/from them? #33

Closed jpellegrini closed 4 years ago

jpellegrini commented 4 years ago

Hello,

I see that currently Foment has no support for executing external binaries and piping data into or from them. It would benice if we could, for example, do this (the with-input-from-pipe procedure below is Chicken-specific):

(with-input-from-pipe
      "iptables -L"
    (lambda ()
      (read-string #f))))

I do not know how difficult it would be to implement this portably in Foment.

leftmike commented 4 years ago

This looks interesting; let me see what I can do. I see that Chicken has a processes module and Chibi has a processes module.

Do you have a preference for a particular API?

jpellegrini commented 4 years ago

This looks interesting; let me see what I can do. I see that Chicken has a processes module and Chibi has a processes module.

Do you have a preference for a particular API?

I see that there is no SRFI for that. Perhaps it would be nice to have part of Chicken's API -- not necessarily all of it? For example,

    process-execute
    process-fork
    process-run
    process-signal
    process-wait
    process-sleep
    process
    process*

but not create-session. Or maybe a subset of the above. What do you think?

The Chibi API doesn't seem too different, conceptually...

leftmike commented 4 years ago

After implementing part of Chicken's API, I decided to use Racket's Processes API instead. I found it to be cleaner and much more platform agnostic. It should be possible to implement the process convenience procedures (eg. with-input-from-pipe) on top of it.

I have done an initial implementation of the subprocess APIs on the processes branch for Mac OSX if you are interested in taking a look.

(call-with-values
    (lambda () (subprocess #f #f 'stdout "/bin/ls" "-lh"))
    (lambda (sub in out err)
        (define (read-all port)
            (let ((s (read-line port)))
                (if (not (eof-object? s))
                    (begin
                        (display s)
                        (newline)
                        (read-all port)))))
        (read-all in)))
jpellegrini commented 4 years ago

That's great!

I compiled it on Linux, BTW, and it worked on a x86 desktop. The only changes necessary were these three lines

#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

inside the #ifdef FOMENT_UNIX block.

Will compile and test on a MIPS machine soon.

jpellegrini commented 4 years ago

The only changes necessary were these three lines

#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

inside the #ifdef FOMENT_UNIX block.

I meant in process.cpp, of course...

leftmike commented 4 years ago

The Processes API is done for Linux and Mac OS. I still need to implement support for Windows.

The code is on the processes branch; I will merge it into master once I have Windows support done.

As part of testing the code, I did sample implementations of call-with-input-pipe, call-with-output-pipe, with-input-from-pipe, and with-output-to-pipe.

jpellegrini commented 4 years ago

Thank you! Foment now will work fine as a scripting language!

leftmike commented 4 years ago

Windows is done as well; Processes API has been merged into the master branch.