* Alexander Polakov <polac...@gmail.com> [110324 15:48]: > * Alexander Polakov <polac...@gmail.com> [110315 23:26]: > > * Federico G. Schwindt <fg...@lodoss.net> [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