#include "semver.h" #include "epoch.h" #include #include #include #include u128 u128FromVersion(Version *self) { u128 out = 0; uint16_t pre = 0, mask = 03777; uint64_t major, minor, patch, build; int64_t ts; switch (self->vk_tag) { case Simple: out |= ((u128)self->simple.major << (64 + 52)); break; case Rapid: major = (uint64_t)self->rapid.major << 52; minor = (uint64_t)self->rapid.minor << 40; out = (u128)(major | minor) << 64; break; case SemVer: major = (uint64_t)self->semver.major << 52; minor = (uint64_t)self->semver.minor << 40; patch = (uint64_t)self->semver.patch << 28; out = (u128)(major | minor | patch) << 64; break; case Extended: major = (uint64_t)self->extended.major << 52; minor = (uint64_t)self->extended.minor << 40; patch = (uint64_t)self->extended.patch << 28; build = (uint64_t)self->extended.build << 16; out = (u128)(major | minor | patch | build) << 64; break; } switch (self->pr.tag) { case Alpha: out |= ((u128)010000 << 64); pre = self->pr.alpha & mask; out |= ((u128)pre << 64); break; case Beta: out |= ((u128)020000 << 64); pre = self->pr.beta & mask; out |= ((u128)pre << 64); break; case ReleaseCandidate: out |= ((u128)040000 << 64); pre = self->pr.rc & mask; out |= ((u128)pre << 64); break; case GitRev: out |= ((u128)01000 << 64); ts = dateTimeGetTimestamp(&self->pr.git.dt); out |= (u128)ts; break; case PRNone: out |= ((u128)0100000 << 64); break; } return out; } Comparison compareVersion(Version *self, Version *other) { u128 a, b; if (self->arch != other->arch) return CompNone; a = u128FromVersion(self); b = u128FromVersion(other); if (a < b) return CompLess; else if (a == b) return CompEqual; else if (a > b) return CompGreater; else return CompNone; } const char *ArchNames[] = { "any", "arm", "aarch64", "loongson", "mips32", "mips64", "ppc", "ppc64", "riscv64", "s390x", "sparc", "sparc64", "x86", "x86_64" }; const char *archToString(Arch self) { return ArchNames[self]; } int parseArch(char *s) { int i; for (i = 0; i < 14; i++) { if (strncasecmp(s, ArchNames[i], 10) == 0) return i; } if (strncasecmp(s, "arm64", 5) == 0) return arm64; else if (strncasecmp(s, "i386", 4) == 0) return x86; else if (strncasecmp(s, "i486", 4) == 0) return x86; else if (strncasecmp(s, "i586", 4) == 0) return x86; else if (strncasecmp(s, "i686", 4) == 0) return x86; else return -1; } uint16_t parseU12NonZero(char *vp, long *out) { long val; char *ep; if (vp == NULL) { *out = 0; } val = strtol(vp, &ep, 10); if (vp != ep && ep == NULL && val <= U12_MAX && val > 0) { *out = val; } else { return 1; } return 0; } int parseGitRev(char *vp, GitRevision *git) { char hash[7]; int64_t ts; char *hash_str, *ts_str, *ep; int i; hash_str = strtok(vp, "."); if (hash_str == NULL) return 1; if (strnlen(hash_str, 8) != 7) return 2; for (i = 0; i < 7; i++) { hash[i] = hash_str[i]; } ts_str = strtok(NULL, "."); if (ts_str == NULL) return 1; ts = strtoll(ts_str, &ep, 10); if (ts_str == ep || ep != NULL) return 3; if (strtok(NULL, ".") != NULL) return 4; for (i = 0; i < 7; i++) { git->hash[i] = hash[i]; } dateTimeFromTimestampParts(ts, 0, &git->dt); return 0; } int parsePreRelease(PreRelease *pr, char *s) { PreReleaseTag tag; long val = 0; char v[50]; char *vp = (char *)v; ssize_t len = strnlen(s, 52); if (len > 50) return 1; memcpy(s, vp, len); if (strncasecmp(s, "alpha", 5) == 0) { tag = Alpha; vp = s + 5; if (parseU12NonZero(vp, &val) != 0) return 1; } else if (strncasecmp(s, "beta", 4) == 0) { tag = Beta; vp = s + 4; if (parseU12NonZero(vp, &val) != 0) return 1; } else if (strncasecmp(s, "rc", 2) == 0) { tag = ReleaseCandidate; vp = s + 2; if (parseU12NonZero(vp, &val) != 0) return 1; } else if (strncasecmp(s, "git_", 4) == 0) { tag = GitRev; vp = s + 4; if (parseGitRev(vp, &pr->git) != 0) return 1; } pr->tag = tag; switch (tag) { case Alpha: pr->alpha = (uint16_t)val; break; case Beta: pr->beta = (uint16_t)val; break; case ReleaseCandidate: pr->rc = (uint16_t)val; break; case GitRev: break; default: return -1; } return 0; } int parseVersion(Version *self, const char *s) { // todo return -1; } char *versionToString(Version *self) { char *buf, *temp; buf = calloc(100, sizeof(char)); if (buf == NULL) return NULL; temp = calloc(50, sizeof(char)); if (temp == NULL) { free(buf); return NULL; } switch (self->vk_tag) { case Simple: snprintf(buf, 6, "%d", self->simple.major); break; case Rapid: snprintf(buf, 13, "%d.%d", self->rapid.major, self->rapid.minor); break; case SemVer: snprintf( buf, 20, "%d.%d.%d", self->semver.major, self->semver.minor, self->semver.patch ); break; case Extended: snprintf( buf, 27, "%d.%d.%d.%d", self->extended.major, self->extended.minor, self->extended.patch, self->extended.build ); break; } switch (self->pr.tag) { case PRNone: snprintf(temp, 9, "-%s", archToString(self->arch)); break; case Alpha: if (self->pr.alpha == 0) snprintf(temp, 25, "_alpha-%s", archToString(self->arch)); else snprintf(temp, 25, "_alpha%d-%s", self->pr.alpha, archToString(self->arch)); break; case Beta: if (self->pr.beta == 0) snprintf(temp, 25, "_beta-%s", archToString(self->arch)); else snprintf(temp, 25, "_beta%d-%s", self->pr.beta, archToString(self->arch)); break; case ReleaseCandidate: if (self->pr.rc == 0) snprintf(temp, 25, "_rc-%s", archToString(self->arch)); else snprintf(temp, 25, "_rc%d-%s", self->pr.rc, archToString(self->arch)); break; case GitRev: snprintf( temp, 50, "_git_%c%c%c%c%c%c%c.%li-%s", self->pr.git.hash[0], self->pr.git.hash[1], self->pr.git.hash[2], self->pr.git.hash[3], self->pr.git.hash[4], self->pr.git.hash[5], self->pr.git.hash[6], dateTimeGetTimestamp(&self->pr.git.dt), archToString(self->arch) ); } strncat(buf, temp, 50); free(temp); return buf; }