text: // Copyright 2014 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/substitution_type.h"
  
  #include <stddef.h>
  #include <stdlib.h>
  
  #include "tools/gn/err.h"
  
  const char* kSubstitutionNames[SUBSTITUTION_NUM_TYPES] = {
      "<<literal>>",  // SUBSTITUTION_LITERAL
  
      "{{source}}",  // SUBSTITUTION_SOURCE
      "{{output}}",  // SUBSTITUTION_OUTPUT
  
      "{{source_name_part}}",          // SUBSTITUTION_NAME_PART
      "{{source_file_part}}",          // SUBSTITUTION_FILE_PART
      "{{source_dir}}",                // SUBSTITUTION_SOURCE_DIR
      "{{source_root_relative_dir}}",  // SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
      "{{source_gen_dir}}",            // SUBSTITUTION_SOURCE_GEN_DIR
      "{{source_out_dir}}",            // SUBSTITUTION_SOURCE_OUT_DIR
      "{{source_target_relative}}",    // SUBSTITUTION_SOURCE_TARGET_RELATIVE
  
      "{{label}}",               // SUBSTITUTION_LABEL
      "{{label_name}}",          // SUBSTITUTION_LABEL_NAME
      "{{root_gen_dir}}",        // SUBSTITUTION_ROOT_GEN_DIR
      "{{root_out_dir}}",        // SUBSTITUTION_ROOT_OUT_DIR
      "{{target_gen_dir}}",      // SUBSTITUTION_TARGET_GEN_DIR
      "{{target_out_dir}}",      // SUBSTITUTION_TARGET_OUT_DIR
      "{{target_output_name}}",  // SUBSTITUTION_TARGET_OUTPUT_NAME
  
      "{{asmflags}}",      // SUBSTITUTION_ASMFLAGS
      "{{cflags}}",        // SUBSTITUTION_CFLAGS
      "{{cflags_c}}",      // SUBSTITUTION_CFLAGS_C
      "{{cflags_cc}}",     // SUBSTITUTION_CFLAGS_CC
      "{{cflags_objc}}",   // SUBSTITUTION_CFLAGS_OBJC
      "{{cflags_objcc}}",  // SUBSTITUTION_CFLAGS_OBJCC
      "{{defines}}",       // SUBSTITUTION_DEFINES
      "{{include_dirs}}",  // SUBSTITUTION_INCLUDE_DIRS
  
      "{{inputs}}",            // SUBSTITUTION_LINKER_INPUTS
      "{{inputs_newline}}",    // SUBSTITUTION_LINKER_INPUTS_NEWLINE
      "{{ldflags}}",           // SUBSTITUTION_LDFLAGS
      "{{libs}}",              // SUBSTITUTION_LIBS
      "{{output_dir}}",        // SUBSTITUTION_OUTPUT_DIR
      "{{output_extension}}",  // SUBSTITUTION_OUTPUT_EXTENSION
      "{{solibs}}",            // SUBSTITUTION_SOLIBS
  
      "{{arflags}}",  // SUBSTITUTION_ARFLAGS
  
      "{{bundle_root_dir}}",            // SUBSTITUTION_BUNDLE_ROOT_DIR
      "{{bundle_contents_dir}}",        // SUBSTITUTION_BUNDLE_CONTENTS_DIR
      "{{bundle_resources_dir}}",       // SUBSTITUTION_BUNDLE_RESOURCES_DIR
      "{{bundle_executable_dir}}",      // SUBSTITUTION_BUNDLE_EXECUTABLE_DIR
      "{{bundle_product_type}}",        // SUBSTITUTION_BUNDLE_PRODUCT_TYPE
      "{{bundle_partial_info_plist}}",  // SUBSTITUTION_BUNDLE_PARTIAL_INFO_PLIST,
  
      "{{response_file_name}}",  // SUBSTITUTION_RSP_FILE_NAME
  };
  
  const char* kSubstitutionNinjaNames[SUBSTITUTION_NUM_TYPES] = {
      nullptr,  // SUBSTITUTION_LITERAL
  
      "in",   // SUBSTITUTION_SOURCE
      "out",  // SUBSTITUTION_OUTPUT
  
      "source_name_part",          // SUBSTITUTION_NAME_PART
      "source_file_part",          // SUBSTITUTION_FILE_PART
      "source_dir",                // SUBSTITUTION_SOURCE_DIR
      "source_root_relative_dir",  // SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
      "source_gen_dir",            // SUBSTITUTION_SOURCE_GEN_DIR
      "source_out_dir",            // SUBSTITUTION_SOURCE_OUT_DIR
      "source_target_relative",    // SUBSTITUTION_SOURCE_TARGET_RELATIVE
  
      "label",               // SUBSTITUTION_LABEL
      "label_name",          // SUBSTITUTION_LABEL_NAME
      "root_gen_dir",        // SUBSTITUTION_ROOT_GEN_DIR
      "root_out_dir",        // SUBSTITUTION_ROOT_OUT_DIR
      "target_gen_dir",      // SUBSTITUTION_TARGET_GEN_DIR
      "target_out_dir",      // SUBSTITUTION_TARGET_OUT_DIR
      "target_output_name",  // SUBSTITUTION_TARGET_OUTPUT_NAME
  
      "asmflags",      // SUBSTITUTION_ASMFLAGS
      "cflags",        // SUBSTITUTION_CFLAGS
      "cflags_c",      // SUBSTITUTION_CFLAGS_C
      "cflags_cc",     // SUBSTITUTION_CFLAGS_CC
      "cflags_objc",   // SUBSTITUTION_CFLAGS_OBJC
      "cflags_objcc",  // SUBSTITUTION_CFLAGS_OBJCC
      "defines",       // SUBSTITUTION_DEFINES
      "include_dirs",  // SUBSTITUTION_INCLUDE_DIRS
  
      // LINKER_INPUTS expands to the same Ninja var as SUBSTITUTION_SOURCE. These
      // are used in different contexts and are named differently to keep things
      // clear, but they both expand to the "set of input files" for a build rule.
      "in",                // SUBSTITUTION_LINKER_INPUTS
      "in_newline",        // SUBSTITUTION_LINKER_INPUTS_NEWLINE
      "ldflags",           // SUBSTITUTION_LDFLAGS
      "libs",              // SUBSTITUTION_LIBS
      "output_dir",        // SUBSTITUTION_OUTPUT_DIR
      "output_extension",  // SUBSTITUTION_OUTPUT_EXTENSION
      "solibs",            // SUBSTITUTION_SOLIBS
  
      "arflags",  // SUBSTITUTION_ARFLAGS
  
      "bundle_root_dir",        // SUBSTITUTION_BUNDLE_ROOT_DIR
      "bundle_contents_dir",    // SUBSTITUTION_BUNDLE_CONTENTS_DIR
      "bundle_resources_dir",   // SUBSTITUTION_BUNDLE_RESOURCES_DIR
      "bundle_executable_dir",  // SUBSTITUTION_BUNDLE_EXECUTABLE_DIR
      "product_type",           // SUBSTITUTION_BUNDLE_PRODUCT_TYPE
      "partial_info_plist",     // SUBSTITUTION_BUNDLE_PARTIAL_INFO_PLIST
  
      "rspfile",  // SUBSTITUTION_RSP_FILE_NAME
  };
  
  SubstitutionBits::SubstitutionBits() : used() {}
  
  void SubstitutionBits::MergeFrom(const SubstitutionBits& other) {
    for (size_t i = 0; i < SUBSTITUTION_NUM_TYPES; i++)
      used[i] |= other.used[i];
  }
  
  void SubstitutionBits::FillVector(std::vector<SubstitutionType>* vect) const {
    for (size_t i = SUBSTITUTION_FIRST_PATTERN; i < SUBSTITUTION_NUM_TYPES; i++) {
      if (used[i])
        vect->push_back(static_cast<SubstitutionType>(i));
    }
  }
  
  bool SubstitutionIsInOutputDir(SubstitutionType type) {
    return type == SUBSTITUTION_SOURCE_GEN_DIR ||
           type == SUBSTITUTION_SOURCE_OUT_DIR ||
           type == SUBSTITUTION_ROOT_GEN_DIR ||
           type == SUBSTITUTION_ROOT_OUT_DIR ||
           type == SUBSTITUTION_TARGET_GEN_DIR ||
           type == SUBSTITUTION_TARGET_OUT_DIR;
  }
  
  bool SubstitutionIsInBundleDir(SubstitutionType type) {
    return type == SUBSTITUTION_BUNDLE_ROOT_DIR ||
           type == SUBSTITUTION_BUNDLE_CONTENTS_DIR ||
           type == SUBSTITUTION_BUNDLE_RESOURCES_DIR ||
           type == SUBSTITUTION_BUNDLE_EXECUTABLE_DIR;
  }
  
  bool IsValidBundleDataSubstitution(SubstitutionType type) {
    return type == SUBSTITUTION_LITERAL ||
           type == SUBSTITUTION_SOURCE_NAME_PART ||
           type == SUBSTITUTION_SOURCE_FILE_PART ||
           type == SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR ||
           type == SUBSTITUTION_BUNDLE_ROOT_DIR ||
           type == SUBSTITUTION_BUNDLE_CONTENTS_DIR ||
           type == SUBSTITUTION_BUNDLE_RESOURCES_DIR ||
           type == SUBSTITUTION_BUNDLE_EXECUTABLE_DIR;
  }
  
  bool IsValidSourceSubstitution(SubstitutionType type) {
    return type == SUBSTITUTION_LITERAL || type == SUBSTITUTION_SOURCE ||
           type == SUBSTITUTION_SOURCE_NAME_PART ||
           type == SUBSTITUTION_SOURCE_FILE_PART ||
           type == SUBSTITUTION_SOURCE_DIR ||
           type == SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR ||
           type == SUBSTITUTION_SOURCE_GEN_DIR ||
           type == SUBSTITUTION_SOURCE_OUT_DIR ||
           type == SUBSTITUTION_SOURCE_TARGET_RELATIVE;
  }
  
  bool IsValidScriptArgsSubstitution(SubstitutionType type) {
    return IsValidSourceSubstitution(type) || type == SUBSTITUTION_RSP_FILE_NAME;
  }
  
  bool IsValidToolSubstitution(SubstitutionType type) {
    return type == SUBSTITUTION_LITERAL || type == SUBSTITUTION_OUTPUT ||
           type == SUBSTITUTION_LABEL || type == SUBSTITUTION_LABEL_NAME ||
           type == SUBSTITUTION_ROOT_GEN_DIR ||
           type == SUBSTITUTION_ROOT_OUT_DIR ||
           type == SUBSTITUTION_TARGET_GEN_DIR ||
           type == SUBSTITUTION_TARGET_OUT_DIR ||
           type == SUBSTITUTION_TARGET_OUTPUT_NAME;
  }
  
  bool IsValidCompilerSubstitution(SubstitutionType type) {
    return IsValidToolSubstitution(type) || IsValidSourceSubstitution(type) ||
           type == SUBSTITUTION_SOURCE || type == SUBSTITUTION_ASMFLAGS ||
           type == SUBSTITUTION_CFLAGS || type == SUBSTITUTION_CFLAGS_C ||
           type == SUBSTITUTION_CFLAGS_CC || type == SUBSTITUTION_CFLAGS_OBJC ||
           type == SUBSTITUTION_CFLAGS_OBJCC || type == SUBSTITUTION_DEFINES ||
           type == SUBSTITUTION_INCLUDE_DIRS;
  }
  
  bool IsValidCompilerOutputsSubstitution(SubstitutionType type) {
    // All tool types except "output" (which would be infinitely recursive).
    return (IsValidToolSubstitution(type) && type != SUBSTITUTION_OUTPUT) ||
           IsValidSourceSubstitution(type);
  }
  
  bool IsValidLinkerSubstitution(SubstitutionType type) {
    return IsValidToolSubstitution(type) || type == SUBSTITUTION_LINKER_INPUTS ||
           type == SUBSTITUTION_LINKER_INPUTS_NEWLINE ||
           type == SUBSTITUTION_LDFLAGS || type == SUBSTITUTION_LIBS ||
           type == SUBSTITUTION_OUTPUT_DIR ||
           type == SUBSTITUTION_OUTPUT_EXTENSION || type == SUBSTITUTION_SOLIBS;
  }
  
  bool IsValidLinkerOutputsSubstitution(SubstitutionType type) {
    // All valid compiler outputs plus the output extension.
    return IsValidCompilerOutputsSubstitution(type) ||
           type == SUBSTITUTION_OUTPUT_DIR ||
           type == SUBSTITUTION_OUTPUT_EXTENSION;
  }
  
  bool IsValidALinkSubstitution(SubstitutionType type) {
    return IsValidToolSubstitution(type) || type == SUBSTITUTION_LINKER_INPUTS ||
           type == SUBSTITUTION_LINKER_INPUTS_NEWLINE ||
           type == SUBSTITUTION_ARFLAGS || type == SUBSTITUTION_OUTPUT_DIR ||
           type == SUBSTITUTION_OUTPUT_EXTENSION;
  }
  
  bool IsValidCopySubstitution(SubstitutionType type) {
    return IsValidToolSubstitution(type) || type == SUBSTITUTION_SOURCE;
  }
  
  bool IsValidCompileXCassetsSubstitution(SubstitutionType type) {
    return IsValidToolSubstitution(type) || type == SUBSTITUTION_LINKER_INPUTS ||
           type == SUBSTITUTION_BUNDLE_PRODUCT_TYPE ||
           type == SUBSTITUTION_BUNDLE_PARTIAL_INFO_PLIST;
  }
  
  bool EnsureValidSubstitutions(const std::vector<SubstitutionType>& types,
                                bool (*is_valid_subst)(SubstitutionType),
                                const ParseNode* origin,
                                Err* err) {
    for (SubstitutionType type : types) {
      if (!is_valid_subst(type)) {
        *err = Err(origin, "Invalid substitution type.",
                   "The substitution " + std::string(kSubstitutionNames[type]) +
                       " isn't valid for something\n"
                       "operating on a source file such as this.");
        return false;
      }
    }
    return true;
  }
  