diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2006-10-15 11:01:18 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2006-10-15 11:01:18 +0000 |
commit | b89b5ba2ee31bd351710670cf5ecc5aa8beb95f3 (patch) | |
tree | 67fa9676aed7cfca7048bc40e60f71e87007149f | |
parent | a7acf1351f3088c0d509e87d84db95d38fed788c (diff) | |
download | rockbox-b89b5ba2ee31bd351710670cf5ecc5aa8beb95f3.tar.gz rockbox-b89b5ba2ee31bd351710670cf5ecc5aa8beb95f3.zip |
(1) New syntax to support conditional formatting.
(2) Reduced tagnavi memory consumption.
(3) There was a bug that splash screen counter was counting down when
inserting tracks next. But in fact that might be preferred, so always
count down after successful tagcache query.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11223 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/tagcache.c | 355 | ||||
-rw-r--r-- | apps/tagcache.h | 4 | ||||
-rw-r--r-- | apps/tagnavi.config | 36 | ||||
-rw-r--r-- | apps/tagtree.c | 233 | ||||
-rw-r--r-- | apps/tagtree.h | 1 |
5 files changed, 398 insertions, 231 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c index ca2421171b..38537b5ceb 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c | |||
@@ -538,6 +538,96 @@ static bool write_index(int masterfd, int idxid, struct index_entry *idx) | |||
538 | return true; | 538 | return true; |
539 | } | 539 | } |
540 | 540 | ||
541 | static bool open_files(struct tagcache_search *tcs, int tag) | ||
542 | { | ||
543 | if (tcs->idxfd[tag] < 0) | ||
544 | { | ||
545 | char fn[MAX_PATH]; | ||
546 | |||
547 | snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tag); | ||
548 | tcs->idxfd[tag] = open(fn, O_RDONLY); | ||
549 | } | ||
550 | |||
551 | if (tcs->idxfd[tag] < 0) | ||
552 | { | ||
553 | logf("File not open!"); | ||
554 | return false; | ||
555 | } | ||
556 | |||
557 | return true; | ||
558 | } | ||
559 | |||
560 | static bool retrieve(struct tagcache_search *tcs, struct index_entry *idx, | ||
561 | int tag, char *buf, long size) | ||
562 | { | ||
563 | struct tagfile_entry tfe; | ||
564 | long seek; | ||
565 | |||
566 | *buf = '\0'; | ||
567 | |||
568 | if (tagcache_is_numeric_tag(tag)) | ||
569 | return false; | ||
570 | |||
571 | seek = idx->tag_seek[tag]; | ||
572 | if (seek < 0) | ||
573 | { | ||
574 | logf("Retrieve failed"); | ||
575 | return false; | ||
576 | } | ||
577 | |||
578 | #ifdef HAVE_TC_RAMCACHE | ||
579 | if (tcs->ramsearch) | ||
580 | { | ||
581 | struct tagfile_entry *ep; | ||
582 | |||
583 | # ifdef HAVE_DIRCACHE | ||
584 | if (tag == tag_filename && idx->flag & FLAG_DIRCACHE) | ||
585 | { | ||
586 | dircache_copy_path((struct dircache_entry *)seek, | ||
587 | buf, size); | ||
588 | return true; | ||
589 | } | ||
590 | else | ||
591 | # endif | ||
592 | if (tag != tag_filename) | ||
593 | { | ||
594 | ep = (struct tagfile_entry *)&hdr->tags[tag][seek]; | ||
595 | strncpy(buf, ep->tag_data, size-1); | ||
596 | |||
597 | return true; | ||
598 | } | ||
599 | } | ||
600 | #endif | ||
601 | |||
602 | if (!open_files(tcs, tag)) | ||
603 | return false; | ||
604 | |||
605 | lseek(tcs->idxfd[tag], seek, SEEK_SET); | ||
606 | if (read(tcs->idxfd[tag], &tfe, sizeof(struct tagfile_entry)) != | ||
607 | sizeof(struct tagfile_entry)) | ||
608 | { | ||
609 | logf("read error #5"); | ||
610 | return false; | ||
611 | } | ||
612 | |||
613 | if (tfe.tag_length >= size) | ||
614 | { | ||
615 | logf("too small buffer"); | ||
616 | return false; | ||
617 | } | ||
618 | |||
619 | if (read(tcs->idxfd[tag], buf, tfe.tag_length) != | ||
620 | tfe.tag_length) | ||
621 | { | ||
622 | logf("read error #6"); | ||
623 | return false; | ||
624 | } | ||
625 | |||
626 | buf[tfe.tag_length] = '\0'; | ||
627 | |||
628 | return true; | ||
629 | } | ||
630 | |||
541 | static long check_virtual_tags(int tag, const struct index_entry *idx) | 631 | static long check_virtual_tags(int tag, const struct index_entry *idx) |
542 | { | 632 | { |
543 | long data = 0; | 633 | long data = 0; |
@@ -671,6 +761,96 @@ static bool check_against_clause(long numeric, const char *str, | |||
671 | return false; | 761 | return false; |
672 | } | 762 | } |
673 | 763 | ||
764 | bool check_clauses(struct tagcache_search *tcs, | ||
765 | struct index_entry *idx, | ||
766 | struct tagcache_search_clause **clause, int count) | ||
767 | { | ||
768 | int i; | ||
769 | |||
770 | #ifdef HAVE_TC_RAMCACHE | ||
771 | if (tcs->ramsearch) | ||
772 | { | ||
773 | /* Go through all conditional clauses. */ | ||
774 | for (i = 0; i < count; i++) | ||
775 | { | ||
776 | struct tagfile_entry *tfe; | ||
777 | int seek; | ||
778 | char buf[256]; | ||
779 | char *str = NULL; | ||
780 | |||
781 | seek = check_virtual_tags(clause[i]->tag, idx); | ||
782 | |||
783 | if (!tagcache_is_numeric_tag(clause[i]->tag)) | ||
784 | { | ||
785 | if (clause[i]->tag == tag_filename) | ||
786 | { | ||
787 | retrieve(tcs, idx, tag_filename, buf, sizeof buf); | ||
788 | str = buf; | ||
789 | } | ||
790 | else | ||
791 | { | ||
792 | tfe = (struct tagfile_entry *)&hdr->tags[clause[i]->tag][seek]; | ||
793 | str = tfe->tag_data; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | if (!check_against_clause(seek, str, clause[i])) | ||
798 | return false; | ||
799 | } | ||
800 | } | ||
801 | else | ||
802 | #endif | ||
803 | { | ||
804 | /* Check for conditions. */ | ||
805 | for (i = 0; i < count; i++) | ||
806 | { | ||
807 | struct tagfile_entry tfe; | ||
808 | int seek; | ||
809 | char str[256]; | ||
810 | |||
811 | seek = check_virtual_tags(clause[i]->tag, idx); | ||
812 | |||
813 | memset(str, 0, sizeof str); | ||
814 | if (!tagcache_is_numeric_tag(clause[i]->tag)) | ||
815 | { | ||
816 | int fd = tcs->idxfd[clause[i]->tag]; | ||
817 | lseek(fd, seek, SEEK_SET); | ||
818 | read(fd, &tfe, sizeof(struct tagfile_entry)); | ||
819 | if (tfe.tag_length >= (int)sizeof(str)) | ||
820 | { | ||
821 | logf("Too long tag read!"); | ||
822 | break ; | ||
823 | } | ||
824 | |||
825 | read(fd, str, tfe.tag_length); | ||
826 | |||
827 | /* Check if entry has been deleted. */ | ||
828 | if (str[0] == '\0') | ||
829 | break; | ||
830 | } | ||
831 | |||
832 | if (!check_against_clause(seek, str, clause[i])) | ||
833 | return false; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | return true; | ||
838 | } | ||
839 | |||
840 | bool tagcache_check_clauses(struct tagcache_search *tcs, | ||
841 | struct tagcache_search_clause **clause, int count) | ||
842 | { | ||
843 | struct index_entry idx; | ||
844 | |||
845 | if (count == 0) | ||
846 | return true; | ||
847 | |||
848 | if (!get_index(tcs->masterfd, tcs->idx_id, &idx, true)) | ||
849 | return false; | ||
850 | |||
851 | return check_clauses(tcs, &idx, clause, count); | ||
852 | } | ||
853 | |||
674 | static bool add_uniqbuf(struct tagcache_search *tcs, long id) | 854 | static bool add_uniqbuf(struct tagcache_search *tcs, long id) |
675 | { | 855 | { |
676 | int i; | 856 | int i; |
@@ -713,18 +893,18 @@ static bool build_lookup_list(struct tagcache_search *tcs) | |||
713 | 893 | ||
714 | for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++) | 894 | for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++) |
715 | { | 895 | { |
896 | struct index_entry *idx = &hdr->indices[i]; | ||
716 | if (tcs->seek_list_count == SEEK_LIST_SIZE) | 897 | if (tcs->seek_list_count == SEEK_LIST_SIZE) |
717 | break ; | 898 | break ; |
718 | 899 | ||
719 | /* Skip deleted files. */ | 900 | /* Skip deleted files. */ |
720 | if (hdr->indices[i].flag & FLAG_DELETED) | 901 | if (idx->flag & FLAG_DELETED) |
721 | continue; | 902 | continue; |
722 | 903 | ||
723 | /* Go through all filters.. */ | 904 | /* Go through all filters.. */ |
724 | for (j = 0; j < tcs->filter_count; j++) | 905 | for (j = 0; j < tcs->filter_count; j++) |
725 | { | 906 | { |
726 | if (hdr->indices[i].tag_seek[tcs->filter_tag[j]] != | 907 | if (idx->tag_seek[tcs->filter_tag[j]] != tcs->filter_seek[j]) |
727 | tcs->filter_seek[j]) | ||
728 | { | 908 | { |
729 | break ; | 909 | break ; |
730 | } | 910 | } |
@@ -733,51 +913,17 @@ static bool build_lookup_list(struct tagcache_search *tcs) | |||
733 | if (j < tcs->filter_count) | 913 | if (j < tcs->filter_count) |
734 | continue ; | 914 | continue ; |
735 | 915 | ||
736 | /* Go through all conditional clauses. */ | 916 | /* Check for conditions. */ |
737 | for (j = 0; j < tcs->clause_count; j++) | 917 | if (!check_clauses(tcs, idx, tcs->clause, tcs->clause_count)) |
738 | { | 918 | continue; |
739 | struct index_entry *idx = &hdr->indices[i]; | ||
740 | int seek; | ||
741 | char buf[256]; | ||
742 | char *str = NULL; | ||
743 | struct tagfile_entry *entry; | ||
744 | |||
745 | seek = check_virtual_tags(tcs->clause[j]->tag, idx); | ||
746 | |||
747 | if (!tagcache_is_numeric_tag(tcs->clause[j]->tag)) | ||
748 | { | ||
749 | if (tcs->clause[j]->tag == tag_filename) | ||
750 | { | ||
751 | int oldtype = tcs->type; | ||
752 | tcs->type = tag_filename; | ||
753 | tagcache_retrieve(tcs, i, buf, sizeof buf); | ||
754 | tcs->type = oldtype; | ||
755 | str = buf; | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | entry = (struct tagfile_entry *)&hdr->tags[tcs->clause[j]->tag][seek]; | ||
760 | str = entry->tag_data; | ||
761 | } | ||
762 | } | ||
763 | |||
764 | |||
765 | if (!check_against_clause(seek, str, tcs->clause[j])) | ||
766 | break ; | ||
767 | } | ||
768 | |||
769 | if (j < tcs->clause_count) | ||
770 | continue ; | ||
771 | 919 | ||
772 | /* Add to the seek list if not already in uniq buffer. */ | 920 | /* Add to the seek list if not already in uniq buffer. */ |
773 | if (!add_uniqbuf(tcs, hdr->indices[i].tag_seek[tcs->type])) | 921 | if (!add_uniqbuf(tcs, idx->tag_seek[tcs->type])) |
774 | continue; | 922 | continue; |
775 | 923 | ||
776 | /* Lets add it. */ | 924 | /* Lets add it. */ |
777 | tcs->seek_list[tcs->seek_list_count] = | 925 | tcs->seek_list[tcs->seek_list_count] = idx->tag_seek[tcs->type]; |
778 | hdr->indices[i].tag_seek[tcs->type]; | 926 | tcs->seek_flags[tcs->seek_list_count] = idx->flag; |
779 | tcs->seek_flags[tcs->seek_list_count] = | ||
780 | hdr->indices[i].flag; | ||
781 | tcs->seek_list_count++; | 927 | tcs->seek_list_count++; |
782 | } | 928 | } |
783 | 929 | ||
@@ -813,39 +959,8 @@ static bool build_lookup_list(struct tagcache_search *tcs) | |||
813 | continue ; | 959 | continue ; |
814 | 960 | ||
815 | /* Check for conditions. */ | 961 | /* Check for conditions. */ |
816 | for (i = 0; i < tcs->clause_count; i++) | 962 | if (!check_clauses(tcs, &entry, tcs->clause, tcs->clause_count)) |
817 | { | 963 | continue; |
818 | struct tagfile_entry tfe; | ||
819 | int seek; | ||
820 | char str[256]; | ||
821 | |||
822 | seek = check_virtual_tags(tcs->clause[i]->tag, &entry); | ||
823 | |||
824 | memset(str, 0, sizeof str); | ||
825 | if (!tagcache_is_numeric_tag(tcs->clause[i]->tag)) | ||
826 | { | ||
827 | int fd = tcs->idxfd[tcs->clause[i]->tag]; | ||
828 | lseek(fd, seek, SEEK_SET); | ||
829 | read(fd, &tfe, sizeof(struct tagfile_entry)); | ||
830 | if (tfe.tag_length >= (int)sizeof(str)) | ||
831 | { | ||
832 | logf("Too long tag read!"); | ||
833 | break ; | ||
834 | } | ||
835 | |||
836 | read(fd, str, tfe.tag_length); | ||
837 | |||
838 | /* Check if entry has been deleted. */ | ||
839 | if (str[0] == '\0') | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | if (!check_against_clause(seek, str, tcs->clause[i])) | ||
844 | break ; | ||
845 | } | ||
846 | |||
847 | if (i < tcs->clause_count) | ||
848 | continue ; | ||
849 | 964 | ||
850 | /* Add to the seek list if not already in uniq buffer. */ | 965 | /* Add to the seek list if not already in uniq buffer. */ |
851 | if (!add_uniqbuf(tcs, entry.tag_seek[tcs->type])) | 966 | if (!add_uniqbuf(tcs, entry.tag_seek[tcs->type])) |
@@ -1025,25 +1140,6 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs, | |||
1025 | return true; | 1140 | return true; |
1026 | } | 1141 | } |
1027 | 1142 | ||
1028 | static bool open_files(struct tagcache_search *tcs) | ||
1029 | { | ||
1030 | if (tcs->idxfd[tcs->type] < 0) | ||
1031 | { | ||
1032 | char fn[MAX_PATH]; | ||
1033 | |||
1034 | snprintf(fn, sizeof fn, TAGCACHE_FILE_INDEX, tcs->type); | ||
1035 | tcs->idxfd[tcs->type] = open(fn, O_RDONLY); | ||
1036 | } | ||
1037 | |||
1038 | if (tcs->idxfd[tcs->type] < 0) | ||
1039 | { | ||
1040 | logf("File not open!"); | ||
1041 | return false; | ||
1042 | } | ||
1043 | |||
1044 | return true; | ||
1045 | } | ||
1046 | |||
1047 | #define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \ | 1143 | #define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \ |
1048 | ? (flag & FLAG_DIRCACHE) : 1) | 1144 | ? (flag & FLAG_DIRCACHE) : 1) |
1049 | 1145 | ||
@@ -1085,7 +1181,7 @@ static bool get_next(struct tagcache_search *tcs) | |||
1085 | if ((!tcs->ramsearch || !TAG_FILENAME_RAM(tcs)) | 1181 | if ((!tcs->ramsearch || !TAG_FILENAME_RAM(tcs)) |
1086 | && !tagcache_is_numeric_tag(tcs->type)) | 1182 | && !tagcache_is_numeric_tag(tcs->type)) |
1087 | { | 1183 | { |
1088 | if (!open_files(tcs)) | 1184 | if (!open_files(tcs, tcs->type)) |
1089 | return false; | 1185 | return false; |
1090 | 1186 | ||
1091 | lseek(tcs->idxfd[tcs->type], tcs->seek_list[tcs->seek_list_count], SEEK_SET); | 1187 | lseek(tcs->idxfd[tcs->type], tcs->seek_list[tcs->seek_list_count], SEEK_SET); |
@@ -1144,7 +1240,7 @@ static bool get_next(struct tagcache_search *tcs) | |||
1144 | else | 1240 | else |
1145 | #endif | 1241 | #endif |
1146 | { | 1242 | { |
1147 | if (!open_files(tcs)) | 1243 | if (!open_files(tcs, tcs->type)) |
1148 | return false; | 1244 | return false; |
1149 | 1245 | ||
1150 | tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR); | 1246 | tcs->result_seek = lseek(tcs->idxfd[tcs->type], 0, SEEK_CUR); |
@@ -1193,72 +1289,13 @@ bool tagcache_get_next(struct tagcache_search *tcs) | |||
1193 | bool tagcache_retrieve(struct tagcache_search *tcs, int idxid, | 1289 | bool tagcache_retrieve(struct tagcache_search *tcs, int idxid, |
1194 | char *buf, long size) | 1290 | char *buf, long size) |
1195 | { | 1291 | { |
1196 | struct tagfile_entry tfe; | ||
1197 | struct index_entry idx; | 1292 | struct index_entry idx; |
1198 | long seek; | ||
1199 | 1293 | ||
1200 | *buf = '\0'; | 1294 | *buf = '\0'; |
1201 | if (!get_index(tcs->masterfd, idxid, &idx, true)) | 1295 | if (!get_index(tcs->masterfd, idxid, &idx, true)) |
1202 | return false; | 1296 | return false; |
1203 | 1297 | ||
1204 | seek = idx.tag_seek[tcs->type]; | 1298 | return retrieve(tcs, &idx, tcs->type, buf, size); |
1205 | if (seek < 0) | ||
1206 | { | ||
1207 | logf("Retrieve failed"); | ||
1208 | return false; | ||
1209 | } | ||
1210 | |||
1211 | #ifdef HAVE_TC_RAMCACHE | ||
1212 | if (tcs->ramsearch) | ||
1213 | { | ||
1214 | struct tagfile_entry *ep; | ||
1215 | |||
1216 | # ifdef HAVE_DIRCACHE | ||
1217 | if (tcs->type == tag_filename && hdr->indices[idxid].flag & FLAG_DIRCACHE) | ||
1218 | { | ||
1219 | dircache_copy_path((struct dircache_entry *)seek, | ||
1220 | buf, size); | ||
1221 | return true; | ||
1222 | } | ||
1223 | else | ||
1224 | # endif | ||
1225 | if (tcs->type != tag_filename) | ||
1226 | { | ||
1227 | ep = (struct tagfile_entry *)&hdr->tags[tcs->type][seek]; | ||
1228 | strncpy(buf, ep->tag_data, size-1); | ||
1229 | |||
1230 | return true; | ||
1231 | } | ||
1232 | } | ||
1233 | #endif | ||
1234 | |||
1235 | if (!open_files(tcs)) | ||
1236 | return false; | ||
1237 | |||
1238 | lseek(tcs->idxfd[tcs->type], seek, SEEK_SET); | ||
1239 | if (read(tcs->idxfd[tcs->type], &tfe, sizeof(struct tagfile_entry)) != | ||
1240 | sizeof(struct tagfile_entry)) | ||
1241 | { | ||
1242 | logf("read error #5"); | ||
1243 | return false; | ||
1244 | } | ||
1245 | |||
1246 | if (tfe.tag_length >= size) | ||
1247 | { | ||
1248 | logf("too small buffer"); | ||
1249 | return false; | ||
1250 | } | ||
1251 | |||
1252 | if (read(tcs->idxfd[tcs->type], buf, tfe.tag_length) != | ||
1253 | tfe.tag_length) | ||
1254 | { | ||
1255 | logf("read error #6"); | ||
1256 | return false; | ||
1257 | } | ||
1258 | |||
1259 | buf[tfe.tag_length] = '\0'; | ||
1260 | |||
1261 | return true; | ||
1262 | } | 1299 | } |
1263 | 1300 | ||
1264 | #if 0 | 1301 | #if 0 |
@@ -2961,11 +2998,13 @@ static bool delete_entry(long idx_id) | |||
2961 | 2998 | ||
2962 | /* Skip the header block */ | 2999 | /* Skip the header block */ |
2963 | lseek(fd, myidx.tag_seek[tag] + sizeof(struct tagfile_entry), SEEK_SET); | 3000 | lseek(fd, myidx.tag_seek[tag] + sizeof(struct tagfile_entry), SEEK_SET); |
2964 | 3001 | ||
3002 | /* Debug, print 10 first characters of the tag | ||
2965 | read(fd, buf, 10); | 3003 | read(fd, buf, 10); |
2966 | buf[10]='\0'; | 3004 | buf[10]='\0'; |
2967 | logf("TAG:%s", buf); | 3005 | logf("TAG:%s", buf); |
2968 | lseek(fd, -10, SEEK_CUR); | 3006 | lseek(fd, -10, SEEK_CUR); |
3007 | */ | ||
2969 | 3008 | ||
2970 | /* Write first data byte in tag as \0 */ | 3009 | /* Write first data byte in tag as \0 */ |
2971 | write(fd, "", 1); | 3010 | write(fd, "", 1); |
diff --git a/apps/tagcache.h b/apps/tagcache.h index f2694cea1b..37423e63c8 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h | |||
@@ -98,7 +98,7 @@ struct tagcache_search_clause | |||
98 | bool numeric; | 98 | bool numeric; |
99 | bool input; | 99 | bool input; |
100 | long numeric_data; | 100 | long numeric_data; |
101 | char str[128]; | 101 | char *str; |
102 | }; | 102 | }; |
103 | 103 | ||
104 | struct tagcache_search { | 104 | struct tagcache_search { |
@@ -139,6 +139,8 @@ bool tagcache_is_numeric_tag(int type); | |||
139 | bool tagcache_is_unique_tag(int type); | 139 | bool tagcache_is_unique_tag(int type); |
140 | bool tagcache_is_sorted_tag(int type); | 140 | bool tagcache_is_sorted_tag(int type); |
141 | bool tagcache_find_index(struct tagcache_search *tcs, const char *filename); | 141 | bool tagcache_find_index(struct tagcache_search *tcs, const char *filename); |
142 | bool tagcache_check_clauses(struct tagcache_search *tcs, | ||
143 | struct tagcache_search_clause **clause, int count); | ||
142 | bool tagcache_search(struct tagcache_search *tcs, int tag); | 144 | bool tagcache_search(struct tagcache_search *tcs, int tag); |
143 | void tagcache_search_set_uniqbuf(struct tagcache_search *tcs, | 145 | void tagcache_search_set_uniqbuf(struct tagcache_search *tcs, |
144 | void *buffer, long length); | 146 | void *buffer, long length); |
diff --git a/apps/tagnavi.config b/apps/tagnavi.config index fdf66828af..191b4bdda5 100644 --- a/apps/tagnavi.config +++ b/apps/tagnavi.config | |||
@@ -5,6 +5,15 @@ | |||
5 | # Instead, you can modify "/.rockbox/tagnavi_custom.config" which will never | 5 | # Instead, you can modify "/.rockbox/tagnavi_custom.config" which will never |
6 | # get overwritten automatically. | 6 | # get overwritten automatically. |
7 | 7 | ||
8 | # Basic format declarations | ||
9 | %format "fmt_title" "%02d. %s" tracknum title ? tracknum > "0" | ||
10 | %format "fmt_title" "%s" title | ||
11 | %format "fmt_mostplayed" "(%3d) %s" playcount title %sort = "inverse" %limit = "100" | ||
12 | %format "fmt_lastplayed" "%06d%s" lastplayed title %sort = "inverse" %limit = "99" %strip = "6" | ||
13 | %format "fmt_best_tracks" "%02d. %s (%3d)" tracknum title autoscore | ||
14 | %format "fmt_played" "(%3d/%d) %s" autoscore playcount title | ||
15 | %format "fmt_score" "(%3d) %s" autoscore title | ||
16 | |||
8 | # Include our custom menu | 17 | # Include our custom menu |
9 | %include "/.rockbox/tagnavi_custom.config" | 18 | %include "/.rockbox/tagnavi_custom.config" |
10 | 19 | ||
@@ -14,11 +23,11 @@ | |||
14 | 23 | ||
15 | # Define the search sub menu | 24 | # Define the search sub menu |
16 | %menu_start "search" "Search by..." | 25 | %menu_start "search" "Search by..." |
17 | "Artist" -> artist ? artist ~ "" -> album -> title = "%02d. %s" tracknum title | 26 | "Artist" -> artist ? artist ~ "" -> album -> title = "fmt_title" |
18 | "Album" -> album ? album ~ "" -> title = "%02d. %s" tracknum title | 27 | "Album" -> album ? album ~ "" -> title = "fmt_title" |
19 | "Title" -> title ? title ~ "" | 28 | "Title" -> title ? title ~ "" |
20 | "Filename" -> filename ? filename ~ "" | 29 | "Filename" -> filename ? filename ~ "" |
21 | "Score" -> title = "(%3d) %s" autoscore title ? autoscore > "" | 30 | "Score" -> title = "fmt_score" ? autoscore > "" |
22 | 31 | ||
23 | # ^ An empy line ends the menu | 32 | # ^ An empy line ends the menu |
24 | 33 | ||
@@ -28,19 +37,20 @@ | |||
28 | 37 | ||
29 | # Define the title of the main menu | 38 | # Define the title of the main menu |
30 | %menu_start "main" "Browse by..." | 39 | %menu_start "main" "Browse by..." |
31 | "Artist" -> artist -> album -> title = "%02d. %s" tracknum title | 40 | "Artist" -> artist -> album -> title = "fmt_title" |
32 | "Album" -> album -> title = "%02d. %s" tracknum title | 41 | "Album" -> album -> title = "fmt_title" |
33 | "Genre" -> genre -> artist -> album -> title = "%02d. %s" tracknum title | 42 | "Genre" -> genre -> artist -> album -> title = "fmt_title" |
34 | "Composer" -> composer -> album -> title = "%02d. %s" tracknum title | 43 | "Composer" -> composer -> album -> title = "fmt_title" |
35 | "Track" -> title | 44 | "Track" -> title |
36 | "Year" -> year ? year > "1000" & year < "2008" -> artist -> album -> title = "%02d. %s" tracknum title | 45 | "Year" -> year ? year > "1000" & year < "2008" -> artist -> album -> title = "fmt_title" |
37 | "Search..." ==> "search" | 46 | "Search..." ==> "search" |
38 | "Most played tracks" -> title = "(%3d) %s" playcount title %sort = "inverse" %limit = "100" ? playcount > "0" | 47 | "Most played tracks" -> title = "fmt_mostplayed" ? playcount > "0" |
39 | "Last played tracks" -> title = "%06d%s" lastplayed title %sort = "inverse" %limit = "99" %strip = "6" ? playcount > "0" | 48 | "Last played tracks" -> title = "fmt_lastplayed" ? playcount > "0" |
40 | "Never played tracks" -> artist ? playcount == "0" -> album -> title = "%02d. %s" tracknum title | 49 | "Never played tracks" -> artist ? playcount == "0" -> album -> title = "fmt_title" |
41 | "Best tracks" -> artist ? playcount > "1" & autoscore > "85" -> album -> title = "%02d. %s (%3d)" tracknum title autoscore | 50 | "Best tracks" -> artist ? playcount > "1" & autoscore > "85" -> album -> title = "fmt_best_tracks" |
42 | "List played tracks" -> title = "(%3d/%d) %s" autoscore playcount title ? playcount > "0" | 51 | "List played tracks" -> title = "fmt_played" ? playcount > "0" |
43 | "Custom view..." ==> "custom" | 52 | "Custom view..." ==> "custom" |
44 | 53 | ||
45 | # And finally set main menu as our root menu | 54 | # And finally set main menu as our root menu |
46 | %root_menu "main" | 55 | %root_menu "main" |
56 | |||
diff --git a/apps/tagtree.c b/apps/tagtree.c index d8d8597d68..a360098aee 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c | |||
@@ -56,6 +56,7 @@ enum variables { | |||
56 | var_menu_start, | 56 | var_menu_start, |
57 | var_include, | 57 | var_include, |
58 | var_rootmenu, | 58 | var_rootmenu, |
59 | var_format, | ||
59 | menu_next, | 60 | menu_next, |
60 | menu_load, | 61 | menu_load, |
61 | }; | 62 | }; |
@@ -82,8 +83,11 @@ static bool sort_inverse; | |||
82 | * sort_inverse = true | 83 | * sort_inverse = true |
83 | */ | 84 | */ |
84 | struct display_format { | 85 | struct display_format { |
85 | bool valid; | 86 | char name[32]; |
86 | char formatstr[64]; | 87 | struct tagcache_search_clause *clause[TAGCACHE_MAX_CLAUSES]; |
88 | int clause_count; | ||
89 | char *formatstr; | ||
90 | int group_id; | ||
87 | int tags[MAX_TAGS]; | 91 | int tags[MAX_TAGS]; |
88 | int tag_count; | 92 | int tag_count; |
89 | 93 | ||
@@ -92,12 +96,15 @@ struct display_format { | |||
92 | bool sort_inverse; | 96 | bool sort_inverse; |
93 | }; | 97 | }; |
94 | 98 | ||
99 | static struct display_format *formats[TAGMENU_MAX_FMTS]; | ||
100 | static int format_count; | ||
101 | |||
95 | struct search_instruction { | 102 | struct search_instruction { |
96 | char name[64]; | 103 | char name[64]; |
97 | int tagorder[MAX_TAGS]; | 104 | int tagorder[MAX_TAGS]; |
98 | int tagorder_count; | 105 | int tagorder_count; |
99 | struct tagcache_search_clause clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; | 106 | struct tagcache_search_clause *clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; |
100 | struct display_format format[MAX_TAGS]; | 107 | int format_id[MAX_TAGS]; |
101 | int clause_count[MAX_TAGS]; | 108 | int clause_count[MAX_TAGS]; |
102 | int result_seek[MAX_TAGS]; | 109 | int result_seek[MAX_TAGS]; |
103 | }; | 110 | }; |
@@ -130,6 +137,7 @@ static int root_menu; | |||
130 | static int current_offset; | 137 | static int current_offset; |
131 | static int current_entry_count; | 138 | static int current_entry_count; |
132 | 139 | ||
140 | static int format_count; | ||
133 | static struct tree_context *tc; | 141 | static struct tree_context *tc; |
134 | 142 | ||
135 | static int get_token_str(char *buf, int size) | 143 | static int get_token_str(char *buf, int size) |
@@ -200,6 +208,7 @@ static int get_tag(int *tag) | |||
200 | MATCH(tag, buf, "%menu_start", var_menu_start); | 208 | MATCH(tag, buf, "%menu_start", var_menu_start); |
201 | MATCH(tag, buf, "%include", var_include); | 209 | MATCH(tag, buf, "%include", var_include); |
202 | MATCH(tag, buf, "%root_menu", var_rootmenu); | 210 | MATCH(tag, buf, "%root_menu", var_rootmenu); |
211 | MATCH(tag, buf, "%format", var_format); | ||
203 | MATCH(tag, buf, "->", menu_next); | 212 | MATCH(tag, buf, "->", menu_next); |
204 | MATCH(tag, buf, "==>", menu_load); | 213 | MATCH(tag, buf, "==>", menu_load); |
205 | 214 | ||
@@ -249,45 +258,36 @@ static int get_clause(int *condition) | |||
249 | return 0; | 258 | return 0; |
250 | } | 259 | } |
251 | 260 | ||
252 | static bool add_clause(struct search_instruction *inst, | 261 | static bool read_clause(struct tagcache_search_clause *clause) |
253 | int tag, int type, const char *str) | ||
254 | { | 262 | { |
255 | int len = strlen(str); | 263 | char buf[256]; |
256 | struct tagcache_search_clause *clause; | ||
257 | 264 | ||
258 | if (inst->clause_count[inst->tagorder_count] >= TAGCACHE_MAX_CLAUSES) | 265 | if (get_tag(&clause->tag) <= 0) |
259 | { | ||
260 | logf("Too many clauses"); | ||
261 | return false; | 266 | return false; |
262 | } | ||
263 | 267 | ||
264 | clause = &inst->clause[inst->tagorder_count] | 268 | if (get_clause(&clause->type) <= 0) |
265 | [inst->clause_count[inst->tagorder_count]]; | ||
266 | if (len >= (int)sizeof(clause->str) - 1) | ||
267 | { | ||
268 | logf("Too long str in condition"); | ||
269 | return false; | 269 | return false; |
270 | } | ||
271 | 270 | ||
272 | clause->tag = tag; | 271 | if (get_token_str(buf, sizeof buf) < 0) |
273 | clause->type = type; | 272 | return false; |
274 | if (len == 0) | 273 | |
274 | clause->str = buffer_alloc(strlen(buf)+1); | ||
275 | strcpy(clause->str, buf); | ||
276 | |||
277 | logf("got clause: %d/%d [%s]", clause->tag, clause->type, clause->str); | ||
278 | |||
279 | if (*(clause->str) == '\0') | ||
275 | clause->input = true; | 280 | clause->input = true; |
276 | else | 281 | else |
277 | clause->input = false; | 282 | clause->input = false; |
278 | 283 | ||
279 | if (tagcache_is_numeric_tag(tag)) | 284 | if (tagcache_is_numeric_tag(clause->tag)) |
280 | { | 285 | { |
281 | clause->numeric = true; | 286 | clause->numeric = true; |
282 | clause->numeric_data = atoi(str); | 287 | clause->numeric_data = atoi(clause->str); |
283 | } | 288 | } |
284 | else | 289 | else |
285 | { | ||
286 | clause->numeric = false; | 290 | clause->numeric = false; |
287 | strcpy(clause->str, str); | ||
288 | } | ||
289 | |||
290 | inst->clause_count[inst->tagorder_count]++; | ||
291 | 291 | ||
292 | return true; | 292 | return true; |
293 | } | 293 | } |
@@ -313,12 +313,38 @@ static int get_format_str(struct display_format *fmt) | |||
313 | { | 313 | { |
314 | int ret; | 314 | int ret; |
315 | char buf[128]; | 315 | char buf[128]; |
316 | int i; | ||
316 | 317 | ||
317 | memset(fmt, 0, sizeof(struct display_format)); | 318 | memset(fmt, 0, sizeof(struct display_format)); |
318 | 319 | ||
319 | if (get_token_str(fmt->formatstr, sizeof fmt->formatstr) < 0) | 320 | if (get_token_str(fmt->name, sizeof fmt->name) < 0) |
321 | return -10; | ||
322 | |||
323 | /* Determine the group id */ | ||
324 | fmt->group_id = 0; | ||
325 | for (i = 0; i < format_count; i++) | ||
326 | { | ||
327 | if (!strcasecmp(formats[i]->name, fmt->name)) | ||
328 | { | ||
329 | fmt->group_id = formats[i]->group_id; | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | if (formats[i]->group_id > fmt->group_id) | ||
334 | fmt->group_id = formats[i]->group_id; | ||
335 | } | ||
336 | |||
337 | if (i == format_count) | ||
338 | fmt->group_id++; | ||
339 | |||
340 | logf("format: (%d) %s", fmt->group_id, fmt->name); | ||
341 | |||
342 | if (get_token_str(buf, sizeof buf) < 0) | ||
320 | return -10; | 343 | return -10; |
321 | 344 | ||
345 | fmt->formatstr = buffer_alloc(strlen(buf) + 1); | ||
346 | strcpy(fmt->formatstr, buf); | ||
347 | |||
322 | while (fmt->tag_count < MAX_TAGS) | 348 | while (fmt->tag_count < MAX_TAGS) |
323 | { | 349 | { |
324 | ret = get_tag(&fmt->tags[fmt->tag_count]); | 350 | ret = get_tag(&fmt->tags[fmt->tag_count]); |
@@ -353,27 +379,79 @@ static int get_format_str(struct display_format *fmt) | |||
353 | } | 379 | } |
354 | } | 380 | } |
355 | 381 | ||
356 | fmt->valid = true; | 382 | return 1; |
383 | } | ||
384 | |||
385 | static int add_format(const char *buf) | ||
386 | { | ||
387 | strp = buf; | ||
388 | |||
389 | if (formats[format_count] == NULL) | ||
390 | formats[format_count] = buffer_alloc(sizeof(struct display_format)); | ||
391 | |||
392 | memset(formats[format_count], 0, sizeof(struct display_format)); | ||
393 | if (get_format_str(formats[format_count]) < 0) | ||
394 | { | ||
395 | logf("get_format_str() parser failed!"); | ||
396 | return -4; | ||
397 | } | ||
398 | |||
399 | while (*strp != '\0' && *strp != '?') | ||
400 | strp++; | ||
401 | |||
402 | if (*strp == '?') | ||
403 | { | ||
404 | int clause_count = 0; | ||
405 | strp++; | ||
406 | |||
407 | while (1) | ||
408 | { | ||
409 | formats[format_count]->clause[clause_count] = | ||
410 | buffer_alloc(sizeof(struct tagcache_search_clause)); | ||
411 | |||
412 | if (!read_clause(formats[format_count]->clause[clause_count])) | ||
413 | break; | ||
414 | |||
415 | clause_count++; | ||
416 | } | ||
417 | |||
418 | formats[format_count]->clause_count = clause_count; | ||
419 | } | ||
420 | |||
421 | format_count++; | ||
357 | 422 | ||
358 | return 1; | 423 | return 1; |
359 | } | 424 | } |
360 | 425 | ||
361 | static int get_condition(struct search_instruction *inst) | 426 | static int get_condition(struct search_instruction *inst) |
362 | { | 427 | { |
363 | int tag; | 428 | int clause_count; |
364 | int condition; | ||
365 | char buf[128]; | 429 | char buf[128]; |
366 | 430 | ||
367 | switch (*strp) | 431 | switch (*strp) |
368 | { | 432 | { |
369 | case '=': | 433 | case '=': |
370 | if (get_format_str(&inst->format[inst->tagorder_count]) < 0) | 434 | { |
435 | int i; | ||
436 | |||
437 | if (get_token_str(buf, sizeof buf) < 0) | ||
438 | return -1; | ||
439 | |||
440 | for (i = 0; i < format_count; i++) | ||
371 | { | 441 | { |
372 | logf("get_format_str() parser failed!"); | 442 | if (!strcasecmp(formats[i]->name, buf)) |
373 | return -4; | 443 | break; |
374 | } | 444 | } |
445 | |||
446 | if (i == format_count) | ||
447 | { | ||
448 | logf("format not found: %s", buf); | ||
449 | return -2; | ||
450 | } | ||
451 | |||
452 | inst->format_id[inst->tagorder_count] = formats[i]->group_id; | ||
375 | return 1; | 453 | return 1; |
376 | 454 | } | |
377 | case '?': | 455 | case '?': |
378 | case ' ': | 456 | case ' ': |
379 | case '&': | 457 | case '&': |
@@ -384,17 +462,20 @@ static int get_condition(struct search_instruction *inst) | |||
384 | return 0; | 462 | return 0; |
385 | } | 463 | } |
386 | 464 | ||
387 | if (get_tag(&tag) <= 0) | 465 | clause_count = inst->clause_count[inst->tagorder_count]; |
388 | return -1; | 466 | if (clause_count >= TAGCACHE_MAX_CLAUSES) |
467 | { | ||
468 | logf("Too many clauses"); | ||
469 | return false; | ||
470 | } | ||
389 | 471 | ||
390 | if (get_clause(&condition) <= 0) | 472 | inst->clause[inst->tagorder_count][clause_count] = |
391 | return -2; | 473 | buffer_alloc(sizeof(struct tagcache_search_clause)); |
392 | 474 | ||
393 | if (get_token_str(buf, sizeof buf) < 0) | 475 | if (!read_clause(inst->clause[inst->tagorder_count][clause_count])) |
394 | return -3; | 476 | return -1; |
395 | 477 | ||
396 | logf("got clause: %d/%d [%s]", tag, condition, buf); | 478 | inst->clause_count[inst->tagorder_count]++; |
397 | add_clause(inst, tag, condition, buf); | ||
398 | 479 | ||
399 | return 1; | 480 | return 1; |
400 | } | 481 | } |
@@ -465,7 +546,9 @@ static bool parse_search(struct menu_entry *entry, const char *str) | |||
465 | 546 | ||
466 | logf("tag: %d", inst->tagorder[inst->tagorder_count]); | 547 | logf("tag: %d", inst->tagorder[inst->tagorder_count]); |
467 | 548 | ||
468 | while (get_condition(inst) > 0) ; | 549 | while ( (ret = get_condition(inst)) > 0 ) ; |
550 | if (ret < 0) | ||
551 | return false; | ||
469 | 552 | ||
470 | inst->tagorder_count++; | 553 | inst->tagorder_count++; |
471 | 554 | ||
@@ -658,6 +741,13 @@ static bool parse_menu(const char *filename) | |||
658 | 741 | ||
659 | switch (variable) | 742 | switch (variable) |
660 | { | 743 | { |
744 | case var_format: | ||
745 | if (add_format(strp) < 0) | ||
746 | { | ||
747 | logf("Format add fail: %s", data); | ||
748 | } | ||
749 | break; | ||
750 | |||
661 | case var_include: | 751 | case var_include: |
662 | if (get_token_str(data, sizeof(data)) < 0) | 752 | if (get_token_str(data, sizeof(data)) < 0) |
663 | { | 753 | { |
@@ -731,9 +821,9 @@ static bool parse_menu(const char *filename) | |||
731 | menu->items[menu->itemcount] = buffer_alloc(sizeof(struct menu_entry)); | 821 | menu->items[menu->itemcount] = buffer_alloc(sizeof(struct menu_entry)); |
732 | memset(menu->items[menu->itemcount], 0, sizeof(struct menu_entry)); | 822 | memset(menu->items[menu->itemcount], 0, sizeof(struct menu_entry)); |
733 | menu->items[menu->itemcount]->si = buffer_alloc(sizeof(struct search_instruction)); | 823 | menu->items[menu->itemcount]->si = buffer_alloc(sizeof(struct search_instruction)); |
734 | memset(menu->items[menu->itemcount]->si, 0, sizeof(struct search_instruction)); | ||
735 | } | 824 | } |
736 | 825 | ||
826 | memset(menu->items[menu->itemcount]->si, 0, sizeof(struct search_instruction)); | ||
737 | if (!parse_search(menu->items[menu->itemcount], buf)) | 827 | if (!parse_search(menu->items[menu->itemcount], buf)) |
738 | continue; | 828 | continue; |
739 | 829 | ||
@@ -746,6 +836,7 @@ static bool parse_menu(const char *filename) | |||
746 | 836 | ||
747 | void tagtree_init(void) | 837 | void tagtree_init(void) |
748 | { | 838 | { |
839 | format_count = 0; | ||
749 | menu_count = 0; | 840 | menu_count = 0; |
750 | menu = NULL; | 841 | menu = NULL; |
751 | root_menu = 0; | 842 | root_menu = 0; |
@@ -852,14 +943,21 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, | |||
852 | int j; | 943 | int j; |
853 | 944 | ||
854 | for (j = 0; j < csi->clause_count[i]; j++) | 945 | for (j = 0; j < csi->clause_count[i]; j++) |
855 | tagcache_search_add_clause(tcs, &csi->clause[i][j]); | 946 | tagcache_search_add_clause(tcs, csi->clause[i][j]); |
856 | } | 947 | } |
857 | 948 | ||
858 | current_offset = offset; | 949 | current_offset = offset; |
859 | current_entry_count = 0; | 950 | current_entry_count = 0; |
860 | c->dirfull = false; | 951 | c->dirfull = false; |
861 | fmt = &csi->format[level]; | 952 | |
862 | if (fmt->valid) | 953 | fmt = NULL; |
954 | for (i = 0; i < format_count; i++) | ||
955 | { | ||
956 | if (formats[i]->group_id == csi->format_id[level]) | ||
957 | fmt = formats[i]; | ||
958 | } | ||
959 | |||
960 | if (fmt) | ||
863 | { | 961 | { |
864 | sort_inverse = fmt->sort_inverse; | 962 | sort_inverse = fmt->sort_inverse; |
865 | sort_limit = fmt->limit; | 963 | sort_limit = fmt->limit; |
@@ -900,12 +998,27 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, | |||
900 | else | 998 | else |
901 | dptr->extraseek = tcs->result_seek; | 999 | dptr->extraseek = tcs->result_seek; |
902 | 1000 | ||
903 | if (!tcs->ramresult || fmt->valid) | 1001 | fmt = NULL; |
1002 | /* Check the format */ | ||
1003 | for (i = 0; i < format_count; i++) | ||
1004 | { | ||
1005 | if (formats[i]->group_id != csi->format_id[level]) | ||
1006 | continue; | ||
1007 | |||
1008 | if (tagcache_check_clauses(tcs, formats[i]->clause, | ||
1009 | formats[i]->clause_count)) | ||
1010 | { | ||
1011 | fmt = formats[i]; | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | if (!tcs->ramresult || fmt) | ||
904 | { | 1017 | { |
905 | char buf[MAX_PATH]; | 1018 | char buf[MAX_PATH]; |
906 | int buf_pos = 0; | 1019 | int buf_pos = 0; |
907 | 1020 | ||
908 | if (fmt->valid) | 1021 | if (fmt) |
909 | { | 1022 | { |
910 | char fmtbuf[8]; | 1023 | char fmtbuf[8]; |
911 | bool read_format = false; | 1024 | bool read_format = false; |
@@ -968,7 +1081,7 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, | |||
968 | } | 1081 | } |
969 | 1082 | ||
970 | dptr->name = &c->name_buffer[namebufused]; | 1083 | dptr->name = &c->name_buffer[namebufused]; |
971 | if (fmt->valid) | 1084 | if (fmt) |
972 | namebufused += buf_pos; | 1085 | namebufused += buf_pos; |
973 | else | 1086 | else |
974 | namebufused += tcs->result_len; | 1087 | namebufused += tcs->result_len; |
@@ -980,7 +1093,7 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs, | |||
980 | sort = false; | 1093 | sort = false; |
981 | break ; | 1094 | break ; |
982 | } | 1095 | } |
983 | if (fmt->valid) | 1096 | if (fmt) |
984 | strcpy(dptr->name, buf); | 1097 | strcpy(dptr->name, buf); |
985 | else | 1098 | else |
986 | strcpy(dptr->name, tcs->result); | 1099 | strcpy(dptr->name, tcs->result); |
@@ -1192,7 +1305,7 @@ int tagtree_enter(struct tree_context* c) | |||
1192 | { | 1305 | { |
1193 | for (j = 0; j < csi->clause_count[i]; j++) | 1306 | for (j = 0; j < csi->clause_count[i]; j++) |
1194 | { | 1307 | { |
1195 | if (!csi->clause[i][j].input) | 1308 | if (!csi->clause[i][j]->input) |
1196 | continue; | 1309 | continue; |
1197 | 1310 | ||
1198 | rc = kbd_input(searchstring, sizeof(searchstring)); | 1311 | rc = kbd_input(searchstring, sizeof(searchstring)); |
@@ -1202,11 +1315,11 @@ int tagtree_enter(struct tree_context* c) | |||
1202 | return 0; | 1315 | return 0; |
1203 | } | 1316 | } |
1204 | 1317 | ||
1205 | if (csi->clause[i][j].numeric) | 1318 | if (csi->clause[i][j]->numeric) |
1206 | csi->clause[i][j].numeric_data = atoi(searchstring); | 1319 | csi->clause[i][j]->numeric_data = atoi(searchstring); |
1207 | else | 1320 | else |
1208 | strncpy(csi->clause[i][j].str, searchstring, | 1321 | strncpy(csi->clause[i][j]->str, searchstring, |
1209 | sizeof(csi->clause[i][j].str)-1); | 1322 | sizeof(csi->clause[i][j]->str)-1); |
1210 | } | 1323 | } |
1211 | } | 1324 | } |
1212 | } | 1325 | } |
@@ -1297,6 +1410,7 @@ bool insert_all_playlist(struct tree_context *c, int position, bool queue) | |||
1297 | int i; | 1410 | int i; |
1298 | char buf[MAX_PATH]; | 1411 | char buf[MAX_PATH]; |
1299 | int from, to, direction; | 1412 | int from, to, direction; |
1413 | int files_left = c->filesindir; | ||
1300 | 1414 | ||
1301 | cpu_boost_id(true, CPUBOOSTID_TAGTREE); | 1415 | cpu_boost_id(true, CPUBOOSTID_TAGTREE); |
1302 | if (!tagcache_search(&tcs, tag_filename)) | 1416 | if (!tagcache_search(&tcs, tag_filename)) |
@@ -1321,7 +1435,8 @@ bool insert_all_playlist(struct tree_context *c, int position, bool queue) | |||
1321 | 1435 | ||
1322 | for (i = from; i != to; i += direction) | 1436 | for (i = from; i != to; i += direction) |
1323 | { | 1437 | { |
1324 | if (!show_search_progress(false, i)) | 1438 | /* Count back to zero */ |
1439 | if (!show_search_progress(false, files_left--)) | ||
1325 | break; | 1440 | break; |
1326 | 1441 | ||
1327 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->extraseek, | 1442 | if (!tagcache_retrieve(&tcs, tagtree_get_entry(c, i)->extraseek, |
diff --git a/apps/tagtree.h b/apps/tagtree.h index 9f570917f7..2c85bf90e1 100644 --- a/apps/tagtree.h +++ b/apps/tagtree.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #define TAGNAVI_VERSION "#! rockbox/tagbrowser/2.0" | 25 | #define TAGNAVI_VERSION "#! rockbox/tagbrowser/2.0" |
26 | #define TAGMENU_MAX_ITEMS 64 | 26 | #define TAGMENU_MAX_ITEMS 64 |
27 | #define TAGMENU_MAX_MENUS 16 | 27 | #define TAGMENU_MAX_MENUS 16 |
28 | #define TAGMENU_MAX_FMTS 32 | ||
28 | 29 | ||
29 | enum table { root = 1, navibrowse, allsubentries, playtrack }; | 30 | enum table { root = 1, navibrowse, allsubentries, playtrack }; |
30 | 31 | ||