On 15 February 2015 at 15:32, FRIGN <d...@frign.de> wrote:
> thanks for reporting this!
> I remember writing this part of mkrunetype.awk at 2am in the morning.
> In the end, the most trivial things are wrong. :P
> I changed the underlying awk-script as well, so we're good to go now.

Revised patchset rebased onto HEAD.

-- 
Tai Chi Minh Ralph Eastwood
tcmreastw...@gmail.com
From a5b63e2e041d64a332cec73203ec460d950289b6 Mon Sep 17 00:00:00 2001
From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com>
Date: Thu, 12 Feb 2015 15:03:31 +0000
Subject: [PATCH 1/4] ls: fix using strcoll instead of strcmp

---
 ls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ls.c b/ls.c
index 81b7f7d..6c0fdef 100644
--- a/ls.c
+++ b/ls.c
@@ -123,7 +123,7 @@ entcmp(const void *va, const void *vb)
 	if (tflag)
 		return b->t - a->t;
 	else
-		return strcmp(a->name, b->name);
+		return strcoll(a->name, b->name);
 }
 
 static void
-- 
2.3.0

From b98c0ff20f6ea882bf6084d712aa85fd72a4ef0b Mon Sep 17 00:00:00 2001
From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com>
Date: Sun, 15 Feb 2015 12:16:55 +0000
Subject: [PATCH 2/4] ls: add -R recursive and -C column output

---
 README |   2 +-
 ls.1   |   4 ++
 ls.c   | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 155 insertions(+), 31 deletions(-)

diff --git a/README b/README
index 8e5d4fe..45760f0 100644
--- a/README
+++ b/README
@@ -40,7 +40,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support,
 =* ln              yes                          none
 =* logger          yes                          none
 =* logname         yes                          none
-=  ls              no                           -C, -R, -q, -u
+=  ls              no                           -q, -u
 =* md5sum          non-posix                    none
 =* mkdir           yes                          none
 =* mkfifo          yes                          none
diff --git a/ls.1 b/ls.1
index 993d29e..ad90b37 100644
--- a/ls.1
+++ b/ls.1
@@ -16,6 +16,8 @@ are given the current directory is listed.
 .Bl -tag -width Ds
 .It Fl a
 Show hidden files (those beginning with '.').
+.It Fl C
+Display output in columns if the output devices is a terminal
 .It Fl c
 Use time file's status was last changed instead of last
 modification time for sorting or printing.
@@ -36,6 +38,8 @@ themselves.
 .It Fl l
 List detailed information about each file, including their type, permissions,
 links, owner, group, size, and last file status/modification time.
+.It Fl R
+Traverse directories recursively.
 .It Fl r
 Reverse the sort order.
 .It Fl t
diff --git a/ls.c b/ls.c
index 6c0fdef..eec5145 100644
--- a/ls.c
+++ b/ls.c
@@ -1,5 +1,6 @@
 /* See LICENSE file for copyright and license details. */
 #include <sys/stat.h>
+#include <sys/ioctl.h>
 
 #include <dirent.h>
 #include <grp.h>
@@ -23,11 +24,13 @@ typedef struct {
 	ino_t ino;
 } Entry;
 
+static int entcmpdir(const void *, const void *);
 static int entcmp(const void *, const void *);
-static void ls(Entry *);
+static int ls(Entry *, FILE *, int);
 static void lsdir(const char *);
 static void mkent(Entry *, char *, int, int);
-static void output(Entry *);
+static void output(Entry *, FILE *);
+static void columns(char *, size_t, int);
 
 static int aflag = 0;
 static int cflag = 0;
@@ -41,20 +44,26 @@ static int lflag = 0;
 static int rflag = 0;
 static int tflag = 0;
 static int Uflag = 0;
-static int first = 1;
+static int Cflag = 0;
+static int Rflag = 0;
 static int many;
