[vlc-commits] directory: reconcile numerical and alphabetical sorting
Rémi Denis-Courmont
git at videolan.org
Sat Feb 18 09:34:16 CET 2017
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed Nov 30 23:43:08 2016 +0200| [40b946f2154af61d880f2de1187ec03f7d606d51] | committer: Rémi Denis-Courmont
directory: reconcile numerical and alphabetical sorting
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=40b946f2154af61d880f2de1187ec03f7d606d51
---
include/vlc_access.h | 4 +-
modules/access/fs.c | 1 +
modules/demux/playlist/playlist.c | 12 ------
src/input/access.c | 83 ++++++++++++++++++---------------------
4 files changed, 41 insertions(+), 59 deletions(-)
diff --git a/include/vlc_access.h b/include/vlc_access.h
index dc91e47..0531035 100644
--- a/include/vlc_access.h
+++ b/include/vlc_access.h
@@ -102,7 +102,6 @@ struct access_fsdir
int i_sub_autodetect_fuzzy;
bool b_show_hiddenfiles;
char *psz_ignored_exts;
- char *psz_sort;
};
/**
@@ -117,8 +116,7 @@ VLC_API void access_fsdir_init(struct access_fsdir *p_fsdir,
/**
* Finish adding items to the node
*
- * \param b_success if true, items of the node will be sorted according
- * "directory-sort" option.
+ * \param b_success if true, items of the node will be sorted.
*/
VLC_API void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success);
diff --git a/modules/access/fs.c b/modules/access/fs.c
index edce520..fc516b4 100644
--- a/modules/access/fs.c
+++ b/modules/access/fs.c
@@ -52,4 +52,5 @@ vlc_module_begin ()
add_bool("list-special-files", false, N_("List special files"),
N_("Include devices and pipes when listing directories"), true)
+ add_obsolete_string("directory-sort") /* since 3.0.0 */
vlc_module_end ()
diff --git a/modules/demux/playlist/playlist.c b/modules/demux/playlist/playlist.c
index f755e14..48c531f 100644
--- a/modules/demux/playlist/playlist.c
+++ b/modules/demux/playlist/playlist.c
@@ -62,16 +62,6 @@ static const char *const psz_recursive_list_text[] = {
"collapse: subdirectories appear but are expanded on first play.\n" \
"expand: all subdirectories are expanded.\n" )
-static const char *const psz_sort_list[] = { "collate", "version", "none" };
-static const char *const psz_sort_list_text[] = {
- N_("Sort alphabetically according to the current language's collation rules."),
- N_("Sort items in a natural order (for example: 1.ogg 2.ogg 10.ogg). This method does not take the current language's collation rules into account."),
- N_("Do not sort the items.") };
-
-#define SORT_TEXT N_("Directory sort order")
-#define SORT_LONGTEXT N_( \
- "Define the sort algorithm used when adding items from a directory." )
-
#define IGNORE_TEXT N_("Ignored extensions")
#define IGNORE_LONGTEXT N_( \
"Files with these extensions will not be added to playlist when " \
@@ -182,8 +172,6 @@ vlc_module_begin ()
change_string_list( psz_recursive_list, psz_recursive_list_text )
add_string( "ignore-filetypes", "m3u,db,nfo,ini,jpg,jpeg,ljpg,gif,png,pgm,pgmyuv,pbm,pam,tga,bmp,pnm,xpm,xcf,pcx,tif,tiff,lbm,sfv,txt,sub,idx,srt,cue,ssa",
IGNORE_TEXT, IGNORE_LONGTEXT, false )
- add_string( "directory-sort", "collate", SORT_TEXT, SORT_LONGTEXT, false )
- change_string_list( psz_sort_list, psz_sort_list_text )
add_bool( "show-hiddenfiles", false,
SHOW_HIDDENFILES_TEXT, SHOW_HIDDENFILES_LONGTEXT, false )
vlc_module_end ()
diff --git a/src/input/access.c b/src/input/access.c
index 6c48431..ed3e40f 100644
--- a/src/input/access.c
+++ b/src/input/access.c
@@ -29,6 +29,9 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#ifdef HAVE_STRCOLL
+# define strcoll strcasecmp
+#endif
#include <vlc_common.h>
#include <vlc_url.h>
@@ -332,9 +335,7 @@ static int compar_type(input_item_t *p1, input_item_t *p2)
return 0;
}
-/* Some code duplication between comparison functions.
- * GNU qsort_r() would be needed to solve this. */
-static int compar_collate(const void *a, const void *b)
+static int compar_filename(const void *a, const void *b)
{
input_item_node_t *const *na = a, *const *nb = b;
input_item_t *ia = (*na)->p_item, *ib = (*nb)->p_item;
@@ -343,28 +344,40 @@ static int compar_collate(const void *a, const void *b)
if (i_ret != 0)
return i_ret;
-#ifdef HAVE_STRCOLL
- /* The program's LOCAL defines if case is ignored */
- return strcoll(ia->psz_name, ib->psz_name);
-#else
- return strcasecmp(ia->psz_name, ib->psz_name);
-#endif
+ size_t i;
+ char c;
+
+ /* Attempt to guess if the sorting algorithm should be alphabetic
+ * (i.e. collation) or numeric:
+ * - If the first mismatching characters are not both digits,
+ * then collation is the only option.
+ * - If one of the first mismatching characters is 0 and the other is also
+ * a digit, the comparands are probably left-padded numerical values.
+ * It does not matter which algorithm is used: the zero will be smaller
+ * than non-zero either way.
+ * - Otherwise, the comparands are numerical values, and might not be
+ * aligned (i.e. not same order of magnitude). If so, collation would
+ * fail. So numerical comparison is performed. */
+ for (i = 0; (c = ia->psz_name[i]) == ib->psz_name[i]; i++)
+ if (c == '\0')
+ return 0; /* strings are exactly identical */
+
+ if ((unsigned)(c - '0') > 9)
+ return strcoll(ia->psz_name, ib->psz_name);
+
+ unsigned long long ua = strtoull(ia->psz_name + i, NULL, 10);
+ unsigned long long ub = strtoull(ib->psz_name + i, NULL, 10);
+
+ /* The number may be identical in two cases:
+ * - leading zero (e.g. "012" and "12")
+ * - overflow on both sides (#ULLONG_MAX) */
+ if (ua == ub)
+ return strcoll(ia->psz_name, ib->psz_name);
+
+ return (ua > ub) ? +1 : -1;
}
-static int compar_version(const void *a, const void *b)
-{
- input_item_node_t *const *na = a, *const *nb = b;
- input_item_t *ia = (*na)->p_item, *ib = (*nb)->p_item;
-
- int i_ret = compar_type(ia, ib);
- if (i_ret != 0)
- return i_ret;
-
- return strverscmp(ia->psz_name, ib->psz_name);
-}
-
-static void fsdir_sort_sub(input_item_node_t *p_node,
- int (*compar)(const void *, const void *))
+static void fsdir_sort(input_item_node_t *p_node)
{
if (p_node->i_children <= 0)
return;
@@ -376,7 +389,7 @@ static void fsdir_sort_sub(input_item_node_t *p_node,
/* Sort current node */
qsort(p_node->pp_children, p_node->i_children,
- sizeof(input_item_node_t *), compar);
+ sizeof(input_item_node_t *), compar_filename);
/* Unlock all children */
for (int i = 0; i < p_node->i_children; i++)
@@ -384,23 +397,7 @@ static void fsdir_sort_sub(input_item_node_t *p_node,
/* Sort all children */
for (int i = 0; i < p_node->i_children; i++)
- fsdir_sort_sub(p_node->pp_children[i], compar);
-}
-
-static void fsdir_sort(struct access_fsdir *p_fsdir)
-{
- int (*pf_compar)(const void *, const void *) = NULL;
-
- if (p_fsdir->psz_sort != NULL)
- {
- if (!strcasecmp(p_fsdir->psz_sort, "version"))
- pf_compar = compar_version;
- else if(strcasecmp(p_fsdir->psz_sort, "none"))
- pf_compar = compar_collate;
-
- if (pf_compar != NULL)
- fsdir_sort_sub(p_fsdir->p_node, pf_compar);
- }
+ fsdir_sort(p_node->pp_children[i]);
}
/**
@@ -636,7 +633,6 @@ void access_fsdir_init(struct access_fsdir *p_fsdir,
p_fsdir->p_node = p_node;
p_fsdir->b_show_hiddenfiles = var_InheritBool(p_access, "show-hiddenfiles");
p_fsdir->psz_ignored_exts = var_InheritString(p_access, "ignore-filetypes");
- p_fsdir->psz_sort = var_InheritString(p_access, "directory-sort");
bool b_autodetect = var_InheritBool(p_access, "sub-autodetect-file");
p_fsdir->i_sub_autodetect_fuzzy = !b_autodetect ? 0 :
var_InheritInteger(p_access, "sub-autodetect-fuzzy");
@@ -648,10 +644,9 @@ void access_fsdir_finish(struct access_fsdir *p_fsdir, bool b_success)
if (b_success)
{
fsdir_attach_slaves(p_fsdir);
- fsdir_sort(p_fsdir);
+ fsdir_sort(p_fsdir->p_node);
}
free(p_fsdir->psz_ignored_exts);
- free(p_fsdir->psz_sort);
/* Remove unmatched slaves */
for (unsigned int i = 0; i < p_fsdir->i_slaves; i++)
More information about the vlc-commits
mailing list