]> pd.if.org Git - zpackage/blob - lib/vercmp.c
remove stray debug fprintf
[zpackage] / lib / vercmp.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include "zpm.h"
7
8 #define TEXT 1
9 #define NUMERIC 2
10
11 struct ver {
12 #if 0
13         char name[1024];
14         char str[1024]; /* string rep of the version */
15 #endif
16         const char *str;
17         int release; /* a trailing -\d+ value */
18         const char *s; /* start component */
19         int cn; /* current component number */
20         int len; /* current component length */
21
22         const char *next; /* start of potential next component */
23         int sep; /* number of characters in separator */
24         
25         int nv; /* numeric value */
26         int type; /* 0 null, 1 text, 2 numeric */
27 };
28
29 static void init_ver(struct ver *v, const char *s) {
30 #if 0
31         strncpy(v->str, s, 1023);
32         v->str[1023] = 0;
33         v->name[1023] = 0;
34 #endif
35         v->str = s;
36         v->release = 0;
37         v->s = v->str;
38         v->cn = 0;
39         v->next = v->str;
40         v->sep = 0;
41         v->len = 0;
42         v->type = 0;
43 }
44
45 static int cmp_strlen(const char *a, size_t alen, const char *b, size_t blen) {
46         size_t shortest;
47         int base;
48
49         if (a && !b) {
50                 return 1;
51         } else if (b && !a) {
52                 return -1;
53         } else if (!a && !b) {
54                 return 0;
55         }
56
57         if (alen && !blen) {
58                 return 1;
59         } else if (blen && !alen) {
60                 return -1;
61         } else if (!alen && !blen) {
62                 return 0;
63         }
64
65         shortest = alen < blen ? alen : blen;
66
67         base = strncmp(a, b, shortest);
68
69         if (base == 0) {
70                 if (alen == blen) {
71                         return 0;
72                 }
73                 return alen < blen ? -1 : 1;
74         }
75
76         return base < 0 ? -1 : 1;
77 }
78
79 static int ver_cmp(struct ver *a, struct ver *b) {
80         if (a->type == 0 && b->type == 0) {
81                 return 0;
82         }
83         if (a->type != b->type) {
84                 return a->type < b->type ? -1 : 1;
85         }
86
87         if (a->type == TEXT) {
88                 int cmp;
89                 if (a->s && ! b->s) return 1;
90                 if (b->s && ! a->s) return -1;
91                 if (!b->s && ! a->s) {
92                         return 0;
93                 }
94                 cmp = strcmp(a->s, b->s);
95                 if (cmp == 0) {
96                         return 0;
97                 }
98                 return cmp < 0 ? -1 : 1;
99         }
100         if (a->type == NUMERIC) {
101                 if (a->nv != b->nv)
102                 return a->nv < b->nv ? -1 : 1;
103         }
104         return 0;
105 }
106
107 static int next_comp(struct ver *v) {
108         const char *s, *next;
109
110         next = v->next;
111         v->len = 0;
112         v->type = 0;
113
114         /* skip over anything that isn't alphanumeric */
115         v->sep = 0;
116         while (*next && !isalnum(*next)) {
117                 next++;
118         }
119
120         /* zero return if at end of string */
121         if (!*next) {
122                 v->s = next;
123                 return 0;
124         }
125
126         s = next;
127         v->s = next;
128
129         if (isdigit(*s)) {
130                 v->type = NUMERIC;
131                 v->nv = *s-'0';
132                 while (isdigit(*s)) {
133                         v->nv = v->nv * 10 + *s-'0';
134                         v->len++;
135                         s++;
136                 }
137                 v->next = s;
138         } else if (isalpha(*s)) {
139                 v->type = TEXT;
140                 while (*s && (isalpha(*s) || *s == '-') ) {
141                         v->len++;
142                         s++;
143                 }
144                 v->next = s;
145                 /* last character in a alphabetic can't be a - */
146                 while (*s == '-') {
147                         v->len--;
148                         s--;
149                 }
150         } else {
151                 /* impossible */
152                 return 0;
153         }
154
155         v->cn++;
156         return v->cn;
157 }
158
159 /*
160  * alphabetic less than numeric
161  * return -1 if vsa < vsb, 0 if equal, 1 if vsa > vsb
162  */
163 int zpm_vercmp(const char *vsa, const char *vsb) {
164         struct ver a, b;
165         struct zpm_version_info ainfo, binfo;
166         int an, bn;
167         int cmp;
168         char astr[256], bstr[256];
169
170         if (vsa && !vsb) {
171                 return 1;
172         }
173         if (vsb && !vsa) {
174                 return -1;
175         }
176         if (!vsa && !vsb) {
177                 return 0;
178         }
179
180         zpm_parse_version(vsa, &ainfo);
181         zpm_parse_version(vsb, &binfo);
182         cmp = cmp_strlen(ainfo.name, ainfo.namelen, binfo.name, binfo.namelen);
183
184         if (cmp != 0) {
185                 return cmp;
186         }
187
188         if (ainfo.verlen > 255) {
189                 ainfo.verlen = 255;
190         }
191         if (binfo.verlen > 255) {
192                 binfo.verlen = 255;
193         }
194
195         strncpy(astr, ainfo.version, ainfo.verlen);
196         strncpy(bstr, binfo.version, binfo.verlen);
197         astr[ainfo.verlen] = 0;
198         bstr[binfo.verlen] = 0;
199
200         init_ver(&a, astr);
201         init_ver(&b, bstr);
202         do {
203                 an = next_comp(&a);
204                 bn = next_comp(&b);
205                 if (an != bn) {
206                         if (an == 0 && a.type == 2 && b.sep == 0 && b.type == 1) {
207                                 cmp = 1; break;
208                         } else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) {
209                                 cmp = -1; break;
210                         }
211                         cmp = an < bn ? -1 : 1; break;
212                 }
213                 if (an == 0 && bn == 0) {
214                         break;
215                 }
216                 cmp = ver_cmp(&a, &b);
217                 if (cmp != 0) {
218                         break;
219                 }
220         } while (an && bn);
221
222         if (cmp != 0) {
223                 return cmp;
224         }
225
226         /* compare release */
227         if (ainfo.release != binfo.release) {
228                 cmp = ainfo.release < binfo.release ? -1 : 1;
229         }
230
231         return cmp;
232 }