diff --git a/apps/tagcache.c b/apps/tagcache.c index 6567a781f8..25728fa6f1 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -132,7 +132,7 @@ static int total_entry_count = 0; static int data_size = 0; static int processed_dir_count; -static bool is_numeric_tag(int type) +bool tagcache_is_numeric_tag(int type) { int i; @@ -326,11 +326,9 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve) long tagcache_get_numeric(const struct tagcache_search *tcs, int tag) { - struct tagcache_header tch; struct index_entry idx; - int masterfd; - if (!is_numeric_tag(tag)) + if (!tagcache_is_numeric_tag(tag)) return -1; #ifdef HAVE_TC_RAMCACHE @@ -340,34 +338,48 @@ long tagcache_get_numeric(const struct tagcache_search *tcs, int tag) } #endif - masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY); - - if (masterfd < 0) - { - logf("open fail"); - return -2; - } - - if (read(masterfd, &tch, sizeof(struct tagcache_header)) != - sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC) - { - logf("header error"); - return -3; - } - - lseek(masterfd, tcs->idx_id * sizeof(struct index_entry), SEEK_CUR); - if (read(masterfd, &idx, sizeof(struct index_entry)) != + lseek(tcs->masterfd, tcs->idx_id * sizeof(struct index_entry), SEEK_CUR); + if (read(tcs->masterfd, &idx, sizeof(struct index_entry)) != sizeof(struct index_entry)) { logf("read error #3"); - close(masterfd); return -4; } - close(masterfd); return idx.tag_seek[tag]; } +static bool check_against_clause(long numeric, const char *str, + const struct tagcache_search_clause *clause) +{ + switch (clause->type) + { + case clause_is: + if (clause->numeric) + return numeric == clause->numeric_data; + else + return !strcasecmp(clause->str, str); + + case clause_gt: + return numeric > clause->numeric_data; + case clause_gteq: + return numeric >= clause->numeric_data; + case clause_lt: + return numeric < clause->numeric_data; + case clause_lteq: + return numeric <= clause->numeric_data; + + case clause_contains: + return (strcasestr(str, clause->str) != NULL); + case clause_begins_with: + return (strcasestr(str, clause->str) == str); + case clause_ends_with: /* Not supported yet */ + return false; + } + + return false; +} + static bool build_lookup_list(struct tagcache_search *tcs) { struct tagcache_header header; @@ -382,7 +394,7 @@ static bool build_lookup_list(struct tagcache_search *tcs) { int j; - for (i = tcs->seek_pos; i < hdr->h.entry_count - tcs->seek_pos; i++) + for (i = tcs->seek_pos; i < hdr->h.entry_count; i++) { if (tcs->seek_list_count == SEEK_LIST_SIZE) break ; @@ -397,6 +409,25 @@ static bool build_lookup_list(struct tagcache_search *tcs) if (j < tcs->filter_count) continue ; + for (j = 0; j < tcs->clause_count; j++) + { + int seek = hdr->indices[i].tag_seek[tcs->clause[j]->tag]; + char *str = NULL; + struct tagfile_entry *entry; + + if (!tagcache_is_numeric_tag(tcs->clause[j]->tag)) + { + entry = (struct tagfile_entry *)&hdr->tags[tcs->clause[j]->tag][seek]; + str = entry->tag_data; + } + + if (!check_against_clause(seek, str, tcs->clause[j])) + break ; + } + + if (j < tcs->clause_count) + continue ; + /* Add to the seek list if not already there. */ for (j = 0; j < tcs->seek_list_count; j++) { @@ -455,6 +486,26 @@ static bool build_lookup_list(struct tagcache_search *tcs) if (i < tcs->filter_count) continue ; + /* Check for conditions. */ + for (i = 0; i < tcs->clause_count; i++) + { + int seek = entry.tag_seek[tcs->clause[i]->tag]; + char str[64]; + + memset(str, 0, sizeof str); + if (!tagcache_is_numeric_tag(tcs->clause[i]->tag)) + { + /* FIXME: Not yet implemented. */ + // str = &hdr->tags[tcs->clause[i].tag][seek]; + } + + if (!check_against_clause(seek, str, tcs->clause[i])) + break ; + } + + if (i < tcs->clause_count) + continue ; + /* Add to the seek list if not already there. */ for (i = 0; i < tcs->seek_list_count; i++) { @@ -484,6 +535,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag) if (tcs->valid) tagcache_search_finish(tcs); + memset(tcs, 0, sizeof(struct tagcache_search)); tcs->position = sizeof(struct tagcache_header); tcs->fd = -1; tcs->type = tag; @@ -491,6 +543,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag) tcs->seek_list_count = 0; tcs->filter_count = 0; tcs->valid = true; + tcs->masterfd = -1; #ifndef HAVE_TC_RAMCACHE tcs->ramsearch = false; @@ -503,7 +556,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag) else #endif { - if (is_numeric_tag(tcs->type)) + if (tagcache_is_numeric_tag(tcs->type)) return true; snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, tcs->type); @@ -521,6 +574,23 @@ bool tagcache_search(struct tagcache_search *tcs, int tag) logf("incorrect header"); return false; } + + tcs->masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY); + + if (tcs->masterfd < 0) + { + logf("open fail"); + return false; + } + + if (read(tcs->masterfd, &h, sizeof(struct tagcache_header)) != + sizeof(struct tagcache_header) || h.magic != TAGCACHE_MAGIC) + { + logf("header error"); + close(tcs->masterfd); + tcs->masterfd = -1; + return false; + } } return true; @@ -539,6 +609,21 @@ bool tagcache_search_add_filter(struct tagcache_search *tcs, return true; } +bool tagcache_search_add_clause(struct tagcache_search *tcs, + struct tagcache_search_clause *clause) +{ + if (tcs->clause_count >= TAGCACHE_MAX_CLAUSES) + { + logf("Too many clauses"); + return false; + } + + tcs->clause[tcs->clause_count] = clause; + tcs->clause_count++; + + return true; +} + bool tagcache_get_next(struct tagcache_search *tcs) { static char buf[MAX_PATH]; @@ -547,7 +632,7 @@ bool tagcache_get_next(struct tagcache_search *tcs) if (!tcs->valid) return false; - if (tcs->fd < 0 && !is_numeric_tag(tcs->type) + if (tcs->fd < 0 && !tagcache_is_numeric_tag(tcs->type) #ifdef HAVE_TC_RAMCACHE && !tcs->ramsearch #endif @@ -555,11 +640,11 @@ bool tagcache_get_next(struct tagcache_search *tcs) return false; /* Searching not supported for numeric tags yet. */ - if (is_numeric_tag(tcs->type)) + if (tagcache_is_numeric_tag(tcs->type)) return false; /* Relative fetch. */ - if (tcs->filter_count > 0) + if (tcs->filter_count > 0 || tcs->clause_count > 0) { /* Check for end of list. */ if (tcs->seek_list_count == 0) @@ -672,9 +757,16 @@ void tagcache_search_finish(struct tagcache_search *tcs) { close(tcs->fd); tcs->fd = -1; - tcs->ramsearch = false; - tcs->valid = false; } + + if (tcs->masterfd >= 0) + { + close(tcs->masterfd); + tcs->masterfd = -1; + } + + tcs->ramsearch = false; + tcs->valid = false; } #ifdef HAVE_TC_RAMCACHE @@ -846,7 +938,7 @@ static void remove_files(void) remove(TAGCACHE_FILE_MASTER); for (i = 0; i < TAG_COUNT; i++) { - if (is_numeric_tag(i)) + if (tagcache_is_numeric_tag(i)) continue; snprintf(buf, sizeof buf, TAGCACHE_FILE_INDEX, i); @@ -1593,7 +1685,7 @@ static bool commit(void) /* Now create the index files. */ for (i = 0; i < TAG_COUNT; i++) { - if (is_numeric_tag(i)) + if (tagcache_is_numeric_tag(i)) { build_numeric_index(i, &header, tmpfd); } @@ -1760,7 +1852,7 @@ static bool load_tagcache(void) struct tagfile_entry *fe; char buf[MAX_PATH]; - if (is_numeric_tag(i)) + if (tagcache_is_numeric_tag(i)) continue ; //p = ((void *)p+1); diff --git a/apps/tagcache.h b/apps/tagcache.h index ddbb8e1dac..052d71b42b 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -39,14 +39,30 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define SEEK_LIST_SIZE 50 #define TAGCACHE_MAX_FILTERS 3 +#define TAGCACHE_MAX_CLAUSES 10 + +enum clause { clause_none, clause_is, clause_gt, clause_gteq, clause_lt, + clause_lteq, clause_contains, clause_begins_with, clause_ends_with }; +enum modifies { clause_mod_none, clause_mod_not }; + +struct tagcache_search_clause +{ + int tag; + int type; + bool numeric; + long numeric_data; + char str[32]; +}; struct tagcache_search { /* For internal use only. */ - int fd; + int fd, masterfd; long seek_list[SEEK_LIST_SIZE]; long filter_tag[TAGCACHE_MAX_FILTERS]; long filter_seek[TAGCACHE_MAX_FILTERS]; int filter_count; + struct tagcache_search_clause *clause[TAGCACHE_MAX_CLAUSES]; + int clause_count; int seek_list_count; int seek_pos; int idx_id; @@ -62,9 +78,12 @@ struct tagcache_search { long result_seek; }; +bool tagcache_is_numeric_tag(int type); bool tagcache_search(struct tagcache_search *tcs, int tag); bool tagcache_search_add_filter(struct tagcache_search *tcs, int tag, int seek); +bool tagcache_search_add_clause(struct tagcache_search *tcs, + struct tagcache_search_clause *clause); bool tagcache_get_next(struct tagcache_search *tcs); void tagcache_search_finish(struct tagcache_search *tcs); long tagcache_get_numeric(const struct tagcache_search *tcs, int tag);