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:
65
eval.c
65
eval.c
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user