| 57 | } |
| 58 | |
| 59 | Status ParseVersion(const string& version_str, |
| 60 | Version* v) { |
| 61 | static regex_t re; |
| 62 | static std::once_flag once; |
| 63 | static const char* kVersionPattern = |
| 64 | "^([[:digit:]]+)\\." // <major>. |
| 65 | "([[:digit:]]+)\\." // <minor>. |
| 66 | "([[:digit:]]+)" // <maintenance> |
| 67 | "([.-].*)?$"; // [<delimiter><extra>] |
| 68 | std::call_once(once, []{ |
| 69 | CHECK_EQ(0, regcomp(&re, kVersionPattern, REG_EXTENDED)); |
| 70 | }); |
| 71 | |
| 72 | DCHECK(v); |
| 73 | const Status invalid_ver_err = |
| 74 | Status::InvalidArgument("invalid version string", version_str); |
| 75 | auto v_str = version_str; |
| 76 | StripWhiteSpace(&v_str); |
| 77 | |
| 78 | regmatch_t matches[5]; |
| 79 | if (regexec(&re, v_str.c_str(), arraysize(matches), matches, 0) != 0) { |
| 80 | return invalid_ver_err; |
| 81 | } |
| 82 | #define PARSE_REQUIRED_COMPONENT(idx, lhs) \ |
| 83 | { \ |
| 84 | int i = (idx); \ |
| 85 | if (matches[i].rm_so == -1 || \ |
| 86 | !SimpleAtoi(v_str.substr(matches[i].rm_so, \ |
| 87 | matches[i].rm_eo - matches[i].rm_so), \ |
| 88 | (lhs))) { \ |
| 89 | return invalid_ver_err; \ |
| 90 | } \ |
| 91 | } |
| 92 | Version temp_v; |
| 93 | PARSE_REQUIRED_COMPONENT(1, &temp_v.major); |
| 94 | PARSE_REQUIRED_COMPONENT(2, &temp_v.minor); |
| 95 | PARSE_REQUIRED_COMPONENT(3, &temp_v.maintenance); |
| 96 | #undef PARSE_REQUIRED_COMPONENT |
| 97 | if (matches[4].rm_so != -1) { |
| 98 | int extra_comp_off = matches[4].rm_so + 1; // skip the delimiter |
| 99 | int extra_comp_len = matches[4].rm_eo - extra_comp_off; |
| 100 | if (extra_comp_len > 0) { |
| 101 | temp_v.extra_delimiter = v_str[extra_comp_off - 1]; |
| 102 | temp_v.extra = v_str.substr(extra_comp_off, extra_comp_len); |
| 103 | } |
| 104 | } |
| 105 | temp_v.raw_version = version_str; |
| 106 | *v = std::move(temp_v); |
| 107 | |
| 108 | return Status::OK(); |
| 109 | } |
| 110 | |
| 111 | } // namespace kudu |