MINOR: cfgcond: support terms made of parenthesis around expressions

Now it's possible to form a term using parenthesis around an expression.
This will soon allow to build more complex expressions. For now they're
still pretty limited but parenthesis do work.
This commit is contained in:
Willy Tarreau 2021-07-16 14:56:59 +02:00
parent ca81887599
commit 316ea7ede5
3 changed files with 37 additions and 1 deletions

View File

@ -811,6 +811,7 @@ expression made of any combination of:
- the integer zero ('0'), always returns "false"
- a non-nul integer (e.g. '1'), always returns "true".
- a predicate optionally followed by argument(s) in parenthesis.
- a condition placed between a pair of parenthesis '(' and ')'
- a question mark ('!') preceeding any of the non-empty elements above, and
which will negate its status.
- expressions combined with a logical AND ('&&'), which will be evaluated
@ -861,7 +862,7 @@ Example:
.endif
.endif
.if streq("$WITH_SSL",yes) && feature(OPENSSL)
.if feature(OPENSSL) && (streq("$WITH_SSL",yes) || streq("$SSL_ONLY",yes))
bind :443 ssl crt ...
.endif

View File

@ -58,6 +58,7 @@ enum cfg_cond_term_type {
CCTT_FALSE,
CCTT_TRUE,
CCTT_PRED,
CCTT_PAREN, // '(' EXPR ')'
};
/* keyword for a condition predicate */
@ -74,6 +75,7 @@ struct cfg_cond_term {
int neg; // 0: direct result; 1: negate
union {
const struct cond_pred_kw *pred; // predicate (function)
struct cfg_cond_expr *expr; // expression for CCTT_PAREN
};
};

View File

@ -51,6 +51,9 @@ void cfg_free_cond_term(struct cfg_cond_term **term)
if (!term || !*term)
return;
if ((*term)->type == CCTT_PAREN)
cfg_free_cond_expr(&(*term)->expr);
free_args((*term)->args);
free((*term)->args);
ha_free(term);
@ -104,6 +107,32 @@ int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **e
return 1;
}
/* Try to parse '(' EXPR ')' */
if (*in == '(') {
int ret;
t->type = CCTT_PAREN;
t->args = NULL;
do { in++; } while (*in == ' ' || *in == '\t');
ret = cfg_parse_cond_expr(&in, &t->expr, err, errptr);
if (ret == -1)
goto fail2;
if (ret == 0)
goto fail0;
/* find the closing ')' */
while (*in == ' ' || *in == '\t')
in++;
if (*in != ')') {
memprintf(err, "expected ')' after conditional expression '%s'", *text);
goto fail1;
}
do { in++; } while (*in == ' ' || *in == '\t');
*text = in;
return 1;
}
/* below we'll likely all make_arg_list() so we must return only via
* the <done> label which frees the arg list.
*/
@ -123,6 +152,7 @@ int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **e
return 1;
}
fail0:
memprintf(err, "unparsable conditional expression '%s'", *text);
fail1:
if (errptr)
@ -196,6 +226,9 @@ int cfg_eval_cond_term(const struct cfg_cond_term *term, char **err)
break;
}
}
else if (term->type == CCTT_PAREN) {
ret = cfg_eval_cond_expr(term->expr, err);
}
else {
memprintf(err, "internal error: unhandled condition term type %d", (int)term->type);
}