summaryrefslogtreecommitdiff
path: root/apps/tagtree.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/tagtree.c')
-rw-r--r--apps/tagtree.c229
1 files changed, 181 insertions, 48 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 0d4330bac8..5766d2892e 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -53,6 +53,7 @@
53#include "storage.h" 53#include "storage.h"
54#include "dir.h" 54#include "dir.h"
55#include "playback.h" 55#include "playback.h"
56#include "panic.h"
56 57
57#define str_or_empty(x) (x ? x : "(NULL)") 58#define str_or_empty(x) (x ? x : "(NULL)")
58 59
@@ -60,6 +61,17 @@
60 61
61static int tagtree_play_folder(struct tree_context* c); 62static int tagtree_play_folder(struct tree_context* c);
62 63
64/* this needs to be same size as struct entry (tree.h) and name needs to be
65 * the first; so that they're compatible enough to walk arrays of both
66 * derefencing the name member*/
67struct tagentry {
68 char* name;
69 int newtable;
70 int extraseek;
71};
72
73static struct tagentry* tagtree_get_entry(struct tree_context *c, int id);
74
63#define SEARCHSTR_SIZE 256 75#define SEARCHSTR_SIZE 256
64 76
65enum table { 77enum table {
@@ -96,7 +108,7 @@ enum variables {
96 108
97/* Capacity 10 000 entries (for example 10k different artists) */ 109/* Capacity 10 000 entries (for example 10k different artists) */
98#define UNIQBUF_SIZE (64*1024) 110#define UNIQBUF_SIZE (64*1024)
99static long *uniqbuf; 111static long uniqbuf[UNIQBUF_SIZE / sizeof(long)];
100 112
101#define MAX_TAGS 5 113#define MAX_TAGS 5
102#define MAX_MENU_ID_SIZE 32 114#define MAX_MENU_ID_SIZE 32
@@ -163,8 +175,8 @@ struct match
163/* Statusbar text of the current view. */ 175/* Statusbar text of the current view. */
164static char current_title[MAX_TAGS][128]; 176static char current_title[MAX_TAGS][128];
165 177
166static struct menu_root *menus[TAGMENU_MAX_MENUS]; 178static struct menu_root * menus[TAGMENU_MAX_MENUS];
167static struct menu_root *menu; 179static struct menu_root * menu;
168static struct search_instruction *csi; 180static struct search_instruction *csi;
169static const char *strp; 181static const char *strp;
170static int menu_count; 182static int menu_count;
@@ -176,8 +188,74 @@ static int current_entry_count;
176static struct tree_context *tc; 188static struct tree_context *tc;
177 189
178/* a few memory alloc helper */ 190/* a few memory alloc helper */
179static int tagtree_handle; 191static int tagtree_handle, lock_count;
180static size_t tagtree_bufsize, tagtree_buf_used; 192static size_t tagtree_bufsize, tagtree_buf_used;
193
194#define UPDATE(x, y) { x = (typeof(x))((char*)(x) + (y)); }
195static int move_callback(int handle, void* current, void* new)
196{
197 (void)handle; (void)current; (void)new;
198 ptrdiff_t diff = new - current;
199
200 if (lock_count > 0)
201 return BUFLIB_CB_CANNOT_MOVE;
202
203 UPDATE(menu, diff);
204 /* loop over menus */
205 for(int i = 0; i < menu_count; i++)
206 {
207 struct menu_root* menu = menus[i];
208 /* then over the menu_entries of a menu */
209 for(int j = 0; j < menu->itemcount; j++)
210 {
211 struct menu_entry* mentry = menu->items[j];
212 /* then over the search_instructions of each menu_entry */
213 for(int k = 0; k < mentry->si.tagorder_count; k++)
214 {
215 for(int l = 0; l < mentry->si.clause_count[k]; l++)
216 {
217 UPDATE(mentry->si.clause[k][l]->str, diff);
218 UPDATE(mentry->si.clause[k][l], diff);
219 }
220 }
221 UPDATE(menu->items[j], diff);
222 }
223 UPDATE(menus[i], diff);
224 }
225
226 /* now the same game for formats */
227 for(int i = 0; i < format_count; i++)
228 {
229 for(int j = 0; j < formats[i]->clause_count; j++)
230 {
231 UPDATE(formats[i]->clause[j]->str, diff);
232 UPDATE(formats[i]->clause[j], diff);
233 }
234
235 if (formats[i]->formatstr)
236 UPDATE(formats[i]->formatstr, diff);
237
238 UPDATE(formats[i], diff);
239 }
240 return BUFLIB_CB_OK;
241}
242#undef UPDATE
243
244static inline void tagtree_lock(void)
245{
246 lock_count++;
247}
248
249static inline void tagtree_unlock(void)
250{
251 lock_count--;
252}
253
254static struct buflib_callbacks ops = {
255 .move_callback = move_callback,
256 .shrink_callback = NULL,
257};
258
181static void* tagtree_alloc(size_t size) 259static void* tagtree_alloc(size_t size)
182{ 260{
183 char* buf = core_get_data(tagtree_handle) + tagtree_buf_used; 261 char* buf = core_get_data(tagtree_handle) + tagtree_buf_used;
@@ -201,6 +279,7 @@ static char* tagtree_strdup(const char* buf)
201 return dest; 279 return dest;
202} 280}
203 281
282/* save to call without locking */
204static int get_token_str(char *buf, int size) 283static int get_token_str(char *buf, int size)
205{ 284{
206 /* Find the start. */ 285 /* Find the start. */
@@ -510,7 +589,8 @@ static int add_format(const char *buf)
510 { 589 {
511 int clause_count = 0; 590 int clause_count = 0;
512 strp++; 591 strp++;
513 592
593 tagtree_lock();
514 while (1) 594 while (1)
515 { 595 {
516 struct tagcache_search_clause *newclause; 596 struct tagcache_search_clause *newclause;
@@ -529,6 +609,7 @@ static int add_format(const char *buf)
529 609
530 clause_count++; 610 clause_count++;
531 } 611 }
612 tagtree_unlock();
532 613
533 formats[format_count]->clause_count = clause_count; 614 formats[format_count]->clause_count = clause_count;
534 } 615 }
@@ -593,9 +674,14 @@ static int get_condition(struct search_instruction *inst)
593 strp++; 674 strp++;
594 new_clause->type = clause_logical_or; 675 new_clause->type = clause_logical_or;
595 } 676 }
596 else if (!read_clause(new_clause)) 677 else
597 return -1; 678 {
598 679 tagtree_lock();
680 bool ret = read_clause(new_clause);
681 tagtree_unlock();
682 if (!ret)
683 return -1;
684 }
599 inst->clause_count[inst->tagorder_count]++; 685 inst->clause_count[inst->tagorder_count]++;
600 686
601 return 1; 687 return 1;
@@ -616,7 +702,6 @@ static bool parse_search(struct menu_entry *entry, const char *str)
616 struct search_instruction *inst = &entry->si; 702 struct search_instruction *inst = &entry->si;
617 char buf[MAX_PATH]; 703 char buf[MAX_PATH];
618 int i; 704 int i;
619 struct menu_root *new_menu;
620 705
621 strp = str; 706 strp = str;
622 707
@@ -654,8 +739,7 @@ static bool parse_search(struct menu_entry *entry, const char *str)
654 739
655 /* Allocate a new menu unless link is found. */ 740 /* Allocate a new menu unless link is found. */
656 menus[menu_count] = tagtree_alloc0(sizeof(struct menu_root)); 741 menus[menu_count] = tagtree_alloc0(sizeof(struct menu_root));
657 new_menu = menus[menu_count]; 742 strlcpy(menus[menu_count]->id, buf, MAX_MENU_ID_SIZE);
658 strlcpy(new_menu->id, buf, MAX_MENU_ID_SIZE);
659 entry->link = menu_count; 743 entry->link = menu_count;
660 ++menu_count; 744 ++menu_count;
661 745
@@ -679,8 +763,11 @@ static bool parse_search(struct menu_entry *entry, const char *str)
679 break ; 763 break ;
680 764
681 logf("tag: %d", inst->tagorder[inst->tagorder_count]); 765 logf("tag: %d", inst->tagorder[inst->tagorder_count]);
682 766
767 tagtree_lock();
683 while ( (ret = get_condition(inst)) > 0 ) ; 768 while ( (ret = get_condition(inst)) > 0 ) ;
769 tagtree_unlock();
770
684 if (ret < 0) 771 if (ret < 0)
685 return false; 772 return false;
686 773
@@ -697,7 +784,7 @@ static int compare(const void *p1, const void *p2)
697{ 784{
698 struct tagentry *e1 = (struct tagentry *)p1; 785 struct tagentry *e1 = (struct tagentry *)p1;
699 struct tagentry *e2 = (struct tagentry *)p2; 786 struct tagentry *e2 = (struct tagentry *)p2;
700 787
701 if (sort_inverse) 788 if (sort_inverse)
702 return strncasecmp(e2->name, e1->name, MAX_PATH); 789 return strncasecmp(e2->name, e1->name, MAX_PATH);
703 790
@@ -1001,11 +1088,11 @@ static int parse_line(int n, char *buf, void *parameters)
1001 if (menu->items[menu->itemcount] == NULL) 1088 if (menu->items[menu->itemcount] == NULL)
1002 menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); 1089 menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry));
1003 1090
1004 if (!parse_search(menu->items[menu->itemcount], buf)) 1091 tagtree_lock();
1005 return 0; 1092 if (parse_search(menu->items[menu->itemcount], buf))
1006 1093 menu->itemcount++;
1007 menu->itemcount++; 1094 tagtree_unlock();
1008 1095
1009 return 0; 1096 return 0;
1010} 1097}
1011 1098
@@ -1040,15 +1127,20 @@ void tagtree_init(void)
1040 menu_count = 0; 1127 menu_count = 0;
1041 menu = NULL; 1128 menu = NULL;
1042 rootmenu = -1; 1129 rootmenu = -1;
1043 tagtree_handle = core_alloc_maximum("tagtree", &tagtree_bufsize, NULL); 1130 tagtree_handle = core_alloc_maximum("tagtree", &tagtree_bufsize, &ops);
1044 parse_menu(FILE_SEARCH_INSTRUCTIONS); 1131 parse_menu(FILE_SEARCH_INSTRUCTIONS);
1132
1133 /* safety check since tree.c needs to cast tagentry to entry */
1134 if (sizeof(struct tagentry) != sizeof(struct entry))
1135 panicf("tagentry(%zu) and entry mismatch(%zu)",
1136 sizeof(struct tagentry), sizeof(struct entry));
1137 if (lock_count > 0)
1138 panicf("tagtree locked after parsing");
1045 1139
1046 /* If no root menu is set, assume it's the first single menu 1140 /* If no root menu is set, assume it's the first single menu
1047 * we have. That shouldn't normally happen. */ 1141 * we have. That shouldn't normally happen. */
1048 if (rootmenu < 0) 1142 if (rootmenu < 0)
1049 rootmenu = 0; 1143 rootmenu = 0;
1050
1051 uniqbuf = tagtree_alloc(UNIQBUF_SIZE);
1052 1144
1053 add_event(PLAYBACK_EVENT_TRACK_BUFFER, false, tagtree_buffer_event); 1145 add_event(PLAYBACK_EVENT_TRACK_BUFFER, false, tagtree_buffer_event);
1054 add_event(PLAYBACK_EVENT_TRACK_FINISH, false, tagtree_track_finish_event); 1146 add_event(PLAYBACK_EVENT_TRACK_FINISH, false, tagtree_track_finish_event);
@@ -1181,10 +1273,14 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1181 return 0; 1273 return 0;
1182} 1274}
1183 1275
1276static struct tagentry* get_entries(struct tree_context *tc)
1277{
1278 return core_get_data(tc->cache.entries_handle);
1279}
1280
1184static int retrieve_entries(struct tree_context *c, int offset, bool init) 1281static int retrieve_entries(struct tree_context *c, int offset, bool init)
1185{ 1282{
1186 struct tagcache_search tcs; 1283 struct tagcache_search tcs;
1187 struct tagentry *dptr = c->cache.entries;
1188 struct display_format *fmt; 1284 struct display_format *fmt;
1189 int i; 1285 int i;
1190 int namebufused = 0; 1286 int namebufused = 0;
@@ -1242,7 +1338,10 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1242 csi->result_seek[i]); 1338 csi->result_seek[i]);
1243 } 1339 }
1244 } 1340 }
1245 1341
1342 /* because tagcache saves the clauses, we need to lock the buffer
1343 * for the entire duration of the search */
1344 tagtree_lock();
1246 for (i = 0; i <= level; i++) 1345 for (i = 0; i <= level; i++)
1247 { 1346 {
1248 int j; 1347 int j;
@@ -1276,6 +1375,10 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1276 strip = 0; 1375 strip = 0;
1277 } 1376 }
1278 1377
1378 /* lock buflib out due to possible yields */
1379 tree_lock_cache(c);
1380 struct tagentry *dptr = core_get_data(c->cache.entries_handle);
1381
1279 if (tag != tag_title && tag != tag_filename) 1382 if (tag != tag_title && tag != tag_filename)
1280 { 1383 {
1281 if (offset == 0) 1384 if (offset == 0)
@@ -1315,6 +1418,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1315 1418
1316 fmt = NULL; 1419 fmt = NULL;
1317 /* Check the format */ 1420 /* Check the format */
1421 tagtree_lock();
1318 for (i = 0; i < format_count; i++) 1422 for (i = 0; i < format_count; i++)
1319 { 1423 {
1320 if (formats[i]->group_id != csi->format_id[level]) 1424 if (formats[i]->group_id != csi->format_id[level])
@@ -1327,6 +1431,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1327 break; 1431 break;
1328 } 1432 }
1329 } 1433 }
1434 tagtree_unlock();
1330 1435
1331 if (strcmp(tcs.result, UNTAGGED) == 0) 1436 if (strcmp(tcs.result, UNTAGGED) == 0)
1332 { 1437 {
@@ -1337,7 +1442,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1337 1442
1338 if (!tcs.ramresult || fmt) 1443 if (!tcs.ramresult || fmt)
1339 { 1444 {
1340 dptr->name = &c->cache.name_buffer[namebufused]; 1445 dptr->name = core_get_data(c->cache.name_buffer_handle)+namebufused;
1341 1446
1342 if (fmt) 1447 if (fmt)
1343 { 1448 {
@@ -1354,6 +1459,8 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1354 { 1459 {
1355 logf("format_str() failed"); 1460 logf("format_str() failed");
1356 tagcache_search_finish(&tcs); 1461 tagcache_search_finish(&tcs);
1462 tree_unlock_cache(c);
1463 tagtree_unlock();
1357 return 0; 1464 return 0;
1358 } 1465 }
1359 else 1466 else
@@ -1392,6 +1499,8 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1392 if (!show_search_progress(false, total_count)) 1499 if (!show_search_progress(false, total_count))
1393 { /* user aborted */ 1500 { /* user aborted */
1394 tagcache_search_finish(&tcs); 1501 tagcache_search_finish(&tcs);
1502 tree_unlock_cache(c);
1503 tagtree_unlock();
1395 return current_entry_count; 1504 return current_entry_count;
1396 } 1505 }
1397 } 1506 }
@@ -1399,15 +1508,17 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1399 1508
1400 if (sort) 1509 if (sort)
1401 { 1510 {
1402 int entry_size = sizeof(struct tagentry); 1511 struct tagentry *entries = get_entries(c);
1403 qsort(c->cache.entries + special_entry_count * entry_size, 1512 qsort(&entries[special_entry_count],
1404 current_entry_count - special_entry_count, 1513 current_entry_count - special_entry_count,
1405 entry_size, compare); 1514 sizeof(struct tagentry), compare);
1406 } 1515 }
1407 1516
1408 if (!init) 1517 if (!init)
1409 { 1518 {
1410 tagcache_search_finish(&tcs); 1519 tagcache_search_finish(&tcs);
1520 tree_unlock_cache(c);
1521 tagtree_unlock();
1411 return current_entry_count; 1522 return current_entry_count;
1412 } 1523 }
1413 1524
@@ -1422,7 +1533,9 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1422 } 1533 }
1423 1534
1424 tagcache_search_finish(&tcs); 1535 tagcache_search_finish(&tcs);
1425 1536 tree_unlock_cache(c);
1537 tagtree_unlock();
1538
1426 if (!sort && (sort_inverse || sort_limit)) 1539 if (!sort && (sort_inverse || sort_limit))
1427 { 1540 {
1428 splashf(HZ*4, ID2P(LANG_SHOWDIR_BUFFER_FULL), total_count); 1541 splashf(HZ*4, ID2P(LANG_SHOWDIR_BUFFER_FULL), total_count);
@@ -1435,7 +1548,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1435 1548
1436 if (strip) 1549 if (strip)
1437 { 1550 {
1438 dptr = c->cache.entries; 1551 dptr = get_entries(c);
1439 for (i = special_entry_count; i < current_entry_count; i++, dptr++) 1552 for (i = special_entry_count; i < current_entry_count; i++, dptr++)
1440 { 1553 {
1441 int len = strlen(dptr->name); 1554 int len = strlen(dptr->name);
@@ -1446,14 +1559,14 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1446 dptr->name = &dptr->name[strip]; 1559 dptr->name = &dptr->name[strip];
1447 } 1560 }
1448 } 1561 }
1449 1562
1450 return total_count; 1563 return total_count;
1451 1564
1452} 1565}
1453 1566
1454static int load_root(struct tree_context *c) 1567static int load_root(struct tree_context *c)
1455{ 1568{
1456 struct tagentry *dptr = c->cache.entries; 1569 struct tagentry *dptr = core_get_data(c->cache.entries_handle);
1457 int i; 1570 int i;
1458 1571
1459 tc = c; 1572 tc = c;
@@ -1569,6 +1682,10 @@ int tagtree_enter(struct tree_context* c)
1569 c->pos_history[c->dirlevel] = c->firstpos; 1682 c->pos_history[c->dirlevel] = c->firstpos;
1570 c->dirlevel++; 1683 c->dirlevel++;
1571 1684
1685 /* lock buflib for possible I/O to protect dptr */
1686 tree_lock_cache(c);
1687 tagtree_lock();
1688
1572 switch (c->currtable) { 1689 switch (c->currtable) {
1573 case ROOT: 1690 case ROOT:
1574 c->currextra = newextra; 1691 c->currextra = newextra;
@@ -1634,6 +1751,8 @@ int tagtree_enter(struct tree_context* c)
1634 if (rc < 0 || !searchstring[0]) 1751 if (rc < 0 || !searchstring[0])
1635 { 1752 {
1636 tagtree_exit(c); 1753 tagtree_exit(c);
1754 tree_unlock_cache(c);
1755 tagtree_unlock();
1637 return 0; 1756 return 0;
1638 } 1757 }
1639 if (csi->clause[i][j]->numeric) 1758 if (csi->clause[i][j]->numeric)
@@ -1682,9 +1801,12 @@ int tagtree_enter(struct tree_context* c)
1682 c->dirlevel--; 1801 c->dirlevel--;
1683 break; 1802 break;
1684 } 1803 }
1804
1685 1805
1686 c->selected_item=0; 1806 c->selected_item=0;
1687 gui_synclist_select_item(&tree_lists, c->selected_item); 1807 gui_synclist_select_item(&tree_lists, c->selected_item);
1808 tree_unlock_cache(c);
1809 tagtree_unlock();
1688 1810
1689 return rc; 1811 return rc;
1690} 1812}
@@ -1704,14 +1826,13 @@ void tagtree_exit(struct tree_context* c)
1704int tagtree_get_filename(struct tree_context* c, char *buf, int buflen) 1826int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
1705{ 1827{
1706 struct tagcache_search tcs; 1828 struct tagcache_search tcs;
1707 struct tagentry *entry; 1829 int extraseek = tagtree_get_entry(c, c->selected_item)->extraseek;
1708 1830
1709 entry = tagtree_get_entry(c, c->selected_item);
1710 1831
1711 if (!tagcache_search(&tcs, tag_filename)) 1832 if (!tagcache_search(&tcs, tag_filename))
1712 return -1; 1833 return -1;
1713 1834
1714 if (!tagcache_retrieve(&tcs, entry->extraseek, tcs.type, buf, buflen)) 1835 if (!tagcache_retrieve(&tcs, extraseek, tcs.type, buf, buflen))
1715 { 1836 {
1716 tagcache_search_finish(&tcs); 1837 tagcache_search_finish(&tcs);
1717 return -2; 1838 return -2;
@@ -1790,9 +1911,9 @@ static bool insert_all_playlist(struct tree_context *c, int position, bool queue
1790 1911
1791bool tagtree_insert_selection_playlist(int position, bool queue) 1912bool tagtree_insert_selection_playlist(int position, bool queue)
1792{ 1913{
1793 struct tagentry *dptr;
1794 char buf[MAX_PATH]; 1914 char buf[MAX_PATH];
1795 int dirlevel = tc->dirlevel; 1915 int dirlevel = tc->dirlevel;
1916 int newtable;
1796 1917
1797 show_search_progress( 1918 show_search_progress(
1798#ifdef HAVE_DISK_STORAGE 1919#ifdef HAVE_DISK_STORAGE
@@ -1804,10 +1925,10 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
1804 1925
1805 1926
1806 /* We need to set the table to allsubentries. */ 1927 /* We need to set the table to allsubentries. */
1807 dptr = tagtree_get_entry(tc, tc->selected_item); 1928 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
1808 1929
1809 /* Insert a single track? */ 1930 /* Insert a single track? */
1810 if (dptr->newtable == PLAYTRACK) 1931 if (newtable == PLAYTRACK)
1811 { 1932 {
1812 if (tagtree_get_filename(tc, buf, sizeof buf) < 0) 1933 if (tagtree_get_filename(tc, buf, sizeof buf) < 0)
1813 { 1934 {
@@ -1819,29 +1940,29 @@ bool tagtree_insert_selection_playlist(int position, bool queue)
1819 return true; 1940 return true;
1820 } 1941 }
1821 1942
1822 if (dptr->newtable == NAVIBROWSE) 1943 if (newtable == NAVIBROWSE)
1823 { 1944 {
1824 tagtree_enter(tc); 1945 tagtree_enter(tc);
1825 tagtree_load(tc); 1946 tagtree_load(tc);
1826 dptr = tagtree_get_entry(tc, tc->selected_item); 1947 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
1827 } 1948 }
1828 else if (dptr->newtable != ALLSUBENTRIES) 1949 else if (newtable != ALLSUBENTRIES)
1829 { 1950 {
1830 logf("unsupported table: %d", dptr->newtable); 1951 logf("unsupported table: %d", newtable);
1831 return false; 1952 return false;
1832 } 1953 }
1833 1954
1834 /* Now the current table should be allsubentries. */ 1955 /* Now the current table should be allsubentries. */
1835 if (dptr->newtable != PLAYTRACK) 1956 if (newtable != PLAYTRACK)
1836 { 1957 {
1837 tagtree_enter(tc); 1958 tagtree_enter(tc);
1838 tagtree_load(tc); 1959 tagtree_load(tc);
1839 dptr = tagtree_get_entry(tc, tc->selected_item); 1960 newtable = tagtree_get_entry(tc, tc->selected_item)->newtable;
1840 1961
1841 /* And now the newtable should be playtrack. */ 1962 /* And now the newtable should be playtrack. */
1842 if (dptr->newtable != PLAYTRACK) 1963 if (newtable != PLAYTRACK)
1843 { 1964 {
1844 logf("newtable: %d !!", dptr->newtable); 1965 logf("newtable: %d !!", newtable);
1845 tc->dirlevel = dirlevel; 1966 tc->dirlevel = dirlevel;
1846 return false; 1967 return false;
1847 } 1968 }
@@ -1886,9 +2007,9 @@ static int tagtree_play_folder(struct tree_context* c)
1886 return 0; 2007 return 0;
1887} 2008}
1888 2009
1889struct tagentry* tagtree_get_entry(struct tree_context *c, int id) 2010static struct tagentry* tagtree_get_entry(struct tree_context *c, int id)
1890{ 2011{
1891 struct tagentry *entry = (struct tagentry *)c->cache.entries; 2012 struct tagentry *entry;
1892 int realid = id - current_offset; 2013 int realid = id - current_offset;
1893 2014
1894 /* Load the next chunk if necessary. */ 2015 /* Load the next chunk if necessary. */
@@ -1905,10 +2026,22 @@ struct tagentry* tagtree_get_entry(struct tree_context *c, int id)
1905 realid = id - current_offset; 2026 realid = id - current_offset;
1906 cpu_boost(false); 2027 cpu_boost(false);
1907 } 2028 }
1908 2029
2030 entry = get_entries(c);
1909 return &entry[realid]; 2031 return &entry[realid];
1910} 2032}
1911 2033
2034char* tagtree_get_entry_name(struct tree_context *c, int id,
2035 char* buf, size_t bufsize)
2036{
2037 struct tagentry *entry = tagtree_get_entry(c, id);
2038 if (!entry)
2039 return NULL;
2040 strlcpy(buf, entry->name, bufsize);
2041 return buf;
2042}
2043
2044
1912char *tagtree_get_title(struct tree_context* c) 2045char *tagtree_get_title(struct tree_context* c)
1913{ 2046{
1914 switch (c->currtable) 2047 switch (c->currtable)