From 44e1022f8141bd57756c2be4277c728ca7443eb3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 16 Dec 2017 12:00:53 +0200 Subject: Redo string/stream representation of dir{} name/target Now instead of: dir{foo/bar/} We get: foo/dir{bar/} Which feels more consistent with how we print other names/targets. That is, "directory bar/ in directory foo/" similar how foo/exe{bar} is "executable bar in directory foo/". --- build2/name.cxx | 72 +++++++++++-------- build2/name.hxx | 1 + build2/target.cxx | 25 ++++--- tests/variable/prerequisite-specific/testscript | 16 ++--- unit-tests/name/buildfile | 6 ++ unit-tests/name/driver.cxx | 96 +++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 46 deletions(-) create mode 100644 unit-tests/name/buildfile create mode 100644 unit-tests/name/driver.cxx diff --git a/build2/name.cxx b/build2/name.cxx index d1f3bd7..f71c7c1 100644 --- a/build2/name.cxx +++ b/build2/name.cxx @@ -6,8 +6,6 @@ #include // strchr() -#include - #include namespace build2 @@ -31,15 +29,18 @@ namespace build2 r += '%'; } - // If the value is empty, then we want to put the directory inside {}, - // e.g., dir{bar/}, not bar/dir{}. + // If the value is empty, then we want to put the last component of the + // directory inside {}, e.g., dir{bar/}, not bar/dir{}. // - bool d (!n.dir.empty ()); bool v (!n.value.empty ()); bool t (!n.type.empty ()); - if (v && d) - r += n.dir.representation (); + const dir_path& pd (v ? n.dir : + t ? n.dir.directory () : + dir_path ()); + + if (!pd.empty ()) + r += pd.representation (); if (t) { @@ -50,7 +51,7 @@ namespace build2 if (v) r += n.value; else - r += n.dir.representation (); + r += (pd.empty () ? n.dir : n.dir.leaf ()).representation (); if (t) r += '}'; @@ -95,18 +96,17 @@ namespace build2 os << v; }; - auto write_dir = [quote, &os, &write_string](const dir_path& d) + uint16_t dv (stream_verb (os)); // Directory verbosity. + + auto write_dir = [dv, quote, &os, &write_string] (const dir_path& d) { + const string& s (dv < 2 + ? diag_relative (d) + : d.representation ()); if (quote) - { - std::ostringstream s; - stream_verb (s, stream_verb (os)); - s << d; - - write_string (s.str ()); - } + write_string (s); else - os << d; + os << s; }; // Note: similar to to_string() below. @@ -123,29 +123,45 @@ namespace build2 os << '%'; } - // If the value is empty, then we want to print the directory inside {}, - // e.g., dir{bar/}, not bar/dir{}. We also want to print {} for an empty - // name (unless quoted). + // If the value is empty, then we want to print the last component of the + // directory inside {}, e.g., dir{bar/}, not bar/dir{}. We also want to + // print {} for an empty name (unless quoted, which is handled above). // bool d (!n.dir.empty ()); bool v (!n.value.empty ()); - bool t (!n.type.empty () || (!d && !v)); + bool t (!n.type.empty ()); - if (v) - write_dir (n.dir); + // Note: relative() may return empty. + // + const dir_path& rd (dv < 2 ? relative (n.dir) : n.dir); // Relative. + const dir_path& pd (v ? rd : + t ? rd.directory () : + dir_path ()); - if (t) + if (!pd.empty ()) + write_dir (pd); + + if (t || (!d && !v)) { - write_string (n.type); + if (t) + write_string (n.type); + os << '{'; } if (v) write_string (n.value); - else - write_dir (n.dir); + else if (d) + { + if (rd.empty ()) + write_string (dir_path (".").representation ()); + else if (!pd.empty ()) + write_string (rd.leaf ().representation ()); + else + write_dir (rd); + } - if (t) + if (t || (!d && !v)) os << '}'; return os; diff --git a/build2/name.hxx b/build2/name.hxx index 20a8aa0..aac0ad1 100644 --- a/build2/name.hxx +++ b/build2/name.hxx @@ -43,6 +43,7 @@ namespace build2 name (string v): value (move (v)) {} name (dir_path d): dir (move (d)) {} name (string t, string v): type (move (t)), value (move (v)) {} + name (dir_path d, string v): dir (move (d)), value (move (v)) {} name (dir_path d, string t, string v) : dir (move (d)), type (move (t)), value (move (v)) {} diff --git a/build2/target.cxx b/build2/target.cxx index aca977e..99c002b 100644 --- a/build2/target.cxx +++ b/build2/target.cxx @@ -418,19 +418,24 @@ namespace build2 ostream& to_stream (ostream& os, const target_key& k, uint16_t ev) { - // If the name is empty, then we want to print the directory - // inside {}, e.g., dir{bar/}, not bar/dir{}. + uint16_t dv (stream_verb (os)); // Directory verbosity. + + // If the name is empty, then we want to print the last component of the + // directory inside {}, e.g., dir{bar/}, not bar/dir{}. // bool n (!k.name->empty ()); - if (n) + // Note: relative() returns empty for './'. + // + const dir_path& rd (dv < 2 ? relative (*k.dir) : *k.dir); // Relative. + const dir_path& pd (n ? rd : rd.directory ()); // Parent. + + if (!pd.empty ()) { - // Avoid printing './' in './{...}' - // - if (stream_verb (os) < 2) - os << diag_relative (*k.dir, false); + if (dv < 2) + os << diag_relative (pd); else - os << *k.dir; + os << pd.representation (); } const target_type& tt (*k.type); @@ -459,7 +464,7 @@ namespace build2 assert (!k.ext); } else - os << *k.dir; + os << (rd.empty () ? dir_path (".") : rd.leaf ()).representation (); os << '}'; @@ -467,7 +472,7 @@ namespace build2 // if (!k.out->empty ()) { - if (stream_verb (os) < 2) + if (dv < 2) { // Don't print '@./'. // diff --git a/tests/variable/prerequisite-specific/testscript b/tests/variable/prerequisite-specific/testscript index c4993f2..ba21557 100644 --- a/tests/variable/prerequisite-specific/testscript +++ b/tests/variable/prerequisite-specific/testscript @@ -18,19 +18,19 @@ dir{x}: dir{c}: bar = [bool] true dump dir{x} EOI :5:1: dump: -% dir\{.+/x/\}:% +% .+/dir\{x/\}:% { fox = FOX } -% dir\{.+/x/\}: .+:dir\{a/\}:% +% .+/dir\{x/\}: .+:dir\{a/\}:% { foo = FOO } -% dir\{.+/x/\}: .+:dir\{b/\}:% +% .+/dir\{x/\}: .+:dir\{b/\}:% { fox = FOX FOX } -% dir\{.+/x/\}: .+:dir\{c/\}:% +% .+/dir\{x/\}: .+:dir\{c/\}:% { bar = [bool] true } @@ -43,20 +43,20 @@ dir{x} dir{y}: dir{a} dir{b}: foo = FOO dump dir{x} dir{y} EOI :2:1: dump: -% dir\{.+/x/\}: .+:dir\{a/\}:% +% .+/dir\{x/\}: .+:dir\{a/\}:% { foo = FOO } -% dir\{.+/x/\}: .+:dir\{b/\}:% +% .+/dir\{x/\}: .+:dir\{b/\}:% { foo = FOO } -% dir\{.+/y/\}: .+:dir\{a/\}:% +% .+/dir\{y/\}: .+:dir\{a/\}:% { foo = FOO } -% dir\{.+/y/\}: .+:dir\{b/\}:% +% .+/dir\{y/\}: .+:dir\{b/\}:% { foo = FOO } diff --git a/unit-tests/name/buildfile b/unit-tests/name/buildfile new file mode 100644 index 0000000..84f22c4 --- /dev/null +++ b/unit-tests/name/buildfile @@ -0,0 +1,6 @@ +# file : unit-tests/name/buildfile +# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +# license : MIT; see accompanying LICENSE file + +include ../../build2/ +exe{driver}: {hxx cxx}{*} ../../build2/libu{b} diff --git a/unit-tests/name/driver.cxx b/unit-tests/name/driver.cxx new file mode 100644 index 0000000..d454685 --- /dev/null +++ b/unit-tests/name/driver.cxx @@ -0,0 +1,96 @@ +// file : unit-tests/name/driver.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include + +#include +#include + +#include // Includes name. +#include + +#include + +using namespace std; + +namespace build2 +{ + int + main (int, char*[]) + { + using dir = dir_path; + + // Test string representation. + // + { + auto ts = [] (const name& n) {return to_string (n);}; + + assert (ts (name ()) == ""); + + assert (ts (name ("foo")) == "foo"); + + assert (ts (name (dir ("bar/"))) == "bar/"); + assert (ts (name (dir ("bar/baz/"))) == "bar/baz/"); + + assert (ts (name (dir ("bar/"), "dir", "")) == "dir{bar/}"); + assert (ts (name (dir ("bar/baz/"), "dir", "")) == "bar/dir{baz/}"); + + assert (ts (name (dir ("bar/"), "foo")) == "bar/foo"); + + assert (ts (name (dir ("bar/"), "dir", "foo")) == "bar/dir{foo}"); + assert (ts (name (dir ("bar/baz/"), "dir", "foo")) == "bar/baz/dir{foo}"); + } + + // Test stream representation. + // + { + auto ts = [] (const name& n, bool quote = true) + { + ostringstream os; + stream_verb (os, 1); + to_stream (os, n, quote); + return os.str (); + }; + + assert (ts (name ()) == "''"); + assert (ts (name (), false) == "{}"); + + assert (ts (name ("foo")) == "foo"); + + assert (ts (name (dir ("bar/"))) == "bar/"); + assert (ts (name (dir ("bar/baz/"))) == "bar/baz/"); + + assert (ts (name (dir ("bar/"), "dir", "")) == "dir{bar/}"); + assert (ts (name (dir ("bar/baz/"), "dir", "")) == "bar/dir{baz/}"); + + assert (ts (name (dir ("bar/"), "foo")) == "bar/foo"); + + assert (ts (name (dir ("bar/"), "dir", "foo")) == "bar/dir{foo}"); + assert (ts (name (dir ("bar/baz/"), "dir", "foo")) == "bar/baz/dir{foo}"); + + // Quoting. + // + assert (ts (name (dir ("bar baz/"), "dir", "foo fox")) == "'bar baz/'dir{'foo fox'}"); + + // Relative logic. + // +#ifndef _WIN32 + dir rb ("/bar/"); + relative_base = &rb; + + assert (ts (name (dir ("/bar/"), "dir", "")) == "dir{./}"); + assert (ts (name (dir ("/bar/"), "", "foo")) == "foo"); + assert (ts (name (dir ("/bar/baz/"), "dir", "")) == "dir{baz/}"); +#endif + } + + return 0; + } +} + +int +main (int argc, char* argv[]) +{ + return build2::main (argc, argv); +} -- cgit v1.1