2 * FreeBSD install - a package for the installation and maintenance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
19 #include <sys/cdefs.h>
20 __FBSDID("$FreeBSD$");
26 * Routines to assist with PLIST_FMT_VER numbers in the packing
29 * Following is the PLIST_FMT_VER history:
30 * 1.0 - Initial revision;
31 * 1.1 - When recording/checking checksum of symlink use hash of readlink()
32 * value instead of the hash of an object this links points to.
36 verscmp(Package
*pkg
, int major
, int minor
)
40 if ((pkg
->fmtver_maj
< major
) || (pkg
->fmtver_maj
== major
&&
41 pkg
->fmtver_mnr
< minor
))
43 else if ((pkg
->fmtver_maj
> major
) || (pkg
->fmtver_maj
== major
&&
44 pkg
->fmtver_mnr
> minor
))
51 * split_version(pkgname, endname, epoch, revision) returns a pointer to
52 * the version portion of a package name and the two special components.
54 * Syntax is: ${PORTNAME}-${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
56 * Written by Oliver Eikemeier
57 * Based on work of Jeremy D. Lea.
60 split_version(const char *pkgname
, const char **endname
, unsigned long *epoch
, unsigned long *revision
)
63 const char *versionstr
;
64 const char *endversionstr
;
67 errx(2, "%s: Passed NULL pkgname.", __func__
);
69 /* Look for the last '-' the the pkgname */
70 ch
= strrchr(pkgname
, '-');
71 /* Cheat if we are just passed a version, not a valid package name */
72 versionstr
= ch
? ch
+ 1 : pkgname
;
74 /* Look for the last '_' in the version string, advancing the end pointer */
75 ch
= strrchr(versionstr
, '_');
76 if (revision
!= NULL
) {
77 *revision
= ch
? strtoul(ch
+ 1, NULL
, 10) : 0;
81 /* Look for the last ',' in the remaining version string */
82 ch
= strrchr(endversionstr
? endversionstr
+ 1 : versionstr
, ',');
84 *epoch
= ch
? strtoul(ch
+ 1, NULL
, 10) : 0;
86 if (ch
&& !endversionstr
)
89 /* set the pointer behind the last character of the version without revision or epoch */
91 *endname
= endversionstr
? endversionstr
: strrchr(versionstr
, '\0');
97 * PORTVERSIONs are composed of components separated by dots. A component
98 * consists of a version number, a letter and a patchlevel number. This does
99 * not conform to the porter's handbook, but let us formulate rules that
100 * fit the current practice and are far simpler than to make decisions
101 * based on the order of netters and lumbers. Besides, people use versions
102 * like 10b2 in the ports...
106 #ifdef __LONG_LONG_SUPPORTED
117 * get_component(position, component) gets the value of the next component
118 * (number - letter - number triple) and returns a pointer to the next character
119 * after any leading separators
121 * - components are separated by dots
122 * - characters !~ [a-zA-Z0-9.+*] are treated as separators
123 * (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect:
124 * 1.0.1:2003.09.16 < 1.0:2003.09.16
125 * - consecutive separators are collapsed (10..1 = 10.1)
126 * - missing separators are inserted, essentially
127 * letter number letter => letter number . letter (10a1b2 = 10a1.b2)
128 * - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0)
129 * - the letter sort order is: [none], a, b, ..., z; numbers without letters
130 * sort first (10 < 10a < 10b)
131 * - missing version numbers (in components starting with a letter) sort as -1
133 * - a separator is inserted before the special strings "pl", "alpha", "beta",
135 * - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc"
136 * sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3
137 * < 0.1beta2 = 0.1.b2 < 0.1)
138 * - other strings use only the first letter for sorting, case is ignored
139 * (1.d2 = 1.dev2 = 1.Development2)
140 * - The special component `*' is guaranteed to be the smallest possible
141 * component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*)
142 * - components separated by `+' are handled by version_cmp below
147 static const struct {
153 { "alpha", 5, 'a'-'a'+1 },
154 { "beta", 4, 'b'-'a'+1 },
155 { "pre", 3, 'p'-'a'+1 },
156 { "rc", 2, 'r'-'a'+1 },
161 get_component(const char *position
, version_component
*component
)
163 const char *pos
= position
;
164 int hasstage
= 0, haspatchlevel
= 0;
167 errx(2, "%s: Passed NULL position.", __func__
);
169 /* handle version number */
172 #ifdef __LONG_LONG_SUPPORTED
173 component
->n
= strtoll(pos
, &endptr
, 10);
175 component
->n
= strtol(pos
, &endptr
, 10);
177 /* should we test for errno == ERANGE? */
179 } else if (*pos
== '*') {
183 } while(*pos
&& *pos
!= '+');
191 int c
= tolower(*pos
);
193 /* handle special suffixes */
194 if (isalpha(pos
[1])) {
196 for (i
= 0; stage
[i
].name
; i
++) {
197 if (strncasecmp(pos
, stage
[i
].name
, stage
[i
].namelen
) == 0
198 && !isalpha(pos
[stage
[i
].namelen
])) {
201 component
->a
= stage
[i
].value
;
202 pos
+= stage
[i
].namelen
;
213 /* unhandled above */
215 /* use the first letter and skip following */
216 component
->a
= c
- 'a' + 1;
219 } while (isalpha(*pos
));
227 /* handle patch number */
230 #ifdef __LONG_LONG_SUPPORTED
231 component
->pl
= strtoll(pos
, &endptr
, 10);
233 component
->pl
= strtol(pos
, &endptr
, 10);
235 /* should we test for errno == ERANGE? */
244 /* skip trailing separators */
245 while (*pos
&& !isdigit(*pos
) && !isalpha(*pos
) && *pos
!= '+' && *pos
!= '*') {
253 * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version
254 * components of pkg1 is less than, equal to or greater than pkg2. No
255 * comparison of the basenames is done.
257 * The port version is defined by:
258 * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}]
259 * ${PORTEPOCH} supersedes ${PORTVERSION} supersedes ${PORTREVISION}.
260 * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk
261 * for more information.
263 * The epoch and revision are defined to be a single number, while the rest
264 * of the version should conform to the porting guidelines. It can contain
265 * multiple components, separated by a period, including letters.
267 * The tests allow for significantly more latitude in the version numbers
268 * than is allowed in the guidelines. No point in enforcing them here.
269 * That's what portlint is for.
272 * reimplemented by Oliver Eikemeier
275 version_cmp(const char *pkg1
, const char *pkg2
)
277 const char *v1
, *v2
, *ve1
, *ve2
;
278 unsigned long e1
, e2
, r1
, r2
;
281 v1
= split_version(pkg1
, &ve1
, &e1
, &r1
);
282 v2
= split_version(pkg2
, &ve2
, &e2
, &r2
);
284 /* Check epoch, port version, and port revision, in that order. */
286 result
= (e1
< e2
? -1 : 1);
289 /* Shortcut check for equality before invoking the parsing routines. */
290 if (result
== 0 && (ve1
- v1
!= ve2
- v2
|| strncasecmp(v1
, v2
, ve1
- v1
) != 0)) {
291 /* Loop over different components (the parts separated by dots).
292 * If any component differs, we have the basis for an inequality. */
293 while(result
== 0 && (v1
< ve1
|| v2
< ve2
)) {
296 version_component vc1
= {0, 0, 0};
297 version_component vc2
= {0, 0, 0};
298 if (v1
< ve1
&& *v1
!= '+') {
299 v1
= get_component(v1
, &vc1
);
303 if (v2
< ve2
&& *v2
!= '+') {
304 v2
= get_component(v2
, &vc2
);
308 if (block_v1
&& block_v2
) {
313 } else if (vc1
.n
!= vc2
.n
) {
314 result
= (vc1
.n
< vc2
.n
? -1 : 1);
315 } else if (vc1
.a
!= vc2
.a
) {
316 result
= (vc1
.a
< vc2
.a
? -1 : 1);
317 } else if (vc1
.pl
!= vc2
.pl
) {
318 result
= (vc1
.pl
< vc2
.pl
? -1 : 1);
323 /* Compare FreeBSD revision numbers. */
324 if (result
== 0 && r1
!= r2
) {
325 result
= (r1
< r2
? -1 : 1);