#include "utils.h" #include "filesystem.hh" #include "platform.h" #include #include #include #include #include #include #include #include #include #include using namespace std::placeholders; void TrimInPlace(std::string& s) { auto f = [](char c) { return !isspace(c); }; s.erase(s.begin(), std::find_if(s.begin(), s.end(), f)); s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end()); } std::string Trim(std::string s) { TrimInPlace(s); return s; } uint64_t HashUsr(std::string_view s) { union { uint64_t ret; uint8_t out[8]; }; // k is an arbitrary key. Don't change it. const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d}; (void)siphash(reinterpret_cast(s.data()), s.size(), k, out, 8); return ret; } bool EndsWith(std::string_view s, std::string_view suffix) { return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); } bool StartsWith(std::string_view s, std::string_view prefix) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } bool AnyStartsWith(const std::vector& xs, std::string_view prefix) { return std::any_of(xs.begin(), xs.end(), std::bind(StartsWith, _1, prefix)); } bool StartsWithAny(std::string_view s, const std::vector& ps) { return std::any_of(ps.begin(), ps.end(), std::bind(StartsWith, s, _1)); } bool EndsWithAny(std::string_view s, const std::vector& ss) { return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1)); } bool FindAnyPartial(const std::string& value, const std::vector& values) { return std::any_of(std::begin(values), std::end(values), [&value](const std::string& v) { return value.find(v) != std::string::npos; }); } std::vector SplitString(const std::string& str, const std::string& delimiter) { // http://stackoverflow.com/a/13172514 std::vector strings; std::string::size_type pos = 0; std::string::size_type prev = 0; while ((pos = str.find(delimiter, prev)) != std::string::npos) { strings.push_back(str.substr(prev, pos - prev)); prev = pos + 1; } // To get the last substring (or only, if delimiter is not found) strings.push_back(str.substr(prev)); return strings; } std::string LowerPathIfInsensitive(const std::string& path) { #if defined(_WIN32) std::string ret = path; for (char& c : ret) c = tolower(c); return ret; #else return path; #endif } void EnsureEndsInSlash(std::string& path) { if (path.empty() || path[path.size() - 1] != '/') path += '/'; } std::string EscapeFileName(std::string path) { bool slash = path.size() && path.back() == '/'; for (char& c : path) if (c == '\\' || c == '/' || c == ':') c = '@'; if (slash) path += '/'; return path; } std::optional ReadContent(const std::string& filename) { LOG_S(INFO) << "read " << filename; char buf[4096]; std::string ret; FILE* f = fopen(filename.c_str(), "rb"); if (!f) return {}; size_t n; while ((n = fread(buf, 1, sizeof buf, f)) > 0) ret.append(buf, n); fclose(f); return ret; } void WriteToFile(const std::string& filename, const std::string& content) { FILE* f = fopen(filename.c_str(), "wb"); if (!f || (content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) { LOG_S(ERROR) << "failed to write to " << filename << ' ' << strerror(errno); return; } fclose(f); } std::optional LastWriteTime(const std::string& filename) { std::error_code ec; auto ftime = fs::last_write_time(filename, ec); if (ec) return std::nullopt; return std::chrono::time_point_cast(ftime) .time_since_epoch() .count(); } std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }