repair globbing $foo/ba*r/baz

This commit is contained in:
tg 2012-08-24 20:05:13 +00:00
parent 829cd0cc70
commit 2ed6e8998c
3 changed files with 48 additions and 45 deletions

83
edit.c
View File

@ -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
View File

@ -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
View File

@ -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