Branch data Line data Source code
1 : : #include <mutable/util/fn.hpp> 2 : : 3 : : #if __linux 4 : : #include <sys/types.h> 5 : : #include <sys/wait.h> 6 : : #include <unistd.h> 7 : : #elif __APPLE__ 8 : : #include <string.h> 9 : : #include <sys/wait.h> 10 : : #include <unistd.h> 11 : : #endif 12 : : 13 : : 14 : : using namespace m; 15 : : 16 : : 17 : 7 : std::string m::escape(const std::string &str, char esc, char quote) 18 : : { 19 : 7 : std::string res; 20 : 7 : res.reserve(str.length()); 21 : : 22 [ + + ]: 112 : for (auto c : str) { 23 : 105 : if (c == esc or c == quote) { 24 : 9 : res += esc; 25 : 9 : res += c; 26 [ + + ]: 105 : } else if (c == '\n') { 27 : 5 : res += esc; 28 : 5 : res += 'n'; 29 : 5 : } else { 30 : 91 : res += c; 31 : : } 32 : : } 33 : : 34 : 7 : return res; 35 : 7 : } 36 : : 37 : 164 : std::string m::unescape(const std::string &str, char esc, char quote) 38 : : { 39 : 164 : std::string res; 40 : 164 : res.reserve(str.length()); 41 : : 42 [ + + ]: 1511 : for (auto it = str.begin(), end = str.end(); it != end; ++it) { 43 [ + + ]: 1347 : if (*it == esc) { 44 : 16 : ++it; 45 : 16 : if (*it == esc or *it == quote) { 46 : 9 : res += *it; 47 [ + + ]: 16 : } else if (*it == 'n') { 48 : 5 : res += '\n'; 49 : 5 : } else { 50 : : /* invalid escape sequence; do not unescape */ 51 : 2 : res += esc; 52 : 2 : --it; 53 : : } 54 : 16 : } else { 55 : 1331 : res += *it; 56 : : } 57 : 1347 : } 58 : : 59 : 164 : return res; 60 : 164 : } 61 : : 62 : 4 : std::string m::html_escape(std::string str) 63 : : { 64 [ + - + - : 4 : str = replace_all(str, "&", "&"); + - ] 65 [ + - + - : 4 : str = replace_all(str, "<", "<"); + - ] 66 [ + - + - : 4 : str = replace_all(str, ">", ">"); + - ] 67 : 4 : return str; 68 : : } // M_LCOV_EXCL_LINE 69 : : 70 : 76 : bool m::like(const std::string &str, const std::string &pattern, const char escape_char) 71 : : { 72 : 76 : M_insist('_' != escape_char and '%' != escape_char, "illegal escape character"); 73 : : 74 : 77 : bool dp[pattern.length() + 1][str.length() + 1]; // dp[i][j] == true iff pattern[:i] contains str[:j] 75 : : 76 : 76 : dp[0][0] = true; // empty pattern contains empty string 77 [ + + ]: 349 : for (std::size_t j = 1; j <= str.length(); ++j) 78 : 273 : dp[0][j] = false; // empty pattern does not contain non-empty string 79 : 76 : std::size_t escaped_row = 0; 80 [ + + ]: 352 : for (std::size_t i = 1; i <= pattern.length(); ++i) { 81 : 281 : const auto c = pattern[i - 1]; 82 : 281 : const auto escaped = i == escaped_row; 83 : 281 : if (escaped and '_' != c and '%' != c and escape_char != c) 84 [ + - ]: 11 : throw m::runtime_error("invalid escape sequence"); 85 : 258 : if (not escaped and escape_char == c) 86 : 29 : escaped_row = i + 1; // next row is escaped 87 : 258 : if (not escaped and '%' == c) 88 : 61 : dp[i][0] = dp[i - 1][0]; // pattern `X%` contains empty string iff `X` contains empty string 89 : : else 90 : 215 : dp[i][0] = false; // pattern without `%`-wildcard does not contain empty string 91 : 276 : } 92 [ + + ]: 71 : if (pattern.length() + 1 == escaped_row) 93 [ + - ]: 6 : throw m::runtime_error("invalid escape sequence"); 94 : : 95 : 65 : escaped_row = 0; 96 [ + + ]: 324 : for (std::size_t i = 1; i <= pattern.length(); ++i) { 97 : 259 : const auto c = pattern[i - 1]; 98 : 259 : const auto escaped = i == escaped_row; 99 : 259 : if (not escaped and escape_char == c) { 100 : : /* Set `escaped_row` and copy entire above row. */ 101 : 17 : escaped_row = i + 1; 102 [ + + ]: 121 : for (std::size_t j = 0; j <= str.length(); ++j) 103 : 104 : dp[i][j] = dp[i - 1][j]; 104 : 17 : continue; 105 : : } 106 [ + + ]: 1831 : for (std::size_t j = 1; j <= str.length(); ++j) { 107 : 1589 : if (not escaped and '%' == c) { 108 : : /* pattern `X%` contains string `c_0...c_n` iff either `X%` contains `c_0...c_{n-1} 109 : : * or `X` contains `c_0...c_n` */ 110 : 432 : dp[i][j] = dp[i][j - 1] or dp[i - 1][j]; 111 : 1502 : } else if ((not escaped and '_' == c) or str[j - 1] == c) { 112 : : /* pattern `X_` contains string `c_0...c_n` iff `X` contains `c_0...c_{n-1}`, 113 : : * pattern `Xa` contains string `c_0...c_{n-1}a` iff `X` contains `c_0...c_{n-1}` */ 114 : 462 : dp[i][j] = dp[i - 1][j - 1]; 115 : 462 : } else { 116 : : /* pattern `Xa` does not contain string `c_0...c_n` if a != c_n */ 117 : 695 : dp[i][j] = false; 118 : : } 119 : 1589 : } 120 : 242 : } 121 : : 122 : 65 : return dp[pattern.length()][str.length()]; 123 : 65 : } 124 : : 125 : 3 : void m::exec(const char *executable, std::initializer_list<const char*> args) 126 : : { 127 : : #if __linux || __APPLE__ 128 : 3 : pid_t pid = fork(); 129 [ + + ]: 3 : if (pid > 0) { 130 : : /* parent: wait for child to finish */ 131 : : int status; 132 : 3 : waitpid(pid, &status, 0); 133 [ + - ]: 6 : } else if (pid == 0) { 134 : : /* child */ 135 : 3 : char **c_args = new char*[args.size() + 2]; 136 : 3 : char **p = c_args; 137 : 3 : *p++ = strdup(executable); 138 [ + + ]: 7 : for (auto arg : args) 139 : 4 : *p++ = strdup(arg); 140 : 3 : *p = nullptr; 141 : 3 : execv(executable, c_args); 142 : : M_unreachable("Invalid executable path or arguments"); // M_LCOV_EXCL_LINE 143 : : } 144 : : #endif 145 : 3 : } 146 : : 147 : 9724 : std::size_t m::get_pagesize() 148 : : { 149 : : static std::size_t pagesize(0); 150 : 9724 : if (0 == pagesize) 151 : 1 : pagesize = sysconf(_SC_PAGESIZE); 152 : 9724 : return pagesize; 153 : : }