Credit: JustMagic
| 309 | |
| 310 | // Credit: JustMagic |
| 311 | struct Command { |
| 312 | std::stringstream &ss; |
| 313 | int depth = 0; |
| 314 | std::string command; |
| 315 | bool first_arg = true; |
| 316 | bool had_newline = false; |
| 317 | bool generated = false; |
| 318 | std::string post_comment; |
| 319 | |
| 320 | Command(std::stringstream &ss, int depth, std::string command, std::string post_comment) |
| 321 | : ss(ss), depth(depth), command(std::move(command)), post_comment(std::move(post_comment)) { |
| 322 | } |
| 323 | |
| 324 | ~Command() noexcept(false) { |
| 325 | if (!generated) { |
| 326 | throw std::runtime_error("Incorrect usage of cmd(), you probably forgot ()"); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | static std::string quote(const std::string &str) { |
| 331 | // Quote an empty string |
| 332 | if (str.empty()) { |
| 333 | return "\"\""; |
| 334 | } |
| 335 | // Don't quote arguments that don't need quoting |
| 336 | // https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#unquoted-argument |
| 337 | // NOTE: Normally '/' does not require quoting according to the documentation but this has been the case here |
| 338 | // previously, so for backwards compatibility its still here. |
| 339 | if (str.find_first_of("()#\"\\'> |/;") == std::string::npos) |
| 340 | return str; |
| 341 | std::string result; |
| 342 | result += "\""; |
| 343 | for (char ch : str) { |
| 344 | switch (ch) { |
| 345 | case '\\': |
| 346 | case '\"': |
| 347 | result += '\\'; |
| 348 | default: |
| 349 | result += ch; |
| 350 | break; |
| 351 | } |
| 352 | } |
| 353 | result += "\""; |
| 354 | return result; |
| 355 | } |
| 356 | |
| 357 | static std::string indent(int n) { |
| 358 | std::string result; |
| 359 | for (int i = 0; i < n; i++) { |
| 360 | result += '\t'; |
| 361 | } |
| 362 | return result; |
| 363 | } |
| 364 | |
| 365 | template <class T> |
| 366 | bool print_arg(const std::vector<T> &vec) { |
| 367 | if (vec.empty()) { |
| 368 | return true; |