#include <string.h>
#include <ctype.h>
+#include "zpm.h"
+
+#define TEXT 1
+#define NUMERIC 2
+
struct ver {
- char str[1024]; /* string rep */
- char *s; /* start component */
+#if 0
+ char name[1024];
+ char str[1024]; /* string rep of the version */
+#endif
+ const char *str;
+ int release; /* a trailing -\d+ value */
+ const 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 len; /* current component length */
+
+ const char *next; /* start of potential next component */
int sep; /* number of characters in separator */
int nv; /* numeric value */
int type; /* 0 null, 1 text, 2 numeric */
- int release;
- char *relstr;
};
static void init_ver(struct ver *v, const char *s) {
+#if 0
strncpy(v->str, s, 1023);
v->str[1023] = 0;
- v->s = 0;
+ v->name[1023] = 0;
+#endif
+ v->str = s;
+ v->release = 0;
+ v->s = v->str;
v->cn = 0;
v->next = v->str;
- v->relstr = 0;
- v->keep = 0;
v->sep = 0;
+ v->len = 0;
+ v->type = 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;
+static int cmp_strlen(const char *a, size_t alen, const char *b, size_t blen) {
+ size_t shortest;
+ int base;
+
+ if (a && !b) {
+ return 1;
+ } else if (b && !a) {
+ return -1;
+ } else if (!a && !b) {
+ return 0;
+ }
+
+ if (alen && !blen) {
+ return 1;
+ } else if (blen && !alen) {
+ return -1;
+ } else if (!alen && !blen) {
+ return 0;
+ }
+
+ shortest = alen < blen ? alen : blen;
+
+ base = strncmp(a, b, shortest);
+
+ if (base == 0) {
+ if (alen == blen) {
+ return 0;
}
+ return alen < blen ? -1 : 1;
}
+ return base < 0 ? -1 : 1;
}
static int ver_cmp(struct ver *a, struct ver *b) {
if (a->type != b->type) {
return a->type < b->type ? -1 : 1;
}
- if (a->type == 1) {
+
+ if (a->type == TEXT) {
int cmp;
+ if (a->s && ! b->s) return 1;
+ if (b->s && ! a->s) return -1;
+ if (!b->s && ! a->s) {
+ return 0;
+ }
cmp = strcmp(a->s, b->s);
if (cmp == 0) {
return 0;
}
return cmp < 0 ? -1 : 1;
}
- if (a->type == 2) {
+ if (a->type == NUMERIC) {
if (a->nv != b->nv)
return a->nv < b->nv ? -1 : 1;
}
}
static int next_comp(struct ver *v) {
- char *s;
+ const char *s, *next;
- /* restore over-written character */
- if (v->keep) {
- v->next[0] = v->keep;
- v->keep = 0;
- }
- s = v->next;
+ next = v->next;
+ v->len = 0;
+ v->type = 0;
/* skip over anything that isn't alphanumeric */
v->sep = 0;
- while (*s && !isalnum(*s)) {
- v->sep++;
- s++;
+ while (*next && !isalnum(*next)) {
+ next++;
}
- v->next = s;
/* zero return if at end of string */
- if (!*s) {
+ if (!*next) {
+ v->s = next;
return 0;
}
+
+ s = next;
+ v->s = next;
+
if (isdigit(*s)) {
- v->type = 2;
- while (isdigit(*s)) s++;
- v->keep = *s;
- *s = 0;
- v->s = v->next;
- v->nv = atoi(v->s);
+ v->type = NUMERIC;
+ v->nv = *s-'0';
+ while (isdigit(*s)) {
+ v->nv = v->nv * 10 + *s-'0';
+ v->len++;
+ s++;
+ }
+ v->next = s;
} else if (isalpha(*s)) {
- v->type = 1;
- while (isalpha(*s)) s++;
- v->keep = *s;
- *s = 0;
- v->s = v->next;
+ v->type = TEXT;
+ while (*s && (isalpha(*s) || *s == '-') ) {
+ v->len++;
+ s++;
+ }
+ v->next = s;
+ /* last character in a alphabetic can't be a - */
+ while (*s == '-') {
+ v->len--;
+ s--;
+ }
+ } else {
+ /* impossible */
+ return 0;
}
- v->next = s;
- return ++v->cn;
+ v->cn++;
+ return v->cn;
}
/*
* alphabetic less than numeric
+ * return -1 if vsa < vsb, 0 if equal, 1 if vsa > vsb
*/
int zpm_vercmp(const char *vsa, const char *vsb) {
struct ver a, b;
+ struct zpm_version_info ainfo, binfo;
int an, bn;
int cmp;
+ char astr[256], bstr[256];
+
+ if (vsa && !vsb) {
+ return 1;
+ }
+ if (vsb && !vsa) {
+ return -1;
+ }
+ if (!vsa && !vsb) {
+ return 0;
+ }
+
+ zpm_parse_version(vsa, &ainfo);
+ zpm_parse_version(vsb, &binfo);
+ cmp = cmp_strlen(ainfo.name, ainfo.namelen, binfo.name, binfo.namelen);
+
+ if (cmp != 0) {
+ return cmp;
+ }
- init_ver(&a, vsa);
- init_ver(&b, vsb);
+ if (ainfo.verlen > 255) {
+ ainfo.verlen = 255;
+ }
+ if (binfo.verlen > 255) {
+ binfo.verlen = 255;
+ }
+
+ strncpy(astr, ainfo.version, ainfo.verlen);
+ strncpy(bstr, binfo.version, binfo.verlen);
+ astr[ainfo.verlen] = 0;
+ bstr[binfo.verlen] = 0;
+
+ init_ver(&a, astr);
+ init_ver(&b, bstr);
do {
an = next_comp(&a);
bn = next_comp(&b);
if (an != bn) {
if (an == 0 && a.type == 2 && b.sep == 0 && b.type == 1) {
- return 1;
+ cmp = 1; break;
} else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) {
- return -1;
+ cmp = -1; break;
}
- return an < bn ? -1 : 1;
+ cmp = an < bn ? -1 : 1; break;
+ }
+ if (an == 0 && bn == 0) {
+ break;
}
cmp = ver_cmp(&a, &b);
if (cmp != 0) {
- return cmp;
+ break;
}
} while (an && bn);
- /* if we've gotten here, and both have releases, check those */
- if (a.relstr && b.relstr && a.release != b.release) {
- return a.release < b.release ? -1 : 1;
+ if (cmp != 0) {
+ return cmp;
}
-
- return 0;
+
+ /* compare release */
+ if (ainfo.release != binfo.release) {
+ cmp = ainfo.release < binfo.release ? -1 : 1;
+ }
+
+ return cmp;
}