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