diff --git i/lisp/subr.el w/lisp/subr.el index e9e19d3..1d7d0dd 100644 --- i/lisp/subr.el +++ w/lisp/subr.el @@ -2753,15 +2753,31 @@ shell-quote-argument "\\1\\1\\\\\"" argument))) - (if (string-match "[%!\"]" argument) - (concat - "^\"" - (replace-regexp-in-string - "\\([%!()\"<>&|^]\\)" - "^\\1" - argument) - "^\"") - (concat "\"" argument "\""))) + ;; cmd.exe performs %var% expansion before anything else, so there + ;; is no way escape '%'s (escaping with '^' *appears* to work, but + ;; that's only because variables with carets in the name are + ;; rare). If "Command Extensions" are enabled, it's possible to + ;; work around this limitation by appending "%CD:~,0%" to each + ;; '%'; it expands to the empty string and stops the preceding '%' + ;; from being interpreted as the beginning of a variable name. + (cond + ((and w32-shell-command-extensions (string-match "%" argument)) + (concat + "^\"" + (replace-regexp-in-string + "\\([!()\"<>&|^]\\)" + "^\\1" + (replace-regexp-in-string "%" "%%CD:~,0%" argument t t)) + "^\"")) + ((string-match "[%!\"]" argument) + (concat + "^\"" + (replace-regexp-in-string + "\\([%!()\"<>&|^]\\)" + "^\\1" + argument) + "^\"")) + (t (concat "\"" argument "\"")))) (t (if (equal argument "") diff --git i/lisp/w32-vars.el w/lisp/w32-vars.el index c9317e4..3e76a86 100644 --- i/lisp/w32-vars.el +++ w/lisp/w32-vars.el @@ -65,6 +65,13 @@ w32-list-proportional-fonts :type '(repeat string) :group 'w32)) +(unless (eq system-type 'cygwin) + (defcustom w32-shell-command-extensions nil ;; (equal (shell-command-to-string "echo %%CD:~,0%") "%\n") + "If non-nil, assume the shell supports \"Command Extensions\". +This is used by `shell-quote-argument' to safely escape \"%\"." + :type 'boolean + :group 'w32)) + ;; Want "menu" custom type for this. (defcustom w32-fixed-font-alist '("Font menu"