■ MinGW版 Emacs 特有の設定
【お知らせ】
<2015/04/01 追記>
SJIS のダメ文字対策が行われていない NTEmacs(恐らくですが、gnupack 以外の ほとんどの NTEmacs)の対策を追加しました。
<2015/03/09 追記>
locale-coding-system の設定を追加しました。
【本題】
NTEmacs から外部プロセスへ引数として渡せる文字列はコードページ(日本語Windows の場合は cp932)に依存するのだそうです。しかし一方で、プログラム引数の coding-system は process-coding-system の「プロセスへの符号化設定」の値と同じものに設定されるため、LANG環境変数を ja_JP.UTF-8 にして process-coding-system の「プロセスへの符号化設定」の値を utf-8 に合わせると、漢字を引数に含むプログラムを正しく動かすことができません。
以下は、この問題を改善するための設定です。
(require 'cl-lib)
(setenv "LANG" "ja_JP.UTF-8")
;; IME の設定をした後には実行しないこと
;; (set-language-environment "Japanese")
(prefer-coding-system 'utf-8-unix)
(set-file-name-coding-system 'cp932)
(setq locale-coding-system 'utf-8-unix)
;; プロセスが出力する文字コードを判定して、process-coding-system の DECODING の設定値を決定する
(setq default-process-coding-system '(undecided-dos . utf-8-unix))
;; サブプロセスに渡すパラメータの文字コードを cp932 にする
(cl-loop for (func args-pos) in '((call-process 4)
(call-process-region 6)
(start-process 3))
do (eval `(advice-add ',func
:around (lambda (orig-fun &rest args)
(setf (nthcdr ,args-pos args)
(mapcar (lambda (arg)
(if (multibyte-string-p arg)
(encode-coding-string arg 'cp932)
arg))
(nthcdr ,args-pos args)))
(apply orig-fun args))
'((depth . 99)))))
さらに以下は、SJIS のダメ文字対策も含めた設定です。SJIS のダメ文字対策が必要な場合(恐らくですが、gnupack 以外の ほとんどの MinGW版 Emacs は未対策)は、上記の設定の代わりに以下の設定の利用を検討ください。
NTEmacsスレッド4 967、NTEmacsスレッド5 33 の投稿を基とした設定であり、次のページの設定を全面的に参考とさせていただきました。(というかほとんどそのままです..m_O_m)
なお、Emacs 本体のクオート処理関連プログラムは次のページにあります。
また、Windows プログラムの場合のクオートの仕様は次のページが参考となります。
(require 'cl-lib)
(setenv "LANG" "ja_JP.UTF-8")
;; IME の設定をした後には実行しないこと
;; (set-language-environment 'Japanese)
(prefer-coding-system 'utf-8-unix)
(set-file-name-coding-system 'cp932)
(setq locale-coding-system 'utf-8)
;; プロセスが出力する文字コードを判定して、process-coding-system の DECODING の設定値を決定する
(setq default-process-coding-system '(undecided-dos . utf-8-unix))
;; ldd の結果のキャッシュ
(defvar ldd-cache nil)
;; filename が Cygwin のプログラムかどうか判定する
(defun cygwin-program-p (filename)
(let ((target (and filename (executable-find filename))))
(when target
(cdr (or (assoc target ldd-cache)
(car (push (cons target
(with-temp-buffer
(let ((w32-quote-process-args nil)) ; advice 中で再帰しないよう nil
;; Cygwin のライブラリをロードしているか判定
(when (eq (call-process "ldd" nil t nil (concat "\"" target "\"")) 0)
(goto-char (point-min))
(number-or-marker-p
(re-search-forward "cygwin[0-9]+\.dll" nil t))))))
ldd-cache)))))))
;; サブプロセスに渡すパラメータに SJIS のダメ文字対策を行い、さらに文字コードを cp932 にする
(defun convert-process-args (orig-fun prog-pos args-pos args)
(let ((cygwin-quote (and w32-quote-process-args ; cygwin-program-p の再帰防止
(cygwin-program-p (nth prog-pos args)))))
(setf (nthcdr args-pos args)
(mapcar (lambda (arg)
(when w32-quote-process-args
(setq arg
(concat "\""
(if cygwin-quote
(replace-regexp-in-string "[\"\\\\]"
"\\\\\\&"
arg)
(replace-regexp-in-string "\\(\\(\\\\\\)*\\)\\(\"\\)"
"\\1\\1\\\\\\3"
arg))
"\"")))
(if (multibyte-string-p arg)
(encode-coding-string arg 'cp932)
arg))
(nthcdr args-pos args))))
(let ((w32-quote-process-args nil))
(apply orig-fun args)))
(cl-loop for (func prog-pos args-pos) in '((call-process 0 4)
(call-process-region 2 6)
(start-process 2 3))
do (eval `(advice-add ',func
:around (lambda (orig-fun &rest args)
(convert-process-args orig-fun
,prog-pos ,args-pos
args))
'((depth . 99)))))
<変更履歴>
- 2012/09/19 mapcar の Warning が出るのを対策した。(http://www.mew.org/~kazu/doc/elisp/function.html)
- 2012/12/27 lambda関数のクォートをとった。
- 2013/01/08 set-process-args-coding-system から引数の存在チェックを削除した。
- 2015/03/09 locale-coding-system の設定を追加した。
- 2015/04/01 SJIS のダメ文字対策が行われていない NTEmacs(恐らくですが、gnupack 以外の ほとんどの NTEmacs)の対策を追加した。
- 2015/09/09 advice を Emacs-24.4 以降の書式に見直した。
- 2015/10/17 advice-add の depth の設定に 99 を設定した。
最終更新:2019年11月03日 19:32