repair globbing $foo/ba*r/baz
This commit is contained in:
parent
829cd0cc70
commit
2ed6e8998c
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) {
|
|
||||||
/*
|
|
||||||
* do not append a glob, we already have a
|
|
||||||
* glob or extglob; it works even if this is
|
|
||||||
* a parameter expansion as we have a 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';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (*toglob == '~' && !vstrchr(toglob, '/')) {
|
||||||
|
/* neither for '~foo' (but '~foo/bar') */
|
||||||
|
*flagsp |= XCF_IS_NOSPACE;
|
||||||
|
goto dont_add_glob;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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,6 +2786,9 @@ 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);
|
||||||
|
if (flags & XCF_IS_SUBST)
|
||||||
|
x_do_ins(words[0], nlen);
|
||||||
|
else
|
||||||
x_escape(words[0], nlen, x_do_ins);
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user