#include "storage_paths.h" #include namespace roro::storage { namespace { // Howard Hinnant's days_from_civil. int daysFromCivil(int y, int m, int d) { y -= m <= 2; int era = (y >= 0 ? y : y - 399) / 400; int yoe = y - era * 400; int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; return era * 146097 + doe - 719468; } bool digits(const std::string& s, size_t pos, size_t n, int& out) { if (pos + n > s.size()) return false; out = 0; for (size_t i = pos; i < pos + n; i++) { if (!std::isdigit(static_cast(s[i]))) return false; out = out * 10 + (s[i] - '0'); } return true; } int validDay(int y, int m, int d) { static const int kDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (y < 1970 || m < 1 || m > 12 || d < 1 || d > kDays[m - 1]) return -1; return daysFromCivil(y, m, d); } } // namespace std::string sanitize(const std::string& name) { std::string out; for (char c : name) { bool forbidden = c == '\\' || c == '/' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|' || static_cast(c) < 0x20; out += forbidden ? '_' : c; } if (out.empty() || out == ".") return "_"; if (out == "..") return "_."; return out; } std::string dailyLogPath(std::initializer_list folders, const std::string& date) { std::string path; for (auto& f : folders) path += "/" + sanitize(f); return path + "/" + (date.empty() ? "undated" : date) + ".log"; } int fileDay(const std::string& name) { int y, m, d; if (digits(name, 0, 4, y) && name.size() > 10 && name[4] == '-' && digits(name, 5, 2, m) && name[7] == '-' && digits(name, 8, 2, d)) return validDay(y, m, d); if (digits(name, 0, 4, y) && digits(name, 4, 2, m) && digits(name, 6, 2, d) && name.size() > 8 && name[8] == '-') return validDay(y, m, d); return -1; } int dayFromUtc(int64_t utcSeconds) { return static_cast(utcSeconds / 86400); } } // namespace roro::storage