LCOV - code coverage report
Current view: top level - src/util - fn.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 92 92 100.0 %
Date: 2025-03-25 01:19:55 Functions: 7 7 100.0 %
Branches: 37 48 77.1 %

           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, "&", "&amp;");
                   +  - ]
      63   [ +  -  +  -  :          4 :     str = replace_all(str, "<", "&lt;");
                   +  - ]
      64   [ +  -  +  -  :          4 :     str = replace_all(str, ">", "&gt;");
                   +  - ]
      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                 :            : }

Generated by: LCOV version 1.16