aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2020-10-13 02:20:49 -0500
committerRob Landley <rob@landley.net>2020-10-13 02:20:49 -0500
commit114f415ca15daaf3e491161885513812eba5b2fc (patch)
tree32429ae8d966a9c2f8a62c97bbaf22bfc5ea63cc
parentb61876564c2977a2d776b26dc7a2dcf28ed00bb7 (diff)
downloadtoybox-114f415ca15daaf3e491161885513812eba5b2fc.tar.gz
Fix up ${x%y} ${x^y} ${x,y} and add tests.
-rw-r--r--tests/sh.test10
-rw-r--r--toys/pending/sh.c64
2 files changed, 37 insertions, 37 deletions
diff --git a/tests/sh.test b/tests/sh.test
index b095bb95..516e0c82 100644
--- a/tests/sh.test
+++ b/tests/sh.test
@@ -9,7 +9,7 @@
# Looked like a prefix but wasn't: three chars (@ # -) are both paremeter name
# and slice operator. When immediately followed by } it's parameter, otherwise
-# otherwise we did NOT have a prefix and it's an operator.
+# we did NOT have a prefix and it's an operator.
#
# ${#-} ${#-abc}
# ${##} ${##0}
@@ -173,6 +173,14 @@ testing '${x#prefix}' 'x=abcde; echo ${x#abc}' 'de\n' '' ''
testing '${x#short} ${x##long}' 'x=banana; echo ${x#b*n} ${x##b*n}' \
'ana a\n' '' ''
toyonly testing '${x#utf8}' 'x=aそcde; echo ${x##a?c}' 'de\n' '' ''
+testing '${x%y}' 'x=potato; echo ${x%t*o} ${x%%t*o}' 'pota po\n' '' ''
+testing '${x^y}' 'x=aaaaa; echo ${x^a}' 'Aaaaa\n' '' ''
+testing '${x^^y}' 'x=abccdec; echo ${x^^c}; x=abcdec; echo ${x^^c}' \
+ 'abCCdeC\nabCdeC\n' '' ''
+testing '${x,y}' 'x=BBB; echo ${x,B}' 'bBB\n' '' ''
+testing '${x,,y}' 'x=POTATO; echo ${x,,} ${x,,?} ${x,,*} ${x,,T}' \
+ 'potato potato potato POtAtO\n' '' ''
+
mkdir -p abc/def/ghi
touch www
testing 'wildcards' 'echo w[v-x]w w[x-v]w abc/*/ghi' \
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index d6aaaff2..90a6c5af 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -786,10 +786,8 @@ int getutf8(char *s, int len, int *cc)
#define WILD_SHORT 1 // else longest match
#define WILD_CASE 2 // case insensitive
#define WILD_ANY 4 // advance through pattern instead of str
-#define WILD_SCAN 8 // search from beginning for start/end
-#define WILD_BACK 16 // search from end
// Returns length of str matched by pattern, or -1 if not all pattern consumed
-static int wildcard_match(char *str, int len, char *pattern, int plen,
+static int wildcard_matchlen(char *str, int len, char *pattern, int plen,
struct sh_arg *deck, int flags)
{
struct sh_arg ant = {0}; // stack: of str offsets
@@ -882,26 +880,12 @@ static int wildcard_match(char *str, int len, char *pattern, int plen,
return best;
}
-static int wildcard_scan(char *s, char *pattern, struct sh_arg *deck, int flags)
+static int wildcard_match(char *s, char *p, struct sh_arg *deck, int flags)
{
- int ll = strlen(s), bb = flags&WILD_BACK, ii = bb ? ll-1 : 0,
- pp = strlen(pattern), rc, best = -1;
-
- for (;;) {
- rc = wildcard_match(s+ii, ll-ii, pattern, pp, deck, flags);
- if (!(flags&(WILD_BACK|WILD_SCAN))) return rc;
- if (rc>0 && !s[rc]) {
- if ((flags&(WILD_SHORT|WILD_BACK))!=WILD_BACK) return rc;
- best = ii;
- }
- if (bb) {
- if (!ii--) return best;
- } else {
- if (!--ll) return -1;
- s++;
- }
- }
+ return wildcard_matchlen(s, strlen(s), p, strlen(p), deck, flags);
}
+
+
// TODO: test that * matches ""
// skip to next slash in wildcard path, passing count active ranges.
@@ -969,8 +953,8 @@ int do_wildcard_files(struct dirtree *node)
ant.c = ll-lvl;
ant.v = TT.wcdeck->v+lvl;
for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] -= pattern-TT.wcpat;
- rc = wildcard_match(node->name, strlen(node->name), pattern, patend-pattern,
- &ant, 0);
+ rc = wildcard_matchlen(node->name, strlen(node->name), pattern,
+ patend-pattern, &ant, 0);
for (ii = 0; ii<ant.c; ii++) TT.wcdeck->v[lvl+ii] += pattern-TT.wcpat;
// Return failure or save exact match.
@@ -1412,10 +1396,12 @@ barf:
if (strchr("^,", *slice)) {
for (ss = ifs; *ss; ss += dd) {
dd = getutf8(ss, 4, &jj);
- if (0<wildcard_scan(ss, s, &wild, WILD_ANY)) {
+ if (!*s || 0<wildcard_match(ss, s, &wild, WILD_ANY)) {
ll = ((*slice=='^') ? towupper : towlower)(jj);
// Of COURSE unicode case switch can change utf8 encoding length
+ // Lower case U+0069 becomes u+0130 in turkish.
+ // Greek U+0390 becomes 3 characters TODO test this
if (ll != jj) {
yy = ss-ifs;
if (!*delete || (*delete)->arg!=ifs)
@@ -1429,22 +1415,28 @@ barf:
}
}
if (!xx) break;
- ss += dd;
- yy -= dd;
}
- } else if (0<(dd = wildcard_scan(ifs, s, &wild,
- WILD_SHORT*!xx+WILD_BACK*(*slice=='%'))))
- {
- if (*slice == '#') ifs += dd;
- else if (ifs[dd]) {
- if (*delete && (*delete)->arg==ifs) ifs[dd] = 0;
- else push_arg(delete, ifs = xstrndup(ifs, dd));
+ } else if (*slice=='#') {
+ if (0<(dd = wildcard_match(ifs, s, &wild, WILD_SHORT*!xx)))
+ ifs += dd;
+ } else if (*slice=='%') {
+ for (ss = ifs+strlen(ifs), yy = -1; ss>=ifs; ss--) {
+ if (0<(dd = wildcard_match(ss, s, &wild, WILD_SHORT*xx))&&!ss[dd])
+ {
+ yy = ss-ifs;
+ if (!xx) break;
+ }
+ }
+
+ if (yy != -1) {
+ if (*delete && (*delete)->arg==ifs) ifs[yy] = 0;
+ else push_arg(delete, ifs = xstrndup(ifs, yy));
}
}
free(s);
free(wild.v);
-// } else if (*slice=='/') {
-//murgle
+// } else if (*slice=='/') {
+// } else if (*slice=='@') {
// TODO test x can be @ or *
} else {
@@ -2866,7 +2858,7 @@ dprintf(2, "TODO skipped init for((;;)), need math parser\n");
if ((err = expand_arg_nobrace(&arg, *vv++, NO_SPLIT, &blk->fdelete,
&arg2))) break;
s = arg.c ? *arg.v : "";
- match = wildcard_scan(blk->fvar, s, &arg2, 0);
+ match = wildcard_match(blk->fvar, s, &arg2, 0);
if (match>=0 && !s[match]) break;
else if (**vv++ == ')') {
vv = 0;