in src/split2monodb.h [64:179]
int split2monodb::parse_upstreams() {
assert(!has_read_upstreams);
assert(upstreamsfd != -1);
mmapped_file file(upstreamsfd);
upstreamsfd = -1;
if (!file.num_bytes) {
// No upstreams.
has_read_upstreams = true;
return 0;
}
struct context {
const char *beg;
const char *cur;
const char *end;
context() = delete;
explicit context(const mmapped_file &file)
: beg(file.bytes), cur(file.bytes), end(file.bytes + file.num_bytes) {}
};
// Create some simple parsers.
context c(file);
auto parse_name = [&c](std::string &name) {
auto *last = c.cur;
for (; last != c.end; ++last) {
// Allow "[0-9a-zA-Z-+_.]".
if (*last >= '0' && *last <= '9' && last != c.cur)
continue;
if (*last >= 'a' && *last <= 'z')
continue;
if (*last >= 'A' && *last <= 'Z')
continue;
if (*last == '.' || *last == '-' || *last == '+' || *last == '_')
continue;
break;
}
if (c.cur == last)
return error("invalid name");
name.assign(c.cur, last);
c.cur = last;
return 0;
};
auto parse_number = [&c](long &num) {
auto *last = c.cur;
for (; last != c.end; ++last) {
if (*last >= '0' && *last <= '9')
continue;
break;
}
if (c.cur == last)
return error("invalid non-negative integer");
std::string digits(c.cur, last);
c.cur = last;
num = strtol(digits.c_str(), nullptr, 10);
assert(num >= 0);
return 0;
};
auto parse_space = [&c](bool needs_any, bool newlines) {
// Pull out a separate flag for needing newlines, for simplicity.
bool needs_newline = newlines && needs_any;
while (*c.cur == ' ' || *c.cur == '\t' || *c.cur == '\n') {
if (*c.cur == '\n') {
if (!newlines)
return error("unexpected newline");
needs_newline = false;
}
++c.cur;
needs_any = false;
}
if (needs_newline)
return error("missing newline");
if (needs_any)
return error("expected space");
return 0;
};
auto parse_string = [&c](const char *label) {
auto impl = [&c](const char *label) {
for (; c.cur != c.end && *label; ++c.cur, ++label) {
if (*c.cur == *label)
continue;
return 1;
}
return *label ? 1 : 0;
};
if (impl(label))
return error("could not parse label '" + std::string(label) + "'");
return 0;
};
// Parse.
if (parse_space(/*needs_any=*/false, /*newlines=*/true) ||
parse_string("name:") ||
parse_space(/*needs_any=*/true, /*newlines=*/false) || parse_name(name) ||
parse_space(/*needs_any=*/true, /*newlines=*/true))
return error("could not parse name");
while (c.cur != c.end) {
upstream_entry ue;
if (parse_string("upstream:") ||
parse_space(/*needs_any=*/true, /*newlines=*/false) ||
parse_name(ue.name) ||
parse_space(/*needs_any=*/true, /*newlines=*/false) ||
parse_string("num-upstreams=") || parse_number(ue.num_upstreams) ||
parse_space(/*needs_any=*/true, /*newlines=*/false) ||
parse_string("commits-size=") || parse_number(ue.commits_size) ||
parse_space(/*needs_any=*/true, /*newlines=*/false) ||
parse_string("svnbase-size=") || parse_number(ue.svnbase_size) ||
parse_space(/*needs_any=*/true, /*newlines=*/true))
return 1;
if (ue.name == name)
return error("upstream has same name as main repo");
std::string copy_name = ue.name;
if (!upstreams.emplace(std::move(copy_name), std::move(ue)).second)
return error("duplicate upstream");
}
has_read_upstreams = true;
return 0;
}