diff options
| author | Daniel Colascione <dan.colascione@gmail.com> | 2011-04-26 03:44:03 -0700 |
|---|---|---|
| committer | Daniel Colascione <dan.colascione@gmail.com> | 2011-04-26 03:44:03 -0700 |
| commit | 8f91bf934523d47a9f57919733d6093b2484e284 (patch) | |
| tree | 788b096654044dcd66966c7d12a78e89610270fd /lisp/subr.el | |
| parent | 0c6b7b19e52ba18b5d4fd2d4b73b133a0a721603 (diff) | |
| download | emacs-8f91bf934523d47a9f57919733d6093b2484e284.tar.gz | |
Improve Windows quoting robustness
Diffstat (limited to 'lisp/subr.el')
| -rw-r--r-- | lisp/subr.el | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/lisp/subr.el b/lisp/subr.el index cb1fdb7f608..2b6a5404060 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2505,27 +2505,63 @@ Note: :data and :device are currently not supported on Windows." (defun shell-quote-argument (argument) "Quote ARGUMENT for passing as argument to an inferior shell." - (if (or (eq system-type 'ms-dos) - (and (eq system-type 'windows-nt) (w32-shell-dos-semantics))) - ;; Quote using double quotes, but escape any existing quotes in - ;; the argument with backslashes. - (let ((result "") - (start 0) - end) - (if (or (null (string-match "[^\"]" argument)) - (< (match-end 0) (length argument))) - (while (string-match "[\"]" argument start) - (setq end (match-beginning 0) - result (concat result (substring argument start end) - "\\" (substring argument end (1+ end))) - start (1+ end)))) - (concat "\"" result (substring argument start) "\"")) + (cond + ((eq system-type 'ms-dos) + ;; Quote using double quotes, but escape any existing quotes in + ;; the argument with backslashes. + (let ((result "") + (start 0) + end) + (if (or (null (string-match "[^\"]" argument)) + (< (match-end 0) (length argument))) + (while (string-match "[\"]" argument start) + (setq end (match-beginning 0) + result (concat result (substring argument start end) + "\\" (substring argument end (1+ end))) + start (1+ end)))) + (concat "\"" result (substring argument start) "\""))) + + ((and (eq system-type 'windows-nt) (w32-shell-dos-semantics)) + + ;; First, quote argument so that CommandLineToArgvW will + ;; understand it. See + ;; http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx + ;; After we perform that level of quoting, escape shell + ;; metacharacters so that cmd won't mangle our argument. If the + ;; argument contains no double quote characters, we can just + ;; surround it with double quotes. Otherwise, we need to prefix + ;; each shell metacharacter with a caret. + + (setq argument + ;; escape backslashes at end of string + (replace-regexp-in-string + "\\(\\\\*\\)$" + "\\1\\1" + ;; escape backslashes and quotes in string body + (replace-regexp-in-string + "\\(\\\\*\\)\"" + "\\1\\1\\\\\"" + argument))) + + (if (string-match "\"" argument) + (concat + "^\"" + (replace-regexp-in-string + "\\([%!()\"<>&|^]\\)" + "^\\1" + argument) + "^\"") + (concat "\"" argument "\""))) + + (t (if (equal argument "") "''" ;; Quote everything except POSIX filename characters. ;; This should be safe enough even for really weird shells. - (replace-regexp-in-string "\n" "'\n'" - (replace-regexp-in-string "[^-0-9a-zA-Z_./\n]" "\\\\\\&" argument))))) + (replace-regexp-in-string + "\n" "'\n'" + (replace-regexp-in-string "[^-0-9a-zA-Z_./\n]" "\\\\\\&" argument)))) + )) (defun string-or-null-p (object) "Return t if OBJECT is a string or nil. |
