summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--lr.c32
2 files changed, 30 insertions, 6 deletions
diff --git a/README.md b/README.md
index d5ebc2d..7cb19a6 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ Over ls:
 
 ## Usage:
 
-	lr [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdsx] [-U|-o ORD] [-t TEST]* PATH...
+	lr [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdhsx] [-U|-o ORD] [-t TEST]* PATH...
 
 * `-0`: output filenames seperated by NUL bytes (implies `-Q`).
 * `-F`: output filenames and an indicator of their file type (`*/=>@|`).
@@ -45,6 +45,7 @@ Over ls:
 * `-1`: don't go below one level of directories.
 * `-Q`: don't shell quote file names.
 * `-d`: don't enter directories.
+* `-h`: print human readable size for `-l` (also `%s`).
 * `-s`: don't print leading `./`.
 * `-x`: don't enter other filesystems.
 * `-U`: don't sort results.
@@ -56,6 +57,7 @@ Over ls:
 * `\a`, `\b`, `\f`, `\n`, `\r`, `\v`, `\0` as in C.
 * `%%`: plain `%`.
 * `%s`: file size in bytes.
+* `%S`: file size, with human readable unit.
 * `%b`: file size in 512-byte blocks.
 * `%k`: file size in 1024-byte blocks.
 * `%d`: path depth.
diff --git a/lr.c b/lr.c
index 30be4d4..a75b739 100644
--- a/lr.c
+++ b/lr.c
@@ -53,11 +53,12 @@
 static int Dflag;
 static int Hflag;
 static int Lflag;
-static int xflag;
+static int Qflag;
 static int Uflag;
+static int hflag;
 static int lflag;
 static int sflag;
-static int Qflag;
+static int xflag;
 
 static char *argv0;
 static char *format;
@@ -787,6 +788,23 @@ print_mode(int mode)
 }
 
 static void
+print_human(intmax_t i)
+{
+	double d = i;
+	const char *u = "\0\0K\0M\0G\0T\0P\0E\0Z\0Y\0";
+	while (d >= 1024) {
+		u += 2;
+		d /= 1024.0;
+	}
+	if (!*u)
+		printf("%5.0f", d);
+	else if (d < 10.0)
+		printf("%4.1f%s", d, u);
+	else
+		printf("%4.0f%s", d, u);
+}
+
+static void
 shquote(const char *s)
 {
 	if (Qflag || !strpbrk(s, "\001\002\003\004\005\006\007\010"
@@ -834,7 +852,10 @@ print(const void *nodep, const VISIT which, const int depth)
 			} else if (*s == '%') {
 				switch (*++s) {
 				case '%': putchar('%'); break;
-				case 's': printf("%*jd", intlen(maxsize), (intmax_t)fi->sb.st_size); break;
+				case 's': if (!hflag) {
+						printf("%*jd", intlen(maxsize), (intmax_t)fi->sb.st_size); break;
+					} else /* FALLTHRU */
+				case 'S': print_human((intmax_t)fi->sb.st_size); break;
 				case 'b': printf("%jd", (intmax_t)fi->sb.st_blocks); break;
 				case 'k': printf("%jd", (intmax_t)fi->sb.st_blocks / 2); break;
 				case 'd': printf("%d", fi->depth); break;
@@ -1073,7 +1094,7 @@ main(int argc, char *argv[])
 	ordering = default_ordering;
 	argv0 = argv[0];
 
-	while ((c = getopt(argc, argv, "01DFHLQUdf:lo:st:x")) != -1)
+	while ((c = getopt(argc, argv, "01DFHLQUdf:lho:st:x")) != -1)
 		switch(c) {
 		case '0': format = zero_format; Qflag++; break;
 		case '1': expr = chain(expr, EXPR_AND, parse_expr("depth == 0 || prune")); break;
@@ -1085,13 +1106,14 @@ main(int argc, char *argv[])
 		case 'U': Uflag++; break;
 		case 'd': expr = chain(expr, EXPR_AND, parse_expr("type == d && prune || print")); break;
 		case 'f': format = optarg; break;
+		case 'h': hflag++; break;
 		case 'l': lflag++; format = long_format; break;
 		case 'o': ordering = optarg; break;
 		case 's': sflag++; break;
 		case 't': expr = chain(expr, EXPR_AND, parse_expr(optarg)); break;
 		case 'x': xflag++; break;
 		default:
-			fprintf(stderr, "Usage: %s [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdsx] [-U|-o ORD] [-t TEST]* PATH...\n", argv0);
+			fprintf(stderr, "Usage: %s [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdhsx] [-U|-o ORD] [-t TEST]* PATH...\n", argv0);
 			exit(2);
 		}