commit:     e534e4c77006dbcd82430588c75433fbfa5e49cf
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sat Jan 17 14:47:13 2026 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Wed Jan 21 21:30:43 2026 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=e534e4c7

libq/atom: reflow, rename depend_atom to atom to match the include name

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/atom.c | 2700 ++++++++++++++++++++++++++++++++---------------------------
 libq/atom.h |  139 +--
 2 files changed, 1561 insertions(+), 1278 deletions(-)

diff --git a/libq/atom.c b/libq/atom.c
index 76e0743..a90e458 100644
--- a/libq/atom.c
+++ b/libq/atom.c
@@ -18,552 +18,657 @@
 #include <xalloc.h>
 
 const char * const atom_suffixes_str[] = {
-       "_alpha", "_beta", "_pre", "_rc", "_/*bogus*/", "_p"
+  "_alpha",
+  "_beta",
+  "_pre",
+  "_rc",
+  "_/*bogus*/",
+  "_p"
 };
 
 const char * const atom_slotdep_str[] = {
-       "", "=", "*"
+  "",
+  "=",
+  "*"
 };
 
 const char * const atom_usecond_str[] = {
-       "", "!", "-", "?", "=", "(+)", "(-)"
+  "",
+  "!",
+  "-",
+  "?",
+  "=",
+  "(+)",
+  "(-)"
 };
 
 const char * const atom_blocker_str[] = {
-       "", "!", "!!", "^"
+  "",
+  "!",
+  "!!",
+  "^"
 };
 
 const char * const atom_op_str[] = {
-       "", "=", ">", ">=", "<", "<=", "~", "*"
+  "",
+  "=",
+  ">",
+  ">=",
+  "<",
+  "<=",
+  "~",
+  "*"
 };
 
