summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/filetree.c23
-rw-r--r--apps/lang/deutsch.lang42
-rw-r--r--apps/lang/english.lang42
-rw-r--r--apps/menus/settings_menu.c3
-rw-r--r--apps/settings.h4
-rw-r--r--apps/settings_list.c23
-rw-r--r--docs/CREDITS2
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/common/strnatcmp.c179
-rw-r--r--firmware/include/strnatcmp.h30
10 files changed, 332 insertions, 17 deletions
diff --git a/apps/filetree.c b/apps/filetree.c
index fc5e4d3934..0ceb5c0941 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -45,6 +45,7 @@
45#include "cuesheet.h" 45#include "cuesheet.h"
46#include "filetree.h" 46#include "filetree.h"
47#include "misc.h" 47#include "misc.h"
48#include "strnatcmp.h"
48#ifdef HAVE_LCD_BITMAP 49#ifdef HAVE_LCD_BITMAP
49#include "keyboard.h" 50#include "keyboard.h"
50#endif 51#endif
@@ -242,12 +243,26 @@ static int compare(const void* p1, const void* p2)
242 243
243 case SORT_ALPHA: 244 case SORT_ALPHA:
244 case SORT_ALPHA_REVERSED: 245 case SORT_ALPHA_REVERSED:
246 {
245 if (global_settings.sort_case) 247 if (global_settings.sort_case)
246 return strncmp(e1->name, e2->name, MAX_PATH) 248 {
247 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1); 249 if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
250 return strnatcmp(e1->name, e2->name)
251 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
252 else
253 return strncmp(e1->name, e2->name, MAX_PATH)
254 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
255 }
248 else 256 else
249 return strncasecmp(e1->name, e2->name, MAX_PATH) 257 {
250 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1); 258 if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
259 return strnatcasecmp(e1->name, e2->name)
260 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
261 else
262 return strncasecmp(e1->name, e2->name, MAX_PATH)
263 * (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
264 }
265 }
251 266
252 } 267 }
253 return 0; /* never reached */ 268 return 0; /* never reached */
diff --git a/apps/lang/deutsch.lang b/apps/lang/deutsch.lang
index 6654688e6c..bc91c81c68 100644
--- a/apps/lang/deutsch.lang
+++ b/apps/lang/deutsch.lang
@@ -12187,3 +12187,45 @@
12187 quickscreen: "" 12187 quickscreen: ""
12188 </voice> 12188 </voice>
12189</phrase> 12189</phrase>
12190<phrase>
12191 id: LANG_SORT_INTERPRET_NUMBERS
12192 desc: in Settings -> File view
12193 user:
12194 <source>
12195 *: "Interpret numbers when sorting"
12196 </source>
12197 <dest>
12198 *: "Zahlen beim Sortieren interpretieren"
12199 </dest>
12200 <voice>
12201 *: "Zahlen beim Sortieren interpretieren"
12202 </voice>
12203</phrase>
12204<phrase>
12205 id: LANG_SORT_INTERPRET_AS_DIGIT
12206 desc: in Settings -> File view
12207 user:
12208 <source>
12209 *: "As digits"
12210 </source>
12211 <dest>
12212 *: "als Ziffern"
12213 </dest>
12214 <voice>
12215 *: "als Ziffern"
12216 </voice>
12217</phrase>
12218<phrase>
12219 id: LANG_SORT_INTERPRET_AS_NUMBERS
12220 desc: in Settings -> File view
12221 user:
12222 <source>
12223 *: "As whole numbers"
12224 </source>
12225 <dest>
12226 *: "als komplette Zahlen"
12227 </dest>
12228 <voice>
12229 *: "als komplette Zahlen"
12230 </voice>
12231</phrase>
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index a335ad179e..25cab34430 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12359,3 +12359,45 @@
12359 *: "Credits" 12359 *: "Credits"
12360 </voice> 12360 </voice>
12361</phrase> 12361</phrase>
12362<phrase>
12363 id: LANG_SORT_INTERPRET_NUMBERS
12364 desc: in Settings -> File view
12365 user:
12366 <source>
12367 *: "Interpret numbers when sorting"
12368 </source>
12369 <dest>
12370 *: "Interpret numbers when sorting"
12371 </dest>
12372 <voice>
12373 *: "Interpret numbers when sorting"
12374 </voice>
12375</phrase>
12376<phrase>
12377 id: LANG_SORT_INTERPRET_AS_DIGIT
12378 desc: in Settings -> File view
12379 user:
12380 <source>
12381 *: "As digits"
12382 </source>
12383 <dest>
12384 *: "As digits"
12385 </dest>
12386 <voice>
12387 *: "As digits"
12388 </voice>
12389</phrase>
12390<phrase>
12391 id: LANG_SORT_INTERPRET_AS_NUMBERS
12392 desc: in Settings -> File view
12393 user:
12394 <source>
12395 *: "As whole numbers"
12396 </source>
12397 <dest>
12398 *: "As whole numbers"
12399 </dest>
12400 <voice>
12401 *: "As whole numbers"
12402 </voice>
12403</phrase>
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 85e4f9649f..35db9b49e6 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -100,6 +100,7 @@ static int fileview_callback(int action,const struct menu_item_ex *this_item);
100MENUITEM_SETTING(sort_case, &global_settings.sort_case, NULL); 100MENUITEM_SETTING(sort_case, &global_settings.sort_case, NULL);
101MENUITEM_SETTING(sort_dir, &global_settings.sort_dir, fileview_callback); 101MENUITEM_SETTING(sort_dir, &global_settings.sort_dir, fileview_callback);
102MENUITEM_SETTING(sort_file, &global_settings.sort_file, fileview_callback); 102MENUITEM_SETTING(sort_file, &global_settings.sort_file, fileview_callback);
103MENUITEM_SETTING(interpret_numbers, &global_settings.interpret_numbers, fileview_callback);
103MENUITEM_SETTING(dirfilter, &global_settings.dirfilter, NULL); 104MENUITEM_SETTING(dirfilter, &global_settings.dirfilter, NULL);
104MENUITEM_SETTING(show_filename_ext, &global_settings.show_filename_ext, NULL); 105MENUITEM_SETTING(show_filename_ext, &global_settings.show_filename_ext, NULL);
105MENUITEM_SETTING(browse_current, &global_settings.browse_current, NULL); 106MENUITEM_SETTING(browse_current, &global_settings.browse_current, NULL);
@@ -124,7 +125,7 @@ static int fileview_callback(int action,const struct menu_item_ex *this_item)
124} 125}
125 126
126MAKE_MENU(file_menu, ID2P(LANG_FILE), 0, Icon_file_view_menu, 127MAKE_MENU(file_menu, ID2P(LANG_FILE), 0, Icon_file_view_menu,
127 &sort_case, &sort_dir, &sort_file, 128 &sort_case, &sort_dir, &sort_file, &interpret_numbers,
128 &dirfilter, &show_filename_ext, &browse_current, 129 &dirfilter, &show_filename_ext, &browse_current,
129#ifdef HAVE_LCD_BITMAP 130#ifdef HAVE_LCD_BITMAP
130 &show_path_in_browser 131 &show_path_in_browser
diff --git a/apps/settings.h b/apps/settings.h
index 7f5f025a8f..669000ea42 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -147,6 +147,7 @@ enum { SHOW_ALL, SHOW_SUPPORTED, SHOW_MUSIC, SHOW_PLAYLIST, SHOW_ID3DB,
147/* file and dir sort options */ 147/* file and dir sort options */
148enum { SORT_ALPHA, SORT_DATE, SORT_DATE_REVERSED, SORT_TYPE, /* available as settings */ 148enum { SORT_ALPHA, SORT_DATE, SORT_DATE_REVERSED, SORT_TYPE, /* available as settings */
149 SORT_ALPHA_REVERSED, SORT_TYPE_REVERSED }; /* internal use only */ 149 SORT_ALPHA_REVERSED, SORT_TYPE_REVERSED }; /* internal use only */
150enum { SORT_INTERPRET_AS_DIGIT, SORT_INTERPRET_AS_NUMBER };
150 151
151/* recursive dir insert options */ 152/* recursive dir insert options */
152enum { RECURSE_OFF, RECURSE_ON, RECURSE_ASK }; 153enum { RECURSE_OFF, RECURSE_ON, RECURSE_ASK };
@@ -612,8 +613,9 @@ struct user_settings
612 613
613 /* file browser sorting */ 614 /* file browser sorting */
614 bool sort_case; /* dir sort order: 0=case insensitive, 1=sensitive */ 615 bool sort_case; /* dir sort order: 0=case insensitive, 1=sensitive */
615 int sort_file; /* 0=alpha, 1=date, 2=date (new first), 3=type */
616 int sort_dir; /* 0=alpha, 1=date (old first), 2=date (new first) */ 616 int sort_dir; /* 0=alpha, 1=date (old first), 2=date (new first) */
617 int sort_file; /* 0=alpha, 1=date, 2=date (new first), 3=type */
618 int interpret_numbers; /* true=strnatcmp, false=strcmp */
617 619
618 /* power settings */ 620 /* power settings */
619 int poweroff; /* idle power off timer */ 621 int poweroff; /* idle power off timer */
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 97ca7cdca5..5729cdcf4a 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -783,7 +783,20 @@ const struct settings_list settings[] = {
783 "all,supported,music,playlists", NULL, 4, ID2P(LANG_ALL), 783 "all,supported,music,playlists", NULL, 4, ID2P(LANG_ALL),
784 ID2P(LANG_FILTER_SUPPORTED), ID2P(LANG_FILTER_MUSIC), 784 ID2P(LANG_FILTER_SUPPORTED), ID2P(LANG_FILTER_MUSIC),
785 ID2P(LANG_PLAYLISTS)), 785 ID2P(LANG_PLAYLISTS)),
786 /* file sorting */
786 OFFON_SETTING(0, sort_case, LANG_SORT_CASE, false, "sort case", NULL), 787 OFFON_SETTING(0, sort_case, LANG_SORT_CASE, false, "sort case", NULL),
788 CHOICE_SETTING(0, sort_dir, LANG_SORT_DIR, 0 ,
789 "sort dirs", "alpha,oldest,newest", NULL, 3,
790 ID2P(LANG_SORT_ALPHA), ID2P(LANG_SORT_DATE),
791 ID2P(LANG_SORT_DATE_REVERSE)),
792 CHOICE_SETTING(0, sort_file, LANG_SORT_FILE, 0 ,
793 "sort files", "alpha,oldest,newest,type", NULL, 4,
794 ID2P(LANG_SORT_ALPHA), ID2P(LANG_SORT_DATE),
795 ID2P(LANG_SORT_DATE_REVERSE) , ID2P(LANG_SORT_TYPE)),
796 CHOICE_SETTING(0, interpret_numbers, LANG_SORT_INTERPRET_NUMBERS, 1,
797 "sort interpret number", "digits,numbers",NULL, 2,
798 ID2P(LANG_SORT_INTERPRET_AS_DIGIT),
799 ID2P(LANG_SORT_INTERPRET_AS_NUMBERS)),
787 CHOICE_SETTING(0, show_filename_ext, LANG_SHOW_FILENAME_EXT, 3, 800 CHOICE_SETTING(0, show_filename_ext, LANG_SHOW_FILENAME_EXT, 3,
788 "show filename exts", "off,on,unknown,view_all", NULL , 4 , 801 "show filename exts", "off,on,unknown,view_all", NULL , 4 ,
789 ID2P(LANG_OFF), ID2P(LANG_ON), ID2P(LANG_UNKNOWN_TYPES), 802 ID2P(LANG_OFF), ID2P(LANG_ON), ID2P(LANG_UNKNOWN_TYPES),
@@ -893,16 +906,6 @@ const struct settings_list settings[] = {
893 OFFON_SETTING(F_TEMPVAR, talk_battery_level, LANG_TALK_BATTERY_LEVEL, false, 906 OFFON_SETTING(F_TEMPVAR, talk_battery_level, LANG_TALK_BATTERY_LEVEL, false,
894 "Announce Battery Level", NULL), 907 "Announce Battery Level", NULL),
895 908
896 /* file sorting */
897 CHOICE_SETTING(0, sort_file, LANG_SORT_FILE, 0 ,
898 "sort files", "alpha,oldest,newest,type", NULL, 4,
899 ID2P(LANG_SORT_ALPHA), ID2P(LANG_SORT_DATE),
900 ID2P(LANG_SORT_DATE_REVERSE) , ID2P(LANG_SORT_TYPE)),
901 CHOICE_SETTING(0, sort_dir, LANG_SORT_DIR, 0 ,
902 "sort dirs", "alpha,oldest,newest", NULL, 3,
903 ID2P(LANG_SORT_ALPHA), ID2P(LANG_SORT_DATE),
904 ID2P(LANG_SORT_DATE_REVERSE)),
905
906#ifdef HAVE_RECORDING 909#ifdef HAVE_RECORDING
907 /* recording */ 910 /* recording */
908 STRINGCHOICE_SETTING(F_RECSETTING, rec_timesplit, LANG_SPLIT_TIME, 0, 911 STRINGCHOICE_SETTING(F_RECSETTING, rec_timesplit, LANG_SPLIT_TIME, 0,
diff --git a/docs/CREDITS b/docs/CREDITS
index 5ae39f468a..e9aa7d7af2 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -450,7 +450,7 @@ Kenderes Tamas
450Eric Shattow 450Eric Shattow
451Joshua Simmons 451Joshua Simmons
452Sei Aoyumi 452Sei Aoyumi
453 453Martin Pool
454 454
455The libmad team 455The libmad team
456The wavpack team 456The wavpack team
diff --git a/firmware/SOURCES b/firmware/SOURCES
index de42ada0cc..0b6bb155b0 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -49,6 +49,7 @@ common/strcasestr.c
49common/strcat.c 49common/strcat.c
50common/strchr.c 50common/strchr.c
51common/strcmp.c 51common/strcmp.c
52common/strnatcmp.c
52common/strcpy.c 53common/strcpy.c
53common/strncmp.c 54common/strncmp.c
54common/strncpy.c 55common/strncpy.c
diff --git a/firmware/common/strnatcmp.c b/firmware/common/strnatcmp.c
new file mode 100644
index 0000000000..84e0d38362
--- /dev/null
+++ b/firmware/common/strnatcmp.c
@@ -0,0 +1,179 @@
1/* -*- mode: c; c-file-style: "k&r" -*-
2
3 strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
4 Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
21*/
22
23
24/* partial change history:
25 *
26 * 2004-10-10 mbp: Lift out character type dependencies into macros.
27 *
28 * Eric Sosman pointed out that ctype functions take a parameter whose
29 * value must be that of an unsigned int, even on platforms that have
30 * negative chars in their default char type.
31 */
32
33#include <ctype.h>
34#include <string.h>
35#include <stdio.h>
36
37#include "strnatcmp.h"
38
39#define assert(x) /* nothing */
40
41
42/* These are defined as macros to make it easier to adapt this code to
43 * different characters types or comparison functions. */
44static inline int
45nat_isdigit(char a)
46{
47 return isdigit((unsigned char) a);
48}
49
50
51static inline int
52nat_isspace(char a)
53{
54 return a == '0' || isspace((unsigned char) a);
55}
56
57
58static inline char
59nat_toupper(char a)
60{
61 return toupper((unsigned char) a);
62}
63
64
65
66static int
67compare_right(char const *a, char const *b)
68{
69 int bias = 0;
70
71 /* The longest run of digits wins. That aside, the greatest
72 value wins, but we can't know that it will until we've scanned
73 both numbers to know that they have the same magnitude, so we
74 remember it in BIAS. */
75 for (;; a++, b++) {
76 if (!nat_isdigit(*a) && !nat_isdigit(*b))
77 return bias;
78 else if (!nat_isdigit(*a))
79 return -1;
80 else if (!nat_isdigit(*b))
81 return +1;
82 else if (*a < *b) {
83 if (!bias)
84 bias = -1;
85 } else if (*a > *b) {
86 if (!bias)
87 bias = +1;
88 } else if (!*a && !*b)
89 return bias;
90 }
91
92 return 0;
93}
94
95
96static int
97compare_left(char const *a, char const *b)
98{
99 /* Compare two left-aligned numbers: the first to have a
100 different value wins. */
101 for (;; a++, b++) {
102 if (!nat_isdigit(*a) && !nat_isdigit(*b))
103 return 0;
104 else if (!nat_isdigit(*a))
105 return -1;
106 else if (!nat_isdigit(*b))
107 return +1;
108 else if (*a < *b)
109 return -1;
110 else if (*a > *b)
111 return +1;
112 }
113
114 return 0;
115}
116
117
118static int strnatcmp0(char const *a, char const *b, int fold_case)
119{
120 int ai, bi;
121 char ca, cb;
122 int fractional, result;
123
124 assert(a && b);
125 ai = bi = 0;
126 while (1) {
127 ca = a[ai]; cb = b[bi];
128
129 /* skip over leading spaces or zeros */
130 while (nat_isspace(ca))
131 ca = a[++ai];
132
133 while (nat_isspace(cb))
134 cb = b[++bi];
135
136 /* process run of digits */
137 if (nat_isdigit(ca) && nat_isdigit(cb)) {
138 fractional = (ca == '0' || cb == '0');
139
140 if (fractional) {
141 if ((result = compare_left(a+ai, b+bi)) != 0)
142 return result;
143 } else {
144 if ((result = compare_right(a+ai, b+bi)) != 0)
145 return result;
146 }
147 }
148
149 if (!ca && !cb) {
150 /* The strings compare the same. Perhaps the caller
151 will want to call strcmp to break the tie. */
152 return 0;
153 }
154
155 if (fold_case) {
156 ca = nat_toupper(ca);
157 cb = nat_toupper(cb);
158 }
159
160 if (ca < cb)
161 return -1;
162 else if (ca > cb)
163 return +1;
164
165 ++ai; ++bi;
166 }
167}
168
169
170
171int strnatcmp(const char *a, const char *b) {
172 return strnatcmp0(a, b, 0);
173}
174
175
176/* Compare, recognizing numeric string and ignoring case. */
177int strnatcasecmp(const char *a, const char *b) {
178 return strnatcmp0(a, b, 1);
179}
diff --git a/firmware/include/strnatcmp.h b/firmware/include/strnatcmp.h
new file mode 100644
index 0000000000..50276554e6
--- /dev/null
+++ b/firmware/include/strnatcmp.h
@@ -0,0 +1,30 @@
1/* -*- mode: c; c-file-style: "k&r" -*-
2
3 strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
4 Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
21*/
22
23
24/* CUSTOMIZATION SECTION
25 *
26 * You can change this typedef, but must then also change the inline
27 * functions in strnatcmp.c */
28
29int strnatcmp(const char *a, const char *b);
30int strnatcasecmp(const char *a, const char *b);