summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/tagtree.c142
1 files changed, 124 insertions, 18 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 12a7a74e5d..e56c805fa3 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -105,6 +105,7 @@ enum variables {
var_format,
menu_next,
menu_load,
+ menu_reload,
};
/* Capacity 10 000 entries (for example 10k different artists) */
@@ -114,6 +115,7 @@ static long uniqbuf[UNIQBUF_SIZE / sizeof(long)];
#define MAX_TAGS 5
#define MAX_MENU_ID_SIZE 32
+#define RELOAD_TAGTREE (-1024)
static bool sort_inverse;
/*
@@ -264,8 +266,12 @@ static struct buflib_callbacks ops = {
static void* tagtree_alloc(size_t size)
{
- char* buf = core_get_data(tagtree_handle) + tagtree_buf_used;
size = ALIGN_UP(size, sizeof(void*));
+ if (size > (tagtree_bufsize - tagtree_buf_used))
+ return NULL;
+
+ char* buf = core_get_data(tagtree_handle) + tagtree_buf_used;
+
tagtree_buf_used += size;
return buf;
}
@@ -273,7 +279,8 @@ static void* tagtree_alloc(size_t size)
static void* tagtree_alloc0(size_t size)
{
void* ret = tagtree_alloc(size);
- memset(ret, 0, size);
+ if (ret)
+ memset(ret, 0, size);
return ret;
}
@@ -281,7 +288,8 @@ static char* tagtree_strdup(const char* buf)
{
size_t len = strlen(buf) + 1;
char* dest = tagtree_alloc(len);
- strcpy(dest, buf);
+ if (dest)
+ strcpy(dest, buf);
return dest;
}
@@ -348,7 +356,8 @@ static int get_tag(int *tag)
{"%root_menu", var_rootmenu},
{"%format", var_format},
{"->", menu_next},
- {"==>", menu_load}
+ {"==>", menu_load},
+ {"%reload", menu_reload}
};
char buf[128];
unsigned int i;
@@ -467,7 +476,12 @@ static bool read_clause(struct tagcache_search_clause *clause)
clause->str = tagtree_strdup(buf);
}
- if (TAGCACHE_IS_NUMERIC(clause->tag))
+ if (!clause->str)
+ {
+ logf("tagtree failed to allocate %s", "clause string");
+ return false;
+ }
+ else if (TAGCACHE_IS_NUMERIC(clause->tag))
{
clause->numeric = true;
clause->numeric_data = atoi(clause->str);
@@ -581,11 +595,16 @@ static int add_format(const char *buf)
if (formats[format_count] == NULL)
formats[format_count] = tagtree_alloc0(sizeof(struct display_format));
-
+ if (!formats[format_count])
+ {
+ logf("tagtree failed to allocate %s", "format string");
+ return -2;
+ }
if (get_format_str(formats[format_count]) < 0)
{
logf("get_format_str() parser failed!");
- memset(formats[format_count], 0, sizeof(struct display_format));
+ if (formats[format_count])
+ memset(formats[format_count], 0, sizeof(struct display_format));
return -4;
}
@@ -600,7 +619,7 @@ static int add_format(const char *buf)
tagtree_lock();
while (1)
{
- struct tagcache_search_clause *newclause;
+ struct tagcache_search_clause *new_clause;
if (clause_count >= TAGCACHE_MAX_CLAUSES)
{
@@ -608,10 +627,14 @@ static int add_format(const char *buf)
break;
}
- newclause = tagtree_alloc(sizeof(struct tagcache_search_clause));
-
- formats[format_count]->clause[clause_count] = newclause;
- if (!read_clause(newclause))
+ new_clause = tagtree_alloc(sizeof(struct tagcache_search_clause));
+ if (!new_clause)
+ {
+ logf("tagtree failed to allocate %s", "search clause");
+ return -3;
+ }
+ formats[format_count]->clause[clause_count] = new_clause;
+ if (!read_clause(new_clause))
break;
clause_count++;
@@ -670,10 +693,16 @@ static int get_condition(struct search_instruction *inst)
if (clause_count >= TAGCACHE_MAX_CLAUSES)
{
logf("Too many clauses");
- return false;
+ return -2;
}
new_clause = tagtree_alloc(sizeof(struct tagcache_search_clause));
+ if (!new_clause)
+ {
+ logf("tagtree failed to allocate %s", "search clause");
+ return -3;
+ }
+
inst->clause[inst->tagorder_count][clause_count] = new_clause;
if (*strp == '|')
@@ -746,6 +775,11 @@ static bool parse_search(struct menu_entry *entry, const char *str)
/* Allocate a new menu unless link is found. */
menus[menu_count] = tagtree_alloc0(sizeof(struct menu_root));
+ if (!menus[menu_count])
+ {
+ logf("tagtree failed to allocate %s", "menu");
+ return false;
+ }
strlcpy(menus[menu_count]->id, buf, MAX_MENU_ID_SIZE);
entry->link = menu_count;
++menu_count;
@@ -1088,6 +1122,11 @@ static int parse_line(int n, char *buf, void *parameters)
if (menu == NULL)
{
menus[menu_count] = tagtree_alloc0(sizeof(struct menu_root));
+ if (!menus[menu_count])
+ {
+ logf("tagtree failed to allocate %s", "menu");
+ return -2;
+ }
menu = menus[menu_count];
++menu_count;
strlcpy(menu->id, data, MAX_MENU_ID_SIZE);
@@ -1135,7 +1174,11 @@ static int parse_line(int n, char *buf, void *parameters)
/* Allocate */
if (menu->items[menu->itemcount] == NULL)
menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry));
-
+ if (!menu->items[menu->itemcount])
+ {
+ logf("tagtree failed to allocate %s", "menu items");
+ return -2;
+ }
tagtree_lock();
if (parse_search(menu->items[menu->itemcount], buf))
menu->itemcount++;
@@ -1148,6 +1191,7 @@ static bool parse_menu(const char *filename)
{
int fd;
char buf[1024];
+ int rc;
if (menu_count >= TAGMENU_MAX_MENUS)
{
@@ -1163,10 +1207,58 @@ static bool parse_menu(const char *filename)
}
/* Now read file for real, parsing into si */
- fast_readline(fd, buf, sizeof buf, NULL, parse_line);
+ rc = fast_readline(fd, buf, sizeof buf, NULL, parse_line);
close(fd);
- return true;
+ return (rc >= 0);
+}
+
+static void tagtree_unload(struct tree_context *c)
+{
+ int i;
+ tagtree_lock();
+
+ remove_event(PLAYBACK_EVENT_TRACK_BUFFER, tagtree_buffer_event);
+ remove_event(PLAYBACK_EVENT_TRACK_FINISH, tagtree_track_finish_event);
+
+ if (c)
+ {
+ tree_lock_cache(c);
+ struct tagentry *dptr = core_get_data(c->cache.entries_handle);
+ menu = menus[c->currextra];
+ if (!menu)
+ {
+ logf("tagtree menu doesn't exist");
+ return;
+ }
+
+ for (i = 0; i < menu->itemcount; i++)
+ {
+ dptr->name = NULL;
+ dptr->newtable = 0;
+ dptr->extraseek = 0;
+ dptr++;
+ }
+ }
+
+ for (i = 0; i < menu_count; i++)
+ menus[i] = NULL;
+ menu_count = 0;
+
+ for (i = 0; i < format_count; i++)
+ formats[i] = NULL;
+ format_count = 0;
+
+ core_free(tagtree_handle);
+ tagtree_handle = 0;
+ tagtree_buf_used = 0;
+ tagtree_bufsize = 0;
+
+ if (c)
+ tree_unlock_cache(c);
+ tagtree_unlock();
+ if (lock_count > 0)
+ tagtree_unlock();/* second unlock to enable re-init */
}
void tagtree_init(void)
@@ -1176,7 +1268,11 @@ void tagtree_init(void)
menu = NULL;
rootmenu = -1;
tagtree_handle = core_alloc_maximum("tagtree", &tagtree_bufsize, &ops);
- parse_menu(FILE_SEARCH_INSTRUCTIONS);
+ if (!parse_menu(FILE_SEARCH_INSTRUCTIONS))
+ {
+ tagtree_unload(NULL);
+ return;
+ }
/* safety check since tree.c needs to cast tagentry to entry */
if (sizeof(struct tagentry) != sizeof(struct entry))
@@ -1358,6 +1454,9 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
else
tag = csi->tagorder[level];
+ if (tag == menu_reload)
+ return RELOAD_TAGTREE;
+
if (!tagcache_search(&tcs, tag))
return -1;
@@ -1691,9 +1790,16 @@ int tagtree_load(struct tree_context* c)
if (count < 0)
{
+ if (count != RELOAD_TAGTREE)
+ splash(HZ, str(LANG_TAGCACHE_BUSY));
+ else /* unload and re-init tagtree */
+ {
+ splash(HZ, str(LANG_WAIT));
+ tagtree_unload(c);
+ tagtree_init();
+ }
c->dirlevel = 0;
count = load_root(c);
- splash(HZ, str(LANG_TAGCACHE_BUSY));
}
/* The _total_ numer of entries available. */