-const char * const booga[] = {"!!!", "!=", "==", ">", "<"};
+const char * const booga[] = {
+  "!!!",
+  "!=",
+  "==",
+  ">",
+  "<"
+};
 
 /* split string into individual components, known as an atom
  * for a definition of which variable contains what, see:
- * https://dev.gentoo.org/~ulm/pms/head/pms.html#x1-10800011 */
-depend_atom *
-atom_explode_cat(const char *atom, const char *cat)
+ * https://projects.gentoo.org/pms/latest/pms.html#names-and-versions */
+atom_ctx *atom_explode_cat
+(
+  const char *input,
+  const char *cat
+)
 {
-       depend_atom *ret;
-       char *ptr;
-       size_t len;
-       size_t slen;
-       size_t idx;
-       size_t sidx;
-       char *lastpv = NULL;
-       char *pv;
-
-       /* PMS 11.1 recap:
-        * CAT  The package’s category                    app-editors
-        * PF   Package name, version, and revision (if any)          
vim-7.0.174-r1
-        * PVR  Package version and revision (if any)                     
7.0.174-r1
-        * P    Package name and version, without the revision part   
vim-7.0.174
-        * PV   Package version, with no revision                         
7.0.174
-        * PN   Package name                                          vim
-        * PR   Package revision, or r0 if none exists                          
  r1
-        *
-        * Thus, CAT/PF is the full allocation of the input string, for the
-        * rest (P, PN, PV, PR, PVR) we need copies.  We represent PR as an
-        * integer, which leaves the set to PN, P and PV.
-        * PVR is an offset inside PF, likewise, PV is an offset inside P.
-        * We allocate memory for atom struct, one string for CAT/PF + PVR,
-        * another to cover PN and a final one for P + PV. */
-       slen = strlen(atom) + 1;
-       len = cat != NULL ? strlen(cat) + 1 : 0;
-       ret = xmalloc(sizeof(*ret) + (slen * 3) + len);
-       memset(ret, '\0', sizeof(*ret));
-
-       /* assign pointers to the three storage containers */
-       ret->CATEGORY = (char *)ret + sizeof(*ret) + len;     /* CAT PF PVR */
-       ret->P        = ret->CATEGORY + slen;                 /* P   PV     */
-       ret->PN       = ret->P + slen;                        /* PN         */
-
-       /* check for blocker operators */
-       ret->blocker = ATOM_BL_NONE;
-       if (*atom == '!') {
-               ret->blocker++;
-               atom++;
-               if (*atom == '!') {
-                       ret->blocker++;
-                       atom++;
-               }
-       } else if (*atom == '^') {
-               ret->blocker = ATOM_BL_ANTISLOT;
-               atom++;
-       }
-
-       /* eat any prefix operators */
-       ret->pfx_op = ATOM_OP_NONE;
-       switch (*atom) {
-       case '>':
-               ret->pfx_op = ATOM_OP_NEWER;
-               atom++;
-               break;
-       case '<':
-               ret->pfx_op = ATOM_OP_OLDER;
-               atom++;
-               break;
-       case '~':
-               ret->pfx_op = ATOM_OP_PV_EQUAL;
-               atom++;
-               break;
-       }
-       if (*atom == '=') {
-               ret->pfx_op += ATOM_OP_EQUAL;
-               atom++;
-       }
-
-       /* fill in full block */
-       strcpy(ret->CATEGORY, atom);
-
-       /* eat file name crap when given an (autocompleted) path */
-       if ((ptr = strstr(ret->CATEGORY, ".ebuild")) != NULL ||
-               (ptr = strstr(ret->CATEGORY, ".tbz2")) != NULL ||
-               (ptr = strstr(ret->CATEGORY, ".xpak")) != NULL ||
-               (ptr = strstr(ret->CATEGORY, ".gpkg.tar")) != NULL)
-       {
-               *ptr = '\0';
-               if (ptr[1] == 'x' ||
-                       ptr[1] == 'g')
-               {
-                       bool valid = false;
-                       /* probe for the build-id, it should be a number, but 
it can
-                        * be optional, which is making it difficult because
-                        * in something like PN-VER.gpkg.tar, VER should not be 
seen
-                        * as BUILDID, while a PN can also contain dashes
-                        * see below note on PMS 3.2, we do a loose check on 
-[0-9]
-                        * from the start */
-                       while (--ptr > ret->CATEGORY &&
-                                  isdigit(*ptr))
-                               valid = true;
-                       if (valid &&
-                               *ptr == '-')
-                       {
-                               for (pv = ret->CATEGORY;
-                                        (pv = strchr(pv, '-')) != NULL;
-                                        pv++)
-                               {
-                                       if (isdigit(pv[1]))
-                                               break;
-                               }
-                               if (pv != ptr) {
-                                       ret->BUILDID = atoll(&ptr[1]);
-                                       *ptr = '\0';
-                               }
-                       }
-               }
-       }
-
-       /* chip off the trailing ::REPO as needed */
-       if ((ptr = strstr(ret->CATEGORY, "::")) != NULL) {
-               ret->REPO = ptr + 2;
-               *ptr = '\0';
-               /* set to NULL if there's nothing */
-               if (ret->REPO[0] == '\0')
-                       ret->REPO = NULL;
-       }
-
-       /* hunt down build with USE dependencies */
-       if ((ptr = strrchr(ret->CATEGORY, ']')) != NULL && ptr[1] == '\0' &&
-                       (ptr = strrchr(ret->CATEGORY, '[')) != NULL)
-       {
-               atom_usedep *w = NULL;
-               do {
-                       if (ret->usedeps == NULL) {
-                               ret->usedeps = w = xmalloc(sizeof(atom_usedep));
-                       } else {
-                               w = w->next = xmalloc(sizeof(atom_usedep));
-                       }
-                       w->next = NULL;
-                       *ptr++ = '\0';
-                       w->pfx_cond = w->sfx_cond = ATOM_UC_NONE;
-                       switch (*ptr) {
-                               case '-':
-                                       w->pfx_cond = ATOM_UC_NEG;
-                                       ptr++;
-                                       break;
-                               case '!':
-                                       w->pfx_cond = ATOM_UC_NOT;
-                                       ptr++;
-                                       break;
-                       }
-                       w->use = ptr;
-                       while (*ptr != '\0') {
-                               switch (*ptr) {
-                                       case '?':
-                                               w->sfx_cond = ATOM_UC_COND;
-                                               *ptr++ = '\0';
-                                               break;
-                                       case '=':
-                                               w->sfx_cond = ATOM_UC_EQUAL;
-                                               *ptr++ = '\0';
-                                               break;
-                                       case '(':
-                                               if (strncmp(ptr, "(+)", 3) == 
0) {
-                                                       w->sfx_cond = 
ATOM_UC_PREV_ENABLED;
-                                                       *ptr = '\0';
-                                                       ptr += 3;
-                                               } else if (strncmp(ptr, "(-)", 
3) == 0) {
-                                                       w->sfx_cond = 
ATOM_UC_PREV_ENABLED;
-                                                       *ptr = '\0';
-                                                       ptr += 3;
-                                               } else {
-                                                       ptr++;
-                                               }
-                                               break;
-                                       case ',':
-                                       case ']':
-                                               *ptr = ']';
-                                               break;
-                                       default:
-                                               ptr++;
-                               }
-                               if (*ptr == ']')
-                                       break;
-                       }
-               } while (ptr[1] != '\0');
-               *ptr++ = '\0';
-       }
-
-       /* chip off the trailing :SLOT as needed */
-       if ((ptr = strrchr(ret->CATEGORY, ':')) != NULL) {
-               *ptr++ = '\0';
-               ret->SLOT = ptr;
-
-               /* deal with slot operators */
-               if ((ptr = strrchr(ret->SLOT, '=')) != NULL && ptr[1] == '\0') {
-                       ret->slotdep = ATOM_SD_ANY_REBUILD;
-                       *ptr = '\0';
-               }
-               if ((ptr = strrchr(ret->SLOT, '*')) != NULL && ptr[1] == '\0') {
-                       ret->slotdep = ATOM_SD_ANY_IGNORE;
-                       *ptr = '\0';
-               }
-
-               /* cut in two when sub-slot */
-               if ((ptr = strchr(ret->SLOT, '/')) != NULL) {
-                       *ptr++ = '\0';
-                       if (*ptr != '\0')
-                               ret->SUBSLOT = ptr;
-               }
-
-               /* set to NULL if there's nothing */
-               if (ret->SLOT[0] == '\0')
-                       ret->SLOT = NULL;
-
-               /* PMS 7.2: SUBSLOT defaults to SLOT when unset */
-               if (ret->SUBSLOT == NULL)
-                       ret->SUBSLOT = ret->SLOT;
-       }
-
-       /* see if we have any suffix operators */
-       if ((ptr = strrchr(ret->CATEGORY, '*')) != NULL && ptr[1] == '\0') {
-               ret->sfx_op = ATOM_OP_STAR;
-               *ptr = '\0';
-       }
-
-       /* break up the CATEGORY, PF and PVR */
-       if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) {
-               *ptr++ = '\0';
-               ret->PF = ptr;
-
-               /* set PN to NULL if there's nothing */
-               if (ret->PF[0] == '\0')
-                       ret->PF = NULL;
-
-               /* eat extra crap in case it exists, this is a feature to allow
-                * /path/to/pkg.ebuild, doesn't work with prefix operators
-                * though */
-               if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL)
-                       ret->CATEGORY = ptr + 1;
-       } else {
-               ret->PF = ret->CATEGORY;
-               ret->CATEGORY = NULL;
-       }
-
-       /* inject separate CATEGORY when given, this will override any found
-        * CATEGORY, which is what it could be used for too */
-       if (cat != NULL) {
-               ret->CATEGORY = (char *)ret + sizeof(*ret);
-               memcpy(ret->CATEGORY, cat, len);
-       }
-
-       if (ret->PF == NULL) {
-               /* atom has no name, this is it */
-               ret->P = NULL;
-               ret->PN = NULL;
-               ret->PVR = NULL;
-
-               return ret;
-       }
-
-       /* portage-utils addition: BUILDID is present as ~BUILDID, remove it
-        * from here if we find it, our extension may never be part of the
-        * official PF/PVR */
-       if ((ptr = strchr(ret->PF, '~')) != NULL &&
-               isdigit(ptr[1]))
-       {
-               ret->BUILDID = atoi(&ptr[1]);
-               *ptr = '\0';
-       }
-
-       /* CATEGORY should be all set here, PF contains everything up to
-        * SLOT, REPO or '*'
-        * PMS 3.1.2 says PN must not end in a hyphen followed by
-        * anything matching version syntax.  PMS 3.2 version syntax
-        * starts with a number, so "-[0-9]" is a separator from PN to
-        * PV* -- except it doesn't when the thing doesn't validate as
-        * version :( */
-
-       ptr = ret->PF;
-       while ((ptr = strchr(ptr, '-')) != NULL) {
-               ptr++;
-               if (!isdigit(*ptr))
-                       continue;
-
-               /* so we should have something like "-2" here, see if this
-                * checks out as valid version string */
-               pv = ptr;
-               while (*++ptr != '\0') {
-                       if (*ptr != '.' && !isdigit(*ptr))
-                               break;
-               }
-               /* allow for 1 optional suffix letter */
-               if (*ptr >= 'a' && *ptr <= 'z')
-                       ret->letter = *ptr++;
-               if (*ptr == '_' || *ptr == '-' || *ptr == '\0') {
-                       lastpv = pv;
-                       continue;  /* valid, keep searching */
-               }
-
-               ret->letter = '\0';
-       }
-       ptr = lastpv;
-
-       if (ptr == NULL) {
-               /* atom has no version, this is it */
-               ret->P = ret->PN = ret->PF;
-               ret->PV = ret->PVR = NULL;
-
-               return ret;
-       }
-
-       ret->PVR = ptr;
-       snprintf(ret->PN, slen, "%.*s", (int)(ret->PVR - 1 - ret->PF), ret->PF);
-
-       /* find -r# */
-       pv = NULL;
-       ptr = ret->PVR + strlen(ret->PVR) - 1;
-       while (*ptr && ptr > ret->PVR) {
-               if (!isdigit((int)*ptr)) {
-                       if (ptr[0] == 'r' && ptr[-1] == '-') {
-                               ret->PR_int = atoi(ptr + 1);
-                               pv = &ptr[-1];
-                       }
-                       break;
-               }
-               ptr--;
-       }
-       if (pv != NULL) {
-               snprintf(ret->P, slen, "%.*s", (int)(pv - ret->PF), ret->PF);
-       } else {
-               ret->P = ret->PF;
-       }
-       ret->PV = ret->P + (ret->PVR - ret->PF);
-
-       /* break out all the suffixes */
-       sidx = 0;
-       ret->suffixes = xrealloc(ret->suffixes, sizeof(atom_suffix) * (sidx + 
1));
-       ret->suffixes[sidx].sint = 0;
-       ret->suffixes[sidx].suffix = VER_NORM;
-       ptr = ret->PV + strlen(ret->PV) - 1;
-       while (ptr-- > ret->PV) {
-               if (*ptr != '_')
-                       continue;
-               for (idx = 0; idx < ARRAY_SIZE(atom_suffixes_str); ++idx) {
-                       if (strncmp(ptr, atom_suffixes_str[idx],
-                                               strlen(atom_suffixes_str[idx])))
-                               continue;
-
-                       ret->suffixes[sidx].sint =
-                               atoll(ptr + strlen(atom_suffixes_str[idx]));
-                       ret->suffixes[sidx].suffix = idx;
-
-                       ++sidx;
-
-                       ret->suffixes = xrealloc(ret->suffixes,
-                                       sizeof(atom_suffix) * (sidx + 1));
-                       ret->suffixes[sidx].sint = 0;
-                       ret->suffixes[sidx].suffix = VER_NORM;
-                       break;
-               }
-       }
-       if (sidx)
-               --sidx;
-       for (idx = 0; idx < sidx; ++idx, --sidx) {
-               atom_suffix t = ret->suffixes[sidx];
-               ret->suffixes[sidx] = ret->suffixes[idx];
-               ret->suffixes[idx] = t;
-       }
-
-       return ret;
+  atom_ctx *ret;
+  char     *ptr;
+  size_t    len;
+  size_t    slen;
+  size_t    idx;
+  size_t    sidx;
+  char     *lastpv = NULL;
+  char     *pv;
+
+  /* PMS variables recap:
+   *  (https://projects.gentoo.org/pms/latest/pms.html#defined-variables1)
+   * CAT  The package’s category                    app-editors
+   * PF   Package name, version, and revision (if any)          vim-7.0.174-r1
+   * PVR  Package version and revision (if any)                     7.0.174-r1
+   * P    Package name and version, without the revision part   vim-7.0.174
+   * PV   Package version, with no revision                         7.0.174
+   * PN   Package name                                          vim
+   * PR   Package revision, or r0 if none exists                            r1
+   *
+   * Thus, CAT/PF is the full allocation of the input string, for the
+   * rest (P, PN, PV, PR, PVR) we need copies.  We represent PR as an
+   * integer, which leaves the set to PN, P and PV.
+   * PVR is an offset inside PF, likewise, PV is an offset inside P.
+   * We allocate memory for atom struct, one string for CAT/PF + PVR,
+   * another to cover PN and a final one for P + PV. */
+  slen = strlen(input) + 1;
+  len = cat != NULL ? strlen(cat) + 1 : 0;
+  ret = xmalloc(sizeof(*ret) + (slen * 3) + len);
+  memset(ret, '\0', sizeof(*ret));
+
+  /* assign pointers to the three storage containers */
+  ret->CATEGORY = (char *)ret + sizeof(*ret) + len;     /* CAT PF PVR */
+  ret->P        = ret->CATEGORY + slen;                 /* P   PV     */
+  ret->PN       = ret->P + slen;                        /* PN         */
+
+  /* check for blocker operators */
+  ret->blocker = ATOM_BL_NONE;
+  if (*input == '!')
+  {
+    ret->blocker++;
+    input++;
+    if (*input == '!')
+    {
+      ret->blocker++;
+      input++;
+    }
+  }
+  else if (*input == '^')
+  {
+    ret->blocker = ATOM_BL_ANTISLOT;
+    input++;
+  }
+
+  /* eat any prefix operators */
+  ret->pfx_op = ATOM_OP_NONE;
+  switch (*input)
+  {
+  case '>':
+    ret->pfx_op = ATOM_OP_NEWER;
+    input++;
+    break;
+  case '<':
+    ret->pfx_op = ATOM_OP_OLDER;
+    input++;
+    break;
+  case '~':
+    ret->pfx_op = ATOM_OP_PV_EQUAL;
+    input++;
+    break;
+  }
+  if (*input == '=')
+  {
+    ret->pfx_op += ATOM_OP_EQUAL;
+    input++;
+  }
+
+  /* fill in full block */
+  strcpy(ret->CATEGORY, input);
+
+  /* eat file name crap when given an (autocompleted) path */
+  if ((ptr = strstr(ret->CATEGORY, ".ebuild"))   != NULL ||
+      (ptr = strstr(ret->CATEGORY, ".tbz2"))     != NULL ||
+      (ptr = strstr(ret->CATEGORY, ".xpak"))     != NULL ||
+      (ptr = strstr(ret->CATEGORY, ".gpkg.tar")) != NULL)
+  {
+    *ptr = '\0';
+    if (ptr[1] == 'x' ||
+        ptr[1] == 'g')
+    {
+      bool valid = false;
+      /* probe for the build-id, it should be a number, but it can
+       * be optional, which is making it difficult because
+       * in something like PN-VER.gpkg.tar, VER should not be seen
+       * as BUILDID, while a PN can also contain dashes
+       * see below note on PMS 3.2, we do a loose check on -[0-9]
+       * from the start */
+      while (--ptr > ret->CATEGORY &&
+             isdigit(*ptr))
+        valid = true;
+      if (valid &&
+          *ptr == '-')
+      {
+        for (pv = ret->CATEGORY;
+             (pv = strchr(pv, '-')) != NULL;
+             pv++)
+        {
+          if (isdigit(pv[1]))
+            break;
+        }
+        if (pv != ptr)
+        {
+          ret->BUILDID = atoll(&ptr[1]);
+          *ptr = '\0';
+        }
+      }
+    }
+  }
+
+  /* chip off the trailing ::REPO as needed */
+  if ((ptr = strstr(ret->CATEGORY, "::")) != NULL)
+  {
+    ret->REPO = ptr + 2;
+    *ptr = '\0';
+    /* set to NULL if there's nothing */
+    if (ret->REPO[0] == '\0')
+      ret->REPO = NULL;
+  }
+
+  /* hunt down build with USE dependencies */
+  if ((ptr = strrchr(ret->CATEGORY, ']')) != NULL &&
+      ptr[1] == '\0' &&
+      (ptr = strrchr(ret->CATEGORY, '[')) != NULL)
+  {
+    atom_usedep *w = NULL;
+    do
+    {
+      if (ret->usedeps == NULL)
+        ret->usedeps = w = xmalloc(sizeof(atom_usedep));
+      else
+        w = w->next = xmalloc(sizeof(atom_usedep));
+
+      w->next = NULL;
+      *ptr++ = '\0';
+      w->pfx_cond = w->sfx_cond = ATOM_UC_NONE;
+      switch (*ptr)
+      {
+      case '-':
+        w->pfx_cond = ATOM_UC_NEG;
+        ptr++;
+        break;
+      case '!':
+        w->pfx_cond = ATOM_UC_NOT;
+        ptr++;
+        break;
+      }
+      w->use = ptr;
+      while (*ptr != '\0')
+      {
+        switch (*ptr)
+        {
+        case '?':
+          w->sfx_cond = ATOM_UC_COND;
+          *ptr++ = '\0';
+          break;
+        case '=':
+          w->sfx_cond = ATOM_UC_EQUAL;
+          *ptr++ = '\0';
+          break;
+        case '(':
+          if (strncmp(ptr, "(+)", 3) == 0)
+          {
+            w->sfx_cond = ATOM_UC_PREV_ENABLED;
+            *ptr = '\0';
+            ptr += 3;
+          }
+          else if (strncmp(ptr, "(-)", 3) == 0)
+          {
+            w->sfx_cond = ATOM_UC_PREV_ENABLED;
+            *ptr = '\0';
+            ptr += 3;
+          }
+          else
+          {
+            ptr++;
+          }
+          break;
+        case ',':
+        case ']':
+          *ptr = ']';
+          break;
+        default:
+          ptr++;
+        }
+        if (*ptr == ']')
+          break;
+      }
+    }
+    while (ptr[1] != '\0');
+    *ptr++ = '\0';
+  }
+
+  /* chip off the trailing :SLOT as needed */
+  if ((ptr = strrchr(ret->CATEGORY, ':')) != NULL)
+  {
+    *ptr++ = '\0';
+    ret->SLOT = ptr;
+
+    /* deal with slot operators */
+    if ((ptr = strrchr(ret->SLOT, '=')) != NULL &&
+        ptr[1] == '\0')
+    {
+      ret->slotdep = ATOM_SD_ANY_REBUILD;
+      *ptr = '\0';
+    }
+    if ((ptr = strrchr(ret->SLOT, '*')) != NULL &&
+        ptr[1] == '\0')
+    {
+      ret->slotdep = ATOM_SD_ANY_IGNORE;
+      *ptr = '\0';
+    }
+
+    /* cut in two when sub-slot */
+    if ((ptr = strchr(ret->SLOT, '/')) != NULL)
+    {
+      *ptr++ = '\0';
+      if (*ptr != '\0')
+        ret->SUBSLOT = ptr;
+    }
+
+    /* set to NULL if there's nothing */
+    if (ret->SLOT[0] == '\0')
+      ret->SLOT = NULL;
+
+    /* PMS 7.2: SUBSLOT defaults to SLOT when unset */
+    if (ret->SUBSLOT == NULL)
+      ret->SUBSLOT = ret->SLOT;
+  }
+
+  /* see if we have any suffix operators */
+  if ((ptr = strrchr(ret->CATEGORY, '*')) != NULL &&
+      ptr[1] == '\0')
+  {
+    ret->sfx_op = ATOM_OP_STAR;
+    *ptr = '\0';
+  }
+
+  /* break up the CATEGORY, PF and PVR */
+  if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL)
+  {
+    *ptr++  = '\0';
+    ret->PF = ptr;
+
+    /* set PN to NULL if there's nothing */
+    if (ret->PF[0] == '\0')
+      ret->PF = NULL;
+
+    /* eat extra crap in case it exists, this is a feature to allow
+     * /path/to/pkg.ebuild, doesn't work with prefix operators
+     * though */
+    if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL)
+      ret->CATEGORY = ptr + 1;
+  }
+  else
+  {
+    ret->PF       = ret->CATEGORY;
+    ret->CATEGORY = NULL;
+  }
+
+  /* inject separate CATEGORY when given, this will override any found
+   * CATEGORY, which is what it could be used for too */
+  if (cat != NULL)
+  {
+    ret->CATEGORY = (char *)ret + sizeof(*ret);
+    memcpy(ret->CATEGORY, cat, len);
+  }
+
+  if (ret->PF == NULL)
+  {
+    /* atom has no name, this is it */
+    ret->P   = NULL;
+    ret->PN  = NULL;
+    ret->PVR = NULL;
+
+    return ret;
+  }
+
+  /* portage-utils addition: BUILDID is present as ~BUILDID, remove it
+   * from here if we find it, our extension may never be part of the
+   * official PF/PVR */
+  if ((ptr = strchr(ret->PF, '~')) != NULL &&
+      isdigit(ptr[1]))
+  {
+    ret->BUILDID = atoi(&ptr[1]);
+    *ptr         = '\0';
+  }
+
+  /* CATEGORY should be all set here, PF contains everything up to
+   * SLOT, REPO or '*'
+   * PMS 3.1.2 says PN must not end in a hyphen followed by
+   * anything matching version syntax.  PMS 3.2 version syntax
+   * starts with a number, so "-[0-9]" is a separator from PN to
+   * PV* -- except it doesn't when the thing doesn't validate as
+   * version :( */
+
+  ptr = ret->PF;
+  while ((ptr = strchr(ptr, '-')) != NULL)
+  {
+    ptr++;
+    if (!isdigit(*ptr))
+      continue;
+
+    /* so we should have something like "-2" here, see if this
+     * checks out as valid version string */
+    pv = ptr;
+    while (*++ptr != '\0')
+    {
+      if (*ptr != '.' &&
+          !isdigit(*ptr))
+        break;
+    }
+    /* allow for 1 optional suffix letter */
+    if (*ptr >= 'a' &&
+        *ptr <= 'z')
+      ret->letter = *ptr++;
+    if (*ptr == '_' ||
+        *ptr == '-' ||
+        *ptr == '\0')
+    {
+      lastpv = pv;
+      continue;  /* valid, keep searching */
+    }
+
+    ret->letter = '\0';
+  }
+  ptr = lastpv;
+
+  if (ptr == NULL)
+  {
+    /* atom has no version, this is it */
+    ret->P  = ret->PN  = ret->PF;
+    ret->PV = ret->PVR = NULL;
+
+    return ret;
+  }
+
+  ret->PVR = ptr;
+  snprintf(ret->PN, slen, "%.*s", (int)(ret->PVR - 1 - ret->PF), ret->PF);
+
+  /* find -r# */
+  pv = NULL;
+  ptr = ret->PVR + strlen(ret->PVR) - 1;
+  while (*ptr &&
+         ptr > ret->PVR)
+  {
+    if (!isdigit((int)*ptr))
+    {
+      if (ptr[0] == 'r' &&
+          ptr[-1] == '-')
+      {
+        ret->PR_int = atoi(ptr + 1);
+        pv = &ptr[-1];
+      }
+      break;
+    }
+    ptr--;
+  }
+  if (pv != NULL)
+    snprintf(ret->P, slen, "%.*s", (int)(pv - ret->PF), ret->PF);
+  else
+    ret->P = ret->PF;
+
+  ret->PV = ret->P + (ret->PVR - ret->PF);
+
+  /* break out all the suffixes */
+  sidx = 0;
+  ret->suffixes = xrealloc(ret->suffixes, sizeof(atom_suffix) * (sidx + 1));
+  ret->suffixes[sidx].sint   = 0;
+  ret->suffixes[sidx].suffix = VER_NORM;
+  ptr = ret->PV + strlen(ret->PV) - 1;
+  while (ptr-- > ret->PV)
+  {
+    if (*ptr != '_')
+      continue;
+    for (idx = 0; idx < ARRAY_SIZE(atom_suffixes_str); idx++)
+    {
+      if (strncmp(ptr, atom_suffixes_str[idx],
+                  strlen(atom_suffixes_str[idx])))
+        continue;
+
+      ret->suffixes[sidx].sint   =
+        atoll(ptr + strlen(atom_suffixes_str[idx]));
+      ret->suffixes[sidx].suffix = idx;
+
+      sidx++;
+
+      ret->suffixes = xrealloc(ret->suffixes,
+                               sizeof(atom_suffix) * (sidx + 1));
+      ret->suffixes[sidx].sint   = 0;
+      ret->suffixes[sidx].suffix = VER_NORM;
+      break;
+    }
+  }
+  if (sidx)
+    sidx--;
+  for (idx = 0; idx < sidx; idx++, sidx--)
+  {
+    atom_suffix t       = ret->suffixes[sidx];
+    ret->suffixes[sidx] = ret->suffixes[idx];
+    ret->suffixes[idx]  = t;
+  }
+
+  return ret;
 }
 
