implement $KSH_MATCH and, to make it usable, ${foo@/bar/baz};

add a real-life example (for slagtc’s programmable tab completion)
to the manpage
This commit is contained in:
tg
2016-08-01 21:38:07 +00:00
parent 8f135b3904
commit 757e25fb21
8 changed files with 197 additions and 34 deletions

65
eval.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.191 2016/07/25 00:04:41 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.192 2016/08/01 21:38:01 tg Exp $");
/*
* string expansion
@ -186,7 +186,7 @@ evalonestr(const char *cp, int f)
rv = (char *) *XPptrv(w);
break;
default:
rv = evalstr(cp, f&~DOGLOB);
rv = evalstr(cp, f & ~DOGLOB);
break;
}
XPfree(w);
@ -478,12 +478,14 @@ expand(
strndupx(x.str, beg, num, ATEMP);
goto do_CSUBST;
}
case 0x100 | '/':
case '/': {
char *s, *p, *d, *sbeg, *end;
char *pat, *rrep;
char *pat = NULL, *rrep = null;
char fpat = 0, *tpat1, *tpat2;
char *ws, *wpat, *wrep;
s = wdcopy(sp, ATEMP);
s = ws = wdcopy(sp, ATEMP);
p = s + (wdscan(sp, ADELIM) - sp);
d = s + (wdscan(sp, CSUBST) - sp);
p[-2] = EOS;
@ -492,16 +494,24 @@ expand(
else
d[-2] = EOS;
sp += (d ? d : p) - s - 1;
if (!(stype & 0x80) &&
if (!(stype & 0x180) &&
s[0] == CHAR &&
(s[1] == '#' || s[1] == '%'))
fpat = s[1];
pat = evalstr(s + (fpat ? 2 : 0),
DOTILDE | DOSCALAR | DOPAT);
rrep = d ? evalstr(p,
DOTILDE | DOSCALAR) : null;
afree(s, ATEMP);
wpat = s + (fpat ? 2 : 0);
wrep = d ? p : NULL;
if (!(stype & 0x100)) {
rrep = wrep ? evalstr(wrep,
DOTILDE | DOSCALAR) :
null;
}
/* prepare string on which to work */
strdupx(s, str_val(st->var), ATEMP);
sbeg = s;
again_search:
pat = evalstr(wpat,
DOTILDE | DOSCALAR | DOPAT);
/* check for special cases */
if (!*pat && !fpat) {
/*
@ -510,19 +520,15 @@ expand(
*/
goto no_repl;
}
if ((stype & 0x80) &&
if ((stype & 0x180) &&
gmatchx(null, pat, false)) {
/*
* pattern matches empty
* string => don't loop
*/
stype &= ~0x80;
stype &= ~0x180;
}
/* prepare string on which to work */
strdupx(s, str_val(st->var), ATEMP);
sbeg = s;
/* first see if we have any match at all */
if (fpat == '#') {
/* anchor at the beginning */
@ -567,13 +573,27 @@ expand(
break;
p--;
}
strndupx(end, sbeg, p - sbeg, ATEMP);
record_match(end);
afree(end, ATEMP);
if (stype & 0x100) {
if (rrep != null)
afree(rrep, ATEMP);
rrep = wrep ? evalstr(wrep,
DOTILDE | DOSCALAR) :
null;
}
strndupx(end, s, sbeg - s, ATEMP);
d = shf_smprintf(Tf_sss, end, rrep, p);
afree(end, ATEMP);
sbeg = d + (sbeg - s) + strlen(rrep);
afree(s, ATEMP);
s = d;
if (stype & 0x80)
if (stype & 0x100) {
afree(tpat1, ATEMP);
afree(pat, ATEMP);
goto again_search;
} else if (stype & 0x80)
goto again_repl;
end_repl:
afree(tpat1, ATEMP);
@ -582,6 +602,7 @@ expand(
afree(pat, ATEMP);
if (rrep != null)
afree(rrep, ATEMP);
afree(ws, ATEMP);
goto do_CSUBST;
}
case '#':
@ -733,6 +754,7 @@ expand(
debunk(dp, dp, strlen(dp) + 1));
break;
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1207,6 +1229,7 @@ varsub(Expand *xp, const char *sp, const char *word,
case '#':
case '?':
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1237,6 +1260,7 @@ varsub(Expand *xp, const char *sp, const char *word,
case '#':
case '?':
case '0':
case 0x100 | '/':
case '/':
case 0x100 | '#':
case 0x100 | 'Q':
@ -1277,13 +1301,13 @@ varsub(Expand *xp, const char *sp, const char *word,
c = stype & 0x7F;
/* test the compiler's code generator */
if (((stype < 0x100) && (ctype(c, C_SUBOP2) || c == '/' ||
if (((stype < 0x100) && (ctype(c, C_SUBOP2) ||
(((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
(state != XARG || (ifs0 || xp->split ?
(xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
c == '=' || c == '-' || c == '?' : c == '+'))) ||
stype == (0x80 | '0') || stype == (0x100 | '#') ||
stype == (0x100 | 'Q'))
stype == (0x100 | 'Q') || (stype & 0x7F) == '/')
/* expand word instead of variable value */
state = XBASE;
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
@ -1420,6 +1444,7 @@ trimsub(char *str, char *pat, int how)
for (p = str; p <= end; p += utf_ptradj(p)) {
c = *p; *p = '\0';
if (gmatchx(str, pat, false)) {
record_match(str);
*p = c;
return (p);
}
@ -1431,6 +1456,7 @@ trimsub(char *str, char *pat, int how)
for (p = end; p >= str; p--) {
c = *p; *p = '\0';
if (gmatchx(str, pat, false)) {
record_match(str);
*p = c;
return (p);
}
@ -1458,6 +1484,7 @@ trimsub(char *str, char *pat, int how)
for (p = str; p <= end; p++)
if (gmatchx(p, pat, false)) {
trimsub_match:
record_match(p);
strndupx(end, str, p - str, ATEMP);
return (end);
}