diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 6210915ec2..97990b37ae 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -241,85 +241,58 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) static mrb_value mrb_file_basename(mrb_state *mrb, mrb_value klass) { -#if defined(_WIN32) - char bname[_MAX_DIR]; - char extname[_MAX_EXT]; - char *path; - const char *suffix = NULL; - - mrb_get_args(mrb, "z|z", &path, &suffix); - size_t ridx = strlen(path); - if (ridx > 0) { - ridx--; - while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) { - path[ridx] = '\0'; - ridx--; - } - if (ridx == 0 && path[0] == '/') { - mrb_value result = mrb_str_new_cstr(mrb, path); - if (suffix && *suffix) { - mrb_int blen = RSTRING_LEN(result); - mrb_int slen = strlen(suffix); - if (blen > slen && memcmp(RSTRING_PTR(result) + blen - slen, suffix, slen) == 0) { - mrb_str_resize(mrb, result, blen - slen); - } - } - return result; - } - } - _splitpath((const char*)path, NULL, NULL, bname, extname); - mrb_value buffer = mrb_str_new_cstr(mrb, bname); - mrb_str_cat_cstr(mrb, buffer, extname); - if (suffix && *suffix) { - mrb_int blen = RSTRING_LEN(buffer); - mrb_int slen = strlen(suffix); - if (blen > slen && memcmp(RSTRING_PTR(buffer) + blen - slen, suffix, slen) == 0) { - mrb_str_resize(mrb, buffer, blen - slen); - } - } - return buffer; -#else - char *path; + const char *path; const char *suffix = NULL; mrb_get_args(mrb, "z|z", &path, &suffix); - // Copy path to a local buffer to avoid modifying the original string - size_t len = strlen(path); - if (len == 0) { + const char *endp = path + strlen(path); + if (path == endp) { return mrb_str_new_lit(mrb, "."); } +#ifdef _WIN32 + if (UNC_PATH_P(path)) { + path += 2; + SKIP_DIRSEP(path); + NEXT_DIRSEP(path); // skip server name + SKIP_DIRSEP(path); + NEXT_DIRSEP(path); // skip share name + } + else if (DRIVE_LETTER_P(path)) { + path += 2; + if (path == endp) { + return mrb_str_new_lit(mrb, ""); + } + } +#endif // _WIN32 + // Remove trailing slashes (except when path is only "/") - while (len > 1 && path[len - 1] == '/') { - len--; + while (path < endp && DIRSEP_P(endp[-1])) { + endp--; } // Find the last path separator - ssize_t base = len - 1; - while (base >= 0 && path[base] != '/') { + const char *base = endp; + while (path < base && !DIRSEP_P(base[-1])) { base--; } - base++; // move to the first character after '/' // If path is all slashes, return "/" - if ((size_t)base == len) { + if (base == endp) { return mrb_str_new_lit(mrb, "/"); } - mrb_value result = mrb_str_new(mrb, path + base, len - base); - // Suffix removal (CRuby compatible) if (suffix && *suffix) { - mrb_int blen = RSTRING_LEN(result); + mrb_int blen = endp - base; mrb_int slen = strlen(suffix); - if (blen > slen && memcmp(RSTRING_PTR(result) + blen - slen, suffix, slen) == 0) { - mrb_str_resize(mrb, result, blen - slen); + if (blen > slen && memcmp(endp - slen, suffix, slen) == 0) { + endp -= slen; } } - return result; -#endif + return mrb_str_new(mrb, base, endp - base); } static mrb_value diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index e6eda54340..fb5f16f5bd 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -57,6 +57,40 @@ def assert_dirname_with_level(path, results) assert_equal 'foo.rb', File.basename('foo.rb', '.RB') # case-sensitive end +if MRubyIOTestUtil.win? + assert('File.basename (for Windows)') do + assert_equal '/', File.basename('/') + assert_equal '/', File.basename('//a') + assert_equal '/', File.basename('//a/') + assert_equal '/', File.basename('//a/b') + assert_equal '/', File.basename('//a/b/') + assert_equal 'c', File.basename('//a/b/c') + assert_equal 'c', File.basename('//a/b/c/') + assert_equal '/', File.basename("\\\\a\\b") + assert_equal '', File.basename('c:') + assert_equal '/', File.basename('c:/') + assert_equal 'a', File.basename('c:/a') + assert_equal 'a', File.basename('c:/a/') + assert_equal 'b', File.basename('c:/a/b') + assert_equal '/', File.basename("c:\\") + end +else + assert('File.basename (for generic)') do + assert_equal '/', File.basename('/') + assert_equal 'a', File.basename('//a') + assert_equal 'a', File.basename('//a/') + assert_equal 'b', File.basename('//a/b') + assert_equal 'b', File.basename('//a/b/') + assert_equal 'c', File.basename('//a/b/c') + assert_equal 'c', File.basename('//a/b/c/') + assert_equal 'c:', File.basename('c:') + assert_equal 'c:', File.basename('c:/') + assert_equal 'a', File.basename('c:/a') + assert_equal 'a', File.basename('c:/a/') + assert_equal 'b', File.basename('c:/a/b') + end +end + assert('File.dirname') do assert_equal '.', File.dirname('') assert_equal '.', File.dirname('a')