[前][次][番号順一覧][スレッド一覧]

ruby-changes:37397

From: nobu <ko1@a...>
Date: Tue, 3 Feb 2015 14:04:56 +0900 (JST)
Subject: [ruby-changes:37397] nobu:r49478 (trunk): dir.c: glob legacy short name

nobu	2015-02-03 14:04:49 +0900 (Tue, 03 Feb 2015)

  New Revision: 49478

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49478

  Log:
    dir.c: glob legacy short name
    
    * dir.c (glob_helper): obtain real name with FindFirstFile API
      instead of matchin all entries, on Windows.
      [ruby-core:67954] [Bug #10819]

  Modified files:
    trunk/ChangeLog
    trunk/dir.c
    trunk/test/ruby/test_dir.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 49477)
+++ ChangeLog	(revision 49478)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Feb  3 14:04:47 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* dir.c (glob_helper): obtain real name with FindFirstFile API
+	  instead of matchin all entries, on Windows.
+	  [ruby-core:67954] [Bug #10819]
+
 Tue Feb  3 12:26:35 2015  Katsuhiko Nishimra  <ktns.87@g...>
 
 	* lib/mkmf.rb (configuration): set the default cxxflags, which is
Index: dir.c
===================================================================
--- dir.c	(revision 49477)
+++ dir.c	(revision 49478)
@@ -81,6 +81,10 @@ char *strchr(char*,char); https://github.com/ruby/ruby/blob/trunk/dir.c#L81
 # define USE_NAME_ON_FS 1
 # define RUP32(size) ((size)+3/4)
 # define SIZEUP32(type) RUP32(sizeof(type))
+#elif defined _WIN32
+# define USE_NAME_ON_FS 1
+#elif defined DOSISH
+# define USE_NAME_ON_FS 2	/* by fnmatch */
 #else
 # define USE_NAME_ON_FS 0
 #endif
@@ -1177,10 +1181,30 @@ has_magic(const char *p, const char *pen https://github.com/ruby/ruby/blob/trunk/dir.c#L1181
 		return PLAIN;
 	    continue;
 
+#ifdef _WIN32
+	  case '~':
+	    /* possibly legacy 8.3 short name */
+	    if (p < pend && (c = *p, ISDIGIT(c))) {
+		while (++p < pend && (c = *p, ISDIGIT(c)));
+		if (p == pend || c == '.') hasalpha = 1;
+	    }
+	    continue;
+#endif
+
 	  default:
 	    if (ISALPHA(c)) {
 		hasalpha = 1;
 	    }
+#ifdef _WIN32
+	    else if (!rb_isascii(c)) {
+		unsigned int code = rb_enc_mbc_to_codepoint(p, pend, enc);
+		if (ONIGENC_IS_CODE_ALPHA(enc, c)) {
+		    /* Full width alphabets */
+		    hasalpha = 1;
+		}
+	    }
+#endif
+	    break;
 	}
 
 	p = Next(p-1, pend, enc);
@@ -1373,7 +1397,7 @@ is_case_sensitive(DIR *dirp) https://github.com/ruby/ruby/blob/trunk/dir.c#L1397
 }
 
 static char *
-replace_real_basename(char *path, long base, int norm_p)
+replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p)
 {
     u_int32_t attrbuf[SIZEUP32(attrreference_t) + RUP32(MAXPATHLEN * 3) + 1];
     struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_NAME};
@@ -1408,6 +1432,43 @@ replace_real_basename(char *path, long b https://github.com/ruby/ruby/blob/trunk/dir.c#L1432
     IF_NORMALIZE_UTF8PATH(if (!NIL_P(utf8str)) rb_str_resize(utf8str, 0));
     return path;
 }
