diff options
author | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-26 03:01:41 +0000 |
---|---|---|
committer | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-26 03:01:41 +0000 |
commit | 0e6dcc7ab24e6e5b8ee3b9a532c0318eb5155e2e (patch) | |
tree | 10e9d00b89f6bb5b0d275ee4dbd6e35fe886b2ef | |
parent | c5b7d11e59cf8953d18ed6aba2c4df2b1eb29fd4 (diff) |
merge revision(s) 32826,34732: [Backport #6681]
* file.c (rb_enc_path_next, rb_enc_path_skip_prefix)
(rb_enc_path_last_separator, rb_enc_path_end)
(ruby_enc_find_basename, ruby_enc_find_extname): encoding-aware
path handling functions.
* file.c (rb_home_dir, file_expand_path, rb_realpath_internal)
(rb_file_s_basename, rb_file_dirname, rb_file_s_extname)
(rb_file_join): should respect the encodings of arguments than
file system encoding. [ruby-dev:45145] [Bug #5919]
* dir.c (check_dirname, ruby_glob0): ditto.
* ext/pathname/pathname.c (path_sub_ext): ditto.
* util.c, include/ruby/util.h (ruby_add_suffix): remove the function.
[Bug #5153] [ruby-core:38736]
* io.c (argf_next_argv): remove the call of above function.
* ext/-test-/add_suffix, test/-ext-/test_add_suffix.rb: remove the test
extension module because this is only for testsing ruby_add_suffix().
* LEGAL: remove the mention about a part of util.c, because now we
removed the part.
* io.c (argf_next_argv): now the new filename is not guranteed to
use, so should check the return value of rename(2).
* test/ruby/test_argf.rb (TestArgf#test_inplace_rename_impossible):
now we expect same result with other platforms on no_safe_rename
platforms (=Windows).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_3@37330 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | LEGAL | 1 | ||||
-rw-r--r-- | dir.c | 11 | ||||
-rw-r--r-- | ext/-test-/add_suffix/bug.c | 32 | ||||
-rw-r--r-- | ext/-test-/add_suffix/depend | 1 | ||||
-rw-r--r-- | ext/-test-/add_suffix/extconf.rb | 4 | ||||
-rw-r--r-- | ext/pathname/pathname.c | 7 | ||||
-rw-r--r-- | file.c | 416 | ||||
-rw-r--r-- | include/ruby/encoding.h | 6 | ||||
-rw-r--r-- | include/ruby/intern.h | 6 | ||||
-rw-r--r-- | include/ruby/util.h | 4 | ||||
-rw-r--r-- | io.c | 14 | ||||
-rw-r--r-- | test/-ext-/test_add_suffix.rb | 47 | ||||
-rw-r--r-- | test/pathname/test_pathname.rb | 8 | ||||
-rw-r--r-- | test/ruby/test_argf.rb | 15 | ||||
-rw-r--r-- | test/ruby/test_file_exhaustive.rb | 27 | ||||
-rw-r--r-- | util.c | 178 | ||||
-rw-r--r-- | version.h | 2 |
18 files changed, 346 insertions, 469 deletions
@@ -1,3 +1,39 @@ +Fri Oct 26 11:03:46 2012 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * file.c (rb_enc_path_next, rb_enc_path_skip_prefix) + (rb_enc_path_last_separator, rb_enc_path_end) + (ruby_enc_find_basename, ruby_enc_find_extname): encoding-aware + path handling functions. + + * file.c (rb_home_dir, file_expand_path, rb_realpath_internal) + (rb_file_s_basename, rb_file_dirname, rb_file_s_extname) + (rb_file_join): should respect the encodings of arguments than + file system encoding. [ruby-dev:45145] [Bug #5919] + + * dir.c (check_dirname, ruby_glob0): ditto. + + * ext/pathname/pathname.c (path_sub_ext): ditto. + +Fri Oct 26 11:03:46 2012 NAKAMURA Usaku <usa@ruby-lang.org> + + * util.c, include/ruby/util.h (ruby_add_suffix): remove the function. + [Bug #5153] [ruby-core:38736] + + * io.c (argf_next_argv): remove the call of above function. + + * ext/-test-/add_suffix, test/-ext-/test_add_suffix.rb: remove the test + extension module because this is only for testsing ruby_add_suffix(). + + * LEGAL: remove the mention about a part of util.c, because now we + removed the part. + + * io.c (argf_next_argv): now the new filename is not guranteed to + use, so should check the return value of rename(2). + + * test/ruby/test_argf.rb (TestArgf#test_inplace_rename_impossible): + now we expect same result with other platforms on no_safe_rename + platforms (=Windows). + Thu Oct 25 18:16:25 2012 NARUSE, Yui <naruse@ruby-lang.org> * lib/rubygems/installer.rb (check_that_user_bin_dir_is_in_path): @@ -148,7 +148,6 @@ util.c (partly): REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -util.c (partly): win32/win32.[ch]: You can apply the Artistic License to these files. (or GPL, @@ -910,11 +910,16 @@ check_dirname(volatile VALUE *dir) { VALUE d = *dir; char *path, *pend; + long len; + rb_encoding *enc; rb_secure(2); FilePathValue(d); - path = RSTRING_PTR(d); - if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) { + enc = rb_enc_get(d); + RSTRING_GETMEM(d, path, len); + pend = path + len; + pend = rb_enc_path_end(rb_enc_path_skip_prefix(path, pend, enc), pend, enc); + if (pend - path < len) { d = rb_str_subseq(d, 0, pend - path); } *dir = rb_str_encode_ospath(d); @@ -1494,7 +1499,7 @@ ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_enco start = root = path; flags |= FNM_SYSCASE; #if defined DOSISH - root = rb_path_skip_prefix(root); + root = rb_enc_path_skip_prefix(root, root + strlen(root), enc); #endif if (root && *root == '/') root++; diff --git a/ext/-test-/add_suffix/bug.c b/ext/-test-/add_suffix/bug.c deleted file mode 100644 index 3dc1201b6e..0000000000 --- a/ext/-test-/add_suffix/bug.c +++ /dev/null @@ -1,32 +0,0 @@ -static unsigned long ruby_scan_oct(); -static unsigned long ruby_scan_hex(); -static unsigned long ruby_strtoul(); -static void ruby_qsort(); -static char *ruby_strdup(); -static char *ruby_getcwd(); -static double ruby_strtod(); -static char *ruby_dtoa(); -static void ruby_each_words(); -static char *ruby_hdtoa(); -#include "ruby.h" -#include "ruby/defines.h" -#include "ruby/util.h" -#ifndef HAVE_RUBY_ADD_SUFFIX -#define _WIN32 1 -#include "util.c" -#endif - -static VALUE -add_suffix(VALUE self, VALUE path, VALUE suffix) -{ - StringValueCStr(path); - ruby_add_suffix(path, StringValueCStr(suffix)); - return path; -} - -void -Init_bug(void) -{ - VALUE mBug = rb_define_module("Bug"); - rb_define_module_function(mBug, "add_suffix", add_suffix, 2); -} diff --git a/ext/-test-/add_suffix/depend b/ext/-test-/add_suffix/depend deleted file mode 100644 index 943d0d9f21..0000000000 --- a/ext/-test-/add_suffix/depend +++ /dev/null @@ -1 +0,0 @@ -bug.o: $(hdrdir)/ruby/util.h $(top_srcdir)/util.c diff --git a/ext/-test-/add_suffix/extconf.rb b/ext/-test-/add_suffix/extconf.rb deleted file mode 100644 index bffd1550f3..0000000000 --- a/ext/-test-/add_suffix/extconf.rb +++ /dev/null @@ -1,4 +0,0 @@ -unless have_func("ruby_add_suffix", "ruby/util.h") - $INCFLAGS << " -I$(top_srcdir)" -end -create_makefile("-test-/add_suffix/bug") diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c index e1632c524b..e35c19d541 100644 --- a/ext/pathname/pathname.c +++ b/ext/pathname/pathname.c @@ -1,4 +1,5 @@ #include "ruby.h" +#include "ruby/encoding.h" static VALUE rb_cPathname; static ID id_at_path, id_to_path; @@ -184,15 +185,15 @@ path_sub_ext(VALUE self, VALUE repl) StringValue(repl); p = RSTRING_PTR(str); - ext = ruby_find_extname(p, &extlen); + extlen = RSTRING_LEN(str); + ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str)); if (ext == NULL) { ext = p + RSTRING_LEN(str); } else if (extlen <= 1) { ext += extlen; } - str2 = rb_str_dup(str); - rb_str_resize(str2, ext-p); + str2 = rb_str_subseq(str, 0, ext-p); rb_str_append(str2, repl); OBJ_INFECT(str2, str); return rb_class_new_instance(1, &str2, rb_obj_class(self)); @@ -2430,6 +2430,8 @@ rb_file_s_symlink(VALUE klass, VALUE from, VALUE to) #endif #ifdef HAVE_READLINK +static VALUE rb_readlink(VALUE path); + /* * call-seq: * File.readlink(link_name) -> file_name @@ -2444,6 +2446,12 @@ rb_file_s_symlink(VALUE klass, VALUE from, VALUE to) static VALUE rb_file_s_readlink(VALUE klass, VALUE path) { + return rb_readlink(path); +} + +static VALUE +rb_readlink(VALUE path) +{ char *buf; int size = 100; ssize_t rv; @@ -2609,9 +2617,8 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'}; #define istrailinggarbage(x) 0 #endif -#ifndef CharNext /* defined as CharNext[AW] on Windows. */ -# define CharNext(p) ((p) + 1) -#endif +#define Next(p, e, enc) ((p) + rb_enc_mbclen((p), (e), (enc))) +#define Inc(p, e, enc) ((p) = Next((p), (e), (enc))) #if defined(DOSISH_UNC) #define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1])) @@ -2673,40 +2680,40 @@ not_same_drive(VALUE path, int drive) #endif static inline char * -skiproot(const char *path) +skiproot(const char *path, const char *end, rb_encoding *enc) { #ifdef DOSISH_DRIVE_LETTER - if (has_drive_letter(path)) path += 2; + if (path + 2 <= end && has_drive_letter(path)) path += 2; #endif - while (isdirsep(*path)) path++; + while (path < end && isdirsep(*path)) path++; return (char *)path; } -#define nextdirsep rb_path_next +#define nextdirsep rb_enc_path_next char * -rb_path_next(const char *s) +rb_enc_path_next(const char *s, const char *e, rb_encoding *enc) { - while (*s && !isdirsep(*s)) { - s = CharNext(s); + while (s < e && !isdirsep(*s)) { + Inc(s, e, enc); } return (char *)s; } #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) -#define skipprefix rb_path_skip_prefix +#define skipprefix rb_enc_path_skip_prefix #else -#define skipprefix(path) (path) +#define skipprefix(path, end, enc) (path) #endif char * -rb_path_skip_prefix(const char *path) +rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc) { #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) #ifdef DOSISH_UNC - if (isdirsep(path[0]) && isdirsep(path[1])) { + if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) { path += 2; - while (isdirsep(*path)) path++; - if (*(path = nextdirsep(path)) && path[1] && !isdirsep(path[1])) - path = nextdirsep(path + 1); + while (path < end && isdirsep(*path)) path++; + if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1])) + path = rb_enc_path_next(path + 1, end, enc); return (char *)path; } #endif @@ -2719,78 +2726,78 @@ rb_path_skip_prefix(const char *path) } static inline char * -skipprefixroot(const char *path) +skipprefixroot(const char *path, const char *end, rb_encoding *enc) { #if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) - char *p = skipprefix(path); + char *p = skipprefix(path, end, enc); while (isdirsep(*p)) p++; return p; #else - return skiproot(path); + return skiproot(path, end, enc); #endif } -#define strrdirsep rb_path_last_separator +#define strrdirsep rb_enc_path_last_separator char * -rb_path_last_separator(const char *path) +rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc) { char *last = NULL; - while (*path) { + while (path < end) { if (isdirsep(*path)) { const char *tmp = path++; - while (isdirsep(*path)) path++; - if (!*path) break; + while (path < end && isdirsep(*path)) path++; + if (path >= end) break; last = (char *)tmp; } else { - path = CharNext(path); + Inc(path, end, enc); } } return last; } static char * -chompdirsep(const char *path) +chompdirsep(const char *path, const char *end, rb_encoding *enc) { - while (*path) { + while (path < end) { if (isdirsep(*path)) { const char *last = path++; - while (isdirsep(*path)) path++; - if (!*path) return (char *)last; + while (path < end && isdirsep(*path)) path++; + if (path >= end) return (char *)last; } else { - path = CharNext(path); + Inc(path, end, enc); } } return (char *)path; } char * -rb_path_end(const char *path) +rb_enc_path_end(const char *path, const char *end, rb_encoding *enc) { - if (isdirsep(*path)) path++; - return chompdirsep(path); + if (path < end && isdirsep(*path)) path++; + return chompdirsep(path, end, enc); } #if USE_NTFS static char * -ntfs_tail(const char *path) +ntfs_tail(const char *path, const char *end, rb_encoding *enc) { - while (*path == '.') path++; - while (*path && *path != ':') { + while (path < end && *path == '.') path++; + while (path < end && *path != ':') { if (istrailinggarbage(*path)) { const char *last = path++; - while (istrailinggarbage(*path)) path++; - if (!*path || *path == ':') return (char *)last; + while (path < end && istrailinggarbage(*path)) path++; + if (path >= end || *path == ':') return (char *)last; } else if (isdirsep(*path)) { const char *last = path++; - while (isdirsep(*path)) path++; - if (!*path) return (char *)last; + while (path < end && isdirsep(*path)) path++; + if (path >= end) return (char *)last; if (*path == ':') path++; } else { - path = CharNext(path); + Inc(path, end, enc); } } return (char *)path; @@ -2819,9 +2826,10 @@ rb_home_dir(const char *user, VALUE result) const char *dir; char *buf; #if defined DOSISH || defined __CYGWIN__ - char *p; + char *p, *bend; #endif long dirlen; + rb_encoding *enc; if (!user || !*user) { if (!(dir = getenv("HOME"))) { @@ -2840,33 +2848,62 @@ rb_home_dir(const char *user, VALUE result) } dirlen = strlen(pwPtr->pw_dir); rb_str_resize(result, dirlen); - strcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir); + memcpy(buf = RSTRING_PTR(result), pwPtr->pw_dir, dirlen + 1); endpwent(); #else return Qnil; #endif } + enc = rb_filesystem_encoding(); + rb_enc_associate(result, enc); #if defined DOSISH || defined __CYGWIN__ - for (p = buf; *p; p = CharNext(p)) { + for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) { if (*p == '\\') { *p = '/'; } } #endif - rb_enc_associate_index(result, rb_filesystem_encindex()); return result; } #ifndef _WIN32 +static char * +append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encoding *fsenc) +{ + char *buf, *cwdp = dir; + VALUE dirname = Qnil; + size_t dirlen = strlen(dir), buflen = rb_str_capacity(result); + + if (*enc != fsenc) { + rb_encoding *direnc = rb_enc_check(fname, dirname = rb_enc_str_new(dir, dirlen, fsenc)); + if (direnc != fsenc) { + dirname = rb_str_conv_enc(dirname, fsenc, direnc); + RSTRING_GETMEM(dirname, cwdp, dirlen); + } + *enc = direnc; + rb_enc_associate(result, direnc); + } + do {buflen *= 2;} while (dirlen > buflen); + rb_str_resize(result, buflen); + buf = RSTRING_PTR(result); + memcpy(buf, cwdp, dirlen); + xfree(dir); + if (!NIL_P(dirname)) rb_str_resize(dirname, 0); + return buf + dirlen; +} + VALUE rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result) { - const char *s, *b; + const char *s, *b, *fend; char *buf, *p, *pend, *root; - size_t buflen, dirlen, bdiff; + size_t buflen, bdiff; int tainted; + rb_encoding *enc, *fsenc = rb_filesystem_encoding(); s = StringValuePtr(fname); + fend = s + RSTRING_LEN(fname); + enc = rb_enc_get(fname); BUFINIT(); tainted = OBJ_TAINTED(fname); @@ -2880,7 +2917,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na if (*++s) ++s; } else { - s = nextdirsep(b = s); + s = nextdirsep(b = s, fend, enc); userlen = s - b; BUFCHECK(bdiff + userlen >= buflen); memcpy(p, b, userlen); @@ -2926,18 +2963,16 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na } } if (!same) { - char *dir = getcwdofdrv(*s); - + char *e = append_fspath(result, fname, getcwdofdrv(*s), &enc, fsenc); tainted = 1; - dirlen = strlen(dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, dir); - xfree(dir); - rb_enc_associate_index(result, rb_filesystem_encindex()); + BUFINIT(); + p = e; } - else - rb_enc_associate(result, rb_enc_check(result, fname)); - p = chompdirsep(skiproot(buf)); + else { + rb_enc_associate(result, enc = rb_enc_check(result, fname)); + p = pend; + } + p = chompdirsep(skiproot(buf, p, enc), p, enc); s += 2; } } @@ -2945,28 +2980,25 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na else if (!rb_is_absolute_path(s)) { if (!NIL_P(dname)) { rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result); - BUFINIT(); rb_enc_associate(result, rb_enc_check(result, fname)); + BUFINIT(); + p = pend; } else { - char *dir = my_getcwd(); - + char *e = append_fspath(result, fname, my_getcwd(), &enc, fsenc); tainted = 1; - dirlen = strlen(dir); - BUFCHECK(dirlen > buflen); - strcpy(buf, dir); - xfree(dir); - rb_enc_associate_index(result, rb_filesystem_encindex()); + BUFINIT(); + p = e; } #if defined DOSISH || defined __CYGWIN__ if (isdirsep(*s)) { /* specified full path, but not drive letter nor UNC */ /* we need to get the drive letter or UNC share name */ - p = skipprefix(buf); + p = skipprefix(buf, p, enc); } else #endif - p = chompdirsep(skiproot(buf)); + p = chompdirsep(skiproot(buf, p, enc), p, enc); } else { size_t len; @@ -2990,7 +3022,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na rb_str_set_len(result, p-buf+1); BUFCHECK(bdiff + 1 >= buflen); p[1] = 0; - root = skipprefix(buf); + root = skipprefix(buf, p+1, enc); b = s; while (*s) { @@ -3006,7 +3038,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na /* We must go back to the parent */ char *n; *p = '\0'; - if (!(n = strrdirsep(root))) { + if (!(n = strrdirsep(root, p, enc))) { *p = '/'; } else { @@ -3036,7 +3068,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na --s; case ' ': { const char *e = s; - while (istrailinggarbage(*s)) s++; + while (s < fend && istrailinggarbage(*s)) s++; if (!*s) { s = e; goto endpath; @@ -3061,7 +3093,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na b = ++s; break; default: - s = CharNext(s); + Inc(s, fend, enc); break; } } @@ -3086,14 +3118,18 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na BUFCHECK(bdiff + (s-b) >= buflen); memcpy(++p, b, s-b); p += s-b; + rb_str_set_len(result, p-buf); } - if (p == skiproot(buf) - 1) p++; + if (p == skiproot(buf, p + !!*p, enc) - 1) p++; #if USE_NTFS *p = '\0'; - if ((s = strrdirsep(b = buf)) != 0 && !strpbrk(s, "*?")) { + if ((s = strrdirsep(b = buf, p, enc)) != 0 && !strpbrk(s, "*?")) { + VALUE tmp, v; size_t len; - WIN32_FIND_DATA wfd; + rb_encoding *enc; + WCHAR *wstr; + WIN32_FIND_DATAW wfd; HANDLE h; #ifdef __CYGWIN__ #ifdef HAVE_CYGWIN_CONV_PATH @@ -3143,21 +3179,43 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na } *p = '/'; #endif - h = FindFirstFile(b, &wfd); + rb_str_set_len(result, p - buf + strlen(p)); + enc = rb_enc_get(result); + tmp = result; + if (enc != rb_utf8_encoding() && rb_enc_str_coderange(result) != ENC_CODERANGE_7BIT) { + tmp = rb_str_encode_ospath(result); + } + len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0); + wstr = ALLOCV_N(WCHAR, v, len); + MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, wstr, len); + if (tmp != result) rb_str_resize(tmp, 0); + h = FindFirstFileW(wstr, &wfd); + ALLOCV_END(v); if (h != INVALID_HANDLE_VALUE) { + size_t wlen; FindClose(h); - len = strlen(wfd.cFileName); + len = lstrlenW(wfd.cFileName); #ifdef __CYGWIN__ if (lnk_added && len > 4 && - STRCASECMP(wfd.cFileName + len - 4, ".lnk") == 0) { - wfd.cFileName[len -= 4] = '\0'; + wcsicmp(wfd.cFileName + len - 4, L".lnk") == 0) { + wfd.cFileName[len -= 4] = L'\0'; } #else p = (char *)s; #endif ++p; + wlen = (int)len; + len = WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, NULL, 0, NULL, NULL); BUFCHECK(bdiff + len >= buflen); - memcpy(p, wfd.cFileName, len + 1); + WideCharToMultiByte(CP_UTF8, 0, wfd.cFileName, wlen, p, len + 1, NULL, NULL); + if (tmp != result) { + rb_str_buf_cat(tmp, p, len); + tmp = rb_str_encode(tmp, rb_enc_from_encoding(enc), 0, Qnil); + len = RSTRING_LEN(tmp); + BUFCHECK(bdiff + len >= buflen); + memcpy(p, RSTRING_PTR(tmp), len); + rb_str_resize(tmp, 0); + } p += len; } #ifdef __CYGWIN__ @@ -3266,23 +3324,27 @@ rb_file_s_absolute_path(int argc, VALUE *argv) } static void -realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopcheck, int strict, int last) +realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE loopcheck, int strict, int last) { + const char *pend = unresolved + strlen(unresolved); + rb_encoding *enc = rb_enc_get(*resolvedp); ID resolving; CONST_ID(resolving, "resolving"); - while (*unresolved) { - char *testname = unresolved; - char *unresolved_firstsep = rb_path_next(unresolved); - long testnamelen = unresolved_firstsep - unresolved; - char *unresolved_nextname = unresolved_firstsep; - while (isdirsep(*unresolved_nextname)) unresolved_nextname++; + while (unresolved < pend) { + const char *testname = unresolved; + const char *unresolved_firstsep = rb_enc_path_next(unresolved, pend, enc); + long testnamelen = unresolved_firstsep - unresolved; + const char *unresolved_nextname = unresolved_firstsep; + while (unresolved_nextname < pend && isdirsep(*unresolved_nextname)) + unresolved_nextname++; unresolved = unresolved_nextname; if (testnamelen == 1 && testname[0] == '.') { } else if (testnamelen == 2 && testname[0] == '.' && testname[1] == '.') { if (*prefixlenp < RSTRING_LEN(*resolvedp)) { - char *resolved_names = RSTRING_PTR(*resolvedp) + *prefixlenp; - char *lastsep = rb_path_last_separator(resolved_names); + const char *resolved_str = RSTRING_PTR(*resolvedp); + const char *resolved_names = resolved_str + *prefixlenp; + const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc); long len = lastsep ? lastsep - resolved_names : 0; rb_str_resize(*resolvedp, *prefixlenp + len); } @@ -3321,23 +3383,24 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, char *unresolved, VALUE loopche } #ifdef HAVE_READLINK if (S_ISLNK(sbuf.st_mode)) { - volatile VALUE link; - char *link_prefix, *link_names; + VALUE link; + const char *link_prefix, *link_names; long link_prefixlen; rb_hash_aset(loopcheck, testpath, ID2SYM(resolving)); - link = rb_file_s_readlink(rb_cFile, testpath); + link = rb_readlink(testpath); link_prefix = RSTRING_PTR(link); - link_names = skipprefixroot(link_prefix); - link_prefixlen = link_names - link_prefix; - if (link_prefixlen == 0) { - realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0'); - } - else { - *resolvedp = rb_str_new(link_prefix, link_prefixlen); - *prefixlenp = link_prefixlen; - realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0'); - } - rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp)); + link_names = skipprefixroot(link_prefix, link_prefix + RSTRING_LEN(link), rb_enc_get(link)); + link_prefixlen = link_names - link_prefix; + if (link_prefixlen > 0) { + rb_encoding *enc, *linkenc = rb_enc_get(link); + link = rb_str_subseq(link, 0, link_prefixlen); + enc = rb_enc_check(*resolvedp, link); + if (enc != linkenc) link = rb_str_conv_enc(link, linkenc, enc); + *resolvedp = link; + *prefixlenp = link_prefixlen; + } + realpath_rec(prefixlenp, resolvedp, link_names, loopcheck, strict, *unresolved_firstsep == '\0'); + rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp)); } else #endif @@ -3360,8 +3423,10 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict) VALUE loopcheck; volatile VALUE curdir = Qnil; + rb_encoding *enc; char *path_names = NULL, *basedir_names = NULL, *curdir_names = NULL; - char *ptr, *prefixptr = NULL; + char *ptr, *prefixptr = NULL, *pend; + long len; rb_secure(2); @@ -3373,34 +3438,33 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict) basedir = rb_str_dup_frozen(basedir); } - ptr = RSTRING_PTR(unresolved_path); - path_names = skipprefixroot(ptr); + RSTRING_GETMEM(unresolved_path, ptr, len); + path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path)); if (ptr != path_names) { - resolved = rb_enc_str_new(ptr, path_names - ptr, - rb_enc_get(unresolved_path)); + resolved = rb_str_subseq(unresolved_path, 0, path_names - ptr); goto root_found; } if (!NIL_P(basedir)) { - ptr = RSTRING_PTR(basedir); - basedir_names = skipprefixroot(ptr); + RSTRING_GETMEM(basedir, ptr, len); + basedir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(basedir)); if (ptr != basedir_names) { - resolved = rb_enc_str_new(ptr, basedir_names - ptr, - rb_enc_get(basedir)); - goto root_found; + resolved = rb_str_subseq(basedir, 0, basedir_names - ptr); + goto root_found; } } curdir = rb_dir_getwd(); - ptr = RSTRING_PTR(curdir); - curdir_names = skipprefixroot(ptr); - resolved = rb_enc_str_new(ptr, curdir_names - ptr, rb_enc_get(curdir)); + RSTRING_GETMEM(curdir, ptr, len); + curdir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(curdir)); + resolved = rb_str_subseq(curdir, 0, curdir_names - ptr); root_found: - prefixptr = RSTRING_PTR(resolved); - prefixlen = RSTRING_LEN(resolved); - ptr = chompdirsep(prefixptr); - if (*ptr) { + RSTRING_GETMEM(resolved, prefixptr, prefixlen); + pend = prefixptr + prefixlen; + enc = rb_enc_get(resolved); + ptr = chompdirsep(prefixptr, pend, enc); + if (ptr < pend) { prefixlen = ++ptr - prefixptr; rb_str_set_len(resolved, prefixlen); } @@ -3409,7 +3473,7 @@ rb_realpath_internal(VALUE basedir, VALUE path, int strict) if (*prefixptr == FILE_ALT_SEPARATOR) { *prefixptr = '/'; } - prefixptr = CharNext(prefixptr); + Inc(prefixptr, pend, enc); } #endif @@ -3466,45 +3530,52 @@ rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass) } static size_t -rmext(const char *p, long l0, long l1, const char *e) +rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc) { - long l2; + int len1, len2; + unsigned int c; + const char *s, *last; if (!e) return 0; - l2 = strlen(e); - if (!l2) return 0; - if (l2 == 2 && e[1] == '*') { - unsigned char c = *e; + c = rb_enc_codepoint_len(e, e + l2, &len1, enc); + if (rb_enc_ascget(e + len1, e + l2, &len2, enc) == '*' && len1 + len2 == l2) { + if (c == '.') return l0; + s = p; e = p + l1; - do { - if (e <= p + l0) return 0; - } while (*--e != c); - return e - p; + last = e; + while (s < e) { + if (rb_enc_codepoint_len(s, e, &len1, enc) == c) last = s; + s += len1; + } + return last - p; } if (l1 < l2) return l1; + s = p+l1-l2; + if (rb_enc_left_char_head(p, s, p+l1, enc) != s) return 0; #if CASEFOLD_FILESYSTEM #define fncomp strncasecmp #else #define fncomp strncmp #endif - if (fncomp(p+l1-l2, e, l2) == 0) { + if (fncomp(s, e, l2) == 0) { return l1-l2; } return 0; } const char * -ruby_find_basename(const char *name, long *baselen, long *alllen) +ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc) { - const char *p, *q, *e; + const char *p, *q, *e, *end; #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC const char *root; #endif long f = 0, n = -1; - name = skipprefix(name); + end = name + *alllen; + name = skipprefix(name, end, enc); #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC root = name; #endif @@ -3531,19 +3602,19 @@ ruby_find_basename(const char *name, long *baselen, long *alllen) #endif } else { - if (!(p = strrdirsep(name))) { + if (!(p = strrdirsep(name, end, enc))) { p = name; } else { while (isdirsep(*p)) p++; /* skip last / */ } #if USE_NTFS - n = ntfs_tail(p) - p; + n = ntfs_tail(p, end, enc) - p; #else - n = chompdirsep(p) - p; + n = chompdirsep(p, end, enc) - p; #endif for (q = p; q - p < n && *q == '.'; q++); - for (e = 0; q - p < n; q = CharNext(q)) { + for (e = 0; q - p < n; Inc(q, end, enc)) { if (*q == '.') e = q; } if (e) f = e - p; @@ -3577,6 +3648,7 @@ rb_file_s_basename(int argc, VALUE *argv) VALUE fname, fext, basename; const char *name, *p; long f, n; + rb_encoding *enc; if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { rb_encoding *enc; @@ -3587,15 +3659,29 @@ rb_file_s_basename(int argc, VALUE *argv) } } FilePathStringValue(fname); - if (!NIL_P(fext)) rb_enc_check(fname, fext); - if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) + if (!NIL_P(fext)) enc = rb_enc_check(fname, fext); + else enc = rb_enc_get(fname); + if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname))) return rb_str_new_shared(fname); - p = ruby_find_basename(name, &f, &n); + p = ruby_enc_find_basename(name, &f, &n, enc); if (n >= 0) { - if (NIL_P(fext) || !(f = rmext(p, f, n, StringValueCStr(fext)))) { + if (NIL_P(fext)) { f = n; } + else { + rb_encoding *fenc = rb_enc_get(fext); + const char *fp; + if (enc != fenc && + rb_enc_str_coderange(fext) != ENC_CODERANGE_7BIT) { + fext = rb_str_conv_enc(fext, fenc, enc); + } + fp = StringValueCStr(fext); + if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) { + f = n; + } + RB_GC_GUARD(fext); + } if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname); } @@ -3626,20 +3712,23 @@ rb_file_s_dirname(VALUE klass, VALUE fname) VALUE rb_file_dirname(VALUE fname) { - const char *name, *root, *p; + const char *name, *root, *p, *end; VALUE dirname; + rb_encoding *enc; FilePathStringValue(fname); name = StringValueCStr(fname); - root = skiproot(name); + end = name + RSTRING_LEN(fname); + enc = rb_enc_get(fname); + root = skiproot(name, end, enc); #ifdef DOSISH_UNC if (root > name + 1 && isdirsep(*name)) - root = skipprefix(name = root - 2); + root = skipprefix(name = root - 2, end, enc); #else if (root > name + 1) name = root - 1; #endif - p = strrdirsep(root); + p = strrdirsep(root, end, enc); if (!p) { p = root; } @@ -3647,7 +3736,7 @@ rb_file_dirname(VALUE fname) return rb_usascii_str_new2("."); #ifdef DOSISH_DRIVE_LETTER if (has_drive_letter(name) && isdirsep(*(name + 2))) { - const char *top = skiproot(name + 2); + const char *top = skiproot(name + 2, end, enc); dirname = rb_str_new(name, 3); rb_str_cat(dirname, top, p - top); } @@ -3676,11 +3765,11 @@ rb_file_dirname(VALUE fname) * */ const char * -ruby_find_extname(const char *name, long *len) +ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc) { - const char *p, *e; + const char *p, *e, *end = name + (len ? *len : (long)strlen(name)); - p = strrdirsep(name); /* get the last path component */ + p = strrdirsep(name, end, enc); /* get the last path component */ if (!p) p = name; else @@ -3713,7 +3802,7 @@ ruby_find_extname(const char *name, long *len) #endif else if (isdirsep(*p)) break; - p = CharNext(p); + Inc(p, end, enc); } if (len) { @@ -3751,11 +3840,11 @@ rb_file_s_extname(VALUE klass, VALUE fname) FilePathStringValue(fname); name = StringValueCStr(fname); - e = ruby_find_extname(name, &len); + len = RSTRING_LEN(fname); + e = ruby_enc_find_extname(name, &len, rb_enc_get(fname)); if (len <= 1) return rb_str_new(0, 0); - extname = rb_str_new(e, len); /* keep the dot, too! */ - rb_enc_copy(extname, fname); + extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */ OBJ_INFECT(extname, fname); return extname; } @@ -3818,8 +3907,9 @@ rb_file_join(VALUE ary, VALUE sep) len = 1; for (i=0; i<RARRAY_LEN(ary); i++) { - if (TYPE(RARRAY_PTR(ary)[i]) == T_STRING) { - len += RSTRING_LEN(RARRAY_PTR(ary)[i]); + tmp = RARRAY_PTR(ary)[i]; + if (RB_TYPE_P(tmp, T_STRING)) { + len += RSTRING_LEN(tmp); } else { len += 10; @@ -3852,11 +3942,12 @@ rb_file_join(VALUE ary, VALUE sep) FilePathStringValue(tmp); } name = StringValueCStr(result); + len = RSTRING_LEN(result); if (i == 0) { rb_enc_copy(result, tmp); } else if (!NIL_P(sep)) { - tail = chompdirsep(name); + tail = chompdirsep(name, name + len, rb_enc_get(result)); if (RSTRING_PTR(tmp) && isdirsep(RSTRING_PTR(tmp)[0])) { rb_str_set_len(result, tail - name); } @@ -4992,6 +5083,8 @@ path_check_0(VALUE path, int execpath) { struct stat st; const char *p0 = StringValueCStr(path); + const char *e0; + rb_encoding *enc; char *p = 0, *s; if (!rb_is_absolute_path(p0)) { @@ -5006,6 +5099,8 @@ path_check_0(VALUE path, int execpath) path = newpath; p0 = RSTRING_PTR(path); } + e0 = p0 + RSTRING_LEN(path); + enc = rb_enc_get(path); for (;;) { #ifndef S_IWOTH # define S_IWOTH 002 @@ -5022,10 +5117,11 @@ path_check_0(VALUE path, int execpath) RB_GC_GUARD(path); return 0; } - s = strrdirsep(p0); + s = strrdirsep(p0, e0, enc); if (p) *p = '/'; if (!s || s == p0) return 1; p = s; + e0 = p; *p = '\0'; } } diff --git a/include/ruby/encoding.h b/include/ruby/encoding.h index 058462fd24..cced3d2688 100644 --- a/include/ruby/encoding.h +++ b/include/ruby/encoding.h @@ -211,6 +211,12 @@ void rb_enc_set_default_external(VALUE encoding); void rb_enc_set_default_internal(VALUE encoding); VALUE rb_locale_charmap(VALUE klass); long rb_memsearch(const void*,long,const void*,long,rb_encoding*); +char *rb_enc_path_next(const char *,const char *,rb_encoding*); +char *rb_enc_path_skip_prefix(const char *,const char *,rb_encoding*); +char *rb_enc_path_last_separator(const char *,const char *,rb_encoding*); +char *rb_enc_path_end(const char *,const char *,rb_encoding*); +const char *ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encoding *enc); +const char *ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc); RUBY_EXTERN VALUE rb_cEncoding; #define ENC_DUMMY_FLAG (1<<24) diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 6dec838e75..927b536678 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -402,15 +402,9 @@ int rb_find_file_ext_safe(VALUE*, const char* const*, int); VALUE rb_find_file_safe(VALUE, int); int rb_find_file_ext(VALUE*, const char* const*); VALUE rb_find_file(VALUE); -char *rb_path_next(const char *); -char *rb_path_skip_prefix(const char *); -char *rb_path_last_separator(const char *); -char *rb_path_end(const char *); VALUE rb_file_directory_p(VALUE,VALUE); VALUE rb_str_encode_ospath(VALUE); int rb_is_absolute_path(const char *); -const char *ruby_find_basename(const char *name, long *baselen, long *alllen); -const char *ruby_find_extname(const char *name, long *len); /* gc.c */ void ruby_set_stack_size(size_t); NORETURN(void rb_memerror(void)); diff --git a/include/ruby/util.h b/include/ruby/util.h index 40f044d3cb..e82f537728 100644 --- a/include/ruby/util.h +++ b/include/ruby/util.h @@ -54,10 +54,6 @@ unsigned long ruby_scan_oct(const char *, size_t, size_t *); #define scan_hex(s,l,e) ((int)ruby_scan_hex((s),(l),(e))) unsigned long ruby_scan_hex(const char *, size_t, size_t *); -#if defined(__CYGWIN32__) || defined(_WIN32) -void ruby_add_suffix(VALUE str, const char *suffix); -#endif - void ruby_qsort(void *, const size_t, const size_t, int (*)(const void *, const void *, void *), void *); @@ -35,10 +35,6 @@ # define NO_SAFE_RENAME #endif -#if defined(__CYGWIN__) || defined(_WIN32) -# define NO_LONG_FNAME -#endif - #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(sun) || defined(_nec_ews) # define USE_SETVBUF #endif @@ -7198,15 +7194,15 @@ argf_next_argv(VALUE argf) fstat(fr, &st); if (*ARGF.inplace) { str = rb_str_new2(fn); -#ifdef NO_LONG_FNAME - ruby_add_suffix(str, ARGF.inplace); -#else rb_str_cat2(str, ARGF.inplace); -#endif #ifdef NO_SAFE_RENAME (void)close(fr); (void)unlink(RSTRING_PTR(str)); - (void)rename(fn, RSTRING_PTR(str)); + if (rename(fn, RSTRING_PTR(str)) < 0) { + rb_warn("Can't rename %s to %s: %s, skipping file", + fn, RSTRING_PTR(str), strerror(errno)); + goto retry; + } fr = rb_sysopen(str, O_RDONLY, 0); #else if (rename(fn, RSTRING_PTR(str)) < 0) { diff --git a/test/-ext-/test_add_suffix.rb b/test/-ext-/test_add_suffix.rb deleted file mode 100644 index 0520baef8c..0000000000 --- a/test/-ext-/test_add_suffix.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'test/unit' -require_relative '../ruby/envutil' -require "-test-/add_suffix/bug" - -class Test_AddSuffix < Test::Unit::TestCase - Dir = "/dev/null/".freeze - Style_1 = (Dir+"foo").freeze - - def test_style_0 - assert_equal("a.x.y", Bug.add_suffix("a.x", ".y")) - end - - def test_style_1 - assert_equal(Style_1+".y", Bug.add_suffix(Style_1+".c", ".y")) - suffix = ".bak".freeze - assert_equal(Style_1+suffix, Bug.add_suffix(Style_1.dup, suffix)) - assert_equal(Style_1+suffix, Bug.add_suffix(Style_1+".bar", suffix)) - assert_equal(Style_1+".$$$", Bug.add_suffix(Style_1+suffix, suffix)) - assert_equal(Style_1+suffix, Bug.add_suffix(Style_1+".$$$", suffix)) - assert_equal(Style_1+".~~~", Bug.add_suffix(Style_1+".$$$", ".$$$")) - assert_equal(Dir+"makefile"+suffix, Bug.add_suffix(Dir+"makefile", suffix)) - end - - def test_style_2 - suffix = "~" - assert_equal(Style_1+"~", Bug.add_suffix(Style_1.dup, suffix)) - assert_equal(Style_1+".c~", Bug.add_suffix(Style_1+".c", suffix)) - assert_equal(Style_1+".c~~", Bug.add_suffix(Style_1+".c~", suffix)) - assert_equal(Style_1+"~.c~~", Bug.add_suffix(Style_1+".c~~", suffix)) - assert_equal(Style_1+"~~.c~~", Bug.add_suffix(Style_1+"~.c~~", suffix)) - assert_equal(Style_1+"~~~~~.cc~", Bug.add_suffix(Style_1+"~~~~~.ccc", suffix)) - assert_equal(Style_1+"~~~~~.$$$", Bug.add_suffix(Style_1+"~~~~~.c~~", suffix)) - assert_equal(Dir+"foo~.pas", Bug.add_suffix(Dir+"foo.pas", suffix)) - assert_equal(Dir+"makefile.~", Bug.add_suffix(Dir+"makefile", suffix)) - assert_equal(Dir+"longname.fi~", Bug.add_suffix(Dir+"longname.fil", suffix)) - assert_equal(Dir+"longnam~.fi~", Bug.add_suffix(Dir+"longname.fi~", suffix)) - assert_equal(Dir+"longnam~.$$$", Bug.add_suffix(Dir+"longnam~.fi~", suffix)) - end - - def test_style_3 - base = "a"*1000 - suffix = "-"+"b"*1000 - assert_equal(base+".~~~", Bug.add_suffix(base, suffix)) - assert_equal(base+".~~~", Bug.add_suffix(base+".$$$", suffix)) - assert_equal(base+".$$$", Bug.add_suffix(base+".~~~", suffix)) - end -end diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb index 8a8c0d9844..61d288d68d 100644 --- a/test/pathname/test_pathname.rb +++ b/test/pathname/test_pathname.rb @@ -1,5 +1,3 @@ -#!/usr/bin/env ruby - require 'test/unit' require 'pathname' @@ -185,10 +183,8 @@ class TestPathname < Test::Unit::TestCase if DOSISH defassert(:del_trailing_separator, "a", "a\\") - require 'Win32API' - if Win32API.new('kernel32', 'GetACP', nil, 'L').call == 932 - defassert(:del_trailing_separator, "\225\\", "\225\\\\") # SJIS - end + defassert(:del_trailing_separator, "\225\\".force_encoding("cp932"), "\225\\\\".force_encoding("cp932")) + defassert(:del_trailing_separator, "\225".force_encoding("cp437"), "\225\\\\".force_encoding("cp437")) end def test_plus diff --git a/test/ruby/test_argf.rb b/test/ruby/test_argf.rb index bf6996f0de..2f1ddf5391 100644 --- a/test/ruby/test_argf.rb +++ b/test/ruby/test_argf.rb @@ -201,21 +201,14 @@ class TestArgf < Test::Unit::TestCase t = make_tempfile assert_in_out_err(["-", t.path], <<-INPUT) do |r, e| - ARGF.inplace_mode = '/\\\\' + ARGF.inplace_mode = '/\\\\:' while line = ARGF.gets puts line.chomp + '.new' end INPUT - if no_safe_rename - assert_equal([], e) - assert_equal([], r) - assert_equal("foo.new\nbar.new\nbaz.new\n", File.read(t.path)) - File.unlink(t.path + ".~~~") rescue nil - else - assert_match(/Can't rename .* to .*: .*. skipping file/, e.first) #' - assert_equal([], r) - assert_equal("foo\nbar\nbaz\n", File.read(t.path)) - end + assert_match(/Can't rename .* to .*: .*. skipping file/, e.first) #' + assert_equal([], r) + assert_equal("foo\nbar\nbaz\n", File.read(t.path)) end end diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb index 02a4730ba2..44b454a773 100644 --- a/test/ruby/test_file_exhaustive.rb +++ b/test/ruby/test_file_exhaustive.rb @@ -403,10 +403,10 @@ class TestFileExhaustive < Test::Unit::TestCase 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')) end - if drive = Dir.pwd[%r'\A(?:[a-z]:|//[^/]+/[^/]+)'i] + if DRIVE assert_match(%r"\Az:/foo\z"i, File.expand_path('/foo', "z:/bar")) assert_match(%r"\A//host/share/foo\z"i, File.expand_path('/foo', "//host/share/bar")) - assert_match(%r"\A#{drive}/foo\z"i, File.expand_path('/foo')) + assert_match(%r"\A#{DRIVE}/foo\z"i, File.expand_path('/foo')) else assert_equal("/foo", File.expand_path('/foo')) end @@ -477,7 +477,6 @@ class TestFileExhaustive < Test::Unit::TestCase ENV["HOMEPATH"] = home_path ENV["USERPROFILE"] = user_profile end - assert_incompatible_encoding {|d| File.expand_path(d)} end def test_expand_path_remove_trailing_alternative_data @@ -683,16 +682,31 @@ class TestFileExhaustive < Test::Unit::TestCase assert_equal(basename, File.basename(@file + ".", ".*")) assert_equal(basename, File.basename(@file + "::$DATA", ".*")) end + if File::ALT_SEPARATOR == '\\' + a = "foo/\225\\\\" + [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.basename(a.dup.force_encoding(cp)), cp) + end + end assert_incompatible_encoding {|d| File.basename(d)} assert_incompatible_encoding {|d| File.basename(d, ".*")} assert_raise(Encoding::CompatibilityError) {File.basename("foo.ext", ".*".encode("utf-16le"))} + + s = "foo\x93_a".force_encoding("cp932") + assert_equal(s, File.basename(s, "_a")) end def test_dirname assert(@file.start_with?(File.dirname(@file))) assert_equal(".", File.dirname("")) assert_incompatible_encoding {|d| File.dirname(d)} + if File::ALT_SEPARATOR == '\\' + a = "\225\\\\foo" + [%W"cp437 \225", %W"cp932 \225\\"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.dirname(a.dup.force_encoding(cp)), cp) + end + end end def test_extname @@ -736,6 +750,13 @@ class TestFileExhaustive < Test::Unit::TestCase def o.to_path; "foo"; end assert_equal(s, File.join(o, "bar", "baz")) assert_equal(s, File.join("foo" + File::SEPARATOR, "bar", File::SEPARATOR + "baz")) + if File::ALT_SEPARATOR == '\\' + a = "\225\\" + b = "foo" + [%W"cp437 \225\\foo", %W"cp932 \225\\/foo"].each do |cp, expected| + assert_equal(expected.force_encoding(cp), File.join(a.dup.force_encoding(cp), b.dup.force_encoding(cp)), cp) + end + end end def test_truncate @@ -184,184 +184,6 @@ ruby_strtoul(const char *str, char **endptr, int base) # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif -#if defined(__CYGWIN32__) || defined(_WIN32) -/* - * Copyright (c) 1993, Intergraph Corporation - * - * You may distribute under the terms of either the GNU General Public - * License or the Artistic License, as specified in the perl README file. - * - * Various Unix compatibility functions and NT specific functions. - * - * Some of this code was derived from the MSDOS port(s) and the OS/2 port. - * - */ - - -/* - * Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!). - * - * Here are the rules: - * - * Style 0: Append the suffix exactly as standard perl would do it. - * If the filesystem groks it, use it. (HPFS will always - * grok it. So will NTFS. FAT will rarely accept it.) - * - * Style 1: The suffix begins with a '.'. The extension is replaced. - * If the name matches the original name, use the fallback method. - * - * Style 2: The suffix is a single character, not a '.'. Try to add the - * suffix to the following places, using the first one that works. - * [1] Append to extension. - * [2] Append to filename, - * [3] Replace end of extension, - * [4] Replace end of filename. - * If the name matches the original name, use the fallback method. - * - * Style 3: Any other case: Ignore the suffix completely and use the - * fallback method. - * - * Fallback method: Change the extension to ".$$$". If that matches the - * original name, then change the extension to ".~~~". - * - * If filename is more than 1000 characters long, we die a horrible - * death. Sorry. - * - * The filename restriction is a cheat so that we can use buf[] to store - * assorted temporary goo. - * - * Examples, assuming style 0 failed. - * - * suffix = ".bak" (style 1) - * foo.bar => foo.bak - * foo.bak => foo.$$$ (fallback) - * makefile => makefile.bak - * suffix = ".$$$" (style 1) - * foo.$$$ => foo.~~~ (fallback) - * - * suffix = "~" (style 2) - * foo.c => foo.c~ - * foo.c~ => foo.c~~ - * foo.c~~ => foo~.c~~ - * foo~.c~~ => foo~~.c~~ - * foo~~~~~.c~~ => foo~~~~~.$$$ (fallback) - * - * foo.pas => foo~.pas - * makefile => makefile.~ - * longname.fil => longname.fi~ - * longname.fi~ => longnam~.fi~ - * longnam~.fi~ => longnam~.$$$ - * - */ - - -static int valid_filename(const char *s); - -static const char suffix1[] = ".$$$"; -static const char suffix2[] = ".~~~"; - -#define strEQ(s1,s2) (strcmp((s1),(s2)) == 0) - -void -ruby_add_suffix(VALUE str, const char *suffix) -{ - long baselen; - long extlen = strlen(suffix); - long slen; - char buf[1024]; - const char *name; - const char *ext; - long len; - - name = StringValueCStr(str); - slen = strlen(name); - if (slen > (long)(sizeof(buf) - 1)) - rb_fatal("Cannot do inplace edit on long filename (%ld characters)", - slen); - - /* Style 0 */ - rb_str_cat(str, suffix, extlen); - if (valid_filename(RSTRING_PTR(str))) return; - - /* Fooey, style 0 failed. Fix str before continuing. */ - rb_str_resize(str, slen); - name = StringValueCStr(str); - ext = ruby_find_extname(name, &len); - - if (*suffix == '.') { /* Style 1 */ - if (ext) { - if (strEQ(ext, suffix)) { - extlen = sizeof(suffix1) - 1; /* suffix2 must be same length */ - suffix = strEQ(suffix, suffix1) ? suffix2 : suffix1; - } - slen = ext - name; - } - rb_str_resize(str, slen); - rb_str_cat(str, suffix, extlen); - } - else { - char *p = buf, *q; - strncpy(buf, name, slen); - if (ext) - p += (ext - name); - else - p += slen; - p[len] = '\0'; - if (suffix[1] == '\0') { /* Style 2 */ - q = (char *)ruby_find_basename(buf, &baselen, 0); - if (len <= 3) { - if (len == 0 && baselen >= 8 && p + 3 <= buf + sizeof(buf)) p[len++] = '.'; /* DOSISH */ - p[len] = *suffix; - p[++len] = '\0'; - } - else if (q && baselen < 8) { - q += baselen; - *q++ = *suffix; - if (ext) { - strncpy(q, ext, ext - name); - q[ext - name + 1] = '\0'; - } - else - *q = '\0'; - } - else if (len == 4 && p[3] != *suffix) - p[3] = *suffix; - else if (baselen == 8 && q[7] != *suffix) - q[7] = *suffix; - else - goto fallback; - } - else { /* Style 3: Panic */ - fallback: - (void)memcpy(p, !ext || strEQ(ext, suffix1) ? suffix2 : suffix1, 5); - } - rb_str_resize(str, strlen(buf)); - memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str)); - } -} - -static int -valid_filename(const char *s) -{ - int fd; - - /* - // It doesn't exist, so see if we can open it. - */ - - if ((fd = open(s, O_CREAT|O_EXCL, 0666)) >= 0) { - close(fd); - unlink(s); /* don't leave it laying around */ - return 1; - } - else if (errno == EEXIST) { - /* if the file exists, then it's a valid filename! */ - return 1; - } - return 0; -} -#endif - /* mm.c */ @@ -1,5 +1,5 @@ #define RUBY_VERSION "1.9.3" -#define RUBY_PATCHLEVEL 302 +#define RUBY_PATCHLEVEL 303 #define RUBY_RELEASE_DATE "2012-10-26" #define RUBY_RELEASE_YEAR 2012 |