Commit 40b946f2 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

directory: reconcile numerical and alphabetical sorting

parent d24cd3b7
......@@ -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);
......
......@@ -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 ()
......@@ -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 ()
......
......@@ -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++)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment