From 9ef25ab2f9da89ab48ecce3fe1b8cbb0bc5f1e09 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 4 Mar 2015 18:04:50 +0200 Subject: Treat names that end with directory separators as directories --- build/name.cxx | 20 +++++++++++------ build/parser.cxx | 65 ++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 28 deletions(-) (limited to 'build') diff --git a/build/name.cxx b/build/name.cxx index 4ffc848..6280676 100644 --- a/build/name.cxx +++ b/build/name.cxx @@ -15,28 +15,34 @@ namespace build ostream& operator<< (ostream& os, const name& n) { - if (!n.type.empty ()) + bool ht (!n.type.empty ()); + bool hv (!n.value.empty ()); + + if (ht) os << n.type << '{'; if (!n.dir.empty ()) { string s (diag_relative_work (n.dir)); - if (s != ".") + // If both type and value are empty, there will be nothing printed. + // + if (s != "." || (!ht && !hv)) { os << s; - if (!n.value.empty () && - s.back () != path::traits::directory_separator) + // Add the directory separator unless it is already there + // or we have type but no value. The idea is to print foo/ + // or dir{foo}. + // + if (s.back () != path::traits::directory_separator && (hv || !ht)) os << path::traits::directory_separator; } - else if (n.value.empty () && n.type.empty ()) - os << s; // Otherwise nothing gets printed. } os << n.value; - if (!n.type.empty ()) + if (ht) os << '}'; return os; diff --git a/build/parser.cxx b/build/parser.cxx index a030a09..8f4f81d 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -35,9 +35,9 @@ namespace build typedef token_type type; // Given a target or prerequisite name, figure out its type, taking - // into account extensions, trailing '/', or anything else that might - // be relevant. Also process the name (in place) by extracting the - // extension, adjusting dir/value, etc. + // into account extensions, special names (e.g., '.' and '..'), or + // anything else that might be relevant. Also process the name (in + // place) by extracting the extension, adjusting dir/value, etc. // const target_type& find_target_type (name& n, const location& l, const string*& ext) @@ -49,11 +49,9 @@ namespace build const char* tt; if (n.type.empty ()) { - // Empty name, '.' and '..', or a name ending with a directory - // separator signifies a directory. + // Empty name or '.' and '..' signify a directory. // - if (v.empty () || v == "." || v == ".." || - path::traits::is_separator (v.back ())) + if (v.empty () || v == "." || v == "..") tt = "dir"; else //@@ TODO: derive type from extension. @@ -189,7 +187,7 @@ namespace build location nloc (get_location (t, &path_)); names_type ns (tt != type::colon ? names (t, tt) - : names_type ({name ("")})); + : names_type ({name ("dir", path (), string ())})); if (tt == type::colon) { @@ -214,7 +212,9 @@ namespace build bool dir (false); for (const auto& n: ns) { - if (n.type.empty () && n.value.back () == '/') + // A name represents directory as an empty value. + // + if (n.type.empty () && n.value.empty ()) { if (ns.size () != 1) { @@ -233,14 +233,8 @@ namespace build { scope& prev (*scope_); - // On Win32 translate the root path to the special empty path. - // Search for root_scope for details. - // -#ifdef _WIN32 - path p (ns[0].value != "/" ? path (ns[0].value) : path ()); -#else - path p (ns[0].value); -#endif + path p (move (ns[0].dir)); // Steal. + if (p.relative ()) p = prev.path () / p; @@ -676,13 +670,15 @@ namespace build continue; } + string::size_type p (name.rfind ('/')); + string::size_type n (name.size () - 1); + // See if this is a type name, directory prefix, or both. That is, // it is followed by '{'. // if (tt == type::lcbrace) { next (t, tt); - string::size_type p (name.rfind ('/')), n (name.size () - 1); if (p != n && tp != nullptr) fail (t) << "nested type name " << name; @@ -727,9 +723,36 @@ namespace build continue; } - ns.emplace_back ((tp != nullptr ? *tp : string ()), - (dp != nullptr ? *dp : path ()), - move (name)); + // If it ends with a directory separator, then it is a directory. + // Note that at this stage we don't treat '.' and '..' as special + // (unless they are specified with a directory separator) because + // then we would have ended up treating '.: ...' as a directory + // scope. Instead, this is handled higher up, in find_target_type(). + // + // @@ TODO: and not quoted + // + if (p == n) + { + // On Win32 translate the root path to the special empty path. + // Search for root_scope for details. + // +#ifdef _WIN32 + path dir (name != "/" ? path (name) : path ()); +#else + path dir (name); +#endif + if (dp != nullptr) + dir = *dp / dir; + + ns.emplace_back ((tp != nullptr ? *tp : string ()), + move (dir), + string ()); + } + else + ns.emplace_back ((tp != nullptr ? *tp : string ()), + (dp != nullptr ? *dp : path ()), + move (name)); + continue; } -- cgit v1.1