# # 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; }