147 lines
4.5 KiB
C++
147 lines
4.5 KiB
C++
#include "utils/utils.h"
|
|
|
|
bool compare(const char *a, const char *b, size_t n) {
|
|
size_t i = 0;
|
|
for (; i < n; ++i)
|
|
if (a[i] != b[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
std::string percent_decode(const std::string &s) {
|
|
std::string out;
|
|
out.reserve(s.size());
|
|
for (size_t i = 0; i < s.size(); ++i) {
|
|
if (s[i] == '%' && i + 2 < s.size() && std::isxdigit(s[i + 1]) &&
|
|
std::isxdigit(s[i + 2])) {
|
|
auto hex = [](char c) -> int {
|
|
if ('0' <= c && c <= '9')
|
|
return c - '0';
|
|
if ('a' <= c && c <= 'f')
|
|
return c - 'a' + 10;
|
|
if ('A' <= c && c <= 'F')
|
|
return c - 'A' + 10;
|
|
return 0;
|
|
};
|
|
char decoded = (hex(s[i + 1]) << 4) | hex(s[i + 2]);
|
|
out.push_back(decoded);
|
|
i += 2;
|
|
} else {
|
|
out.push_back(s[i]);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::string percent_encode(const std::string &s) {
|
|
static const char *hex = "0123456789ABCDEF";
|
|
std::string out;
|
|
out.reserve(s.size() * 3);
|
|
for (unsigned char c : s) {
|
|
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' ||
|
|
c == '/') {
|
|
out.push_back(c);
|
|
} else {
|
|
out.push_back('%');
|
|
out.push_back(hex[c >> 4]);
|
|
out.push_back(hex[c & 0xF]);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
std::string substitute_fence(const std::string &documentation,
|
|
const std::string &lang) {
|
|
int errorcode;
|
|
PCRE2_SIZE erroroffset;
|
|
const char *pattern = "\n```\n(.*?)```\n";
|
|
pcre2_code *re =
|
|
pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, PCRE2_DOTALL,
|
|
&errorcode, &erroroffset, nullptr);
|
|
if (!re)
|
|
return documentation;
|
|
PCRE2_SIZE outlen = 0;
|
|
std::string replacement = "```" + lang + "\n$1```";
|
|
int rc = pcre2_substitute(
|
|
re, (PCRE2_SPTR)documentation.c_str(), documentation.size(), 0,
|
|
PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH, nullptr,
|
|
nullptr, (PCRE2_SPTR)replacement.c_str(), replacement.size(), nullptr,
|
|
&outlen);
|
|
if (rc < 0) {
|
|
pcre2_code_free(re);
|
|
return documentation;
|
|
}
|
|
std::string out(outlen, '\0');
|
|
rc = pcre2_substitute(re, (PCRE2_SPTR)documentation.c_str(),
|
|
documentation.size(), 0, PCRE2_SUBSTITUTE_GLOBAL,
|
|
nullptr, nullptr, (PCRE2_SPTR)replacement.c_str(),
|
|
replacement.size(), (PCRE2_UCHAR *)out.data(), &outlen);
|
|
pcre2_code_free(re);
|
|
if (rc < 0)
|
|
return documentation;
|
|
out.resize(outlen);
|
|
return out;
|
|
}
|
|
|
|
std::string trim(const std::string &s) {
|
|
size_t start = s.find_first_not_of(" \t\n\r");
|
|
if (start == std::string::npos)
|
|
return "";
|
|
size_t end = s.find_last_not_of(" \t\n\r");
|
|
return s.substr(start, end - start + 1);
|
|
}
|
|
|
|
std::string clean_text(const std::string &input) {
|
|
std::string result = input;
|
|
static const std::unordered_map<std::string, std::string> entities = {
|
|
{" ", " "}, {"<", "<"}, {">", ">"},
|
|
{"&", "&"}, {""", "\""}, {"'", "'"}};
|
|
for (const auto &e : entities) {
|
|
size_t pos = 0;
|
|
while ((pos = result.find(e.first, pos)) != std::string::npos) {
|
|
result.replace(pos, e.first.length(), e.second);
|
|
pos += e.second.length();
|
|
}
|
|
}
|
|
int errorcode;
|
|
PCRE2_SIZE erroroffset;
|
|
pcre2_code *re =
|
|
pcre2_compile((PCRE2_SPTR) "(\n\\s*)+", PCRE2_ZERO_TERMINATED, 0,
|
|
&errorcode, &erroroffset, nullptr);
|
|
if (!re)
|
|
return result;
|
|
pcre2_match_data *match_data =
|
|
pcre2_match_data_create_from_pattern(re, nullptr);
|
|
PCRE2_SIZE offset = 0;
|
|
std::string clean;
|
|
while (offset < result.size()) {
|
|
int rc = pcre2_match(re, (PCRE2_SPTR)result.c_str(), result.size(), offset,
|
|
0, match_data, nullptr);
|
|
if (rc < 0) {
|
|
clean += result.substr(offset);
|
|
break;
|
|
}
|
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
|
|
clean += result.substr(offset, ovector[0] - offset) + "\n";
|
|
offset = ovector[1];
|
|
}
|
|
pcre2_match_data_free(match_data);
|
|
pcre2_code_free(re);
|
|
std::string final_str;
|
|
size_t start = 0;
|
|
while (start < clean.size()) {
|
|
size_t end = clean.find('\n', start);
|
|
if (end == std::string::npos)
|
|
end = clean.size();
|
|
std::string line = clean.substr(start, end - start);
|
|
size_t first = line.find_first_not_of(" \t\r");
|
|
size_t last = line.find_last_not_of(" \t\r");
|
|
if (first != std::string::npos)
|
|
final_str += line.substr(first, last - first + 1) + "\n";
|
|
start = end + 1;
|
|
}
|
|
if (!final_str.empty() && final_str.back() == '\n')
|
|
final_str.pop_back();
|
|
return final_str;
|
|
}
|