-depend_atom *
-atom_clone(depend_atom *atom)
+atom_ctx *atom_clone
+(
+  atom_ctx *a
+)
 {
-       depend_atom *ret;
-       char *p;
-       size_t alen;
-       size_t clen = 0;
-       size_t flen = 0;
-       size_t plen = 0;
-       size_t nlen = 0;
-       size_t slen = 0;
-       size_t sslen = 0;
-       size_t rlen = 0;
-
-       if (atom->REPO != NULL)
-               rlen = strlen(atom->REPO) + 1;
-       if (atom->SLOT != NULL)
-               slen = strlen(atom->SLOT) + 1;
-       if (atom->SUBSLOT != NULL && atom->SUBSLOT != atom->SLOT)
-               sslen = strlen(atom->SUBSLOT) + 1;
-       if (atom->CATEGORY != NULL)
-               clen = strlen(atom->CATEGORY) + 1;
-       if (atom->PF != NULL)
-               flen = strlen(atom->PF) + 1;  /* should include PVR */
-       if (atom->P != NULL)
-               plen = strlen(atom->P) + 1;  /* should include PV */
-       if (atom->PN != NULL)
-               nlen = strlen(atom->PN) + 1;
-
-       alen = sizeof(*ret) + clen + flen + plen + nlen + rlen + slen + sslen;
-       ret = xmalloc(alen);
-       memset(ret, '\0', sizeof(*ret));
-
-       /* build up main storage pointers, see explode */
-       p = (char *)ret + sizeof(*ret);
-       if (atom->CATEGORY != NULL) {
-               ret->CATEGORY = p;
-               memcpy(ret->CATEGORY, atom->CATEGORY, clen);
-               p += clen;
-       }
-       if (atom->PF != NULL) {
-               ret->PF = p;
-               memcpy(ret->PF, atom->PF, flen);
-               p += flen;
-       }
-       if (atom->PVR > atom->PF && atom->PVR < (atom->PF + flen))
-               ret->PVR = ret->PF + (atom->PVR - atom->PF);
-       if (atom->P != NULL) {
-               ret->P = p;
-               memcpy(ret->P, atom->P, plen);
-               p += plen;
-       }
-       if (atom->PV > atom->P && atom->PV < (atom->P + plen))
-               ret->PV = ret->P + (atom->PV - atom->P);
-       if (atom->PN != NULL) {
-               ret->PN = p;
-               memcpy(ret->PN, atom->PN, nlen);
-               p += nlen;
-       }
-       if (atom->SLOT != NULL) {
-               ret->SLOT = p;
-               memcpy(ret->SLOT, atom->SLOT, slen);
-               p += slen;
-       }
-       if (atom->SUBSLOT != NULL) {
-               if (atom->SUBSLOT == atom->SLOT) {  /* PMS 7.2 */
-                       ret->SUBSLOT = ret->SLOT;
-               } else {
-                       ret->SUBSLOT = p;
-                       memcpy(ret->SUBSLOT, atom->SUBSLOT, sslen);
-                       p += sslen;
-               }
-       }
-       if (atom->REPO != NULL) {
-               ret->REPO = p;
-               memcpy(ret->REPO, atom->REPO, rlen);
-               p += rlen;
-       }
-
-       ret->blocker = atom->blocker;
-       ret->pfx_op  = atom->pfx_op;
-       ret->sfx_op  = atom->sfx_op;
-       ret->PR_int  = atom->PR_int;
-       ret->letter  = atom->letter;
-       ret->slotdep = atom->slotdep;
-       ret->BUILDID = atom->BUILDID;
-
-       if (atom->suffixes != NULL) {
-               for (slen = 0; atom->suffixes[slen].suffix != VER_NORM; slen++)
-                       ;
-               slen++;
-               ret->suffixes = xmalloc(sizeof(ret->suffixes[0]) * slen);
-               memcpy(ret->suffixes, atom->suffixes, sizeof(ret->suffixes[0]) 
* slen);
-       }
-
-       if (atom->usedeps) {
-               atom_usedep *w;
-               atom_usedep *n = NULL;
-
-               for (w = atom->usedeps; w != NULL; w = w->next) {
-                       nlen = w->use != NULL ? strlen(w->use) + 1 : 0;
-                       if (n == NULL) {
-                               ret->usedeps = n = xmalloc(sizeof(*n) + nlen);
-                       } else {
-                               n = n->next = xmalloc(sizeof(*n) + nlen);
-                       }
-                       n->next = NULL;
-                       n->pfx_cond = w->pfx_cond;
-                       n->sfx_cond = w->sfx_cond;
-                       n->use = (char *)n + sizeof(*n);
-                       memcpy(n->use, w->use, nlen);
-               }
-       }
-
-       return ret;
+  atom_ctx *ret;
+  char     *p;
+  size_t    alen;
+  size_t    clen = 0;
+  size_t    flen = 0;
+  size_t    plen = 0;
+  size_t    nlen = 0;
+  size_t    slen = 0;
+  size_t    sslen = 0;
+  size_t    rlen = 0;
+
+  if (a->REPO != NULL)
+    rlen = strlen(a->REPO) + 1;
+  if (a->SLOT != NULL)
+    slen = strlen(a->SLOT) + 1;
+  if (a->SUBSLOT != NULL &&
+      a->SUBSLOT != a->SLOT)
+    sslen = strlen(a->SUBSLOT) + 1;
+  if (a->CATEGORY != NULL)
+    clen = strlen(a->CATEGORY) + 1;
+  if (a->PF != NULL)
+    flen = strlen(a->PF) + 1;  /* should include PVR */
+  if (a->P != NULL)
+    plen = strlen(a->P) + 1;  /* should include PV */
+  if (a->PN != NULL)
+    nlen = strlen(a->PN) + 1;
+
+  alen = sizeof(*ret) + clen + flen + plen + nlen + rlen + slen + sslen;
+  ret  = xmalloc(alen);
+  memset(ret, '\0', sizeof(*ret));
+
+  /* build up main storage pointers, see explode */
+  p = (char *)ret + sizeof(*ret);
+  if (a->CATEGORY != NULL)
+  {
+    ret->CATEGORY = p;
+    memcpy(ret->CATEGORY, a->CATEGORY, clen);
+    p += clen;
+  }
+  if (a->PF != NULL)
+  {
+    ret->PF = p;
+    memcpy(ret->PF, a->PF, flen);
+    p += flen;
+  }
+  if (a->PVR > a->PF &&
+      a->PVR < (a->PF + flen))
+    ret->PVR = ret->PF + (a->PVR - a->PF);
+  if (a->P != NULL)
+  {
+    ret->P = p;
+    memcpy(ret->P, a->P, plen);
+    p += plen;
+  }
+  if (a->PV > a->P &&
+      a->PV < (a->P + plen))
+    ret->PV = ret->P + (a->PV - a->P);
+  if (a->PN != NULL)
+  {
+    ret->PN = p;
+    memcpy(ret->PN, a->PN, nlen);
+    p += nlen;
+  }
+  if (a->SLOT != NULL)
+  {
+    ret->SLOT = p;
+    memcpy(ret->SLOT, a->SLOT, slen);
+    p += slen;
+  }
+  if (a->SUBSLOT != NULL)
+  {
+    if (a->SUBSLOT == a->SLOT)  /* PMS 7.2 */
+    {
+      ret->SUBSLOT = ret->SLOT;
+    }
+    else
+    {
+      ret->SUBSLOT = p;
+      memcpy(ret->SUBSLOT, a->SUBSLOT, sslen);
+      p += sslen;
+    }
+  }
+  if (a->REPO != NULL)
+  {
+    ret->REPO = p;
+    memcpy(ret->REPO, a->REPO, rlen);
+    p += rlen;
+  }
+
+  ret->blocker = a->blocker;
+  ret->pfx_op  = a->pfx_op;
+  ret->sfx_op  = a->sfx_op;
+  ret->PR_int  = a->PR_int;
+  ret->letter  = a->letter;
+  ret->slotdep = a->slotdep;
+  ret->BUILDID = a->BUILDID;
+
+  if (a->suffixes != NULL)
+  {
+    for (slen = 0; a->suffixes[slen].suffix != VER_NORM; slen++)
+      ;
+    slen++;
+    ret->suffixes = xmalloc(sizeof(ret->suffixes[0]) * slen);
+    memcpy(ret->suffixes, a->suffixes, sizeof(ret->suffixes[0]) * slen);
+  }
+
+  if (a->usedeps)
+  {
+    atom_usedep *w;
+    atom_usedep *n = NULL;
+
+    for (w = a->usedeps; w != NULL; w = w->next)
+    {
+      nlen = w->use != NULL ? strlen(w->use) + 1 : 0;
+      if (n == NULL)
+        ret->usedeps = n = xmalloc(sizeof(*n) + nlen);
+      else
+        n = n->next = xmalloc(sizeof(*n) + nlen);
+      n->next     = NULL;
+      n->pfx_cond = w->pfx_cond;
+      n->sfx_cond = w->sfx_cond;
+      n->use      = (char *)n + sizeof(*n);
+      memcpy(n->use, w->use, nlen);
+    }
+  }
+
+  return ret;
 }
 
-void
-atom_implode(depend_atom *atom)
+void atom_implode
+(
+  atom_ctx *a
+)
 {
-       if (!atom)
-               errf("Atom is empty !");
-       while (atom->usedeps != NULL) {
-               atom_usedep *n = atom->usedeps->next;
-               free(atom->usedeps);
-               atom->usedeps = n;
-       }
-       free(atom->suffixes);
-       free(atom);
+  if (!a)
+    errf("Atom is empty !");
+  while (a->usedeps != NULL)
+  {
+    atom_usedep *n = a->usedeps->next;
+    free(a->usedeps);
+    a->usedeps = n;
+  }
+  free(a->suffixes);
+  free(a);
 }
 
-static atom_equality
-_atom_compare_match(int ret, atom_operator op)
+static atom_equality _atom_compare_match
+(
+  int           ret,
+  atom_operator op
+)
 {
-       if (op == ATOM_OP_NONE)
-               return ret;
+  if (op == ATOM_OP_NONE)
+    return ret;
 
 #define E(x) ((x) ? EQUAL : NOT_EQUAL)
-       switch (op) {
-       case ATOM_OP_NEWER:
-               return E(ret == NEWER);
-       case ATOM_OP_NEWER_EQUAL:
-               return E(ret != OLDER);
-       case ATOM_OP_PV_EQUAL:  /* we handled this in atom_compare */
-       case ATOM_OP_EQUAL:
-               return E(ret == EQUAL);
-       case ATOM_OP_OLDER_EQUAL:
-               return E(ret != NEWER);
-       case ATOM_OP_OLDER:
-               return E(ret == OLDER);
-       default:
-               /* blockers/etc... */
-               return NOT_EQUAL;
-       }
+  switch (op)
+  {
+  case ATOM_OP_NEWER:
+    return E(ret == NEWER);
+  case ATOM_OP_NEWER_EQUAL:
+    return E(ret != OLDER);
+  case ATOM_OP_PV_EQUAL:  /* we handled this in atom_compare */
+  case ATOM_OP_EQUAL:
+    return E(ret == EQUAL);
+  case ATOM_OP_OLDER_EQUAL:
+    return E(ret != NEWER);
+  case ATOM_OP_OLDER:
+    return E(ret == OLDER);
+  default:
+    /* blockers/etc... */
+    return NOT_EQUAL;
+  }
 #undef E
 }
 
@@ -572,534 +677,620 @@ _atom_compare_match(int ret, atom_operator op)
  * foo-1 <OLDER> foo-2
  * foo-1 <NOT_EQUAL> bar-1
  */
