about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--lr.c35
2 files changed, 32 insertions, 8 deletions
diff --git a/README.md b/README.md
index 99aa027..acf406a 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,9 @@ best features of `ls(1)`, `find(1)` and `du(1)`.
 
 ## Usage:
 
-	lr [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1dsx] [-U|-o ORD] [-t TEST]* PATH...
+	lr [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdsx] [-U|-o ORD] [-t TEST]* PATH...
 
-* `-0`: output filenames seperated by NUL bytes.
+* `-0`: output filenames seperated by NUL bytes (implies `-Q`).
 * `-F`: output filenames and an indicator of their file type (`*/=>@|`).
 * `-l`: long output ala `ls -l`.
 * `-f FMT`: custom formatting, see below.
@@ -16,6 +16,7 @@ best features of `ls(1)`, `find(1)` and `du(1)`.
 * `-H`: only follow symlinks on command line.
 * `-L`: follow all symlinks.
 * `-1`: don't go below one level of directories.
+* `-Q`: don't shell quote file names.
 * `-d`: don't enter directories.
 * `-s`: don't print leading `./`.
 * `-x`: don't enter other filesystems.
diff --git a/lr.c b/lr.c
index 22195cb..7c424a1 100644
--- a/lr.c
+++ b/lr.c
@@ -57,6 +57,7 @@ static int xflag;
 static int Uflag;
 static int lflag;
 static int sflag;
+static int Qflag;
 
 static char *argv0;
 static char *format;
@@ -769,6 +770,27 @@ print_mode(int mode)
 	                     : (mode & 00001 ? 'x' : '-'));
 }
 
+static void
+shquote(const char *s)
+{
+	if (Qflag || !strpbrk(s, "\001\002\003\004\005\006\007\010"
+	                         "\011\012\013\014\015\016\017\020"
+	                         "\021\022\023\024\025\026\027\030"
+	                         "\031\032\033\034\035\036\037\040"
+	                         "`^#*[]=|\\?${}()'\"<>&;\127")) {
+		printf("%s", s);
+		return;
+	}
+
+	putchar('\'');
+	for (; *s; s++)
+		if (*s == '\'')
+			printf("'\\''");
+		else
+			putchar(*s);
+	putchar('\'');
+}
+
 void
 print(const void *nodep, const VISIT which, const int depth)
 {
@@ -808,13 +830,13 @@ print(const void *nodep, const VISIT which, const int depth)
 						printf(" ");
 					break;
 				}
-				case 'p': printf("%s",
+				case 'p': shquote(
 					    sflag && strncmp(fi->fpath, "./", 2) == 0 ?
 					    fi->fpath+2 : fi->fpath);
 					break;
 				case 'l':
 					if (S_ISLNK(fi->sb.st_mode))
-						printf("%s", readlin(fi->fpath, ""));
+						shquote(readlin(fi->fpath, ""));
 					break;
 				case 'n': printf("%*ld", intlen(maxlinks), fi->sb.st_nlink); break;
 				case 'F':
@@ -833,7 +855,7 @@ print(const void *nodep, const VISIT which, const int depth)
 						putchar('*');
 					}
 					break;
-				case 'f': printf("%s", basenam(fi->fpath)); break;
+				case 'f': shquote(basenam(fi->fpath)); break;
 				case 'A':
 				case 'C':
 				case 'T': {
@@ -1035,14 +1057,15 @@ main(int argc, char *argv[])
 	ordering = default_ordering;
 	argv0 = argv[0];
 
-	while ((c = getopt(argc, argv, "01DFHLUdf:lo:st:x")) != -1)
+	while ((c = getopt(argc, argv, "01DFHLQUdf:lo:st:x")) != -1)
 		switch(c) {
-		case '0': format = zero_format; break;
+		case '0': format = zero_format; Qflag++; break;
 		case '1': expr = chain(expr, EXPR_AND, parse_expr("depth == 0 || prune")); break;
 		case 'D': Dflag++; break;
 		case 'F': format = type_format; break;
 		case 'H': Hflag++; break;
 		case 'L': Lflag++; break;
+		case 'Q': Qflag++; break;
 		case 'U': Uflag++; break;
 		case 'd': expr = chain(expr, EXPR_AND, parse_expr("type == d && prune || print")); break;
 		case 'f': format = optarg; break;
@@ -1052,7 +1075,7 @@ main(int argc, char *argv[])
 		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] [-1dsx] [-U|-o ORD] [-t TEST]* PATH...\n", argv0);
+			fprintf(stderr, "Usage: %s [-0|-F|-l|-f FMT] [-D] [-H|-L] [-1Qdsx] [-U|-o ORD] [-t TEST]* PATH...\n", argv0);
 			exit(2);
 		}