* Alexander Polakov <[email protected]> [110324 15:48]:
> * Alexander Polakov <[email protected]> [110315 23:26]:
> > * Federico G. Schwindt <[email protected]> [110315 17:38]:
> > > > I think I'm slightly confused as to you'd like fixed - do you mean that
> > > > one shouldn't need to escape a '[' if it's the first character? (note
> > > > that /bin/[ exists). Else, can you clarify a bit more? Thanks!
> > >
> > > correct, shouldn't need to escape a '[' if it's teh first character.
> > > i do know of [, but command and file completion are two different
> > > things. see
> > > bash too.
> >
> > I don't want to be defensive, but hey, how is bash relevant? [ is treated as
> > a globbing character, you know. Is it first character or not, ksh doesn't
> > care,
> > it just tries to expand it.
> >
> > Oh well, you can try expanding it and then - if it failed - escape it and
> > try again, like in the patch below. Bear in mind I didn't give it much
> > thought, because I have a feeling it's not a good idea.
>
> And just for the archives, a patch that really works as advertised
> (and using it for some time I feel like it *is* a good idea).
New version using toglob[] instead of str[] fixes double-escaping bug.
Tested by LEVAI Daniel and me.
Does anyone care? Woule be cool to have initial diff committed at least.
Index: bin/ksh/edit.c
===================================================================
RCS file: /cvs/src/bin/ksh/edit.c,v
retrieving revision 1.34
diff -u -r1.34 edit.c
--- bin/ksh/edit.c 20 May 2010 01:13:07 -0000 1.34
+++ bin/ksh/edit.c 5 Apr 2011 10:12:19 -0000
@@ -18,13 +18,14 @@
#include <libgen.h>
#include <sys/stat.h>
+#define ESCAPEDCHARS "\"#$&'()*;<=>?[\\`{|}"
static void x_sigwinch(int);
static volatile sig_atomic_t got_sigwinch;
static void check_sigwinch(void);
-static int x_file_glob(int, const char *, int, char ***);
-static int x_command_glob(int, const char *, int, char ***);
+static int x_file_glob(int, const char *, int, char ***, int);
+static int x_command_glob(int, const char *, int, char ***, int);
static int x_locate_word(const char *, int, int, int *, int *);
@@ -344,10 +345,11 @@
* - returns number of matching strings
*/
static int
-x_file_glob(int flags, const char *str, int slen, char ***wordsp)
+x_file_glob(int flags, const char *str, int slen, char ***wordsp, int
canrecurse)
{
char *toglob;
char **words;
+ char *estr;
int nwords, i, idx, escaping;
XPtrV w;
struct source *s, *sold;
@@ -365,6 +367,11 @@
continue;
}
+ /* specially escape escaped [ or $ or ` for globbing */
+ if (escaping && (toglob[i] == '[' ||
+ toglob[i] == '$' || toglob[i] == '`'))
+ toglob[idx++] = QCHAR;
+
toglob[idx] = toglob[i];
idx++;
if (escaping) escaping = 0;
@@ -378,7 +385,7 @@
s = pushs(SWSTR, ATEMP);
s->start = s->str = toglob;
source = s;
- if (yylex(ONEWORD) != LWORD) {
+ if (yylex(ONEWORD|LQCHAR) != LWORD) {
source = sold;
internal_errorf(0, "fileglob: substitute error");
return 0;
@@ -409,6 +416,24 @@
nwords = 0;
}
}
+
+ /* Globbing failed, do escaping and try again. */
+ if (!nwords && !words && canrecurse) {
+ slen = idx;
+ estr = alloc(2 * slen + 1, ATEMP);
+ idx = 0;
+ for(i = 0; i < slen; i++) {
+ if (strchr(ESCAPEDCHARS, toglob[i]))
+ estr[idx++] = '\\';
+ estr[idx++] = toglob[i];
+ }
+ estr[idx] = '\0';
+ nwords = x_file_glob(flags, estr, idx, wordsp, !canrecurse);
+ afree(estr, ATEMP);
+ afree(toglob, ATEMP);
+ return nwords;
+ }
+
afree(toglob, ATEMP);
if (nwords) {
@@ -443,7 +468,7 @@
}
static int
-x_command_glob(int flags, const char *str, int slen, char ***wordsp)
+x_command_glob(int flags, const char *str, int slen, char ***wordsp, int
canrecurse)
{
char *toglob;
char *pat;
@@ -607,7 +632,7 @@
return 0;
nwords = (is_command ? x_command_glob : x_file_glob)(flags,
- buf + *startp, len, &words);
+ buf + *startp, len, &words, 1);
if (nwords == 0) {
*wordsp = (char **) 0;
return 0;
@@ -821,7 +846,7 @@
int rval = 0;
for (add = 0, wlen = len; wlen - add > 0; add++) {
- if (strchr("\"#$&'()*;<=>?[\\]`{|}", s[add]) ||
+ if (strchr(ESCAPEDCHARS, s[add]) ||
strchr(ifs, s[add])) {
if (putbuf_func(s, add) != 0) {
rval = -1;
Index: bin/ksh/lex.c
===================================================================
RCS file: /cvs/src/bin/ksh/lex.c,v
retrieving revision 1.45
diff -u -r1.45 lex.c
--- bin/ksh/lex.c 9 Mar 2011 09:30:39 -0000 1.45
+++ bin/ksh/lex.c 5 Apr 2011 10:12:19 -0000
@@ -411,6 +411,13 @@
}
}
break;
+ case QCHAR:
+ if (cf & LQCHAR) {
+ *wp++ = QCHAR;
+ *wp++ = getsc();
+ break;
+ }
+ /* FALLTHROUGH */
default:
*wp++ = CHAR, *wp++ = c;
}
Index: bin/ksh/lex.h
===================================================================
RCS file: /cvs/src/bin/ksh/lex.h,v
retrieving revision 1.11
diff -u -r1.11 lex.h
--- bin/ksh/lex.h 29 May 2006 18:22:24 -0000 1.11
+++ bin/ksh/lex.h 5 Apr 2011 10:12:19 -0000
@@ -113,6 +113,7 @@
#define CMDWORD BIT(8) /* parsing simple command (alias related) */
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define HEREDOC BIT(10) /* parsing heredoc */
+#define LQCHAR BIT(11) /* source string contains QCHAR */
#define HERES 10 /* max << in line */
--
Alexander Polakov | plhk.ru