コンテンツへスキップ
2010/10/20 / highmt

NTEmacs23.2 Shift_JISパッチ

GNU Emacs 23.2.1 (i386-mingw-nt6.0.6002)

テキストファイルをアップロードできないので直接貼りつけ。

いわゆるShift_JISで0x5cで終わっている文字列(「XXX表」とか)がファイル名/
フォルダ名になっているとdiredで見れない問題とか、
コマンドラインをjapanese-shift-jisで吐いてるはずなのになぜかへんな
エスケープが入ってファイルが見つからないとかいわれる、
とかといった現象が解消します。
(今さらかよ、という気もしますが。emacsだっせーとかいわないように。)

テストも何もしてないので申し訳ないんですが適用は自己責任でお願いします。
(自分もビクビクしながら使ってます。)
あときれいなパッチでもないのでそのへんも許してください。

ベースは
http://sourceforge.jp/projects/gnupack/

のソース(オリジナル
+Emacs-23.1.92-IME+a.patch+Emacs-23.1.92-IME_ReConversion.patch)
です。

パッチ内の「^L」は実際はコントロールコードが入ってます。
適当に編集してください。

まず本体(src)のほう。

diff -ur emacs-23.2.orig/src/buffer.c emacs-23.2/src/buffer.c
--- emacs-23.2.orig/src/buffer.c	2010-04-04 07:26:12.000000000 +0900
+++ emacs-23.2/src/buffer.c	2010-10-16 22:19:43.065400000 +0900
@@ -189,6 +189,19 @@
     error ("No buffer named %s", SDATA (spec));
   error ("Invalid buffer argument");
 }
