]> pd.if.org Git - zpackage/commitdiff
fix vercmp bugs
authorNathan Wagner <nw@hydaspes.if.org>
Tue, 26 Feb 2019 05:10:18 +0000 (05:10 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Tue, 26 Feb 2019 05:10:18 +0000 (05:10 +0000)
Makefile
doc/zpm-vercmp.8
lib/parse.c
lib/vercmp.c
src/vercmp.c
t/vercmp.t
zpm.h

index 802360ba8ce644bffc8176952ad2f70b47c84554..dabebe853f4664a69878df27189b8bbeb5750793 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ lib/jsw/jsw_rbtree.c
 JSWOBJ=$(JSWSRC:%.c=%.o)
 LIBZPMSRC=sha256.c db.c compress.c uncompress.c zpm.c zpm_hash.c \
          foreach_path.c vercmp.c findpkg.c quote.c dbquery.c script_hash.c \
-         parse.c integ.c seterror.c notes.c createpkg.c
+         parse.c integ.c seterror.c notes.c createpkg.c buffer.c
 
 LIBZPMOBJ=$(addprefix lib/, $(LIBZPMSRC:%.c=%.o))
 
@@ -198,10 +198,10 @@ sqlite/shell.o: sqlite/shell.c sqlite/config.h Makefile
 
 lib/zpm.o: newdb.c
 
-zpm-vercmp: src/vercmp.o lib/vercmp.o
+zpm-vercmp: src/vercmp.o lib/vercmp.o lib/parse.o
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+
        
-zpm-shell: sqlite/sqlite3.o sqlite/shell.o sqlite/extensions.o lib/vercmp.o
+zpm-shell: sqlite/sqlite3.o sqlite/shell.o sqlite/extensions.o lib/vercmp.o lib/parse.o
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+
 
 libelf.a: elf/libelf.o
index 9a31fac7e2c495cdfebd3d4fcefda213c08322eb..d046998954a6f57e269a8942ec247896cde3a780 100644 (file)
@@ -1,28 +1,46 @@
-.TH zpm-vercmp 8 2018-12-10 "ZPM 0.4"
+.TH zpm-vercmp 8 2019-02-26 "ZPM 0.4"
 .SH NAME
 zpm-vercmp \- compare strings with version numbering
 .SH SYNOPSIS
 .B zpm vercmp \fR[\fB-q\fR] \fIstring1 string2\fR
 .SH DESCRIPTION
-\fBzpm-vercmp\fR compares its first two arguments, using
-the usual version numbering semantics.  It will write
-the result of the comparison to stdout, 0 if the arguments
-compare equal, -1 if the first is greater, and 1 if the
-second is greater.
+\fBzpm-vercmp\fR compares its arguments, using
+version numbering semantics.  It can operate in
+test mode or search mode.  In search mode, activated with \-G or \-L
+it will print the highest or lowest version string to stdout.
+.PP
+In test mode, it compares all the arguments, and prints '0' if they are all
+equal, '-1' if they are in version order, and 1 if they are out of order.
+Adjacent identical version strings are considered both equal and in order.
+Additionally in test mode,
+the process will exit 0 if the strings are all equal, 1 if the
+strings are not in order, and 2 if they are in order.
 .SH OPTIONS
 .TP
 \-q
 write nothing to stdout.  The program will still exit with the
 usual exit status
+.TP
+\-G
+Print the largest argument version string found.
+.TP
+\-L
+Print the smallest argument version string found.
 .SH EXAMPLES
 .PP
 .nf
-zpm-vercmp a b -> "1"
+zpm-vercmp a b -> "-1"
 .fi
 .SH EXIT STATUS
-0 if the two strings compare equal
--1 if the first string is greater than the second
-1 if the second string is greater then the first
+.TP
+0
+if the strings are all equal
+.TP
+1
+if the strings are not in version order
+.TP
+2
+if the strings are in version order
 .SH FILES
 None
 .SH ENVIRONMENT
index 5009c01bff3decc5964459457dcd795d3bb6aed8..2451e3f007b332a9b49926313fa75c31c0020f7a 100644 (file)
@@ -7,10 +7,81 @@
 
 #include "zpm.h"
 
-#include "sqlite3.h"
-
 #define DMARK fprintf(stderr, "mark %s %s:%d\n", __FILE__, __func__, __LINE__)
 
+int zpm_parse_version(const char *pstr, struct zpm_version_info *info) {
+       int cur = 0, ch;
+
+       info->verstr = pstr;
+       info->name = 0;
+       info->namelen = 0;
+       info->version = 0;
+       info->verlen = 0;
+       info->release = -1;
+       info->rellen = 0;
+       info->relstr = 0;
+
+       if (!pstr) {
+               return 0;
+       }
+
+       /* skip leading whitespace */
+       while (isspace(pstr[cur])) {
+               cur++;
+       }
+
+       /* get the name, if any */
+       if (isalpha(pstr[cur])) {
+               info->name = pstr + cur;
+               for (ch = pstr[cur]; ch; ch = pstr[++cur]) {
+                       if (ch == '-') {
+                               if (isdigit(pstr[cur+1])) {
+                                       break;
+                               }
+                       }
+                       if (!isgraph(ch)) {
+                               break;
+                       }
+                       info->namelen++;
+               }
+       }
+
+       while (pstr[cur] == '-') {
+               cur++;
+       }
+
+       /* should be pointing at a digit.  if not, we're done */
+       if (isdigit(pstr[cur])) {
+               info->version = pstr + cur;
+               for (ch = pstr[cur]; ch; ch = pstr[++cur]) {
+                       if (ch == '-') {
+                               break;
+                       }
+                       if (!isgraph(ch)) {
+                               break;
+                       }
+                       info->verlen++;
+               }
+       }
+
+       while (pstr[cur] == '-') {
+               cur++;
+       }
+
+       if (isdigit(pstr[cur])) {
+               info->relstr = pstr + cur;
+               while (isdigit(pstr[cur++])) {
+                       info->rellen++;
+               }
+       }
+
+       if (info->relstr) {
+               info->release = atoi(info->relstr);
+       }
+
+       return info->namelen || info->verlen || info->rellen;
+}
+
 int zpm_parse_package(char *pstr, char *name, char *ver, int *rel) {
        if (name) *name = 0;
        if (ver) *ver = 0;
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;
 }
index b0e5117b8e703384f89f65dee630ca7dea8e2566..340d80fbd013b4df2cc02bf0ba04fcfaf9406be5 100644 (file)
@@ -19,30 +19,23 @@ int main(int ac, char *av[]) {
        int cmp;
        char *a = 0, *b = 0;
        int print = 1;
-       int argn, opt, pass, failed = 0;
-
-       /* 0x1 = less than, 0x2 = equal, 0x4 = greater */
-       unsigned testmask = 0;
-       unsigned testcases = 0;
+       int argn, opt = 0;
+       int inorder = 1, equal = 1;
 
        char *greatest = 0;
        char *least = 0;
 
-       if (ac < 2) return 1;
-
-       while ((opt = getopt(ac, av, "qgleLG")) != -1) {
+       while ((opt = getopt(ac, av, "qLG")) != -1) {
                switch (opt) {
                        case 'q': print = 0; break;
-                       case 'l': testmask |= 0x1; break;
-                       case 'e': testmask |= 0x2; break;
-                       case 'g': testmask |= 0x4; break;
-                       case 'L': print = 2; break;
-                       case 'G': print = 3; break;
+                       case 'G': print = 2; break;
+                       case 'L': print = 3; break;
                        default:
                                  exit(EXIT_FAILURE);
                                  break;
                }
        }
+
        argn = optind;
 
        if (ac > argn) {
@@ -54,43 +47,44 @@ int main(int ac, char *av[]) {
        while (ac > argn) {
                b = av[argn++];
 
-               cmp = zpm_vercmp(a, b) + 1;
-               testcases |= (1<<cmp);
-               
-               if (testmask) {
-                       pass = (testmask & (1 << cmp));
-                       if (!pass) {
-                               failed++;
-                       }
+               cmp = zpm_vercmp(a, b);
+               switch (cmp) {
+                       case 0:
+                               break;
+                       case -1:
+                               equal = 0;
+                               break;
+                       case 1:
+                               equal = 0;
+                               inorder = 0;
+                               break;
+                       default:
+                               break;
                }
-
-               cmp = zpm_vercmp(greatest, b);
+               
+               cmp = zpm_vercmp(b, greatest);
                if (cmp > 0) {
                        greatest = b;
                }
 
-               cmp = zpm_vercmp(least, b);
+               cmp = zpm_vercmp(b, least);
                if (cmp < 0) {
                        least = b;
                }
+               a = b;
        }
 
-       switch (testcases) {
-               case 0: /* no tests */
-                       cmp = 0; break;
-               case 1: /* only less than */
-                       cmp = 2; break;
-               case 2: /* only equal */
-                       cmp = 0; break;
-               case 4: /* only greater than */
-                       cmp = 1; break;
-               default: /* mixed */
-                       cmp = 3; break;
+       if (equal) {
+               cmp = 0;
+       } else if (inorder) {
+               cmp = -1;
+       } else {
+               cmp = 1;
        }
 
        switch (print) {
                case 1:
-                       printf("%d\n", cmp == 2 ? -1 : cmp);
+                       printf("%d\n", cmp);
                        break;
                case 2:
                        if (greatest) printf("%s\n", greatest);
@@ -101,11 +95,6 @@ int main(int ac, char *av[]) {
                default:
                        break;
        }
-       fflush(stdout);
 
-       if (testmask == 0) {
-               return cmp;
-       } else {
-               return failed ? 1 : 0;
-       }
+       return cmp == -1 ? 2 : cmp;
 }
index a877c08e2824d3c8fb3dab79381c66454f4741ed..205f9502ec8f8f0c768c824c68d2a5167cca1cd2 100755 (executable)
@@ -4,13 +4,29 @@
 
 . tap.sh
 
+# 17 vtests, 3 least, 3 greatest, 2 other, 3 temp handling
+# 17 * 6 + 3 + 3
+plan 111
+
+require rm -rf tmp
+require mkdir tmp
+
 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"
+
+       res=$(zpm shell vercmp.db "select '$1' < '$2' collate vercmp")
+       okstreq "$res" 1 "zpm shell $1 < $2"
+       res=$(zpm shell vercmp.db "select '$1' > '$2' collate vercmp")
+       okstreq "$res" 0 "zpm shell not $1 > $2"
+       res=$(zpm shell vercmp.db "select '$1' = '$1' collate vercmp")
+       okstreq "$res" 1 "zpm shell $1 = $1"
 }
 
 least() {
@@ -27,8 +43,6 @@ greatest() {
        okstreq "$g" "$want" "greatest $*"
 }
 
-plan 53
-
 least 1.0a 1.0a 1.0b
 least 1.0a 1.0b 1.0a
 greatest z a b z
@@ -36,11 +50,11 @@ greatest z a z b
 least abc abc
 greatest abc abc
  
-zpm vercmp -gq 'gnupg-1.0-1' "gnupg-2.0-1"
-exitwith 1 vercmp -g not gt
+#zpm vercmp -gq 'gnupg-1.0-1' "gnupg-2.0-1"
+#exitwith 1 vercmp -g not gt
 
-zpm vercmp -gq 'gnupg-2.0-1' "gnupg-1.0-1"
-exitwith 0 vercmp -g is gt
+#zpm vercmp -gq 'gnupg-2.0-1' "gnupg-1.0-1"
+#exitwith 0 vercmp -g is gt
 
 # alpha
 vtest 1.0a 1.0b
@@ -48,12 +62,14 @@ 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.0rc
 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
@@ -62,4 +78,9 @@ vtest 2.0 3.0.0
 vtest 1.0-1 1.0-2
 vtest 1.0-2 2.0-1
 
+# full
+vtest ffmpeg-4.1-3 ffmpeg-4.1.1-1
+vtest 4.1-3 4.1.1-1
+
+require rm -rf tmp
 finish
diff --git a/zpm.h b/zpm.h
index 5eddd56e1646716a839e7d1596ddb49aefaa2029..98971c126bb64adc45deb0cea274c2949addbb00 100644 (file)
--- a/zpm.h
+++ b/zpm.h
@@ -198,6 +198,15 @@ void *compresslzma(void *buf, size_t bufsize, size_t *len);
 int zpm_hash(char *path, char *hash, uint32_t flags);
 int zpm_readopts(struct zpm *pkg, int ac, char **av);
 
+struct zpm_version_info {
+       const char *verstr;
+       const char *name; int namelen;
+       const char *version; int verlen;
+       const char *relstr; int rellen;
+       int release;
+};
+
+int zpm_parse_version(const char *pstr, struct zpm_version_info *info);
 int zpm_vercmp(const char *a, const char *b);
 
 /* add vercmp collation to db */