Line data Source code
1 : /*-
2 : * Copyright (c) 2015, 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 :
36 : #include "pkg.h"
37 : #include "private/event.h"
38 : #include "private/pkg_deps.h"
39 : #include "utlist.h"
40 :
41 : struct pkg_dep_formula *
42 12 : pkg_deps_parse_formula(const char *in)
43 : {
44 12 : struct pkg_dep_formula *res = NULL, *cur = NULL;
45 12 : struct pkg_dep_formula_item *cur_item = NULL;
46 12 : struct pkg_dep_version_item *cur_ver = NULL;
47 12 : struct pkg_dep_option_item *cur_opt = NULL;
48 : const char *p, *c, *end;
49 12 : enum pkg_dep_version_op cur_op = VERSION_ANY;
50 : enum {
51 : st_parse_dep_name = 0,
52 : st_parse_after_name,
53 : st_parse_ver_op,
54 : st_parse_after_op,
55 : st_parse_version_number,
56 : st_parse_after_version,
57 : st_parse_option_start,
58 : st_parse_option,
59 : st_parse_after_option,
60 : st_parse_comma,
61 : st_parse_or,
62 : st_skip_spaces,
63 : st_error
64 12 : } state = 0, next_state = 0;
65 :
66 12 : c = in;
67 12 : p = in;
68 :
69 12 : end = p + strlen(p);
70 :
71 448 : while (p <= end) {
72 424 : switch (state) {
73 : case st_parse_dep_name:
74 126 : if (isspace(*p) || *p == '\0') {
75 20 : state = st_skip_spaces;
76 :
77 40 : if (p == c) {
78 : /* Spaces at the beginning */
79 0 : next_state = st_parse_dep_name;
80 : }
81 : else {
82 : /* Spaces after the name */
83 20 : cur_item = calloc(1, sizeof(*cur_item));
84 :
85 20 : if (cur_item == NULL) {
86 0 : pkg_emit_errno("malloc", "struct pkg_dep_formula_item");
87 :
88 0 : return (NULL);
89 : }
90 20 : cur_item->name = malloc(p - c + 1);
91 :
92 20 : if (cur_item->name == NULL) {
93 0 : pkg_emit_errno("malloc", "cur->name");
94 :
95 0 : return (NULL);
96 : }
97 :
98 20 : strlcpy(cur_item->name, c, p - c + 1);
99 20 : next_state = st_parse_after_name;
100 : }
101 : }
102 106 : else if (*p == ',') {
103 2 : if (p == c) {
104 0 : state = st_error;
105 : }
106 : else {
107 2 : cur_item = calloc(1, sizeof(*cur_item));
108 :
109 2 : if (cur_item == NULL) {
110 0 : pkg_emit_errno("malloc", "struct pkg_dep_formula_item");
111 :
112 0 : return (NULL);
113 : }
114 2 : cur_item->name = malloc(p - c + 1);
115 :
116 2 : if (cur_item->name == NULL) {
117 0 : pkg_emit_errno("malloc", "cur->name");
118 :
119 0 : return (NULL);
120 : }
121 :
122 2 : strlcpy(cur_item->name, c, p - c + 1);
123 2 : state = st_parse_after_name;
124 : }
125 : }
126 104 : else if (!isprint(*p)) {
127 0 : state = st_error;
128 : }
129 : else {
130 104 : p++;
131 : }
132 126 : break;
133 :
134 : case st_parse_after_name:
135 : case st_parse_after_version:
136 : case st_parse_after_option: {
137 28 : switch (*p) {
138 : case ',':
139 : case '\0':
140 5 : state = st_parse_comma;
141 5 : break;
142 : case '|':
143 5 : state = st_parse_or;
144 5 : break;
145 : case '+':
146 : case '-':
147 2 : c = p;
148 2 : state = st_parse_option_start;
149 2 : break;
150 : case '>':
151 : case '<':
152 : case '=':
153 : case '!':
154 16 : c = p;
155 16 : cur_op = VERSION_ANY;
156 16 : state = st_parse_ver_op;
157 16 : break;
158 : default:
159 0 : state = st_error;
160 0 : break;
161 : }
162 28 : break;
163 : }
164 :
165 : case st_parse_ver_op: {
166 39 : switch (*p) {
167 : case '>':
168 : case '<':
169 : case '=':
170 : case '!':
171 23 : p ++;
172 23 : break;
173 : default:
174 16 : if (p - c == 2) {
175 7 : if (memcmp(c, ">=", 2) == 0) {
176 2 : cur_op = VERSION_GE;
177 : }
178 5 : else if (memcmp(c, "<=", 2) == 0) {
179 0 : cur_op = VERSION_LE;
180 : }
181 5 : else if (memcmp(c, "!=", 2) == 0) {
182 5 : cur_op = VERSION_NOT;
183 : }
184 0 : else if (memcmp(c, "==", 2) == 0) {
185 0 : cur_op = VERSION_EQ;
186 : }
187 : else {
188 0 : state = st_error;
189 : }
190 : }
191 9 : else if (p - c == 1) {
192 9 : if (*c == '>') {
193 2 : cur_op = VERSION_GT;
194 : }
195 7 : else if (*c == '<') {
196 2 : cur_op = VERSION_LT;
197 : }
198 5 : else if (*c == '!') {
199 0 : cur_op = VERSION_NOT;
200 : }
201 5 : else if (*c == '=') {
202 5 : cur_op = VERSION_EQ;
203 : }
204 : else {
205 0 : state = st_error;
206 : }
207 : }
208 : else {
209 0 : state = st_error;
210 : }
211 :
212 16 : if (state != st_error) {
213 16 : state = st_skip_spaces;
214 16 : next_state = st_parse_after_op;
215 : }
216 16 : break;
217 : }
218 39 : break;
219 : }
220 :
221 : case st_parse_after_op:
222 16 : if (cur_op == VERSION_ANY) {
223 0 : state = st_error;
224 : }
225 : else {
226 16 : state = st_parse_version_number;
227 : }
228 16 : break;
229 :
230 : case st_parse_version_number:
231 86 : if (isalnum(*p) || *p == '-' || *p == '_' || *p == '.' ||
232 23 : (*p == ',' && isdigit(*(p + 1)))) {
233 52 : p ++;
234 : }
235 : else {
236 16 : if (p - c > 0) {
237 16 : cur_ver = calloc(1, sizeof(*cur_ver));
238 :
239 16 : if (cur_ver == NULL) {
240 0 : pkg_emit_errno("malloc", "struct pkg_dep_version");
241 :
242 0 : return (NULL);
243 : }
244 16 : cur_ver->ver = malloc(p - c + 1);
245 :
246 16 : if (cur_ver->ver == NULL) {
247 0 : pkg_emit_errno("malloc", "cur_ver->ver");
248 :
249 0 : return (NULL);
250 : }
251 :
252 16 : strlcpy(cur_ver->ver, c, p - c + 1);
253 16 : cur_ver->op = cur_op;
254 16 : assert(cur_item != NULL);
255 16 : DL_APPEND(cur_item->versions, cur_ver);
256 16 : state = st_skip_spaces;
257 16 : next_state = st_parse_after_version;
258 : }
259 : else {
260 0 : state = st_error;
261 : }
262 : }
263 68 : break;
264 :
265 : case st_parse_option_start:
266 2 : cur_opt = calloc(1, sizeof(*cur_opt));
267 2 : if (cur_ver == NULL) {
268 0 : pkg_emit_errno("malloc", "struct pkg_dep_option");
269 :
270 0 : return (NULL);
271 : }
272 :
273 2 : if (*p == '+') {
274 1 : cur_opt->on = true;
275 : }
276 : else {
277 1 : cur_opt->on = false;
278 : }
279 :
280 2 : p ++;
281 2 : c = p;
282 2 : state = st_parse_option;
283 2 : break;
284 :
285 : case st_parse_option:
286 10 : if (isalnum(*p) || *p == '-' || *p == '_') {
287 8 : p ++;
288 : }
289 : else {
290 2 : if (p - c > 0) {
291 2 : cur_opt->opt = malloc(p - c + 1);
292 :
293 2 : if (cur_opt->opt == NULL) {
294 0 : pkg_emit_errno("malloc", "cur_opt->opt");
295 :
296 0 : return (NULL);
297 : }
298 :
299 2 : strlcpy(cur_opt->opt, c, p - c + 1);
300 2 : assert(cur_item != NULL);
301 2 : DL_APPEND(cur_item->options, cur_opt);
302 2 : state = st_skip_spaces;
303 2 : next_state = st_parse_after_option;
304 : }
305 : else {
306 0 : state = st_error;
307 : }
308 : }
309 10 : break;
310 :
311 : case st_parse_comma:
312 17 : assert(cur_item != NULL);
313 :
314 17 : if (cur == NULL) {
315 12 : cur = calloc(1, sizeof(*cur));
316 :
317 12 : if (cur == NULL) {
318 0 : pkg_emit_errno("malloc", "struct pkg_dep_formula");
319 :
320 0 : return (NULL);
321 : }
322 : }
323 :
324 17 : DL_APPEND(cur->items, cur_item);
325 17 : DL_APPEND(res, cur);
326 17 : cur_item = NULL;
327 17 : cur = NULL;
328 17 : p ++;
329 17 : state = st_skip_spaces;
330 17 : next_state = st_parse_dep_name;
331 17 : break;
332 :
333 : case st_parse_or:
334 5 : assert(cur_item != NULL);
335 :
336 5 : if (cur == NULL) {
337 5 : cur = calloc(1, sizeof(*cur));
338 :
339 5 : if (cur == NULL) {
340 0 : pkg_emit_errno("malloc", "struct pkg_dep_formula");
341 :
342 0 : return (NULL);
343 : }
344 : }
345 :
346 5 : DL_APPEND(cur->items, cur_item);
347 5 : cur_item = NULL;
348 5 : p ++;
349 5 : state = st_skip_spaces;
350 5 : next_state = st_parse_dep_name;
351 5 : break;
352 :
353 : case st_skip_spaces:
354 113 : if (isspace(*p)) {
355 49 : p ++;
356 : }
357 64 : else if (*p == '\0') {
358 12 : state = st_parse_comma;
359 : }
360 : else {
361 52 : c = p;
362 52 : state = next_state;
363 : }
364 113 : break;
365 :
366 : case st_error:
367 : default:
368 0 : pkg_emit_error("cannot parse pkg formula: %s", in);
369 0 : pkg_deps_formula_free(res);
370 :
371 0 : return (NULL);
372 :
373 : break;
374 : }
375 : }
376 :
377 12 : if (state != st_skip_spaces && state != st_parse_comma) {
378 0 : pkg_emit_error("cannot parse pkg formula: %s", in);
379 0 : pkg_deps_formula_free(res);
380 :
381 0 : return (NULL);
382 : }
383 :
384 12 : return (res);
385 : }
386 :
387 : void
388 12 : pkg_deps_formula_free(struct pkg_dep_formula *f)
389 : {
390 : struct pkg_dep_formula *cf, *cftmp;
391 : struct pkg_dep_formula_item *cit, *cittmp;
392 : struct pkg_dep_version_item *cver, *cvertmp;
393 : struct pkg_dep_option_item *copt, *copttmp;
394 :
395 29 : DL_FOREACH_SAFE(f, cf, cftmp) {
396 39 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
397 22 : free(cit->name);
398 :
399 38 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
400 16 : free(cver->ver);
401 16 : free(cver);
402 : }
403 :
404 24 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
405 2 : free(copt->opt);
406 2 : free(copt);
407 : }
408 :
409 22 : free(cit);
410 : }
411 :
412 17 : free(cf);
413 : }
414 12 : }
415 :
416 : static const char*
417 16 : pkg_deps_op_tostring(enum pkg_dep_version_op op)
418 : {
419 : const char *op_str;
420 :
421 16 : switch (op) {
422 : case VERSION_ANY:
423 : default:
424 0 : op_str = "?";
425 0 : break;
426 : case VERSION_EQ:
427 5 : op_str = "=";
428 5 : break;
429 : case VERSION_LE:
430 0 : op_str = "<=";
431 0 : break;
432 : case VERSION_GE:
433 2 : op_str = ">=";
434 2 : break;
435 : case VERSION_LT:
436 2 : op_str = "<";
437 2 : break;
438 : case VERSION_GT:
439 2 : op_str = ">";
440 2 : break;
441 : case VERSION_NOT:
442 5 : op_str = "!=";
443 5 : break;
444 : }
445 :
446 16 : return (op_str);
447 : }
448 :
449 : char*
450 7 : pkg_deps_formula_tostring(struct pkg_dep_formula *f)
451 : {
452 : struct pkg_dep_formula *cf, *cftmp;
453 : struct pkg_dep_formula_item *cit, *cittmp;
454 : struct pkg_dep_version_item *cver, *cvertmp;
455 : struct pkg_dep_option_item *copt, *copttmp;
456 7 : char *res = NULL, *p;
457 :
458 7 : int rlen = 0, r;
459 :
460 19 : DL_FOREACH_SAFE(f, cf, cftmp) {
461 27 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
462 15 : rlen += strlen(cit->name);
463 :
464 27 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
465 12 : rlen += strlen(cver->ver);
466 12 : rlen += 4; /* <OP><SP><VER><SP> */
467 : }
468 :
469 17 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
470 2 : rlen += strlen(copt->opt);
471 2 : rlen += 2; /* <+-><OPT><SP> */
472 : }
473 :
474 15 : rlen += 2; /* |<SP> */
475 : }
476 :
477 12 : rlen += 2; /* <,><SP> */
478 : }
479 :
480 7 : if (rlen == 0) {
481 0 : return (NULL);
482 : }
483 :
484 7 : res = malloc(rlen + 1);
485 :
486 7 : if (res == NULL) {
487 0 : pkg_emit_errno("malloc", "string");
488 :
489 0 : return (NULL);
490 : }
491 :
492 7 : p = res;
493 :
494 19 : DL_FOREACH_SAFE(f, cf, cftmp) {
495 27 : DL_FOREACH_SAFE(cf->items, cit, cittmp) {
496 15 : r = snprintf(p, rlen, "%s", cit->name);
497 15 : p += r;
498 15 : rlen -= r;
499 :
500 27 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
501 12 : r = snprintf(p, rlen, " %s %s", pkg_deps_op_tostring(cver->op),
502 : cver->ver);
503 12 : p += r;
504 12 : rlen -= r;
505 : }
506 :
507 17 : DL_FOREACH_SAFE(cit->options, copt, copttmp) {
508 2 : r = snprintf(p, rlen, " %c%s", copt->on ? '+' : '-', copt->opt);
509 2 : p += r;
510 2 : rlen -= r;
511 : }
512 :
513 15 : r = snprintf(p, rlen, "%s", cit->next ? " | " : "");
514 15 : p += r;
515 15 : rlen -= r;
516 : }
517 :
518 12 : r = snprintf(p, rlen, "%s", cf->next ? ", " : "");
519 12 : p += r;
520 12 : rlen -= r;
521 : }
522 :
523 7 : return (res);
524 : }
525 :
526 : char*
527 5 : pkg_deps_formula_tosql(struct pkg_dep_formula_item *f)
528 : {
529 : struct pkg_dep_formula_item *cit, *cittmp;
530 : struct pkg_dep_version_item *cver, *cvertmp;
531 5 : char *res = NULL, *p;
532 :
533 5 : int rlen = 0, r;
534 :
535 12 : DL_FOREACH_SAFE(f, cit, cittmp) {
536 7 : rlen += sizeof("AND (name='' )");
537 7 : rlen += strlen(cit->name);
538 :
539 11 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
540 4 : rlen += sizeof(" AND vercmp(>=, version,'') ");
541 4 : rlen += strlen(cver->ver);
542 : }
543 :
544 7 : rlen += sizeof(" OR ");
545 : }
546 :
547 5 : if (rlen == 0) {
548 0 : return (NULL);
549 : }
550 :
551 5 : res = malloc(rlen + 1);
552 :
553 5 : if (res == NULL) {
554 0 : pkg_emit_errno("malloc", "string");
555 :
556 0 : return (NULL);
557 : }
558 :
559 5 : p = res;
560 :
561 12 : DL_FOREACH_SAFE(f, cit, cittmp) {
562 7 : r = snprintf(p, rlen, "(name='%s'", cit->name);
563 7 : p += r;
564 7 : rlen -= r;
565 :
566 11 : DL_FOREACH_SAFE(cit->versions, cver, cvertmp) {
567 4 : r = snprintf(p, rlen, " AND vercmp('%s',version,'%s')",
568 : pkg_deps_op_tostring(cver->op),
569 : cver->ver);
570 4 : p += r;
571 4 : rlen -= r;
572 : }
573 7 : r = snprintf(p, rlen, ")%s", cit->next ? " OR " : "");
574 7 : p += r;
575 7 : rlen -= r;
576 : }
577 :
578 5 : return (res);
579 : }
580 :
581 : enum pkg_dep_version_op
582 11 : pkg_deps_string_toop(const char *in)
583 : {
584 11 : enum pkg_dep_version_op ret = VERSION_ANY;
585 : int len;
586 :
587 11 : if (in != NULL) {
588 10 : len = strlen(in);
589 :
590 10 : if (len == 2) {
591 5 : if (memcmp(in, ">=", 2) == 0) {
592 1 : ret = VERSION_GE;
593 : }
594 4 : else if (memcmp(in, "<=", 2) == 0) {
595 1 : ret = VERSION_LE;
596 : }
597 3 : else if (memcmp(in, "!=", 2) == 0) {
598 1 : ret = VERSION_NOT;
599 : }
600 2 : else if (memcmp(in, "==", 2) == 0) {
601 1 : ret = VERSION_EQ;
602 : }
603 : }
604 5 : else if (len == 1) {
605 5 : if (*in == '>') {
606 1 : ret = VERSION_GT;
607 : }
608 4 : else if (*in == '<') {
609 1 : ret = VERSION_LT;
610 : }
611 3 : else if (*in == '!') {
612 1 : ret = VERSION_NOT;
613 : }
614 2 : else if (*in == '=') {
615 1 : ret = VERSION_EQ;
616 : }
617 : }
618 : }
619 :
620 11 : return (ret);
621 : }
|