]> pd.if.org Git - zpackage/blob - lib/vercmp.c
16cf1cdc4eab48ab1f4b89b4cac0178d23b4a858
[zpackage] / lib / vercmp.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 struct ver {
7         char str[1024]; /* string rep */
8         char *s; /* start component */
9         int cn; /* current component number */
10         char *next; /* start of potential next component */
11         char keep; /* character over-written with null byte */
12         int sep; /* number of characters in separator */
13         
14         int nv; /* numeric value */
15         int type; /* 0 null, 1 text, 2 numeric */
16         int release;
17         char *relstr;
18 };
19
20 static void init_ver(struct ver *v, const char *s) {
21         strncpy(v->str, s, 1023);
22         v->str[1023] = 0;
23         v->s = 0;
24         v->cn = 0;
25         v->next = v->str;
26         v->relstr = 0;
27         v->keep = 0;
28         v->sep = 0;
29
30         /* scan for trailing release */
31         int n;
32         n = strlen(v->str) - 1;
33         if (n > 0 && isdigit(v->str[n])) {
34                 while (isdigit(v->str[n])) {
35                         n--;
36                 }
37                 if (s[n] == '-') {
38                         v->relstr = v->str + n;
39                         v->release = atoi(v->str + n + 1);
40                         v->str[n] = 0;
41                 }
42         }
43
44 }
45
46 static int ver_cmp(struct ver *a, struct ver *b) {
47         if (a->type == 0 && b->type == 0) {
48                 return 0;
49         }
50         if (a->type != b->type) {
51                 return a->type < b->type ? -1 : 1;
52         }
53         if (a->type == 1) {
54                 int cmp;
55                 if (a->s && ! b->s) return 1;
56                 if (b->s && ! a->s) return -1;
57                 if (!b->s && ! a->s) return 0;
58                 cmp = strcmp(a->s, b->s);
59                 if (cmp == 0) {
60                         return 0;
61                 }
62                 return cmp < 0 ? -1 : 1;
63         }
64         if (a->type == 2) {
65                 if (a->nv != b->nv)
66                 return a->nv < b->nv ? -1 : 1;
67         }
68         return 0;
69 }
70
71 static int next_comp(struct ver *v) {
72         char *s;
73
74         /* restore over-written character */
75         if (v->keep) {
76                 v->next[0] = v->keep;
77                 v->keep = 0;
78         }
79         s = v->next;
80
81         /* skip over anything that isn't alphanumeric */
82         v->sep = 0;
83         while (*s && !isalnum(*s)) {
84                 v->sep++;
85                 s++;
86         }
87         v->next = s;
88
89         /* zero return if at end of string */
90         if (!*s) {
91                 return 0;
92         }
93         if (isdigit(*s)) {
94                 v->type = 2;
95                 while (isdigit(*s)) s++;
96                 v->keep = *s;
97                 *s = 0;
98                 v->s = v->next;
99                 v->nv = atoi(v->s);
100         } else if (isalpha(*s)) {
101                 v->type = 1;
102                 while (isalpha(*s)) s++;
103                 v->keep = *s;
104                 *s = 0;
105                 v->s = v->next;
106         }
107         v->next = s;
108
109         return ++v->cn;
110 }
111
112 /*
113  * alphabetic less than numeric
114  */
115 int zpm_vercmp(const char *vsa, const char *vsb) {
116         struct ver a, b;
117         int an, bn;
118         int cmp;
119
120         init_ver(&a, vsa);
121         init_ver(&b, vsb);
122         do {
123                 an = next_comp(&a);
124                 bn = next_comp(&b);
125                 if (an != bn) {
126                         if (an == 0 && a.type == 2 && b.sep == 0 && b.type == 1) {
127                                 return 1;
128                         } else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) {
129                                 return -1;
130                         }
131                         return an < bn ? -1 : 1;
132                 }
133                 if (an == 0 && bn == 0) {
134                         return 0;
135                 }
136                 cmp = ver_cmp(&a, &b);
137                 if (cmp != 0) {
138                         return cmp;
139                 }
140         } while (an && bn);
141
142         /* if we've gotten here, and both have releases, check those */
143         if (a.relstr && b.relstr && a.release != b.release) {
144                 return a.release < b.release ? -1 : 1;
145         }
146         
147         return 0;
148 }