diff options
author | Denys Vlasenko | 2018-01-07 01:19:08 +0100 |
---|---|---|
committer | Denys Vlasenko | 2018-01-07 01:19:08 +0100 |
commit | 6f4a785bd1bd0e6973b5c27b34b86655b1d7a602 (patch) | |
tree | f7c5acf0f2f844883e5e183b45d85ba0ee5471df | |
parent | 7367a949a6a81d71d524f0635a212371120df4e0 (diff) | |
download | busybox-6f4a785bd1bd0e6973b5c27b34b86655b1d7a602.zip busybox-6f4a785bd1bd0e6973b5c27b34b86655b1d7a602.tar.gz |
awk: fix 'delete array[var--]' decrementing var twice
function old new delta
evaluate 3395 3390 -5
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | editors/awk.c | 54 | ||||
-rwxr-xr-x | testsuite/awk.tests | 19 |
2 files changed, 50 insertions, 23 deletions
diff --git a/editors/awk.c b/editors/awk.c index d40c781..8f523ea 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -2514,6 +2514,32 @@ static var *evaluate(node *op, var *res) op1 = op->l.n; debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); + /* "delete" is special: + * "delete array[var--]" must evaluate index expr only once, + * must not evaluate it in "execute inevitable things" part. + */ + if (XC(opinfo & OPCLSMASK) == XC(OC_DELETE)) { + uint32_t info = op1->info & OPCLSMASK; + var *v; + + debug_printf_eval("DELETE\n"); + if (info == OC_VAR) { + v = op1->l.v; + } else if (info == OC_FNARG) { + v = &fnargs[op1->l.aidx]; + } else { + syntax_error(EMSG_NOT_ARRAY); + } + if (op1->r.n) { /* array ref? */ + const char *s; + s = getvar_s(evaluate(op1->r.n, v1)); + hash_remove(iamarray(v), s); + } else { + clear_array(iamarray(v)); + } + goto next; + } + /* execute inevitable things */ if (opinfo & OF_RES1) L.v = evaluate(op1, v1); @@ -2621,28 +2647,7 @@ static var *evaluate(node *op, var *res) break; } - case XC( OC_DELETE ): { - uint32_t info = op1->info & OPCLSMASK; - var *v; - - if (info == OC_VAR) { - v = op1->l.v; - } else if (info == OC_FNARG) { - v = &fnargs[op1->l.aidx]; - } else { - syntax_error(EMSG_NOT_ARRAY); - } - - if (op1->r.n) { - const char *s; - clrvar(L.v); - s = getvar_s(evaluate(op1->r.n, v1)); - hash_remove(iamarray(v), s); - } else { - clear_array(iamarray(v)); - } - break; - } + /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ case XC( OC_NEWSOURCE ): g_progname = op->l.new_progname; @@ -2666,12 +2671,14 @@ static var *evaluate(node *op, var *res) /* -- recursive node type -- */ case XC( OC_VAR ): + debug_printf_eval("VAR\n"); L.v = op->l.v; if (L.v == intvar[NF]) split_f0(); goto v_cont; case XC( OC_FNARG ): + debug_printf_eval("FNARG[%d]\n", op->l.aidx); L.v = &fnargs[op->l.aidx]; v_cont: res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; @@ -3035,7 +3042,8 @@ static var *evaluate(node *op, var *res) default: syntax_error(EMSG_POSSIBLE_ERROR); - } + } /* switch */ + next: if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) op = op->a.n; if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS) diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 82937bc..ad0583a 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -261,6 +261,25 @@ end d " \ "" "" +prg=' +BEGIN{ +cnt = 0 +a[cnt] = "zeroth" +a[++cnt] = "first" +delete a[cnt--] +print cnt +print "[0]:" a[0] +print "[1]:" a[1] +}' +testing "awk 'delete a[v--]' evaluates v-- once" \ + "awk '$prg'" \ + "\ +0 +[0]:zeroth +[1]: +" \ + "" "" + testing "awk handles empty ()" \ "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" |