バックアップファイルの拡張子を正しく返すパッチ

設定ファイル .emacs は肥大化しがちなので、設定ごとにファイルを分割して .emacs.d ディレクトリに放り込むことにした。こうすればメンテナンスの効率がいいし、起動時にエラーが走っても *Messsage* バッファでどのファイルを読み込んだ場合か確認できる。

分割した設定ファイル群を読み込むため .emacs で以下のような関数を呼び出すことにしたのだが、これだとバックアップファイル ".el~" も読み込んでしまうことに気づいた。原因は file.el の関数 file-name-extension が ~ のついたファイル名の拡張子を正しく返してくれないことだった。

(defun my-load-directory-files (dir)
  (let ((wd (getenv "PWD"))(file)(filelist (directory-files dir)))
    (cd dir)
    (while filelist
      (setq file (car filelist))
      (if (not (file-directory-p file))
	  (if (equal (file-name-extension file) "el")
	      (load-file file)))
      (setq filelist (cdr filelist)))
    (cd wd)))

実際は file-name-extension が内部で使用している低レベル関数 file-name-sans-versions の使い方に問題があるようだ。この低レベル関数はしっかりとそのへんを考慮した作りで optional 引数を与えることで切り替えができるようなインタフェイスを持っているのにそれを利用していないのが実にもったいない。(^-^;

ということで、file-name-extension の改善版パッチを作ってみた。今まで関数を使っている人が困らないよう旧版とのインタフェイスを生かしつつ、低レベル関数 file-name-sans-version に渡せるよう optional で引数をひとつ追加している。

[PATCH] Suggestion about a minor change of `file-name-extension' for backup filenames
http://groups.google.com/group/gnu.emacs.sources/browse_thread/thread/35e5f739be7ef108#

$ cat file-name-extension.patch 
--- files.el.orig	2009-03-03 10:58:07.000000000 +0900
+++ files.el	2009-03-17 18:19:19.000000000 +0900
@@ -3682,7 +3682,7 @@ except that a leading `.', if any, doesn
 	    (substring file 0 (match-beginning 0)))
 	filename))))
 
-(defun file-name-extension (filename &optional period)
+(defun file-name-extension (filename &optional period backup-version)
   "Return FILENAME's final \"extension\".
 The extension, in a file name, is the part that follows the last `.',
 excluding version numbers and backup suffixes,
@@ -3694,7 +3694,7 @@ If PERIOD is non-nil, then the returned 
 that delimits the extension, and if FILENAME has no extension,
 the value is \"\"."
   (save-match-data
-    (let ((file (file-name-sans-versions (file-name-nondirectory filename))))
+    (let ((file (file-name-sans-versions (file-name-nondirectory filename) (if backup-version t nil))))
       (if (and (string-match "\\.[^.]*\\'" file)
 	       (not (eq 0 (match-beginning 0))))
           (substring file (+ (match-beginning 0) (if period 0 1)))