[slime-devel] Handling ^M and ^H characters output from ext:run-program?

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. -- LOOP :: a Domain Specific Language.

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. -- [ingvar] Modelling forest damage by storms with regular expressions is... a curious idea. [Xach] before: ||| after: //_ [Xach] seems easy enough to me

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. -- [ingvar] Modelling forest damage by storms with regular expressions is... a curious idea. [Xach] before: ||| after: //_ [Xach] seems easy enough to me

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. -- [ingvar] Modelling forest damage by storms with regular expressions is... a curious idea. [Xach] before: ||| after: //_ [Xach] seems easy enough to me
participants (3)
-
Edi Weitz
-
GP lisper
-
Jeff Cunningham