_ _
| |_ ___| |_ _
| | . | | | |
|_|_|___|_|_ |
|___|
git mirror - github.com/owenewans/holy - branch master
file backends/deb-version.c
#include "deb-version.h"
#include <stddef.h>
#include <string.h>
struct part { const char *start, *end; };
struct version { struct part epoch, upstream, revision; };
static int digit(unsigned char c) { return c >= '0' && c <= '9'; }
static int letter(unsigned char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static int split(const char *text, struct version *out)
{
const char *p, *end, *colon = NULL, *dash = NULL;
static const char zero[] = "0";
if (!text || !*text) return 0;
for (end = text; *end; ++end) {
if (end - text >= 65536 || (!letter((unsigned char)*end) &&
!digit((unsigned char)*end) && !strchr(".+:~-", *end))) return 0;
if (*end == ':' && !colon) colon = end;
if (*end == '-') dash = end;
}
out->epoch = (struct part){zero, zero + 1};
if (colon) {
if (colon == text) return 0;
for (p = text; p < colon; ++p) if (!digit((unsigned char)*p)) return 0;
out->epoch = (struct part){text, colon};
text = colon + 1;
}
if (!digit((unsigned char)*text)) return 0;
if (dash && dash < text) return 0;
out->upstream = (struct part){text, dash ? dash : end};
if (out->upstream.start == out->upstream.end) return 0;
for (p = text; p < out->upstream.end; ++p)
if (*p == ':' && !colon) return 0;
if (dash) {
if (dash + 1 == end) return 0;
for (p = dash + 1; p < end; ++p)
if (!letter((unsigned char)*p) && !digit((unsigned char)*p) &&
!strchr("+.~", *p)) return 0;
out->revision = (struct part){dash + 1, end};
} else {
out->revision = (struct part){end, end};
}
return 1;
}
static int numeric(struct part a, struct part b)
{
size_t x, y;
while (a.start < a.end && *a.start == '0') ++a.start;
while (b.start < b.end && *b.start == '0') ++b.start;
x = (size_t)(a.end - a.start); y = (size_t)(b.end - b.start);
if (x != y) return x < y ? -1 : 1;
if (x) {
int compared = memcmp(a.start, b.start, x);
if (compared) return compared < 0 ? -1 : 1;
}
return 0;
}
static int rank(unsigned char c)
{
if (c == '~') return -1;
if (!c || digit(c)) return 0;
if (letter(c)) return c;
return c + 256;
}
static int component(struct part a, struct part b)
{
const char *x = a.start, *y = b.start;
while (x < a.end || y < b.end) {
int first = 0;
while ((x < a.end && !digit((unsigned char)*x)) ||
(y < b.end && !digit((unsigned char)*y))) {
int left = rank(x < a.end ? (unsigned char)*x : 0);
int right = rank(y < b.end ? (unsigned char)*y : 0);
if (left != right) return left < right ? -1 : 1;
if (x < a.end) ++x;
if (y < b.end) ++y;
}
while (x < a.end && *x == '0') ++x;
while (y < b.end && *y == '0') ++y;
while (x < a.end && y < b.end && digit((unsigned char)*x) && digit((unsigned char)*y)) {
if (!first) first = *x - *y;
++x; ++y;
}
if (x < a.end && digit((unsigned char)*x)) return 1;
if (y < b.end && digit((unsigned char)*y)) return -1;
if (first) return first < 0 ? -1 : 1;
}
return 0;
}
int holy_deb_version_compare(const char *a, const char *b, int *order)
{
struct version left, right;
if (!order || !split(a, &left) || !split(b, &right)) return 0;
*order = numeric(left.epoch, right.epoch);
if (!*order) *order = component(left.upstream, right.upstream);
if (!*order) *order = component(left.revision, right.revision);
return 1;
}