1 (in-package :lambda-utils
)
4 "Return the value of this environment variable"
5 #+sbcl
(sb-posix:getenv var
)
6 #-sbcl
(error "getenv: Not implemented for this Common Lisp"))
9 (defun find-in-path (prog)
10 "Find prog in system path"
11 (let ((paths (split-sequence #\
: (getenv "PATH"))))
13 (let ((path (make-pathname :directory dir
:name prog
)))
14 (when (probe-file path
)
15 (return-from find-in-path path
))))
16 (error "Program ~a not found in path ~a" prog paths
))) ; TODO: Use cerror here
20 (defun exec-prog-l (prog args
)
21 "Find prog in the path and execute it with args given by a list.
22 Version with args in a list.
23 Example: (exec-prog-l \"echo\" '(\"a\" \"b\")) ==> a b "
24 (run-prog (find-in-path prog
) :args args
))
26 (defun exec-prog (prog &rest args
)
27 "Find prog in the path and execute it with args given by a list
28 Example: (exec-prog \"echo\" \"a\" \"b\") ==> a b "
29 (exec-prog-l prog args
))
31 (defun run-prog (prog &key args
(wait t
) (opts nil
))
32 "Common interface to shell. Does not return anything useful."
33 #+sbcl
(apply #'sb-ext
:run-program prog args
:wait wait
:output
*standard-output
* opts
)
35 (error 'not-implemented
:proc
(list 'run-prog prog opts
)))
37 (defun pipe-output (prog &rest args
)
38 "Return an output stream which will go to the command."
39 #+allegro
(excl:run-shell-command
(format nil
"~a~{ ~a~}" prog args
)
40 :input
:stream
:wait nil
)
41 #+clisp
(#+lisp
=cl ext
:make-pipe-output-stream
42 #-lisp
=cl lisp
:make-pipe-output-stream
43 (format nil
"~a~{ ~a~}" prog args
))
44 #+cmu
(ext:process-input
(ext:run-program prog args
:input
:stream
46 #+gcl
(si::fp-input-stream
(apply #'si
:run-process prog args
))
47 #+lispworks
(sys::open-pipe
(format nil
"~a~{ ~a~}" prog args
)
49 #+lucid
(lcl:run-program prog
:arguments args
:wait nil
:output
:stream
)
50 #+sbcl
(sb-ext:process-input
(sb-ext:run-program prog args
:input
:stream
52 #-
(or allegro clisp cmu gcl lispworks lucid sbcl
)
53 (error 'not-implemented
:proc
(list 'pipe-output prog args
)))
55 (defun pipe-input (prog &rest args
)
56 "Return an input stream from which the command output will be read."
57 #+allegro
(excl:run-shell-command
(format nil
"~a~{ ~a~}" prog args
)
58 :output
:stream
:wait nil
)
59 #+clisp
(#+lisp
=cl ext
:make-pipe-input-stream
60 #-lisp
=cl lisp
:make-pipe-input-stream
61 (format nil
"~a~{ ~a~}" prog args
))
62 #+cmu
(ext:process-output
(ext:run-program prog args
:output
:stream
63 :error t
:input t
:wait nil
))
64 #+gcl
(si::fp-output-stream
(apply #'si
:run-process prog args
))
65 #+lispworks
(sys::open-pipe
(format nil
"~a~{ ~a~}" prog args
)
67 #+lucid
(lcl:run-program prog
:arguments args
:wait nil
:input
:stream
)
68 #+sbcl
(sb-ext:process-output
(sb-ext:run-program prog args
:output
:stream
69 :error t
:input t
:wait nil
))
70 #-
(or allegro clisp cmu gcl lispworks lucid sbcl
)
71 (error 'not-implemented
:proc
(list 'pipe-input prog args
)))
73 ;;; Allegro CL: a simple `close' does NOT get rid of the process.
74 ;;; The right way, of course, is to define a Gray stream `pipe-stream',
75 ;;; define the `close' method and use `with-open-stream'.
76 ;;; Unfortunately, not every implementation supports Gray streams, so we
77 ;;; have to stick with this to further the portability.
79 (defun close-pipe (stream)
80 "Close the pipe stream."
81 (declare (stream stream
))
83 #+allegro
(sys:reap-os-subprocess
))
85 (defmacro with-open-pipe
((pipe open
) &body body
)
86 "Open the pipe, do something, then close it."
88 (declare (stream ,pipe
))
89 (unwind-protect (progn ,@body
)
95 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
96 (set-macro-character #\
] (get-macro-character #\
)))
97 (set-dispatch-macro-character #\
# #\
[
98 (lambda (stream char1 char2
)
99 (declare (ignore char1 char2
))
100 (setf (readtable-case *readtable
*) :preserve
)
102 (let ((command-line (read-delimited-list #\
] stream t
)))
103 `(exec-prog-l ,(princ-to-string (car command-line
))
104 ',(mapcar #'princ-to-string
(rest command-line
))))
105 (setf (readtable-case *readtable
*) :upcase
))))