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