2 * Copyright 2005 Timo Hirvonen
8 #include <track_info.h>
20 /* #define DEBUG_EXPR */
28 #define NR_COMBINATIONS TOK_EQ
37 #define NR_SPECIALS TOK_NE
38 #define COMB_BASE TOK_NE
40 /* same as the first 3 + '=' */
49 #define NR_TOKS (TOK_STR + 1)
52 struct list_head node
;
54 /* for TOK_KEY, TOK_INT_OR_KEY and TOK_STR */
58 /* same order as TOK_* */
59 static const char specials
[NR_SPECIALS
] = "!<>=&|()";
61 static const int tok_to_op
[NR_TOKS
] = {
62 -1, OP_LT
, OP_GT
, OP_EQ
, -1, -1, -1, -1, OP_NE
, OP_LE
, OP_GE
, -1, -1, -1
65 static const char * const op_names
[NR_OPS
] = { "<", "<=", "=", ">=", ">", "!=" };
66 static const char * const expr_names
[NR_EXPRS
] = {
67 "&", "|", "!", "a string", "an integer", "a boolean"
70 static char error_buf
[64] = { 0, };
73 #define CHECK_EXPR(e) \
75 BUG_ON(e->type < 0); \
76 BUG_ON(e->type >= NR_EXPRS); \
80 BUG_ON(e->left == NULL); \
81 BUG_ON(e->right == NULL); \
85 BUG_ON(e->left == NULL); \
92 BUG_ON(e->key == NULL); \
93 BUG_ON(e->estr.op != SOP_EQ && e->estr.op != SOP_NE); \
98 BUG_ON(e->key == NULL); \
99 BUG_ON(e->eint.op < 0); \
100 BUG_ON(e->eint.op >= NR_OPS); \
105 BUG_ON(e->key == NULL); \
110 #define CHECK_EXPR(e) do { } while (0)
113 static void set_error(const char *format
, ...)
117 va_start(ap
, format
);
118 vsnprintf(error_buf
, sizeof(error_buf
), format
, ap
);
122 static struct token
*get_str(const char *str
, int *idxp
)
128 /* can't remove all backslashes here => don't remove any */
129 while (str
[e
] != '"') {
143 tok
= xmalloc(sizeof(struct token
) + e
- s
+ 1);
144 memcpy(tok
->str
, str
+ s
, e
- s
);
150 set_error("end of expression at middle of string");
154 static struct token
*get_int_or_key(const char *str
, int *idxp
)
166 for (i
= 0; i
< NR_SPECIALS
; i
++) {
167 if (c
== specials
[i
])
170 if (c
< '0' || c
> '9') {
172 if (!isalpha(c
) && c
!= '_' && c
!= '-') {
173 set_error("unexpected '%c'", c
);
180 tok
= xmalloc(sizeof(struct token
) + e
- s
+ 1);
181 memcpy(tok
->str
, str
+ s
, e
- s
);
185 tok
->type
= TOK_INT_OR_KEY
;
190 static struct token
*get_token(const char *str
, int *idxp
)
196 for (i
= 0; i
< NR_SPECIALS
; i
++) {
199 if (c
!= specials
[i
])
203 tok
= xnew(struct token
, 1);
205 if (i
< NR_COMBINATIONS
&& str
[idx
] == '=') {
206 tok
->type
= COMB_BASE
+ i
;
213 return get_str(str
, idxp
);
214 return get_int_or_key(str
, idxp
);
217 static void free_tokens(struct list_head
*head
)
219 struct list_head
*item
= head
->next
;
221 while (item
!= head
) {
222 struct list_head
*next
= item
->next
;
223 struct token
*tok
= container_of(item
, struct token
, node
);
230 static int tokenize(struct list_head
*head
, const char *str
)
238 tok
= get_token(str
, &idx
);
243 list_add_tail(&tok
->node
, head
);
248 static struct expr
*expr_new(int type
)
250 struct expr
*new = xnew(struct expr
, 1);
260 static int parse(struct expr
**rootp
, struct list_head
*head
, struct list_head
**itemp
, int level
);
262 static int parse_one(struct expr
**exprp
, struct list_head
*head
, struct list_head
**itemp
)
264 struct list_head
*item
= *itemp
;
266 enum token_type type
;
271 set_error("expression expected");
275 tok
= container_of(item
, struct token
, node
);
277 if (type
== TOK_NOT
) {
278 struct expr
*new, *tmp
;
281 rc
= parse_one(&tmp
, head
, itemp
);
284 new = expr_new(EXPR_NOT
);
288 } else if (type
== TOK_LPAREN
) {
291 return parse(exprp
, head
, itemp
, 1);
292 /* ')' already eaten */
293 } else if (type
== TOK_KEY
|| type
== TOK_INT_OR_KEY
) {
294 const char *key
= tok
->str
;
300 tok
= container_of(item
, struct token
, node
);
301 op
= tok_to_op
[tok
->type
];
303 if (item
== head
|| op
== -1) {
305 new = expr_new(EXPR_BOOL
);
306 new->key
= xstrdup(key
);
313 set_error("right side of expression expected");
316 tok
= container_of(item
, struct token
, node
);
319 if (type
== TOK_STR
) {
320 if (op
!= OP_EQ
&& op
!= OP_NE
) {
321 set_error("invalid string operator '%s'", op_names
[op
]);
324 new = expr_new(EXPR_STR
);
325 new->key
= xstrdup(key
);
326 glob_compile(&new->estr
.glob_head
, tok
->str
);
330 } else if (type
== TOK_INT_OR_KEY
) {
333 if (str_to_int(tok
->str
, &val
)) {
335 new = expr_new(EXPR_INT
);
336 new->key
= xstrdup(key
);
342 if (op
== OP_EQ
|| op
== OP_NE
) {
343 set_error("integer or string expected");
345 set_error("integer expected");
349 set_error("key expected");
353 static void add(struct expr
**rootp
, struct expr
*expr
)
355 struct expr
*tmp
, *root
= *rootp
;
357 BUG_ON(expr
== NULL
);
366 if (tmp
->type
<= EXPR_OR
) {
367 /* tmp is binary, tree is incomplete */
373 /* tmp is unary, tree is complete
374 * expr must be a binary operator */
375 BUG_ON(expr
->type
> EXPR_OR
);
382 static int parse(struct expr
**rootp
, struct list_head
*head
, struct list_head
**itemp
, int level
)
384 struct list_head
*item
= *itemp
;
391 rc
= parse_one(&expr
, head
, &item
);
397 set_error("')' expected");
403 tok
= container_of(item
, struct token
, node
);
404 if (tok
->type
== TOK_RPAREN
) {
406 set_error("unexpected ')'");
413 if (tok
->type
== TOK_AND
) {
415 } else if (tok
->type
== TOK_OR
) {
418 set_error("'&' or '|' expected");
421 expr
= expr_new(type
);
427 struct expr
*expr_parse(const char *str
)
430 struct expr
*root
= NULL
;
431 struct list_head
*item
;
434 for (i
= 0; str
[i
]; i
++) {
435 unsigned char c
= str
[i
];
437 set_error("filter contains control characters");
441 if (!u_is_valid(str
)) {
442 set_error("invalid UTF-8");
446 if (tokenize(&head
, str
))
450 if (parse(&root
, &head
, &item
, 0))
456 static const struct {
460 { "album", EXPR_STR
},
461 { "artist", EXPR_STR
},
462 { "date", EXPR_INT
},
463 { "discnumber", EXPR_INT
},
464 { "duration", EXPR_INT
},
465 { "filename", EXPR_STR
},
466 { "genre", EXPR_STR
},
467 { "stream", EXPR_BOOL
},
468 { "tag", EXPR_BOOL
},
469 { "title", EXPR_STR
},
470 { "tracknumber",EXPR_INT
},
474 int expr_check_leaves(struct expr
**exprp
, const char *(*get_filter
)(const char *name
))
476 struct expr
*expr
= *exprp
;
482 if (expr_check_leaves(&expr
->left
, get_filter
))
485 return expr_check_leaves(&expr
->right
, get_filter
);
489 for (i
= 0; builtin
[i
].key
; i
++) {
490 int cmp
= strcmp(expr
->key
, builtin
[i
].key
);
497 if (builtin
[i
].type
!= expr
->type
) {
499 set_error("%s is %s", builtin
[i
].key
, expr_names
[builtin
[i
].type
]);
504 if (expr
->type
!= EXPR_BOOL
) {
506 set_error("unkown key %s", expr
->key
);
510 /* user defined filter */
511 filter
= get_filter(expr
->key
);
512 if (filter
== NULL
) {
513 set_error("unkown filter or boolean %s", expr
->key
);
516 e
= expr_parse(filter
);
520 rc
= expr_check_leaves(&e
, get_filter
);
527 e
->parent
= expr
->parent
;
530 /* this sets parents left pointer */
535 int expr_eval(struct expr
*expr
, struct track_info
*ti
)
537 enum expr_type type
= expr
->type
;
542 int left
= expr_eval(expr
->left
, ti
);
544 if (type
== EXPR_AND
)
545 return left
&& expr_eval(expr
->right
, ti
);
547 return left
|| expr_eval(expr
->right
, ti
);
553 if (type
== EXPR_STR
) {
557 if (strcmp(key
, "filename") == 0) {
560 val
= comments_get_val(ti
->comments
, key
);
562 /* NULL="something" is false */
563 if (expr
->estr
.op
== SOP_EQ
)
565 /* NULL!="something" is true */
569 res
= glob_match(&expr
->estr
.glob_head
, val
);
570 if (expr
->estr
.op
== SOP_EQ
)
573 } else if (type
== EXPR_INT
) {
576 if (strcmp(key
, "duration") == 0) {
578 /* duration of a stream is infinite (well, almost) */
579 if (is_url(ti
->filename
))
582 val
= comments_get_int(ti
->comments
, key
);
584 if (expr
->eint
.val
== -1) {
586 * doesn't make sense to do 123 < "not set"
587 * but it makes sense to do date=-1 (date is not set)
589 if (expr
->eint
.op
== IOP_EQ
)
591 if (expr
->eint
.op
== IOP_NE
)
595 /* tag not set, can't compare */
598 res
= val
- expr
->eint
.val
;
599 switch (expr
->eint
.op
) {
614 if (strcmp(key
, "stream") == 0)
615 return is_url(ti
->filename
);
616 return track_info_has_tag(ti
);
619 void expr_free(struct expr
*expr
)
622 expr_free(expr
->left
);
624 expr_free(expr
->right
);
627 if (expr
->type
== EXPR_STR
)
628 glob_free(&expr
->estr
.glob_head
);
632 const char *expr_error(void)