bool read_constdb(ZString filename) { io::ReadFile in(filename); if (!in.is_open()) { PRINTF("can't read %s\n"_fmt, filename); return false; } bool rv = true; AString line_; while (in.getline(line_)) { // is_comment only works for whole-line comments // that could change once the Z dependency is dropped ... LString comment = "//"_s; XString line = line_.xislice_h(std::search(line_.begin(), line_.end(), comment.begin(), comment.end())).rstrip(); if (!line) continue; // "%m[A-Za-z0-9_] %i %i" // TODO promote either qsplit() or asplit() auto _it = std::find(line.begin(), line.end(), ' '); auto name = line.xislice_h(_it); auto _rest = line.xislice_t(_it); while (_rest.startswith(' ')) _rest = _rest.xslice_t(1); auto _it2 = std::find(_rest.begin(), _rest.end(), ' '); auto val_ = _rest.xislice_h(_it2); auto type_ = _rest.xislice_t(_it2); while (type_.startswith(' ')) type_ = type_.xslice_t(1); // yes, the above actually DTRT even for underlength input int val; int type = 0; // Note for future archeaologists: this code is indented correctly if (std::find_if_not(name.begin(), name.end(), [](char c) { return ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || (c == '_'); }) != name.end() || !extract(val_, &val) || (!extract(type_, &type) && type_)) { PRINTF("Bad const line: %s\n"_fmt, line_); rv = false; continue; } P<str_data_t> n = add_strp(name); n->type = type ? StringCode::PARAM : StringCode::INT; n->val = val; } return rv; }
inline bool extract(XString str, HumanTimeDiff *iv) { // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) // there are NO spaces here // parse by counting the number starts auto is_num = [](char c) { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; if (!str || !is_num(str.front())) return false; *iv = HumanTimeDiff{}; while (str) { auto it = std::find_if_not(str.begin(), str.end(), is_num); auto it2 = std::find_if(it, str.end(), is_num); XString number = str.xislice_h(it); XString suffix = str.xislice(it, it2); str = str.xislice_t(it2); short *ptr = nullptr; if (suffix == "y"_s || suffix == "a"_s) ptr = &iv->year; else if (suffix == "m"_s) ptr = &iv->month; else if (suffix == "j"_s || suffix == "d"_s) ptr = &iv->day; else if (suffix == "h"_s) ptr = &iv->hour; else if (suffix == "mn"_s) ptr = &iv->minute; else if (suffix == "s"_s) ptr = &iv->second; else return false; if (number.startswith('+') && !number.startswith("+-"_s)) number = number.xslice_t(1); if (*ptr || !extract(number, ptr)) return false; } return true; }
/// Return a pair of strings, {spellname, parameter} /// Parameter may be empty. static std::pair<XString, XString> magic_tokenise(XString src) { auto seeker = std::find(src.begin(), src.end(), ' '); if (seeker == src.end()) { return {src, XString()}; } else { XString rv1 = src.xislice_h(seeker); ++seeker; while (seeker != src.end() && *seeker == ' ') ++seeker; // Note: this very well could be empty XString rv2 = src.xislice_t(seeker); return {rv1, rv2}; } }
//--------------------------------------------------- // E-mail check: return 0 (not correct) or 1 (valid). //--------------------------------------------------- bool e_mail_check(XString email) { // athena limits if (email.size() < 3 || email.size() > 39) return 0; // part of RFC limits (official reference of e-mail description) XString::iterator at = std::find(email.begin(), email.end(), '@'); if (at == email.end()) return 0; XString username = email.xislice_h(at); XString hostname = email.xislice_t(at + 1); if (!username || !hostname) return 0; if (hostname.contains('@')) return 0; if (hostname.front() == '.' || hostname.back() == '.') return 0; if (hostname.contains_seq("..")) return 0; if (email.contains_any(" ;")) return 0; return email.is_print(); }