aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-02 23:28:55 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-02 23:28:55 +0100
commitbd8b05ba1b0901bbd6a913dfd5186ac7c8beffed (patch)
treed4989ed16d4824dc8925042bce8c426bd499df2f
parent9e2a5668fd38db169d9d91b13089a99df4c9bd37 (diff)
downloadbusybox-w32-bd8b05ba1b0901bbd6a913dfd5186ac7c8beffed.tar.gz
busybox-w32-bd8b05ba1b0901bbd6a913dfd5186ac7c8beffed.tar.bz2
busybox-w32-bd8b05ba1b0901bbd6a913dfd5186ac7c8beffed.zip
awk: fix more "length" cases, closes 12486
function old new delta next_token 808 831 +23 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/awk.c22
-rwxr-xr-xtestsuite/awk.tests23
2 files changed, 40 insertions, 5 deletions
diff --git a/editors/awk.c b/editors/awk.c
index f19990901..70df2fdb4 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -272,7 +272,8 @@ typedef struct tsplitter_s {
272/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ 272/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
273/* operator is inserted between them */ 273/* operator is inserted between them */
274#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ 274#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
275 | TC_STRING | TC_NUMBER | TC_UOPPOST) 275 | TC_STRING | TC_NUMBER | TC_UOPPOST \
276 | TC_LENGTH)
276#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) 277#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
277 278
278#define OF_RES1 0x010000 279#define OF_RES1 0x010000
@@ -1070,8 +1071,10 @@ static uint32_t next_token(uint32_t expected)
1070 const uint32_t *ti; 1071 const uint32_t *ti;
1071 1072
1072 if (t_rollback) { 1073 if (t_rollback) {
1074 debug_printf_parse("%s: using rolled-back token\n", __func__);
1073 t_rollback = FALSE; 1075 t_rollback = FALSE;
1074 } else if (concat_inserted) { 1076 } else if (concat_inserted) {
1077 debug_printf_parse("%s: using concat-inserted token\n", __func__);
1075 concat_inserted = FALSE; 1078 concat_inserted = FALSE;
1076 t_tclass = save_tclass; 1079 t_tclass = save_tclass;
1077 t_info = save_info; 1080 t_info = save_info;
@@ -1200,7 +1203,11 @@ static uint32_t next_token(uint32_t expected)
1200 goto readnext; 1203 goto readnext;
1201 1204
1202 /* insert concatenation operator when needed */ 1205 /* insert concatenation operator when needed */
1203 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { 1206 debug_printf_parse("%s: %x %x %x concat_inserted?\n", __func__,
1207 (ltclass & TC_CONCAT1), (tc & TC_CONCAT2), (expected & TC_BINOP));
1208 if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)
1209 && !(ltclass == TC_LENGTH && tc == TC_SEQSTART) /* but not for "length(..." */
1210 ) {
1204 concat_inserted = TRUE; 1211 concat_inserted = TRUE;
1205 save_tclass = tc; 1212 save_tclass = tc;
1206 save_info = t_info; 1213 save_info = t_info;
@@ -1208,6 +1215,7 @@ static uint32_t next_token(uint32_t expected)
1208 t_info = OC_CONCAT | SS | P(35); 1215 t_info = OC_CONCAT | SS | P(35);
1209 } 1216 }
1210 1217
1218 debug_printf_parse("%s: t_tclass=tc=%x\n", __func__, t_tclass);
1211 t_tclass = tc; 1219 t_tclass = tc;
1212 } 1220 }
1213 ltclass = t_tclass; 1221 ltclass = t_tclass;
@@ -1218,6 +1226,7 @@ static uint32_t next_token(uint32_t expected)
1218 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); 1226 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
1219 } 1227 }
1220 1228
1229 debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double);
1221 return ltclass; 1230 return ltclass;
1222#undef concat_inserted 1231#undef concat_inserted
1223#undef save_tclass 1232#undef save_tclass
@@ -1282,7 +1291,7 @@ static node *parse_expr(uint32_t iexp)
1282 glptr = NULL; 1291 glptr = NULL;
1283 1292
1284 } else if (tc & (TC_BINOP | TC_UOPPOST)) { 1293 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1285 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); 1294 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST tc:%x\n", __func__, tc);
1286 /* for binary and postfix-unary operators, jump back over 1295 /* for binary and postfix-unary operators, jump back over
1287 * previous operators with higher priority */ 1296 * previous operators with higher priority */
1288 vn = cn; 1297 vn = cn;
@@ -1387,7 +1396,12 @@ static node *parse_expr(uint32_t iexp)
1387 1396
1388 case TC_LENGTH: 1397 case TC_LENGTH:
1389 debug_printf_parse("%s: TC_LENGTH\n", __func__); 1398 debug_printf_parse("%s: TC_LENGTH\n", __func__);
1390 next_token(TC_SEQSTART | TC_OPTERM | TC_GRPTERM); 1399 next_token(TC_SEQSTART /* length(...) */
1400 | TC_OPTERM /* length; (or newline)*/
1401 | TC_GRPTERM /* length } */
1402 | TC_BINOPX /* length <op> NUM */
1403 | TC_COMMA /* print length, 1 */
1404 );
1391 rollback_token(); 1405 rollback_token();
1392 if (t_tclass & TC_SEQSTART) { 1406 if (t_tclass & TC_SEQSTART) {
1393 /* It was a "(" token. Handle just like TC_BUILTIN */ 1407 /* It was a "(" token. Handle just like TC_BUILTIN */
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index a7a533ba0..b5008290f 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -85,7 +85,8 @@ testing "awk floating const with leading zeroes" \
85 "" "\n" 85 "" "\n"
86 86
87# long field seps requiring regex 87# long field seps requiring regex
88testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ 88testing "awk long field sep" \
89 "awk -F-- '{ print NF, length(\$NF), \$NF }'" \
89 "2 0 \n3 0 \n4 0 \n5 0 \n" \ 90 "2 0 \n3 0 \n4 0 \n5 0 \n" \
90 "" \ 91 "" \
91 "a--\na--b--\na--b--c--\na--b--c--d--" 92 "a--\na--b--\na--b--c--\na--b--c--d--"
@@ -317,6 +318,26 @@ testing "awk length()" \
317 "3\n3\n3\n3\n" \ 318 "3\n3\n3\n3\n" \
318 "" "qwe" 319 "" "qwe"
319 320
321testing "awk print length, 1" \
322 "awk '{ print length, 1 }'" \
323 "0 1\n" \
324 "" "\n"
325
326testing "awk print length 1" \
327 "awk '{ print length 1 }'" \
328 "01\n" \
329 "" "\n"
330
331testing "awk length == 0" \
332 "awk 'length == 0 { print \"foo\" }'" \
333 "foo\n" \
334 "" "\n"
335
336testing "awk if (length == 0)" \
337 "awk '{ if (length == 0) { print \"bar\" } }'" \
338 "bar\n" \
339 "" "\n"
340
320testing "awk -f and ARGC" \ 341testing "awk -f and ARGC" \
321 "awk -f - input" \ 342 "awk -f - input" \
322 "re\n2\n" \ 343 "re\n2\n" \