commit: c6537da04a6695656d655bf4e48813fb041ec010 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> AuthorDate: Wed Jan 1 12:50:18 2020 +0000 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> CommitDate: Wed Jan 1 12:50:18 2020 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c6537da0
libq/atom: stick to PMS for PVR rework allocations somewhat, and make sure PVR does NOT include -r0, in addition add PF to the structure, so this one can be grabbed more easily Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> TODO.md | 9 +-- libq/atom.c | 149 ++++++++++++++++++++++++++-------------------- libq/atom.h | 1 + tests/atom_explode/test.c | 22 +++++-- 4 files changed, 107 insertions(+), 74 deletions(-) diff --git a/TODO.md b/TODO.md index dffaa91..cd4f2b2 100644 --- a/TODO.md +++ b/TODO.md @@ -22,13 +22,8 @@ - replace all strtok by strtok\_r, because the latter is already used, so we can -# Atoms - -- only 32bit values are supported for revision (-r#) -- only 64bit values are supported in any individual version component - foo-(1234)\_alpha(56789) -- these limits should not be an issue for all practical purposes -- make PVR match PMS https://dev.gentoo.org/~ulm/pms/head/pms.html#x1-10800011 +- parse package.accept\_keywords such that we can provide the latest + "available" version like Portage # qmerge diff --git a/libq/atom.c b/libq/atom.c index 05b138c..6f70847 100644 --- a/libq/atom.c +++ b/libq/atom.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 Gentoo Foundation + * Copyright 2005-2020 Gentoo Foundation * Distributed under the terms of the GNU General Public License v2 * * Copyright 2005-2008 Ned Ludd - <so...@gentoo.org> @@ -39,6 +39,9 @@ const char * const atom_op_str[] = { 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(const char *atom) { @@ -48,18 +51,33 @@ atom_explode(const char *atom) size_t slen; size_t idx; size_t sidx; - - /* we allocate mem for atom struct and two strings (strlen(atom)). - * the first string is for CAT/PN/PV while the second is for PVR. - * PVR needs 3 extra bytes for possible implicit '-r0'. */ - slen = strlen(atom); - len = sizeof(*ret) + (slen + 1) * sizeof(*atom) * 3 + 3; + 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 = sizeof(*ret) + (slen * 3); ret = xmalloc(len); memset(ret, '\0', sizeof(*ret)); - ptr = (char *)ret; - ret->P = ptr + sizeof(*ret); - ret->PVR = ret->P + slen + 1; - ret->CATEGORY = ret->PVR + slen + 1 + 3; + + /* assign pointers to the three storage containers */ + ret->CATEGORY = (char *)ret + sizeof(*ret); /* 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; @@ -95,13 +113,15 @@ atom_explode(const char *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 = '\0'; - /* chip off the trailing [::REPO] as needed */ + /* chip off the trailing ::REPO as needed */ if ((ptr = strstr(ret->CATEGORY, "::")) != NULL) { ret->REPO = ptr + 2; *ptr = '\0'; @@ -172,7 +192,7 @@ atom_explode(const char *atom) *ptr++ = '\0'; } - /* chip off the trailing [:SLOT] as needed */ + /* chip off the trailing :SLOT as needed */ if ((ptr = strrchr(ret->CATEGORY, ':')) != NULL) { *ptr++ = '\0'; ret->SLOT = ptr; @@ -205,14 +225,14 @@ atom_explode(const char *atom) *ptr = '\0'; } - /* break up the CATEGORY and PVR */ + /* break up the CATEGORY, PF and PVR */ if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) { - ret->PN = ptr + 1; - *ptr = '\0'; + *ptr++ = '\0'; + ret->PF = ptr; /* set PN to NULL if there's nothing */ - if (ret->PN[0] == '\0') - ret->PN = NULL; + 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 @@ -220,75 +240,81 @@ atom_explode(const char *atom) if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) ret->CATEGORY = ptr + 1; } else { - ret->PN = ret->CATEGORY; + ret->PF = ret->CATEGORY; ret->CATEGORY = NULL; } - if (ret->PN == NULL) { + if (ret->PF == NULL) { /* atom has no name, this is it */ ret->P = NULL; + ret->PN = NULL; ret->PVR = NULL; + return ret; } - /* CATEGORY should be all set here, PN contains everything up to + /* CATEGORY should be all set here, PF contains everything up to * SLOT, REPO or '*' - * PN must not end in a hyphen followed by anything matching version - * syntax, 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->PN; - { - char *lastpv = NULL; - char *pv; - - while ((ptr = strchr(ptr, '-')) != NULL) { - ptr++; - if (!isdigit(*ptr)) - continue; + * 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'; + /* 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 */ } - ptr = lastpv; + ret->letter = '\0'; } + ptr = lastpv; if (ptr == NULL) { /* atom has no version, this is it */ - strcpy(ret->P, ret->PN); - ret->PVR = NULL; + ret->P = ret->PN = ret->PF; + ret->PV = ret->PVR = NULL; + return ret; } - ret->PV = ptr; + + ret->PVR = ptr; + snprintf(ret->PN, slen, "%.*s", (int)(ret->PVR - 1 - ret->PF), ret->PF); /* find -r# */ - ptr = ret->PV + strlen(ret->PV) - 1; - while (*ptr && ptr > ret->PV) { - if (!isdigit(*ptr)) { + 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); - ptr[-1] = '\0'; + pv = &ptr[-1]; } break; } ptr--; } - strcpy(ret->P, ret->PN); - ret->PV[-1] = '\0'; + 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; @@ -325,9 +351,6 @@ atom_explode(const char *atom) ret->suffixes[idx] = t; } - /* size is malloced above with the required space in mind */ - sprintf(ret->PVR, "%s-r%i", ret->PV, ret->PR_int); - return ret; } diff --git a/libq/atom.h b/libq/atom.h index a5175b0..1548dd9 100644 --- a/libq/atom.h +++ b/libq/atom.h @@ -74,6 +74,7 @@ typedef struct { char *CATEGORY; char *PN; char *PV; + char *PF; unsigned int PR_int; char letter; atom_suffix *suffixes; diff --git a/tests/atom_explode/test.c b/tests/atom_explode/test.c index 21a5f1d..b794d3b 100644 --- a/tests/atom_explode/test.c +++ b/tests/atom_explode/test.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 Gentoo Foundation + * Copyright 2005-2020 Gentoo Foundation * Distributed under the terms of the GNU General Public License v2 * * Copyright 2005-2008 Ned Ludd - <so...@gentoo.org> @@ -19,9 +19,23 @@ FILE *warnout; static inline void boom(depend_atom *a, char *s) { - printf("%s -> %s / [%s] %s - %s [%s] [r%i]\n", - s, (a->CATEGORY?:"null"), a->P, a->PN, - a->PVR, a->PV, a->PR_int); + /* python code: + * CATEGORY = cpv[0] + * PN = cpv[1] + * PV = cpv[2] + * PR_int = cpv[3] + * P = PN + "-" + PV + * PVR = PV + "-" + cpv[3] + * print(a+" -> "+CATEGORY+" / ["+P+"] "+PN+" - "+PVR+" ["+PV+"] ["+PR_int+"]") + * this most notably doesn't test PVR in compliance with PMS */ + printf("%s -> %s / [%s] %s - %s%s [%s] [r%i]\n", + s, + (a->CATEGORY ? a->CATEGORY : "null"), + a->P, + a->PN, + a->PVR, (a->PVR != NULL && a->PR_int == 0) ? "-r0" : "", + a->PV, + a->PR_int); } int main(int argc, char *argv[])