+static int first = 1;
+static struct winsize ws;
 
 static void
 usage(void)
 {
-	eprintf("usage: %s [-1acdFHhiLlrtU] [file ...]\n", argv0);
+	eprintf("usage: %s [-1aCcdFHhiLlRrtU] [file ...]\n", argv0);
 }
 
 int
 main(int argc, char *argv[])
 {
-	int i;
+	int i, c = 0;
 	Entry *ents;
+	FILE *mfp;
+	char *buf;
+	size_t size;
 
 	ARGBEGIN {
 	case '1':
@@ -96,6 +105,13 @@ main(int argc, char *argv[])
 	case 'U':
 		Uflag = 1;
 		break;
+	case 'C':
+		if ((Cflag = isatty(fileno(stdout))))
+			ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+		break;
+	case 'R':
+		Rflag = 1;
+		break;
 	default:
 		usage();
 	} ARGEND;
@@ -106,19 +122,47 @@ main(int argc, char *argv[])
 
 	ents = emalloc(argc * sizeof(*ents));
 
+	if (Cflag)
+		mfp = open_memstream(&buf, &size);
+	else
+		mfp = stdout;
+
 	for (i = 0; i < argc; i++)
 		mkent(&ents[i], argv[i], 1, Hflag || Lflag);
 	qsort(ents, argc, sizeof *ents, entcmp);
 	for (i = 0; i < argc; i++)
-		ls(&ents[rflag ? argc-i-1 : i]);
+		c += ls(&ents[rflag ? argc-i-1 : i], mfp, 1);
+
+	if (Cflag) {
+		fclose(mfp);
+		columns(buf, size, c);
+		free(buf);
+	}
 
 	return 0;
 }
 
 static int
+entcmpdir(const void *va, const void *vb)
+{
+	const Entry *a = va, *b = vb;
+	int ad, bd;
+
+	ad = (S_ISDIR(a->mode) || (S_ISLNK(a->mode) && S_ISDIR(a->tmode) && !Fflag && !lflag));
+	bd = (S_ISDIR(b->mode) || (S_ISLNK(b->mode) && S_ISDIR(b->tmode) && !Fflag && !lflag));
+	return ad - bd;
+}
+
+static int
 entcmp(const void *va, const void *vb)
 {
 	const Entry *a = va, *b = vb;
+	int d = 0;
+
+	if (many && !dflag) {
+		if ((d = entcmpdir(va, vb)))
+			return d;
+	}
 
 	if (tflag)
 		return b->t - a->t;
@@ -126,13 +170,15 @@ entcmp(const void *va, const void *vb)
 		return strcoll(a->name, b->name);
 }
 
-static void
-ls(Entry *ent)
+static int
+ls(Entry *ent, FILE *mfp, int recurse)
 {
-	if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) {
+	if (recurse && (S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) {
 		lsdir(ent->name);
+		return 0;
 	} else {
-		output(ent);
+		output(ent, mfp);
+		return 1;
 	}
 }
 
@@ -143,8 +189,11 @@ lsdir(const char *path)
 	long i, n = 0;
 	struct dirent *d;
 	DIR *dp;
-	Entry ent, *ents = NULL;
+	Entry ent, *entp, *ents = NULL;
 	size_t sz;
+	FILE *mfp;
+	char *buf;
+	size_t size;
 
 	cwd = agetcwd();
 	if (!(dp = opendir(path)))
@@ -152,36 +201,62 @@ lsdir(const char *path)
 	if (chdir(path) < 0)
 		eprintf("chdir %s:", path);
 
-	if (many) {
+	if (many || Rflag) {
 		if (!first)
 			putchar('\n');
 		printf("%s:\n", path);
-		first = 0;
 	}
+	first = 0;
+
+	if (Cflag)
+		mfp = open_memstream(&buf, &size);
+	else
+		mfp = stdout;
 
 	while ((d = readdir(dp))) {
 		if (d->d_name[0] == '.' && !aflag)
 			continue;
-		if (Uflag){
-			mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag);
-			output(&ent);
+		if (Uflag && !Rflag){
+			mkent(&ent, d->d_name, Fflag || lflag || iflag || Rflag, Lflag);
+			n += ls(&ent, mfp, Rflag);
 		} else {
 			ents = erealloc(ents, ++n * sizeof *ents);
 			p = emalloc((sz = strlen(d->d_name)+1));
 			memcpy(p, d->d_name, sz);
-			mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag, Lflag);
+			mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag || Rflag, Lflag);
 		}
 	}
 	closedir(dp);
