[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