tagtree add %reload to allow hot reloading of tagnavi config

adds (static) function tagtree_unload
 frees all buflib allocations for tagtree

adds command %reload that allows a new tagnavi file to be loaded
without device restart
use it like so..
"Reload..." -> %reload

Allocations are now checked for validity (probably a good idea anyway)

Change-Id: I2b4b9b7e253f97f3e6575e0ea7a92905e004d47f
This commit is contained in:
William Wilgus 2019-07-29 20:49:41 -05:00
parent d3a3a41b0f
commit 501404d703

View file

@ -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,6 +279,7 @@ static void* tagtree_alloc(size_t size)
static void* tagtree_alloc0(size_t size)
{
void* ret = tagtree_alloc(size);
if (ret)
memset(ret, 0, size);
return ret;
}
@ -281,6 +288,7 @@ static char* tagtree_strdup(const char* buf)
{
size_t len = strlen(buf) + 1;
char* dest = tagtree_alloc(len);
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,10 +595,15 @@ 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!");
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. */