diff options
Diffstat (limited to 'libbuild2/name.cxx')
-rw-r--r-- | libbuild2/name.cxx | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/libbuild2/name.cxx b/libbuild2/name.cxx new file mode 100644 index 0000000..4aac32f --- /dev/null +++ b/libbuild2/name.cxx @@ -0,0 +1,187 @@ +// file : libbuild2/name.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <libbuild2/types.hxx> // Note: not <libbuild2/name.hxx> + +#include <string.h> // strchr() + +#include <libbuild2/diagnostics.hxx> + +namespace build2 +{ + const name empty_name; + const names empty_names; + + string + to_string (const name& n) + { + string r; + + // Note: similar to to_stream() below. + // + if (n.empty ()) + return r; + + if (n.proj) + { + r += n.proj->string (); + r += '%'; + } + + // 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 v (!n.value.empty ()); + bool t (!n.type.empty ()); + + const dir_path& pd (v ? n.dir : + t ? n.dir.directory () : + dir_path ()); + + if (!pd.empty ()) + r += pd.representation (); + + if (t) + { + r += n.type; + r += '{'; + } + + if (v) + r += n.value; + else + r += (pd.empty () ? n.dir : n.dir.leaf ()).representation (); + + if (t) + r += '}'; + + return r; + } + + ostream& + to_stream (ostream& os, const name& n, bool quote, char pair) + { + auto write_string = [quote, pair, &os](const string& v) + { + char sc[] = { + '{', '}', '[', ']', '$', '(', ')', // Token endings. + ' ', '\t', '\n', '#', // Spaces. + '\\', '"', // Escaping and quoting. + '%', // Project name separator. + '*', '?', // Wildcard characters. + pair, // Pair separator, if any. + '\0'}; + + if (quote && v.find ('\'') != string::npos) + { + // Quote the string with the double quotes rather than with the single + // one. Escape some of the special characters. + // + os << '"'; + + for (auto c: v) + { + if (strchr ("\\$(\"", c) != nullptr) // Special inside double quotes. + os << '\\'; + + os << c; + } + + os << '"'; + } + else if (quote && v.find_first_of (sc) != string::npos) + os << "'" << v << "'"; + else + os << v; + }; + + uint16_t dv (stream_verb (os).path); // Directory verbosity. + + auto write_dir = [dv, quote, &os, &write_string] (const dir_path& d) + { + const string& s (dv < 1 + ? diag_relative (d) + : d.representation ()); + if (quote) + write_string (s); + else + os << s; + }; + + // Note: similar to to_string() below. + // + + // If quoted then print empty name as '' rather than {}. + // + if (quote && n.empty ()) + return os << "''"; + + if (n.proj) + { + write_string (n.proj->string ()); + os << '%'; + } + + // 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 ()); + + // Note: relative() may return empty. + // + const dir_path& rd (dv < 1 ? relative (n.dir) : n.dir); // Relative. + const dir_path& pd (v ? rd : + t ? rd.directory () : + dir_path ()); + + if (!pd.empty ()) + write_dir (pd); + + if (t || (!d && !v)) + { + if (t) + write_string (n.type); + + os << '{'; + } + + if (v) + write_string (n.value); + 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 || (!d && !v)) + os << '}'; + + return os; + } + + ostream& + to_stream (ostream& os, const names_view& ns, bool quote, char pair) + { + for (auto i (ns.begin ()), e (ns.end ()); i != e; ) + { + const name& n (*i); + ++i; + to_stream (os, n, quote, pair); + + if (n.pair) + os << n.pair; + else if (i != e) + os << ' '; + } + + return os; + } +} |