From 8f058b4f92a8cd167524bace0f2b9f989a6fed17 Mon Sep 17 00:00:00 2001 From: markm Date: Mon, 24 Jun 2002 16:03:24 +0000 Subject: C replacement for the Perl5 code. Submitted by: reg --- usr.sbin/pkg_install/lib/lib.h | 2 + usr.sbin/pkg_install/lib/version.c | 139 +++++++++++++++++++++++++++++++++++-- 2 files changed, 134 insertions(+), 7 deletions(-) (limited to 'usr.sbin/pkg_install/lib') diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h index 5a11712..6a01fac 100644 --- a/usr.sbin/pkg_install/lib/lib.h +++ b/usr.sbin/pkg_install/lib/lib.h @@ -203,6 +203,8 @@ int requiredby(const char *, struct reqr_by_head **, Boolean, Boolean); /* Version */ int verscmp(Package *, int, int); +const char *version_of(const char *, int *, int *); +int version_cmp(const char *, const char *); /* Externs */ extern Boolean Verbose; diff --git a/usr.sbin/pkg_install/lib/version.c b/usr.sbin/pkg_install/lib/version.c index dca95cc..8241961 100644 --- a/usr.sbin/pkg_install/lib/version.c +++ b/usr.sbin/pkg_install/lib/version.c @@ -14,6 +14,15 @@ * Maxim Sobolev * 31 July 2001 * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "lib.h" +#include + +/* * Routines to assist with PLIST_FMT_VER numbers in the packing * lists. * @@ -23,13 +32,6 @@ * value insted of the hash of an object this links points to. * */ - -#include -__FBSDID("$FreeBSD$"); - -#include "lib.h" -#include - int verscmp(Package *pkg, int major, int minor) { @@ -44,3 +46,126 @@ verscmp(Package *pkg, int major, int minor) return rval; } + +/* + * version_of(pkgname, epoch, revision) returns a pointer to the version + * portion of a package name and the two special components. + * + * Jeremy D. Lea. + */ +const char * +version_of(const char *pkgname, int *epoch, int *revision) +{ + char *ch; + + if (pkgname == NULL) + errx(2, "%s: Passed NULL pkgname.", __func__); + if (epoch != NULL) { + if ((ch = strrchr(pkgname, ',')) == NULL) + *epoch = 0; + else + *epoch = atoi(&ch[1]); + } + if (revision != NULL) { + if ((ch = strrchr(pkgname, '_')) == NULL) + *revision = 0; + else + *revision = atoi(&ch[1]); + } + /* Cheat if we are just passed a version, not a valid package name */ + if ((ch = strrchr(pkgname, '-')) == NULL) + return pkgname; + else + return &ch[1]; +} + +/* + * version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version + * components of pkg1 is less than, equal to or greater than pkg2. No + * comparision of the basenames is done. + * + * The port verison is defined by: + * ${PORTVERSION}[_${PORTREVISION}][,${PORTEPOCH}] + * ${PORTEPOCH} supercedes ${PORTVERSION} supercedes ${PORTREVISION}. + * See the commit log for revision 1.349 of ports/Mk/bsd.port.mk + * for more information. + * + * The epoch and revision are defined to be a single number, while the rest + * of the version should conform to the porting guidelines. It can contain + * multiple components, seperated by a period, including letters. + * + * The tests below allow for significantly more latitude in the version + * numbers than is allowed in the guidelines. No point in wasting user's + * time enforcing them here. That's what flamewars are for. + * + * Jeremy D. Lea. + */ +int +version_cmp(const char *pkg1, const char *pkg2) +{ + const char *c1, *c2, *v1, *v2; + char *t1, *t2; + int e1, e2, r1, r2, n1, n2; + + v1 = version_of(pkg1, &e1, &r1); + v2 = version_of(pkg2, &e2, &r2); + /* Minor optimisation. */ + if (strcmp(v1, v2) == 0) + return 0; + /* First compare epoch. */ + if (e1 != e2) + return (e1 < e2 ? -1 : 1); + else { + /* + * We walk down the versions, trying to convert to numbers. + * We terminate when we reach an underscore, a comma or the + * string terminator, thanks to a nasty trick with strchr(). + * strtol() conveniently gobbles up the chars it converts. + */ + c1 = strchr("_,", v1[0]); + c2 = strchr("_,", v2[0]); + while (c1 == NULL && c2 == NULL) { + n1 = strtol(v1, &t1, 10); + n2 = strtol(v2, &t2, 10); + if (n1 != n2) + return (n1 < n2 ? -1 : 1); + /* + * The numbers are equal, check for letters. Assume they're + * letters purely because strtol() didn't chomp them. + */ + c1 = strchr("_,.", t1[0]); + c2 = strchr("_,.", t2[0]); + if (c1 == NULL && c2 == NULL) { + /* Both have letters. Compare them. */ + if (t1[0] != t2[0]) + return (t1[0] < t2[0] ? -1 : 1); + /* Boring. The letters are equal. Carry on. */ + v1 = &t1[1], v2 = &t2[1]; + } else if (c1 == NULL) { + /* + * Letters are strange. After a number, a letter counts + * as greater, but after a period it's less. + */ + return (isdigit(v1[0]) ? 1 : -1); + } else if (c2 == NULL) { + return (isdigit(v2[0]) ? -1 : 1); + } else { + /* Neither were letters. Advance over the period. */ + v1 = (t1[0] == '.' ? &t1[1] : t1); + v2 = (t2[0] == '.' ? &t2[1] : t2); + } + c1 = strchr("_,", v1[0]); + c2 = strchr("_,", v2[0]); + } + /* If we got here, check if one version has something left. */ + if (c1 == NULL) + return (isdigit(v1[0]) ? 1 : -1); + if (c2 == NULL) + return (isdigit(v2[0]) ? -1 : 1); + /* We've run out of version. Try the revision... */ + if (r1 != r2) + return (r1 < r2 ? -1 : 1); + else + return 0; + } +} -- cgit v1.1