summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--file.c78
-rw-r--r--test/ruby/test_file_exhaustive.rb14
3 files changed, 86 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 6da788d34b..5a7dbf826d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Thu Dec 25 16:01:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_expand_path_internal): drop characters ignored
+ by filesystem on Mac OS X.
+
Thu Dec 25 15:36:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* dir.c (replace_real_basename): get the real name and replace the
diff --git a/file.c b/file.c
index b22ff8fbee..9539ea937a 100644
--- a/file.c
+++ b/file.c
@@ -315,6 +315,38 @@ rb_str_normalize_ospath(const char *ptr, long len)
return str;
}
+
+static int
+ignored_char_p(const char *p, const char *e, rb_encoding *enc)
+{
+ unsigned char c;
+ if (p+3 > e) return 0;
+ switch ((unsigned char)*p) {
+ case 0xe2:
+ switch ((unsigned char)p[1]) {
+ case 0x80:
+ c = (unsigned char)p[2];
+ /* c >= 0x200c && c <= 0x200f */
+ if (c >= 0x8c && c <= 0x8f) return 3;
+ /* c >= 0x202a && c <= 0x202e */
+ if (c >= 0xaa && c <= 0xae) return 3;
+ return 0;
+ case 0x81:
+ c = (unsigned char)p[2];
+ /* c >= 0x206a && c <= 0x206f */
+ if (c >= 0xaa && c <= 0xaf) return 3;
+ return 0;
+ }
+ break;
+ case 0xef:
+ /* c == 0xfeff */
+ if ((unsigned char)p[1] == 0xbb &&
+ (unsigned char)p[2] == 0xbf)
+ return 3;
+ break;
+ }
+ return 0;
+}
#endif
static long
@@ -3103,6 +3135,27 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
buflen = RSTRING_LEN(result),\
pend = p + buflen)
+#ifdef __APPLE__
+# define SKIPPATHSEP(p) ((*(p)) ? 1 : 0)
+#else
+# define SKIPPATHSEP(p) 1
+#endif
+
+#define BUFCOPY(srcptr, srclen) do { \
+ const int skip = SKIPPATHSEP(p); \
+ rb_str_set_len(result, p-buf+skip); \
+ BUFCHECK(bdiff + ((srclen)+skip) >= buflen); \
+ p += skip; \
+ memcpy(p, (srcptr), (srclen)); \
+ p += (srclen); \
+} while (0)
+
+#define WITH_ROOTDIFF(stmt) do { \
+ long rootdiff = root - buf; \
+ stmt; \
+ root = buf + rootdiff; \
+} while (0)
+
static VALUE
copy_home_path(VALUE result, const char *dir)
{
@@ -3374,17 +3427,25 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
case '\\':
#endif
if (s > b) {
- long rootdiff = root - buf;
- rb_str_set_len(result, p-buf+1);
- BUFCHECK(bdiff + (s-b+1) >= buflen);
- root = buf + rootdiff;
- memcpy(++p, b, s-b);
- p += s-b;
+ WITH_ROOTDIFF(BUFCOPY(b, s-b));
*p = '/';
}
b = ++s;
break;
default:
+#ifdef __APPLE__
+ {
+ int n = ignored_char_p(s, fend, enc);
+ if (n) {
+ if (s > b) {
+ WITH_ROOTDIFF(BUFCOPY(b, s-b));
+ *p = '\0';
+ }
+ b = s += n;
+ break;
+ }
+ }
+#endif
Inc(s, fend, enc);
break;
}
@@ -3406,10 +3467,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
#endif
- rb_str_set_len(result, p-buf+1);
- BUFCHECK(bdiff + (s-b) >= buflen);
- memcpy(++p, b, s-b);
- p += s-b;
+ BUFCOPY(b, s-b);
rb_str_set_len(result, p-buf);
}
if (p == skiproot(buf, p + !!*p, enc) - 1) p++;
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb
index af66b68123..c629461efd 100644
--- a/test/ruby/test_file_exhaustive.rb
+++ b/test/ruby/test_file_exhaustive.rb
@@ -440,13 +440,25 @@ class TestFileExhaustive < Test::Unit::TestCase
def test_expand_path
assert_equal(@file, File.expand_path(File.basename(@file), File.dirname(@file)))
- if /cygwin|mingw|mswin|bccwin/ =~ RUBY_PLATFORM
+ case RUBY_PLATFORM
+ when /cygwin|mingw|mswin|bccwin/
assert_equal(@file, File.expand_path(@file + " "))
assert_equal(@file, File.expand_path(@file + "."))
assert_equal(@file, File.expand_path(@file + "::$DATA"))
assert_match(/\Ac:\//i, File.expand_path('c:'), '[ruby-core:31591]')
assert_match(/\Ac:\//i, File.expand_path('c:foo', 'd:/bar'))
assert_match(%r'\Ac:/bar/foo\z'i, File.expand_path('c:foo', 'c:/bar'))
+ when /darwin/
+ ["\u{feff}", *"\u{2000}"..."\u{2100}"].each do |c|
+ file = @file + c
+ begin
+ open(file) {}
+ rescue
+ assert_equal(file, File.expand_path(file), c.dump)
+ else
+ assert_equal(@file, File.expand_path(file), c.dump)
+ end
+ end
end
if DRIVE
assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar"))