Import pkg_install-20090528:
[netbsd-mini2440.git] / external / bsd / pkg_install / dist / lib / dewey.c
blob56c73b70dfee49dc131d6e925cb493e806b7da47
1 /* $NetBSD: dewey.c,v 1.11 2009/03/06 15:18:42 joerg Exp $ */
3 /*
4 * Copyright © 2002 Alistair G. Crooks. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #if HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include <nbcompat.h>
36 #if HAVE_CTYPE_H
37 #include <ctype.h>
38 #endif
39 #if HAVE_STDLIB_H
40 #include <stdlib.h>
41 #endif
43 #include "defs.h"
44 #include "dewey.h"
46 #define PKG_PATTERN_MAX 1024
48 /* do not modify these values, or things will NOT work */
49 enum {
50 Alpha = -3,
51 Beta = -2,
52 RC = -1,
53 Dot = 0,
54 Patch = 1
57 /* this struct defines a version number */
58 typedef struct arr_t {
59 unsigned c; /* # of version numbers */
60 unsigned size; /* size of array */
61 int *v; /* array of decimal numbers */
62 int netbsd; /* any "nb" suffix */
63 } arr_t;
65 /* this struct describes a test */
66 typedef struct test_t {
67 const char *s; /* string representation */
68 unsigned len; /* length of string */
69 int t; /* enumerated type of test */
70 } test_t;
73 /* the tests that are recognised. */
74 const test_t tests[] = {
75 { "<=", 2, DEWEY_LE },
76 { "<", 1, DEWEY_LT },
77 { ">=", 2, DEWEY_GE },
78 { ">", 1, DEWEY_GT },
79 { "==", 2, DEWEY_EQ },
80 { "!=", 2, DEWEY_NE },
81 { NULL, 0, 0 }
84 const test_t modifiers[] = {
85 { "alpha", 5, Alpha },
86 { "beta", 4, Beta },
87 { "pre", 3, RC },
88 { "rc", 2, RC },
89 { "pl", 2, Dot },
90 { "_", 1, Dot },
91 { ".", 1, Dot },
92 { NULL, 0, 0 }
97 /* locate the test in the tests array */
98 int
99 dewey_mktest(int *op, const char *test)
101 const test_t *tp;
103 for (tp = tests ; tp->s ; tp++) {
104 if (strncasecmp(test, tp->s, tp->len) == 0) {
105 *op = tp->t;
106 return tp->len;
109 return -1;
113 * make a component of a version number.
114 * '.' encodes as Dot which is '0'
115 * '_' encodes as 'patch level', or 'Dot', which is 0.
116 * 'pl' encodes as 'patch level', or 'Dot', which is 0.
117 * 'alpha' encodes as 'alpha version', or Alpha, which is -3.
118 * 'beta' encodes as 'beta version', or Beta, which is -2.
119 * 'rc' encodes as 'release candidate', or RC, which is -1.
120 * 'nb' encodes as 'netbsd version', which is used after all other tests
122 static int
123 mkcomponent(arr_t *ap, const char *num)
125 static const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
126 const test_t *modp;
127 int n;
128 const char *cp;
130 if (ap->c == ap->size) {
131 if (ap->size == 0) {
132 ap->size = 62;
133 if ((ap->v = malloc(ap->size * sizeof(int))) == NULL)
134 err(EXIT_FAILURE, "mkver malloc failed");
135 } else {
136 ap->size *= 2;
137 if ((ap->v = realloc(ap->v, ap->size * sizeof(int)))
138 == NULL)
139 err(EXIT_FAILURE, "mkver realloc failed");
142 if (isdigit((unsigned char)*num)) {
143 for (cp = num, n = 0 ; isdigit((unsigned char)*num) ; num++) {
144 n = (n * 10) + (*num - '0');
146 ap->v[ap->c++] = n;
147 return (int)(num - cp);
149 for (modp = modifiers ; modp->s ; modp++) {
150 if (strncasecmp(num, modp->s, modp->len) == 0) {
151 ap->v[ap->c++] = modp->t;
152 return modp->len;
155 if (strncasecmp(num, "nb", 2) == 0) {
156 for (cp = num, num += 2, n = 0 ; isdigit((unsigned char)*num) ; num++) {
157 n = (n * 10) + (*num - '0');
159 ap->netbsd = n;
160 return (int)(num - cp);
162 if (isalpha((unsigned char)*num)) {
163 ap->v[ap->c++] = Dot;
164 cp = strchr(alphas, tolower((unsigned char)*num));
165 if (ap->c == ap->size) {
166 ap->size *= 2;
167 if ((ap->v = realloc(ap->v, ap->size * sizeof(int))) == NULL)
168 err(EXIT_FAILURE, "mkver realloc failed");
170 ap->v[ap->c++] = (int)(cp - alphas) + 1;
171 return 1;
173 return 1;
176 /* make a version number string into an array of comparable ints */
177 static int
178 mkversion(arr_t *ap, const char *num)
180 ap->c = 0;
181 ap->size = 0;
182 ap->v = NULL;
183 ap->netbsd = 0;
185 while (*num) {
186 num += mkcomponent(ap, num);
188 return 1;
191 static void
192 freeversion(arr_t *ap)
194 free(ap->v);
195 ap->v = NULL;
196 ap->c = 0;
197 ap->size = 0;
200 #define DIGIT(v, c, n) (((n) < (c)) ? v[n] : 0)
202 /* compare the result against the test we were expecting */
203 static int
204 result(int cmp, int tst)
206 switch(tst) {
207 case DEWEY_LT:
208 return cmp < 0;
209 case DEWEY_LE:
210 return cmp <= 0;
211 case DEWEY_GT:
212 return cmp > 0;
213 case DEWEY_GE:
214 return cmp >= 0;
215 case DEWEY_EQ:
216 return cmp == 0;
217 case DEWEY_NE:
218 return cmp != 0;
219 default:
220 return 0;
224 /* do the test on the 2 vectors */
225 static int
226 vtest(arr_t *lhs, int tst, arr_t *rhs)
228 int cmp;
229 unsigned int c, i;
231 for (i = 0, c = MAX(lhs->c, rhs->c) ; i < c ; i++) {
232 if ((cmp = DIGIT(lhs->v, lhs->c, i) - DIGIT(rhs->v, rhs->c, i)) != 0) {
233 return result(cmp, tst);
236 return result(lhs->netbsd - rhs->netbsd, tst);
240 * Compare two dewey decimal numbers
243 dewey_cmp(const char *lhs, int op, const char *rhs)
245 arr_t right;
246 arr_t left;
247 int retval;
249 if (!mkversion(&left, lhs))
250 return 0;
251 if (!mkversion(&right, rhs)) {
252 freeversion(&left);
253 return 0;
255 retval = vtest(&left, op, &right);
256 freeversion(&left);
257 freeversion(&right);
258 return retval;
262 * Perform dewey match on "pkg" against "pattern".
263 * Return 1 on match, 0 on non-match, -1 on error.
266 dewey_match(const char *pattern, const char *pkg)
268 const char *version;
269 const char *sep, *sep2;
270 int op, op2;
271 int n;
273 /* compare names */
274 if ((version=strrchr(pkg, '-')) == NULL) {
275 return 0;
277 if ((sep = strpbrk(pattern, "<>")) == NULL)
278 return -1;
279 /* compare name lengths */
280 if ((sep-pattern != version-pkg) ||
281 strncmp(pkg, pattern, (size_t)(version-pkg)) != 0)
282 return 0;
283 version++;
285 /* extract comparison operator */
286 if ((n = dewey_mktest(&op, sep)) < 0) {
287 return 0;
289 /* skip operator */
290 sep += n;
292 /* if greater than, look for less than */
293 sep2 = NULL;
294 if (op == DEWEY_GT || op == DEWEY_GE) {
295 if ((sep2 = strchr(sep, '<')) != NULL) {
296 if ((n = dewey_mktest(&op2, sep2)) < 0) {
297 return 0;
299 /* compare upper limit */
300 if (!dewey_cmp(version, op2, sep2+n))
301 return 0;
305 /* compare only pattern / lower limit */
306 if (sep2) {
307 char ver[PKG_PATTERN_MAX];
309 strlcpy(ver, sep, MIN((ssize_t)sizeof(ver), sep2-sep+1));
310 if (dewey_cmp(version, op, ver))
311 return 1;
313 else {
314 if (dewey_cmp(version, op, sep))
315 return 1;
318 return 0;