diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2006-09-19 11:54:33 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2006-09-19 11:54:33 +0000 |
commit | ba34c379676f629d94b80d0c4076e6b08ade171e (patch) | |
tree | 5aa0ad237f799c01f8b80a25dddb2a974399b767 /apps/tagtree.c | |
parent | 1d5b248f7b8ed9a82f63587f9090556a45885405 (diff) | |
download | rockbox-ba34c379676f629d94b80d0c4076e6b08ade171e.tar.gz rockbox-ba34c379676f629d94b80d0c4076e6b08ade171e.zip |
Improved tag browser configuration file syntax with submenus and
includes (custom user menu, without overwriting by default menu).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11000 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/tagtree.c')
-rw-r--r-- | apps/tagtree.c | 263 |
1 files changed, 223 insertions, 40 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c index c674cf4ebd..7a710c6fc3 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c | |||
@@ -51,7 +51,12 @@ static char searchstring[32]; | |||
51 | 51 | ||
52 | enum variables { | 52 | enum variables { |
53 | var_sorttype = 100, | 53 | var_sorttype = 100, |
54 | var_limit | 54 | var_limit, |
55 | var_menu_start, | ||
56 | var_include, | ||
57 | var_rootmenu, | ||
58 | menu_next, | ||
59 | menu_load, | ||
55 | }; | 60 | }; |
56 | 61 | ||
57 | /* Capacity 10 000 entries (for example 10k different artists) */ | 62 | /* Capacity 10 000 entries (for example 10k different artists) */ |
@@ -95,9 +100,30 @@ struct search_instruction { | |||
95 | int result_seek[MAX_TAGS]; | 100 | int result_seek[MAX_TAGS]; |
96 | }; | 101 | }; |
97 | 102 | ||
98 | static struct search_instruction *si, *csi; | 103 | struct menu_entry { |
99 | static int si_count = 0; | 104 | char name[64]; |
105 | int type; | ||
106 | struct search_instruction *si; | ||
107 | int link; | ||
108 | }; | ||
109 | |||
110 | #define TAGNAVI_VERSION "#! rockbox/tagbrowser/2.0" | ||
111 | #define TAGMENU_MAX_ITEMS 32 | ||
112 | #define TAGMENU_MAX_MENUS 8 | ||
113 | struct root_menu { | ||
114 | char title[64]; | ||
115 | char id[32]; | ||
116 | int itemcount; | ||
117 | struct root_menu *parent; | ||
118 | struct menu_entry *items[TAGMENU_MAX_ITEMS]; | ||
119 | }; | ||
120 | |||
121 | static struct root_menu menus[TAGMENU_MAX_MENUS]; | ||
122 | static struct root_menu *menu; | ||
123 | static struct search_instruction *csi; | ||
100 | static const char *strp; | 124 | static const char *strp; |
125 | static int menu_count; | ||
126 | static int root_menu; | ||
101 | 127 | ||
102 | static int current_offset; | 128 | static int current_offset; |
103 | static int current_entry_count; | 129 | static int current_entry_count; |
@@ -138,10 +164,10 @@ static int get_tag(int *tag) | |||
138 | int i; | 164 | int i; |
139 | 165 | ||
140 | /* Find the start. */ | 166 | /* Find the start. */ |
141 | while (*strp == ' ' && *strp != '\0') | 167 | while ((*strp == ' ' || *strp == '>') && *strp != '\0') |
142 | strp++; | 168 | strp++; |
143 | 169 | ||
144 | if (*strp == '\0' || *strp == '?' || *strp == ':') | 170 | if (*strp == '\0' || *strp == '?') |
145 | return 0; | 171 | return 0; |
146 | 172 | ||
147 | for (i = 0; i < (int)sizeof(buf)-1; i++) | 173 | for (i = 0; i < (int)sizeof(buf)-1; i++) |
@@ -167,6 +193,11 @@ static int get_tag(int *tag) | |||
167 | MATCH(tag, buf, "autoscore", tag_virt_autoscore); | 193 | MATCH(tag, buf, "autoscore", tag_virt_autoscore); |
168 | MATCH(tag, buf, "%sort", var_sorttype); | 194 | MATCH(tag, buf, "%sort", var_sorttype); |
169 | MATCH(tag, buf, "%limit", var_limit); | 195 | MATCH(tag, buf, "%limit", var_limit); |
196 | MATCH(tag, buf, "%menu_start", var_menu_start); | ||
197 | MATCH(tag, buf, "%include", var_include); | ||
198 | MATCH(tag, buf, "%root_menu", var_rootmenu); | ||
199 | MATCH(tag, buf, "->", menu_next); | ||
200 | MATCH(tag, buf, "==>", menu_load); | ||
170 | 201 | ||
171 | logf("NO MATCH: %s\n", buf); | 202 | logf("NO MATCH: %s\n", buf); |
172 | if (buf[0] == '?') | 203 | if (buf[0] == '?') |
@@ -337,8 +368,7 @@ static int get_condition(struct search_instruction *inst) | |||
337 | case '&': | 368 | case '&': |
338 | strp++; | 369 | strp++; |
339 | return 1; | 370 | return 1; |
340 | case ':': | 371 | case '-': |
341 | strp++; | ||
342 | case '\0': | 372 | case '\0': |
343 | return 0; | 373 | return 0; |
344 | } | 374 | } |
@@ -366,25 +396,56 @@ static int get_condition(struct search_instruction *inst) | |||
366 | * $ ends with | 396 | * $ ends with |
367 | */ | 397 | */ |
368 | 398 | ||
369 | static bool parse_search(struct search_instruction *inst, const char *str) | 399 | static bool parse_search(struct menu_entry *entry, const char *str) |
370 | { | 400 | { |
371 | int ret; | 401 | int ret; |
402 | int type; | ||
403 | struct search_instruction *inst = entry->si; | ||
404 | char buf[MAX_PATH]; | ||
405 | int i; | ||
372 | 406 | ||
373 | memset(inst, 0, sizeof(struct search_instruction)); | ||
374 | strp = str; | 407 | strp = str; |
375 | 408 | ||
376 | if (get_token_str(inst->name, sizeof inst->name) < 0) | 409 | /* Parse entry name */ |
410 | if (get_token_str(entry->name, sizeof entry->name) < 0) | ||
377 | { | 411 | { |
378 | logf("No name found."); | 412 | logf("No name found."); |
379 | return false; | 413 | return false; |
380 | } | 414 | } |
381 | 415 | ||
416 | /* Parse entry type */ | ||
417 | if (get_tag(&entry->type) <= 0) | ||
418 | return false; | ||
419 | |||
420 | if (entry->type == menu_load) | ||
421 | { | ||
422 | if (get_token_str(buf, sizeof buf) < 0) | ||
423 | return false; | ||
424 | |||
425 | /* Find the matching root menu or "create" it */ | ||
426 | for (i = 0; i < menu_count; i++) | ||
427 | { | ||
428 | if (!strcasecmp(menus[i].id, buf)) | ||
429 | { | ||
430 | entry->link = i; | ||
431 | menus[i].parent = menu; | ||
432 | return true; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | return false; | ||
437 | } | ||
438 | |||
439 | if (entry->type != menu_next) | ||
440 | return false; | ||
441 | |||
382 | while (inst->tagorder_count < MAX_TAGS) | 442 | while (inst->tagorder_count < MAX_TAGS) |
383 | { | 443 | { |
384 | ret = get_tag(&inst->tagorder[inst->tagorder_count]); | 444 | ret = get_tag(&inst->tagorder[inst->tagorder_count]); |
385 | if (ret < 0) | 445 | if (ret < 0) |
386 | { | 446 | { |
387 | logf("Parse error #1"); | 447 | logf("Parse error #1"); |
448 | logf("%s", strp); | ||
388 | return false; | 449 | return false; |
389 | } | 450 | } |
390 | 451 | ||
@@ -396,6 +457,9 @@ static bool parse_search(struct search_instruction *inst, const char *str) | |||
396 | while (get_condition(inst) > 0) ; | 457 | while (get_condition(inst) > 0) ; |
397 | 458 | ||
398 | inst->tagorder_count++; | 459 | inst->tagorder_count++; |
460 | |||
461 | if (get_tag(&type) <= 0 || type != menu_next) | ||
462 | break; | ||
399 | } | 463 | } |
400 | 464 | ||
401 | return true; | 465 | return true; |
@@ -520,46 +584,142 @@ bool tagtree_import(void) | |||
520 | return false; | 584 | return false; |
521 | } | 585 | } |
522 | 586 | ||
523 | void tagtree_init(void) | 587 | static bool parse_menu(const char *filename) |
524 | { | 588 | { |
525 | int fd; | 589 | int fd; |
526 | char buf[256]; | 590 | char buf[256]; |
591 | char data[256]; | ||
592 | int variable; | ||
527 | int rc; | 593 | int rc; |
528 | int line_count; | 594 | bool first = true; |
595 | bool read_menu = false; | ||
596 | int i; | ||
597 | |||
598 | if (menu_count >= TAGMENU_MAX_MENUS) | ||
599 | return false; | ||
529 | 600 | ||
530 | fd = open(FILE_SEARCH_INSTRUCTIONS, O_RDONLY); | 601 | fd = open(filename, O_RDONLY); |
531 | if (fd < 0) | 602 | if (fd < 0) |
532 | { | 603 | { |
533 | logf("Search instruction file not found."); | 604 | logf("Search instruction file not found."); |
534 | return ; | 605 | return false; |
535 | } | 606 | } |
536 | 607 | ||
537 | /* Pre-pass search instructions file to count how many entries */ | ||
538 | line_count = 0; | ||
539 | while ( 1 ) | ||
540 | { | ||
541 | rc = read_line(fd, buf, sizeof(buf)-1); | ||
542 | if (rc <= 0) | ||
543 | break; | ||
544 | line_count++; | ||
545 | } | ||
546 | |||
547 | /* Allocate memory for searches */ | ||
548 | si = (struct search_instruction *) buffer_alloc(sizeof(struct search_instruction) * line_count + 4); | ||
549 | |||
550 | /* Now read file for real, parsing into si */ | 608 | /* Now read file for real, parsing into si */ |
551 | lseek(fd, 0L, SEEK_SET); | ||
552 | while ( 1 ) | 609 | while ( 1 ) |
553 | { | 610 | { |
554 | rc = read_line(fd, buf, sizeof(buf)-1); | 611 | rc = read_line(fd, buf, sizeof(buf)-1); |
555 | if (rc <= 0) | 612 | if (rc <= 0) |
556 | break; | ||
557 | if (!parse_search(si + si_count, buf)) | ||
558 | break; | 613 | break; |
559 | si_count++; | 614 | |
615 | if (first) | ||
616 | { | ||
617 | if (strcasecmp(TAGNAVI_VERSION, buf)) | ||
618 | { | ||
619 | logf("Version mismatch"); | ||
620 | break; | ||
621 | } | ||
622 | first = false; | ||
623 | } | ||
624 | |||
625 | if (buf[0] == '#') | ||
626 | continue; | ||
627 | |||
628 | if (buf[0] == '\0') | ||
629 | { | ||
630 | if (read_menu) | ||
631 | { | ||
632 | /* End the menu */ | ||
633 | menu_count++; | ||
634 | menu = &menus[menu_count]; | ||
635 | read_menu = false; | ||
636 | } | ||
637 | continue; | ||
638 | } | ||
639 | |||
640 | if (!read_menu) | ||
641 | { | ||
642 | strp = buf; | ||
643 | if (get_tag(&variable) <= 0) | ||
644 | continue; | ||
645 | |||
646 | switch (variable) | ||
647 | { | ||
648 | case var_include: | ||
649 | if (get_token_str(data, sizeof(data)) < 0) | ||
650 | { | ||
651 | logf("%include empty"); | ||
652 | return false; | ||
653 | } | ||
654 | |||
655 | if (!parse_menu(data)) | ||
656 | { | ||
657 | logf("Load menu fail: %s", data); | ||
658 | } | ||
659 | break; | ||
660 | |||
661 | case var_menu_start: | ||
662 | if (get_token_str(menu->id, sizeof(menu->id)) < 0) | ||
663 | { | ||
664 | logf("%menu_start id empty"); | ||
665 | return false; | ||
666 | } | ||
667 | if (get_token_str(menu->title, sizeof(menu->title)) < 0) | ||
668 | { | ||
669 | logf("%menu_start title empty"); | ||
670 | return false; | ||
671 | } | ||
672 | menu->itemcount = 0; | ||
673 | read_menu = true; | ||
674 | break; | ||
675 | |||
676 | case var_rootmenu: | ||
677 | if (get_token_str(data, sizeof(data)) < 0) | ||
678 | { | ||
679 | logf("%root_menu empty"); | ||
680 | return false; | ||
681 | } | ||
682 | |||
683 | for (i = 0; i < menu_count; i++) | ||
684 | { | ||
685 | if (!strcasecmp(menus[i].id, data)) | ||
686 | { | ||
687 | root_menu = i; | ||
688 | } | ||
689 | } | ||
690 | break; | ||
691 | } | ||
692 | |||
693 | continue; | ||
694 | } | ||
695 | |||
696 | /* Allocate */ | ||
697 | if (menu->items[menu->itemcount] == NULL) | ||
698 | { | ||
699 | menu->items[menu->itemcount] = buffer_alloc(sizeof(struct menu_entry)); | ||
700 | memset(menu->items[menu->itemcount], 0, sizeof(struct menu_entry)); | ||
701 | menu->items[menu->itemcount]->si = buffer_alloc(sizeof(struct search_instruction)); | ||
702 | memset(menu->items[menu->itemcount]->si, 0, sizeof(struct search_instruction)); | ||
703 | } | ||
704 | |||
705 | if (!parse_search(menu->items[menu->itemcount], buf)) | ||
706 | continue; | ||
707 | |||
708 | menu->itemcount++; | ||
560 | } | 709 | } |
561 | close(fd); | 710 | close(fd); |
562 | 711 | ||
712 | return true; | ||
713 | } | ||
714 | |||
715 | void tagtree_init(void) | ||
716 | { | ||
717 | memset(menus, 0, sizeof menus); | ||
718 | menu_count = 0; | ||
719 | menu = &menus[0]; | ||
720 | root_menu = 0; | ||
721 | parse_menu(FILE_SEARCH_INSTRUCTIONS); | ||
722 | |||
563 | uniqbuf = buffer_alloc(UNIQBUF_SIZE); | 723 | uniqbuf = buffer_alloc(UNIQBUF_SIZE); |
564 | audio_set_track_buffer_event(tagtree_buffer_event); | 724 | audio_set_track_buffer_event(tagtree_buffer_event); |
565 | audio_set_track_unbuffer_event(tagtree_unbuffer_event); | 725 | audio_set_track_unbuffer_event(tagtree_unbuffer_event); |
@@ -858,11 +1018,27 @@ static int load_root(struct tree_context *c) | |||
858 | 1018 | ||
859 | tc = c; | 1019 | tc = c; |
860 | c->currtable = root; | 1020 | c->currtable = root; |
861 | for (i = 0; i < si_count; i++) | 1021 | if (c->dirlevel == 0) |
1022 | c->currextra = root_menu; | ||
1023 | |||
1024 | menu = &menus[c->currextra]; | ||
1025 | |||
1026 | for (i = 0; i < menu->itemcount; i++) | ||
862 | { | 1027 | { |
863 | dptr->name = (si+i)->name; | 1028 | dptr->name = menu->items[i]->name; |
864 | dptr->newtable = navibrowse; | 1029 | switch (menu->items[i]->type) |
865 | dptr->extraseek = i; | 1030 | { |
1031 | case menu_next: | ||
1032 | dptr->newtable = navibrowse; | ||
1033 | dptr->extraseek = i; | ||
1034 | break; | ||
1035 | |||
1036 | case menu_load: | ||
1037 | dptr->newtable = root; | ||
1038 | dptr->extraseek = menu->items[i]->link; | ||
1039 | break; | ||
1040 | } | ||
1041 | |||
866 | dptr++; | 1042 | dptr++; |
867 | } | 1043 | } |
868 | 1044 | ||
@@ -884,13 +1060,13 @@ int tagtree_load(struct tree_context* c) | |||
884 | c->dirfull = false; | 1060 | c->dirfull = false; |
885 | table = root; | 1061 | table = root; |
886 | c->currtable = table; | 1062 | c->currtable = table; |
1063 | c->currextra = root_menu; | ||
887 | } | 1064 | } |
888 | 1065 | ||
889 | switch (table) | 1066 | switch (table) |
890 | { | 1067 | { |
891 | case root: | 1068 | case root: |
892 | count = load_root(c); | 1069 | count = load_root(c); |
893 | c->dirlevel = 0; | ||
894 | break; | 1070 | break; |
895 | 1071 | ||
896 | case allsubentries: | 1072 | case allsubentries: |
@@ -945,11 +1121,17 @@ int tagtree_enter(struct tree_context* c) | |||
945 | case root: | 1121 | case root: |
946 | c->currextra = newextra; | 1122 | c->currextra = newextra; |
947 | 1123 | ||
948 | if (newextra == navibrowse) | 1124 | if (newextra == root) |
1125 | { | ||
1126 | menu = &menus[seek]; | ||
1127 | c->currextra = seek; | ||
1128 | } | ||
1129 | |||
1130 | else if (newextra == navibrowse) | ||
949 | { | 1131 | { |
950 | int i, j; | 1132 | int i, j; |
951 | 1133 | ||
952 | csi = si+seek; | 1134 | csi = menu->items[seek]->si; |
953 | c->currextra = 0; | 1135 | c->currextra = 0; |
954 | 1136 | ||
955 | /* Read input as necessary. */ | 1137 | /* Read input as necessary. */ |
@@ -963,7 +1145,7 @@ int tagtree_enter(struct tree_context* c) | |||
963 | rc = kbd_input(searchstring, sizeof(searchstring)); | 1145 | rc = kbd_input(searchstring, sizeof(searchstring)); |
964 | if (rc == -1 || !searchstring[0]) | 1146 | if (rc == -1 || !searchstring[0]) |
965 | { | 1147 | { |
966 | c->dirlevel--; | 1148 | tagtree_exit(c); |
967 | return 0; | 1149 | return 0; |
968 | } | 1150 | } |
969 | 1151 | ||
@@ -1024,7 +1206,8 @@ int tagtree_enter(struct tree_context* c) | |||
1024 | void tagtree_exit(struct tree_context* c) | 1206 | void tagtree_exit(struct tree_context* c) |
1025 | { | 1207 | { |
1026 | c->dirfull = false; | 1208 | c->dirfull = false; |
1027 | c->dirlevel--; | 1209 | if (c->dirlevel > 0) |
1210 | c->dirlevel--; | ||
1028 | c->selected_item=c->selected_item_history[c->dirlevel]; | 1211 | c->selected_item=c->selected_item_history[c->dirlevel]; |
1029 | gui_synclist_select_item(&tree_lists, c->selected_item); | 1212 | gui_synclist_select_item(&tree_lists, c->selected_item); |
1030 | c->currtable = c->table_history[c->dirlevel]; | 1213 | c->currtable = c->table_history[c->dirlevel]; |