The unified diff between revisions [850c20aa..] and [a80e1661..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'paths.cc'

#
#
# patch "paths.cc"
#  from [3ea54d2be240cc811a52130f6711f3c3ae410763]
#    to [b77289a76e8d3c43a1dc2467c7b679c1aa6f9ca9]
#
============================================================
--- paths.cc	3ea54d2be240cc811a52130f6711f3c3ae410763
+++ paths.cc	b77289a76e8d3c43a1dc2467c7b679c1aa6f9ca9
@@ -27,6 +27,7 @@ struct access_tracker
   void set(T const & val, bool may_be_initialized)
   {
     I(may_be_initialized || !initialized);
+    I(!very_uninitialized);
     I(!used);
     initialized = true;
     value = val;
@@ -42,14 +43,19 @@ struct access_tracker
     I(initialized);
     return value;
   }
+  void may_not_initialize()
+  {
+    I(!initialized);
+    very_uninitialized = true;
+  }
   // for unit tests
   void unset()
   {
-    used = initialized = false;
+    used = initialized = very_uninitialized = false;
   }
   T value;
-  bool initialized, used;
-  access_tracker() : initialized(false), used(false) {};
+  bool initialized, used, very_uninitialized;
+  access_tracker() : initialized(false), used(false), very_uninitialized(false) {};
 };

 // paths to use in interpreting paths from various sources,
@@ -165,12 +171,19 @@ file_path::file_path(file_path::source_t
     case internal:
       data = path;
       break;
-    case internal_from_user:
-      data = path;
-      N(is_valid_internal(path),
-        F("path '%s' is invalid") % path);
-      break;
     case external:
+      if (!initial_rel_path.initialized)
+	{
+	  // we are not in a working directory; treat this as an internal
+	  // path, and set the access_tracker() into a very uninitialised
+	  // state so that we will hit an exception if we do eventually
+	  // enter a working directory
+	  initial_rel_path.may_not_initialize();
+	  data = path;
+	  N(is_valid_internal(path),
+	    F("path '%s' is invalid") % path);
+	  break;
+	}
       N(!path.empty(), F("empty path '%s' is invalid") % path);
       fs::path out, base, relative;
       try
@@ -392,7 +405,11 @@ normalize_out_dots(std::string const & p
 static std::string
 normalize_out_dots(std::string const & path)
 {
+#ifdef WIN32
+  return fs::path(path, fs::native).normalize().string();
+#else
   return fs::path(path, fs::native).normalize().native_file_string();
+#endif
 }

 system_path::system_path(any_path const & other, bool in_true_working_copy)
@@ -530,16 +547,12 @@ static void test_file_path_internal()
   for (char const ** c = baddies; *c; ++c)
     {
       BOOST_CHECK_THROW(file_path_internal(*c), std::logic_error);
-      BOOST_CHECK_THROW(file_path_internal_from_user(std::string(*c)),
-                        informative_failure);
     }
   initial_rel_path.unset();
   initial_rel_path.set(file_path_internal("blah/blah/blah"), true);
   for (char const ** c = baddies; *c; ++c)
     {
       BOOST_CHECK_THROW(file_path_internal(*c), std::logic_error);
-      BOOST_CHECK_THROW(file_path_internal_from_user(std::string(*c)),
-                        informative_failure);
     }

   BOOST_CHECK(file_path().empty());
@@ -583,8 +596,6 @@ static void test_file_path_internal()
           for (std::vector<path_component>::const_iterator i = split_test.begin();
                i != split_test.end(); ++i)
             BOOST_CHECK(!null_name(*i));
-          file_path fp_user = file_path_internal_from_user(std::string(*c));
-          BOOST_CHECK(fp == fp_user);
         }
     }

@@ -649,7 +660,9 @@ static void test_file_path_external_no_p
   check_fp_normalizes_to(".foo/bar", ".foo/bar");
   check_fp_normalizes_to("..foo/bar", "..foo/bar");
   check_fp_normalizes_to(".", "");
+#ifndef WIN32
   check_fp_normalizes_to("foo:bar", "foo:bar");
+#endif
   check_fp_normalizes_to("foo/with,other+@weird*%#$=stuff/bar",
                          "foo/with,other+@weird*%#$=stuff/bar");

@@ -698,7 +711,9 @@ static void test_file_path_external_pref
   check_fp_normalizes_to(".foo/bar", "a/b/.foo/bar");
   check_fp_normalizes_to("..foo/bar", "a/b/..foo/bar");
   check_fp_normalizes_to(".", "a/b");
+#ifndef WIN32
   check_fp_normalizes_to("foo:bar", "a/b/foo:bar");
+#endif
   check_fp_normalizes_to("foo/with,other+@weird*%#$=stuff/bar",
                          "a/b/foo/with,other+@weird*%#$=stuff/bar");
   // why are the tests with // in them commented out?  because boost::fs sucks
@@ -845,13 +860,13 @@ static void test_system_path()
 #ifdef WIN32
   check_system_normalizes_to("c:foo", "c:foo");
   check_system_normalizes_to("c:/foo", "c:/foo");
-  check_system_normalizes_to("c:\\foo", "c:\\foo");
+  check_system_normalizes_to("c:\\foo", "c:/foo");
 #else
   check_system_normalizes_to("c:foo", "/a/b/c:foo");
   check_system_normalizes_to("c:/foo", "/a/b/c:/foo");
   check_system_normalizes_to("c:\\foo", "/a/b/c:\\foo");
+  check_system_normalizes_to("foo:bar", "/a/b/foo:bar");
 #endif
-  check_system_normalizes_to("foo:bar", "/a/b/foo:bar");
   // we require that system_path normalize out ..'s, because of the following
   // case:
   //   /work mkdir newdir
@@ -870,13 +885,17 @@ static void test_system_path()
   // can't do particularly interesting checking of tilde expansion, but at
   // least we can check that it's doing _something_...
   std::string tilde_expanded = system_path("~/foo").as_external();
+#ifdef WIN32
+  BOOST_CHECK(tilde_expanded[1] == ':');
+#else
   BOOST_CHECK(tilde_expanded[0] == '/');
+#endif
   BOOST_CHECK(tilde_expanded.find('~') == std::string::npos);
   // and check for the weird WIN32 version
 #ifdef WIN32
   std::string tilde_expanded2 = system_path("~this_user_does_not_exist_anywhere").as_external();
   BOOST_CHECK(tilde_expanded2[0] = '/');
-  BOOST_CHECK(tilde_expanded.find('~') == std::string::npos);
+  BOOST_CHECK(tilde_expanded2.find('~') == std::string::npos);
 #else
   BOOST_CHECK_THROW(system_path("~this_user_does_not_exist_anywhere"), informative_failure);
 #endif
@@ -923,6 +942,13 @@ static void test_access_tracker()
   BOOST_CHECK_THROW(a.set(3, false), std::logic_error);
   BOOST_CHECK(a.get() == 2);
   BOOST_CHECK_THROW(a.set(3, true), std::logic_error);
+  a.unset();
+  a.may_not_initialize();
+  BOOST_CHECK_THROW(a.set(1, false), std::logic_error);
+  BOOST_CHECK_THROW(a.set(2, true), std::logic_error);
+  a.unset();
+  a.set(1, false);
+  BOOST_CHECK_THROW(a.may_not_initialize(), std::logic_error);
 }

 void add_paths_tests(test_suite * suite)