Subject: Re: ksh: escape spaces when expanding
To: None <tech-userlevel@netbsd.org>
From: Jaromir Dolecek <dolecek@ics.muni.cz>
List: tech-userlevel
Date: 09/22/1999 18:51:27
Hi,
so I added escaping of (hopefully) all shell special chars. The only
change is in the vi.c:complete_word(). The " & ' quoting is still
not handled at all.

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/22 16:52:44
@@ -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/22 16:52:44
@@ -1996,7 +1996,7 @@ complete_word(command, count)
 	int start, end;
 	char **words;
 	char *match;
-	int match_len;
+	int match_len, len, add;
 	int is_unique;
 	int is_command;
 
@@ -2069,16 +2069,37 @@ 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) {
+
+	/* escape all shell-sensitive characters in the word */
+	for (add = 0, len = match_len; len - add > 0; add++) {
+		if (strchr("\\$(){}*&;|<> \t\"'", match[add])) {
+			if (putbuf(match, add, 0) != 0) {
+				rval = -1;
+				break;
+			}
+
+			putbuf("\\", 1, 0);
+			putbuf(&match[add], 1, 0);
+
+			add++;
+			len -= add;
+			match += add;
+			add = -1; /* after the increment it will go to 0 */
+		}
+	}
+	if (len > 0) {
+		rval = putbuf(match, len, 0);
+		match += len;
+	}
+
+	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