repair globbing $foo/ba*r/baz
This commit is contained in:
		
							
								
								
									
										83
									
								
								edit.c
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								edit.c
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ | |||||||
|  |  | ||||||
| #ifndef MKSH_NO_CMDLINE_EDITING | #ifndef MKSH_NO_CMDLINE_EDITING | ||||||
|  |  | ||||||
| __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.247 2012/08/24 19:14:56 tg Exp $"); | __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.248 2012/08/24 20:05:11 tg Exp $"); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * in later versions we might use libtermcap for this, but since external |  * in later versions we might use libtermcap for this, but since external | ||||||
| @@ -61,8 +61,8 @@ static X_chars edchars; | |||||||
| #define XCF_FULLPATH	BIT(2)	/* command completion: store full path */ | #define XCF_FULLPATH	BIT(2)	/* command completion: store full path */ | ||||||
| #define XCF_COMMAND_FILE (XCF_COMMAND | XCF_FILE) | #define XCF_COMMAND_FILE (XCF_COMMAND | XCF_FILE) | ||||||
| #define XCF_IS_COMMAND	BIT(3)	/* return flag: is command */ | #define XCF_IS_COMMAND	BIT(3)	/* return flag: is command */ | ||||||
| #define XCF_IS_SUBGLOB	BIT(4)	/* return flag: is $FOO or ~foo substitution */ | #define XCF_IS_SUBST	BIT(4)	/* return flag: is $FOO substitution */ | ||||||
| #define XCF_IS_EXTGLOB	BIT(5)	/* return flag: is foo* expansion */ | #define XCF_IS_NOSPACE	BIT(5)	/* return flag: do not append a space */ | ||||||
|  |  | ||||||
| static char editmode; | static char editmode; | ||||||
| static int xx_cols;			/* for Emacs mode */ | static int xx_cols;			/* for Emacs mode */ | ||||||
| @@ -96,10 +96,10 @@ static int x_vi(char *, size_t); | |||||||
| #define x_putc(c)	shf_putc((c), shl_out) | #define x_putc(c)	shf_putc((c), shl_out) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| static int path_order_cmp(const void *aa, const void *bb); | static int path_order_cmp(const void *, const void *); | ||||||
| static void glob_table(const char *, XPtrV *, struct table *); | static void glob_table(const char *, XPtrV *, struct table *); | ||||||
| static void glob_path(int flags, const char *, XPtrV *, const char *); | static void glob_path(int, const char *, XPtrV *, const char *); | ||||||
| static int x_file_glob(int, char *, char ***); | static int x_file_glob(int *, char *, char ***); | ||||||
| static int x_command_glob(int, char *, char ***); | static int x_command_glob(int, char *, char ***); | ||||||
| static int x_locate_word(const char *, int, int, int *, bool *); | static int x_locate_word(const char *, int, int, int *, bool *); | ||||||
|  |  | ||||||
| @@ -347,9 +347,9 @@ x_glob_hlp_rem_qchar(char *cp) | |||||||
|  *	- returns number of matching strings |  *	- returns number of matching strings | ||||||
|  */ |  */ | ||||||
| static int | static int | ||||||
| x_file_glob(int flags MKSH_A_UNUSED, char *toglob, char ***wordsp) | x_file_glob(int *flagsp, char *toglob, char ***wordsp) | ||||||
| { | { | ||||||
| 	char **words; | 	char **words, *cp; | ||||||
| 	int nwords; | 	int nwords; | ||||||
| 	XPtrV w; | 	XPtrV w; | ||||||
| 	struct source *s, *sold; | 	struct source *s, *sold; | ||||||
| @@ -372,7 +372,16 @@ x_file_glob(int flags MKSH_A_UNUSED, char *toglob, char ***wordsp) | |||||||
| 	source = sold; | 	source = sold; | ||||||
| 	afree(s, ATEMP); | 	afree(s, ATEMP); | ||||||
| 	XPinit(w, 32); | 	XPinit(w, 32); | ||||||
| 	expand(yylval.cp, &w, DOGLOB | DOTILDE | DOMARKDIRS); | 	cp = yylval.cp; | ||||||
|  | 	while (*cp == CHAR || *cp == QCHAR) | ||||||
|  | 		cp += 2; | ||||||
|  | 	nwords = DOGLOB | DOTILDE | DOMARKDIRS; | ||||||
|  | 	if (*cp != EOS) { | ||||||
|  | 		/* probably a $FOO expansion */ | ||||||
|  | 		nwords = DOKEEPQUOTE; | ||||||
|  | 		*flagsp |= XCF_IS_SUBST | XCF_IS_NOSPACE; | ||||||
|  | 	} | ||||||
|  | 	expand(yylval.cp, &w, nwords); | ||||||
| 	XPput(w, NULL); | 	XPput(w, NULL); | ||||||
| 	words = (char **)XPclose(w); | 	words = (char **)XPclose(w); | ||||||
|  |  | ||||||
| @@ -581,7 +590,6 @@ x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp, | |||||||
|  |  | ||||||
| 	if (len >= 0) { | 	if (len >= 0) { | ||||||
| 		char *toglob, *s; | 		char *toglob, *s; | ||||||
| 		bool saw_dollar = false, saw_glob = false; |  | ||||||
|  |  | ||||||
| 		/* | 		/* | ||||||
| 		 * Given a string, copy it and possibly add a '*' to the end. | 		 * Given a string, copy it and possibly add a '*' to the end. | ||||||
| @@ -592,52 +600,40 @@ x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp, | |||||||
|  |  | ||||||
| 		/* | 		/* | ||||||
| 		 * If the pathname contains a wildcard (an unquoted '*', | 		 * If the pathname contains a wildcard (an unquoted '*', | ||||||
| 		 * '?', or '[') or parameter expansion ('$'), or a ~username | 		 * '?', or '[') or an extglob, then it is globbed based | ||||||
| 		 * with no trailing slash, then it is globbed based on that | 		 * on that value (i.e., without the appended '*'). | ||||||
| 		 * value (i.e., without the appended '*'). |  | ||||||
| 		 */ | 		 */ | ||||||
| 		for (s = toglob; *s; s++) { | 		for (s = toglob; *s; s++) { | ||||||
| 			if (*s == '\\' && s[1]) | 			if (*s == '\\' && s[1]) | ||||||
| 				s++; | 				s++; | ||||||
| 			else if (*s == '$') { | 			else if (*s == '?' || *s == '*' || *s == '[' || | ||||||
| 				/* | 			    /* also skip this for variable expansion */ | ||||||
| 				 * Do not append a space after the value | 			    *s == '$' || | ||||||
| 				 * if expanding a parameter substitution |  | ||||||
| 				 * as in: “cat $HOME/.ss↹” (LP: #710539) |  | ||||||
| 				 */ |  | ||||||
| 				saw_dollar = true; |  | ||||||
| 			} else if (*s == '?' || *s == '*' || *s == '[' || |  | ||||||
| 			    /* ?() *() +() @() !() but two already checked */ | 			    /* ?() *() +() @() !() but two already checked */ | ||||||
| 			    (s[1] == '(' /*)*/ && | 			    (s[1] == '(' /*)*/ && | ||||||
| 			    (*s == '+' || *s == '@' || *s == '!'))) { | 			    (*s == '+' || *s == '@' || *s == '!'))) { | ||||||
| 				/* just expand based on the extglob */ | 				/* just expand based on the extglob */ | ||||||
| 				saw_glob = true; | 				goto dont_add_glob; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if (saw_glob) { |  | ||||||
| 			/* | 		if (*toglob == '~' && !vstrchr(toglob, '/')) { | ||||||
| 			 * do not append a glob, we already have a | 			/* neither for '~foo' (but '~foo/bar') */ | ||||||
| 			 * glob or extglob; it works even if this is | 			*flagsp |= XCF_IS_NOSPACE; | ||||||
| 			 * a parameter expansion as we have a glob | 			goto dont_add_glob; | ||||||
| 			 */ |  | ||||||
| 			*flagsp |= XCF_IS_EXTGLOB; |  | ||||||
| 		} else if (saw_dollar || |  | ||||||
| 		    (*toglob == '~' && !vstrchr(toglob, '/'))) { |  | ||||||
| 			/* do not append a glob, nor later a space */ |  | ||||||
| 			*flagsp |= XCF_IS_SUBGLOB; |  | ||||||
| 		} else { |  | ||||||
| 			/* append a glob, this is not just a tilde */ |  | ||||||
| 			toglob[len] = '*'; |  | ||||||
| 			toglob[len + 1] = '\0'; |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		/* append a glob */ | ||||||
|  | 		toglob[len] = '*'; | ||||||
|  | 		toglob[len + 1] = '\0'; | ||||||
|  |  dont_add_glob: | ||||||
| 		/* | 		/* | ||||||
| 		 * Expand (glob) it now. | 		 * Expand (glob) it now. | ||||||
| 		 */ | 		 */ | ||||||
|  |  | ||||||
| 		nwords = is_command ? | 		nwords = is_command ? | ||||||
| 		    x_command_glob(*flagsp, toglob, &words) : | 		    x_command_glob(*flagsp, toglob, &words) : | ||||||
| 		    x_file_glob(*flagsp, toglob, &words); | 		    x_file_glob(flagsp, toglob, &words); | ||||||
| 		afree(toglob, ATEMP); | 		afree(toglob, ATEMP); | ||||||
| 	} | 	} | ||||||
| 	if (nwords == 0) { | 	if (nwords == 0) { | ||||||
| @@ -2752,7 +2748,7 @@ do_complete( | |||||||
| 	} | 	} | ||||||
| 	olen = end - start; | 	olen = end - start; | ||||||
| 	nlen = x_longest_prefix(nwords, words); | 	nlen = x_longest_prefix(nwords, words); | ||||||
| 	if (nwords == 1 || (flags & XCF_IS_SUBGLOB)) { | 	if (nwords == 1 || (flags & XCF_IS_SUBST)) { | ||||||
| 		/* | 		/* | ||||||
| 		 * always complete the expansion of parameter and | 		 * always complete the expansion of parameter and | ||||||
| 		 * homedir substitution as well as single matches | 		 * homedir substitution as well as single matches | ||||||
| @@ -2790,7 +2786,10 @@ do_complete( | |||||||
| 		xcp = xbuf + start; | 		xcp = xbuf + start; | ||||||
| 		xep -= olen; | 		xep -= olen; | ||||||
| 		memmove(xcp, xcp + olen, xep - xcp + 1); | 		memmove(xcp, xcp + olen, xep - xcp + 1); | ||||||
| 		x_escape(words[0], nlen, x_do_ins); | 		if (flags & XCF_IS_SUBST) | ||||||
|  | 			x_do_ins(words[0], nlen); | ||||||
|  | 		else | ||||||
|  | 			x_escape(words[0], nlen, x_do_ins); | ||||||
| 	} | 	} | ||||||
| 	x_adjust(); | 	x_adjust(); | ||||||
| 	/* | 	/* | ||||||
| @@ -2798,7 +2797,7 @@ do_complete( | |||||||
| 	 * and not a parameter or homedir substitution | 	 * and not a parameter or homedir substitution | ||||||
| 	 */ | 	 */ | ||||||
| 	if (nwords == 1 && words[0][nlen - 1] != '/' && | 	if (nwords == 1 && words[0][nlen - 1] != '/' && | ||||||
| 	    !(flags & XCF_IS_SUBGLOB)) { | 	    !(flags & XCF_IS_NOSPACE)) { | ||||||
| 		x_ins(" "); | 		x_ins(" "); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -5354,7 +5353,7 @@ complete_word(int cmd, int count) | |||||||
| 		 * and not a parameter or homedir substitution | 		 * and not a parameter or homedir substitution | ||||||
| 		 */ | 		 */ | ||||||
| 		if (match_len > 0 && match[match_len - 1] != '/' && | 		if (match_len > 0 && match[match_len - 1] != '/' && | ||||||
| 		    !(flags & XCF_IS_SUBGLOB)) | 		    !(flags & XCF_IS_NOSPACE)) | ||||||
| 			rval = putbuf(" ", 1, 0); | 			rval = putbuf(" ", 1, 0); | ||||||
| 	} | 	} | ||||||
| 	x_free_words(nwords, words); | 	x_free_words(nwords, words); | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								eval.c
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								eval.c
									
									
									
									
									
								
							| @@ -23,7 +23,7 @@ | |||||||
|  |  | ||||||
| #include "sh.h" | #include "sh.h" | ||||||
|  |  | ||||||
| __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.125 2012/08/24 19:02:57 tg Exp $"); | __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.126 2012/08/24 20:05:13 tg Exp $"); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * string expansion |  * string expansion | ||||||
| @@ -1009,9 +1009,12 @@ expand(const char *cp,	/* input word */ | |||||||
| 					} | 					} | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
| 			else | 			else { | ||||||
| 				/* undo temporary */ | 				/* undo temporary */ | ||||||
| 				quote &= ~2; | 				quote &= ~2; | ||||||
|  | 				if (f & DOKEEPQUOTE) | ||||||
|  | 					*dp++ = '\\'; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			if (make_magic) { | 			if (make_magic) { | ||||||
| 				make_magic = false; | 				make_magic = false; | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								sh.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								sh.h
									
									
									
									
									
								
							| @@ -157,7 +157,7 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef EXTERN | #ifdef EXTERN | ||||||
| __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.580 2012/08/24 19:09:10 tg Exp $"); | __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.581 2012/08/24 20:05:13 tg Exp $"); | ||||||
| #endif | #endif | ||||||
| #define MKSH_VERSION "R40 2012/08/17" | #define MKSH_VERSION "R40 2012/08/17" | ||||||
|  |  | ||||||
| @@ -1343,6 +1343,7 @@ struct ioword { | |||||||
| #define DOTEMP	BIT(8)		/* dito: in word part of ${..[%#=?]..} */ | #define DOTEMP	BIT(8)		/* dito: in word part of ${..[%#=?]..} */ | ||||||
| #define DOVACHECK BIT(9)	/* var assign check (for typeset, set, etc) */ | #define DOVACHECK BIT(9)	/* var assign check (for typeset, set, etc) */ | ||||||
| #define DOMARKDIRS BIT(10)	/* force markdirs behaviour */ | #define DOMARKDIRS BIT(10)	/* force markdirs behaviour */ | ||||||
|  | #define DOKEEPQUOTE BIT(11)	/* internal use by globbing code */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * The arguments of [[ .. ]] expressions are kept in t->args[] and flags |  * The arguments of [[ .. ]] expressions are kept in t->args[] and flags | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user