I posted the following question on comp.lang.lisp:
I have this code embedded in a process I'm running:
(ext:process-exit-code (ext:run-program "cdrecord" args :output *standard-output*)))
and it works fine, except that the cdrecord utility (and many others) uses both backspace ^H and carriage return ^M to write updates to the screen. This makes a big mess in the slime-repl window ,as they aren't properly interpreted and so stuff spews out for miles before it finishes.
Is there a way to capture these characters before they hit *standard-output* and interpete them so they either work correctly or are at least benign (i.e. convert carriage return to a linefeed, and any sequence of backspaces ^H^H^H^H^H^H^H with a linefeed)?
One of the respondents pointed out that:
"*STANDARD-OUTPUT* is bound to some Lisp stream maintained by SLIME, attached to an Emacs buffer. cdrecord was not designed to attach to an Emacs buffer, or to anything other than a terminal (or some program which emulates a terminal by understandin the control codes for moving your cursor around"
Is there a way to still embed this program call within my lisp project so I can still run it in slime without this behavior?
Thanks
--Jeff Cunningham
On Fri, 15 Jul 2005 04:33:26 -0700, jeffrey@cunningham.net wrote:
"*STANDARD-OUTPUT* is bound to some Lisp stream maintained by SLIME, attached to an Emacs buffer. cdrecord was not designed to attach to an Emacs buffer, or to anything other than a terminal (or some program which emulates a terminal by understandin the control codes for moving your cursor around"
Is there a way to still embed this program call within my lisp project so I can still run it in slime without this behavior?
a) Check cdrecord options for a 'quiet' mode, where only the bare minimum is printed. Never used it myself, but ^H^H^H^H sounds like an updating bar graphic designed to display progress. You don't need it.
b) expand your external system call to include a pipe into a filter.
c) did someone suggest CL-PPCRE (same as 'b actually)?
I've done something similar with NGREP, but I also hacked it's source code to get what I wanted. CDRECORD might be clean enough for you to do that too.
On Fri Jul 15, 2005 at 02:01:45PM -0700, GP lisper wrote:
On Fri, 15 Jul 2005 04:33:26 -0700, jeffrey@cunningham.net wrote:
"*STANDARD-OUTPUT* is bound to some Lisp stream maintained by SLIME, attached to an Emacs buffer. cdrecord was not designed to attach to an Emacs buffer, or to anything other than a terminal (or some program which emulates a terminal by understandin the control codes for moving your cursor around"
Is there a way to still embed this program call within my lisp project so I can still run it in slime without this behavior?
a) Check cdrecord options for a 'quiet' mode, where only the bare minimum is printed. Never used it myself, but ^H^H^H^H sounds like an updating bar graphic designed to display progress. You don't need it.
b) expand your external system call to include a pipe into a filter.
c) did someone suggest CL-PPCRE (same as 'b actually)?
I've done something similar with NGREP, but I also hacked it's source code to get what I wanted. CDRECORD might be clean enough for you to do that too.
I'll play with the verbosity - don't know why I didn't think of that. I thought of hacking the source, but don't really want to have to do it everytime I update cdrecord.
I've had trouble getting shell commands to run with ext:run-program under CMUCL, so that avenue might be difficult.
I guess I don't understand (c). I use cl-ppcre all the time but how would I capture *standard-output* from cdrecord and pipe it through regex match?
--Jeff
On Fri, 15 Jul 2005 14:44:44 -0700, Jeff Cunningham jeffrey@cunningham.net wrote:
I've had trouble getting shell commands to run with ext:run-program under CMUCL, so that avenue might be difficult.
What trouble? Did you call it in such a way that sh(1) was the external program or did you try to call the shell script directly?
Cheers, Edi.
On Fri, 15 Jul 2005 14:44:44 -0700, jeffrey@cunningham.net wrote:
On Fri Jul 15, 2005 at 02:01:45PM -0700, GP lisper wrote:
On Fri, 15 Jul 2005 04:33:26 -0700, jeffrey@cunningham.net wrote:
"*STANDARD-OUTPUT* is bound to some Lisp stream maintained by SLIME, attached to an Emacs buffer. cdrecord was not designed to attach to an Emacs buffer, or to anything other than a terminal (or some program which emulates a terminal by understandin the control codes for moving your cursor around"
Is there a way to still embed this program call within my lisp project so I can still run it in slime without this behavior?
a) Check cdrecord options for a 'quiet' mode, where only the bare minimum is printed. Never used it myself, but ^H^H^H^H sounds like an updating bar graphic designed to display progress. You don't need it.
b) expand your external system call to include a pipe into a filter.
c) did someone suggest CL-PPCRE (same as 'b actually)?
I've done something similar with NGREP, but I also hacked it's source code to get what I wanted. CDRECORD might be clean enough for you to do that too.
I'll play with the verbosity - don't know why I didn't think of that. I thought of hacking the source, but don't really want to have to do it everytime I update cdrecord.
man diff man patch
I guess I don't understand (c). I use cl-ppcre all the time but how would I capture *standard-output* from cdrecord and pipe it through regex match?
Read manual.
(with-open-stream (rip (ext:process-output (ext:run-program "cdrecord" '("-blah" "-foo=" "fie") :output :stream :wait nil :error nil)))
You might want a different :wait option.
On Fri Jul 15, 2005 at 10:13:27PM -0700, GP lisper wrote:
... Read manual.
(with-open-stream (rip (ext:process-output (ext:run-program "cdrecord" '("-blah" "-foo=" "fie") :output :stream :wait nil :error nil)))
You might want a different :wait option.
I can't figure out how to access anything from the rip input-stream. I *have* read the manuals. It seems like this should work:
(with-open-stream (rip (ext:process-output (ext:run-program "cdrdao" `("read-test" "-v" "1" "--device" ,*burner-scsi-id* ,tocfile) :output :stream :wait nil :error t))) (do ((line (read-line rip nil 'eof) (read-line rip nil 'eof))) ((eql line 'eof)) (format t "~a~%" line)))
But it executes without producing any output. Any ideas?
--Jeff
On Sat, 16 Jul 2005 07:37:33 -0700, jeffrey@cunningham.net wrote:
On Fri Jul 15, 2005 at 10:13:27PM -0700, GP lisper wrote:
... Read manual.
(with-open-stream (rip (ext:process-output (ext:run-program "cdrecord" '("-blah" "-foo=" "fie") :output :stream :wait nil :error nil)))
You might want a different :wait option.
I can't figure out how to access anything from the rip input-stream. I *have* read the manuals. It seems like this should work:
(with-open-stream (rip (ext:process-output (ext:run-program "cdrdao" `("read-test" "-v" "1" "--device"
This needs to be a list, I'm not up enough on backtick tricks to know if it is. Double check in the process list (something similar to "top -c" with a fast rep rate) that the proper arguments appear.
,*burner-scsi-id* ,tocfile) :output :stream :wait nil :error t)))
(when rip (loop for line = (read-line rip nil) while line do (format t "~a~%" line)) (close rip)))
Is ~ what I use daily. I built it up playing in the REPL.
On Sat Jul 16, 2005 at 10:24:08AM -0700, GP lisper wrote:
(with-open-stream (rip (ext:process-output (ext:run-program "cdrdao" `("read-test" "-v" "1" "--device"
This needs to be a list, I'm not up enough on backtick tricks to know if it is. Double check in the process list (something similar to "top -c" with a fast rep rate) that the proper arguments appear.
,*burner-scsi-id* ,tocfile) :output :stream :wait nil :error t)))
(when rip (loop for line = (read-line rip nil) while line do (format t "~a~%" line)) (close rip)))
Is ~ what I use daily. I built it up playing in the REPL.
It is a list. The command runs fine, its just filtering its output which is problematic. Here's the only thing I've been able to make work even remotely the way I want it to:
(let ((rip (ext:process-output (ext:run-program "cdrdao" '("read-test" "-v" "1" "--device" "0,6,0" "p7.toc") :output :stream :wait nil :error t)))) (do ((line (read-line rip nil 'done) (read-line rip nil 'done))) ((eql line 'eof)) (let ((progress (scan-to-strings "^Read \d+ of \d+ MB." line))) (if progress (format t "~a~%" progress) (format t "~a~%" (subseq line 0 (1- (length line))))))))
This works - except that there's no graceful exit out of the do loop - it results in the following:
Cdrdao version 1.1.9 - (C) Andreas Mueller andreas@daneb.de
Starting read test... Writing track 01 (mode AUDIO/AUDIO )... Read 0 of 547 MB. Read 36 of 547 MB. Read 104 of 547 MB. Read 264 of 547 MB. Read 341 of 547 MB. Read 418 of 547 MB. Read 244218 blocks.
; Compilation unit aborted.
(After I kill the process in the *slime-repl*):
Type-error in KERNEL::OBJECT-NOT-TYPE-ERROR-HANDLER: DONE is not of type SEQUENCE [Condition of type TYPE-ERROR]
Restarts: 0: [ABORT] Abort SLIME compilation. 1: [ABORT-READ] Abort reading input from Emacs. 2: [ABORT] Abort SLIME compilation. 3: [ABORT] Abort handling SLIME request. 4: [ABORT] Return to Top-Level.
Backtrace: 0: (LENGTH 1 DONE)[:EXTERNAL] 1: (SCAN-TO-STRINGS #<#1=unavailable-arg> #<#1#> :START #<#1#> ...) 2: ("Top-Level Form")[:TOP-LEVEL]
There must be some way to exit that loop gracefully. I tried the loop construct suggested:
(when rip (loop for line = (read-line rip nil) while line do (format t "~a~%" line)) (close rip)))
but couldn't get it to work at all. In any event, why would you need to close rip? Isn't it handled automatically by the 'with-open-stream function?
--Jeff
On Sat, 16 Jul 2005 13:36:30 -0700, jeffrey@cunningham.net wrote:
but couldn't get it to work at all. In any event, why would you need to close rip? Isn't it handled automatically by the 'with-open-stream function?
Probably leftover deadwood from the version without 'with-open-stream'. As I mentioned, I built that up, in your case that might have clued you in faster that *stderror* had what you needed, e.g. you can skip the loop and just look for a single line, etc.