From 114f415ca15daaf3e491161885513812eba5b2fc Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 13 Oct 2020 02:20:49 -0500 Subject: Fix up ${x%y} ${x^y} ${x,y} and add tests. --- tests/sh.test | 10 ++++++++- toys/pending/sh.c | 64 ++++++++++++++++++++++++------------------------------- 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; iiv[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; iiv[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 (0arg!=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; -- cgit v1.2.3