From: "U.Nakamura" Date: 2001-07-11T20:37:33+09:00 Subject: [ruby-dev:13817] Fw: DOSISH file.c changes --------_3B4C38AAECFA033D3FE0_MULTIPART_MIXED_ Content-Type: text/plain; charset="ISO-2022-JP" Content-Transfer-Encoding: 7bit こんにちは、なかむら(う)です。 Patrick Cheng氏から下記のようなパッチを頂いているので転送し ます。 At Tue, 10 Jul 2001 00:30:49 -0700, "Patrick Cheng" wrote: > Hello, > I have made some changes to the File class to handle DOSISH file name > better, namely: > > - basname() and dirname() can split using backslash > - expand_path() to handle drive letter better. > > hopefully, some of it you might find it useful. > > Patrick Cheng あとUNC対応が必要? # マルチバイト対応は... まぁ「置き」ですかねぇ。 それでは。 -- U.Nakamura --------_3B4C38AAECFA033D3FE0_MULTIPART_MIXED_ Content-Type: text/plain; format="flowed"; name="file.patch" Content-Disposition: attachment; filename="file.patch" Content-Transfer-Encoding: 8bit --- file.c Tue Jul 10 00:05:49 2001 +++ new/file.c Mon Jul 9 23:56:05 2001 @@ -75,6 +75,9 @@ static VALUE rb_cStat; static int +is_absolute_path(path); + +static int apply2files(func, vargs, arg) int (*func)(); VALUE vargs; @@ -1345,14 +1348,62 @@ } } #if defined DOSISH - /* skip drive letter */ - else if (ISALPHA(s[0]) && s[1] == ':' && isdirsep(s[2])) { - while (*s && !isdirsep(*s)) { - *p++ = *s++; - } + else if (ISALPHA(s[0]) && s[1] == ':') { + if (isdirsep(s[2])) { + /* specified drive letter, and full path */ + /* skip drive letter */ + while (*s && !isdirsep(*s)) { + *p++ = *s++; + } + } + else { + /* specified drive, but not full path */ + char drive[3]; + char oldcwd[MAXPATHLEN+1]; + + drive[0] = *s++; + drive[1] = *s++; + drive[2] = '\0'; + + /* the only way that I know to get the current directory + of a particular drive is to change chdir() to that drive, + so save the old cwd before chdir() + */ + getcwd(oldcwd, MAXPATHLEN); + chdir(drive); + + tainted = 1; + getcwd(buf, MAXPATHLEN); + p = &buf[strlen(buf)]; + if ( *s ) + { + /* need to append '/' before appending the rest of the path */ + if (! isdirsep(*(p - 1))) *p++ = '/'; + while (*s && !isdirsep(*s)) { + *p++ = *s++; + } + } + chdir(oldcwd); + } + } +#endif +#if defined DOSISH && ! defined(__CYGWIN__) + else if (isdirsep(*s)) { + /* specified full path, but not drive letter */ + /* we need to get the drive letter */ + tainted = 1; +#ifdef HAVE_GETCWD + getcwd(buf, MAXPATHLEN); +#else + getwd(buf); +#endif + p = &buf[2]; + while (*s && !isdirsep(*s)) { + *p++ = *s++; + } } #endif - else if (!isdirsep(*s)) { + else if (!is_absolute_path(s)) { if (!NIL_P(dname)) { dname = rb_file_s_expand_path(1, &dname); if (OBJ_TAINTED(dname)) tainted = 1; @@ -1367,7 +1418,7 @@ #endif } p = &buf[strlen(buf)]; - while (p > buf && *(p - 1) == '/') p--; + while (p > buf && isdirsep(*(p - 1))) p--; } else { while (*s && isdirsep(*s)) { @@ -1418,6 +1469,13 @@ /* Place a \0 at end. If path ends with a "/", delete it */ if (p == buf || !isdirsep(*p)) p++; +#if defined(DOSISH) + if (ISALPHA(buf[0]) && buf[1] == ':' && isdirsep(buf[2])) { + /* root directory needs a trailing backslash, + otherwise it mean the current directory of the drive */ + if (p == (buf+2)) p++; + } +#endif *p = '\0'; fname = rb_str_new2(buf); @@ -1448,6 +1506,20 @@ return 0; } + +static char * +strrdirsep(name) + char *name; +{ + char *last = NULL; + do { + if (isdirsep(*name)) last = name; + name++; + } + while( *name ); + return last; +} + static VALUE rb_file_s_basename(argc, argv) int argc; @@ -1461,7 +1533,7 @@ ext = StringValuePtr(fext); } name = StringValuePtr(fname); - p = strrchr(name, '/'); + p = strrdirsep(name); if (!p) { if (NIL_P(fext) || !(f = rmext(name, ext))) return fname; @@ -1488,12 +1560,16 @@ VALUE dirname; name = StringValuePtr(fname); - p = strrchr(name, '/'); + p = strrdirsep(name); if (!p) { return rb_str_new2("."); } if (p == name) p++; +#if defined(DOSISH) + if ( ISALPHA(name[0]) && name[1] == ':' && p == &name[2]) + p++; +#endif dirname = rb_str_new(name, p - name); if (OBJ_TAINTED(fname)) OBJ_TAINT(dirname); return dirname; @@ -2121,10 +2197,11 @@ is_absolute_path(path) const char *path; { +#if ! defined(DOSISH) || defined(__CYGWIN__) if (path[0] == '/') return 1; +#endif # if defined DOSISH - if (path[0] == '\\') return 1; - if (strlen(path) > 2 && path[1] == ':') return 1; + if (strlen(path) > 3 && path[1] == ':' && isdirsep(path[2]) ) return 1; # endif return 0; } @@ -2155,7 +2232,7 @@ if (p) *p = '/'; return 0; } - s = strrchr(path, '/'); + s = strrdirsep(path); if (p) *p = '/'; if (!s || s == path) return 1; p = s; --------_3B4C38AAECFA033D3FE0_MULTIPART_MIXED_ Content-Type: text/plain; format="flowed"; name="testfile.rb" Content-Disposition: attachment; filename="testfile.rb" Content-Transfer-Encoding: 8bit require 'runit/testcase' require 'runit/cui/testrunner' require 'rbconfig' class TestFile_basename < RUNIT::TestCase def test_basename_separator dirname = 'dir' basename = 'basename.txt' expandpath = dirname + File::SEPARATOR + basename assert_equal ( basename, File.basename( expandpath ) ) end if ! File::ALT_SEPARATOR.nil? then def test_basename_alt_separator dirname = 'dir' basename = 'basename.txt' expandpath = dirname + File::ALT_SEPARATOR + basename assert_equal ( basename, File.basename( expandpath ) ) end end end class TestFile_dirname < RUNIT::TestCase def test_dirname_separator dirname = 'dir' basename = 'basename.txt' expandpath = dirname + File::SEPARATOR + basename assert_equal ( dirname, File.dirname( expandpath ) ) end if ! File::ALT_SEPARATOR.nil? then def test_dirname_alt_separator dirname = 'dir' basename = 'basename.txt' expandpath = dirname + File::ALT_SEPARATOR + basename assert_equal ( dirname, File.dirname( expandpath ) ) end end if ["mswin32"].include?( Config::CONFIG["host_os"]) then def test_dirname_dos assert_equal ( "c:/winnt/system32", File.dirname( "c:/winnt/system32/test.txt" ) ) end def test_dirname_dos_root assert_equal ( "c:/", File.dirname( "c:/test.txt" ) ) end end def test_dirname_root assert_equal ( "/", File.dirname( "/test.txt" ) ) end end class TestFile_join < RUNIT::TestCase def test_join_root assert_equal ( "/test.txt", File.join( "/", "test.txt" ) ) end def test_join_non_root assert_equal ( "/etc/test.txt", File.join( "/etc", "test.txt" ) ) end def test_join_non_root_with_trailing_slash assert_equal ( "/etc/test.txt", File.join( "/etc/", "test.txt" ) ) end end class TestFile_expand_path < RUNIT::TestCase if ! ["mswin32"].include?( Config::CONFIG["host_os"]) then def test_expand_path_root assert_equal ( "/", File::expand_path( "/" ) ) end end if ["mswin32"].include?( Config::CONFIG["host_os"]) then def test_expand_path_root Dir::chdir( "c:/winnt/system32" ) assert_equal ( "c:/", File::expand_path( "/" ) ) end def test_expand_path_dos_root_forward_slash assert_equal ( "c:/", File::expand_path( "c:/" ) ) end def test_expand_path_dos_root_backward_slash assert_equal ( "c:/", File::expand_path( "c:\\" ) ) end def test_expand_path_dos_non_root_forward_slash assert_equal ( "c:/winnt/system32/test.txt", File::expand_path( "c:/winnt/system32/test.txt" ) ) end def test_expand_path_dos_non_root_backward_slash assert_equal ( "c:/winnt/system32/test.txt", File::expand_path( "c:\\winnt\\system32\\test.txt" ) ) end def test_expand_path_dos_drive_only Dir::chdir( "c:/winnt/system32" ) assert_equal ( "c:/winnt/system32", File::expand_path( "c:" ) ) end def test_expand_path_dos_drive_relative_path Dir::chdir( "c:/winnt/system32" ) assert_equal ( "c:/winnt/system32/test.txt", File::expand_path( "c:test.txt" ) ) end end end suite = RUNIT::TestSuite.new suite.add_test(TestFile_basename.suite) suite.add_test(TestFile_dirname.suite) suite.add_test(TestFile_expand_path.suite) # join current does not deal with trailing separator #suite.add_test(TestFile_join.suite) RUNIT::CUI::TestRunner.quiet_mode = true RUNIT::CUI::TestRunner.run(suite) --------_3B4C38AAECFA033D3FE0_MULTIPART_MIXED_--