Comment 4 for bug 1503496

Revision history for this message
Faré (fahree) wrote :

Let's take a trivial Windows scripting example, the equivalent of cat < in > out 2> err,
where the rough equivalent of cat is the internal command findstr "^"
where the caret must be properly quoted.

;; With my patch, you can run this command, that works:
(sb-ext:RUN-PROGRAM "cmd" "/c findstr \"^\"" :INPUT #P"c:/cygwin64/home/fare/in"
                  :OUTPUT #P"c:/cygwin64/home/fare/out" :ERROR
                  #P"c:/cygwin64/home/fare/err" :WAIT T :EXTERNAL-FORMAT :UTF-8 :IF-INPUT-DOES-NOT-EXIST
                  :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-EXISTS :OVERWRITE :SEARCH T)
;; It calls:
(SB-WIN32::MSWIN-SPAWN "cmd" "cmd /c findstr \"^\"" 712 732 804 T #.(SB-SYS:INT-SAP #X00000000) T NIL)

;; Without my patch, I can't make it work.

;; This trivial attempt fails with exit code 2, because it doesn't quote enough:
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "^") :INPUT #P"c:/cygwin64/home/fare/in"
                  :OUTPUT #P"c:/cygwin64/home/fare/out" :ERROR
                  #P"c:/cygwin64/home/fare/err" :WAIT T :EXTERNAL-FORMAT :UTF-8 :IF-INPUT-DOES-NOT-EXIST
                  :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-EXISTS :OVERWRITE :SEARCH T)
(SB-WIN32::MSWIN-SPAWN "cmd" "cmd /c findstr ^" 852 796 696 T #.(SB-SYS:INT-SAP #X00000000) T NIL)

;; This fails with exit code 1, because it quotes too much:
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "\"^\"") :INPUT #P"c:/cygwin64/home/fare/in"
                  :OUTPUT #P"c:/cygwin64/home/fare/out" :ERROR
                  #P"c:/cygwin64/home/fare/err" :WAIT T :EXTERNAL-FORMAT :UTF-8 :IF-INPUT-DOES-NOT-EXIST
                  :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-EXISTS :OVERWRITE :SEARCH T)
(SB-WIN32::MSWIN-SPAWN "cmd" "cmd /c findstr \"\\\"^\\\"\"" 808 796 780 T #.(SB-SYS:INT-SAP #X00000000) T NIL)

;; Trying to use multiple nested cmd /c to achieve unquoting doesn't obviously work either (exit 1):
(sb-ext:RUN-PROGRAM "cmd" '("/c" "cmd" "/c" "findstr \"^\"") :INPUT #P"c:/cygwin64/home/fare/in"
                  :OUTPUT #P"c:/cygwin64/home/fare/out" :ERROR
                  #P"c:/cygwin64/home/fare/err" :WAIT T :EXTERNAL-FORMAT :UTF-8 :IF-INPUT-DOES-NOT-EXIST
                  :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-EXISTS :OVERWRITE :SEARCH T)
(SB-WIN32::MSWIN-SPAWN "cmd" "cmd /c cmd /c \"findstr \\\"^\\\"\"" 808 804 892 T #.(SB-SYS:INT-SAP #X00000000) T NIL)

;; In this particular case, I can finesse cmd because the character to be quoted was the ^, which is a shell escape character like \ in Unix shell:
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "^^") :INPUT #P"c:/cygwin64/home/fare/in"
                  :OUTPUT #P"c:/cygwin64/home/fare/out" :ERROR
                  #P"c:/cygwin64/home/fare/err" :WAIT T :EXTERNAL-FORMAT :UTF-8 :IF-INPUT-DOES-NOT-EXIST
                  :ERROR :IF-OUTPUT-EXISTS :OVERWRITE :IF-ERROR-EXISTS :OVERWRITE :SEARCH T)
(SB-WIN32::MSWIN-SPAWN "cmd" "cmd /c findstr ^^" 760 1108 968 T #.(SB-SYS:INT-SAP #X00000000) T NIL)

;; But what if you want to run an arbitrary command, wit carets and quotes, etc.? Maybe someone can write a clever quoting algorithm just to overcome this SBCL hurdle. Or SBCL can get a pass-thru mode.