+#elif defined _WIN32
+VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
+
+static char *
+replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p)
+{
+    char *plainname = path;
+    volatile VALUE tmp = 0;
+    WIN32_FIND_DATAW fd;
+    WCHAR *wplain;
+    HANDLE h;
+    long wlen;
+    if (enc &&
+	enc != rb_usascii_encoding() &&
+	enc != rb_ascii8bit_encoding() &&
+	enc != rb_utf8_encoding()) {
+	tmp = rb_enc_str_new_cstr(plainname, enc);
+	tmp = rb_str_encode_ospath(tmp);
+	plainname = RSTRING_PTR(tmp);
+    }
+    wplain = rb_w32_mbstr_to_wstr(CP_UTF8, plainname, -1, &wlen);
+    if (tmp) rb_str_resize(tmp, 0);
+    if (!wplain) return path;
+    h = FindFirstFileW(wplain, &fd);
+    free(wplain);
+    if (h == INVALID_HANDLE_VALUE) return path;
+    FindClose(h);
+    tmp = rb_w32_conv_from_wchar(fd.cFileName, enc);
+    wlen = RSTRING_LEN(tmp);
+    path = GLOB_REALLOC(path, base + wlen + 1);
+    memcpy(path + base, RSTRING_PTR(tmp), wlen);
+    path[base + wlen] = 0;
+    rb_str_resize(tmp, 0);
+    return path;
+}
+#elif USE_NAME_ON_FS == 1
+# error not implemented
 #endif
 
 enum answer {UNKNOWN = -1, NO, YES};
@@ -1473,7 +1534,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L1534
 	    plain = 1;
 	    break;
 	  case ALPHA:
-#ifdef HAVE_GETATTRLIST
+#if defined HAVE_GETATTRLIST || defined _WIN32
 	    plain = 1;
 #else
 	    magical = 1;
@@ -1533,11 +1594,11 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L1594
     if (magical || recursive) {
 	struct dirent *dp;
 	DIR *dirp;
-# ifdef DOSISH
+# if USE_NAME_ON_FS == 2
 	char *plainname = 0;
 # endif
 	IF_NORMALIZE_UTF8PATH(int norm_p);
-# ifdef DOSISH
+# if USE_NAME_ON_FS == 2
 	if (cur + 1 == end && (*cur)->type <= ALPHA) {
 	    plainname = join_path(path, pathlen, dirsep, (*cur)->str, strlen((*cur)->str));
 	    if (!plainname) return -1;
@@ -1633,7 +1694,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L1694
 		}
 		switch (p->type) {
 		  case ALPHA:
-# ifdef DOSISH
+# if USE_NAME_ON_FS == 2
 		    if (plainname) {
 			*new_end++ = p->next;
 			break;
@@ -1703,10 +1764,10 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L1764
 		    status = -1;
 		    break;
 		}
-#ifdef HAVE_GETATTRLIST
+#if defined HAVE_GETATTRLIST || defined _WIN32
 		if ((*cur)->type == ALPHA) {
 		    long base = pathlen + (dirsep != 0);
-		    buf = replace_real_basename(buf, base, IF_NORMALIZE_UTF8PATH(1)+0);
+		    buf = replace_real_basename(buf, base, enc, IF_NORMALIZE_UTF8PATH(1)+0);
 		}
 #endif
 		status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg,
Index: test/ruby/test_dir.rb
===================================================================
--- test/ruby/test_dir.rb	(revision 49477)
+++ test/ruby/test_dir.rb	(revision 49478)
@@ -248,6 +248,18 @@ class TestDir < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_dir.rb#L248
     assert_equal(roots.map {|n| "/..#{n}"}, Dir.glob("/../*"), bug9648)
   end
 
+  if /mswin|mingw/ =~ RUBY_PLATFORM
+    def test_glob_legacy_short_name
+      bug10819 = '[ruby-core:67954] [Bug #10819]'
+      skip unless /\A\w:/ =~ ENV["ProgramFiles"]
+      short = "#$&/PROGRA~1"
+      skip unless File.directory?(short)
+      entries = Dir.glob("#{short}/Common*")
+      assert_not_empty(entries, bug10819)
+      assert_equal(Dir.glob("#{File.expand_path(short)}/Common*"), entries, bug10819)
+    end
+  end
+
   def test_home
     env_home = ENV["HOME"]
     env_logdir = ENV["LOGDIR"]

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]