1 /* $NetBSD: dewey.c,v 1.1.1.3 2009/03/08 14:51:37 joerg Exp $ */
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
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
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.
46 #define PKG_PATTERN_MAX 1024
48 /* do not modify these values, or things will NOT work */
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 */
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 */
73 /* the tests that are recognised. */
74 const test_t tests
[] = {
75 { "<=", 2, DEWEY_LE
},
77 { ">=", 2, DEWEY_GE
},
79 { "==", 2, DEWEY_EQ
},
80 { "!=", 2, DEWEY_NE
},
84 const test_t modifiers
[] = {
85 { "alpha", 5, Alpha
},
97 /* locate the test in the tests array */
99 dewey_mktest(int *op
, const char *test
)
103 for (tp
= tests
; tp
->s
; tp
++) {
104 if (strncasecmp(test
, tp
->s
, tp
->len
) == 0) {
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
123 mkcomponent(arr_t
*ap
, const char *num
)
125 static const char alphas
[] = "abcdefghijklmnopqrstuvwxyz";
130 if (ap
->c
== ap
->size
) {
133 if ((ap
->v
= malloc(ap
->size
* sizeof(int))) == NULL
)
134 err(EXIT_FAILURE
, "mkver malloc failed");
137 if ((ap
->v
= realloc(ap
->v
, ap
->size
* sizeof(int)))
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');
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
;
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');
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
) {
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;
176 /* make a version number string into an array of comparable ints */
178 mkversion(arr_t
*ap
, const char *num
)
186 num
+= mkcomponent(ap
, num
);
192 freeversion(arr_t
*ap
)
200 #define DIGIT(v, c, n) (((n) < (c)) ? v[n] : 0)
202 /* compare the result against the test we were expecting */
204 result(int cmp
, int tst
)
224 /* do the test on the 2 vectors */
226 vtest(arr_t
*lhs
, int tst
, arr_t
*rhs
)
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
)
249 if (!mkversion(&left
, lhs
))
251 if (!mkversion(&right
, rhs
)) {
255 retval
= vtest(&left
, op
, &right
);
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
)
269 const char *sep
, *sep2
;
274 if ((version
=strrchr(pkg
, '-')) == NULL
) {
277 if ((sep
= strpbrk(pattern
, "<>")) == NULL
)
279 /* compare name lengths */
280 if ((sep
-pattern
!= version
-pkg
) ||
281 strncmp(pkg
, pattern
, (size_t)(version
-pkg
)) != 0)
285 /* extract comparison operator */
286 if ((n
= dewey_mktest(&op
, sep
)) < 0) {
292 /* if greater than, look for less than */
294 if (op
== DEWEY_GT
|| op
== DEWEY_GE
) {
295 if ((sep2
= strchr(sep
, '<')) != NULL
) {
296 if ((n
= dewey_mktest(&op2
, sep2
)) < 0) {
299 /* compare upper limit */
300 if (!dewey_cmp(version
, op2
, sep2
+n
))
305 /* compare only pattern / lower limit */
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
))
314 if (dewey_cmp(version
, op
, sep
))