summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCiprian Tomoiaga <ciprian.tomoiaga@gmail.com>2021-12-22 14:26:42 +0000
committerCiprian Tomoiaga <ciprian.tomoiaga@gmail.com>2021-12-22 14:26:42 +0000
commit8137444062c8f1e08d9bc2d3951ec96b164191f2 (patch)
tree57c95fc1a6e0fdb3959e23e7295b5870941c75c4
parente1a9b30803f2a6d7a079c223234c95a156bfab2f (diff)
Use Natural Sort by Name in v1.x
-rw-r--r--Makefile.am1
-rw-r--r--src/dirlist.c4
-rw-r--r--src/strnatcmp.c177
-rw-r--r--src/strnatcmp.h31
4 files changed, 211 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 01a79c4..223e24f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,6 +12,7 @@ ncdu_SOURCES=\
src/dir_scan.c\
src/exclude.c\
src/help.c\
+ src/strnatcmp.c\
src/shell.c\
src/quit.c\
src/main.c\
diff --git a/src/dirlist.c b/src/dirlist.c
index 2061007..2352ee5 100644
--- a/src/dirlist.c
+++ b/src/dirlist.c
@@ -24,6 +24,7 @@
*/
#include "global.h"
+#include "strnatcmp.h"
#include <string.h>
#include <stdlib.h>
@@ -79,7 +80,7 @@ static int dirlist_cmp(struct dir *x, struct dir *y) {
*
* Note that the method used below is supposed to be fast, not readable :-)
*/
-#define CMP_NAME strcmp(x->name, y->name)
+#define CMP_NAME strnatcmp(x->name, y->name)
#define CMP_SIZE (x->size > y->size ? 1 : (x->size == y->size ? 0 : -1))
#define CMP_ASIZE (x->asize > y->asize ? 1 : (x->asize == y->asize ? 0 : -1))
#define CMP_ITEMS (x->items > y->items ? 1 : (x->items == y->items ? 0 : -1))
@@ -395,4 +396,3 @@ void dirlist_set_hidden(int hidden) {
dirlist_fixup();
dirlist_top(-5);
}
-
diff --git a/src/strnatcmp.c b/src/strnatcmp.c
new file mode 100644
index 0000000..e253eec
--- /dev/null
+++ b/src/strnatcmp.c
@@ -0,0 +1,177 @@
+/* -*- mode: c; c-file-style: "k&r" -*-
+
+ strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
+ Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+/* partial change history:
+ *
+ * 2004-10-10 mbp: Lift out character type dependencies into macros.
+ *
+ * Eric Sosman pointed out that ctype functions take a parameter whose
+ * value must be that of an unsigned int, even on platforms that have
+ * negative chars in their default char type.
+ */
+
+#include <stddef.h> /* size_t */
+#include <ctype.h>
+
+#include "strnatcmp.h"
+
+
+/* These are defined as macros to make it easier to adapt this code to
+ * different characters types or comparison functions. */
+static inline int
+nat_isdigit(nat_char a)
+{
+ return isdigit((unsigned char) a);
+}
+
+
+static inline int
+nat_isspace(nat_char a)
+{
+ return isspace((unsigned char) a);
+}
+
+
+static inline nat_char
+nat_toupper(nat_char a)
+{
+ return toupper((unsigned char) a);
+}
+
+
+static int
+compare_right(nat_char const *a, nat_char const *b)
+{
+ int bias = 0;
+
+ /* The longest run of digits wins. That aside, the greatest
+ value wins, but we can't know that it will until we've scanned
+ both numbers to know that they have the same magnitude, so we
+ remember it in BIAS. */
+ for (;; a++, b++) {
+ if (!nat_isdigit(*a) && !nat_isdigit(*b))
+ return bias;
+ if (!nat_isdigit(*a))
+ return -1;
+ if (!nat_isdigit(*b))
+ return +1;
+ if (*a < *b) {
+ if (!bias)
+ bias = -1;
+ } else if (*a > *b) {
+ if (!bias)
+ bias = +1;
+ } else if (!*a && !*b)
+ return bias;
+ }
+
+ return 0;
+}
+
+
+static int
+compare_left(nat_char const *a, nat_char const *b)
+{
+ /* Compare two left-aligned numbers: the first to have a
+ different value wins. */
+ for (;; a++, b++) {
+ if (!nat_isdigit(*a) && !nat_isdigit(*b))
+ return 0;
+ if (!nat_isdigit(*a))
+ return -1;
+ if (!nat_isdigit(*b))
+ return +1;
+ if (*a < *b)
+ return -1;
+ if (*a > *b)
+ return +1;
+ }
+
+ return 0;
+}
+
+
+static int
+strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
+{
+ int ai, bi;
+ nat_char ca, cb;
+ int fractional, result;
+
+ ai = bi = 0;
+ while (1) {
+ ca = a[ai]; cb = b[bi];
+
+ /* skip over leading spaces or zeros */
+ while (nat_isspace(ca))
+ ca = a[++ai];
+
+ while (nat_isspace(cb))
+ cb = b[++bi];
+
+ /* process run of digits */
+ if (nat_isdigit(ca) && nat_isdigit(cb)) {
+ fractional = (ca == '0' || cb == '0');
+
+ if (fractional) {
+ if ((result = compare_left(a+ai, b+bi)) != 0)
+ return result;
+ } else {
+ if ((result = compare_right(a+ai, b+bi)) != 0)
+ return result;
+ }
+ }
+
+ if (!ca && !cb) {
+ /* The strings compare the same. Perhaps the caller
+ will want to call strcmp to break the tie. */
+ return 0;
+ }
+
+ if (fold_case) {
+ ca = nat_toupper(ca);
+ cb = nat_toupper(cb);
+ }
+
+ if (ca < cb)
+ return -1;
+
+ if (ca > cb)
+ return +1;
+
+ ++ai; ++bi;
+ }
+}
+
+
+int
+strnatcmp(nat_char const *a, nat_char const *b) {
+ return strnatcmp0(a, b, 0);
+}
+
+
+/* Compare, recognizing numeric string and ignoring case. */
+int
+strnatcasecmp(nat_char const *a, nat_char const *b) {
+ return strnatcmp0(a, b, 1);
+}
diff --git a/src/strnatcmp.h b/src/strnatcmp.h
new file mode 100644
index 0000000..51a3c4e
--- /dev/null
+++ b/src/strnatcmp.h
@@ -0,0 +1,31 @@
+/* -*- mode: c; c-file-style: "k&r" -*-
+
+ strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
+ Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+/* CUSTOMIZATION SECTION
+ *
+ * You can change this typedef, but must then also change the inline
+ * functions in strnatcmp.c */
+typedef char nat_char;
+
+int strnatcmp(nat_char const *a, nat_char const *b);
+int strnatcasecmp(nat_char const *a, nat_char const *b);