aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/ls.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2023-05-31 19:04:15 -0500
committerRob Landley <rob@landley.net>2023-05-31 19:04:15 -0500
commit0b20d799bc9a486fa740fedb4020a2be3faa30e4 (patch)
tree4c687fe0131cc2a2af83ddd0d8c7f2cb64f84e8b /toys/posix/ls.c
parent23fc1ecab1b49e3dfd681882946c6729adb78da6 (diff)
downloadtoybox-0b20d799bc9a486fa740fedb4020a2be3faa30e4.tar.gz
Add test for ls --sort and ls -lc vs -ltc, fix issues found by them.
Diffstat (limited to 'toys/posix/ls.c')
-rw-r--r--toys/posix/ls.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 56d5c638..228af58c 100644
--- a/toys/posix/ls.c
+++ b/toys/posix/ls.c
@@ -6,12 +6,13 @@
* See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html
*
* Deviations from posix:
- * add -b (and default to it instead of -q for an unambiguous representation
- * that doesn't cause collisions)
+ * add -b (as default instead of -q: -b is unambiguous without collisions)
* add -Z -ll --color
* Posix says the -l date format should vary based on how recent it is
* and we do --time-style=long-iso instead
* ignore -k because we default to 1024 byte blocks
+ * Deviations from gnu: -N switches off -q (no --show-control-chars)
+ * No --quoting-style=shell-escape, mostly because no short or long opt for it
USE_LS(NEWTOY(ls, "(sort):(color):;(full-time)(show-control-chars)\241(group-directories-first)\376ZgoACFHLNRSUXabcdfhikl@mnpqrstuw#=80<0x1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][-Nqb]", TOYFLAG_BIN|TOYFLAG_LOCALE))
@@ -161,7 +162,7 @@ static void entrylen(struct dirtree *dt, unsigned *len)
// Perform one or more comparisons on a pair of files.
// Reused FLAG_a to mean "alphabetical"
-static int do_compare(struct dirtree *a, struct dirtree *b, long flags)
+static int do_compare(struct dirtree *a, struct dirtree *b, long long flags)
{
struct timespec *ts1 = 0, *ts2;
char *s1, *s2;
@@ -173,11 +174,11 @@ static int do_compare(struct dirtree *a, struct dirtree *b, long flags)
if (a->st.st_size > b->st.st_size) return -1;
else if (a->st.st_size < b->st.st_size) return 1;
}
-
if (flags&FLAG_t) ts1 = &a->st.st_mtim, ts2 = &b->st.st_mtim;
if (flags&FLAG_u) ts1 = &a->st.st_atim, ts2 = &b->st.st_atim;
if (flags&FLAG_c) ts1 = &a->st.st_ctim, ts2 = &b->st.st_ctim;
if (ts1) {
+ // Newest is first by default, so return values are backwards
if (ts1->tv_sec > ts2->tv_sec) return -1;
else if (ts1->tv_sec < ts2->tv_sec) return 1;
else if (ts1->tv_nsec > ts2->tv_nsec) return -1;
@@ -188,9 +189,15 @@ static int do_compare(struct dirtree *a, struct dirtree *b, long flags)
return S_ISDIR(a->st.st_mode) ? -1 : 1;
// -X is a form of alphabetical sort, without -~ do case sensitive comparison
- if ((flags&FLAG_X) && (s1 = strrchr(a->name, '.')) && (s2 = strrchr(b->name, '.'))) {
+ s1 = 0;
+ if (flags&FLAG_X) {
+ s1 = strrchr(a->name, '.');
+ s2 = strrchr(b->name, '.');
+ if (s2 && !s1) return -1;
+ if (s1 && !s2) return 1;
if (!(flags&FLAG_X7E)) flags |= FLAG_a;
- } else {
+ }
+ if (!s1) {
s1 = a->name;
s2 = b->name;
}
@@ -215,13 +222,13 @@ static int compare(void *a, void *b)
char *ss = TT.sort;
long long ll = 0;
int ret = 0;
-
// TODO: test --sort=reverse with fallback alphabetical
- if (ss) while (*ss) {
+ if (ss) for (;;) {
+ while (*ss==',') ss++;
+ if (!*ss) break;
if (comma_start(&ss, "reverse")) toys.optflags |= FLAG_r;
else if (comma_start(&ss, "none")) goto skip;
- else if (ret) continue;
else if (comma_start(&ss, "ctime")) ll = FLAG_c;
else if (comma_start(&ss, "size")) ll = FLAG_S;
else if (comma_start(&ss, "time")) ll = FLAG_t;
@@ -231,10 +238,19 @@ static int compare(void *a, void *b)
else if (comma_start(&ss, "dirfirst")) ll = FLAG_X21;
else error_exit("bad --sort %s", ss);
- ret = do_compare(dta, dtb, ll);
+ if (!ret) ret = do_compare(dta, dtb, ll);
}
- if (!ret) ret = do_compare(dta, dtb, toys.optflags|FLAG_a);
+ // Alpha fallback sort, and handle short opts
+ if (!ret) {
+ ll = toys.optflags|FLAG_a;
+ // historical nonsense: -lc displays -c but doesn't sort, -ltc sorts.
+ if (FLAG(o)|FLAG(l)) {
+ if (!FLAG(t)) ll &= ~(FLAG_c|FLAG_u);
+ else if (FLAG(c)||FLAG(u)) ll &= ~FLAG_t;
+ }
+ ret = do_compare(dta, dtb, ll);
+ }
skip:
if (FLAG(r)) ret *= -1;