-	if (!Uflag){
-		qsort(ents, n, sizeof *ents, entcmp);
+	if (!Uflag || Rflag) {
+		qsort(ents, n, sizeof *ents, Uflag ? entcmpdir : entcmp);
 		for (i = 0; i < n; i++) {
-			output(&ents[rflag ? n-i-1 : i]);
-			free(ents[rflag ? n-i-1 : i].name);
+			entp = &ents[rflag ? n-i-1 : i];
+			if ((S_ISDIR(entp->mode) ||
+			    (S_ISLNK(entp->mode) &&
+			     S_ISDIR(entp->tmode) &&
+			     !Fflag && !lflag)) && Rflag)
+				break;
+			ls(entp, mfp, Rflag);
+			free(entp->name);
 		}
 	}
+
 	if (chdir(cwd) < 0)
 		eprintf("chdir %s:", cwd);
+
+	if (Cflag) {
+		fclose(mfp);
+		columns(buf, size, i);
+		free(buf);
+	}
+
+	if (Rflag) {
+		for (; i < n; i++) {
+			ls(&ents[rflag ? n-i-1 : i], mfp, Rflag);
+			free(ents[rflag ? n-i-1 : i].name);
+		}
+	}
+
 	free(ents);
 	free(cwd);
 }
@@ -230,7 +305,7 @@ indicator(mode_t mode)
 }
 
 static void
