[m-rev.] for review: fix dir.m Cygwin bugs
Simon Taylor
stayl at cs.mu.OZ.AU
Thu Jul 24 03:27:52 AEST 2003
Estimated hours taken: 3
Branches: main
Fix bugs in my changes to dir.m which caused problems running
the compiler on Cygwin.
library/dir.m:
Handle Windows paths correctly on Cygwin.
library/io.m:
Add io__have_cygwin, which succeeds if the process
is compiled against the Cygwin library.
Index: library/dir.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/dir.m,v
retrieving revision 1.17
diff -u -u -r1.17 dir.m
--- library/dir.m 21 Jul 2003 14:08:40 -0000 1.17
+++ library/dir.m 23 Jul 2003 16:12:09 -0000
@@ -12,9 +12,11 @@
%
% Note that the predicates and functions in this module change
% directory separators in paths passed to them to the normal
-% separator for the platform. Duplicate directory separators
-% and trailing separators are also removed where that doesn't
-% change the meaning of the path name.
+% separator for the platform, if that doesn't change the meaning
+% of the path name.
+%
+% Duplicate directory separators and trailing separators are also
+% removed where that doesn't change the meaning of the path name.
%
%-----------------------------------------------------------------------------%
@@ -64,6 +66,9 @@
% On Windows, drive current directories are handled correctly,
% for example `dir__split_name("C:foo", "C:", "foo")'.
% (`X:' is the current directory on drive `X').
+ % Note that Cygwin doesn't support drive current directories,
+ % so `dir__split_name("C:foo, _, _)' will fail when running
+ % under Cygwin.
:- pred dir__split_name(string::in, string::out, string::out) is semidet.
% dir__basename(PathName) = BaseName.
@@ -235,7 +240,7 @@
:- func dir__alt_directory_separator = char.
-dir__alt_directory_separator = ('/').
+dir__alt_directory_separator = (io__have_cygwin -> ('\\') ; ('/')).
:- pragma foreign_proc("C#", dir__alt_directory_separator = (Sep::out),
[promise_pure, will_not_call_mercury, thread_safe],
"
@@ -373,7 +378,9 @@
\+ (
dir__is_directory_separator(Sep),
(
- use_windows_paths,
+ ( use_windows_paths
+ ; io__have_cygwin
+ ),
RevDirName1 = [(':'), Drive],
char__is_alpha(Drive)
;
@@ -436,17 +443,22 @@
(
% Windows allows path names of the form "\\server\share".
% These path names are referred to as UNC path names.
- use_windows_paths,
+ ( use_windows_paths ; io__have_cygwin ),
FileName0 = [Char1 | FileName1],
is_directory_separator(Char1)
->
+ % On Cygwin "//" is different to "\\"
+ % ("//" is the Cygwin root directory, "\\" is
+ % the root directory of the current drive).
+ CanonicalChar1 =
+ ( io__have_cygwin -> Char1 ; directory_separator ),
FileName2 = canonicalize_path_chars_2(FileName1, []),
% "\\" isn't a UNC path name, so it is equivalent to "\".
( FileName2 = [Char2], is_directory_separator(Char2) ->
- FileName = FileName2
+ FileName = [CanonicalChar1]
;
- FileName = [directory_separator | FileName2]
+ FileName = [CanonicalChar1 | FileName2]
)
;
FileName = canonicalize_path_chars_2(FileName0, [])
@@ -458,8 +470,14 @@
canonicalize_path_chars_2([C0 | FileName0], RevFileName0) =
canonicalize_path_chars_2(FileName0, RevFileName) :-
% Convert all directory separators to the standard separator
- % for the platform.
- C = ( is_directory_separator(C0) -> directory_separator ; C0 ),
+ % for the platform, if that doesn't change the meaning.
+ % On Cygwin, "\foo\bar" (relative to root of current drive)
+ % is different to "/foo/bar" (relative to Cygwin root directory),
+ % so we can't convert separators.
+ C = ( if \+ io__have_cygwin, is_directory_separator(C0)
+ then directory_separator
+ else C0
+ ),
% Remove repeated directory separators.
(
@@ -494,7 +512,7 @@
is_root_directory(FileName) :-
( have_dotnet ->
is_dotnet_root_directory(string__from_char_list(FileName))
- ; use_windows_paths ->
+ ; ( use_windows_paths ; io__have_cygwin ) ->
strip_leading_win32_root_directory(FileName, [])
;
FileName = [Char],
@@ -517,11 +535,15 @@
).
% Check for `X:\'.
+ % XXX On Cygwin `C:' is treated as being identical to `C:\'.
+ % The comments in the Cygwin source imply that this behaviour
+ % may change, and it's pretty awful anyway (`C:foo' isn't the
+ % same as `C:\foo'), so we don't support it here.
:- pred strip_leading_win32_drive_root_directory(list(char)::in,
list(char)::out) is semidet.
strip_leading_win32_drive_root_directory(
- [Letter, ':', Sep| !.FileName],
+ [Letter, ':', Sep | !.FileName],
!:FileName) :-
char__is_alpha(Letter),
dir__is_directory_separator(Sep).
@@ -606,7 +628,7 @@
dir__path_name_is_absolute(FileName) :-
( have_dotnet ->
dotnet_path_name_is_absolute(FileName)
- ; use_windows_paths ->
+ ; ( use_windows_paths ; io__have_cygwin ) ->
strip_leading_win32_root_directory(
canonicalize_path_chars(
string__to_char_list(FileName)),
Index: library/io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.299
diff -u -u -r1.299 io.m
--- library/io.m 21 Jul 2003 14:08:40 -0000 1.299
+++ library/io.m 23 Jul 2003 16:12:09 -0000
@@ -1428,6 +1428,9 @@
% Succeeds iff the Win32 API is available.
:- pred have_win32 is semidet.
+% Succeeds iff the current process was compiled against the Cygwin library.
+:- pred have_cygwin is semidet.
+
% Succeeds iff the .NET class library is available.
:- pred have_dotnet is semidet.
@@ -2198,6 +2201,19 @@
[will_not_call_mercury, promise_pure, thread_safe],
"
#ifdef MR_WIN32
+ SUCCESS_INDICATOR = MR_TRUE;
+#else
+ SUCCESS_INDICATOR = MR_FALSE;
+#endif
+").
+
+have_cygwin :- semidet_fail.
+
+:- pragma foreign_proc("C",
+ have_cygwin,
+ [will_not_call_mercury, promise_pure, thread_safe],
+"
+#ifdef __CYGWIN__
SUCCESS_INDICATOR = MR_TRUE;
#else
SUCCESS_INDICATOR = MR_FALSE;
Index: tests/hard_coded/dir_test.exp3
===================================================================
RCS file: tests/hard_coded/dir_test.exp3
diff -N tests/hard_coded/dir_test.exp3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/dir_test.exp3 23 Jul 2003 16:12:25 -0000
@@ -0,0 +1,164 @@
+Directory separator is '/'.
+dir__split_name("\\server\share\foo", "\\server\share", "foo").
+""\\server\share"/"foo" = "\\server\share/foo".
+dir__dirname("\\server\share\foo") = "\\server\share".
+dir__basename("\\server\share\foo") = "foo".
+dir__path_name_is_absolute("\\server\share\foo").
+dir__path_name_is_root_directory("\\server\share\foo") failed
+
+dir__split_name("\\server\share", _, _) failed.
+dir__dirname("\\server\share") = "\\server\share".
+dir__basename("\\server\share") = _ failed.
+dir__path_name_is_absolute("\\server\share").
+dir__path_name_is_root_directory("\\server\share").
+
+dir__split_name("\\server\share\\", _, _) failed.
+dir__dirname("\\server\share\\") = "\\server\share\".
+dir__basename("\\server\share\\") = _ failed.
+dir__path_name_is_absolute("\\server\share\\").
+dir__path_name_is_root_directory("\\server\share\\").
+
+dir__split_name("C:\foo", "C:\", "foo").
+""C:\"/"foo" = "C:\foo".
+dir__dirname("C:\foo") = "C:\".
+dir__basename("C:\foo") = "foo".
+dir__path_name_is_absolute("C:\foo").
+dir__path_name_is_root_directory("C:\foo") failed
+
+dir__split_name("C:\foo\", "C:\", "foo").
+""C:\"/"foo" = "C:\foo".
+dir__dirname("C:\foo\") = "C:\".
+dir__basename("C:\foo\") = "foo".
+dir__path_name_is_absolute("C:\foo\").
+dir__path_name_is_root_directory("C:\foo\") failed
+
+dir__split_name("C:\", _, _) failed.
+dir__dirname("C:\") = "C:\".
+dir__basename("C:\") = _ failed.
+dir__path_name_is_absolute("C:\").
+dir__path_name_is_root_directory("C:\").
+
+dir__split_name("C:", _, _) failed.
+dir__dirname("C:") = ".".
+dir__basename("C:") = "C:".
+dir__path_name_is_absolute("C:") failed
+dir__path_name_is_root_directory("C:") failed
+
+dir__split_name("\", _, _) failed.
+dir__dirname("\") = "\".
+dir__basename("\") = _ failed.
+dir__path_name_is_absolute("\").
+dir__path_name_is_root_directory("\").
+
+dir__split_name("", _, _) failed.
+dir__dirname("") = ".".
+dir__basename("") = "".
+dir__path_name_is_absolute("") failed
+dir__path_name_is_root_directory("") failed
+
+dir__split_name("foo\\bar\", "foo", "bar").
+""foo"/"bar" = "foo/bar".
+dir__dirname("foo\\bar\") = "foo".
+dir__basename("foo\\bar\") = "bar".
+dir__path_name_is_absolute("foo\\bar\") failed
+dir__path_name_is_root_directory("foo\\bar\") failed
+
+dir__split_name("foo\bar\", "foo", "bar").
+""foo"/"bar" = "foo/bar".
+dir__dirname("foo\bar\") = "foo".
+dir__basename("foo\bar\") = "bar".
+dir__path_name_is_absolute("foo\bar\") failed
+dir__path_name_is_root_directory("foo\bar\") failed
+
+dir__split_name("foo", _, _) failed.
+dir__dirname("foo") = ".".
+dir__basename("foo") = "foo".
+dir__path_name_is_absolute("foo") failed
+dir__path_name_is_root_directory("foo") failed
+
+dir__split_name("/foo", "/", "foo").
+""/"/"foo" = "/foo".
+dir__dirname("/foo") = "/".
+dir__basename("/foo") = "foo".
+dir__path_name_is_absolute("/foo").
+dir__path_name_is_root_directory("/foo") failed
+
+dir__split_name("/foo//bar///", "/foo", "bar").
+""/foo"/"bar" = "/foo/bar".
+dir__dirname("/foo//bar///") = "/foo".
+dir__basename("/foo//bar///") = "bar".
+dir__path_name_is_absolute("/foo//bar///").
+dir__path_name_is_root_directory("/foo//bar///") failed
+
+dir__split_name("//foo//bar/", _, _) failed.
+dir__dirname("//foo//bar/") = "//foo/bar/".
+dir__basename("//foo//bar/") = _ failed.
+dir__path_name_is_absolute("//foo//bar/").
+dir__path_name_is_root_directory("//foo//bar/").
+
+dir__split_name("//foo//", _, _) failed.
+dir__dirname("//foo//") = "//foo/".
+dir__basename("//foo//") = _ failed.
+dir__path_name_is_absolute("//foo//").
+dir__path_name_is_root_directory("//foo//").
+
+dir__split_name("/", _, _) failed.
+dir__dirname("/") = "/".
+dir__basename("/") = _ failed.
+dir__path_name_is_absolute("/").
+dir__path_name_is_root_directory("/").
+
+dir__split_name("//", _, _) failed.
+dir__dirname("//") = "/".
+dir__basename("//") = _ failed.
+dir__path_name_is_absolute("//").
+dir__path_name_is_root_directory("//").
+
+dir__split_name("foo/bar", "foo", "bar").
+""foo"/"bar" = "foo/bar".
+dir__dirname("foo/bar") = "foo".
+dir__basename("foo/bar") = "bar".
+dir__path_name_is_absolute("foo/bar") failed
+dir__path_name_is_root_directory("foo/bar") failed
+
+"C:"/"foo" = "C:/foo".
+"C:\"/"foo" = "C:\foo".
+"C:"/"C:" = "C:/C:".
+"C:"/"C:\foo" threw exception: software_error("dir./: second argument is absolute")
+"."/"/foo" threw exception: software_error("dir./: second argument is absolute")
+"."/"\foo" threw exception: software_error("dir./: second argument is absolute")
+"foo"/"bar/baz" = "foo/bar/baz".
+"foo/"/"bar/baz" = "foo/bar/baz".
+checking whether `unwritable' is readable...ok
+unwritable file found to be unwritable
+make_directory succeeded
+make_directory succeeded
+dir.make_single_directory with non-existent parent failed as expected.
+make_single_directory succeeded
+make_single_directory 2 succeeded
+file_type succeeded
+type of test_dir/d1 is directory
+file_type 2 succeeded
+type of dir_test.m is regular_file
+touching file succeeded
+touching file succeeded
+touching file succeeded
+touching file succeeded
+creating directory with same name as ordinary file failed (as expected).
+making symlink 1 succeeded
+making symlink 2 succeeded
+making symlink 3 succeeded
+following symlink succeeded
+test_dir/d1/bar points to baz
+file_type 3 succeeded
+type of test_dir/d1/bar is symbolic_link
+dir__foldl2 succeeded
+Files in test_dir:
+test_dir/d1, test_dir/d2, test_dir/quark, test_dir/queeg, test_dir/d3
+dir__recursive_foldl2 (no symlinks) succeeded
+Files in test_dir (recursive, not following symlinks):
+test_dir/d1, test_dir/d1/foo, test_dir/d1/baz, test_dir/d1/bar, test_dir/d1/parent, test_dir/d2, test_dir/d2/d2, test_dir/quark, test_dir/queeg, test_dir/d3
+dir__recursive_foldl2 (symlinks) succeeded
+Files in test_dir (recursive, following symlinks:
+test_dir/d1, test_dir/d1/foo, test_dir/d1/baz, test_dir/d1/bar, test_dir/d1/parent, test_dir/d2, test_dir/d2/d2, test_dir/quark, test_dir/queeg, test_dir/d3, test_dir/d3/foo, test_dir/d3/baz, test_dir/d3/bar, test_dir/d3/parent
+dir.recursive_foldl2(list_files, "dir_test.m", ...) failed as expected.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list