From 32b17a4523816ca8d78cdbf15d2a135a88816f60 Mon Sep 17 00:00:00 2001 From: sideral Date: Tue, 10 May 2011 10:25:41 +0000 Subject: [PATCH] tagnavi.config: Add a logical-OR operator ("|") for tagnavi conditionals. Logical-AND ("&") always takes precedence over logical-OR. (Parentheses are not supported.) Fight binsize increase by storing some common expressions in local variables. This avoids repeated reevaluations involving memory accesses. check_clauses: Fail clause (return false) in case of errors (tag too long, DB entry deleted). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29851 a1c6a512-1295-4272-9138-f99709370657 --- apps/tagcache.c | 103 ++++++++++++++++++++++++++++++++------------------------ apps/tagcache.h | 2 +- apps/tagtree.c | 24 +++++++++---- 3 files changed, 78 insertions(+), 51 deletions(-) diff --git a/apps/tagcache.c b/apps/tagcache.c index 75191d678..7555781cb 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -984,74 +984,86 @@ static bool check_against_clause(long numeric, const char *str, static bool check_clauses(struct tagcache_search *tcs, struct index_entry *idx, - struct tagcache_search_clause **clause, int count) + struct tagcache_search_clause **clauses, int count) { int i; -#ifdef HAVE_TC_RAMCACHE - if (tcs->ramsearch) + /* Go through all conditional clauses. */ + for (i = 0; i < count; i++) { - /* Go through all conditional clauses. */ - for (i = 0; i < count; i++) + int seek; + char buf[256]; + char *str; + struct tagcache_search_clause *clause = clauses[i]; + + if (clause->type == clause_logical_or) + break; /* all conditions before logical-or satisfied -- + stop processing clauses */ + +#ifdef HAVE_TC_RAMCACHE + str = NULL; + + if (tcs->ramsearch) { struct tagfile_entry *tfe; - int seek; - char buf[256]; - char *str = NULL; - seek = check_virtual_tags(clause[i]->tag, tcs->idx_id, idx); + seek = check_virtual_tags(clause->tag, tcs->idx_id, idx); - if (!TAGCACHE_IS_NUMERIC(clause[i]->tag)) + if (!TAGCACHE_IS_NUMERIC(clause->tag)) { - if (clause[i]->tag == tag_filename) + if (clause->tag == tag_filename) { retrieve(tcs, idx, tag_filename, buf, sizeof buf); str = buf; } else { - tfe = (struct tagfile_entry *)&hdr->tags[clause[i]->tag][seek]; + tfe = (struct tagfile_entry *)&hdr->tags[clause->tag][seek]; str = tfe->tag_data; } } - - if (!check_against_clause(seek, str, clause[i])) - return false; } - } - else + else #endif - { - /* Check for conditions. */ - for (i = 0; i < count; i++) { struct tagfile_entry tfe; - int seek; - char str[256]; + str = buf; - seek = check_virtual_tags(clause[i]->tag, tcs->idx_id, idx); + seek = check_virtual_tags(clause->tag, tcs->idx_id, idx); - memset(str, 0, sizeof str); - if (!TAGCACHE_IS_NUMERIC(clause[i]->tag)) + memset(buf, 0, sizeof buf); + if (!TAGCACHE_IS_NUMERIC(clause->tag)) { - int fd = tcs->idxfd[clause[i]->tag]; + int fd = tcs->idxfd[clause->tag]; lseek(fd, seek, SEEK_SET); ecread_tagfile_entry(fd, &tfe); - if (tfe.tag_length >= (int)sizeof(str)) + if (tfe.tag_length >= (int)sizeof(buf)) { logf("Too long tag read!"); - break ; + return false; } read(fd, str, tfe.tag_length); /* Check if entry has been deleted. */ if (str[0] == '\0') + return false; + } + } + + if (!check_against_clause(seek, str, clause)) + { + /* Clause failed -- try finding a logical-or clause */ + while (++i < count) + { + if (clauses[i]->type == clause_logical_or) break; } - if (!check_against_clause(seek, str, clause[i])) - return false; + if (i < count) /* Found logical-or? */ + continue; /* Check clauses after logical-or */ + + return false; } } @@ -1369,21 +1381,24 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs, return false; } - /* Check if there is already a similar filter in present (filters are - * much faster than clauses). - */ - for (i = 0; i < tcs->filter_count; i++) - { - if (tcs->filter_tag[i] == clause->tag) - return true; - } - - if (!TAGCACHE_IS_NUMERIC(clause->tag) && tcs->idxfd[clause->tag] < 0) + if (clause->type != clause_logical_or) { - char buf[MAX_PATH]; - - snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, clause->tag); - tcs->idxfd[clause->tag] = open(buf, O_RDONLY); + /* Check if there is already a similar filter in present (filters are + * much faster than clauses). + */ + for (i = 0; i < tcs->filter_count; i++) + { + if (tcs->filter_tag[i] == clause->tag) + return true; + } + + if (!TAGCACHE_IS_NUMERIC(clause->tag) && tcs->idxfd[clause->tag] < 0) + { + char buf[MAX_PATH]; + + snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, clause->tag); + tcs->idxfd[clause->tag] = open(buf, O_RDONLY); + } } tcs->clause[tcs->clause_count] = clause; diff --git a/apps/tagcache.h b/apps/tagcache.h index 59f8b8bc9..7351998c0 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -120,7 +120,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, enum clause { clause_none, clause_is, clause_is_not, clause_gt, clause_gteq, clause_lt, clause_lteq, clause_contains, clause_not_contains, clause_begins_with, clause_not_begins_with, clause_ends_with, - clause_not_ends_with, clause_oneof }; + clause_not_ends_with, clause_oneof, clause_logical_or }; struct tagcache_stat { bool initialized; /* Is tagcache currently busy? */ diff --git a/apps/tagtree.c b/apps/tagtree.c index 2a2e2b805..e7f703154 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -461,16 +461,18 @@ static int add_format(const char *buf) while (1) { + struct tagcache_search_clause *newclause; + if (clause_count >= TAGCACHE_MAX_CLAUSES) { logf("too many clauses"); break; } - formats[format_count]->clause[clause_count] = - buffer_alloc(sizeof(struct tagcache_search_clause)); + newclause = buffer_alloc(sizeof(struct tagcache_search_clause)); - if (!read_clause(formats[format_count]->clause[clause_count])) + formats[format_count]->clause[clause_count] = newclause; + if (!read_clause(newclause)) break; clause_count++; @@ -486,6 +488,7 @@ static int add_format(const char *buf) static int get_condition(struct search_instruction *inst) { + struct tagcache_search_clause *new_clause; int clause_count; char buf[128]; @@ -530,10 +533,15 @@ static int get_condition(struct search_instruction *inst) return false; } - inst->clause[inst->tagorder_count][clause_count] = - buffer_alloc(sizeof(struct tagcache_search_clause)); + new_clause = buffer_alloc(sizeof(struct tagcache_search_clause)); + inst->clause[inst->tagorder_count][clause_count] = new_clause; - if (!read_clause(inst->clause[inst->tagorder_count][clause_count])) + if (*strp == '|') + { + strp++; + new_clause->type = clause_logical_or; + } + else if (!read_clause(new_clause)) return -1; inst->clause_count[inst->tagorder_count]++; @@ -1502,6 +1510,10 @@ int tagtree_enter(struct tree_context* c) for (j = 0; j < csi->clause_count[i]; j++) { char* searchstring; + + if (csi->clause[i][j]->type == clause_logical_or) + continue; + source = csi->clause[i][j]->source; if (source == source_constant) -- 2.11.4.GIT