]> pd.if.org Git - zpackage/blobdiff - lib/vercmp.c
fix vercmp bugs
[zpackage] / lib / vercmp.c
index cfc7edd27519e9e1f58924ecbb5ff51e9d937a45..5d22aea798ffd25db8ecde7082a55e5f8fa4d57e 100644 (file)
@@ -3,12 +3,23 @@
 #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 */
@@ -16,13 +27,53 @@ struct ver {
 };
 
 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->keep = 0;
        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) {
@@ -32,7 +83,8 @@ 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;
@@ -45,7 +97,7 @@ static int ver_cmp(struct ver *a, struct ver *b) {
                }
                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;
        }
@@ -53,53 +105,67 @@ static int ver_cmp(struct ver *a, struct ver *b) {
 }
 
 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;
@@ -111,27 +177,56 @@ int zpm_vercmp(const char *vsa, const char *vsb) {
                return 0;
        }
 
-       init_ver(&a, vsa);
-       init_ver(&b, vsb);
+       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.verstr, ainfo.verlen);
+       strncpy(bstr, binfo.verstr, 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) {
-                       return 0;
+                       break;
                }
                cmp = ver_cmp(&a, &b);
                if (cmp != 0) {
-                       return cmp;
+                       break;
                }
        } while (an && bn);
 
-       return 0;
+       if (cmp != 0) {
+               return cmp;
+       }
+
+       /* compare release */
+       if (ainfo.release != binfo.release) {
+               cmp = ainfo.release < binfo.release ? -1 : 1;
+       }
+
+       return cmp;
 }