1 |
commit: c6537da04a6695656d655bf4e48813fb041ec010 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Wed Jan 1 12:50:18 2020 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed Jan 1 12:50:18 2020 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c6537da0 |
7 |
|
8 |
libq/atom: stick to PMS for PVR |
9 |
|
10 |
rework allocations somewhat, and make sure PVR does NOT include -r0, in |
11 |
addition add PF to the structure, so this one can be grabbed more easily |
12 |
|
13 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
14 |
|
15 |
TODO.md | 9 +-- |
16 |
libq/atom.c | 149 ++++++++++++++++++++++++++-------------------- |
17 |
libq/atom.h | 1 + |
18 |
tests/atom_explode/test.c | 22 +++++-- |
19 |
4 files changed, 107 insertions(+), 74 deletions(-) |
20 |
|
21 |
diff --git a/TODO.md b/TODO.md |
22 |
index dffaa91..cd4f2b2 100644 |
23 |
--- a/TODO.md |
24 |
+++ b/TODO.md |
25 |
@@ -22,13 +22,8 @@ |
26 |
- replace all strtok by strtok\_r, because the latter is already used, |
27 |
so we can |
28 |
|
29 |
-# Atoms |
30 |
- |
31 |
-- only 32bit values are supported for revision (-r#) |
32 |
-- only 64bit values are supported in any individual version component |
33 |
- foo-(1234)\_alpha(56789) |
34 |
-- these limits should not be an issue for all practical purposes |
35 |
-- make PVR match PMS https://dev.gentoo.org/~ulm/pms/head/pms.html#x1-10800011 |
36 |
+- parse package.accept\_keywords such that we can provide the latest |
37 |
+ "available" version like Portage |
38 |
|
39 |
# qmerge |
40 |
|
41 |
|
42 |
diff --git a/libq/atom.c b/libq/atom.c |
43 |
index 05b138c..6f70847 100644 |
44 |
--- a/libq/atom.c |
45 |
+++ b/libq/atom.c |
46 |
@@ -1,5 +1,5 @@ |
47 |
/* |
48 |
- * Copyright 2005-2019 Gentoo Foundation |
49 |
+ * Copyright 2005-2020 Gentoo Foundation |
50 |
* Distributed under the terms of the GNU General Public License v2 |
51 |
* |
52 |
* Copyright 2005-2008 Ned Ludd - <solar@g.o> |
53 |
@@ -39,6 +39,9 @@ const char * const atom_op_str[] = { |
54 |
|
55 |
const char * const booga[] = {"!!!", "!=", "==", ">", "<"}; |
56 |
|
57 |
+/* split string into individual components, known as an atom |
58 |
+ * for a definition of which variable contains what, see: |
59 |
+ * https://dev.gentoo.org/~ulm/pms/head/pms.html#x1-10800011 */ |
60 |
depend_atom * |
61 |
atom_explode(const char *atom) |
62 |
{ |
63 |
@@ -48,18 +51,33 @@ atom_explode(const char *atom) |
64 |
size_t slen; |
65 |
size_t idx; |
66 |
size_t sidx; |
67 |
- |
68 |
- /* we allocate mem for atom struct and two strings (strlen(atom)). |
69 |
- * the first string is for CAT/PN/PV while the second is for PVR. |
70 |
- * PVR needs 3 extra bytes for possible implicit '-r0'. */ |
71 |
- slen = strlen(atom); |
72 |
- len = sizeof(*ret) + (slen + 1) * sizeof(*atom) * 3 + 3; |
73 |
+ char *lastpv = NULL; |
74 |
+ char *pv; |
75 |
+ |
76 |
+ /* PMS 11.1 recap: |
77 |
+ * CAT The package’s category app-editors |
78 |
+ * PF Package name, version, and revision (if any) vim-7.0.174-r1 |
79 |
+ * PVR Package version and revision (if any) 7.0.174-r1 |
80 |
+ * P Package name and version, without the revision part vim-7.0.174 |
81 |
+ * PV Package version, with no revision 7.0.174 |
82 |
+ * PN Package name vim |
83 |
+ * PR Package revision, or r0 if none exists r1 |
84 |
+ * |
85 |
+ * Thus, CAT/PF is the full allocation of the input string, for the |
86 |
+ * rest (P, PN, PV, PR, PVR) we need copies. We represent PR as an |
87 |
+ * integer, which leaves the set to PN, P and PV. |
88 |
+ * PVR is an offset inside PF, likewise, PV is an offset inside P. |
89 |
+ * We allocate memory for atom struct, one string for CAT/PF + PVR, |
90 |
+ * another to cover PN and a final one for P + PV. */ |
91 |
+ slen = strlen(atom) + 1; |
92 |
+ len = sizeof(*ret) + (slen * 3); |
93 |
ret = xmalloc(len); |
94 |
memset(ret, '\0', sizeof(*ret)); |
95 |
- ptr = (char *)ret; |
96 |
- ret->P = ptr + sizeof(*ret); |
97 |
- ret->PVR = ret->P + slen + 1; |
98 |
- ret->CATEGORY = ret->PVR + slen + 1 + 3; |
99 |
+ |
100 |
+ /* assign pointers to the three storage containers */ |
101 |
+ ret->CATEGORY = (char *)ret + sizeof(*ret); /* CAT PF PVR */ |
102 |
+ ret->P = ret->CATEGORY + slen; /* P PV */ |
103 |
+ ret->PN = ret->P + slen; /* PN */ |
104 |
|
105 |
/* check for blocker operators */ |
106 |
ret->blocker = ATOM_BL_NONE; |
107 |
@@ -95,13 +113,15 @@ atom_explode(const char *atom) |
108 |
ret->pfx_op += ATOM_OP_EQUAL; |
109 |
atom++; |
110 |
} |
111 |
+ |
112 |
+ /* fill in full block */ |
113 |
strcpy(ret->CATEGORY, atom); |
114 |
|
115 |
/* eat file name crap when given an (autocompleted) path */ |
116 |
if ((ptr = strstr(ret->CATEGORY, ".ebuild")) != NULL) |
117 |
*ptr = '\0'; |
118 |
|
119 |
- /* chip off the trailing [::REPO] as needed */ |
120 |
+ /* chip off the trailing ::REPO as needed */ |
121 |
if ((ptr = strstr(ret->CATEGORY, "::")) != NULL) { |
122 |
ret->REPO = ptr + 2; |
123 |
*ptr = '\0'; |
124 |
@@ -172,7 +192,7 @@ atom_explode(const char *atom) |
125 |
*ptr++ = '\0'; |
126 |
} |
127 |
|
128 |
- /* chip off the trailing [:SLOT] as needed */ |
129 |
+ /* chip off the trailing :SLOT as needed */ |
130 |
if ((ptr = strrchr(ret->CATEGORY, ':')) != NULL) { |
131 |
*ptr++ = '\0'; |
132 |
ret->SLOT = ptr; |
133 |
@@ -205,14 +225,14 @@ atom_explode(const char *atom) |
134 |
*ptr = '\0'; |
135 |
} |
136 |
|
137 |
- /* break up the CATEGORY and PVR */ |
138 |
+ /* break up the CATEGORY, PF and PVR */ |
139 |
if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) { |
140 |
- ret->PN = ptr + 1; |
141 |
- *ptr = '\0'; |
142 |
+ *ptr++ = '\0'; |
143 |
+ ret->PF = ptr; |
144 |
|
145 |
/* set PN to NULL if there's nothing */ |
146 |
- if (ret->PN[0] == '\0') |
147 |
- ret->PN = NULL; |
148 |
+ if (ret->PF[0] == '\0') |
149 |
+ ret->PF = NULL; |
150 |
|
151 |
/* eat extra crap in case it exists, this is a feature to allow |
152 |
* /path/to/pkg.ebuild, doesn't work with prefix operators |
153 |
@@ -220,75 +240,81 @@ atom_explode(const char *atom) |
154 |
if ((ptr = strrchr(ret->CATEGORY, '/')) != NULL) |
155 |
ret->CATEGORY = ptr + 1; |
156 |
} else { |
157 |
- ret->PN = ret->CATEGORY; |
158 |
+ ret->PF = ret->CATEGORY; |
159 |
ret->CATEGORY = NULL; |
160 |
} |
161 |
|
162 |
- if (ret->PN == NULL) { |
163 |
+ if (ret->PF == NULL) { |
164 |
/* atom has no name, this is it */ |
165 |
ret->P = NULL; |
166 |
+ ret->PN = NULL; |
167 |
ret->PVR = NULL; |
168 |
+ |
169 |
return ret; |
170 |
} |
171 |
|
172 |
- /* CATEGORY should be all set here, PN contains everything up to |
173 |
+ /* CATEGORY should be all set here, PF contains everything up to |
174 |
* SLOT, REPO or '*' |
175 |
- * PN must not end in a hyphen followed by anything matching version |
176 |
- * syntax, version syntax starts with a number, so "-[0-9]" is a |
177 |
- * separator from PN to PV* -- except it doesn't when the thing |
178 |
- * doesn't validate as version :( */ |
179 |
- |
180 |
- ptr = ret->PN; |
181 |
- { |
182 |
- char *lastpv = NULL; |
183 |
- char *pv; |
184 |
- |
185 |
- while ((ptr = strchr(ptr, '-')) != NULL) { |
186 |
- ptr++; |
187 |
- if (!isdigit(*ptr)) |
188 |
- continue; |
189 |
+ * PMS 3.1.2 says PN must not end in a hyphen followed by |
190 |
+ * anything matching version syntax. PMS 3.2 version syntax |
191 |
+ * starts with a number, so "-[0-9]" is a separator from PN to |
192 |
+ * PV* -- except it doesn't when the thing doesn't validate as |
193 |
+ * version :( */ |
194 |
+ |
195 |
+ ptr = ret->PF; |
196 |
+ while ((ptr = strchr(ptr, '-')) != NULL) { |
197 |
+ ptr++; |
198 |
+ if (!isdigit(*ptr)) |
199 |
+ continue; |
200 |
|
201 |
- /* so we should have something like "-2" here, see if this |
202 |
- * checks out as valid version string */ |
203 |
- pv = ptr; |
204 |
- while (*++ptr != '\0') { |
205 |
- if (*ptr != '.' && !isdigit(*ptr)) |
206 |
- break; |
207 |
- } |
208 |
- /* allow for 1 optional suffix letter */ |
209 |
- if (*ptr >= 'a' && *ptr <= 'z') |
210 |
- ret->letter = *ptr++; |
211 |
- if (*ptr == '_' || *ptr == '-' || *ptr == '\0') { |
212 |
- lastpv = pv; |
213 |
- continue; /* valid, keep searching */ |
214 |
- } |
215 |
- ret->letter = '\0'; |
216 |
+ /* so we should have something like "-2" here, see if this |
217 |
+ * checks out as valid version string */ |
218 |
+ pv = ptr; |
219 |
+ while (*++ptr != '\0') { |
220 |
+ if (*ptr != '.' && !isdigit(*ptr)) |
221 |
+ break; |
222 |
+ } |
223 |
+ /* allow for 1 optional suffix letter */ |
224 |
+ if (*ptr >= 'a' && *ptr <= 'z') |
225 |
+ ret->letter = *ptr++; |
226 |
+ if (*ptr == '_' || *ptr == '-' || *ptr == '\0') { |
227 |
+ lastpv = pv; |
228 |
+ continue; /* valid, keep searching */ |
229 |
} |
230 |
- ptr = lastpv; |
231 |
+ ret->letter = '\0'; |
232 |
} |
233 |
+ ptr = lastpv; |
234 |
|
235 |
if (ptr == NULL) { |
236 |
/* atom has no version, this is it */ |
237 |
- strcpy(ret->P, ret->PN); |
238 |
- ret->PVR = NULL; |
239 |
+ ret->P = ret->PN = ret->PF; |
240 |
+ ret->PV = ret->PVR = NULL; |
241 |
+ |
242 |
return ret; |
243 |
} |
244 |
- ret->PV = ptr; |
245 |
+ |
246 |
+ ret->PVR = ptr; |
247 |
+ snprintf(ret->PN, slen, "%.*s", (int)(ret->PVR - 1 - ret->PF), ret->PF); |
248 |
|
249 |
/* find -r# */ |
250 |
- ptr = ret->PV + strlen(ret->PV) - 1; |
251 |
- while (*ptr && ptr > ret->PV) { |
252 |
- if (!isdigit(*ptr)) { |
253 |
+ pv = NULL; |
254 |
+ ptr = ret->PVR + strlen(ret->PVR) - 1; |
255 |
+ while (*ptr && ptr > ret->PVR) { |
256 |
+ if (!isdigit((int)*ptr)) { |
257 |
if (ptr[0] == 'r' && ptr[-1] == '-') { |
258 |
ret->PR_int = atoi(ptr + 1); |
259 |
- ptr[-1] = '\0'; |
260 |
+ pv = &ptr[-1]; |
261 |
} |
262 |
break; |
263 |
} |
264 |
ptr--; |
265 |
} |
266 |
- strcpy(ret->P, ret->PN); |
267 |
- ret->PV[-1] = '\0'; |
268 |
+ if (pv != NULL) { |
269 |
+ snprintf(ret->P, slen, "%.*s", (int)(pv - ret->PF), ret->PF); |
270 |
+ } else { |
271 |
+ ret->P = ret->PF; |
272 |
+ } |
273 |
+ ret->PV = ret->P + (ret->PVR - ret->PF); |
274 |
|
275 |
/* break out all the suffixes */ |
276 |
sidx = 0; |
277 |
@@ -325,9 +351,6 @@ atom_explode(const char *atom) |
278 |
ret->suffixes[idx] = t; |
279 |
} |
280 |
|
281 |
- /* size is malloced above with the required space in mind */ |
282 |
- sprintf(ret->PVR, "%s-r%i", ret->PV, ret->PR_int); |
283 |
- |
284 |
return ret; |
285 |
} |
286 |
|
287 |
|
288 |
diff --git a/libq/atom.h b/libq/atom.h |
289 |
index a5175b0..1548dd9 100644 |
290 |
--- a/libq/atom.h |
291 |
+++ b/libq/atom.h |
292 |
@@ -74,6 +74,7 @@ typedef struct { |
293 |
char *CATEGORY; |
294 |
char *PN; |
295 |
char *PV; |
296 |
+ char *PF; |
297 |
unsigned int PR_int; |
298 |
char letter; |
299 |
atom_suffix *suffixes; |
300 |
|
301 |
diff --git a/tests/atom_explode/test.c b/tests/atom_explode/test.c |
302 |
index 21a5f1d..b794d3b 100644 |
303 |
--- a/tests/atom_explode/test.c |
304 |
+++ b/tests/atom_explode/test.c |
305 |
@@ -1,5 +1,5 @@ |
306 |
/* |
307 |
- * Copyright 2005-2019 Gentoo Foundation |
308 |
+ * Copyright 2005-2020 Gentoo Foundation |
309 |
* Distributed under the terms of the GNU General Public License v2 |
310 |
* |
311 |
* Copyright 2005-2008 Ned Ludd - <solar@g.o> |
312 |
@@ -19,9 +19,23 @@ FILE *warnout; |
313 |
|
314 |
static inline void boom(depend_atom *a, char *s) |
315 |
{ |
316 |
- printf("%s -> %s / [%s] %s - %s [%s] [r%i]\n", |
317 |
- s, (a->CATEGORY?:"null"), a->P, a->PN, |
318 |
- a->PVR, a->PV, a->PR_int); |
319 |
+ /* python code: |
320 |
+ * CATEGORY = cpv[0] |
321 |
+ * PN = cpv[1] |
322 |
+ * PV = cpv[2] |
323 |
+ * PR_int = cpv[3] |
324 |
+ * P = PN + "-" + PV |
325 |
+ * PVR = PV + "-" + cpv[3] |
326 |
+ * print(a+" -> "+CATEGORY+" / ["+P+"] "+PN+" - "+PVR+" ["+PV+"] ["+PR_int+"]") |
327 |
+ * this most notably doesn't test PVR in compliance with PMS */ |
328 |
+ printf("%s -> %s / [%s] %s - %s%s [%s] [r%i]\n", |
329 |
+ s, |
330 |
+ (a->CATEGORY ? a->CATEGORY : "null"), |
331 |
+ a->P, |
332 |
+ a->PN, |
333 |
+ a->PVR, (a->PVR != NULL && a->PR_int == 0) ? "-r0" : "", |
334 |
+ a->PV, |
335 |
+ a->PR_int); |
336 |
} |
337 |
|
338 |
int main(int argc, char *argv[]) |