#include #include #include #include #include "zpm.h" #define TEXT 1 #define NUMERIC 2 struct ver { #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 */ 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 */ }; static void init_ver(struct ver *v, const char *s) { #if 0 strncpy(v->str, s, 1023); v->str[1023] = 0; v->name[1023] = 0; #endif v->str = s; v->release = 0; v->s = v->str; v->cn = 0; v->next = v->str; v->sep = 0; v->len = 0; v->type = 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 == 0 && b->type == 0) { return 0; } if (a->type != b->type) { return a->type < b->type ? -1 : 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 == NUMERIC) { if (a->nv != b->nv) return a->nv < b->nv ? -1 : 1; } return 0; } static int next_comp(struct ver *v) { const char *s, *next; next = v->next; v->len = 0; v->type = 0; /* skip over anything that isn't alphanumeric */ v->sep = 0; while (*next && !isalnum(*next)) { next++; } /* zero return if at end of string */ if (!*next) { v->s = next; return 0; } s = next; v->s = next; if (isdigit(*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 = 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->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; } 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) { cmp = 1; break; } else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) { cmp = -1; break; } cmp = an < bn ? -1 : 1; break; } if (an == 0 && bn == 0) { break; } cmp = ver_cmp(&a, &b); if (cmp != 0) { break; } } while (an && bn); if (cmp != 0) { return cmp; } /* compare release */ if (ainfo.release != binfo.release) { cmp = ainfo.release < binfo.release ? -1 : 1; } return cmp; }