Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2015-2017, Vsevolod Stakhov
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions are met:
7 : : * * Redistributions of source code must retain the above copyright
8 : : * notice, this list of conditions and the following disclaimer.
9 : : * * Redistributions in binary form must reproduce the above copyright
10 : : * notice, this list of conditions and the following disclaimer in the
11 : : * documentation and/or other materials provided with the distribution.
12 : : *
13 : : * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14 : : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 : : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 : : * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17 : : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 : : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 : : */
24 : :
25 : : #ifdef HAVE_CONFIG_H
26 : : #include "pkg_config.h"
27 : : #endif
28 : :
29 : : #include "bsd_compat.h"
30 : :
31 : : #include <stddef.h>
32 : : #include <ctype.h>
33 : : #include <assert.h>
34 : : #include <string.h>
35 : : #include <stdlib.h>
36 : :
37 : : #include "pkg.h"
38 : : #include "private/event.h"
39 : : #include "private/pkg_deps.h"
40 : : #include "xmalloc.h"
41 : : #include "utlist.h"
42 : :
43 : : struct pkg_dep_formula *
44 : 156 : pkg_deps_parse_formula(const char *in)
45 : : {
46 : 156 : struct pkg_dep_formula *res = NULL, *cur = NULL;
47 : 156 : struct pkg_dep_formula_item *cur_item = NULL;
48 : 156 : struct pkg_dep_version_item *cur_ver = NULL;
49 : 156 : struct pkg_dep_option_item *cur_opt = NULL;
50 : : const char *p, *c, *end;
51 : 156 : enum pkg_dep_version_op cur_op = VERSION_ANY;
52 : : enum {
53 : : st_parse_dep_name = 0,
54 : : st_parse_after_name,
55 : : st_parse_ver_op,
56 : : st_parse_after_op,
57 : : st_parse_version_number,
58 : : st_parse_after_version,
59 : : st_parse_option_start,
60 : : st_parse_option,
61 : : st_parse_after_option,
62 : : st_parse_comma,
63 : : st_parse_or,
64 : : st_skip_spaces,
65 : : st_error
66 : 156 : } state = 0, next_state = 0;
67 : :
68 : 156 : c = in;
69 : 156 : p = in;
70 : :
71 : 156 : end = p + strlen(p);
72 : :
73 [ + + ]: 5668 : while (p <= end) {
74 [ + - + + : 5512 : switch (state) {
+ + + + +
+ + - ]
75 : : case st_parse_dep_name:
76 [ + + + + ]: 1638 : if (isspace(*p) || *p == '\0') {
77 : 260 : state = st_skip_spaces;
78 : :
79 [ - + ]: 260 : if (p == c) {
80 : : /* Spaces at the beginning */
81 : 0 : next_state = st_parse_dep_name;
82 : 0 : }
83 : : else {
84 : : /* Spaces after the name */
85 : 260 : cur_item = xcalloc(1, sizeof(*cur_item));
86 : 260 : cur_item->name = xmalloc(p - c + 1);
87 : 260 : strlcpy(cur_item->name, c, p - c + 1);
88 : 260 : next_state = st_parse_after_name;
89 : : }
90 : 260 : }
91 [ + + ]: 1378 : else if (*p == ',') {
92 [ + - ]: 26 : if (p == c) {
93 : 0 : state = st_error;
94 : 0 : }
95 : : else {
96 : 26 : cur_item = xcalloc(1, sizeof(*cur_item));
97 : 26 : cur_item->name = xmalloc(p - c + 1);
98 : 26 : strlcpy(cur_item->name, c, p - c + 1);
99 : 26 : state = st_parse_after_name;
100 : : }
101 : 26 : }
102 [ + - ]: 1352 : else if (!isprint(*p)) {
103 : 0 : state = st_error;
104 : 0 : }
105 : : else {
106 : 1352 : p++;
107 : : }
108 : 1638 : break;
109 : :
110 : : case st_parse_after_name:
111 : : case st_parse_after_version:
112 : : case st_parse_after_option: {
113 [ + + + - : 364 : switch (*p) {
+ ]
114 : : case ',':
115 : : case '\0':
116 : 65 : state = st_parse_comma;
117 : 65 : break;
118 : : case '|':
119 : 65 : state = st_parse_or;
120 : 65 : break;
121 : : case '+':
122 : : case '-':
123 : 26 : c = p;
124 : 26 : state = st_parse_option_start;
125 : 26 : break;
126 : : case '>':
127 : : case '<':
128 : : case '=':
129 : : case '!':
130 : 208 : c = p;
131 : 208 : cur_op = VERSION_ANY;
132 : 208 : state = st_parse_ver_op;
133 : 208 : break;
134 : : default:
135 : 0 : state = st_error;
136 : 0 : break;
137 : : }
138 : 364 : break;
139 : : }
140 : :
141 : : case st_parse_ver_op: {
142 [ + + ]: 507 : switch (*p) {
143 : : case '>':
144 : : case '<':
145 : : case '=':
146 : : case '!':
147 : 299 : p ++;
148 : 299 : break;
149 : : default:
150 [ + + ]: 208 : if (p - c == 2) {
151 [ + + ]: 91 : if (memcmp(c, ">=", 2) == 0) {
152 : 26 : cur_op = VERSION_GE;
153 : 26 : }
154 [ + - ]: 65 : else if (memcmp(c, "<=", 2) == 0) {
155 : 0 : cur_op = VERSION_LE;
156 : 0 : }
157 [ - + ]: 65 : else if (memcmp(c, "!=", 2) == 0) {
158 : 65 : cur_op = VERSION_NOT;
159 : 65 : }
160 [ # # ]: 0 : else if (memcmp(c, "==", 2) == 0) {
161 : 0 : cur_op = VERSION_EQ;
162 : 0 : }
163 : : else {
164 : 0 : state = st_error;
165 : : }
166 : 91 : }
167 [ + - ]: 117 : else if (p - c == 1) {
168 [ + + ]: 117 : if (*c == '>') {
169 : 26 : cur_op = VERSION_GT;
170 : 26 : }
171 [ + + ]: 91 : else if (*c == '<') {
172 : 26 : cur_op = VERSION_LT;
173 : 26 : }
174 [ - + ]: 65 : else if (*c == '!') {
175 : 0 : cur_op = VERSION_NOT;
176 : 0 : }
177 [ + - ]: 65 : else if (*c == '=') {
178 : 65 : cur_op = VERSION_EQ;
179 : 65 : }
180 : : else {
181 : 0 : state = st_error;
182 : : }
183 : 117 : }
184 : : else {
185 : 0 : state = st_error;
186 : : }
187 : :
188 [ - + ]: 208 : if (state != st_error) {
189 : 208 : state = st_skip_spaces;
190 : 208 : next_state = st_parse_after_op;
191 : 208 : }
192 : 208 : break;
193 : : }
194 : 507 : break;
195 : : }
196 : :
197 : : case st_parse_after_op:
198 [ + - ]: 208 : if (cur_op == VERSION_ANY) {
199 : 0 : state = st_error;
200 : 0 : }
201 : : else {
202 : 208 : state = st_parse_version_number;
203 : : }
204 : 208 : break;
205 : :
206 : : case st_parse_version_number:
207 [ + + + - : 949 : if (isalnum(*p) || *p == '-' || *p == '_' || *p == '.' ||
+ - + + +
+ ]
208 [ + + ]: 234 : (*p == ',' && isdigit(*(p + 1)))) {
209 : 676 : p ++;
210 : 676 : }
211 : : else {
212 [ + - ]: 208 : if (p - c > 0) {
213 : 208 : cur_ver = xcalloc(1, sizeof(*cur_ver));
214 : 208 : cur_ver->ver = xmalloc(p - c + 1);
215 : 208 : strlcpy(cur_ver->ver, c, p - c + 1);
216 : 208 : cur_ver->op = cur_op;
217 [ - + ]: 208 : assert(cur_item != NULL);
218 [ + + ]: 208 : DL_APPEND(cur_item->versions, cur_ver);
219 : 208 : state = st_skip_spaces;
220 : 208 : next_state = st_parse_after_version;
221 : 208 : }
222 : : else {
223 : 0 : state = st_error;
224 : : }
225 : : }
226 : 884 : break;
227 : :
228 : : case st_parse_option_start:
229 : 26 : cur_opt = xcalloc(1, sizeof(*cur_opt));
230 [ + + ]: 26 : if (*p == '+') {
231 : 13 : cur_opt->on = true;
232 : 13 : }
233 : : else {
234 : 13 : cur_opt->on = false;
235 : : }
236 : :
237 : 26 : p ++;
238 : 26 : c = p;
239 : 26 : state = st_parse_option;
240 : 26 : break;
241 : :
242 : : case st_parse_option:
243 [ + + + - : 130 : if (isalnum(*p) || *p == '-' || *p == '_') {
- + ]
244 : 104 : p ++;
245 : 104 : }
246 : : else {
247 [ - + ]: 26 : if (p - c > 0) {
248 : 26 : cur_opt->opt = xmalloc(p - c + 1);
249 : 26 : strlcpy(cur_opt->opt, c, p - c + 1);
250 [ + - ]: 26 : assert(cur_item != NULL);
251 [ + + ]: 26 : DL_APPEND(cur_item->options, cur_opt);
252 : 26 : state = st_skip_spaces;
253 : 26 : next_state = st_parse_after_option;
254 : 26 : }
255 : : else {
256 : 0 : state = st_error;
257 : : }
258 : : }
259 : 130 : break;
260 : :
261 : : case st_parse_comma:
262 [ + - ]: 221 : assert(cur_item != NULL);
263 : :
264 [ + + ]: 221 : if (cur == NULL) {
265 : 156 : cur = xcalloc(1, sizeof(*cur));
266 : 156 : }
267 : :
268 [ + + ]: 221 : DL_APPEND(cur->items, cur_item);
269 [ + + ]: 221 : DL_APPEND(res, cur);
270 : 221 : cur_item = NULL;
271 : 221 : cur = NULL;
272 : 221 : p ++;
273 : 221 : state = st_skip_spaces;
274 : 221 : next_state = st_parse_dep_name;
275 : 221 : break;
276 : :
277 : : case st_parse_or:
278 [ + - ]: 65 : assert(cur_item != NULL);
279 : :
280 [ - + ]: 65 : if (cur == NULL) {
281 : 65 : cur = xcalloc(1, sizeof(*cur));
282 : 65 : }
283 : :
284 [ - + ]: 65 : DL_APPEND(cur->items, cur_item);
285 : 65 : cur_item = NULL;
286 : 65 : p ++;
287 : 65 : state = st_skip_spaces;
288 : 65 : next_state = st_parse_dep_name;
289 : 65 : break;
290 : :
291 : : case st_skip_spaces:
292 [ + + ]: 1469 : if (isspace(*p)) {
293 : 637 : p ++;
294 : 637 : }
295 [ + + ]: 832 : else if (*p == '\0') {
296 : 156 : state = st_parse_comma;
297 : 156 : }
298 : : else {
299 : 676 : c = p;
300 : 676 : state = next_state;
301 : : }
302 : 1469 : break;
303 : :
304 : : case st_error:
305 : : default:
306 : 0 : pkg_emit_error("cannot parse pkg formula: %s", in);
307 : 0 : pkg_deps_formula_free(res);
308 [ # # ]: 0 : if (cur_item != NULL) {
309 : 0 : free(cur_item->name);
310 : 0 : free(cur_item);
311 : 0 : }
312 : :
313 : 0 : return (NULL);
314 : :
315 : : break;
316 : : }
317 : : }
318 : :
319 [ - + # # ]: 156 : if (state != st_skip_spaces && state != st_parse_comma) {
320 : 0 : pkg_emit_error("cannot parse pkg formula: %s", in);
321 : 0 : pkg_deps_formula_free(res);
322 [ # # ]: 0 : if (cur_item != NULL) {
323 : 0 : free(cur_item->name);
324 : 0 : free(cur_item);
325 : 0 : }
326 : :
327 : 0 : return (NULL);
328 : : }
329 : :
330 : 156 : return (res);
331 : 156 : }
332 : :
333 : : void
334 : 156 : pkg_deps_formula_free(struct pkg_dep_formula *f)
335 : : {
336 : : struct pkg_dep_formula *cf, *cftmp;
337 : : struct pkg_dep_formula_item *cit, *cittmp;
338 : : struct pkg_dep_version_item *cver, *cvertmp;
339 : : struct pkg_dep_option_item *copt, *copttmp;
340 : :
341 [ + + + + ]: 377 : DL_FOREACH_SAFE(f, cf, cftmp) {
342 [ + + + + ]: 507 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
343 : 286 : free(cit->name);
344 : :
345 [ + + + + ]: 494 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
346 : 208 : free(cver->ver);
347 : 208 : free(cver);
348 : 208 : }
349 : :
350 [ + + + + ]: 312 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
351 : 26 : free(copt->opt);
352 : 26 : free(copt);
353 : 26 : }
354 : :
355 : 286 : free(cit);
356 : 286 : }
357 : :
358 : 221 : free(cf);
359 : 221 : }
360 : 156 : }
361 : :
362 : : static const char*
363 : 208 : pkg_deps_op_tostring(enum pkg_dep_version_op op)
364 : : {
365 : : const char *op_str;
366 : :
367 [ - - + - : 208 : switch (op) {
+ + + + ]
368 : : case VERSION_ANY:
369 : : default:
370 : 0 : op_str = "?";
371 : 0 : break;
372 : : case VERSION_EQ:
373 : 65 : op_str = "=";
374 : 65 : break;
375 : : case VERSION_LE:
376 : 0 : op_str = "<=";
377 : 0 : break;
378 : : case VERSION_GE:
379 : 26 : op_str = ">=";
380 : 26 : break;
381 : : case VERSION_LT:
382 : 26 : op_str = "<";
383 : 26 : break;
384 : : case VERSION_GT:
385 : 26 : op_str = ">";
386 : 26 : break;
387 : : case VERSION_NOT:
388 : 65 : op_str = "!=";
389 : 65 : break;
390 : : }
391 : :
392 : 208 : return (op_str);
393 : : }
394 : :
395 : : char*
396 : 91 : pkg_deps_formula_tostring(struct pkg_dep_formula *f)
397 : : {
398 : : struct pkg_dep_formula *cf, *cftmp;
399 : : struct pkg_dep_formula_item *cit, *cittmp;
400 : : struct pkg_dep_version_item *cver, *cvertmp;
401 : : struct pkg_dep_option_item *copt, *copttmp;
402 : 91 : char *res = NULL, *p;
403 : :
404 : 91 : int rlen = 0, r;
405 : :
406 [ + + + + ]: 247 : DL_FOREACH_SAFE(f, cf, cftmp) {
407 [ + + + + ]: 351 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
408 : 195 : rlen += strlen(cit->name);
409 : :
410 [ + + + + ]: 351 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
411 : 156 : rlen += strlen(cver->ver);
412 : 156 : rlen += 4; /* <OP><SP><VER><SP> */
413 : 156 : }
414 : :
415 [ + + + + ]: 221 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
416 : 26 : rlen += strlen(copt->opt);
417 : 26 : rlen += 2; /* <+-><OPT><SP> */
418 : 26 : }
419 : :
420 : 195 : rlen += 2; /* |<SP> */
421 : 195 : }
422 : :
423 : 156 : rlen += 2; /* <,><SP> */
424 : 156 : }
425 : :
426 [ - + ]: 91 : if (rlen == 0) {
427 : 0 : return (NULL);
428 : : }
429 : :
430 : 91 : res = xmalloc(rlen + 1);
431 : :
432 : 91 : p = res;
433 : :
434 [ + + + + ]: 247 : DL_FOREACH_SAFE(f, cf, cftmp) {
435 [ + + + + ]: 351 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
436 : 195 : r = snprintf(p, rlen, "%s", cit->name);
437 : 195 : p += r;
438 : 195 : rlen -= r;
439 : :
440 [ + + + + ]: 351 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
441 : 312 : r = snprintf(p, rlen, " %s %s", pkg_deps_op_tostring(cver->op),
442 : 156 : cver->ver);
443 : 156 : p += r;
444 : 156 : rlen -= r;
445 : 156 : }
446 : :
447 [ + + + + ]: 221 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
448 : 26 : r = snprintf(p, rlen, " %c%s", copt->on ? '+' : '-', copt->opt);
449 : 26 : p += r;
450 : 26 : rlen -= r;
451 : 26 : }
452 : :
453 : 195 : r = snprintf(p, rlen, "%s", cit->next ? " | " : "");
454 : 195 : p += r;
455 : 195 : rlen -= r;
456 : 195 : }
457 : :
458 : 156 : r = snprintf(p, rlen, "%s", cf->next ? ", " : "");
459 : 156 : p += r;
460 : 156 : rlen -= r;
461 : 156 : }
462 : :
463 : 91 : return (res);
464 : 91 : }
465 : :
466 : : char*
467 : 65 : pkg_deps_formula_tosql(struct pkg_dep_formula_item *f)
468 : : {
469 : : struct pkg_dep_formula_item *cit, *cittmp;
470 : : struct pkg_dep_version_item *cver, *cvertmp;
471 : 65 : char *res = NULL, *p;
472 : :
473 : 65 : int rlen = 0, r;
474 : :
475 [ + + + + ]: 156 : DL_FOREACH_SAFE(f, cit, cittmp) {
476 : 91 : rlen += sizeof("AND (name='' )");
477 : 91 : rlen += strlen(cit->name);
478 : :
479 [ + + + + ]: 143 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
480 : 52 : rlen += sizeof(" AND vercmp(>=, version,'') ");
481 : 52 : rlen += strlen(cver->ver);
482 : 52 : }
483 : :
484 : 91 : rlen += sizeof(" OR ");
485 : 91 : }
486 : :
487 [ - + ]: 65 : if (rlen == 0) {
488 : 0 : return (NULL);
489 : : }
490 : :
491 : 65 : res = xmalloc(rlen + 1);
492 : :
493 : 65 : p = res;
494 : :
495 [ + + + + ]: 156 : DL_FOREACH_SAFE(f, cit, cittmp) {
496 : 91 : r = snprintf(p, rlen, "(name='%s'", cit->name);
497 : 91 : p += r;
498 : 91 : rlen -= r;
499 : :
500 [ + + + + ]: 143 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
501 : 104 : r = snprintf(p, rlen, " AND vercmp('%s',version,'%s')",
502 : 52 : pkg_deps_op_tostring(cver->op),
503 : 52 : cver->ver);
504 : 52 : p += r;
505 : 52 : rlen -= r;
506 : 52 : }
507 : 91 : r = snprintf(p, rlen, ")%s", cit->next ? " OR " : "");
508 : 91 : p += r;
509 : 91 : rlen -= r;
510 : 91 : }
511 : :
512 : 65 : return (res);
513 : 65 : }
514 : :
515 : : enum pkg_dep_version_op
516 : 143 : pkg_deps_string_toop(const char *in)
517 : : {
518 : 143 : enum pkg_dep_version_op ret = VERSION_ANY;
519 : : int len;
520 : :
521 [ + + ]: 143 : if (in != NULL) {
522 : 130 : len = strlen(in);
523 : :
524 [ + + ]: 130 : if (len == 2) {
525 [ + + ]: 65 : if (memcmp(in, ">=", 2) == 0) {
526 : 13 : ret = VERSION_GE;
527 : 13 : }
528 [ + + ]: 52 : else if (memcmp(in, "<=", 2) == 0) {
529 : 13 : ret = VERSION_LE;
530 : 13 : }
531 [ + + ]: 39 : else if (memcmp(in, "!=", 2) == 0) {
532 : 13 : ret = VERSION_NOT;
533 : 13 : }
534 [ + + ]: 26 : else if (memcmp(in, "==", 2) == 0) {
535 : 13 : ret = VERSION_EQ;
536 : 13 : }
537 : 65 : }
538 [ - + ]: 65 : else if (len == 1) {
539 [ + + ]: 65 : if (*in == '>') {
540 : 13 : ret = VERSION_GT;
541 : 13 : }
542 [ + + ]: 52 : else if (*in == '<') {
543 : 13 : ret = VERSION_LT;
544 : 13 : }
545 [ + + ]: 39 : else if (*in == '!') {
546 : 13 : ret = VERSION_NOT;
547 : 13 : }
548 [ + + ]: 26 : else if (*in == '=') {
549 : 13 : ret = VERSION_EQ;
550 : 13 : }
551 : 65 : }
552 : 130 : }
553 : :
554 : 143 : return (ret);
555 : : }
|