For example if we want to use unix cat
(1) without starting a shell as an echo server.
#|
(setq inferior-lisp-program "ecl")
(slime)
(setq eepitch-buffer-name "*slime-repl ECL*")
|#
ext:run-program "cat" '() :wait nil
in so many words.
(locally
(declare (special *2way* *exit* *proc*))
(multiple-value-setq
(*2way* *exit* *proc*)
(ext:run-program "cat" '() :wait nil)))
We need to preserve the process to interactively ext:external-process-wait
for it to finish when we close it.
I always find this confusing, but it is clearly correct.
(two-way-stream-output-stream *2way*)
(print "This is only a
test" *)
And let’s read-line
from that:
(two-way-stream-input-stream *2way*)
(read-line *) ; ⮕ ""
(read-line **) ; ⮕ ""This is only a"
(read-line ***) ; ⮕ (waits for stream) C-c C-c ABORT <ret>
Note that the cat
(1) survives us interactively aborting read-line
in lisp. However, partially reading that line loses us the characters for next time we try to read. Instead
read-char-no-hang
instead(two-way-stream-output-stream *2way*)
(print "foo
bar
baz
" *)
(two-way-stream-input-stream *2way*)
(loop :for ch := (read-char-no-hang *)
:while ch
:collect ch :into chars
:finally (return (coerce chars 'string)))
#|
"
"foo
bar
baz
""
|#
as we may have expected (I had a stray newline from before).
(ext:terminate-process *proc*)
(ext:external-process-wait *proc*)
(multiple-value-setq
(*2way* *exit* *proc*)
(values))
ext:terminate-process
and ext:external-process-wait
So an embeddable common lisp ext:external-process
running cat
(1) functions as a kind of in-memory echo server.
I have always tended to use embeddable common lisp’s multiprocessing and external-process extensions directly when available. They are meant to be similar to lisp machine useages, which I imagine is preserved across compilers. Technically I guess ‘semi-portable’ uiop:launch-program
is going to work the same, except arguements to the program are written into the program’s invocation as though one was using a shell (which we are not) instead of ecl’s list of flags. Confusingly uiop:run-program
is reserved for syncronous external processes.
I kind of want to use embeddable common lisp anyway, because my insane fairy kitten godmother idea is to arbitrarily transform all C++ programs into kittens.
Well, how do you like to use external processes in common lisp - in the mastodon thread.
Please do share this embeddable common lisp example however occurs to you and in whatever way. Since I sometimes stumble around here when I have forgotten how to use arbitrary external programs from inside my lisp image like this, so I imagine you might find it helpful.
screwlisp proposes kittens