Initial runtimedb support for tagcache. Only for developers,

statistical data will be lost in future until changelogs has been
implemented.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10217 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2006-07-15 17:36:25 +00:00
parent e60cb43a98
commit 45dfe2a36f
6 changed files with 426 additions and 148 deletions

View file

@ -2189,11 +2189,13 @@ void audio_thread(void)
case Q_AUDIO_PLAY:
logf("starting...");
audio_clear_track_entries(true, false);
audio_play_start((size_t)ev.data);
break ;
case Q_AUDIO_STOP:
logf("audio_stop");
audio_clear_track_entries(true, false);
audio_stop_playback();
break ;
@ -2816,22 +2818,6 @@ void mpeg_id3_options(bool _v1first)
}
#ifdef ROCKBOX_HAS_LOGF
void test_buffer_event(struct mp3entry *id3, bool last_track)
{
(void)id3;
(void)last_track;
logf("be:%d%s", last_track, id3->path);
}
void test_unbuffer_event(struct mp3entry *id3, bool last_track)
{
(void)id3;
(void)last_track;
logf("ube:%d%s", last_track, id3->path);
}
void test_track_changed_event(struct mp3entry *id3)
{
(void)id3;
@ -2854,8 +2840,6 @@ static void playback_init(void)
#endif
#ifdef ROCKBOX_HAS_LOGF
audio_set_track_buffer_event(test_buffer_event);
audio_set_track_unbuffer_event(test_unbuffer_event);
audio_set_track_changed_event(test_track_changed_event);
#endif

View file

@ -1545,6 +1545,16 @@ static bool tagcache_autoupdate(void)
return rc;
}
static bool tagcache_runtimedb(void)
{
bool rc = set_bool_options(str(LANG_RUNTIMEDB_ACTIVE),
&global_settings.runtimedb,
STR(LANG_ON),
STR(LANG_OFF),
NULL);
return rc;
}
static bool tagcache_settings_menu(void)
{
int m;
@ -1557,6 +1567,7 @@ static bool tagcache_settings_menu(void)
{ ID2P(LANG_TAGCACHE_AUTOUPDATE), tagcache_autoupdate },
{ ID2P(LANG_TAGCACHE_FORCE_UPDATE), tagcache_rebuild },
{ ID2P(LANG_TAGCACHE_UPDATE), tagcache_update },
{ ID2P(LANG_RUNTIMEDB_ACTIVE), tagcache_runtimedb },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,

View file

@ -58,7 +58,8 @@ static const int sorted_tags[] = { tag_artist, tag_album, tag_genre, tag_compose
static const int unique_tags[] = { tag_artist, tag_album, tag_genre, tag_composer };
/* Numeric tags (we can use these tags with conditional clauses). */
static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate };
static const int numeric_tags[] = { tag_year, tag_tracknumber, tag_length, tag_bitrate,
tag_playcount, tag_playtime, tag_lastplayed, tag_virt_autoscore };
/* Status information of the tagcache. */
static struct tagcache_stat stat;
@ -179,8 +180,8 @@ bool tagcache_is_sorted_tag(int type)
}
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
static struct index_entry *find_entry_ram(const char *filename,
const struct dircache_entry *dc)
static long find_entry_ram(const char *filename,
const struct dircache_entry *dc)
{
static long last_pos = 0;
int counter = 0;
@ -188,7 +189,7 @@ static struct index_entry *find_entry_ram(const char *filename,
/* Check if we tagcache is loaded into ram. */
if (!stat.ramcache)
return NULL;
return -1;
if (dc == NULL)
dc = dircache_get_entry_ptr(filename);
@ -196,7 +197,7 @@ static struct index_entry *find_entry_ram(const char *filename,
if (dc == NULL)
{
logf("tagcache: file not found.");
return NULL;
return -1;
}
try_again:
@ -211,7 +212,7 @@ static struct index_entry *find_entry_ram(const char *filename,
if (hdr->indices[i].tag_seek[tag_filename] == (long)dc)
{
last_pos = MAX(0, i - 3);
return &hdr->indices[i];
return i;
}
if (++counter == 100)
@ -227,28 +228,28 @@ static struct index_entry *find_entry_ram(const char *filename,
goto try_again;
}
return NULL;
return -1;
}
#endif
static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
static long find_entry_disk(const char *filename)
{
static struct index_entry idx;
static long last_pos = -1;
long pos_history[POS_HISTORY_COUNT];
long pos_history_idx = 0;
struct tagcache_header tch;
bool found = false;
struct tagfile_entry tfe;
int masterfd, fd = filenametag_fd;
int fd;
char buf[MAX_PATH];
int i;
int pos = -1;
fd = filenametag_fd;
if (fd < 0)
{
last_pos = -1;
return NULL;
if ( (fd = open(TAGCACHE_FILE_MASTER, O_RDONLY)) < 0)
return -1;
}
check_again:
@ -276,7 +277,7 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
logf("too long tag #1");
close(fd);
last_pos = -1;
return NULL;
return -2;
}
if (read(fd, buf, tfe.tag_length) != tfe.tag_length)
@ -284,7 +285,7 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
logf("read error #2");
close(fd);
last_pos = -1;
return NULL;
return -3;
}
if (!strcasecmp(filename, buf))
@ -307,90 +308,106 @@ static struct index_entry *find_entry_disk(const char *filename, bool retrieve)
logf("seek again");
goto check_again;
}
//close(fd);
return NULL;
}
if (!retrieve)
{
/* Just return a valid pointer without a valid entry. */
return &idx;
}
/* Found. Now read the index_entry (if requested). */
masterfd = open(TAGCACHE_FILE_MASTER, O_RDONLY);
if (masterfd < 0)
{
logf("open fail");
return NULL;
}
if (read(fd, &tch, sizeof(struct tagcache_header)) !=
sizeof(struct tagcache_header) || tch.magic != TAGCACHE_MAGIC)
{
logf("header error");
return NULL;
}
for (i = 0; i < tch.entry_count; i++)
{
if (read(masterfd, &idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
{
logf("read error #3");
if (fd != filenametag_fd)
close(fd);
return NULL;
}
if (idx.tag_seek[tag_filename] == pos)
break ;
}
close(masterfd);
/* Not found? */
if (i == tch.entry_count)
{
logf("not found!");
return NULL;
return -4;
}
return &idx;
if (fd != filenametag_fd)
close(fd);
return tfe.idx_id;
}
static long tagcache_get_seek(const struct tagcache_search *tcs,
int tag, int idxid)
bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
{
struct index_entry idx;
long idx_id = -1;
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
if (stat.ramcache && dircache_is_enabled())
idx_id = find_entry_ram(filename, NULL);
#endif
if (idx_id < 0)
idx_id = find_entry_disk(filename);
if (idx_id < 0)
return false;
if (!tagcache_search(tcs, tag_filename))
return false;
tcs->entry_count = 0;
tcs->idx_id = idx_id;
return true;
}
static bool tagcache_get_index(const struct tagcache_search *tcs,
int idxid, struct index_entry *idx)
{
#ifdef HAVE_TC_RAMCACHE
if (tcs->ramsearch)
{
if (hdr->indices[idxid].flag & FLAG_DELETED)
return false;
return hdr->indices[idxid].tag_seek[tag];
memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry));
return true;
}
#endif
lseek(tcs->masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct tagcache_header), SEEK_SET);
if (read(tcs->masterfd, &idx, sizeof(struct index_entry)) !=
if (read(tcs->masterfd, idx, sizeof(struct index_entry)) !=
sizeof(struct index_entry))
{
logf("read error #3");
return -4;
return false;
}
return idx.tag_seek[tag];
return true;
}
static long check_virtual_tags(int tag, const struct index_entry *idx)
{
long data = 0;
switch (tag)
{
case tag_virt_autoscore:
if (idx->tag_seek[tag_length] == 0
|| idx->tag_seek[tag_playcount] == 0)
{
data = 0;
}
else
{
data = 100 * idx->tag_seek[tag_playtime]
/ idx->tag_seek[tag_length]
/ idx->tag_seek[tag_playcount];
}
break;
default:
data = idx->tag_seek[tag];
}
return data;
}
long tagcache_get_numeric(const struct tagcache_search *tcs, int tag)
{
struct index_entry idx;
if (!tagcache_is_numeric_tag(tag))
return -1;
return tagcache_get_seek(tcs, tag, tcs->idx_id);
if (!tagcache_get_index(tcs, tcs->idx_id, &idx))
return -2;
return check_virtual_tags(tag, &idx);
}
static bool check_against_clause(long numeric, const char *str,
@ -459,16 +476,20 @@ static bool build_lookup_list(struct tagcache_search *tcs)
/* Go through all conditional clauses. */
for (j = 0; j < tcs->clause_count; j++)
{
int seek = hdr->indices[i].tag_seek[tcs->clause[j]->tag];
struct index_entry *idx = &hdr->indices[i];
int seek;
char *str = NULL;
struct tagfile_entry *entry;
seek = check_virtual_tags(tcs->clause[j]->tag, idx);
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 ;
}
@ -529,9 +550,11 @@ static bool build_lookup_list(struct tagcache_search *tcs)
for (i = 0; i < tcs->clause_count; i++)
{
struct tagfile_entry tfe;
int seek = entry.tag_seek[tcs->clause[i]->tag];
int seek;
char str[256];
seek = check_virtual_tags(tcs->clause[i]->tag, &entry);
memset(str, 0, sizeof str);
if (!tagcache_is_numeric_tag(tcs->clause[i]->tag))
{
@ -852,9 +875,13 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
char *buf, long size)
{
struct tagfile_entry tfe;
struct index_entry idx;
long seek;
seek = tagcache_get_seek(tcs, tcs->type, idxid);
if (!tagcache_get_index(tcs, idxid, &idx))
return false;
seek = idx.tag_seek[tcs->type];
if (seek < 0)
{
logf("Retrieve failed");
@ -974,12 +1001,15 @@ static long get_tag_numeric(const struct index_entry *entry, int tag)
bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
{
struct index_entry *entry;
int idx_id;
/* Find the corresponding entry in tagcache. */
entry = find_entry_ram(filename, NULL);
if (entry == NULL || !stat.ramcache)
idx_id = find_entry_ram(filename, NULL);
if (idx_id < 0 || !stat.ramcache)
return false;
entry = &hdr->indices[idx_id];
id3->title = get_tag(entry, tag_title)->tag_data;
id3->artist = get_tag(entry, tag_artist)->tag_data;
id3->album = get_tag(entry, tag_album)->tag_data;
@ -1036,13 +1066,13 @@ static void add_tagcache(const char *path)
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
if (stat.ramcache && dircache_is_enabled())
{
if (find_entry_ram(path, dc))
if (find_entry_ram(path, dc) >= 0)
return ;
}
else
#endif
{
if (find_entry_disk(path, false))
if (find_entry_disk(path) >= 0)
return ;
}
@ -2051,35 +2081,101 @@ static void free_tempbuf(void)
tempbuf_size = 0;
}
static bool delete_entry(long idx_id)
static int open_master_fd(struct tagcache_header *hdr)
{
int fd;
int tag, i;
struct index_entry idx, myidx;
struct tagcache_header hdr;
char buf[MAX_PATH];
int in_use[TAG_COUNT];
fd = open(TAGCACHE_FILE_MASTER, O_RDWR);
if (fd < 0)
{
logf("master file open failed for R/W");
return false;
return fd;
}
/* Check the header. */
read(fd, &hdr, sizeof(struct tagcache_header));
if (hdr.magic != TAGCACHE_MAGIC)
read(fd, hdr, sizeof(struct tagcache_header));
if (hdr->magic != TAGCACHE_MAGIC)
{
logf("header error");
close(fd);
return -2;
}
return fd;
}
bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
int tag, long data)
{
struct index_entry idx;
struct tagcache_header myhdr;
if (!tagcache_is_numeric_tag(tag))
return false;
#ifdef HAVE_TC_RAMCACHE
/* Update ram entries first. */
if (tcs->ramsearch)
{
hdr->indices[tcs->idx_id].tag_seek[tag] = data;
hdr->indices[tcs->idx_id].flag |= FLAG_DIRTYNUM;
}
#endif
/* And now update the db on disk also. */
if (tcs->masterfd < 0)
{
if ( (tcs->masterfd = open_master_fd(&myhdr)) < 0)
return false;
}
lseek(tcs->masterfd, tcs->idx_id * sizeof(struct index_entry)
+ sizeof(struct tagcache_header), SEEK_SET);
if (read(tcs->masterfd, &idx, sizeof(struct index_entry))
!= sizeof(struct index_entry))
{
logf("read error");
return false;
}
idx.flag |= FLAG_DIRTYNUM;
idx.tag_seek[tag] = data;
lseek(tcs->masterfd, -sizeof(struct index_entry), SEEK_CUR);
if (write(tcs->masterfd, &idx, sizeof(struct index_entry))
!= sizeof(struct index_entry))
{
logf("write error");
return false;
}
return true;
}
static bool delete_entry(long idx_id)
{
int fd;
int tag, i;
struct index_entry idx, myidx;
struct tagcache_header myhdr;
char buf[MAX_PATH];
int in_use[TAG_COUNT];
#ifdef HAVE_TC_RAMCACHE
/* At first mark the entry removed from ram cache. */
if (hdr)
hdr->indices[idx_id].flag |= FLAG_DELETED;
#endif
if ( (fd = open_master_fd(&myhdr) < 0) )
return false;
lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
if (read(fd, &myidx, sizeof(struct index_entry))
!= sizeof(struct index_entry))
{
logf("read error");
close(fd);
return false;
}
@ -2089,6 +2185,7 @@ static bool delete_entry(long idx_id)
!= sizeof(struct index_entry))
{
logf("write error");
close(fd);
return false;
}
@ -2097,7 +2194,7 @@ static bool delete_entry(long idx_id)
in_use[tag] = 0;
lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
for (i = 0; i < hdr.entry_count; i++)
for (i = 0; i < myhdr.entry_count; i++)
{
if (read(fd, &idx, sizeof(struct index_entry))
!= sizeof(struct index_entry))
@ -2376,7 +2473,6 @@ static bool load_tagcache(void)
{
logf("Entry no longer valid.");
logf("-> %s", buf);
idx->flag |= FLAG_DELETED;
delete_entry(fe->idx_id);
continue ;
}
@ -2397,7 +2493,6 @@ static bool load_tagcache(void)
{
logf("Entry no longer valid.");
logf("-> %s", buf);
idx->flag |= FLAG_DELETED;
delete_entry(fe->idx_id);
continue;
}
@ -2808,6 +2903,7 @@ void tagcache_init(void)
{
stat.initialized = false;
stat.commit_step = 0;
filenametag_fd = -1;
queue_init(&tagcache_queue);
create_thread(tagcache_thread, tagcache_stack,

View file

@ -23,9 +23,11 @@
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
tag_filename, tag_composer, tag_year, tag_tracknumber,
tag_bitrate, tag_length };
tag_bitrate, tag_length, tag_playcount, tag_playtime, tag_lastplayed,
/* Virtual tags */
tag_virt_autoscore };
#define TAG_COUNT 10
#define TAG_COUNT 13
/* Allow a little drift to the filename ordering (should not be too high/low). */
#define POS_HISTORY_COUNT 4
@ -34,7 +36,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define IDX_BUF_DEPTH 64
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
#define TAGCACHE_MAGIC 0x54434804
#define TAGCACHE_MAGIC 0x54434805
/* How much to allocate extra space for ramcache. */
#define TAGCACHE_RESERVE 32768
@ -68,6 +70,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
/* Flags */
#define FLAG_DELETED 0x0001 /* Entry has been removed from db */
#define FLAG_DIRCACHE 0x0002 /* Filename is a dircache pointer */
#define FLAG_DIRTYNUM 0x0004 /* Numeric data has been modified */
enum clause { clause_none, clause_is, clause_gt, clause_gteq, clause_lt,
clause_lteq, clause_contains, clause_begins_with, clause_ends_with };
@ -123,6 +126,7 @@ struct tagcache_search {
bool tagcache_is_numeric_tag(int type);
bool tagcache_is_unique_tag(int type);
bool tagcache_is_sorted_tag(int type);
bool tagcache_find_index(struct tagcache_search *tcs, const char *filename);
bool tagcache_search(struct tagcache_search *tcs, int tag);
bool tagcache_search_add_filter(struct tagcache_search *tcs,
int tag, int seek);
@ -133,6 +137,8 @@ bool tagcache_retrieve(struct tagcache_search *tcs, int idxid,
char *buf, long size);
void tagcache_search_finish(struct tagcache_search *tcs);
long tagcache_get_numeric(const struct tagcache_search *tcs, int tag);
bool tagcache_modify_numeric_entry(struct tagcache_search *tcs,
int tag, long data);
struct tagcache_stat* tagcache_get_stat(void);
int tagcache_get_commit_step(void);

View file

@ -1,11 +1,16 @@
"Artists" artist : album : title
"Albums" album : title
"Genres" genre : artist : album : title
"Composers" composer : album : title
"Artists" artist : album : title = "%02d. %s" tracknum title
"Albums" album : title = "%02d. %s" tracknum title
"Genres" genre : artist : album : title = "%02d. %s" tracknum title
"Composers" composer : album : title = "%02d. %s" tracknum title
"Tracks" title
"Search by artist" artist ? artist ~ "" : album : title
"Search by album" album ? album ~ "" : title
"Search by artist" artist ? artist ~ "" : album : title = "%02d. %s" tracknum title
"Search by album" album ? album ~ "" : title = "%02d. %s" tracknum title
"Search by title" title ? title ~ ""
"Search by year" artist ? year = "" : album : title
"Search by year" artist ? year = "" : album : title = "%02d. %s" tracknum title
"Search by score" title = "(%3d) %s" autoscore title ? autoscore > ""
"Most played tracks" title = "(%d) %s" playcount title ? playcount > "1"
"Never played tracks" artist ? playcount == "0" : album : title = "%02d. %s" tracknum title
"Best tracks" title ? autoscore > "60" & playcount > "1"
"Example 1" artist ? year >= "2000" & artist ^ "a" : album : title
"Example 2" genre ? genre ~ "metal" : artist ? year >= "2000" : album ? year >= "2000" : title
"List played tracks" title = "(%3d/%d) %s" autoscore playcount title ? playcount > "0"

View file

@ -39,6 +39,7 @@
#include "gui/list.h"
#include "buffer.h"
#include "atoi.h"
#include "playback.h"
#define FILE_SEARCH_INSTRUCTIONS ROCKBOX_DIR "/tagnavi.config"
@ -47,11 +48,28 @@ static int tagtree_play_folder(struct tree_context* c);
static char searchstring[32];
#define MAX_TAGS 5
/*
* "%3d. %s" autoscore title
*
* valid = true
* formatstr = "%-3d. %s"
* tags[0] = tag_autoscore
* tags[1] = tag_title
* tag_count = 2
*/
struct display_format {
bool valid;
char formatstr[64];
int tags[MAX_TAGS];
int tag_count;
};
struct search_instruction {
char name[64];
int tagorder[MAX_TAGS];
int tagorder_count;
struct tagcache_search_clause clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES];
struct display_format format[MAX_TAGS];
int clause_count[MAX_TAGS];
int result_seek[MAX_TAGS];
};
@ -121,6 +139,8 @@ static int get_tag(int *tag)
MATCH(tag, buf, "title", tag_title);
MATCH(tag, buf, "tracknum", tag_tracknumber);
MATCH(tag, buf, "year", tag_year);
MATCH(tag, buf, "playcount", tag_playcount);
MATCH(tag, buf, "autoscore", tag_virt_autoscore);
logf("NO MATCH: %s\n", buf);
if (buf[0] == '?')
@ -206,14 +226,51 @@ static bool add_clause(struct search_instruction *inst,
return true;
}
static int get_format_str(struct display_format *fmt)
{
int ret;
memset(fmt, 0, sizeof(struct display_format));
if (get_token_str(fmt->formatstr, sizeof fmt->formatstr) < 0)
return -10;
while (fmt->tag_count < MAX_TAGS)
{
ret = get_tag(&fmt->tags[fmt->tag_count]);
if (ret < 0)
return -11;
if (ret == 0)
break;
fmt->tag_count++;
}
fmt->valid = true;
return 1;
}
static int get_condition(struct search_instruction *inst)
{
struct display_format format;
struct display_format *fmt = NULL;
int tag;
int condition;
char buf[32];
switch (*strp)
{
case '=':
if (get_format_str(&format) < 0)
{
logf("get_format_str() parser failed!");
return -4;
}
fmt = &format;
break;
case '?':
case ' ':
case '&':
@ -225,6 +282,14 @@ static int get_condition(struct search_instruction *inst)
return 0;
}
if (fmt)
{
memcpy(&inst->format[inst->tagorder_count], fmt,
sizeof(struct display_format));
}
else
inst->format[inst->tagorder_count].valid = false;
if (get_tag(&tag) <= 0)
return -1;
@ -294,6 +359,62 @@ static int compare(const void *p1, const void *p2)
return strncasecmp(e1->name, e2->name, MAX_PATH);
}
static void tagtree_buffer_event(struct mp3entry *id3, bool last_track)
{
(void)id3;
(void)last_track;
logf("be:%d%s", last_track, id3->path);
}
static void tagtree_unbuffer_event(struct mp3entry *id3, bool last_track)
{
(void)last_track;
long playcount;
long playtime;
long lastplayed;
/* Do not gather data unless proper setting has been enabled. */
if (!global_settings.runtimedb)
return;
/* Don't process unplayed tracks. */
if (id3->elapsed == 0)
return;
if (!tagcache_find_index(&tcs, id3->path))
{
logf("tc stat: not found: %s", id3->path);
return;
}
playcount = tagcache_get_numeric(&tcs, tag_playcount);
playtime = tagcache_get_numeric(&tcs, tag_playtime);
lastplayed = tagcache_get_numeric(&tcs, tag_lastplayed);
playcount++;
/* Ignore the last 15s (crossfade etc.) */
playtime += MIN(id3->length, id3->elapsed + 15 * 1000);
logf("ube:%s", id3->path);
logf("-> %d/%d/%d", last_track, playcount, playtime);
logf("-> %d/%d/%d", id3->elapsed, id3->length, MIN(id3->length, id3->elapsed + 15 * 1000));
/* lastplayed not yet supported. */
if (!tagcache_modify_numeric_entry(&tcs, tag_playcount, playcount)
|| !tagcache_modify_numeric_entry(&tcs, tag_playtime, playtime)
|| !tagcache_modify_numeric_entry(&tcs, tag_lastplayed, tag_lastplayed))
{
logf("tc stat: modify failed!");
tagcache_search_finish(&tcs);
return;
}
tagcache_search_finish(&tcs);
}
void tagtree_init(void)
{
int fd;
@ -350,6 +471,9 @@ void tagtree_init(void)
close(fd);
audiobuf += sizeof(struct search_instruction) * si_count + 4;
audio_set_track_buffer_event(tagtree_buffer_event);
audio_set_track_unbuffer_event(tagtree_unbuffer_event);
}
bool show_search_progress(bool init, int count)
@ -445,48 +569,100 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
while (tagcache_get_next(tcs))
{
struct display_format *fmt = &csi->format[extra];
if (total_count++ < offset)
continue;
dptr->newtable = navibrowse;
dptr->extraseek = tcs->result_seek;
if (!tcs->ramsearch || tag == tag_title)
if (tag == tag_title)
dptr->newtable = playtrack;
if (!tcs->ramsearch || fmt->valid)
{
int tracknum = -1;
char buf[MAX_PATH];
int buf_pos = 0;
if (fmt->valid)
{
char fmtbuf[8];
bool read_format = false;
int fmtbuf_pos = 0;
int parpos = 0;
memset(buf, 0, sizeof buf);
for (i = 0; fmt->formatstr[i] != '\0'; i++)
{
if (fmt->formatstr[i] == '%')
{
read_format = true;
fmtbuf_pos = 0;
if (parpos >= fmt->tag_count)
{
logf("too many format tags");
return 0;
}
}
if (read_format)
{
fmtbuf[fmtbuf_pos++] = fmt->formatstr[i];
if (fmtbuf_pos >= (long)sizeof(fmtbuf))
{
logf("format parse error");
return 0;
}
if (fmt->formatstr[i] == 's')
{
fmtbuf[fmtbuf_pos] = '\0';
read_format = false;
snprintf(&buf[buf_pos], MAX_PATH - buf_pos, fmtbuf, tcs->result);
buf_pos += strlen(&buf[buf_pos]);
parpos++;
}
else if (fmt->formatstr[i] == 'd')
{
fmtbuf[fmtbuf_pos] = '\0';
read_format = false;
snprintf(&buf[buf_pos], MAX_PATH - buf_pos, fmtbuf,
tagcache_get_numeric(tcs, fmt->tags[parpos]));
buf_pos += strlen(&buf[buf_pos]);
parpos++;
}
continue;
}
buf[buf_pos++] = fmt->formatstr[i];
if (buf_pos - 1 >= (long)sizeof(buf))
{
logf("buffer overflow");
return 0;
}
}
buf[buf_pos++] = '\0';
}
dptr->name = &c->name_buffer[namebufused];
if (tag == tag_title)
{
dptr->newtable = playtrack;
if (c->currtable != allsubentries && c->dirlevel > 1)
tracknum = tagcache_get_numeric(tcs, tag_tracknumber);
}
if (tracknum > 0)
{
snprintf(dptr->name, c->name_buffer_size - namebufused, "%02d. %s",
tracknum, tcs->result);
namebufused += strlen(dptr->name) + 1;
if (namebufused >= c->name_buffer_size)
{
logf("chunk mode #1: %d", current_entry_count);
c->dirfull = true;
sort = false;
break ;
}
}
if (fmt->valid)
namebufused += buf_pos;
else
{
namebufused += tcs->result_len;
if (namebufused >= c->name_buffer_size)
{
logf("chunk mode #2: %d", current_entry_count);
c->dirfull = true;
sort = false;
break ;
}
strcpy(dptr->name, tcs->result);
if (namebufused >= c->name_buffer_size)
{
logf("chunk mode #2: %d", current_entry_count);
c->dirfull = true;
sort = false;
break ;
}
if (fmt->valid)
strcpy(dptr->name, buf);
else
strcpy(dptr->name, tcs->result);
}
else
dptr->name = tcs->result;