about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--man/mpick.13
-rw-r--r--mpick.c38
2 files changed, 35 insertions, 6 deletions
diff --git a/man/mpick.1 b/man/mpick.1
index 64a63d1..744fa24 100644
--- a/man/mpick.1
+++ b/man/mpick.1
@@ -92,7 +92,8 @@ Unread messages.
 .Nm
 tests are given by the following EBNF:
 .Bd -literal
-<expr>     ::= <expr> || <expr>  -- disjunction
+<expr>     ::= <expr> ? <expr> : <expr>  -- ternary operator
+             | <expr> || <expr>  -- disjunction
              | <expr> && <expr>  -- conjunction
              | ! <expr>          -- negation
              | ( <expr> )
diff --git a/mpick.c b/mpick.c
index c4a4207..f9da79d 100644
--- a/mpick.c
+++ b/mpick.c
@@ -46,6 +46,7 @@
 enum op {
 	EXPR_OR = 1,
 	EXPR_AND,
+	EXPR_COND,
 	EXPR_NOT,
 	EXPR_LT,
 	EXPR_LE,
@@ -115,7 +116,7 @@ struct expr {
 		int64_t num;
 		regex_t *regex;
 		enum var var;
-	} a, b;
+	} a, b, c;
 	int extra;
 };
 
@@ -263,7 +264,7 @@ parse_op()
 }
 
 static struct expr *parse_cmp();
-static struct expr *parse_or();
+static struct expr *parse_cond();
 
 static struct expr *
 parse_inner()
@@ -285,7 +286,7 @@ parse_inner()
 		not->a.expr = e;
 		return not;
 	} else if (token("(")) {
-		struct expr *e = parse_or();
+		struct expr *e = parse_cond();
 		if (token(")"))
 			return e;
 		parse_error("missing ) at '%.15s'", pos);
@@ -723,10 +724,33 @@ parse_or()
 }
 
 static struct expr *
-parse_expr(char *s)
+parse_cond()
+{
+	struct expr *e1 = parse_or();
+
+	if (token("?")) {
+		struct expr *e2 = parse_or();
+		if (token(":")) {
+			struct expr *e3 = parse_cond();
+			struct expr *r = mkexpr(EXPR_COND);
+			r->a.expr = e1;
+			r->b.expr = e2;
+			r->c.expr = e3;
+
+			return r;
+		} else {
+			parse_error("expected : at '%.15s'", pos);
+		}
+	}
+
+	return e1;
+}
+
+static struct expr *
+parse_expr()
 {
 	pos = s;
-	struct expr *e = parse_or();
+	struct expr *e = parse_cond();
 	if (*pos)
 		parse_error("trailing garbage at '%.15s'", pos);
 	return e;
@@ -942,6 +966,10 @@ eval(struct expr *e, struct mailinfo *m)
 		return eval(e->a.expr, m) || eval(e->b.expr, m);
 	case EXPR_AND:
 		return eval(e->a.expr, m) && eval(e->b.expr, m);
+	case EXPR_COND:
+		return eval(e->a.expr, m)
+		    ? eval(e->b.expr, m)
+			: eval(e->c.expr, m);
 	case EXPR_NOT:
 		return !eval(e->a.expr, m);
 		return 1;