-diff -ur poldek-0.42.2/capreq.h poldek-0.42.2-boolean-deps/capreq.h
---- poldek-0.42.2/capreq.h 2020-01-25 22:59:59.000000000 +0100
-+++ poldek-0.42.2-boolean-deps/capreq.h 2022-06-08 20:48:12.797280673 +0200
-@@ -58,6 +58,22 @@
- char _buff[0]; /* for evr, first byte is always '\0' */
- };
-
-+#define CAPREQ_BOOL_OP_AND (1 << 0)
-+#define CAPREQ_BOOL_OP_OR (1 << 1)
-+#define CAPREQ_BOOL_OP_IF (1 << 2)
-+#define CAPREQ_BOOL_OP_UNLESS (1 << 3)
-+#define CAPREQ_BOOL_OP_ELSE (1 << 4)
-+#define CAPREQ_BOOL_OP_WITH (1 << 5)
-+#define CAPREQ_BOOL_OP_WITHOUT (1 << 6)
-+
-+struct boolean_req {
-+ uint16_t op; // and, or, ir (else), with, without, unless (else)
-+ struct capreq* req;
-+ struct boolean_req* left; // left (and|or|with|without) right
-+ struct boolean_req* leftn; // left (if|unless) right (else leftn)
-+ struct boolean_req* right;
-+};
-+
- /* CAUTION: side effects! */
- #define capreq_name(cr) (cr)->name
- #define capreq_name_len(cr) (cr)->namelen
-diff -ur poldek-0.42.2/install3/requirements.c poldek-0.42.2-boolean-deps/install3/requirements.c
---- poldek-0.42.2/install3/requirements.c 2020-04-06 14:24:18.000000000 +0200
-+++ poldek-0.42.2-boolean-deps/install3/requirements.c 2022-06-08 20:48:12.797280673 +0200
-@@ -16,13 +16,163 @@
-
- #include "ictx.h"
-
--static int skip_boolean_dep(const struct capreq *cr) {
-- if (capreq_is_boolean(cr)) {
-- logn(LOGWARN, "%s: skipping boolean dependency (not supported yet)",
-- capreq_stra(cr));
-- return 1;
-+static struct BooleanOpComp {
-+ const char *n;
-+ int l;
-+ uint16_t op;
-+} BooleanOps[] = {
-+ { "and", 3, CAPREQ_BOOL_OP_AND },
-+ { "or", 2, CAPREQ_BOOL_OP_OR },
-+ { "if", 2, CAPREQ_BOOL_OP_IF },
-+ { "unless", 6, CAPREQ_BOOL_OP_UNLESS },
-+ { "with", 4, CAPREQ_BOOL_OP_WITH },
-+ { "without", 7, CAPREQ_BOOL_OP_WITHOUT },
-+ { NULL, 0, 0},
-+};
-+
-+static struct capreq* parse_single_dep(char *req, int *len) {
-+ char *q, *cap, *name, *evr = NULL;
-+ int name_len, evr_len;
-+ struct capreq* cr = NULL;
-+ uint16_t op;
-+
-+ cap = q = strdup(req);
-+ DBGF("dep: %s", q);
-+ // skip whitespace
-+ while (*q == ' ')
-+ q++;
-+ DBGF("ltrim: %s", q);
-+ name = q;
-+ // look for the end of normal dep
-+ while (*q != ' ')
-+ q++;
-+ name_len = q - name;
-+ DBGF("to parse: %s, name: %s, name_len: %d", q, name, name_len);
-+ while (*q == ' ')
-+ q++;
-+ DBGF("ltrim: %s", q);
-+ op = 0;
-+ while (*q != ' ') {
-+ if (*q == '<')
-+ op |= REL_LT;
-+ else if (*q == '=')
-+ op |= REL_EQ;
-+ else if (*q == '>')
-+ op |= REL_GT;
-+ else
-+ break;
-+ q++;
-+ }
-+ DBGF("to parse: %s, op: %d", q, op);
-+ while (*q == ' ')
-+ q++;
-+ DBGF("ltrim: %s", q);
-+ if (op) {
-+ evr = q;
-+ while (*q != ' ' && *q != ')')
-+ q++;
-+ evr_len = q - evr;
-+ DBGF("to parse: evr: %s, evr_len: %d", evr, evr_len);
-+ }
-+ DBGF("to parse: %s", q);
-+ while (*q == ' ')
-+ q++;
-+ DBGF("ltrim: %s", q);
-+ *len = q - cap;
-+ *(name + name_len) = '\0';
-+ DBGF("name: %s, name_len: %d", name, name_len);
-+ if (evr) {
-+ *(evr + evr_len) = '\0';
-+ DBGF("evr: %s, evr_len: %d", evr, evr_len);
-+ }
-+ cr = capreq_new_evr(NULL, name, evr, op, 0);
-+ free(cap);
-+ return cr;
-+}
-+
-+static struct boolean_req* parse_boolean_dep(const char *strreq, uint16_t op, int* len) {
-+ char *p, *q, *cap;
-+ struct boolean_req *breq;
-+ int parsed_len;
-+ struct BooleanOpComp *o;
-+
-+ cap = p = strdup(strreq);
-+ // boolean dep must start with '(' except if we're chaining 'and' or 'or'
-+ if (op != CAPREQ_BOOL_OP_AND && op != CAPREQ_BOOL_OP_OR) {
-+ if (*p != '(')
-+ return NULL;
-+ p++;
-+ }
-+ DBGF("breq: %s", p);
-+ breq = malloc(sizeof(struct boolean_req));
-+ bzero(breq, sizeof(struct boolean_req));
-+ // skip whitespace
-+ while (*p == ' ')
-+ p++;
-+ DBGF("breq ltrim: %s", p);
-+ // nested dep
-+ q = p;
-+ if (*p == '(')
-+ breq->left = parse_boolean_dep(p, 0, &parsed_len);
-+ else
-+ breq->req = parse_single_dep(p, &parsed_len);
-+ q += parsed_len;
-+ DBGF("breq to parse: %s", q);
-+ if (*q == ')') {
-+ if (len)
-+ *len = q - cap;
-+ return breq;
- }
-- return 0;
-+
-+ for (o = BooleanOps; o->n; o++)
-+ if (!strncmp(q, o->n, o->l))
-+ break;
-+ breq->op = o->op;
-+ if (!breq->op) {
-+ DBGF("fail no-op");
-+ return NULL;
-+ }
-+ q += o->l;
-+ while (*q == ' ')
-+ q++;
-+ if (*q == '(')
-+ breq->right = parse_boolean_dep(q, breq->op, &parsed_len);
-+ else {
-+ breq->right = malloc(sizeof(struct boolean_req));
-+ bzero(breq->right, sizeof(struct boolean_req));
-+ breq->right->req = parse_single_dep(q, &parsed_len);
-+ }
-+ q += parsed_len;
-+ if (*q == ')') {
-+ if (len)
-+ *len = q - cap;
-+ return breq;
-+ }
-+
-+ if (breq->op == CAPREQ_BOOL_OP_IF || breq->op == CAPREQ_BOOL_OP_UNLESS) {
-+ if (!strncmp(q, "else", 4)) {
-+ q += 4;
-+ while (*q == ' ')
-+ q++;
-+ if (*q == '(')
-+ breq->leftn = parse_boolean_dep(q, breq->op, &parsed_len);
-+ else {
-+ breq->leftn = malloc(sizeof(struct boolean_req));
-+ bzero(breq->leftn, sizeof(struct boolean_req));
-+ breq->leftn->req = parse_single_dep(q, &parsed_len);
-+ }
-+ }
-+ }
-+ while (*q == ' ')
-+ q++;
-+ if (*q != ')' && op != CAPREQ_BOOL_OP_AND && op != CAPREQ_BOOL_OP_OR) {
-+ DBGF("fail no closing paren");
-+ return NULL;
-+ }
-+
-+ if (len)
-+ *len = q - cap;
-+ return breq;
- }
-
- static
-@@ -553,8 +703,11 @@
-
- }
-
-+
-+// i3pkg - package to be installed
-+// req - dependency we are looking for
- static int process_req(int indent, struct i3ctx *ictx,
-- struct i3pkg *i3pkg, const struct capreq *req)
-+ struct i3pkg *i3pkg, const struct capreq *req, int boolean)
- {
- struct poldek_ts *ts = ictx->ts; /* just for short */
- struct pkg *pkg, *tomark = NULL;
-@@ -644,7 +797,8 @@
- else
- errfmt = _("%s: req %s not found");
-
-- i3_error(ictx, pkg, I3ERR_NOTFOUND, errfmt, pkg_id(pkg), strreq);
-+ if (boolean == 0)
-+ i3_error(ictx, pkg, I3ERR_NOTFOUND, errfmt, pkg_id(pkg), strreq);
- rc = 0;
-
- l_end:
-@@ -653,6 +807,49 @@
- return rc;
- }
-
-+static int process_boolean_req(int indent, struct i3ctx *ictx,
-+ struct i3pkg *i3pkg, const struct boolean_req *breq)
-+{
-+ int rcl, rcr, rce;
-+ if (breq->req)
-+ rcl = process_req(indent, ictx, i3pkg, breq->req, 1);
-+ else
-+ rcl = process_boolean_req(indent, ictx, i3pkg, breq->left);
-+ if (breq->op != CAPREQ_BOOL_OP_OR)
-+ if (breq->right)
-+ rcr = process_boolean_req(indent, ictx, i3pkg, breq->right);
-+ else
-+ return rcl;
-+ switch (breq->op) {
-+ case CAPREQ_BOOL_OP_AND:
-+ return (rcl > 0 && rcr > 0) ? 1 : -1;
-+ case CAPREQ_BOOL_OP_OR:
-+ if (rcl <= 0 && breq->right)
-+ return process_boolean_req(indent, ictx, i3pkg, breq->right);
-+ return rcl;
-+ case CAPREQ_BOOL_OP_IF:
-+ if (rcr > 0)
-+ return rcl;
-+ if (breq->leftn)
-+ return process_boolean_req(indent, ictx, i3pkg, breq->leftn);
-+ return 1;
-+ case CAPREQ_BOOL_OP_UNLESS:
-+ if (rcr <= 0)
-+ return rcl;
-+ if (breq->leftn)
-+ return process_boolean_req(indent, ictx, i3pkg, breq->leftn);
-+ return 1;
-+ case CAPREQ_BOOL_OP_WITH:
-+ // TODO: check that both deps are stisfied by the same package
-+ return (rcl > 0 && rcr > 0) ? 1 : -1;
-+ case CAPREQ_BOOL_OP_WITHOUT:
-+ // TODO: check that both deps are stisfied by the same package
-+ return (rcl > 0 && rcr <= 0) ? 1 : -1;
-+ default:
-+ return -1;
-+ }
-+ return -1;
-+}
-
- static tn_array *with_suggests(int indent, struct i3ctx *ictx, struct pkg *pkg)
- {
-@@ -660,6 +857,7 @@
- struct pkg *oldpkg = NULL;
- char *autochoice = NULL; /* testing only */
- int i;
-+ struct boolean_req* breq;
-
- if (pkg->sugs == NULL)
- return NULL;
-@@ -693,8 +891,14 @@
-
- //trace(indent, "%d) suggested %s", i, reqstr);
-
-- if (skip_boolean_dep(req))
-+ if (capreq_is_boolean(req)) {
-+ logn(LOGWARN, "%s: skipping boolean dependency (weak deps not supported yet)",
-+ capreq_stra(req));
-+ // TODO
-+ // breq = parse_boolean_dep(capreq_name(req), 0, NULL);
-+ // process_boolean_req(indent, ictx, i3pkg, breq);
- continue;
-+ }
-
- if (iset_provides(ictx->inset, req)) {
- trace(indent, "- %s: already marked", reqstr);
-@@ -791,6 +995,7 @@
- const struct capreq *req = NULL;
- unsigned itflags = PKG_ITER_REQIN;
- int nerrors = 0, backtrack = 0;
-+ struct boolean_req* breq;
-
- pkg = i3pkg->pkg;
- n_assert(pkg);
-@@ -806,10 +1011,18 @@
- while ((req = pkg_req_iter_get(it))) {
- int rc;
-
-- if (skip_boolean_dep(req))
-- continue;
-+ if (capreq_is_boolean(req)) {
-+ msgn_i(1, indent, "%s required by %s",
-+ capreq_stra(req), pkg->name ? pkg->name : "(null)");
-+ breq = parse_boolean_dep(capreq_name(req), 0, NULL);
-+ rc = process_boolean_req(indent + 2, ictx, i3pkg, breq);
-+ if (rc <= 0)
-+ i3_error(ictx, i3pkg->pkg, I3ERR_NOTFOUND, _("%s: req %s not found"), pkg_id(i3pkg->pkg), capreq_stra(req));
-+ } else {
-+ rc = process_req(indent, ictx, i3pkg, req, 0);
-+ }
-
-- if ((rc = process_req(indent, ictx, i3pkg, req)) <= 0) {
-+ if (rc <= 0) {
- nerrors++;
- if (rc < 0) {
- backtrack = 1;
-@@ -836,7 +1049,7 @@
-
- req = n_array_nth(suggests, i);
-
-- if ((rc = process_req(indent, ictx, i3pkg, req)) <= 0) {
-+ if ((rc = process_req(indent, ictx, i3pkg, req, 0)) <= 0) {
- nerrors++;
- if (rc < 0) {
- backtrack = 1;