From c2b4305349ca855c497904282db354de56c74842 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 7 Aug 2018 14:59:07 +0200 Subject: Add support for default extension specification, trailing dot escaping For example: cxx{*}: extension = cxx cxx{foo} # foo.cxx cxx{foo.test} # foo.test (probably what we want...) cxx{foo.test...} # foo.test.cxx (... is this) cxx{foo..} # foo. cxx{foo....} # foo.. cxx{foo.....} # error (must come in escape pair) --- build2/scope.cxx | 61 ++++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 33 deletions(-) (limited to 'build2/scope.cxx') diff --git a/build2/scope.cxx b/build2/scope.cxx index dc08925..bf83830 100644 --- a/build2/scope.cxx +++ b/build2/scope.cxx @@ -588,36 +588,38 @@ namespace build2 return nullptr; } - const target_type* scope:: - find_target_type (name& n, optional& ext, const location& loc) const + pair> scope:: + find_target_type (name& n, const location& loc) const { - ext = nullopt; + const target_type* tt (nullptr); + optional ext; + string& v (n.value); // If the target type is specified, resolve it and bail out if not found. // Otherwise, we know in the end it will resolve to something (if nothing // else, either dir{} or file{}), so we can go ahead and process the name. // - const target_type* r (nullptr); if (n.typed ()) { - r = find_target_type (n.type); + tt = find_target_type (n.type); - if (r == nullptr) - return r; + if (tt == nullptr) + return make_pair (tt, move (ext)); } else { - // Empty name as well as '.' and '..' signify a directory. + // Empty name as well as '.' and '..' signify a directory. Note that + // this logic must be consistent with other places (grep for ".."). // if (v.empty () || v == "." || v == "..") - r = &dir::static_type; + tt = &dir::static_type; } // Directories require special name processing. If we find that more - // targets deviate, then we should make this target-type-specific. + // targets deviate, then we should make this target type-specific. // - if (r != nullptr && (r->is_a () || r->is_a ())) + if (tt != nullptr && (tt->is_a () || tt->is_a ())) { // The canonical representation of a directory name is with empty // value. @@ -634,50 +636,43 @@ namespace build2 // the extension (if any). We cannot assume the name part is a valid // filesystem name so we will have to do the splitting manually. // - path::size_type i (path::traits::rfind_separator (v)); + // See also parser::expand_name_pattern() if changing anything here. + // + size_t p (path::traits::rfind_separator (v)); - if (i != string::npos) + if (p != string::npos) { try { - n.dir /= dir_path (v, i != 0 ? i : 1); // Special case: "/". + n.dir /= dir_path (v, p != 0 ? p : 1); // Special case: "/". } catch (const invalid_path& e) { fail (loc) << "invalid path '" << e.path << "'"; } - v = string (v, i + 1, string::npos); + v.erase (0, p + 1); } - // Extract the extension. Treat trailing dot as specified but empty - // extension. + // Extract the extension. // - string::size_type j (v.back () != '.' - ? path::traits::find_extension (v) - : v.size () - 1); - - if (j != string::npos) - { - ext = string (v.c_str () + j + 1); - v.resize (j); - } + ext = target::split_name (v, loc); } // If the target type is still unknown, map it using the name/extension, // falling back to file{}. // - if (r == nullptr) + if (tt == nullptr) { // We only consider files without extension for file name mapping. // if (!ext) - r = find_file_target_type (this, v); + tt = find_file_target_type (this, v); //@@ TODO: derive type from extension. - if (r == nullptr) - r = &file::static_type; + if (tt == nullptr) + tt = &file::static_type; } // If the target type does not use extensions but one was specified, @@ -685,15 +680,15 @@ namespace build2 // diagnostics; see to_stream(target_key) for details). // if (ext && - r->fixed_extension == nullptr && - r->default_extension == nullptr) + tt->fixed_extension == nullptr && + tt->default_extension == nullptr) { v += '.'; v += *ext; ext = nullopt; } - return r; + return make_pair (tt, move (ext)); } static target* -- cgit v1.1