-atom_equality
-atom_compare_flg(const depend_atom *data, const depend_atom *query, int flags)
+atom_equality atom_compare_flg
+(
+  const atom_ctx *data,
+  const atom_ctx *query,
+  int             flags
+)
 {
-       atom_operator pfx_op;
-       atom_operator sfx_op;
-       atom_blocker bl_op;
-       unsigned int ver_bits;
-
-       /* remember:
-        * query should have operators, if data has them, they are ignored */
-
-       /* here comes the antislot: bug #683430
-        * it basically is a feature to select versions that are *not*
-        * what's queried for, but requiring SLOT to be set
-        *
-        * recap of slot operators:
-        *
-        * DEPEND  perl:=        (any slot change, rebuild)
-        *         perl:0=       (any sub-slot change, rebuild)
-        *         perl:*        (any slot will do, never rebuild)
-        *         perl:0*       (any sub-slot will do, never rebuild ?valid?)
-        *         perl:0        (effectively we can treat * as absent)
-        *
-        * VDB     perl:0/5.28=  (the slot/subslot it satisfied when merging)
-        *
-        * ebuild  perl:0/5.26
-        *         perl:0        (SLOT defaults to 0)
-        *
-        * query   perl:0        (matches perl:0, perl:0/5.28)
-        *         perl:0/5.28   (matches any perl:0/5.28)
-        *        !perl:0/5.28   (matches perl, perl:0, perl:0/5.26, perl:1)
-        *        ^perl:0/5.28   (matches perl:0/5.26, perl:0/5.30)
-        *        ^perl:0        (matches perl:1)
-        *         perl:=        (= in this case is meaningless: perl, perl:0 
...)
-        *  (with ^ being a portage-utils addition to match antislot)
-        */
-       bl_op = query->blocker;
-       if (bl_op == ATOM_BL_ANTISLOT) {
-               /* just disable/ignore antislot op when SLOT is supposed to be
-                * ignored */
-               if (!(flags & ATOM_COMP_NOSLOT)) {
-                       /* ^perl -> match anything with a SLOT */
-                       if (query->SLOT == NULL && data->SLOT == NULL)
-                               return NOT_EQUAL;
-                       if (query->SLOT != NULL) {
-                               if (query->SUBSLOT == query->SLOT ||
-                                               flags & ATOM_COMP_NOSUBSLOT)
-                               {
-                                       /* ^perl:0 -> match different SLOT */
-                                       if (data->SLOT == NULL ||
-                                                       strcmp(query->SLOT, 
data->SLOT) == 0)
-                                               return NOT_EQUAL;
-                               } else {
-                                       /* ^perl:0/5.28 -> match SLOT, but 
different SUBSLOT */
-                                       if (data->SLOT == NULL ||
-                                                       strcmp(query->SLOT, 
data->SLOT) != 0)
-                                               return NOT_EQUAL;
-                                       if (!(flags & ATOM_COMP_NOSUBSLOT))
-                                               if (data->SUBSLOT == 
query->SLOT ||
-                                                               
strcmp(query->SUBSLOT, data->SUBSLOT) == 0)
-                                                       return NOT_EQUAL;
-                               }
-                       }
-               }
-               bl_op = ATOM_BL_NONE;  /* ease work below */
-       } else if (query->SLOT != NULL && !(flags & ATOM_COMP_NOSLOT)) {
-               /* check SLOT only when query side has it */
-               if (data->SLOT == NULL) {
-                       if (bl_op == ATOM_BL_NONE)
-                               return NOT_EQUAL;
-               } else {
-                       if (strcmp(query->SLOT, data->SLOT) != 0) {
-                               /* slot has differs */
-                               if (bl_op == ATOM_BL_NONE)
-                                       return NOT_EQUAL;
-                       } else if (!(flags & ATOM_COMP_NOSUBSLOT)) {
-                               if (query->SUBSLOT != query->SLOT) {
-                                       if (data->SUBSLOT == data->SLOT) {
-                                               if (bl_op == ATOM_BL_NONE)
-                                                       return NOT_EQUAL;
-                                       } else {
-                                               if (strcmp(query->SUBSLOT, 
data->SUBSLOT) != 0) {
-                                                       if (bl_op == 
ATOM_BL_NONE)
-                                                               return 
NOT_EQUAL;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /* handle the inversing effect of blockers */
-       pfx_op = query->pfx_op;
-       sfx_op = query->sfx_op;
-       if (bl_op != ATOM_BL_NONE) {
-               switch (pfx_op) {
-                       case ATOM_OP_NEWER:
-                               pfx_op = ATOM_OP_OLDER_EQUAL;
-                               break;
-                       case ATOM_OP_NEWER_EQUAL:
-                               pfx_op = ATOM_OP_OLDER;
-                               break;
-                       case ATOM_OP_OLDER:
-                               pfx_op = ATOM_OP_NEWER_EQUAL;
-                               break;
-                       case ATOM_OP_OLDER_EQUAL:
-                               pfx_op = ATOM_OP_NEWER;
-                               break;
-                       case ATOM_OP_EQUAL:
-                       case ATOM_OP_PV_EQUAL:
-                       default:
-                               pfx_op = ATOM_OP_NEQUAL;
-                               break;
-               }
-       }
-
-       /* check REPO, if query has it, ignore blocker stuff for this one */
-       if (query->REPO != NULL && !(flags & ATOM_COMP_NOREPO)) {
-               if (data->REPO == NULL)
-                       return NOT_EQUAL;
-               if (strcmp(query->REPO, data->REPO) != 0)
-                       return NOT_EQUAL;
-       }
-
-       /* check CATEGORY, if query has it, so we match
-        * atoms like "sys-devel/gcc" and "gcc" */
-       if (query->CATEGORY != NULL) {
-               if (data->CATEGORY == NULL)
-                       return NOT_EQUAL;
-               if (strcmp(query->CATEGORY, data->CATEGORY) != 0) {
-                       if (bl_op == ATOM_BL_NONE)
-                               return NOT_EQUAL;
-               } else {
-                       if (bl_op != ATOM_BL_NONE && query->PN == NULL)
-                               return EQUAL;
-               }
-       }
-
-       /* check PN, this may be absent if query is for CATEGORY only */
-       if (query->PN != NULL) {
-               if (data->PN == NULL)
-                       return NOT_EQUAL;
-               if (strcmp(query->PN, data->PN) != 0) {
-                       if (bl_op == ATOM_BL_NONE)
-                               return NOT_EQUAL;
-               } else {
-                       if (bl_op != ATOM_BL_NONE && query->PV == NULL)
-                               return EQUAL;
-               }
-       }
-
-       /* in order to handle suffix globs, we need to know all of the
-        * version elements provided in it ahead of time */
-       ver_bits = 0;
-       if (sfx_op == ATOM_OP_STAR) {
-               if (query->letter)
-                       ver_bits |= (1 << 0);
-               if (query->suffixes && query->suffixes[0].suffix != VER_NORM)
-                       ver_bits |= (1 << 1);
-               /* This doesn't handle things like foo-1.0-r0*, but that atom
-                * doesn't ever show up in practice, so who cares. */
-               if (query->PR_int)
-                       ver_bits |= (1 << 2);
-       }
-
-       /* check version */
-       if (data->PV && query->PV) {
-               char              *s1;
-               char              *ends1;
-               char              *s2;
-               char              *ends2;
-               long long          n1;
-               long long          n2;
-               const atom_suffix *as1;
-               const atom_suffix *as2;
-
-               /* PMS 3.3 Version Comparison
-                *
-                * Algorithm 3.1: Version comparison top-level logic
-                * 1:  let A and B be the versions to be compared
-                * 2:  compare numeric components using Algorithm 3.2
-                * 3:  compare letter components using Algorithm 3.4
-                * 4:  compare suffixes using Algorithm 3.5
-                * 5:  compare revision components using Algorithm 3.7
-                * 6:  return  A = B
-                */
-
-               /* step 2: numeric components
-                *
-                * Algorithm 3.2: Version comparison logic for numeric
-                * components
-                *  1:  define the notations Ank and Bnk to mean the kth numeric
-                *      component of A and B respectively, using 0-based 
indexing
-                *  2:  if An0 > Bn0 using integer comparison then
-                *  3:    return  A > B
-                *  4:  else if An0 < Bn0 using integer comparison then
-                *  5:    return  A < B
-                *  6:  end if
-                *  7:  let Ann be the number of numeric components of A
-                *  8:  let Bnn be the number of numeric components of B
-                *  9:  for all i such that i ≥ 1 and i < Ann and i < Bnn, in
-                *      ascending order do
-                * 10:    compare Ani and Bni using Algorithm 3.3
-                * 11:  end for
-                * 12:  if Ann > Bnn then
-                * 13:    return  A > B
-                * 14:  else if Ann < Bnn then
-                * 15:    return  A < B
-                * 16:  end if
-                *
-                * Algorithm 3.3: Version comparison logic for each numeric
-                * component after the first
-                *  1:  if either Ani or Bni has a leading 0 then
-                *  2:    let An′i be Ani with any trailing 0s removed
-                *  3:    let Bn′i be Bni with any trailing 0s removed
-                *  4:    if An′i > Bn′i using ASCII stringwise comparison then
-                *  5:      return  A > B
-                *  6:    else if An′i < Bn′i using ASCII stringwise comparison 
then
-                *  7:      return  A < B
-                *  8:    end if
-                *  9:  else
-                * 10:    if Ani > Bni using integer comparison then
-                * 11:      return  A > B
-                * 12:    else if Ani < Bni using integer comparison then
-                * 13:      return  A < B
-                * 14:    end if
-                * 15:  end if
-                */
-               s1    = data->PV;   /* A */
-               s2    = query->PV;  /* B */
-               ends1 = NULL;
-               ends2 = NULL;
-               n1    = 0;
-               n2    = 0;
-               while (s1 != NULL || s2 != NULL) {
-                       if (s1 != NULL && s2 != NULL) {
-                               if (ends1 == NULL) {
-                                       /* 3.2#L2-6: first component integer 
comparison */
-                                       n1 = strtoll(s1, &ends1, 10);
-                                       if (ends1 == s1)
-                                               n1 = -1;
-                                       n2 = strtoll(s2, &ends2, 10);
-                                       if (ends2 == s2)
-                                               n2 = -1;
-                               } else {
-                                       /* 3.2#L9-11: run algorithm 3.3 for 
remaining
-                                        * components */
-
-                                       /* 3.3#L1-9: if a leading zero is 
present do strcmp */
-                                       if (*s1 == '0' || *s2 == '0') {  /* 
3.3#L1 */
-                                               /* find end of component */
-                                               for (ends1 = s1;
-                                                        *ends1 != '\0' &&
-                                                        *ends1 != '.' &&
-                                                        *ends1 != '_';
-                                                        ends1++)
-                                                       ;
-                                               if (ends1 != s1)
-                                                       ends1--;
-                                               for (ends2 = s2;
-                                                        *ends2 != '\0' &&
-                                                        *ends2 != '.' &&
-                                                        *ends2 != '_';
-                                                        ends2++)
-                                                       ;
-                                               if (ends2 != s2)
-                                                       ends2--;
-                                               /* bug 852197: leading 0 means 
something else
-                                                *              must follow */
-                                               if (ends1 - s1 > 1 || ends2 - 
s2 > 1) {
-                                                       /* 3.3L2-3: remove 
*trailing* zeros */
-                                                       for (; ends1 > s1 && 
*ends1 == '0'; ends1--)
-                                                               ;
-                                                       for (; ends2 > s2 && 
*ends2 == '0'; ends2--)
-                                                               ;
-                                                       /* 3.3L4 ASCII 
stringwise comparison */
-                                                       n1 = ends1 - s1;
-                                                       n2 = ends2 - s2;
-                                                       n1 = strncmp(s1, s2, n1 
> n2 ? n1 : n2);
-                                                       n2 = 0;
-                                               } else {
-                                                       /* repeat of 3.3#L9 
(else case below) */
-                                                       n1 = strtoll(s1, 
&ends1, 10);
-                                                       if (ends1 == s1)
-                                                               n1 = -1;
-                                                       n2 = strtoll(s2, 
&ends2, 10);
-                                                       if (ends2 == s2)
-                                                               n2 = -1;
-                                               }
-                                       } else {  /* 3.3#L9 */
-                                               n1 = strtoll(s1, &ends1, 10);
-                                               if (ends1 == s1)
-                                                       n1 = -1;
-                                               n2 = strtoll(s2, &ends2, 10);
-                                               if (ends2 == s2)
-                                                       n2 = -1;
-                                       }
-                               }
-                       } else if (sfx_op == ATOM_OP_STAR && s2 == NULL && 
!ver_bits) {
-                               return _atom_compare_match(EQUAL, pfx_op);
-                       } else {  /* 3.2#L12-16 */
-                               if (s1 == NULL) {
-                                       n1    = -1;
-                                       n2    =  0;
-                                       ends1 =  NULL;
-                               }
-                               else if (s2 == NULL) {
-                                       n1    =  0;
-                                       n2    = -1;
-                                       ends2 =  NULL;
-                               }
-                       }
-
-                       if (n1 < n2)
-                               return _atom_compare_match(OLDER, pfx_op);
-                       else if (n1 > n2)
-                               return _atom_compare_match(NEWER, pfx_op);
-
-                       s1 = *ends1 == '\0' ? NULL : ends1;
-                       if (s1 != NULL) {
-                               if (*s1 != '.')
-                                       s1 = strchr(s1, '.');
-                               if (s1 != NULL)
-                                       s1++;
-                       }
-                       s2 = *ends2 == '\0' ? NULL : ends2;
-                       if (s2 != NULL) {
-                               if (*s2 != '.')
-                                       s2 = strchr(s2, '.');
-                               if (s2 != NULL)
-                                       s2++;
-                       }
-               }
-
-               /* step 3: compare trailing letter 1.0[z]_alpha1
-                *
-                * Algorithm 3.4: Version comparison logic for letter components
-                * 1:  let Al be the letter component of A if any, otherwise the
-                *     empty string
-                * 2:  let Bl be the letter component of B if any, otherwise the
-                *     empty string
-                * 3:  if Al > Bl using ASCII stringwise comparison then
-                * 4:    return  A > B
-                * 5:  else if Al < Bl using ASCII stringwise comparison then
-                * 6:    return  A < B
-                * 7:  end if
-                */
-               if (sfx_op == ATOM_OP_STAR) {
-                       ver_bits >>= 1;
-                       if (!query->letter && !ver_bits)
-                               return _atom_compare_match(EQUAL, pfx_op);
-               }
-               if (data->letter < query->letter)
-                       return _atom_compare_match(OLDER, pfx_op);
-               if (data->letter > query->letter)
-                       return _atom_compare_match(NEWER, pfx_op);
-
-               /* Algorithm 3.5: Version comparison logic for suffixes
-                *  1:  define the notations Ask and Bsk to mean the kth suffix
-                *      of A and B respectively, using 0-based indexing
-                *  2:  let Asn be the number of suffixes of A
-                *  3:  let Bsn be the number of suffixes of B
-                *  4:  for all i such that i ≥ 0 and i < Asn and i < Bsn, in
-                *      ascending order do
-                *  5:    compare Asi and Bsi using algorithm 3.6
-                *  6:  end for
-                *  7:  if Asn > Bsn then
-                *  8:    if AsBsn is of type _p then
-                *  9:      return  A > B
-                * 10:    else
-                * 11:      return  A < B
-                * 12:    end if
-                * 13:  else if Asn < Bsn then
-                * 14:    if BsAsn is of type _p then
-                * 15:      return  A < B
-                * 16:    else
-                * 17:      return  A > B
-                * 18:    end if
-                * 19:  end if
-                *
-                * Algorithm 3.6: Version comparison logic for each suffix
-                *  1:  if Asi and Bsi are of the same type (_alpha vs _beta 
etc) then
-                *  2:    let As′i be the integer part of Asi if any, otherwise 0
-                *  3:    let Bs′i be the integer part of Bsi if any, otherwise 0
-                *  4:    if As′i > Bs′i, using integer comparison then
-                *  5:      return  A > B
-                *  6:    else if As′i < Bs′i, using integer comparison then
-                *  7:      return  A < B
-                *  8:    end if
-                *  9:  else if the type of Asi is greater than the type of Bsi
-                *      using the ordering _alpha < _beta < _pre < _rc < _p then
-                * 10:    return  A > B
-                * 11:  else
-                * 12:    return  A < B
-                * 13:  end if
-                */
-
-               /* step 4: find differing suffixes 1.0z[_alpha1] */
-               as1 = &data->suffixes[0];
-               as2 = &query->suffixes[0];
-               while (as1->suffix == as2->suffix) {
-                       if (as1->suffix == VER_NORM || as2->suffix == VER_NORM)
-                               break;
-
-                       if (as1->sint != as2->sint)
-                               break;
-
-                       as1++;
-                       as2++;
-               }
-
-               /* compare suffixes 1.0z[_alpha]1 */
-               if (sfx_op == ATOM_OP_STAR) {
-                       ver_bits >>= 1;
-                       if (as2->suffix == VER_NORM && !ver_bits)
-                               return _atom_compare_match(EQUAL, pfx_op);
-               }
-               if (as1->suffix < as2->suffix)  /* 3.6#L9 */
-                       return _atom_compare_match(OLDER, pfx_op);
-               else if (as1->suffix > as2->suffix)
-                       return _atom_compare_match(NEWER, pfx_op);
-               /* compare suffix number 1.0z_alpha[1] 3.6#L4 */
-               if (sfx_op == ATOM_OP_STAR && !as2->sint && !ver_bits)
-                       return _atom_compare_match(EQUAL, pfx_op);
-               else if (as1->sint < as2->sint)
-                       return _atom_compare_match(OLDER, pfx_op);
-               else if (as1->sint > as2->sint)
-                       return _atom_compare_match(NEWER, pfx_op);
-               /* fall through to -r# check below */
-       } else if (data->PV || query->PV)
-               return EQUAL;
-
-       /* Algorithm 3.7: Version comparison logic for revision components
-        * 1:  let Ar be the integer part of the revision component of A if
-        *     any, otherwise 0
-        * 2:  let Br be the integer part of the revision component of B if
-        *     any, otherwise 0
-        * 3:  if Ar > Br using integer comparison then
-        * 4:    return  A > B
-        * 5:  else if Ar < Br using integer comparison then
-        * 6:    return  A < B
-        * 7:  end if
-        */
-       /* first handle wildcarding cases */
-       if ((sfx_op == ATOM_OP_STAR && query->PR_int == 0) ||
-           pfx_op == ATOM_OP_PV_EQUAL ||
-               flags & ATOM_COMP_NOREV)
-               return _atom_compare_match(EQUAL, pfx_op);
-       /* Make sure the -r# is the same. 3.7 */
-       if (data->PR_int < query->PR_int)
-               return _atom_compare_match(OLDER, pfx_op);
-       else if (data->PR_int > query->PR_int)
-               return _atom_compare_match(NEWER, pfx_op);
-
-       /* binpkg-multi-instance support */
-       if (data->BUILDID > 0 &&
-               query->BUILDID > 0)
-       {
-               if (data->BUILDID < query->BUILDID)
-                       return _atom_compare_match(OLDER, pfx_op);
-               if (data->BUILDID > query->BUILDID)
-                       return _atom_compare_match(NEWER, pfx_op);
-       }
-
-       return _atom_compare_match(EQUAL, pfx_op);
+  atom_operator pfx_op;
+  atom_operator sfx_op;
+  atom_blocker  bl_op;
+  unsigned int  ver_bits;
+
+  /* remember:
+   * query should have operators, if data has them, they are ignored */
+
+  /* here comes the antislot: bug #683430
+   * it basically is a feature to select versions that are *not*
+   * what's queried for, but requiring SLOT to be set
+   *
+   * recap of slot operators:
+   *
+   * DEPEND  perl:=        (any slot change, rebuild)
+   *         perl:0=       (any sub-slot change, rebuild)
+   *         perl:*        (any slot will do, never rebuild)
+   *         perl:0*       (any sub-slot will do, never rebuild ?valid?)
+   *         perl:0        (effectively we can treat * as absent)
+   *
+   * VDB     perl:0/5.28=  (the slot/subslot it satisfied when merging)
+   *
+   * ebuild  perl:0/5.26
+   *         perl:0        (SLOT defaults to 0)
+   *
+   * query   perl:0        (matches perl:0, perl:0/5.28)
+   *         perl:0/5.28   (matches any perl:0/5.28)
+   *        !perl:0/5.28   (matches perl, perl:0, perl:0/5.26, perl:1)
+   *        ^perl:0/5.28   (matches perl:0/5.26, perl:0/5.30)
+   *        ^perl:0        (matches perl:1)
+   *         perl:=        (= in this case is meaningless: perl, perl:0 ...)
+   *  (with ^ being a portage-utils addition to match antislot)
+   */
+  bl_op = query->blocker;
+  if (bl_op == ATOM_BL_ANTISLOT)
+  {
+    /* just disable/ignore antislot op when SLOT is supposed to be
+     * ignored */
+    if (!(flags & ATOM_COMP_NOSLOT))
+    {
+      /* ^perl -> match anything with a SLOT */
+      if (query->SLOT == NULL && data->SLOT == NULL)
+        return NOT_EQUAL;
+      if (query->SLOT != NULL)
+      {
+        if (query->SUBSLOT == query->SLOT ||
+            flags & ATOM_COMP_NOSUBSLOT)
+        {
+          /* ^perl:0 -> match different SLOT */
+          if (data->SLOT == NULL ||
+              strcmp(query->SLOT, data->SLOT) == 0)
+            return NOT_EQUAL;
+        }
+        else
+        {
+          /* ^perl:0/5.28 -> match SLOT, but different SUBSLOT */
+          if (data->SLOT == NULL ||
+              strcmp(query->SLOT, data->SLOT) != 0)
+            return NOT_EQUAL;
+          if (!(flags & ATOM_COMP_NOSUBSLOT))
+            if (data->SUBSLOT == query->SLOT ||
+                strcmp(query->SUBSLOT, data->SUBSLOT) == 0)
+              return NOT_EQUAL;
+        }
+      }
+    }
+    bl_op = ATOM_BL_NONE;  /* ease work below */
+  }
+  else if (query->SLOT != NULL &&
+           !(flags & ATOM_COMP_NOSLOT))
+  {
+    /* check SLOT only when query side has it */
+    if (data->SLOT == NULL)
+    {
+      if (bl_op == ATOM_BL_NONE)
+        return NOT_EQUAL;
+    }
+    else
+    {
+      if (strcmp(query->SLOT, data->SLOT) != 0)
+      {
+        /* slot has differs */
+        if (bl_op == ATOM_BL_NONE)
+          return NOT_EQUAL;
+      }
+      else if (!(flags & ATOM_COMP_NOSUBSLOT))
+      {
+        if (query->SUBSLOT != query->SLOT)
+        {
+          if (data->SUBSLOT == data->SLOT)
+          {
+            if (bl_op == ATOM_BL_NONE)
+              return NOT_EQUAL;
+          }
+          else
+          {
+            if (strcmp(query->SUBSLOT, data->SUBSLOT) != 0)
+            {
+              if (bl_op == ATOM_BL_NONE)
+                return NOT_EQUAL;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /* handle the inversing effect of blockers */
+  pfx_op = query->pfx_op;
+  sfx_op = query->sfx_op;
+  if (bl_op != ATOM_BL_NONE)
+  {
+    switch (pfx_op)
+    {
+    case ATOM_OP_NEWER:
+      pfx_op = ATOM_OP_OLDER_EQUAL;
+      break;
+    case ATOM_OP_NEWER_EQUAL:
+      pfx_op = ATOM_OP_OLDER;
+      break;
+    case ATOM_OP_OLDER:
+      pfx_op = ATOM_OP_NEWER_EQUAL;
+      break;
+    case ATOM_OP_OLDER_EQUAL:
+      pfx_op = ATOM_OP_NEWER;
+      break;
+    case ATOM_OP_EQUAL:
+    case ATOM_OP_PV_EQUAL:
+    default:
+      pfx_op = ATOM_OP_NEQUAL;
+      break;
+    }
+  }
+
+  /* check REPO, if query has it, ignore blocker stuff for this one */
+  if (query->REPO != NULL &&
+      !(flags & ATOM_COMP_NOREPO))
+  {
+    if (data->REPO == NULL)
+      return NOT_EQUAL;
+    if (strcmp(query->REPO, data->REPO) != 0)
+      return NOT_EQUAL;
+  }
+
+  /* check CATEGORY, if query has it, so we match
+   * atoms like "sys-devel/gcc" and "gcc" */
+  if (query->CATEGORY != NULL)
+  {
+    if (data->CATEGORY == NULL)
+      return NOT_EQUAL;
+    if (strcmp(query->CATEGORY, data->CATEGORY) != 0)
+    {
+      if (bl_op == ATOM_BL_NONE)
+        return NOT_EQUAL;
+    }
+    else
+    {
+      if (bl_op != ATOM_BL_NONE && query->PN == NULL)
+        return EQUAL;
+    }
+  }
+
+  /* check PN, this may be absent if query is for CATEGORY only */
+  if (query->PN != NULL)
+  {
+    if (data->PN == NULL)
+      return NOT_EQUAL;
+    if (strcmp(query->PN, data->PN) != 0)
+    {
+      if (bl_op == ATOM_BL_NONE)
+        return NOT_EQUAL;
+    }
+    else
+    {
+      if (bl_op != ATOM_BL_NONE && query->PV == NULL)
+        return EQUAL;
+    }
+  }
+
+  /* in order to handle suffix globs, we need to know all of the
+   * version elements provided in it ahead of time */
+  ver_bits = 0;
+  if (sfx_op == ATOM_OP_STAR)
+  {
+    if (query->letter)
+      ver_bits |= (1 << 0);
+    if (query->suffixes &&
+        query->suffixes[0].suffix != VER_NORM)
+      ver_bits |= (1 << 1);
+    /* This doesn't handle things like foo-1.0-r0*, but that atom
+     * doesn't ever show up in practice, so who cares. */
+    if (query->PR_int)
+      ver_bits |= (1 << 2);
+  }
+
+  /* check version */
+  if (data->PV &&
+      query->PV)
+  {
+    char              *s1;
+    char              *ends1;
+    char              *s2;
+    char              *ends2;
+    long long          n1;
+    long long          n2;
+    const atom_suffix *as1;
+    const atom_suffix *as2;
+
+    /* PMS 3.3 Version Comparison
+     *
+     * Algorithm 3.1: Version comparison top-level logic
+     * 1:  let A and B be the versions to be compared
+     * 2:  compare numeric components using Algorithm 3.2
+     * 3:  compare letter components using Algorithm 3.4
+     * 4:  compare suffixes using Algorithm 3.5
+     * 5:  compare revision components using Algorithm 3.7
+     * 6:  return  A = B
+     */
+
+    /* step 2: numeric components
+     *
+     * Algorithm 3.2: Version comparison logic for numeric
+     * components
+     *  1:  define the notations Ank and Bnk to mean the kth numeric
+     *      component of A and B respectively, using 0-based indexing
+     *  2:  if An0 > Bn0 using integer comparison then
+     *  3:    return  A > B
+     *  4:  else if An0 < Bn0 using integer comparison then
+     *  5:    return  A < B
+     *  6:  end if
+     *  7:  let Ann be the number of numeric components of A
+     *  8:  let Bnn be the number of numeric components of B
+     *  9:  for all i such that i ≥ 1 and i < Ann and i < Bnn, in
+     *      ascending order do
+     * 10:    compare Ani and Bni using Algorithm 3.3
+     * 11:  end for
+     * 12:  if Ann > Bnn then
+     * 13:    return  A > B
+     * 14:  else if Ann < Bnn then
+     * 15:    return  A < B
+     * 16:  end if
+     *
+     * Algorithm 3.3: Version comparison logic for each numeric
+     * component after the first
+     *  1:  if either Ani or Bni has a leading 0 then
+     *  2:    let An′i be Ani with any trailing 0s removed
+     *  3:    let Bn′i be Bni with any trailing 0s removed
+     *  4:    if An′i > Bn′i using ASCII stringwise comparison then
+     *  5:      return  A > B
+     *  6:    else if An′i < Bn′i using ASCII stringwise comparison then
+     *  7:      return  A < B
+     *  8:    end if
+     *  9:  else
+     * 10:    if Ani > Bni using integer comparison then
+     * 11:      return  A > B
+     * 12:    else if Ani < Bni using integer comparison then
+     * 13:      return  A < B
+     * 14:    end if
+     * 15:  end if
+     */
+    s1    = data->PV;   /* A */
+    s2    = query->PV;  /* B */
+    ends1 = NULL;
+    ends2 = NULL;
+    n1    = 0;
+    n2    = 0;
+    while (s1 != NULL ||
+           s2 != NULL)
+    {
+      if (s1 != NULL &&
+          s2 != NULL)
+      {
+        if (ends1 == NULL)
+        {
+          /* 3.2#L2-6: first component integer comparison */
+          n1 = strtoll(s1, &ends1, 10);
+          if (ends1 == s1)
+            n1 = -1;
+          n2 = strtoll(s2, &ends2, 10);
+          if (ends2 == s2)
+            n2 = -1;
+        }
+        else
+        {
+          /* 3.2#L9-11: run algorithm 3.3 for remaining
+           * components */
+
+          /* 3.3#L1-9: if a leading zero is present do strcmp */
+          if (*s1 == '0' ||
+              *s2 == '0')
+          {  /* 3.3#L1 */
+            /* find end of component */
+            for (ends1 = s1;
+                 (*ends1 != '\0' &&
+                  *ends1 != '.' &&
+                  *ends1 != '_');
+                 ends1++)
+              ;
+            if (ends1 != s1)
+              ends1--;
+            for (ends2 = s2;
+                 (*ends2 != '\0' &&
+                  *ends2 != '.' &&
+                  *ends2 != '_');
+                 ends2++)
+              ;
+            if (ends2 != s2)
+              ends2--;
+            /* bug 852197: leading 0 means something else
+             *              must follow */
+            if (ends1 - s1 > 1 ||
+                ends2 - s2 > 1)
+            {
+              /* 3.3L2-3: remove *trailing* zeros */
+              for (; ends1 > s1 && *ends1 == '0'; ends1--)
+                ;
+              for (; ends2 > s2 && *ends2 == '0'; ends2--)
+                ;
+              /* 3.3L4 ASCII stringwise comparison */
+              n1 = ends1 - s1;
+              n2 = ends2 - s2;
+              n1 = strncmp(s1, s2, n1 > n2 ? n1 : n2);
+              n2 = 0;
+            }
+            else
+            {
+              /* repeat of 3.3#L9 (else case below) */
+              n1 = strtoll(s1, &ends1, 10);
+              if (ends1 == s1)
+                n1 = -1;
+              n2 = strtoll(s2, &ends2, 10);
+              if (ends2 == s2)
+                n2 = -1;
+            }
+          }
+          else
+          {  /* 3.3#L9 */
+            n1 = strtoll(s1, &ends1, 10);
+            if (ends1 == s1)
+              n1 = -1;
+            n2 = strtoll(s2, &ends2, 10);
+            if (ends2 == s2)
+              n2 = -1;
+          }
+        }
+      }
+      else if (sfx_op == ATOM_OP_STAR &&
+               s2 == NULL &&
+               !ver_bits)
+      {
+        return _atom_compare_match(EQUAL, pfx_op);
+      }
+      else
+      {  /* 3.2#L12-16 */
+        if (s1 == NULL)
+        {
+          n1    = -1;
+          n2    =  0;
+          ends1 =  NULL;
+        }
+        else if (s2 == NULL)
+        {
+          n1    =  0;
+          n2    = -1;
+          ends2 =  NULL;
+        }
+      }
+
+      if (n1 < n2)
+        return _atom_compare_match(OLDER, pfx_op);
+      else if (n1 > n2)
+        return _atom_compare_match(NEWER, pfx_op);
+
+      s1 = *ends1 == '\0' ? NULL : ends1;
+      if (s1 != NULL)
+      {
+        if (*s1 != '.')
+          s1 = strchr(s1, '.');
+        if (s1 != NULL)
+          s1++;
+      }
+      s2 = *ends2 == '\0' ? NULL : ends2;
+      if (s2 != NULL)
+      {
+        if (*s2 != '.')
+          s2 = strchr(s2, '.');
+        if (s2 != NULL)
+          s2++;
+      }
+    }
+
+    /* step 3: compare trailing letter 1.0[z]_alpha1
+     *
+     * Algorithm 3.4: Version comparison logic for letter components
+     * 1:  let Al be the letter component of A if any, otherwise the
+     *     empty string
+     * 2:  let Bl be the letter component of B if any, otherwise the
+     *     empty string
+     * 3:  if Al > Bl using ASCII stringwise comparison then
+     * 4:    return  A > B
+     * 5:  else if Al < Bl using ASCII stringwise comparison then
+     * 6:    return  A < B
+     * 7:  end if
+     */
+    if (sfx_op == ATOM_OP_STAR)
+    {
+      ver_bits >>= 1;
+      if (!query->letter &&
+          !ver_bits)
+        return _atom_compare_match(EQUAL, pfx_op);
+    }
+    if (data->letter < query->letter)
+      return _atom_compare_match(OLDER, pfx_op);
+    if (data->letter > query->letter)
+      return _atom_compare_match(NEWER, pfx_op);
+
+    /* Algorithm 3.5: Version comparison logic for suffixes
+     *  1:  define the notations Ask and Bsk to mean the kth suffix
+     *      of A and B respectively, using 0-based indexing
+     *  2:  let Asn be the number of suffixes of A
+     *  3:  let Bsn be the number of suffixes of B
+     *  4:  for all i such that i >= 0 and i < Asn and i < Bsn, in
+     *      ascending order do
+     *  5:    compare Asi and Bsi using algorithm 3.6
+     *  6:  end for
+     *  7:  if Asn > Bsn then
+     *  8:    if AsBsn is of type _p then
+     *  9:      return  A > B
+     * 10:    else
+     * 11:      return  A < B
+     * 12:    end if
+     * 13:  else if Asn < Bsn then
+     * 14:    if BsAsn is of type _p then
+     * 15:      return  A < B
+     * 16:    else
+     * 17:      return  A > B
+     * 18:    end if
+     * 19:  end if
+     *
+     * Algorithm 3.6: Version comparison logic for each suffix
+     *  1:  if Asi and Bsi are of the same type (_alpha vs _beta etc) then
+     *  2:    let As'i be the integer part of Asi if any, otherwise 0
+     *  3:    let Bs'i be the integer part of Bsi if any, otherwise 0
+     *  4:    if As'i > Bs'i, using integer comparison then
+     *  5:      return  A > B
+     *  6:    else if As'i < Bs'i, using integer comparison then
+     *  7:      return  A < B
+     *  8:    end if
+     *  9:  else if the type of Asi is greater than the type of Bsi
+     *      using the ordering _alpha < _beta < _pre < _rc < _p then
+     * 10:    return  A > B
+     * 11:  else
+     * 12:    return  A < B
+     * 13:  end if
+     */
+
+    /* step 4: find differing suffixes 1.0z[_alpha1] */
+    as1 = &data->suffixes[0];
+    as2 = &query->suffixes[0];
+    while (as1->suffix == as2->suffix)
+    {
+      if (as1->suffix == VER_NORM ||
+          as2->suffix == VER_NORM)
+        break;
+
+      if (as1->sint != as2->sint)
+        break;
+
+      as1++;
+      as2++;
+    }
+
+    /* compare suffixes 1.0z[_alpha]1 */
+    if (sfx_op == ATOM_OP_STAR)
+    {
+      ver_bits >>= 1;
+      if (as2->suffix == VER_NORM &&
+          !ver_bits)
+        return _atom_compare_match(EQUAL, pfx_op);
+    }
+    if (as1->suffix < as2->suffix)  /* 3.6#L9 */
+      return _atom_compare_match(OLDER, pfx_op);
+    else if (as1->suffix > as2->suffix)
+      return _atom_compare_match(NEWER, pfx_op);
+    /* compare suffix number 1.0z_alpha[1] 3.6#L4 */
+    if (sfx_op == ATOM_OP_STAR &&
+        !as2->sint &&
+        !ver_bits)
+      return _atom_compare_match(EQUAL, pfx_op);
+    else if (as1->sint < as2->sint)
+      return _atom_compare_match(OLDER, pfx_op);
+    else if (as1->sint > as2->sint)
+      return _atom_compare_match(NEWER, pfx_op);
+    /* fall through to -r# check below */
+  }
+  else if (data->PV ||
+           query->PV)
+  {
+    return EQUAL;
+  }
+
+  /* Algorithm 3.7: Version comparison logic for revision components
+   * 1:  let Ar be the integer part of the revision component of A if
+   *     any, otherwise 0
+   * 2:  let Br be the integer part of the revision component of B if
+   *     any, otherwise 0
+   * 3:  if Ar > Br using integer comparison then
+   * 4:    return  A > B
+   * 5:  else if Ar < Br using integer comparison then
+   * 6:    return  A < B
+   * 7:  end if
+   */
+  /* first handle wildcarding cases */
+  if ((sfx_op == ATOM_OP_STAR &&
+       query->PR_int == 0) ||
+      pfx_op == ATOM_OP_PV_EQUAL ||
+      flags & ATOM_COMP_NOREV)
+    return _atom_compare_match(EQUAL, pfx_op);
+  /* Make sure the -r# is the same. 3.7 */
+  if (data->PR_int < query->PR_int)
+    return _atom_compare_match(OLDER, pfx_op);
+  else if (data->PR_int > query->PR_int)
+    return _atom_compare_match(NEWER, pfx_op);
+
+  /* binpkg-multi-instance support */
+  if (data->BUILDID > 0 &&
+      query->BUILDID > 0)
+  {
+    if (data->BUILDID < query->BUILDID)
+      return _atom_compare_match(OLDER, pfx_op);
+    if (data->BUILDID > query->BUILDID)
+      return _atom_compare_match(NEWER, pfx_op);
+  }
+
+  return _atom_compare_match(EQUAL, pfx_op);
 }
 
-atom_equality
-atom_compare_str(const char * const s1, const char * const s2)
+atom_equality atom_compare_str
+(
+  const char * const s1,
+  const char * const s2
+)
 {
-       depend_atom *a1, *a2;
-       atom_equality ret = ERROR;
+  atom_ctx     *a1;
+  atom_ctx     *a2;
+  atom_equality ret = ERROR;
 
-       a1 = atom_explode(s1);
-       if (!a1)
-               return ret;
+  a1 = atom_explode(s1);
+  if (!a1)
+    return ret;
 
-       a2 = atom_explode(s2);
-       if (!a2)
-               goto implode_a1_ret;
+  a2 = atom_explode(s2);
+  if (!a2)
+    goto implode_a1_ret;
 
-       ret = atom_compare(a1, a2);
+  ret = atom_compare(a1, a2);
 
-       atom_implode(a2);
+  atom_implode(a2);
 implode_a1_ret:
-       atom_implode(a1);
-       return ret;
+  atom_implode(a1);
+  return ret;
 }
 
 /**
  * Reconstructs an atom exactly like it was originally given (exploded).
  */
-char *
-atom_to_string_r(char *buf, size_t buflen, depend_atom *a)
+char *atom_to_string_r
+(
+  char     *buf,
+  size_t    buflen,
+  atom_ctx *a
+)
 {
-       size_t off = 0;
-       atom_usedep *ud;
-
-       off += snprintf(buf + off, buflen - off, "%s%s",
-                       atom_blocker_str[a->blocker], atom_op_str[a->pfx_op]);
-       if (a->CATEGORY != NULL)
-               off += snprintf(buf + off, buflen - off, "%s/", a->CATEGORY);
-       if (a->PN != NULL)
-               off += snprintf(buf + off, buflen - off, "%s", a->PN);
-       if (a->PV != NULL)
-               off += snprintf(buf + off, buflen - off, "-%s", a->PV);
-       if (a->PR_int > 0)
-               off += snprintf(buf + off, buflen - off, "-r%d", a->PR_int);
-       if (a->BUILDID > 0)
-               off += snprintf(buf + off, buflen - off, "~%u", a->BUILDID);
-       off += snprintf(buf + off, buflen - off, "%s", atom_op_str[a->sfx_op]);
-       if (a->SLOT != NULL || a->slotdep != ATOM_SD_NONE)
-               off += snprintf(buf + off, buflen - off, ":%s%s%s%s",
-                               a->SLOT ? a->SLOT : "",
-                               a->SUBSLOT && a->SUBSLOT != a->SLOT ?  "/" : "",
-                               a->SUBSLOT && a->SUBSLOT != a->SLOT ? 
a->SUBSLOT : "",
-                               atom_slotdep_str[a->slotdep]);
-       for (ud = a->usedeps; ud != NULL; ud = ud->next)
-               off += snprintf(buf + off, buflen - off, "%s%s%s%s%s",
-                               ud == a->usedeps ? "[" : "",
-                               atom_usecond_str[ud->pfx_cond],
-                               ud->use,
-                               atom_usecond_str[ud->sfx_cond],
-                               ud->next == NULL ? "]" : ",");
-       if (a->REPO != NULL)
-               off += snprintf(buf + off, buflen - off, "::%s", a->REPO);
-
-       return buf;
+  atom_usedep *ud;
+  size_t       off = 0;
+
+  off += snprintf(buf + off, buflen - off, "%s%s",
+                  atom_blocker_str[a->blocker], atom_op_str[a->pfx_op]);
+  if (a->CATEGORY != NULL)
+    off += snprintf(buf + off, buflen - off, "%s/", a->CATEGORY);
+  if (a->PN != NULL)
+    off += snprintf(buf + off, buflen - off, "%s", a->PN);
+  if (a->PV != NULL)
+    off += snprintf(buf + off, buflen - off, "-%s", a->PV);
+  if (a->PR_int > 0)
+    off += snprintf(buf + off, buflen - off, "-r%d", a->PR_int);
+  if (a->BUILDID > 0)
+    off += snprintf(buf + off, buflen - off, "~%u", a->BUILDID);
+  off += snprintf(buf + off, buflen - off, "%s", atom_op_str[a->sfx_op]);
+  if (a->SLOT != NULL ||
+      a->slotdep != ATOM_SD_NONE)
+    off += snprintf(buf + off, buflen - off, ":%s%s%s%s",
+                    a->SLOT ? a->SLOT : "",
+                    a->SUBSLOT && a->SUBSLOT != a->SLOT ?  "/" : "",
+                    a->SUBSLOT && a->SUBSLOT != a->SLOT ? a->SUBSLOT : "",
+                    atom_slotdep_str[a->slotdep]);
+  for (ud = a->usedeps; ud != NULL; ud = ud->next)
+    off += snprintf(buf + off, buflen - off, "%s%s%s%s%s",
+                    ud == a->usedeps ? "[" : "",
+                    atom_usecond_str[ud->pfx_cond],
+                    ud->use,
+                    atom_usecond_str[ud->sfx_cond],
+                    ud->next == NULL ? "]" : ",");
+  if (a->REPO != NULL)
+    off += snprintf(buf + off, buflen - off, "::%s", a->REPO);
+
+  return buf;
 }
 
 /**
@@ -1114,207 +1305,290 @@ atom_to_string_r(char *buf, size_t buflen, 
depend_atom *a)
  *  sfx - the version qualifier if set (e.g. *)
  *  BUILDID - the binpkg-multi-instance id
  */
-char *
-atom_format_r(
-               char *buf,
-               size_t buflen,
-               const char *format,
-               const depend_atom *atom)
+char *atom_format_r
+(
+  char           *buf,
+  size_t          buflen,
+  const char     *format,
+  const atom_ctx *a
+)
 {
-       char bracket;
-       const char *fmt;
-       const char *p;
-       size_t len;
-       bool showit;
-       bool connected;
-       char *ret;
-
-       if (!atom) {
-               snprintf(buf, buflen, "%s", "(NULL:atom)");
-               return buf;
-       }
+  const char *fmt;
+  const char *p;
+  char       *ret;
+  size_t      len;
+  char        bracket;
+  bool        showit;
+  bool        connected;
+
+  if (!a)
+  {
+    snprintf(buf, buflen, "%s", "(NULL:atom)");
+    return buf;
+  }
 
 #define append_buf(B,L,FMT,...) \
-       { \
-               len = snprintf(B, L, FMT, __VA_ARGS__); \
-               L -= len; \
-               B += len; \
-       }
-       ret = buf;
-       p = format;
-       while (*p != '\0') {
-               fmt = strchr(p, '%');
-               if (fmt == NULL) {
-                       append_buf(buf, buflen, "%s", p);
-                       return ret;
-               } else if (fmt != p) {
-                       append_buf(buf, buflen, "%.*s", (int)(fmt - p), p);
-                       connected = false;
-               } else {
-                       connected = true;
-               }
-
-               bracket = fmt[1];
-               if (bracket == '{' || bracket == '[') {
-                       connected &= bracket == '[';
-                       fmt += 2;
-                       if ((p = strchr(fmt, bracket == '{' ? '}' : ']')) != 
NULL) {
-                               len = p - fmt;
-                               showit = bracket == '{';
+  { \
+    len = snprintf(B, L, FMT, __VA_ARGS__); \
+    L -= len; \
+    B += len; \
+  }
+  ret = buf;
+  p = format;
+  while (*p != '\0')
+  {
+    fmt = strchr(p, '%');
+    if (fmt == NULL)
+    {
+      append_buf(buf, buflen, "%s", p);
+      return ret;
+    }
+    else if (fmt != p)
+    {
+      append_buf(buf, buflen, "%.*s", (int)(fmt - p), p);
+      connected = false;
+    }
+    else
+    {
+      connected = true;
+    }
+
+    bracket = fmt[1];
+    if (bracket == '{' ||
+        bracket == '[')
+    {
+      connected &= bracket == '[';
+      fmt += 2;
+      if ((p = strchr(fmt, bracket == '{' ? '}' : ']')) != NULL)
+      {
+        len = p - fmt;
+        showit = bracket == '{';
 #define HN(X) (X ? X : "<unset>")
-                               if (!strncmp("CATEGORY", fmt, len)) {
-                                       connected = (p[1] == '%') & (bracket == 
'[');
-                                       if (showit || atom->CATEGORY)
-                                               append_buf(buf, buflen, 
"%s%s%s%s",
-                                                               BOLD, 
HN(atom->CATEGORY),
-                                                               connected ? "/" 
: "", NORM);
-                               } else if (!strncmp("P", fmt, len)) {
-                                       if (showit || atom->P)
-                                               append_buf(buf, buflen, 
"%s%s%s",
-                                                               BLUE, 
HN(atom->P), NORM);
-                               } else if (!strncmp("PN", fmt, len)) {
-                                       if (showit || atom->PN)
-                                               append_buf(buf, buflen, 
"%s%s%s",
-                                                               BLUE, 
HN(atom->PN), NORM);
-                               } else if (!strncmp("PV", fmt, len)) {
-                                       if (showit || atom->PV)
-                                               append_buf(buf, buflen, 
"%s%s%s",
-                                                               CYAN, 
HN(atom->PV), NORM);
-                               } else if (!strncmp("PVR", fmt, len)) {
-                                       if (showit || atom->PVR)
-                                               append_buf(buf, buflen, 
"%s%s%s",
-                                                               CYAN, 
HN(atom->PVR), NORM);
-                               } else if (!strncmp("PF", fmt, len)) {
-                                       append_buf(buf, buflen, "%s%s%s", BLUE, 
atom->PN, NORM);
-                                       if (atom->PV)
-                                               append_buf(buf, buflen, 
"%s-%s%s",
-                                                               CYAN, 
atom->PVR, NORM);
-                               } else if (!strncmp("PR", fmt, len)) {
-                                       if (showit || atom->PR_int)
-                                               append_buf(buf, buflen, 
"%sr%d%s",
-                                                               CYAN, 
atom->PR_int, NORM);
-                               } else if (!strncmp("SLOT", fmt, len)) {
-                                       if (showit || atom->SLOT)
-                                               append_buf(buf, buflen, 
"%s%s%s%s",
-                                                               YELLOW,
-                                                               connected ? ":" 
: "",
-                                                               HN(atom->SLOT),
-                                                               NORM);
-                               } else if (!strncmp("SUBSLOT", fmt, len)) {
-                                       if (showit ||
-                                                       (atom->SUBSLOT && 
atom->SUBSLOT != atom->SLOT))
-                                               append_buf(buf, buflen, 
"%s%s%s%s%s",
-                                                               YELLOW,
-                                                               connected ? "/" 
: "",
-                                                               
HN(atom->SUBSLOT),
-                                                               
atom_slotdep_str[atom->slotdep],
-                                                               NORM);
-                               } else if (!strncmp("REPO", fmt, len)) {
-                                       if (showit || atom->REPO)
-                                               append_buf(buf, buflen, 
"%s%s%s%s",
-                                                               GREEN, 
connected ? "::" : "",
-                                                               HN(atom->REPO), 
NORM);
-                               } else if (!strncmp("pfx", fmt, len)) {
-                                       if (showit || atom->pfx_op != 
ATOM_OP_NONE)
-                                               append_buf(buf, buflen, "%s",
-                                                               atom->pfx_op == 
ATOM_OP_NONE ?
-                                                               "<unset>" : 
atom_op_str[atom->pfx_op]);
-                               } else if (!strncmp("sfx", fmt, len)) {
-                                       if (showit || atom->sfx_op != 
ATOM_OP_NONE)
-                                               append_buf(buf, buflen, "%s",
-                                                               atom->sfx_op == 
ATOM_OP_NONE ?
-                                                               "<unset>" : 
atom_op_str[atom->sfx_op]);
-                               } else if (!strncmp("USE", fmt, len)) {
-                                       if (showit || atom->usedeps) {
-                                               atom_usedep *ud;
-                                               if (atom->usedeps == NULL) {
-                                                       append_buf(buf, buflen, 
"%s", "<unset>");
-                                               } else {
-                                                       if (connected)
-                                                               append_buf(buf, 
buflen, "%s", "[");
-                                                       for (ud = 
atom->usedeps; ud != NULL; ud = ud->next)
-                                                               append_buf(buf, 
buflen, "%s%s%s%s%s%s",
-                                                                               
MAGENTA, atom_usecond_str[ud->pfx_cond],
-                                                                               
ud->use, atom_usecond_str[ud->sfx_cond],
-                                                                               
NORM, ud->next == NULL ? "" :
-                                                                               
(connected ? "," : " "));
-                                                       if (connected)
-                                                               append_buf(buf, 
buflen, "%s", "]");
-                                               }
-                                       }
-                               } else if (strncmp("BUILDID", fmt, len) == 0) {
-                                       if (showit || atom->BUILDID > 0) {
-                                               /* this is really shitty, '-' 
is not feasible,
-                                                * but used by Portage
-                                                * 
https://archives.gentoo.org/gentoo-portage-dev/message/054f5f1f334b60bdb1b7f80ff4755bd4
-                                                * using this we cannot parse 
what we would
-                                                * produce, but look more like 
the original
-                                                * since it's not clear this is 
necessary at
-                                                * all, I decided to avoid any 
confusion and use
-                                                * '~' so we can see this is 
not a version bit */
-                                               append_buf(buf, buflen, 
"%s%s%u%s",
-                                                                  RED, 
connected ? "~" : "",
-                                                                  
atom->BUILDID, NORM);
-                                       }
-                               } else
-                                       append_buf(buf, buflen, "<BAD:%.*s>", 
(int)len, fmt);
-                               p++;
+        if (strncmp("CATEGORY", fmt, len) == 0)
+        {
+          connected = (p[1] == '%') & (bracket == '[');
+          if (showit ||
+              a->CATEGORY)
+            append_buf(buf, buflen, "%s%s%s%s",
+                       BOLD, HN(a->CATEGORY),
+                       connected ? "/" : "", NORM);
+        }
+        else if (strncmp("P", fmt, len) == 0)
+        {
+          if (showit ||
+              a->P)
+            append_buf(buf, buflen, "%s%s%s",
+                       BLUE, HN(a->P), NORM);
+        }
+        else if (strncmp("PN", fmt, len) == 0)
+        {
+          if (showit ||
+              a->PN)
+            append_buf(buf, buflen, "%s%s%s",
+                       BLUE, HN(a->PN), NORM);
+        }
+        else if (strncmp("PV", fmt, len) == 0)
+        {
+          if (showit ||
+              a->PV)
+            append_buf(buf, buflen, "%s%s%s",
+                       CYAN, HN(a->PV), NORM);
+        }
+        else if (strncmp("PVR", fmt, len) == 0)
+        {
+          if (showit ||
+              a->PVR)
+            append_buf(buf, buflen, "%s%s%s",
+                       CYAN, HN(a->PVR), NORM);
+        }
+        else if (strncmp("PF", fmt, len) == 0)
+        {
+          append_buf(buf, buflen, "%s%s%s", BLUE, a->PN, NORM);
+          if (a->PV)
+            append_buf(buf, buflen, "%s-%s%s",
+                       CYAN, a->PVR, NORM);
+        }
+        else if (strncmp("PR", fmt, len) == 0)
+        {
+          if (showit ||
+              a->PR_int)
+            append_buf(buf, buflen, "%sr%d%s",
+                       CYAN, a->PR_int, NORM);
+        }
+        else if (strncmp("SLOT", fmt, len) == 0)
+        {
+          if (showit ||
+              a->SLOT)
+            append_buf(buf, buflen, "%s%s%s%s",
+                       YELLOW,
+                       connected ? ":" : "",
+                       HN(a->SLOT),
+                       NORM);
+        }
+        else if (strncmp("SUBSLOT", fmt, len) == 0)
+        {
+          if (showit ||
+              (a->SUBSLOT &&
+               a->SUBSLOT != a->SLOT))
+            append_buf(buf, buflen, "%s%s%s%s%s",
+                       YELLOW,
+                       connected ? "/" : "",
+                       HN(a->SUBSLOT),
+                       atom_slotdep_str[a->slotdep],
+                       NORM);
+        }
+        else if (strncmp("REPO", fmt, len) == 0)
+        {
+          if (showit ||
+              a->REPO)
+            append_buf(buf, buflen, "%s%s%s%s",
+                       GREEN, connected ? "::" : "",
+                       HN(a->REPO), NORM);
+        }
+        else if (strncmp("pfx", fmt, len) == 0)
+        {
+          if (showit ||
+              a->pfx_op != ATOM_OP_NONE)
+            append_buf(buf, buflen, "%s",
+                       a->pfx_op == ATOM_OP_NONE ?
+                       "<unset>" : atom_op_str[a->pfx_op]);
+        }
+        else if (strncmp("sfx", fmt, len) == 0)
+        {
+          if (showit ||
+              a->sfx_op != ATOM_OP_NONE)
+            append_buf(buf, buflen, "%s",
+                       a->sfx_op == ATOM_OP_NONE ?
+                       "<unset>" : atom_op_str[a->sfx_op]);
+        }
+        else if (strncmp("USE", fmt, len) == 0)
+        {
+          if (showit ||
+              a->usedeps)
+          {
+            atom_usedep *ud;
+            if (a->usedeps == NULL)
+            {
+              append_buf(buf, buflen, "%s", "<unset>");
+            }
+            else
+            {
+              if (connected)
+                append_buf(buf, buflen, "%s", "[");
+              for (ud = a->usedeps; ud != NULL; ud = ud->next)
+                append_buf(buf, buflen, "%s%s%s%s%s%s",
+                           MAGENTA, atom_usecond_str[ud->pfx_cond],
+                           ud->use, atom_usecond_str[ud->sfx_cond],
+                           NORM, ud->next == NULL ? "" :
+                           (connected ? "," : " "));
+              if (connected)
+                append_buf(buf, buflen, "%s", "]");
+            }
+          }
+        }
+        else if (strncmp("BUILDID", fmt, len) == 0)
+        {
+          if (showit ||
+              a->BUILDID > 0)
+          {
+            /* this is really shitty, '-' is not feasible,
+             * but used by Portage
+             * 
https://archives.gentoo.org/gentoo-portage-dev/message/054f5f1f334b60bdb1b7f80ff4755bd4
+             * using this we cannot parse what we would
+             * produce, but look more like the original
+             * since it's not clear this is necessary at
+             * all, I decided to avoid any confusion and use
+             * '~' so we can see this is not a version bit */
+            append_buf(buf, buflen, "%s%s%u%s",
+                       RED, connected ? "~" : "",
+                       a->BUILDID, NORM);
+          }
+        }
+        else
+        {
+          append_buf(buf, buflen, "<BAD:%.*s>", (int)len, fmt);
+        }
+        p++;
 #undef HN
-                       } else {
-                               p = fmt + 1;
-                       }
-               } else {
-                       p++;
-               }
-       }
+      }
+      else
+      {
+        p = fmt + 1;
+      }
+    }
+    else
+    {
+      p++;
+    }
+  }
 #undef append_buf
 
-       return ret;
+  return ret;
 }
 
 /* versions that use an internal buffer, which is suitable for most
  * scenarios */
 static char _atom_buf[BUFSIZ];
-char *
-atom_to_string(depend_atom *a)
+char *atom_to_string
+(
+  atom_ctx *a
+)
 {
-       return atom_to_string_r(_atom_buf, sizeof(_atom_buf), a);
+  return atom_to_string_r(_atom_buf, sizeof(_atom_buf), a);
 }
 
-char *
-atom_format(const char *format, const depend_atom *atom)
+char *atom_format
+(
+  const char     *format,
+  const atom_ctx *a
+)
 {
-       return atom_format_r(_atom_buf, sizeof(_atom_buf), format, atom);
+  return atom_format_r(_atom_buf, sizeof(_atom_buf), format, a);
 }
 
 /* qsort compatible callback function */
-inline int
-atom_compar_cb(const void *l, const void *r)
+inline int atom_compar_cb
+(
+  const void *l,
+  const void *r
+)
 {
-       const depend_atom *al = *(const depend_atom**)l;
-       const depend_atom *ar = *(const depend_atom**)r;
-
-       switch (atom_compare(al, ar)) {
-               case EQUAL:  return  0;
-               case NEWER:  return -1;
-               case OLDER:  return  1;
-               default:
-               {
-                       int ret;
-                       if (!al->CATEGORY && !ar->CATEGORY) {
-                               ret = 0;
-                       } else if (!al->CATEGORY) {
-                               ret = -1;
-                       } else if (!ar->CATEGORY) {
-                               ret = 1;
-                       } else {
-                               ret = strcmp(al->CATEGORY, ar->CATEGORY);
-                       }
-                       if (ret == 0)
-                               ret = strcasecmp(al->PN, ar->PN);
-                       return ret;
-               }
-       }
-
-       /* unreachable */
+  const atom_ctx *al = *(const atom_ctx **)l;
+  const atom_ctx *ar = *(const atom_ctx **)r;
+
+  switch (atom_compare(al, ar))
+  {
+  case EQUAL:  return  0;
+  case NEWER:  return -1;
+  case OLDER:  return  1;
+  case NOT_EQUAL:
+  default:
+    {
+      int ret;
+      if (!al->CATEGORY &&
+          !ar->CATEGORY)
+      {
+        ret = 0;
+      }
+      else if (!al->CATEGORY)
+      {
+        ret = -1;
+      }
+      else if (!ar->CATEGORY)
+      {
+        ret = 1;
+      }
+      else
+      {
+        ret = strcmp(al->CATEGORY, ar->CATEGORY);
+      }
+      if (ret == 0)
+        ret = strcmp(al->PN, ar->PN);
+      return ret;
+    }
+  }
+
+  /* unreachable */
 }
+
+/* vim: set ts=2 sw=2 expandtab cino+=\:0 foldmethod=marker: */

diff --git a/libq/atom.h b/libq/atom.h
index fcfa0bd..d25a754 100644
--- a/libq/atom.h
+++ b/libq/atom.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2022 Gentoo Foundation
+ * Copyright 2005-2026 Gentoo Foundation
  * Distributed under the terms of the GNU General Public License v2
  *
  * Copyright 2005-2008 Ned Ludd        - <[email protected]>
@@ -11,90 +11,97 @@
 #define _ATOM_COMPARE_H 1
 
 typedef enum {
-       VER_ALPHA=0, VER_BETA, VER_PRE, VER_RC, VER_NORM, VER_P
+  VER_ALPHA = 1,
+  VER_BETA,
+  VER_PRE,
+  VER_RC,
+  VER_NORM,
+  VER_P
 } atom_suffixes;
 extern const char * const atom_suffixes_str[];
 
 /* slotdeps, := :* :SLOT= */
 typedef enum {
-       /*   */ ATOM_SD_NONE = 0,
-       /* = */ ATOM_SD_ANY_REBUILD,
-       /* * */ ATOM_SD_ANY_IGNORE,
+  /*   */ ATOM_SD_NONE = 0,
+  /* = */ ATOM_SD_ANY_REBUILD,
+  /* * */ ATOM_SD_ANY_IGNORE,
 } atom_slotdep;
 extern const char * const atom_slotdep_str[];
 
 typedef enum {
-       /*     */ ATOM_UC_NONE = 0,
-       /* !   */ ATOM_UC_NOT,
-       /* -   */ ATOM_UC_NEG,
-       /* ?   */ ATOM_UC_COND,
-       /* =   */ ATOM_UC_EQUAL,
-       /* (+) */ ATOM_UC_PREV_ENABLED,
-       /* (-) */ ATOM_UC_PREV_DISABLED,
+  /*     */ ATOM_UC_NONE = 0,
+  /* !   */ ATOM_UC_NOT,
+  /* -   */ ATOM_UC_NEG,
+  /* ?   */ ATOM_UC_COND,
+  /* =   */ ATOM_UC_EQUAL,
+  /* (+) */ ATOM_UC_PREV_ENABLED,
+  /* (-) */ ATOM_UC_PREV_DISABLED,
 } atom_usecond;
 extern const char * const atom_usecond_str[];
 
 typedef enum {
-       /*    */ ATOM_BL_NONE = 0,
-       /* !  */ ATOM_BL_BLOCK,
-       /* !! */ ATOM_BL_BLOCK_HARD,
-       /* ^  */ ATOM_BL_ANTISLOT,
+  /*    */ ATOM_BL_NONE = 0,
+  /* !  */ ATOM_BL_BLOCK,
+  /* !! */ ATOM_BL_BLOCK_HARD,
+  /* ^  */ ATOM_BL_ANTISLOT,
 } atom_blocker;
 extern const char * const atom_blocker_str[];
 
 typedef enum {
-       /*    */ ATOM_OP_NONE = 0,
-       /* =  */ ATOM_OP_EQUAL,
-       /* >  */ ATOM_OP_NEWER,
-       /* >= */ ATOM_OP_NEWER_EQUAL,
-       /* <  */ ATOM_OP_OLDER,
-       /* <= */ ATOM_OP_OLDER_EQUAL,
-       /* ~  */ ATOM_OP_PV_EQUAL,
-       /* *  */ ATOM_OP_STAR,
-       /*    */ ATOM_OP_NEQUAL,
+  /*    */ ATOM_OP_NONE = 0,
+  /* =  */ ATOM_OP_EQUAL,
+  /* >  */ ATOM_OP_NEWER,
+  /* >= */ ATOM_OP_NEWER_EQUAL,
+  /* <  */ ATOM_OP_OLDER,
+  /* <= */ ATOM_OP_OLDER_EQUAL,
+  /* ~  */ ATOM_OP_PV_EQUAL,
+  /* *  */ ATOM_OP_STAR,
+  /*    */ ATOM_OP_NEQUAL,
 } atom_operator;
 extern const char * const atom_op_str[];
 
 typedef struct {
-       atom_suffixes suffix;
-       uint64_t sint;
+  atom_suffixes suffix;
+  uint64_t sint;
 } atom_suffix;
 
 typedef struct _atom_usedep {
-       struct _atom_usedep *next;
-       char *use;
-       atom_usecond pfx_cond;
-       atom_usecond sfx_cond;
+  struct _atom_usedep *next;
+  char *use;
+  atom_usecond pfx_cond;
+  atom_usecond sfx_cond;
 } atom_usedep;
 
 typedef struct {
-       atom_blocker  blocker;
-       atom_operator pfx_op;
-       atom_operator sfx_op;
-       char         *CATEGORY;
-       char         *PN;
-       char         *PV;
-       char         *PF;
-       unsigned int  PR_int;
-       char          letter;
-       atom_suffix  *suffixes;
-       char         *PVR;
-       char         *P;
-       atom_usedep  *usedeps;
-       char         *SLOT;
-       char         *SUBSLOT;
-       atom_slotdep  slotdep;
-       char         *REPO;
-       unsigned int  BUILDID;
-} depend_atom;
+  atom_blocker  blocker;
+  atom_operator pfx_op;
+  atom_operator sfx_op;
+  char         *CATEGORY;
+  char         *PN;
+  char         *PV;
+  char         *PF;
+  unsigned int  PR_int;
+  char          letter;
+  atom_suffix  *suffixes;
+  char         *PVR;
+  char         *P;
+  atom_usedep  *usedeps;
+  char         *SLOT;
+  char         *SUBSLOT;
+  atom_slotdep  slotdep;
+  char         *REPO;
+  unsigned int  BUILDID;
+} atom_ctx;
+/* backwards compat definition */
+typedef atom_ctx depend_atom;
 
 extern const char * const booga[];
 typedef enum {
-       ERROR = 0,
-       NOT_EQUAL,
-       EQUAL,
-       NEWER,
-       OLDER
+  ERROR = 0,
+  NOT_EQUAL,
+  EQUAL,
+  NEWER,
+  OLDER
 } atom_equality;
 
 /* bitflags to control compare behaviour */
@@ -104,18 +111,20 @@ typedef enum {
 #define ATOM_COMP_NOSUBSLOT  (1<<2)
 #define ATOM_COMP_NOREPO     (1<<3)
 
-depend_atom *atom_explode_cat(const char *atom, const char *cat);
+atom_ctx *atom_explode_cat(const char *atom, const char *cat);
 #define atom_explode(A) atom_explode_cat(A, NULL)
-depend_atom *atom_clone(depend_atom *atom);
-void atom_implode(depend_atom *atom);
-atom_equality atom_compare_flg(const depend_atom *a1, const depend_atom *a2, 
int flags);
-#define atom_compare(A,B) atom_compare_flg(A, B, ATOM_COMP_DEFAULT)
-atom_equality atom_compare_str(const char * const s1, const char * const s2);
-char *atom_to_string_r(char *buf, size_t buflen, depend_atom *a);
+atom_ctx *atom_clone(atom_ctx *atom);
+void atom_implode(atom_ctx *atom);
+atom_equality atom_compare_flg(const atom_ctx *d, const atom_ctx *q, int 
flags);
+#define atom_compare(D,Q) atom_compare_flg(D, Q, ATOM_COMP_DEFAULT)
+atom_equality atom_compare_str(const char * const d, const char * const q);
+char *atom_to_string_r(char *buf, size_t buflen, atom_ctx *a);
 char *atom_format_r(char *buf, size_t buflen,
-               const char *format, const depend_atom *atom);
-char *atom_to_string(depend_atom *a);
-char *atom_format(const char *format, const depend_atom *atom);
+                    const char *format, const atom_ctx *atom);
+char *atom_to_string(atom_ctx *a);
+char *atom_format(const char *format, const atom_ctx *atom);
 int atom_compar_cb(const void *l, const void *r);
 
 #endif
+
+/* vim: set ts=2 sw=2 expandtab cino+=\:0 foldmethod=marker: */

Reply via email to