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.
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: 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) :MSWIN- SPAWN "cmd" "cmd /c findstr \"^\"" 712 732 804 T #.(SB-SYS:INT-SAP #X00000000) T NIL)
(sb-ext:RUN-PROGRAM "cmd" "/c findstr \"^\"" :INPUT #P"c:/cygwin64/
;; It calls:
(SB-WIN32:
;; Without my patch, I can't make it work.
;; This trivial attempt fails with exit code 2, because it doesn't quote enough: 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) :MSWIN- SPAWN "cmd" "cmd /c findstr ^" 852 796 696 T #.(SB-SYS:INT-SAP #X00000000) T NIL)
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "^") :INPUT #P"c:/cygwin64/
(SB-WIN32:
;; This fails with exit code 1, because it quotes too much: 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) :MSWIN- SPAWN "cmd" "cmd /c findstr \"\\\"^\\\"\"" 808 796 780 T #.(SB-SYS:INT-SAP #X00000000) T NIL)
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "\"^\"") :INPUT #P"c:/cygwin64/
(SB-WIN32:
;; Trying to use multiple nested cmd /c to achieve unquoting doesn't obviously work either (exit 1): 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) :MSWIN- SPAWN "cmd" "cmd /c cmd /c \"findstr \\\"^\\\"\"" 808 804 892 T #.(SB-SYS:INT-SAP #X00000000) T NIL)
(sb-ext:RUN-PROGRAM "cmd" '("/c" "cmd" "/c" "findstr \"^\"") :INPUT #P"c:/cygwin64/
(SB-WIN32:
;; 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: 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) :MSWIN- SPAWN "cmd" "cmd /c findstr ^^" 760 1108 968 T #.(SB-SYS:INT-SAP #X00000000) T NIL)
(sb-ext:RUN-PROGRAM "cmd" '("/c" "findstr" "^^") :INPUT #P"c:/cygwin64/
(SB-WIN32:
;; 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.