| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/escape.h" | 5 #include "tools/gn/escape.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/containers/stack_container.h" | |
| 10 #include "base/logging.h" | 9 #include "base/logging.h" |
| 11 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 12 | 11 |
| 13 namespace { | 12 namespace { |
| 14 | 13 |
| 15 // A "1" in this lookup table means that char is valid in the Posix shell. | 14 // A "1" in this lookup table means that char is valid in the Posix shell. |
| 16 const char kShellValid[0x80] = { | 15 const char kShellValid[0x80] = { |
| 17 // 00-1f: all are invalid | 16 // 00-1f: all are invalid |
| 18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 17 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 20 // ' ' ! " # $ % & ' ( ) * + , - . / | 19 // ' ' ! " # $ % & ' ( ) * + , - . / |
| 21 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, | 20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, |
| 22 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? | 21 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? |
| 23 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, | 22 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, |
| 24 // @ A B C D E F G H I J K L M N O | 23 // @ A B C D E F G H I J K L M N O |
| 25 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 24 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 26 // P Q R S T U V W X Y Z [ \ ] ^ _ | 25 // P Q R S T U V W X Y Z [ \ ] ^ _ |
| 27 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, | 26 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, |
| 28 // ` a b c d e f g h i j k l m n o | 27 // ` a b c d e f g h i j k l m n o |
| 29 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | 28 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 30 // p q r s t u v w x y z { | } ~ | 29 // p q r s t u v w x y z { | } ~ |
| 31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }; | 30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }; |
| 32 | 31 |
| 33 // Append one character to the given string, escaping it for Ninja. | 32 // Append one character to the given string, escaping it for Ninja. |
| 34 // | 33 // |
| 35 // Ninja's escaping rules are very simple. We always escape colons even | 34 // Ninja's escaping rules are very simple. We always escape colons even |
| 36 // though they're OK in many places, in case the resulting string is used on | 35 // though they're OK in many places, in case the resulting string is used on |
| 37 // the left-hand-side of a rule. | 36 // the left-hand-side of a rule. |
| 38 template<typename DestString> | 37 inline void NinjaEscapeChar(char ch, std::string* dest) { |
| 39 inline void NinjaEscapeChar(char ch, DestString* dest) { | |
| 40 if (ch == '$' || ch == ' ' || ch == ':') | 38 if (ch == '$' || ch == ' ' || ch == ':') |
| 41 dest->push_back('$'); | 39 dest->push_back('$'); |
| 42 dest->push_back(ch); | 40 dest->push_back(ch); |
| 43 } | 41 } |
| 44 | 42 |
| 45 template<typename DestString> | |
| 46 void EscapeStringToString_Ninja(const base::StringPiece& str, | 43 void EscapeStringToString_Ninja(const base::StringPiece& str, |
| 47 const EscapeOptions& options, | 44 const EscapeOptions& options, |
| 48 DestString* dest, | 45 std::string* dest, |
| 49 bool* needed_quoting) { | 46 bool* needed_quoting) { |
| 50 for (const auto& elem : str) | 47 for (const auto& elem : str) |
| 51 NinjaEscapeChar(elem, dest); | 48 NinjaEscapeChar(elem, dest); |
| 52 } | 49 } |
| 53 | 50 |
| 54 template<typename DestString> | |
| 55 void EscapeStringToString_NinjaPreformatted(const base::StringPiece& str, | 51 void EscapeStringToString_NinjaPreformatted(const base::StringPiece& str, |
| 56 DestString* dest) { | 52 std::string* dest) { |
| 57 // Only Ninja-escape $. | 53 // Only Ninja-escape $. |
| 58 for (const auto& elem : str) { | 54 for (const auto& elem : str) { |
| 59 if (elem == '$') | 55 if (elem == '$') |
| 60 dest->push_back('$'); | 56 dest->push_back('$'); |
| 61 dest->push_back(elem); | 57 dest->push_back(elem); |
| 62 } | 58 } |
| 63 } | 59 } |
| 64 | 60 |
| 65 // Escape for CommandLineToArgvW and additionally escape Ninja characters. | 61 // Escape for CommandLineToArgvW and additionally escape Ninja characters. |
| 66 // | 62 // |
| 67 // The basic algorithm is if the string doesn't contain any parse-affecting | 63 // The basic algorithm is if the string doesn't contain any parse-affecting |
| 68 // characters, don't do anything (other than the Ninja processing). If it does, | 64 // characters, don't do anything (other than the Ninja processing). If it does, |
| 69 // quote the string, and backslash-escape all quotes and backslashes. | 65 // quote the string, and backslash-escape all quotes and backslashes. |
| 70 // See: | 66 // See: |
| 71 // http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/eve
ryone-quotes-arguments-the-wrong-way.aspx | 67 // http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/eve
ryone-quotes-arguments-the-wrong-way.aspx |
| 72 // http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx | 68 // http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx |
| 73 template<typename DestString> | |
| 74 void EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str, | 69 void EscapeStringToString_WindowsNinjaFork(const base::StringPiece& str, |
| 75 const EscapeOptions& options, | 70 const EscapeOptions& options, |
| 76 DestString* dest, | 71 std::string* dest, |
| 77 bool* needed_quoting) { | 72 bool* needed_quoting) { |
| 78 // We assume we don't have any whitespace chars that aren't spaces. | 73 // We assume we don't have any whitespace chars that aren't spaces. |
| 79 DCHECK(str.find_first_of("\r\n\v\t") == std::string::npos); | 74 DCHECK(str.find_first_of("\r\n\v\t") == std::string::npos); |
| 80 | 75 |
| 81 if (str.find_first_of(" \"") == std::string::npos) { | 76 if (str.find_first_of(" \"") == std::string::npos) { |
| 82 // Simple case, don't quote. | 77 // Simple case, don't quote. |
| 83 EscapeStringToString_Ninja(str, options, dest, needed_quoting); | 78 EscapeStringToString_Ninja(str, options, dest, needed_quoting); |
| 84 } else { | 79 } else { |
| 85 if (!options.inhibit_quoting) | 80 if (!options.inhibit_quoting) |
| 86 dest->push_back('"'); | 81 dest->push_back('"'); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 109 } | 104 } |
| 110 } | 105 } |
| 111 | 106 |
| 112 if (!options.inhibit_quoting) | 107 if (!options.inhibit_quoting) |
| 113 dest->push_back('"'); | 108 dest->push_back('"'); |
| 114 if (needed_quoting) | 109 if (needed_quoting) |
| 115 *needed_quoting = true; | 110 *needed_quoting = true; |
| 116 } | 111 } |
| 117 } | 112 } |
| 118 | 113 |
| 119 template<typename DestString> | |
| 120 void EscapeStringToString_PosixNinjaFork(const base::StringPiece& str, | 114 void EscapeStringToString_PosixNinjaFork(const base::StringPiece& str, |
| 121 const EscapeOptions& options, | 115 const EscapeOptions& options, |
| 122 DestString* dest, | 116 std::string* dest, |
| 123 bool* needed_quoting) { | 117 bool* needed_quoting) { |
| 124 for (const auto& elem : str) { | 118 for (const auto& elem : str) { |
| 125 if (elem == '$' || elem == ' ') { | 119 if (elem == '$' || elem == ' ') { |
| 126 // Space and $ are special to both Ninja and the shell. '$' escape for | 120 // Space and $ are special to both Ninja and the shell. '$' escape for |
| 127 // Ninja, then backslash-escape for the shell. | 121 // Ninja, then backslash-escape for the shell. |
| 128 dest->push_back('\\'); | 122 dest->push_back('\\'); |
| 129 dest->push_back('$'); | 123 dest->push_back('$'); |
| 130 dest->push_back(elem); | 124 dest->push_back(elem); |
| 131 } else if (elem == ':') { | 125 } else if (elem == ':') { |
| 132 // Colon is the only other Ninja special char, which is not special to | 126 // Colon is the only other Ninja special char, which is not special to |
| 133 // the shell. | 127 // the shell. |
| 134 dest->push_back('$'); | 128 dest->push_back('$'); |
| 135 dest->push_back(':'); | 129 dest->push_back(':'); |
| 136 } else if (static_cast<unsigned>(elem) >= 0x80 || | 130 } else if (static_cast<unsigned>(elem) >= 0x80 || |
| 137 !kShellValid[static_cast<int>(elem)]) { | 131 !kShellValid[static_cast<int>(elem)]) { |
| 138 // All other invalid shell chars get backslash-escaped. | 132 // All other invalid shell chars get backslash-escaped. |
| 139 dest->push_back('\\'); | 133 dest->push_back('\\'); |
| 140 dest->push_back(elem); | 134 dest->push_back(elem); |
| 141 } else { | 135 } else { |
| 142 // Everything else is a literal. | 136 // Everything else is a literal. |
| 143 dest->push_back(elem); | 137 dest->push_back(elem); |
| 144 } | 138 } |
| 145 } | 139 } |
| 146 } | 140 } |
| 147 | 141 |
| 148 template<typename DestString> | |
| 149 void EscapeStringToString(const base::StringPiece& str, | 142 void EscapeStringToString(const base::StringPiece& str, |
| 150 const EscapeOptions& options, | 143 const EscapeOptions& options, |
| 151 DestString* dest, | 144 std::string* dest, |
| 152 bool* needed_quoting) { | 145 bool* needed_quoting) { |
| 153 switch (options.mode) { | 146 switch (options.mode) { |
| 154 case ESCAPE_NONE: | 147 case ESCAPE_NONE: |
| 155 dest->append(str.data(), str.size()); | 148 dest->append(str.data(), str.size()); |
| 156 break; | 149 break; |
| 157 case ESCAPE_NINJA: | 150 case ESCAPE_NINJA: |
| 158 EscapeStringToString_Ninja(str, options, dest, needed_quoting); | 151 EscapeStringToString_Ninja(str, options, dest, needed_quoting); |
| 159 break; | 152 break; |
| 160 case ESCAPE_NINJA_COMMAND: | 153 case ESCAPE_NINJA_COMMAND: |
| 161 switch (options.platform) { | 154 switch (options.platform) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 bool* needed_quoting) { | 188 bool* needed_quoting) { |
| 196 std::string result; | 189 std::string result; |
| 197 result.reserve(str.size() + 4); // Guess we'll add a couple of extra chars. | 190 result.reserve(str.size() + 4); // Guess we'll add a couple of extra chars. |
| 198 EscapeStringToString(str, options, &result, needed_quoting); | 191 EscapeStringToString(str, options, &result, needed_quoting); |
| 199 return result; | 192 return result; |
| 200 } | 193 } |
| 201 | 194 |
| 202 void EscapeStringToStream(std::ostream& out, | 195 void EscapeStringToStream(std::ostream& out, |
| 203 const base::StringPiece& str, | 196 const base::StringPiece& str, |
| 204 const EscapeOptions& options) { | 197 const EscapeOptions& options) { |
| 205 base::StackString<256> escaped; | 198 std::string escaped; |
| 206 EscapeStringToString(str, options, &escaped.container(), nullptr); | 199 EscapeStringToString(str, options, &escaped, nullptr); |
| 207 if (!escaped->empty()) | 200 if (!escaped.empty()) |
| 208 out.write(escaped->data(), escaped->size()); | 201 out.write(escaped.data(), escaped.size()); |
| 209 } | 202 } |
| OLD | NEW |