Subject: ksh: escape spaces when expanding
To: None <tech-userlevel@netbsd.org>
From: Jaromir Dolecek <dolecek@ics.muni.cz>
List: tech-userlevel
Date: 09/21/1999 16:37:57
Hi,
what always bothered me that pdksh's tab expanding doesn't really play well 
with filenames containing spaces. While playing with CygWin, I
found out that bash uses nice hack - it just escapes the space with
a backslash. So I implemented the same for ksh. 

Note that only spaces are currently supported. Adding e.g. tab would
not be hard, but I haven't came across any filename containing it yet.
If nobody would complain, I'll commit the changes shortly.

Please keep me on CC, I'm not subscribed on tech-userlevel@NetBSD.org.

Index: edit.c
===================================================================
RCS file: /cvsroot/basesrc/bin/ksh/edit.c,v
retrieving revision 1.4
diff -u -p -r1.4 edit.c
--- edit.c	1998/11/04 18:27:21	1.4
+++ edit.c	1999/09/21 14:29:10
@@ -537,7 +537,7 @@ x_file_glob(flags, str, slen, wordsp)
 {
 	char *toglob;
 	char **words;
-	int nwords;
+	int nwords, i, idx, escaping;
 	XPtrV w;
 	struct source *s, *sold;
 
@@ -546,6 +546,20 @@ x_file_glob(flags, str, slen, wordsp)
 
 	toglob = add_glob(str, slen);
 
+	/* remove all escaping backward slashes */
+	escaping = 0;
+	for(i = 0, idx = 0; toglob[i]; i++) {
+		if (toglob[i] == '\\' && !escaping) {
+			escaping = 1;
+			continue;
+		}
+
+		toglob[idx] = toglob[i];
+		idx++;
+		if (escaping) escaping = 0;
+	}
+	toglob[idx] = '\0';
+
 	/*
 	 * Convert "foo*" (toglob) to an array of strings (words)
 	 */
@@ -740,11 +754,14 @@ x_locate_word(buf, buflen, pos, startp, 
 	/* Keep going backwards to start of word (has effect of allowing
 	 * one blank after the end of a word)
 	 */
-	for (; start > 0 && IS_WORDC(buf[start - 1]); start--)
+	for (; (start > 0 && IS_WORDC(buf[start - 1]))
+		|| (start > 1 && buf[start-2] == '\\'); start--)
 		;
 	/* Go forwards to end of word */
-	for (end = start; end < buflen && IS_WORDC(buf[end]); end++)
-		;
+	for (end = start; end < buflen && IS_WORDC(buf[end]); end++) {
+		if (buf[end] == '\\' && (end+1) < buflen && buf[end+1] == ' ')
+			end++;
+	}
 
 	if (is_commandp) {
 		int iscmd;
Index: vi.c
===================================================================
RCS file: /cvsroot/basesrc/bin/ksh/vi.c,v
retrieving revision 1.3
diff -u -p -r1.3 vi.c
--- vi.c	1998/11/04 18:27:21	1.3
+++ vi.c	1999/09/21 14:29:11
@@ -1995,8 +1995,8 @@ complete_word(command, count)
 	int nwords;
 	int start, end;
 	char **words;
-	char *match;
-	int match_len;
+	char *match, *spp;
+	int match_len, len, add;
 	int is_unique;
 	int is_command;
 
@@ -2069,16 +2069,30 @@ complete_word(command, count)
 	buf = save_edstate(es);
 	del_range(start, end);
 	es->cursor = start;
-	if (putbuf(match, match_len, 0) != 0)
-		rval = -1;
-	else if (is_unique) {
+	len = match_len;
+	do {
+		spp = memchr(match, ' ', len);
+		add = (spp) ? spp - match : len;
+		if (putbuf(match, add, 0) != 0) {
+			rval = -1;
+			break;
+		}
+		if (spp) {
+			add++;
+			putbuf("\\ ", 2, 0);
+		}
+		match += add;
+		len -= add;
+	} while(spp);
+
+	if (rval == 0 && is_unique) {
 		/* If exact match, don't undo.  Allows directory completions
 		 * to be used (ie, complete the next portion of the path).
 		 */
 		expanded = NONE;
 
 		/* If not a directory, add a space to the end... */
-		if (match_len > 0 && !ISDIRSEP(match[match_len - 1]))
+		if (match_len > 0 && !ISDIRSEP(match[-1]))
 			rval = putbuf(space, 1, 0);
 	}
 	x_free_words(nwords, words);
-- 
Jaromir Dolecek <jdolecek@NetBSD.org>      http://www.ics.muni.cz/~dolecek/
"The only way how to get rid temptation is to yield to it." -- Oscar Wilde