From 7b403f71d248ad6eb4823f48472dbeca3a992b8d Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 21 Dec 2011 20:40:15 +0100 Subject: [PATCH] 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. --- apps/lang/english.lang | 14 +++++++ apps/menus/settings_menu.c | 23 ++++++++++- apps/misc.c | 31 +++++++++++++++ apps/misc.h | 1 + apps/settings.h | 1 + apps/settings_list.c | 8 ++++ apps/tagcache.c | 92 +++++++++++++++++++++++++++++++++---------- apps/tagcache.h | 2 - 8 files changed, 147 insertions(+), 25 deletions(-) diff --git a/apps/lang/english.lang b/apps/lang/english.lang index d955c46..7cfbd1f 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -12965,3 +12965,17 @@ *: "Glyphs To Cache" + + 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 bcb182e..fb23d77 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -65,6 +65,22 @@ static void tagcache_update_with_splash(void) splash(HZ*2, ID2P(LANG_TAGCACHE_FORCE_UPDATE_SPLASH)); } +static int dirs_to_scan(void) +{ + if (!kbd_input(global_settings.tagcache_scan_paths, + sizeof(global_settings.tagcache_scan_paths) - 1)) + + { + 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 +98,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 407a26c..79d4308 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -1005,6 +1005,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 4647898..695e0ce 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -66,6 +66,7 @@ bool list_stop_handler(void); void car_adapter_mode_init(void); extern int show_logo(void); +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/settings.h b/apps/settings.h index 2524dcc..cddccc5 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -593,6 +593,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 54c0917..3584f1c 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -309,6 +309,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, @@ -1352,6 +1358,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..5f5ce1d 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -4272,10 +4272,27 @@ static void __attribute__ ((noinline)) check_ignore(const char *dirname, *unignore = file_exists(newpath); } +#define MAX_STATIC_ROOTS 8 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 +4333,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 +4361,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; } @@ -4459,7 +4481,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 +4524,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 +4593,19 @@ 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 +4691,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 +4713,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 604e93b..835b718 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -200,8 +200,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.7.1