#
# patch "ChangeLog"
# from [2af96a9b8fae3b480d1b6a057714906ad28e98d7]
# to [db6bbb22aece4e1191dfe6c2dc8d878aeb3f70fb]
#
# patch "app_state.cc"
# from [1352a5df1824518d6d38a3267746a6afa57cb239]
# to [0c74ac9f4088c41625e4c7c508bd503479c57b5b]
#
# patch "interner.hh"
# from [56755be621a718730f8e1d3963d102b72eb272c3]
# to [a8d437360e4e6e069cb5ed9bea59a066cf975ea9]
#
# patch "paths.cc"
# from [49d6162087fab93f304518d7e6ee87557b550f88]
# to [0c1b0fce8ee57dfbde149d134ddfee6e7d00f508]
#
========================================================================
--- ChangeLog 2af96a9b8fae3b480d1b6a057714906ad28e98d7
+++ ChangeLog db6bbb22aece4e1191dfe6c2dc8d878aeb3f70fb
@@ -1,5 +1,18 @@
+2005-08-20 Nathaniel Smith
+
+ * paths.cc (is_absolute): New function.
+ (file_path::file_path(vector))
+ (file_path::split): Implement.
+
2005-08-20 Nathaniel Smith
+ * interner.hh (interner): Add a scary constructor that lets us
+ insert an initial value and assert that we already knew that the
+ value assigned to it would be. (This lets us make it an inlined
+ constant.)
+
+2005-08-20 Nathaniel Smith
+
* paths.cc: Yet more tests.
2005-08-20 Nathaniel Smith
========================================================================
--- app_state.cc 1352a5df1824518d6d38a3267746a6afa57cb239
+++ app_state.cc 0c74ac9f4088c41625e4c7c508bd503479c57b5b
@@ -274,7 +274,8 @@
options[branch_option] = branch_name();
if (found_working_copy)
{
- // already have a working copy, can (must) write options directly
+ // already have a working copy, can (must) write options directly,
+ // because no-one else will do so
// if we don't have a working copy yet, then require_working_copy (for
// instance) will call write_options when it finds one.
write_options();
========================================================================
--- interner.hh 56755be621a718730f8e1d3963d102b72eb272c3
+++ interner.hh a8d437360e4e6e069cb5ed9bea59a066cf975ea9
@@ -31,6 +31,10 @@
hmap fwd;
std::vector rev;
interner() {}
+ interner(std::string const & init_str, T init_value)
+ {
+ I(intern(init_str) == init_value);
+ }
std::string lookup (T in) const
{
std::vector::size_type k = static_cast::size_type>(in);
========================================================================
--- paths.cc 49d6162087fab93f304518d7e6ee87557b550f88
+++ paths.cc 0c1b0fce8ee57dfbde149d134ddfee6e7d00f508
@@ -1,7 +1,8 @@
#include "paths.hh"
#include "platform.hh"
#include "sanity.hh"
+// path to use when absolutifying
static std::string initial_path;
void
save_initial_path()
@@ -14,6 +15,102 @@
// string with no trailing /.
static std::string path_prefix;
+bool
+find_and_go_to_working_copy(external_path const & search_root)
+{
+ // unimplemented
+ // should do what find_working_copy in file_io.cc does, and what
+ // allow_working_copy in app_state.cc does
+ // should use change_current_working_dir when it finds the root
+ // should set path_prefix too
+ I(false);
+}
+
+static bool
+is_absolute(std::string const & path)
+{
+ if (path.empty())
+ return false;
+ if (path[0] == '/')
+ return true;
+#ifdef _WIN32
+ if (path[0] == '\\')
+ return true;
+ if (path.size() > 1 && path[1] == ':')
+ return true;
+#endif
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////
+// splitting/joining
+// this code must be superfast
+// it depends very much on knowing that it can only be applied to fully
+// normalized, relative, paths.
+/////////////////////////////////////////////////////////////////
+
+static interner pc_interner("", the_null_component);
+
+// This function takes a vector of path components and joins them into a
+// single file_path. Valid input may be a single-element vector whose sole
+// element is the empty path component (""); this represents the null path,
+// which we use to represent non-existent files. Alternatively, input may be
+// a multi-element vector, in which case all elements of the vector are
+// required to be non-null. The following are valid inputs (with strings
+// replaced by their interned version, of course):
+// - [""]
+// - ["foo"]
+// - ["foo", "bar"]
+// The following are not:
+// - []
+// - ["foo", ""]
+// - ["", "bar"]
+file_path::file_path(std::vector const & pieces)
+{
+ std::vector::const_iterator i = names.begin();
+ I(i != names.end());
+ if (names.size() > 1)
+ I(!null_name(*i));
+ data = pc_interner.lookup(*i);
+ for (++i; i != names.end(); ++i)
+ {
+ I(!null_name(*i));
+ data += "/";
+ data += pc_interner.lookup(*i);
+ }
+}
+
+//
+// this takes a path of the form
+//
+// "p[0]/p[1]/.../p[n-1]/p[n]"
+//
+// and fills in a vector of paths corresponding to p[0] ... p[n-1]
+//
+// _unlike_ the old path splitting functions, this is the inverse to the above
+// joining function. the difference is that this code always returns a vector
+// with at least one element in it; if you split the null path (""), you will
+// get a single-element vector containing the null component. with the old
+// code, in this one case, you would have gotten an empty vector.
+void
+file_path::split(std::vector & pieces)
+{
+ pieces.clear();
+ std::string::size_type start, stop;
+ start = 0;
+ while (1)
+ {
+ stop = p_str.find('/', start);
+ if (stop < 0 || stop > p_str.length())
+ {
+ pieces.push_back(pc_interner.intern(p_str.substr(start)));
+ break;
+ }
+ components.push_back(pc_interner.intern(p_str.substr(start, stop - start)));
+ start = stop + 1;
+ }
+}
+
#ifdef BUILD_UNIT_TESTS
#include "unit_tests.hh"
@@ -201,8 +298,18 @@
file_path fp3(internal, "");
pcv split3;
fp3.split(split3);
- BOOST_CHECK(split3.size() == 0);
+ BOOST_CHECK(split3.size() == 1);
+ BOOST_CHECK(null_name(split3[0]));
BOOST_CHECK(fp3 == file_path(split3));
+
+ pcv split4;
+ BOOST_CHECK_THROW(file_path(split4), logic_error);
+ split4.push_back(the_null_component);
+ BOOST_CHECK_NOT_THROW(file_path(split4), logic_error);
+ split4.push_back(split1[0]);
+ BOOST_CHECK_THROW(file_path(split4), logic_error);
+ split4.push_front(split1[0]);
+ BOOST_CHECK_THROW(file_path(split4), logic_error);
}
static void check_bk_normalizes_to(char * before, char * after)
@@ -263,7 +370,9 @@
#endif
// can't do particularly interesting checking of tilde expansion, but at
// least we can check that it's doing _something_...
- BOOST_CHECK(external_path("~/foo").as_external()[0] == '/');
+ std::string tilde_expanded = external_path("~/foo").as_external();
+ BOOST_CHECK(tilde_expanded[0] == '/');
+ BOOST_CHECK(tilde_expanded.find('~') == std::string::npos);
initial_path = initial_path_saved;
}