From 5e398265f296dc369777896adcfec48da26dd1a0 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 18 Jul 2012 10:45:19 +0200 Subject: [PATCH] Configurable database scan directories. Squashed commit of the following: commit 9148508e15ac0991a71b52967ad1507cc02de101 Author: Thomas Martitz Date: Wed Jul 18 10:36:57 2012 +0200 tagcache_config: do not use separate file, show root folder - Do not use a separate file to specifiy the paths. Instead read/write from the settings using the tagcache_scan_paths. - show the root folder so that the entire file system remains scannable. This is for native targets where it's the default. - Do not ask for scan paths at every visit to the db browser (configure through context menu/database settings). Change-Id: I68e27a7670037fcb0afa9f95852288874464b20b commit 44f43aaeb6e78c520f750b8c408b210d03c78683 Author: Thomas Martitz Date: Thu Jul 5 07:29:06 2012 +0200 Import of FS#12474. Change-Id: I99802667f51924118485cc3256e6ccb3e6b60b97 commit d6ff0020fde9331090f38366dedd65e48cbc8613 Author: Thomas Martitz Date: Wed Dec 21 20:40:15 2011 +0100 Database: Support for multiple search roots. The setting works similar to the autoresume dirs: Directories are seperated by colon, e.g. "/Music:/Podcasts". Default is "/sdcard" on android, "/" on all other targets. A maximum of 8 dirs can be selected, the setting cannot be longer than 80 chars. Change-Id: Id0c5e93c2befbbf24085401cdfc1ffdf8d9a85b9 Change-Id: I6c2fd829e2bf08f5d31b512f8b64f368f394498d --- apps/SOURCES | 1 + apps/gui/bitmap/list.c | 30 ++- apps/gui/tagcache_config.c | 454 ++++++++++++++++++++++++++++++++++++++++++++ apps/lang/english.lang | 14 ++ apps/menus/settings_menu.c | 22 ++- apps/misc.c | 31 +++ apps/misc.h | 1 + apps/root_menu.c | 4 +- apps/settings.h | 1 + apps/settings_list.c | 8 + apps/tagcache.c | 95 ++++++--- apps/tagcache.h | 3 +- 12 files changed, 636 insertions(+), 28 deletions(-) create mode 100644 apps/gui/tagcache_config.c diff --git a/apps/SOURCES b/apps/SOURCES index 8749c36..8046103 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -86,6 +86,7 @@ gui/pitchscreen.c #ifdef HAVE_QUICKSCREEN gui/quickscreen.c #endif +gui/tagcache_config.c gui/wps.c gui/scrollbar.c diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c index aad3eda..974730a 100644 --- a/apps/gui/bitmap/list.c +++ b/apps/gui/bitmap/list.c @@ -154,9 +154,11 @@ void list_draw(struct screen *display, struct gui_synclist *list) int icon_yoffset = 0; /* to center the icon */ bool show_title; struct viewport *list_text_vp = &list_text[screen]; - + int indent = 0; + int char_width; line_height = parent->line_height; display->set_viewport(parent); + char_width = display->getstringsize("M", NULL, NULL); display->clear_viewport(); display->scroll_stop(list_text_vp); *list_text_vp = *parent; @@ -249,9 +251,29 @@ void list_draw(struct screen *display, struct gui_synclist *list) unsigned char *entry_name; int text_pos = 0; int line = i - start; + indent = 0; s = list->callback_get_item_name(i, list->data, entry_buffer, sizeof(entry_buffer)); entry_name = P2STR(s); + while (*entry_name == '\t') + { + indent++; + entry_name++; + } + if (indent) + { + if (icon_width) + indent *= icon_width; + else + indent *= char_width; + } + if (indent) + { + list_icons.x += indent; + list_text_vp->x += indent; + list_text_vp->width -= indent; + } + display->set_viewport(list_text_vp); style = STYLE_DEFAULT; /* position the string at the correct offset place */ @@ -353,6 +375,12 @@ void list_draw(struct screen *display, struct gui_synclist *list) line*line_height + draw_offset + icon_yoffset, Icon_Cursor); } + if (indent) + { + list_icons.x -= indent; + list_text_vp->x -= indent; + list_text_vp->width += indent; + } } display->set_viewport(parent); display->update_viewport(); diff --git a/apps/gui/tagcache_config.c b/apps/gui/tagcache_config.c new file mode 100644 index 0000000..ebbafd7 --- /dev/null +++ b/apps/gui/tagcache_config.c @@ -0,0 +1,454 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2011 Jonathan Gordon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include "inttypes.h" +#include "config.h" +#include "core_alloc.h" +#include "filetypes.h" +#include "lang.h" +#include "language.h" +#include "list.h" +#include "plugin.h" +#include "tagcache.h" + + +/* + * Order for changing child states: + * 1) expand folder (skip to 2 if empty) + * 2) collapse and select + * 3) unselect + */ + +enum child_state { + EXPANDED, + SELECTED, + COLLAPSED +}; + +struct child { + char* name; + struct folder *folder; + enum child_state state; +}; + +struct folder { + char *name; + struct child *children; + int children_count; + int depth; + + struct folder* previous; +}; + +static char *buffer_front, *buffer_end; +static char* folder_alloc(size_t size) +{ + char* retval; + /* 32-bit aligned */ + size = (size + 3) & ~3; + if (buffer_front + size > buffer_end) + { + return NULL; + } + retval = buffer_front; + buffer_front += size; + return retval; +} + +static char* folder_alloc_from_end(size_t size) +{ + if (buffer_end - size < buffer_front) + { + return NULL; + } + buffer_end -= size; + return buffer_end; +} + +static void get_full_path_r(struct folder *start, char* dst) +{ + if (start->previous) + get_full_path_r(start->previous, dst); + + if (start->name && start->name[0] && strcmp(start->name, "/")) + { + strlcat(dst, "/", MAX_PATH); + strlcat(dst, start->name, MAX_PATH); + } +} + +static char* get_full_path(struct folder *start) +{ + static char buffer[MAX_PATH]; + + buffer[0] = '\0'; + + get_full_path_r(start, buffer); + + return buffer; +} + +/* support function for qsort() */ +static int compare(const void* p1, const void* p2) +{ + struct child *left = (struct child*)p1; + struct child *right = (struct child*)p2; + return strcasecmp(left->name, right->name); +} + +static struct folder* load_folder(struct folder* parent, char *folder) +{ + DIR *dir; + char* path = get_full_path(parent); + char fullpath[MAX_PATH]; + struct dirent *entry; + struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder)); + int child_count = 0; + char *first_child = NULL; + + if (!strcmp(folder,"/")) + strlcpy(fullpath, folder, 2); + else + snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder); + + if (!this) + return NULL; + dir = opendir(fullpath); + if (!dir) + return NULL; + this->previous = parent; + this->name = folder; + this->children = NULL; + this->children_count = 0; + this->depth = parent ? parent->depth + 1 : 0; + + while ((entry = readdir(dir))) { + int len = strlen((char *)entry->d_name); + struct dirinfo info; + + info = dir_get_info(dir, entry); + + /* skip anything not a directory */ + if ((info.attribute & ATTR_DIRECTORY) == 0) { + continue; + } + /* skip directories . and .. */ + if ((!strcmp((char *)entry->d_name, ".")) || + (!strcmp((char *)entry->d_name, ".."))) { + continue; + } + char *name = folder_alloc_from_end(len+1); + if (!name) + return NULL; + memcpy(name, (char *)entry->d_name, len+1); + child_count++; + first_child = name; + } + closedir(dir); + /* now put the names in the array */ + this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count); + + if (!this->children) + return NULL; + while (child_count) + { + this->children[this->children_count].name = first_child; + this->children[this->children_count].folder = NULL; + this->children[this->children_count].state = COLLAPSED; + this->children_count++; + first_child += strlen(first_child) + 1; + child_count--; + } + qsort(this->children, this->children_count, sizeof(struct child), compare); + + return this; +} + +struct folder* load_root(void) +{ + static struct child root_child; + + root_child.name = "/"; + root_child.folder = NULL; + root_child.state = COLLAPSED; + + static struct folder root = { + .name = "", + .children = &root_child, + .children_count = 1, + .depth = -1, + .previous = NULL, + }; + + return &root; +} + +static int count_items(struct folder *start) +{ + int count = 0; + int i; + + for (i=0; ichildren_count; i++) + { + struct child *foo = &start->children[i]; + if (foo->state == EXPANDED) + count += count_items(foo->folder); + count++; + } + return count; +} + +static struct child* find_index(struct folder *start, int index, struct folder **parent) +{ + int i = 0; + + *parent = NULL; + + while (i < start->children_count) + { + struct child *foo = &start->children[i]; + if (i == index) + { + *parent = start; + return foo; + } + i++; + if (foo->state == EXPANDED) + { + struct child *bar = find_index(foo->folder, index - i, parent); + if (bar) + { + return bar; + } + index -= count_items(foo->folder); + } + } + return NULL; +} + +static const char * folder_get_name(int selected_item, void * data, + char * buffer, size_t buffer_len) +{ + (void)buffer_len; + struct folder *root = (struct folder*)data; + struct folder *parent; + struct child *this = find_index(root, selected_item , &parent); + + buffer[0] = '\0'; + + if (parent->depth >= 0) + for(int i = 0; i <= parent->depth; i++) + strcat(buffer, "\t"); + + strcat(buffer, this->name); + return buffer; +} + +static enum themable_icons folder_get_icon(int selected_item, void * data) +{ + struct folder *root = (struct folder*)data; + struct folder *parent; + struct child *this = find_index(root, selected_item, &parent); + + switch (this->state) + { + case SELECTED: + return Icon_Cursor; + case COLLAPSED: + return Icon_Folder; + case EXPANDED: + return Icon_Submenu; + } + return Icon_NOICON; +} + +static int folder_action_callback(int action, struct gui_synclist *list) +{ + struct folder *root = (struct folder*)list->data; + + if (action == ACTION_STD_OK) + { + struct folder *parent; + struct child *this = find_index(root, list->selected_item, &parent); + switch (this->state) + { + case EXPANDED: + this->state = SELECTED; + break; + case SELECTED: + this->state = COLLAPSED; + break; + case COLLAPSED: + if (this->folder == NULL) + this->folder = load_folder(parent, this->name); + this->state = this->folder->children_count == 0 ? + SELECTED : EXPANDED; + } + list->nb_items = count_items(root); + return ACTION_REDRAW; + } + return action; +} + +static struct child* find_from_filename(char* filename, struct folder *root) +{ + char *slash = strchr(filename, '/'); + int i = 0; + if (slash) + *slash = '\0'; + if (!root) + return NULL; + + struct child *this; + + /* filenames beginning with a / are specially treated as the + * loop below can't handle them. they can only occur on the first, + * and not recursive, calls to this function.*/ + if (slash == filename) + { + /* filename begins with /. in this case root must be the + * top level folder */ + this = &root->children[0]; + if (!slash[1]) + { /* filename == "/" */ + return this; + } + else + { + /* filename == "/XXX/YYY". cascade down */ + if (!this->folder) + this->folder = load_folder(root, this->name); + this->state = EXPANDED; + /* recurse with XXX/YYY */ + return find_from_filename(slash+1, this->folder); + } + } + + while (i < root->children_count) + { + this = &root->children[i]; + if (!strcasecmp(this->name, filename)) + { + if (!slash) + { /* filename == XXX */ + return this; + } + else + { + /* filename == XXX/YYY. cascade down */ + if (!this->folder) + this->folder = load_folder(root, this->name); + this->state = EXPANDED; + return find_from_filename(slash+1, this->folder); + } + } + i++; + } + return NULL; +} + +/* _modifies_ buf */ +int select_paths(struct folder* root, char* buf) +{ + struct child *item = find_from_filename(buf, root); + if (item) + item->state = SELECTED; + return 0; +} + +static void save_folders_r(struct folder *root, char* dst, size_t maxlen) +{ + int i = 0; + + while (i < root->children_count) + { + struct child *this = &root->children[i]; + if (this->state == SELECTED) + { + if (this->folder) + snprintf(buffer_front, buffer_end - buffer_front, + "%s:", get_full_path(this->folder)); + else + snprintf(buffer_front, buffer_end - buffer_front, + "%s/%s:", get_full_path(root), this->name); + strlcat(dst, buffer_front, maxlen); + } + else if (this->state == EXPANDED) + save_folders_r(this->folder, dst, maxlen); + i++; + } +} + +static void save_folders(struct folder *root, char* dst, size_t maxlen) +{ + int len; + dst[0] = '\0'; + save_folders_r(root, dst, maxlen); + len = strlen(dst); + /* fix trailing ':' */ + if (len > 1) dst[len-1] = '\0'; +} + +bool tagcache_do_config(void) +{ + struct folder *root; + struct simplelist_info info; + size_t buf_size; + char *vect[MAX_STATIC_ROOTS]; + char copy[sizeof(global_settings.tagcache_scan_paths)]; + int nb_items; + + /* copy onto stack as split_string() modifies it */ + strlcpy(copy, global_settings.tagcache_scan_paths, sizeof(copy)); + puts(copy); + nb_items = split_string(copy, ':', vect, MAX_STATIC_ROOTS); + + buffer_front = plugin_get_buffer(&buf_size); + buffer_end = buffer_front + buf_size; + root = load_root(); + + if (nb_items > 0) + { + for(int i = 0; i < nb_items; i++) + select_paths(root, vect[i]); + } + + simplelist_info_init(&info, str(LANG_SELECT_DATABASE_DIRS), + count_items(root), root); + info.get_name = folder_get_name; + info.action_callback = folder_action_callback; + info.get_icon = folder_get_icon; + simplelist_show_list(&info); + + /* done editing. check for changes */ + save_folders(root, copy, sizeof(copy)); + if (strcmp(copy, global_settings.tagcache_scan_paths)) + { /* prompt for saving changes and commit if yes */ + if (yesno_pop(ID2P(LANG_SAVE_CHANGES))) + { + strcpy(global_settings.tagcache_scan_paths, copy); + settings_save(); + return true; + } + } + return false; +} diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 7366a80..33e9c79 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -13086,3 +13086,17 @@ swcodec: "Custom" + + id: LANG_SELECT_DATABASE_DIRS + desc: in settings_menu + user: core + + *: "Select directories to scan" + + + *: "Select directories to scan" + + + *: "Select directories to scan" + + diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 9cdff01..fb33701 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -65,6 +65,21 @@ static void tagcache_update_with_splash(void) splash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); } +bool tagcache_do_config(void); +static int dirs_to_scan(void) +{ + if (tagcache_do_config()) + { + static const char *lines[] = {ID2P(LANG_TAGCACHE_BUSY), + ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; + static const struct text_message message = {lines, 2}; + + if (gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) + tagcache_rebuild_with_splash(); + } + return 0; +} + #ifdef HAVE_TC_RAMCACHE MENUITEM_SETTING(tagcache_ram, &global_settings.tagcache_ram, NULL); #endif @@ -82,12 +97,17 @@ MENUITEM_FUNCTION(tc_export, 0, ID2P(LANG_TAGCACHE_EXPORT), MENUITEM_FUNCTION(tc_import, 0, ID2P(LANG_TAGCACHE_IMPORT), (int(*)(void))tagtree_import, NULL, NULL, Icon_NOICON); +MENUITEM_FUNCTION(tc_paths, 0, ID2P(LANG_SELECT_DATABASE_DIRS), + dirs_to_scan, NULL, NULL, Icon_NOICON); + MAKE_MENU(tagcache_menu, ID2P(LANG_TAGCACHE), 0, Icon_NOICON, #ifdef HAVE_TC_RAMCACHE &tagcache_ram, #endif &tagcache_autoupdate, &tc_init, &tc_update, &runtimedb, - &tc_export, &tc_import); + &tc_export, &tc_import + ,&tc_paths + ); #endif /* HAVE_TAGCACHE */ /* TAGCACHE MENU */ /***********************************/ diff --git a/apps/misc.c b/apps/misc.c index 5b20b35..d7d4bdd 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -1075,6 +1075,37 @@ void format_time(char* buf, int buf_size, long t) } } +/** + * Splits str at each occurence of split_char and puts the substrings into vector, + * but at most vector_lenght items. Empty substrings are ignored. + * + * Modifies str by replacing each split_char following a substring with nul + * + * Returns the number of substrings found, i.e. the number of valid strings + * in vector + */ +int split_string(char *str, const char split_char, char *vector[], const int vector_length) +{ + int i; + char *p = str; + + /* skip leading splitters */ + while(*p == split_char) p++; + + /* *p in the condition takes care of trailing splitters */ + for(i = 0; p && *p && i < vector_length; i++) + { + vector[i] = p; + if ((p = strchr(p, split_char))) + { + *p++ = '\0'; + while(*p == split_char) p++; /* skip successive splitters */ + } + } + + return i; +} + /** Open a UTF-8 file and set file descriptor to first byte after BOM. * If no BOM is present this behaves like open(). diff --git a/apps/misc.h b/apps/misc.h index 7ca8d75..994e777 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -73,6 +73,7 @@ extern int show_logo(void); #define BOM_UTF_16_BE "\xfe\xff" #define BOM_UTF_16_SIZE 2 +int split_string(char *str, const char needle, char *vector[], int vector_length); int open_utf8(const char* pathname, int flags); #ifdef BOOTFILE diff --git a/apps/root_menu.c b/apps/root_menu.c index 3f2e933..3e67e14 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -189,10 +189,10 @@ static int browser(void* param) stat->processed_entries == 0 && stat->commit_step == 0) { /* Prompt the user */ - reinit_attempted = true; static const char *lines[]={ ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)}; - static const struct text_message message={lines, 2}; + static const struct text_message message={lines, 2}; + reinit_attempted = true; if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO) break; FOR_NB_SCREENS(i) diff --git a/apps/settings.h b/apps/settings.h index ef0bae5..2af29ce 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -561,6 +561,7 @@ struct user_settings 2=custom */ unsigned char autoresume_paths[MAX_PATHNAME+1]; /* colon-separated list */ bool runtimedb; /* runtime database active? */ + unsigned char tagcache_scan_paths[MAX_PATHNAME+1]; #endif /* HAVE_TAGCACHE */ #if LCD_DEPTH > 1 diff --git a/apps/settings_list.c b/apps/settings_list.c index 5e660b4..f27c13c 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -316,6 +316,12 @@ static const char graphic_numeric[] = "graphic,numeric"; #endif /* HAVE_RECORDING */ +#if (CONFIG_PLATFORM & PLATFORM_ANDROID) +#define DEFAULT_TAGCACHE_SCAN_PATHS "/sdcard" +#else +#define DEFAULT_TAGCACHE_SCAN_PATHS "/" +#endif + #ifdef HAVE_TOUCHSCREEN static const char* list_pad_formatter(char *buffer, size_t buffer_size, @@ -1355,6 +1361,8 @@ const struct settings_list settings[] = { OFFON_SETTING(0, runtimedb, LANG_RUNTIMEDB_ACTIVE, false, "gather runtime data", NULL), + TEXT_SETTING(0, tagcache_scan_paths, "database scan paths", + DEFAULT_TAGCACHE_SCAN_PATHS, NULL, NULL), #endif #if CONFIG_CODEC == SWCODEC diff --git a/apps/tagcache.c b/apps/tagcache.c index ef642b1..1cd4e14 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -4275,7 +4275,23 @@ static void __attribute__ ((noinline)) check_ignore(const char *dirname, static struct search_roots_ll { const char *path; struct search_roots_ll * next; -} roots_ll; +} roots_ll[MAX_STATIC_ROOTS]; + +/* check if the path is already included in the search roots, by the + * means that the path itself or one of its parents folders is in the list */ +static bool search_root_exists(const char *path) +{ + struct search_roots_ll *this; + for(this = &roots_ll[0]; this; this = this->next) + { + size_t root_len = strlen(this->path); + /* check if the link target is inside of an existing search root + * don't add if target is inside, we'll scan it later */ + if (!strncmp(this->path, path, root_len)) + return true; + } + return false; +} #ifdef APPLICATION /* @@ -4316,14 +4332,11 @@ static bool add_search_root(const char *name) if (realpath(target, abs_target) == NULL) return false; - for(this = &roots_ll; this; prev = this, this = this->next) - { - size_t root_len = strlen(this->path); - /* check if the link target is inside of an existing search root - * don't add if target is inside, we'll scan it later */ - if (!strncmp(this->path, abs_target, root_len)) - return false; - } + if (search_root_exists(abs_target)) + return false; + + /* get the end of the list */ + for(this = &roots_ll[0]; this; prev = this, this = this->next); if (prev) { @@ -4347,14 +4360,22 @@ static bool add_search_root(const char *name) return false; } +static int free_search_root_single(struct search_roots_ll * start) +{ + if (start < &roots_ll[0] && start >= &roots_ll[MAX_STATIC_ROOTS]) + { + free(start->next); + return sizeof(struct search_roots_ll); + } + return 0; +} + static int free_search_roots(struct search_roots_ll * start) { int ret = 0; if (start->next) { - ret += free_search_roots(start->next); - ret += sizeof(struct search_roots_ll); - free(start->next); + ret += free_search_root_single(start->next); } return ret; } @@ -4382,6 +4403,11 @@ static bool check_dir(const char *dirname, int add_files) /* don't do anything if both ignore and unignore are there */ if (ignore != unignore) add_files = unignore; + if (ignore) + { + closedir(dir); + return true; + } /* Recursively scan the dir. */ #ifdef __PCTOOL__ @@ -4459,7 +4485,8 @@ void tagcache_screensync_enable(bool state) tc_stat.syncscreen = state; } -void tagcache_build(const char *path) + +static void do_tagcache_build(const char *path[]) { struct tagcache_header header; bool ret; @@ -4501,17 +4528,29 @@ void tagcache_build(const char *path) write(cachefd, &header, sizeof(struct tagcache_header)); ret = true; - roots_ll.path = path; - roots_ll.next = NULL; + + roots_ll[0].path = path[0]; + roots_ll[0].next = NULL; + /* i is for the path vector, j for the roots_ll array + * path can be skipped , but root_ll entries can't */ + for(int i = 1, j = 1; path[i] && j < MAX_STATIC_ROOTS; i++) + { + if (search_root_exists(path[i])) /* skip this path */ + continue; + + roots_ll[j].path = path[i]; + roots_ll[j-1].next = &roots_ll[j]; + j++; + } + struct search_roots_ll * this; /* check_dir might add new roots */ - for(this = &roots_ll; this; this = this->next) + for(this = &roots_ll[0]; this; this = this->next) { strcpy(curpath, this->path); ret = ret && check_dir(this->path, true); } - if (roots_ll.next) - free_search_roots(roots_ll.next); + free_search_roots(&roots_ll[0]); /* Write the header. */ header.magic = TAGCACHE_MAGIC; @@ -4558,6 +4597,18 @@ void tagcache_build(const char *path) cpu_boost(false); } +void tagcache_build(void) +{ + char *vect[MAX_STATIC_ROOTS + 1]; /* +1 to ensure NULL sentinel */ + char str[sizeof(global_settings.tagcache_scan_paths)]; + strlcpy(str, global_settings.tagcache_scan_paths, sizeof(str)); + + int res = split_string(str, ':', vect, MAX_STATIC_ROOTS); + vect[res] = NULL; + + do_tagcache_build((const char**)vect); +} + #ifdef HAVE_TC_RAMCACHE static void load_ramcache(void) { @@ -4643,11 +4694,11 @@ static void tagcache_thread(void) case Q_REBUILD: remove_files(); remove(TAGCACHE_FILE_TEMP); - tagcache_build("/"); + tagcache_build(); break; case Q_UPDATE: - tagcache_build("/"); + tagcache_build(); #ifdef HAVE_TC_RAMCACHE load_ramcache(); #endif @@ -4665,13 +4716,13 @@ static void tagcache_thread(void) { load_ramcache(); if (tc_stat.ramcache && global_settings.tagcache_autoupdate) - tagcache_build("/"); + tagcache_build(); } else #endif if (global_settings.tagcache_autoupdate) { - tagcache_build("/"); + tagcache_build(); /* This will be very slow unless dircache is enabled or target is flash based, but do it anyway for diff --git a/apps/tagcache.h b/apps/tagcache.h index 44161cf..af86e07 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -82,6 +82,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define TAGCACHE_MAX_FILTERS 4 #define TAGCACHE_MAX_CLAUSES 32 +#define MAX_STATIC_ROOTS 8 /* Tag database files. */ /* Temporary database containing new tags to be committed to the main db. */ @@ -201,8 +202,6 @@ struct tagcache_search { int32_t idx_id; /* Entry number in the master index. */ }; -void tagcache_build(const char *path); - #ifdef __PCTOOL__ void tagcache_reverse_scan(void); #endif -- 1.7.10.4