aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-03-04 18:04:50 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-03-04 18:04:50 +0200
commit9ef25ab2f9da89ab48ecce3fe1b8cbb0bc5f1e09 (patch)
treed378fd3b684daf8b5d517ad7f8c88a6c767ea397
parent7eed858cac7e8ff78626bdc5d63a7f36ca8f8010 (diff)
Treat names that end with directory separators as directories
-rw-r--r--build/name.cxx20
-rw-r--r--build/parser.cxx65
2 files changed, 57 insertions, 28 deletions
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;
}