]> pd.if.org Git - zpackage/blobdiff - lib/vercmp.c
remove stray debug fprintf
[zpackage] / lib / vercmp.c
index 91d536305cdcf97d6c84d0b32343a1f794d69c73..c533be02aae4cf66c19064a94217c8313786281e 100644 (file)
@@ -3,44 +3,77 @@
 #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) {
@@ -50,15 +83,21 @@ 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;
        }
@@ -66,77 +105,128 @@ 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;
+       }
+       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;
 }