+
+/* patch20101016 */
+#ifdef WINDOWSNT
+#include <mbstring.h>
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 ^L
 DEFUN ("buffer-live-p", Fbuffer_live_p, Sbuffer_live_p, 1, 1, 0,
        doc: /* Return non-nil if OBJECT is a buffer which has not been killed.
@@ -5379,7 +5392,10 @@
   /* Maybe this should really use some standard subroutine
      whose definition is filename syntax dependent.  */
   len = strlen (pwd);
+/* patch20101016
   if (!(IS_DIRECTORY_SEP (pwd[len - 1])))
+*/
+  if (!(IS_DIRECTORY_SEP (LAST_CHAR(pwd, len))))
     {
       /* Grow buffer to add directory separator and ''.  */
       pwd = (char *) realloc (pwd, len + 2);
diff -ur emacs-23.2.orig/src/w32.c emacs-23.2/src/w32.c
--- emacs-23.2.orig/src/w32.c	2010-10-14 01:36:32.399000000 +0900
+++ emacs-23.2/src/w32.c	2010-10-16 22:26:30.218800000 +0900
@@ -159,6 +159,18 @@
 
 extern int w32_num_mouse_buttons;
 
+/* patch20101016 */
+#ifdef WINDOWSNT
+#include <mbstring.h>
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 ^L
 /* Initialization states.
 
@@ -304,8 +316,6 @@
     LPFILETIME lpKernelTime,
     LPFILETIME lpUserTime);
 
-
-
   /* ** A utility function ** */
 static BOOL
 is_windows_9x ()
@@ -1352,7 +1362,10 @@
         {
 	  if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
 	    break;
+/* patch20101016
 	  name++;
+*/
+	  name = STRINC(name);
 	}
       while ( *name );
       if (IS_DIRECTORY_SEP (name[0]))
@@ -2175,7 +2188,13 @@
         {
 	  if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
 	    break;
+/* patch20101016
 	  *str++ = *name++;
+*/
+	  {
+	    const char *namex = STRINC(name);
+	    while (namex != name) *str++ = *name++;
+	  }
 	}
       while ( *name );
 
@@ -2411,8 +2430,12 @@
 
       strcpy (filename, dir_pathname);
       ln = strlen (filename) - 1;
+/* patch20101016
       if (!IS_DIRECTORY_SEP (filename[ln]))
 	strcat (filename, "\\");
+*/
+      if (!IS_DIRECTORY_SEP (LAST_CHAR(filename, ln + 1)))
+	strcat (filename, "\\");
       strcat (filename, "*");
 
       dir_find_handle = FindFirstFile (filename, &dir_find_data);
@@ -2517,7 +2540,10 @@
   /* WNetEnumResource returns \\resource\share...skip forward to "share". */
   ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
   ptr += 2;
+/* patch20101016
   while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
+*/
+  while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr = STRINC(ptr);
   ptr++;
 
   strncpy (readbuf, ptr, size);
@@ -2578,6 +2604,7 @@
   n_slashes = 2;
   strncpy (share, path, MAX_PATH);
   /* Truncate to just server and share name.  */
+/* patch20101016
   for (i = 2; i < MAX_PATH; i++)
     {
       if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
@@ -2586,6 +2613,15 @@
           break;
         }
     }
+*/
+  for (i = 2; i < MAX_PATH; i += (char*)STRINC(share + i) - (share + i))
+    {
+      if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
+        {
+          share[i] = '';
+          break;
+        }
+    }
 
   resource.dwType = RESOURCETYPE_DISK;
   resource.lpLocalName = NULL;
@@ -3191,9 +3227,17 @@
 	  const char *s;
 	  char *p;
 
+/* patch20101016
 	  for (s = fname + 2, p = machine;
 	       *s && !IS_DIRECTORY_SEP (*s); s++, p++)
 	    *p = *s;
+*/
+	  for (s = fname + 2, p = machine;
+	       *s && !IS_DIRECTORY_SEP (*s);)
+	    {
+	      const char *sx = STRINC(s);
+	      while (sx != s) *p = *s;
+	    }
 	  *p = '';
 	  mp = machine;
 	}
@@ -3334,7 +3378,11 @@
     }
   else if (rootdir)
     {
+/* patch20101016
       if (!IS_DIRECTORY_SEP (name[len-1]))
+*/
+	strcat (name, "\\");
+      if (!IS_DIRECTORY_SEP (LAST_CHAR(name, len)))
 	strcat (name, "\\");
       if (GetDriveType (name) < 2)
 	{
@@ -3350,15 +3398,23 @@
     }
   else
     {
+/* patch20101016
       if (IS_DIRECTORY_SEP (name[len-1]))
 	name[len - 1] = 0;
+*/
+      if (IS_DIRECTORY_SEP (LAST_CHAR(name, len)))
+	name[len - 1] = 0;
 
       /* (This is hacky, but helps when doing file completions on
 	 network drives.)  Optimize by using information available from
 	 active readdir if possible.  */
       len = strlen (dir_pathname);
+/* patch20101016
       if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
 	len--;
+*/
+      if (IS_DIRECTORY_SEP (LAST_CHAR(dir_pathname, len)))
+	len--;
       if (dir_find_handle != INVALID_HANDLE_VALUE
 	  && strnicmp (name, dir_pathname, len) == 0
 	  && IS_DIRECTORY_SEP (name[len])
diff -ur emacs-23.2.orig/src/w32proc.c emacs-23.2/src/w32proc.c
--- emacs-23.2.orig/src/w32proc.c	2010-04-04 07:26:11.000000000 +0900
+++ emacs-23.2/src/w32proc.c	2010-10-17 04:46:29.630600000 +0900
@@ -71,6 +71,19 @@
 	    + ((DWORD)(var) - (section)->VirtualAddress)		\
 	    + (filedata).file_base))
 
+
+/* patch20101016 */
+#ifdef WINDOWSNT
+#include <mbstring.h>
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 /* Control whether spawnve quotes arguments as necessary to ensure
    correct parsing by child process.  Because not all uses of spawnve
    are careful about constructing argv arrays, we make this behavior
@@ -906,7 +919,10 @@
 
       if (*p == 0)
 	need_quotes = 1;
+/* patch20101016
       for ( ; *p; p++)
+*/
+      for ( ; *p; p = STRINC(p))
 	{
 	  if (escape_char == '"' && *p == '\\')
 	    /* If it's a Cygwin app, \ needs to be escaped.  */
@@ -958,7 +974,10 @@
 
       if (do_quoting)
 	{
+/* patch20101016
 	  for ( ; *p; p++)
+*/
+	  for ( ; *p; p = STRINC(p))
 	    if ((strchr (sepchars, *p) != NULL) || *p == '"')
 	      need_quotes = 1;
 	}
@@ -986,7 +1005,10 @@
 	      *parg++ = *p++;
 	    }
 #else
+/* patch20101016
 	  for ( ; *p; p++)
+*/
+	  for ( ; *p; )
 	    {
 	      if (*p == '"')
 		{
@@ -1001,12 +1023,20 @@
 		}
 	      else if (escape_char == '"' && *p == '\\')
 		*parg++ = '\\';
+/* patch20101016
 	      *parg++ = *p;
+*/
 
 	      if (*p == escape_char && escape_char != '"')
 		escape_char_run++;
 	      else
 		escape_char_run = 0;
+/* patch20101016 */
+	      {
+		char *px = STRINC(p);
+	        while (px != p) *parg++ = *p++;
+	      }
+/* patch20101016 */
 	    }
 	  /* double escape chars before enclosing quote */
 	  while (escape_char_run > 0)

付属ツール(lib-src)のほう。
こっちは使ってないのでさらに人柱の覚悟が必要です。

diff -ur emacs-23.2.orig/lib-src/emacsclient.c emacs-23.2/lib-src/emacsclient.c
--- emacs-23.2.orig/lib-src/emacsclient.c	2010-04-04 07:26:07.000000000 +0900
+++ emacs-23.2/lib-src/emacsclient.c	2010-10-16 22:57:30.106400000 +0900
@@ -228,6 +228,17 @@
 #endif
 
 
+/* patch20101016 */
+#ifdef WINDOWSNT
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 /* Return the current working directory.  Returns NULL on errors.
    Any other returned value must be freed with free.  This is used
    only when get_current_dir_name is not defined on the system.  */
diff -ur emacs-23.2.orig/lib-src/make-docfile.c emacs-23.2/lib-src/make-docfile.c
--- emacs-23.2.orig/lib-src/make-docfile.c	2010-04-04 07:26:08.000000000 +0900
+++ emacs-23.2/lib-src/make-docfile.c	2010-10-16 22:58:56.724000000 +0900
@@ -87,6 +87,17 @@
 /* Name this program was invoked with.  */
 char *progname;
 
+/* patch20101016 */
+#ifdef WINDOWSNT
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 /* Print error message.  `s1' is printf control string, `s2' is arg for it.  */
 
 /* VARARGS1 */
@@ -192,10 +203,17 @@
 {
   char *tmp;
 
+/* patch20101016
   for (tmp = filename; *tmp; tmp++)
     {
       if (IS_DIRECTORY_SEP(*tmp))
 	filename = tmp + 1;
+    }
+*/
+  for (tmp = filename; *tmp; tmp = STRINC(tmp))
+    {
+      if (IS_DIRECTORY_SEP(*tmp))
+	filename = tmp + 1;
     }
 
   putc (037, outfile);
diff -ur emacs-23.2.orig/lib-src/movemail.c emacs-23.2/lib-src/movemail.c
--- emacs-23.2.orig/lib-src/movemail.c	2010-04-04 07:26:13.000000000 +0900
+++ emacs-23.2/lib-src/movemail.c	2010-10-16 23:00:12.774000000 +0900
@@ -166,6 +166,17 @@
 /* Nonzero means this is name of a lock file to delete on fatal error.  */
 char *delete_lockname;
 
+/* patch20101016 */
+#ifdef WINDOWSNT
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 int
 main (argc, argv)
      int argc;
@@ -301,8 +312,12 @@
       tempname = (char *) xmalloc (strlen (inname) + strlen ("EXXXXXX") + 1);
       strcpy (tempname, inname);
       p = tempname + strlen (tempname);
+/* patch20101016
       while (p != tempname && !IS_DIRECTORY_SEP (p[-1]))
 	p--;
+*/
+      while (p != tempname && !IS_DIRECTORY_SEP (*STRDEC(tempname, p)))
+	p = STRDEC(tempname, p);
       *p = 0;
       strcpy (p, "EXXXXXX");
       mktemp (tempname);
diff -ur emacs-23.2.orig/lib-src/ntlib.c emacs-23.2/lib-src/ntlib.c
--- emacs-23.2.orig/lib-src/ntlib.c	2010-04-04 07:26:05.000000000 +0900
+++ emacs-23.2/lib-src/ntlib.c	2010-10-16 23:03:26.840000000 +0900
@@ -32,6 +32,18 @@
 
 #include "ntlib.h"
 
+/* patch20101016 */
+#ifdef WINDOWSNT
+#include <mbstring.h>
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *_mbsdec((buf), (buf) + (len)))
+#define STRINC(p) _mbsinc(p)
+#define STRDEC(start, p) _mbsdec(start, p)
+#else
+#define LAST_CHAR(buf,len) ((len) < 1 ? '' : *((buf) + (len) - 1))
+#define STRINC(p) p + 1
+#define STRDEC(start, p) p - 1
+#endif
+
 #define MAXPATHLEN _MAX_PATH
 
 /* Emulate sleep...we could have done this with a define, but that
@@ -327,8 +339,12 @@
     }
   else
     {
+/* patch20101016
       if (IS_DIRECTORY_SEP (name[len-1]))
 	name[len - 1] = 0;
+*/
+      if (IS_DIRECTORY_SEP (LAST_CHAR(name, len)))
+	name[len - 1] = 0;
 
       fh = FindFirstFile (name, &wfd);
       if (fh == INVALID_HANDLE_VALUE)

cvsのSJISパッチを思い出す強引さ。
本当はutf-8パッチを作りたいんですが、仕様的に悩んでます。
WindowsのCreateProcessAが妙なことをするから実質japanese-shift-jisか
utf-16しか受け付けられないし。
coding-system-for-writeがコマンドラインのエンコーディングに使われるのが
Windows上ではちょっと困る感じ。
windows-argument-coding-systemとか別につくったほうがきれいにいくのかも。

7件のコメント

  1. shingo / 9月 2 2011 23:34

    はじめまして。自分もこの問題に悩んでいたところ、こちらのサイトを見つけました。
    大変貴重な情報ありがとうございます。

    ところでこのバグレポートあるいはパッチは、本家GNU Emacsにご報告されているのでしょうか??
    (非常に重要な内容だと思いましたので。。。)

    • highmt / 9月 7 2011 04:33

      すみません。気後れしていて現状は特にどこかに報告などはしていません。
      こんなんじゃいけないとは思ってるんですが…

      • sf / 2月 3 2013 02:08

        w32proc.c、力不足で修正入れてもらえませんでした。

      • shingo / 2月 21 2014 20:33

        お久しぶりです。でも最新のEmacsではこの問題はもう発生しないですよね。別のアプローチで解決されたんですかね。

  2. oka / 3月 15 2012 13:02

    + while (sx != s) *p = *s;

    + while (sx != s) *p++ = *s++;
    の間違いではありませんか。UNC パスでファイルが開けなくなりました。

    • highmt / 3月 16 2012 23:14

      ありがとうございます。おはずかしい。

  3. highmt / 3月 16 2012 23:32

    ‘\0’ が ” になっていたりとかもおかしいですね… すみません。

コメントは受け付けていません。