-output(Entry *ent)
+output(Entry *ent, FILE *f)
 {
 	char buf[BUFSIZ], *fmt;
 	char mode[] = "----------";
@@ -240,10 +315,11 @@ output(Entry *ent)
 	char pwname[_SC_LOGIN_NAME_MAX];
 	char grname[_SC_LOGIN_NAME_MAX];
 
+	first = 0;
 	if (iflag)
-		printf("%lu ", (unsigned long)ent->ino);
+		fprintf(f, "%lu ", (unsigned long)ent->ino);
 	if (!lflag) {
-		printf("%s%s\n", ent->name, indicator(ent->mode));
+		fprintf(f, "%s%s\n", ent->name, indicator(ent->mode));
 		return;
 	}
 	if (S_ISREG(ent->mode))
@@ -295,17 +371,61 @@ output(Entry *ent)
 		fmt = "%b %d %H:%M";
 
 	strftime(buf, sizeof buf, fmt, localtime(&ent->t));
-	printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
+	fprintf(f, "%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
 	if (hflag)
-		printf("%10s ", humansize((unsigned long)ent->size));
+		fprintf(f, "%10s ", humansize((unsigned long)ent->size));
 	else
-		printf("%10lu ", (unsigned long)ent->size);
-	printf("%s %s%s", buf, ent->name, indicator(ent->mode));
+		fprintf(f, "%10lu ", (unsigned long)ent->size);
+	fprintf(f, "%s %s%s", buf, ent->name, indicator(ent->mode));
 	if (S_ISLNK(ent->mode)) {
 		if ((len = readlink(ent->name, buf, sizeof buf - 1)) < 0)
 			eprintf("readlink %s:", ent->name);
 		buf[len] = '\0';
-		printf(" -> %s%s", buf, indicator(ent->tmode));
+		fprintf(f, " -> %s%s", buf, indicator(ent->tmode));
 	}
-	putchar('\n');
+	fputc('\n', f);
+}
+
+static void columns(char *buf, size_t sz, int cnt)
+{
+	int colw[16];
+	char *p = buf, *lp = buf;
+	int i = 0, j, k, t, l, s;
+	int *ll = emalloc(sizeof(*ll) * cnt);
+	char **sp = emalloc(sizeof(char *) * cnt);
+
+	while ((p = strchr(lp, '\n'))) {
+		*p = '\0';
+		ll[i] = strlen(lp);
+		sp[i++] = lp;
+		lp = p + 1;
+	}
+
+	for (l = 16; l > 0; --l) { /* each col size */
+		t = k = 0;
+		s = cnt / l + !!(cnt % l);
+		memset(colw, 0, sizeof(*colw) * l);
+		for (j = 0; j < cnt; j++) {
+			k += (j && !(j % s));
+			if (colw[k] < ll[j]) {
+				t += ll[j] - colw[k];
+				colw[k] = ll[j];
+			}
+			if (t > ws.ws_col - (l - 1) * 2)
+				break;
+		}
+		if (t <= ws.ws_col - (l - 1) * 2)
+			break; /* fits */
+	}
+	if (l == 0)
+		l = 1;
+	for (j = 0; j < s; j++) {
+		for (i = 0; i < l && i * s + j < cnt; i++)
+			printf("%-*s", colw[i] + (i == l - 1 ? 0 : 2),
+			       sp[i * s + j]);
+		putchar('\n');
+	}
+
+	free(ll);
+	free(sp);
 }
-- 
2.3.0

From 76218e5eb0c081ac8718fd1a1cfc28da16595a71 Mon Sep 17 00:00:00 2001
From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com>
Date: Sun, 15 Feb 2015 10:23:21 +0000
Subject: [PATCH 3/4] ls: add implementation of -q and -u flags

---
 ls.1 |  5 +++++
 ls.c | 51 +++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/ls.1 b/ls.1
index ad90b37..2aa37b2 100644
--- a/ls.1
+++ b/ls.1
@@ -38,6 +38,8 @@ themselves.
 .It Fl l
 List detailed information about each file, including their type, permissions,
 links, owner, group, size, and last file status/modification time.
+.It Fl q
+When printing file names, replace all non-printable characters with 'q'.
 .It Fl R
 Traverse directories recursively.
 .It Fl r
@@ -46,6 +48,9 @@ Reverse the sort order.
 Sort files by last file status/modification time instead of by name.
 .It Fl U
 Keep the list unsorted.
+.It Fl u
+Use time file was last access instead of last modification time for sorting
+or printing.
 .El
 .Sh SEE ALSO
 .Xr stat 2
diff --git a/ls.c b/ls.c
index eec5145..75cb418 100644
--- a/ls.c
+++ b/ls.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "util.h"
+#include "utf.h"
 
 typedef struct {
 	char *name;
@@ -46,6 +47,8 @@ static int tflag = 0;
 static int Uflag = 0;
 static int Cflag = 0;
 static int Rflag = 0;
+static int qflag = 0;
+static int uflag = 0;
 static int many;
 static int first = 1;
 static struct winsize ws;
@@ -53,7 +56,7 @@ static struct winsize ws;
 static void
 usage(void)
 {
-	eprintf("usage: %s [-1aCcdFHhiLlRrtU] [file ...]\n", argv0);
+	eprintf("usage: %s [-1aCcdFHhiLlqRrtUu] [file ...]\n", argv0);
 }
 
 int
@@ -74,6 +77,7 @@ main(int argc, char *argv[])
 		break;
 	case 'c':
 		cflag = 1;
+		uflag = 0;
 		break;
 	case 'd':
 		dflag = 1;
@@ -112,6 +116,13 @@ main(int argc, char *argv[])
 	case 'R':
 		Rflag = 1;
 		break;
+	case 'q':
+		qflag = 1;
+		break;
+	case 'u':
+		uflag = 1;
+		cflag = 0;
+		break;
 	default:
 		usage();
 	} ARGEND;
@@ -276,7 +287,12 @@ mkent(Entry *ent, char *path, int dostat, int follow)
 	ent->uid    = st.st_uid;
 	ent->gid    = st.st_gid;
 	ent->size   = st.st_size;
-	ent->t      = cflag ? st.st_ctime : st.st_mtime;
+	if (cflag)
+		ent->t = st.st_ctime;
+	else if (uflag)
+		ent->t = st.st_atime;
+	else
+		ent->t = st.st_mtime;
 	ent->ino    = st.st_ino;
 	if (S_ISLNK(ent->mode))
 		ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0;
@@ -314,12 +330,32 @@ output(Entry *ent, FILE *f)
 	struct passwd *pw;
 	char pwname[_SC_LOGIN_NAME_MAX];
 	char grname[_SC_LOGIN_NAME_MAX];
+	char *name = ent->name, *p, *n;
+	Rune r;
 
 	first = 0;
+
+	if (qflag) {
+		n = name = emalloc(utflen(ent->name) + 1);
+		strcpy(name, (p = ent->name));
+		while (*p) {
+			len = chartorune(&r, p);
+			if (isprintrune(r)) {
+				while (len) {
+					*n++ = *p++;
+					--len;
+				}
+			} else {
+				*n++ = '?';
+				p += len;
+			}
+		}
+		*n++ = '\0';
+	}
 	if (iflag)
 		fprintf(f, "%lu ", (unsigned long)ent->ino);
 	if (!lflag) {
-		fprintf(f, "%s%s\n", ent->name, indicator(ent->mode));
+		fprintf(f, "%s%s\n", name, indicator(ent->mode));
 		return;
 	}
 	if (S_ISREG(ent->mode))
@@ -376,14 +412,17 @@ output(Entry *ent, FILE *f)
 		fprintf(f, "%10s ", humansize((unsigned long)ent->size));
 	else
 		fprintf(f, "%10lu ", (unsigned long)ent->size);
-	fprintf(f, "%s %s%s", buf, ent->name, indicator(ent->mode));
+	fprintf(f, "%s %s%s", buf, name, indicator(ent->mode));
 	if (S_ISLNK(ent->mode)) {
-		if ((len = readlink(ent->name, buf, sizeof buf - 1)) < 0)
-			eprintf("readlink %s:", ent->name);
+		if ((len = readlink(name, buf, sizeof buf - 1)) < 0)
+			eprintf("readlink %s:", name);
 		buf[len] = '\0';
 		fprintf(f, " -> %s%s", buf, indicator(ent->tmode));
 	}
 	fputc('\n', f);
+
+	if (name != ent->name)
+		free(name);
 }
 
 static void columns(char *buf, size_t sz, int cnt)
