diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-02 23:28:55 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-02 23:28:55 +0100 |
| commit | bd8b05ba1b0901bbd6a913dfd5186ac7c8beffed (patch) | |
| tree | d4989ed16d4824dc8925042bce8c426bd499df2f | |
| parent | 9e2a5668fd38db169d9d91b13089a99df4c9bd37 (diff) | |
| download | busybox-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.c | 22 | ||||
| -rwxr-xr-x | testsuite/awk.tests | 23 |
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 |
| 88 | testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ | 88 | testing "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 | ||
| 321 | testing "awk print length, 1" \ | ||
| 322 | "awk '{ print length, 1 }'" \ | ||
| 323 | "0 1\n" \ | ||
| 324 | "" "\n" | ||
| 325 | |||
| 326 | testing "awk print length 1" \ | ||
| 327 | "awk '{ print length 1 }'" \ | ||
| 328 | "01\n" \ | ||
| 329 | "" "\n" | ||
| 330 | |||
| 331 | testing "awk length == 0" \ | ||
| 332 | "awk 'length == 0 { print \"foo\" }'" \ | ||
| 333 | "foo\n" \ | ||
| 334 | "" "\n" | ||
| 335 | |||
| 336 | testing "awk if (length == 0)" \ | ||
| 337 | "awk '{ if (length == 0) { print \"bar\" } }'" \ | ||
| 338 | "bar\n" \ | ||
| 339 | "" "\n" | ||
| 340 | |||
| 320 | testing "awk -f and ARGC" \ | 341 | testing "awk -f and ARGC" \ |
| 321 | "awk -f - input" \ | 342 | "awk -f - input" \ |
| 322 | "re\n2\n" \ | 343 | "re\n2\n" \ |
