aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-07 01:19:08 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-01-07 01:19:08 +0100
commit6f4a785bd1bd0e6973b5c27b34b86655b1d7a602 (patch)
treef7c5acf0f2f844883e5e183b45d85ba0ee5471df
parent7367a949a6a81d71d524f0635a212371120df4e0 (diff)
downloadbusybox-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.c54
-rwxr-xr-xtestsuite/awk.tests19
2 files changed, 50 insertions, 23 deletions
diff --git a/editors/awk.c b/editors/awk.c
index d40c7816a..8f523ea28 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 82937bc10..ad0583afb 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" "" ""