RPM Community Forums

Mailing List Message of <rpm-devel>

Re: Implementing EVR comparisons using *RE's ?

From: Jeff Johnson <n3npq@mac.com>
Date: Thu 07 May 2009 - 18:41:38 CEST
Message-id: <DC560CDB-8D37-4659-99BE-4A976F7CE8ED@mac.com>

On May 7, 2009, at 12:15 PM, devzero2000 wrote:

> On Thu, May 7, 2009 at 3:12 PM, Mark Hatle  
> <mark.hatle@windriver.com> wrote:
> > While I don't have an answer for you, my concern with any change to
> > rpmvercmp is around compatibility.. bugs become features....
> >
> > What I've never seen well documented is the actual algorithm that  
> rpmvercmp
> > uses for it's comparison (in a human readable form).  I attempted  
> to write
> > one once and I can dig it up if it will help... but I'm not even  
> 100% sure
> > it's really correct.
> >
>
> Look here, for an example description
>
> https://fedorahosted.org/pyrpm/browser/doc/pyrpm-devel.txt
>

That describes the behavior, but not the algorithm

What @rpm5.org uses for what is traditionally called "rpmvercmp"
is in rpmdb/rpmevr.c in a function called rpmEVRcmp().

The code was rewritten for clarity a couple of years back.

Whether the rpmEVRcmp() code is "official", I will not say. YMMV,
caveat emptor.

Meanwhile this is the rpmEVRcmp() code that has now been used  
@rpm5.org without
problem for several years.

int rpmEVRcmp(const char * a, const char * b)
         /*@*/
{
     const char * ae = NULL, * be = NULL;
     int rc = 0;         /* assume equal */

assert(a != NULL);
assert(b != NULL);
     /* Compare version strings segment by segment. */
     for (; *a && *b && rc == 0; a = ae, b = be) {

         /* Skip leading non-alpha, non-digit characters. */
         while (*a && !(xisdigit((int)*a) || xisrpmalpha((int)*a))) a++;
         while (*b && !(xisdigit((int)*b) || xisrpmalpha((int)*b))) b++;

         /* Wildcard comparison? */
         /* Note: limited to suffix-only wildcard matching at the  
moment. */
         if (a[0] == '*' && a[1] == '\0') {
             be = strchr(b, '\0');       /* XXX be = b + strlen(b); */
         } else
         if (b[0] == '*' && b[1] == '\0') {
             ae = strchr(a, '\0');       /* XXX ae = a + strlen(a); */
         } else
         /* Digit string comparison? */
         if (xisdigit((int)*a) || xisdigit((int)*b)) {
             /* Discard leading zeroes. */
             while (a[0] == '0' && xisdigit((int)a[1])) a++;
             while (b[0] == '0' && xisdigit((int)b[1])) b++;

             /* Find end of digit strings. */
             ae = a; while (xisdigit((int)*ae)) ae++;
             be = b; while (xisdigit((int)*be)) be++;

             /* Calculate digit comparison return code. */
             if (a == ae || b == be)
                 rc = (int)(*a - *b) * _invert_digits_alphas_comparison;
             else {
                 rc = (ae - a) - (be - b);
                 if (!rc)
                     rc = strncmp(a, b, (ae - a));
             }
         } else {
             /* Find end of alpha strings. */
             ae = a; while (xisrpmalpha((int)*ae)) ae++;
             be = b; while (xisrpmalpha((int)*be)) be++;

             /* Calculate alpha comparison return code. */
             rc = strncmp(a, b, MAX((ae - a), (be - b)));
         }
     }

     /* Longer string wins. */
     if (!rc)
         rc = (int)(*a - *b);

     /* Force strict -1, 0, 1 return. */
     rc = (rc > 0 ? 1
         : rc < 0 ? -1
         : 0);
     return rc;
}
Received on Thu May 7 18:42:32 2009
Driven by Jeff Johnson and the RPM project team.
Hosted by OpenPKG and Ralf S. Engelschall.
Powered by FreeBSD and OpenPKG.