| Index: tools/gn/file_template.cc
|
| diff --git a/tools/gn/file_template.cc b/tools/gn/file_template.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8b5d09f24006b74a400c7d700750d5651291075e
|
| --- /dev/null
|
| +++ b/tools/gn/file_template.cc
|
| @@ -0,0 +1,125 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "tools/gn/file_template.h"
|
| +
|
| +#include "tools/gn/filesystem_utils.h"
|
| +
|
| +const char FileTemplate::kSource[] = "{{source}}";
|
| +const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}";
|
| +
|
| +FileTemplate::FileTemplate(const Value& t, Err* err) {
|
| + ParseInput(t, err);
|
| +}
|
| +
|
| +FileTemplate::FileTemplate(const std::vector<std::string>& t) {
|
| + for (size_t i = 0; i < t.size(); i++)
|
| + ParseOneTemplateString(t[i]);
|
| +}
|
| +
|
| +FileTemplate::~FileTemplate() {
|
| +}
|
| +
|
| +void FileTemplate::Apply(const Value& sources,
|
| + const ParseNode* origin,
|
| + std::vector<Value>* dest,
|
| + Err* err) const {
|
| + if (!sources.VerifyTypeIs(Value::LIST, err))
|
| + return;
|
| + dest->reserve(sources.list_value().size() * templates_.container().size());
|
| +
|
| + // Temporary holding place, allocate outside to re-use- buffer.
|
| + std::vector<std::string> string_output;
|
| +
|
| + const std::vector<Value>& sources_list = sources.list_value();
|
| + for (size_t i = 0; i < sources_list.size(); i++) {
|
| + if (!sources_list[i].VerifyTypeIs(Value::STRING, err))
|
| + return;
|
| +
|
| + ApplyString(sources_list[i].string_value(), &string_output);
|
| + for (size_t out_i = 0; out_i < string_output.size(); out_i++)
|
| + dest->push_back(Value(origin, string_output[i]));
|
| + }
|
| +}
|
| +
|
| +void FileTemplate::ApplyString(const std::string& str,
|
| + std::vector<std::string>* output) const {
|
| + // Compute all substitutions needed so we can just do substitutions below.
|
| + // We skip the LITERAL one since that varies each time.
|
| + std::string subst[Subrange::NUM_TYPES];
|
| + if (types_required_[Subrange::SOURCE])
|
| + subst[Subrange::SOURCE] = str;
|
| + if (types_required_[Subrange::NAME_PART])
|
| + subst[Subrange::NAME_PART] = FindFilenameNoExtension(&str).as_string();
|
| +
|
| + output->resize(templates_.container().size());
|
| + for (size_t template_i = 0;
|
| + template_i < templates_.container().size(); template_i++) {
|
| + const Template& t = templates_[template_i];
|
| + (*output)[template_i].clear();
|
| + for (size_t subrange_i = 0; subrange_i < t.container().size();
|
| + subrange_i++) {
|
| + if (t[subrange_i].type == Subrange::LITERAL)
|
| + (*output)[template_i].append(t[subrange_i].literal);
|
| + else
|
| + (*output)[template_i].append(subst[t[subrange_i].type]);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void FileTemplate::ParseInput(const Value& value, Err* err) {
|
| + switch (value.type()) {
|
| + case Value::STRING:
|
| + ParseOneTemplateString(value.string_value());
|
| + break;
|
| + case Value::LIST:
|
| + for (size_t i = 0; i < value.list_value().size(); i++) {
|
| + if (!value.list_value()[i].VerifyTypeIs(Value::STRING, err))
|
| + return;
|
| + ParseOneTemplateString(value.list_value()[i].string_value());
|
| + }
|
| + break;
|
| + default:
|
| + *err = Err(value, "File template must be a string or list.",
|
| + "A sarcastic comment about your skills goes here.");
|
| + }
|
| +}
|
| +
|
| +void FileTemplate::ParseOneTemplateString(const std::string& str) {
|
| + templates_.container().resize(templates_.container().size() + 1);
|
| + Template& t = templates_[templates_.container().size() - 1];
|
| +
|
| + size_t cur = 0;
|
| + while (true) {
|
| + size_t next = str.find("{{", cur);
|
| +
|
| + // Pick up everything from the previous spot to here as a literal.
|
| + if (next == std::string::npos) {
|
| + if (cur != str.size())
|
| + t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur)));
|
| + break;
|
| + } else if (next > cur) {
|
| + t.container().push_back(
|
| + Subrange(Subrange::LITERAL, str.substr(cur, next - cur)));
|
| + }
|
| +
|
| + // Decode the template param.
|
| + if (str.compare(next, arraysize(kSource) - 1, kSource) == 0) {
|
| + t.container().push_back(Subrange(Subrange::SOURCE));
|
| + types_required_[Subrange::SOURCE] = true;
|
| + cur = next + arraysize(kSource) - 1;
|
| + } else if (str.compare(next, arraysize(kSourceNamePart) - 1,
|
| + kSourceNamePart) == 0) {
|
| + t.container().push_back(Subrange(Subrange::NAME_PART));
|
| + types_required_[Subrange::NAME_PART] = true;
|
| + cur = next + arraysize(kSourceNamePart) - 1;
|
| + } else {
|
| + // If it's not a match, treat it like a one-char literal (this will be
|
| + // rare, so it's not worth the bother to add to the previous literal) so
|
| + // we can keep going.
|
| + t.container().push_back(Subrange(Subrange::LITERAL, "{"));
|
| + cur = next + 1;
|
| + }
|
| + }
|
| +}
|
|
|