aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'libq/atom.c')
-rw-r--r--libq/atom.c338
1 files changed, 207 insertions, 131 deletions
diff --git a/libq/atom.c b/libq/atom.c
index 8b1b47a3..12a393a3 100644
--- a/libq/atom.c
+++ b/libq/atom.c
@@ -30,7 +30,7 @@ const char * const atom_usecond_str[] = {
};
const char * const atom_blocker_str[] = {
- "", "!", "!!"
+ "", "!", "!!", "^"
};
const char * const atom_op_str[] = {
@@ -65,9 +65,12 @@ atom_explode(const char *atom)
if (*atom == '!') {
ret->blocker++;
atom++;
- }
- if (*atom == '!') {
- ret->blocker++;
+ if (*atom == '!') {
+ ret->blocker++;
+ atom++;
+ }
+ } else if (*atom == '^') {
+ ret->blocker = ATOM_BL_ANTISLOT;
atom++;
}
@@ -101,65 +104,14 @@ atom_explode(const char *atom)
if ((ptr = strstr(ret->CATEGORY, "::")) != NULL) {
ret->REPO = ptr + 2;
*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';
- ret->SUBSLOT = ptr;
- }
- }
-
- /* 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 and PVR */
- if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) {
- ret->PN = ptr + 1;
- *ptr = '\0';
-
- /* set PN to NULL if there's nothing */
- if (ret->PN[0] == '\0')
- ret->PN = 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->PN = ret->CATEGORY;
- ret->CATEGORY = NULL;
- }
-
- if (ret->PN == NULL) {
- /* atom has no name, this is it */
- ret->P = NULL;
- ret->PVR = NULL;
- return ret;
+ /* 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->PN, ']')) != NULL && ptr[1] == '\0' &&
- (ptr = strrchr(ret->PN, '[')) != NULL)
+ if ((ptr = strrchr(ret->CATEGORY, ']')) != NULL && ptr[1] == '\0' &&
+ (ptr = strrchr(ret->CATEGORY, '[')) != NULL)
{
atom_usedep *w = NULL;
do {
@@ -219,6 +171,65 @@ atom_explode(const char *atom)
*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;
+ }
+
+ /* 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 and PVR */
+ if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) {
+ ret->PN = ptr + 1;
+ *ptr = '\0';
+
+ /* set PN to NULL if there's nothing */
+ if (ret->PN[0] == '\0')
+ ret->PN = 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->PN = ret->CATEGORY;
+ ret->CATEGORY = NULL;
+ }
+
+ if (ret->PN == NULL) {
+ /* atom has no name, this is it */
+ ret->P = NULL;
+ ret->PVR = NULL;
+ return ret;
+ }
+
/* CATEGORY should be all set here, PN contains everything up to
* SLOT, REPO or '*'
* PN must not end in a hyphen followed by anything matching version
@@ -360,30 +371,93 @@ _atom_compare_match(int ret, atom_operator op)
* foo-1 <NOT_EQUAL> bar-1
*/
int
-atom_compare(const depend_atom *a1, const depend_atom *a2)
+atom_compare(const depend_atom *data, const depend_atom *query)
{
- /* sanity check that at most one has operators */
- if (a1->pfx_op != ATOM_OP_NONE ||
- a1->sfx_op != ATOM_OP_NONE ||
- a1->blocker != ATOM_BL_NONE)
- {
- /* is the other also having operators, then punt it */
- if (a2->pfx_op != ATOM_OP_NONE ||
- a2->sfx_op != ATOM_OP_NONE ||
- a2->blocker != ATOM_BL_NONE)
+ 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) {
+ /* ^perl -> match anything with a SLOT */
+ if (query->SLOT == NULL && data->SLOT == NULL)
return NOT_EQUAL;
-
- /* swap a1 & a2 so that a2 is the atom with operators */
- const depend_atom *as = a2;
- a2 = a1;
- a1 = as;
+ if (query->SLOT != NULL) {
+ if (query->SUBSLOT == NULL) {
+ /* ^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 (data->SUBSLOT == NULL ||
+ strcmp(query->SUBSLOT, data->SUBSLOT) == 0)
+ return NOT_EQUAL;
+ }
+ }
+ bl_op = ATOM_BL_NONE; /* ease work below */
+ } else if (query->SLOT != NULL) {
+ /* 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 (query->SUBSLOT != NULL) {
+ if (data->SUBSLOT == NULL) {
+ 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;
+ }
+ }
+ }
+ }
+ }
}
- atom_operator pfx_op = a2->pfx_op;
- atom_operator sfx_op = a2->sfx_op;
-
/* handle the inversing effect of blockers */
- if (a2->blocker != ATOM_BL_NONE) {
+ 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;
@@ -405,60 +479,62 @@ atom_compare(const depend_atom *a1, const depend_atom *a2)
}
}
- /* check slot only when both sides have it */
- if (a1->SLOT != NULL && a2->SLOT != NULL &&
- a1->SLOT[0] != '\0' && a2->SLOT[0] != '\0' &&
- (strcmp(a1->SLOT, a2->SLOT) != 0 ||
- (a1->SUBSLOT != NULL && a2->SUBSLOT != NULL &&
- strcmp(a1->SUBSLOT, a2->SUBSLOT) != 0)))
- return NOT_EQUAL;
-
- /* same for check repo */
- if (a1->REPO != NULL && a2->REPO != NULL &&
- a1->REPO[0] != '\0' && a2->REPO[0] != '\0' &&
- strcmp(a1->REPO, a2->REPO) != 0)
- return NOT_EQUAL;
+ /* check REPO, if query has it, ignore blocker stuff for this one */
+ if (query->REPO != NULL) {
+ if (data->REPO == NULL)
+ return NOT_EQUAL;
+ if (strcmp(query->REPO, data->REPO) != 0)
+ return NOT_EQUAL;
+ }
- /* Check category, iff both are specified. This way we can match
- * atoms like "sys-devel/gcc" and "gcc". */
- if (a1->CATEGORY && a2->CATEGORY) {
- if (strcmp(a1->CATEGORY, a2->CATEGORY))
+ /* 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 name */
- if (a1->PN && a2->PN) {
- if (strcmp(a1->PN, a2->PN))
+ /* check PN, this may be absent if query is for CATEGORY only */
+ if (query->PN != NULL) {
+ if (data->PN == NULL)
return NOT_EQUAL;
- } else if (a1->CATEGORY && a2->CATEGORY) {
- /* if CAT is set, and one side has empty PN, accept as match */
- return a2->blocker != ATOM_BL_NONE ? NOT_EQUAL : EQUAL;
- } else if (a1->PN || a2->PN)
- 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
- */
- unsigned int ver_bits = 0;
+ * version elements provided in it ahead of time */
+ ver_bits = 0;
if (sfx_op == ATOM_OP_STAR) {
- if (a2->letter)
+ if (query->letter)
ver_bits |= (1 << 0);
- if (a2->suffixes[0].suffix != VER_NORM)
+ if (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 (a2->PR_int)
+ * doesn't ever show up in practice, so who cares. */
+ if (query->PR_int)
ver_bits |= (1 << 2);
}
/* check version */
- if (a1->PV && a2->PV) {
+ if (data->PV && query->PV) {
char *s1, *s2;
uint64_t n1, n2;
/* first we compare the version [1.0]z_alpha1 */
- s1 = a1->PV;
- s2 = a2->PV;
+ s1 = data->PV;
+ s2 = query->PV;
while (s1 || s2) {
if (s1 && s2) {
/* deal with leading zeros */
@@ -491,16 +567,16 @@ atom_compare(const depend_atom *a1, const depend_atom *a2)
/* compare trailing letter 1.0[z]_alpha1 */
if (sfx_op == ATOM_OP_STAR) {
ver_bits >>= 1;
- if (!a2->letter && !ver_bits)
+ if (!query->letter && !ver_bits)
return _atom_compare_match(EQUAL, pfx_op);
}
- if (a1->letter < a2->letter)
+ if (data->letter < query->letter)
return _atom_compare_match(OLDER, pfx_op);
- if (a1->letter > a2->letter)
+ if (data->letter > query->letter)
return _atom_compare_match(NEWER, pfx_op);
/* find differing suffixes 1.0z[_alpha1] */
- const atom_suffix *as1 = &a1->suffixes[0];
- const atom_suffix *as2 = &a2->suffixes[0];
+ const atom_suffix *as1 = &data->suffixes[0];
+ const atom_suffix *as2 = &query->suffixes[0];
while (as1->suffix == as2->suffix) {
if (as1->suffix == VER_NORM ||
as2->suffix == VER_NORM)
@@ -509,8 +585,8 @@ atom_compare(const depend_atom *a1, const depend_atom *a2)
if (as1->sint != as2->sint)
break;
- ++as1;
- ++as2;
+ as1++;
+ as2++;
}
/* compare suffixes 1.0z[_alpha]1 */
if (sfx_op == ATOM_OP_STAR) {
@@ -530,15 +606,15 @@ atom_compare(const depend_atom *a1, const depend_atom *a2)
else if (as1->sint > as2->sint)
return _atom_compare_match(NEWER, pfx_op);
/* fall through to -r# check below */
- } else if (a1->PV || a2->PV)
+ } else if (data->PV || query->PV)
return EQUAL;
/* Make sure the -r# is the same. */
- if ((sfx_op == ATOM_OP_STAR && !a2->PR_int) ||
+ if ((sfx_op == ATOM_OP_STAR && !query->PR_int) ||
pfx_op == ATOM_OP_PV_EQUAL ||
- a1->PR_int == a2->PR_int)
+ data->PR_int == query->PR_int)
return _atom_compare_match(EQUAL, pfx_op);
- else if (a1->PR_int < a2->PR_int)
+ else if (data->PR_int < query->PR_int)
return _atom_compare_match(OLDER, pfx_op);
else
return _atom_compare_match(NEWER, pfx_op);
@@ -586,6 +662,11 @@ atom_to_string_r(char *buf, size_t buflen, depend_atom *a)
if (a->PR_int > 0)
off += snprintf(buf + off, buflen - off, "-r%d", a->PR_int);
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->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 ? "[" : "",
@@ -593,11 +674,6 @@ atom_to_string_r(char *buf, size_t buflen, depend_atom *a)
ud->use,
atom_usecond_str[ud->sfx_cond],
ud->next == NULL ? "]" : ",");
- if (a->SLOT != NULL)
- off += snprintf(buf + off, buflen - off, ":%s%s%s%s",
- a->SLOT,
- a->SUBSLOT ? "/" : "", a->SUBSLOT ? a->SUBSLOT : "",
- atom_slotdep_str[a->slotdep]);
if (a->REPO != NULL)
off += snprintf(buf + off, buflen - off, "::%s", a->REPO);