diff options
Diffstat (limited to 'build2/scope.cxx')
-rw-r--r-- | build2/scope.cxx | 61 |
1 files changed, 28 insertions, 33 deletions
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<string>& ext, const location& loc) const + pair<const target_type*, optional<string>> scope:: + find_target_type (name& n, const location& loc) const { - ext = nullopt; + const target_type* tt (nullptr); + optional<string> 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<dir> () || r->is_a<fsdir> ())) + if (tt != nullptr && (tt->is_a<dir> () || tt->is_a<fsdir> ())) { // 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* |