-- 
2.3.0

From 63bb7fcd440909a936cfddb3e41d262af1d1e3ad Mon Sep 17 00:00:00 2001
From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com>
Date: Sun, 15 Feb 2015 14:38:01 +0000
Subject: [PATCH 4/4] ls: add fallback if ioctl does not work

---
 ls.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/ls.c b/ls.c
index 75cb418..5d3db3e 100644
--- a/ls.c
+++ b/ls.c
@@ -51,7 +51,7 @@ static int qflag = 0;
 static int uflag = 0;
 static int many;
 static int first = 1;
-static struct winsize ws;
+static int cols = 65;
 
 static void
 usage(void)
@@ -67,6 +67,7 @@ main(int argc, char *argv[])
 	FILE *mfp;
 	char *buf;
 	size_t size;
+	static struct winsize ws;
 
 	ARGBEGIN {
 	case '1':
@@ -111,7 +112,8 @@ main(int argc, char *argv[])
 		break;
 	case 'C':
 		if ((Cflag = isatty(fileno(stdout))))
-			ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+			if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws))
+				cols = ws.ws_col;
 		break;
 	case 'R':
 		Rflag = 1;
@@ -450,10 +452,10 @@ static void columns(char *buf, size_t sz, int cnt)
 				t += ll[j] - colw[k];
 				colw[k] = ll[j];
 			}
-			if (t > ws.ws_col - (l - 1) * 2)
+			if (t > cols - (l - 1) * 2)
 				break;
 		}
-		if (t <= ws.ws_col - (l - 1) * 2)
+		if (t <= cols - (l - 1) * 2)
 			break; /* fits */
 	}
 	if (l == 0)
-- 
2.3.0

Reply via email to