From: Nathan Wagner Date: Thu, 17 Nov 2016 09:10:05 +0000 (+0000) Subject: add zpm-vercmp X-Git-Tag: v0.1.6~156 X-Git-Url: https://pd.if.org/git/?p=zpackage;a=commitdiff_plain;h=07a13ad59dc3e488d7eba6368f54a308f0b31f9c add zpm-vercmp --- diff --git a/t/vercmp.t b/t/vercmp.t new file mode 100755 index 0000000..2799a53 --- /dev/null +++ b/t/vercmp.t @@ -0,0 +1,38 @@ +#!/bin/sh + +# test addfile + +. tap.sh + +vtest() { + res=$(zpm-vercmp "$1" "$2") + okstreq "$res" -1 "$1 < $2" + res=$(zpm-vercmp "$2" "$1") + okstreq "$res" 1 "$2 > $1" + res=$(zpm-vercmp "$1" "$1") + okstreq "$res" 0 "$1 == $1" +} + +plan 45 + +# alpha +vtest 1.0a 1.0b +vtest 1.0b 1.0beta +vtest 1.0beta 1.0p +vtest 1.0p 1.0pre +vtest 1.0pre 1.0rc +vtest 1.0rc 1.0 +vtest 1.0 1.0.a +vtest 1.0.a 1.0.1 + +vtest 1 1.0 +vtest 1.0 1.1 +vtest 1.1 1.1.1 +vtest 1.2 2.0 +vtest 2.0 3.0.0 + +# release +vtest 1.0-1 1.0-2 +vtest 1.0-2 2.0-1 + +finish diff --git a/vercmp.c b/vercmp.c new file mode 100644 index 0000000..58053d9 --- /dev/null +++ b/vercmp.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +struct ver { + char str[1024]; /* string rep */ + char *s; /* start component */ + int cn; /* current component number */ + char *next; /* start of potential next component */ + char keep; /* character over-written with null byte */ + int sep; /* number of characters in separator */ + + int nv; /* numeric value */ + int type; /* 0 null, 1 text, 2 numeric */ + int release; + char *relstr; +}; + +void init_ver(struct ver *v, char *s) { + strncpy(v->str, s, 1023); + v->str[1023] = 0; + v->s = 0; + v->cn = 0; + v->next = v->str; + v->relstr = 0; + v->keep = 0; + v->sep = 0; + + /* scan for trailing release */ + int n; + n = strlen(v->str) - 1; + if (n > 0 && isdigit(v->str[n])) { + while (isdigit(v->str[n])) { + n--; + } + if (s[n] == '-') { + v->relstr = v->str + n; + v->release = atoi(v->str + n + 1); + v->str[n] = 0; + } + } + +} + +int ver_cmp(struct ver *a, struct ver *b) { + if (a->type == 0 && b->type == 0) { + return 0; + } + if (a->type != b->type) { + return a->type < b->type ? -1 : 1; + } + if (a->type == 1) { + int cmp; + cmp = strcmp(a->s, b->s); + if (cmp == 0) { + return 0; + } + return cmp < 0 ? -1 : 1; + } + if (a->type == 2) { + if (a->nv != b->nv) + return a->nv < b->nv ? -1 : 1; + } + return 0; +} + +int next_comp(struct ver *v) { + char *s; + + /* restore over-written character */ + if (v->keep) { + v->next[0] = v->keep; + v->keep = 0; + } + s = v->next; + + /* skip over anything that isn't alphanumeric */ + v->sep = 0; + while (*s && !isalnum(*s)) { + v->sep++; + s++; + } + v->next = s; + + /* zero return if at end of string */ + if (!*s) { + return 0; + } + if (isdigit(*s)) { + v->type = 2; + while (isdigit(*s)) s++; + v->keep = *s; + *s = 0; + v->s = v->next; + v->nv = atoi(v->s); + } else if (isalpha(*s)) { + v->type = 1; + while (isalpha(*s)) s++; + v->keep = *s; + *s = 0; + v->s = v->next; + } + v->next = s; + + return ++v->cn; +} + +/* + * alphabetic less than numeric + */ +int main(int ac, char *av[]) { + struct ver a, b; + int an, bn; + int cmp; + + if (ac < 2) return 1; + + init_ver(&a, av[1]); + init_ver(&b, av[2]); + do { + an = next_comp(&a); + bn = next_comp(&b); + if (an != bn) { + if (an == 0 && a.type == 2 && b.sep == 0 && b.type == 1) { + printf("1\n"); + } else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) { + printf("-1\n"); + } else { + printf("%s\n", an < bn ? "-1" : "1"); + } + exit(0); + } + cmp = ver_cmp(&a, &b); + if (cmp != 0) { + printf("%d\n", cmp); + exit(0); + } + } while (an && bn); + + /* if we've gotten here, and both have releases, check those */ + if (a.relstr && b.relstr && a.release != b.release) { + printf("%s\n", a.release < b.release ? "-1" : "1"); + exit(0); + } + + printf("0\n"); + return 0; +}