FS#12132 patch 6: tagnavi.config: Add support for "basename" in formats and conditions, and for "%{width}.{truncation}s" in tagnavi %formats. String truncation is especially useful when using part of a string tag, filename, or basename for sorting and %strip'ing. Also renovated the format_str() code a bit (improved structuring, removed code duplication) and increased the maximum length of a printf conversion specification to 20 characters. --- apps/tagcache.c | 20 +++++++++++++- apps/tagcache.h | 4 +- apps/tagtree.c | 77 +++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/apps/tagcache.c b/apps/tagcache.c index a3585fe..d990028 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -869,6 +869,10 @@ static long check_virtual_tags(int tag, int idx_id, - find_tag(tag_commitid, idx_id, idx) - 1; break; + case tag_virt_basename: + tag = tag_filename; /* return filename; caller handles basename */ + /* FALLTHRU */ + default: data = find_tag(tag, idx_id, idx); } @@ -1009,7 +1013,8 @@ static bool check_clauses(struct tagcache_search *tcs, if (!TAGCACHE_IS_NUMERIC(clause->tag)) { - if (clause->tag == tag_filename) + if (clause->tag == tag_filename + || clause->tag == tag_virt_basename) { retrieve(tcs, idx, tag_filename, buf, sizeof buf); } @@ -1027,7 +1032,11 @@ static bool check_clauses(struct tagcache_search *tcs, if (!TAGCACHE_IS_NUMERIC(clause->tag)) { - int fd = tcs->idxfd[clause->tag]; + int tag = clause->tag; + if (tag == tag_virt_basename) + tag = tag_filename; + + int fd = tcs->idxfd[tag]; lseek(fd, seek, SEEK_SET); ecread_tagfile_entry(fd, &tfe); if (tfe.tag_length >= (int)sizeof(buf)) @@ -1045,6 +1054,13 @@ static bool check_clauses(struct tagcache_search *tcs, } } + if (clause->tag == tag_virt_basename) + { + char *basename = strrchr(str, '/'); + if (basename) + str = basename + 1; + } + if (!check_against_clause(seek, str, clause)) { /* Clause failed -- try finding a logical-or clause */ diff --git a/apps/tagcache.h b/apps/tagcache.h index 6f23bfc..18d44a4 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -36,7 +36,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, /* Real tags end here, count them. */ TAG_COUNT, /* Virtual tags */ - tag_virt_length_min, tag_virt_length_sec, + tag_virt_basename, tag_virt_length_min, tag_virt_length_sec, tag_virt_playtime_min, tag_virt_playtime_sec, tag_virt_entryage, tag_virt_autoscore }; @@ -103,7 +103,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, (1LU << tag_tracknumber) | (1LU << tag_length) | (1LU << tag_bitrate) | \ (1LU << tag_playcount) | (1LU << tag_rating) | (1LU << tag_playtime) | \ (1LU << tag_lastplayed) | (1LU << tag_commitid) | (1LU << tag_mtime) | \ - (1LU << tag_lastoffset) | \ + (1LU << tag_lastoffset) | (1LU << tag_virt_basename) | \ (1LU << tag_virt_length_min) | (1LU << tag_virt_length_sec) | \ (1LU << tag_virt_playtime_min) | (1LU << tag_virt_playtime_sec) | \ (1LU << tag_virt_entryage) | (1LU << tag_virt_autoscore)) diff --git a/apps/tagtree.c b/apps/tagtree.c index a1c5640..b7e5bae 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -219,6 +219,7 @@ static int get_tag(int *tag) {"Ps", tag_virt_playtime_sec}, {"title", tag_title}, {"filename", tag_filename}, + {"basename", tag_virt_basename}, {"tracknum", tag_tracknumber}, {"discnum", tag_discnumber}, {"year", tag_year}, @@ -1052,9 +1053,9 @@ static bool show_search_progress(bool init, int count) static int format_str(struct tagcache_search *tcs, struct display_format *fmt, char *buf, int buf_size) { - char fmtbuf[8]; + char fmtbuf[20]; bool read_format = false; - int fmtbuf_pos = 0; + unsigned fmtbuf_pos = 0; int parpos = 0; int buf_pos = 0; int i; @@ -1075,47 +1076,67 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt, if (read_format) { - fmtbuf[fmtbuf_pos++] = fmt->formatstr[i]; - if (fmtbuf_pos >= buf_size) + char formatchar = fmt->formatstr[i]; + + fmtbuf[fmtbuf_pos++] = formatchar; + if (fmtbuf_pos >= sizeof fmtbuf) { logf("format parse error"); return -2; } - - if (fmt->formatstr[i] == 's') + + if (formatchar == 's' || formatchar == 'd') { + unsigned space_left = buf_size - buf_pos; + char tmpbuf[space_left + 1]; + char *result; + fmtbuf[fmtbuf_pos] = '\0'; read_format = false; - if (fmt->tags[parpos] == tcs->type) - { - snprintf(&buf[buf_pos], buf_size - buf_pos, fmtbuf, tcs->result); - } - else + + switch (formatchar) { - /* Need to fetch the tag data. */ - if (!tagcache_retrieve(tcs, tcs->idx_id, fmt->tags[parpos], - &buf[buf_pos], buf_size - buf_pos)) + case 's': + if (fmt->tags[parpos] == tcs->type) { - logf("retrieve failed"); - return -3; + result = tcs->result; + } + else + { + /* Need to fetch the tag data. */ + int tag = fmt->tags[parpos]; + + if (!tagcache_retrieve(tcs, tcs->idx_id, + (tag == tag_virt_basename ? + tag_filename : tag), + tmpbuf, space_left)) + { + logf("retrieve failed"); + return -3; + } + + if (tag == tag_virt_basename + && (result = strrchr(tmpbuf, '/')) != NULL) + { + result++; + } + else + result = tmpbuf; } + snprintf(&buf[buf_pos], space_left, fmtbuf, result); + break; + + case 'd': + snprintf(&buf[buf_pos], space_left, fmtbuf, + tagcache_get_numeric(tcs, fmt->tags[parpos])); } + buf_pos += strlen(&buf[buf_pos]); parpos++; } - else if (fmt->formatstr[i] == 'd') - { - fmtbuf[fmtbuf_pos] = '\0'; - read_format = false; - snprintf(&buf[buf_pos], buf_size - buf_pos, fmtbuf, - tagcache_get_numeric(tcs, fmt->tags[parpos])); - buf_pos += strlen(&buf[buf_pos]); - parpos++; - } - continue; } - - buf[buf_pos++] = fmt->formatstr[i]; + else + buf[buf_pos++] = fmt->formatstr[i]; if (buf_pos - 1 >= buf_size) { -- 1.7.1