1 /* Copyright (C) 2012-2021 by László Nagy 2 This file is part of Bear. 3 4 Bear is a tool to generate compilation database for clang tooling. 5 6 Bear is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 Bear is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "libshell/Command.h" 21 22 #include <regex> 23 #include <stdexcept> 24 25 namespace sh { 26 escape(const std::string & input)27 std::string escape(const std::string& input) 28 { 29 if (input.empty()) { 30 return "''"; 31 } 32 33 const std::regex ESCAPE_PATTERN(R"#(([^A-Za-z0-9_\-.,:/@\n]))#"); 34 const std::regex LINE_FEED(R"#(\n)#"); 35 36 auto output = std::regex_replace(input, ESCAPE_PATTERN, "\\$1"); 37 return std::regex_replace(output, LINE_FEED, "'\n'"); 38 } 39 join(const std::list<std::string> & arguments)40 std::string join(const std::list<std::string>& arguments) 41 { 42 std::string result; 43 for (auto it = arguments.begin(); it != arguments.end(); ++it) { 44 if (it != arguments.begin()) { 45 result += " "; 46 } 47 result += escape(*it); 48 } 49 return result; 50 } 51 split(const std::string & input)52 rust::Result<std::list<std::string>> split(const std::string& input) 53 { 54 const std::regex MAIN_PATTERN(R"#((?:\s*(?:([^\s\\'"]+)|'([^']*)'|"((?:[^"\\]|\\.)*)"|(\\.?)|(\S))(\s|$)?))#", 55 std::regex::ECMAScript); 56 const std::regex ESCAPE_PATTERN(R"#(\\(.))#"); 57 const std::regex METACHAR_PATTERN(R"(\\([$`"\\\n]))"); 58 59 std::list<std::string> words; 60 std::string field; 61 62 auto input_begin = std::sregex_iterator(input.begin(), input.end(), MAIN_PATTERN); 63 auto input_end = std::sregex_iterator(); 64 for (auto it = input_begin; it != input_end; ++it) { 65 if (it->ready()) { 66 if (it->operator[](1).matched) { 67 field += it->str(1); 68 } else if (it->operator[](2).matched) { 69 field += it->str(2); 70 } else if (it->operator[](3).matched) { 71 field += std::regex_replace(it->str(3), METACHAR_PATTERN, "$1"); 72 } else if (it->operator[](4).matched) { 73 field += std::regex_replace(it->str(4), ESCAPE_PATTERN, "$1"); 74 } else if (it->operator[](5).matched) { 75 return rust::Err(std::runtime_error("Mismatched quotes.")); 76 } 77 78 if (it->operator[](6).matched) { 79 words.push_back(field); 80 field.clear(); 81 } 82 } 83 } 84 return rust::Ok(words); 85 } 86 } 87