diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-28 07:46:32 +0100 |
commit | e1ad66c0b8fd58a7158d40771175a7dab224202d (patch) | |
tree | 959d687eee9637151ad5798322586174de331141 /editors/awk.c | |
parent | 0fdf99bee07b6c38795eb5415b5e337ab82cfba8 (diff) | |
parent | 5dbbd0a6f52befe6bc57baf97d39168e595197f1 (diff) | |
download | busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.gz busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.tar.bz2 busybox-w32-e1ad66c0b8fd58a7158d40771175a7dab224202d.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'editors/awk.c')
-rw-r--r-- | editors/awk.c | 272 |
1 files changed, 199 insertions, 73 deletions
diff --git a/editors/awk.c b/editors/awk.c index 41a57ea0c..9b9b202db 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #endif | 66 | #endif |
67 | #ifndef debug_printf_parse | 67 | #ifndef debug_printf_parse |
68 | # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) | 68 | # define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) |
69 | #else | ||
70 | # define debug_parse_print_tc(...) ((void)0) | ||
69 | #endif | 71 | #endif |
70 | 72 | ||
71 | 73 | ||
@@ -210,13 +212,13 @@ typedef struct tsplitter_s { | |||
210 | #define TC_SEQTERM (1 << 1) /* ) */ | 212 | #define TC_SEQTERM (1 << 1) /* ) */ |
211 | #define TC_REGEXP (1 << 2) /* /.../ */ | 213 | #define TC_REGEXP (1 << 2) /* /.../ */ |
212 | #define TC_OUTRDR (1 << 3) /* | > >> */ | 214 | #define TC_OUTRDR (1 << 3) /* | > >> */ |
213 | #define TC_UOPPOST (1 << 4) /* unary postfix operator */ | 215 | #define TC_UOPPOST (1 << 4) /* unary postfix operator ++ -- */ |
214 | #define TC_UOPPRE1 (1 << 5) /* unary prefix operator */ | 216 | #define TC_UOPPRE1 (1 << 5) /* unary prefix operator ++ -- $ */ |
215 | #define TC_BINOPX (1 << 6) /* two-opnd operator */ | 217 | #define TC_BINOPX (1 << 6) /* two-opnd operator */ |
216 | #define TC_IN (1 << 7) | 218 | #define TC_IN (1 << 7) |
217 | #define TC_COMMA (1 << 8) | 219 | #define TC_COMMA (1 << 8) |
218 | #define TC_PIPE (1 << 9) /* input redirection pipe */ | 220 | #define TC_PIPE (1 << 9) /* input redirection pipe */ |
219 | #define TC_UOPPRE2 (1 << 10) /* unary prefix operator */ | 221 | #define TC_UOPPRE2 (1 << 10) /* unary prefix operator + - ! */ |
220 | #define TC_ARRTERM (1 << 11) /* ] */ | 222 | #define TC_ARRTERM (1 << 11) /* ] */ |
221 | #define TC_GRPSTART (1 << 12) /* { */ | 223 | #define TC_GRPSTART (1 << 12) /* { */ |
222 | #define TC_GRPTERM (1 << 13) /* } */ | 224 | #define TC_GRPTERM (1 << 13) /* } */ |
@@ -243,14 +245,51 @@ typedef struct tsplitter_s { | |||
243 | #define TC_STRING (1 << 29) | 245 | #define TC_STRING (1 << 29) |
244 | #define TC_NUMBER (1 << 30) | 246 | #define TC_NUMBER (1 << 30) |
245 | 247 | ||
246 | #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) | 248 | #ifndef debug_parse_print_tc |
249 | #define debug_parse_print_tc(n) do { \ | ||
250 | if ((n) & TC_SEQSTART) debug_printf_parse(" SEQSTART"); \ | ||
251 | if ((n) & TC_SEQTERM ) debug_printf_parse(" SEQTERM" ); \ | ||
252 | if ((n) & TC_REGEXP ) debug_printf_parse(" REGEXP" ); \ | ||
253 | if ((n) & TC_OUTRDR ) debug_printf_parse(" OUTRDR" ); \ | ||
254 | if ((n) & TC_UOPPOST ) debug_printf_parse(" UOPPOST" ); \ | ||
255 | if ((n) & TC_UOPPRE1 ) debug_printf_parse(" UOPPRE1" ); \ | ||
256 | if ((n) & TC_BINOPX ) debug_printf_parse(" BINOPX" ); \ | ||
257 | if ((n) & TC_IN ) debug_printf_parse(" IN" ); \ | ||
258 | if ((n) & TC_COMMA ) debug_printf_parse(" COMMA" ); \ | ||
259 | if ((n) & TC_PIPE ) debug_printf_parse(" PIPE" ); \ | ||
260 | if ((n) & TC_UOPPRE2 ) debug_printf_parse(" UOPPRE2" ); \ | ||
261 | if ((n) & TC_ARRTERM ) debug_printf_parse(" ARRTERM" ); \ | ||
262 | if ((n) & TC_GRPSTART) debug_printf_parse(" GRPSTART"); \ | ||
263 | if ((n) & TC_GRPTERM ) debug_printf_parse(" GRPTERM" ); \ | ||
264 | if ((n) & TC_SEMICOL ) debug_printf_parse(" SEMICOL" ); \ | ||
265 | if ((n) & TC_NEWLINE ) debug_printf_parse(" NEWLINE" ); \ | ||
266 | if ((n) & TC_STATX ) debug_printf_parse(" STATX" ); \ | ||
267 | if ((n) & TC_WHILE ) debug_printf_parse(" WHILE" ); \ | ||
268 | if ((n) & TC_ELSE ) debug_printf_parse(" ELSE" ); \ | ||
269 | if ((n) & TC_BUILTIN ) debug_printf_parse(" BUILTIN" ); \ | ||
270 | if ((n) & TC_LENGTH ) debug_printf_parse(" LENGTH" ); \ | ||
271 | if ((n) & TC_GETLINE ) debug_printf_parse(" GETLINE" ); \ | ||
272 | if ((n) & TC_FUNCDECL) debug_printf_parse(" FUNCDECL"); \ | ||
273 | if ((n) & TC_BEGIN ) debug_printf_parse(" BEGIN" ); \ | ||
274 | if ((n) & TC_END ) debug_printf_parse(" END" ); \ | ||
275 | if ((n) & TC_EOF ) debug_printf_parse(" EOF" ); \ | ||
276 | if ((n) & TC_VARIABLE) debug_printf_parse(" VARIABLE"); \ | ||
277 | if ((n) & TC_ARRAY ) debug_printf_parse(" ARRAY" ); \ | ||
278 | if ((n) & TC_FUNCTION) debug_printf_parse(" FUNCTION"); \ | ||
279 | if ((n) & TC_STRING ) debug_printf_parse(" STRING" ); \ | ||
280 | if ((n) & TC_NUMBER ) debug_printf_parse(" NUMBER" ); \ | ||
281 | } while (0) | ||
282 | #endif | ||
247 | 283 | ||
248 | /* combined token classes */ | 284 | /* combined token classes */ |
285 | #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) | ||
286 | |||
249 | #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) | 287 | #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) |
250 | //#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) | 288 | //#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) |
251 | #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ | 289 | #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ |
252 | | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ | 290 | | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ |
253 | | TC_SEQSTART | TC_STRING | TC_NUMBER) | 291 | | TC_SEQSTART | TC_STRING | TC_NUMBER) |
292 | #define TC_LVALUE (TC_VARIABLE | TC_ARRAY) | ||
254 | 293 | ||
255 | #define TC_STATEMNT (TC_STATX | TC_WHILE) | 294 | #define TC_STATEMNT (TC_STATX | TC_WHILE) |
256 | #define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) | 295 | #define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) |
@@ -284,7 +323,6 @@ typedef struct tsplitter_s { | |||
284 | #define OF_CHECKED 0x200000 | 323 | #define OF_CHECKED 0x200000 |
285 | #define OF_REQUIRED 0x400000 | 324 | #define OF_REQUIRED 0x400000 |
286 | 325 | ||
287 | |||
288 | /* combined operator flags */ | 326 | /* combined operator flags */ |
289 | #define xx 0 | 327 | #define xx 0 |
290 | #define xV OF_RES2 | 328 | #define xV OF_RES2 |
@@ -313,10 +351,8 @@ typedef struct tsplitter_s { | |||
313 | #define PRIMASK2 0x7E000000 | 351 | #define PRIMASK2 0x7E000000 |
314 | 352 | ||
315 | /* Operation classes */ | 353 | /* Operation classes */ |
316 | |||
317 | #define SHIFT_TIL_THIS 0x0600 | 354 | #define SHIFT_TIL_THIS 0x0600 |
318 | #define RECUR_FROM_THIS 0x1000 | 355 | #define RECUR_FROM_THIS 0x1000 |
319 | |||
320 | enum { | 356 | enum { |
321 | OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, | 357 | OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, |
322 | OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, | 358 | OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, |
@@ -411,13 +447,16 @@ static const uint32_t tokeninfo[] ALIGN4 = { | |||
411 | OC_REGEXP, | 447 | OC_REGEXP, |
412 | xS|'a', xS|'w', xS|'|', | 448 | xS|'a', xS|'w', xS|'|', |
413 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', | 449 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', |
414 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), | 450 | #define TI_PREINC (OC_UNARY|xV|P(9)|'P') |
451 | #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') | ||
452 | TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), | ||
415 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', | 453 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', |
416 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | 454 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', |
417 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | 455 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', |
418 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | 456 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
419 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | 457 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
420 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | 458 | #define TI_LESS (OC_COMPARE|VV|P(39)|2) |
459 | TI_LESS, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | ||
421 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', | 460 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', |
422 | OC_IN|SV|P(49), /* TC_IN */ | 461 | OC_IN|SV|P(49), /* TC_IN */ |
423 | OC_COMMA|SS|P(80), | 462 | OC_COMMA|SS|P(80), |
@@ -1074,6 +1113,10 @@ static uint32_t next_token(uint32_t expected) | |||
1074 | uint32_t tc; | 1113 | uint32_t tc; |
1075 | const uint32_t *ti; | 1114 | const uint32_t *ti; |
1076 | 1115 | ||
1116 | debug_printf_parse("%s() expected(%x):", __func__, expected); | ||
1117 | debug_parse_print_tc(expected); | ||
1118 | debug_printf_parse("\n"); | ||
1119 | |||
1077 | if (t_rollback) { | 1120 | if (t_rollback) { |
1078 | debug_printf_parse("%s: using rolled-back token\n", __func__); | 1121 | debug_printf_parse("%s: using rolled-back token\n", __func__); |
1079 | t_rollback = FALSE; | 1122 | t_rollback = FALSE; |
@@ -1178,6 +1221,8 @@ static uint32_t next_token(uint32_t expected) | |||
1178 | if (!isalnum_(*p)) | 1221 | if (!isalnum_(*p)) |
1179 | syntax_error(EMSG_UNEXP_TOKEN); /* no */ | 1222 | syntax_error(EMSG_UNEXP_TOKEN); /* no */ |
1180 | /* yes */ | 1223 | /* yes */ |
1224 | /* "move name one char back" trick: we need a byte for NUL terminator */ | ||
1225 | /* NB: this results in argv[i][-1] being used (!!!) in e.g. "awk -e 'NAME'" case */ | ||
1181 | t_string = --p; | 1226 | t_string = --p; |
1182 | while (isalnum_(*++p)) { | 1227 | while (isalnum_(*++p)) { |
1183 | p[-1] = *p; | 1228 | p[-1] = *p; |
@@ -1230,7 +1275,9 @@ static uint32_t next_token(uint32_t expected) | |||
1230 | EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); | 1275 | EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); |
1231 | } | 1276 | } |
1232 | 1277 | ||
1233 | debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double); | 1278 | debug_printf_parse("%s: returning, t_double:%f ltclass:", __func__, t_double); |
1279 | debug_parse_print_tc(ltclass); | ||
1280 | debug_printf_parse("\n"); | ||
1234 | return ltclass; | 1281 | return ltclass; |
1235 | #undef concat_inserted | 1282 | #undef concat_inserted |
1236 | #undef save_tclass | 1283 | #undef save_tclass |
@@ -1270,7 +1317,7 @@ static node *condition(void) | |||
1270 | 1317 | ||
1271 | /* parse expression terminated by given argument, return ptr | 1318 | /* parse expression terminated by given argument, return ptr |
1272 | * to built subtree. Terminator is eaten by parse_expr */ | 1319 | * to built subtree. Terminator is eaten by parse_expr */ |
1273 | static node *parse_expr(uint32_t iexp) | 1320 | static node *parse_expr(uint32_t term_tc) |
1274 | { | 1321 | { |
1275 | node sn; | 1322 | node sn; |
1276 | node *cn = &sn; | 1323 | node *cn = &sn; |
@@ -1278,15 +1325,17 @@ static node *parse_expr(uint32_t iexp) | |||
1278 | uint32_t tc, xtc; | 1325 | uint32_t tc, xtc; |
1279 | var *v; | 1326 | var *v; |
1280 | 1327 | ||
1281 | debug_printf_parse("%s(%x)\n", __func__, iexp); | 1328 | debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); |
1329 | debug_parse_print_tc(term_tc); | ||
1330 | debug_printf_parse("\n"); | ||
1282 | 1331 | ||
1283 | sn.info = PRIMASK; | 1332 | sn.info = PRIMASK; |
1284 | sn.r.n = sn.a.n = glptr = NULL; | 1333 | sn.r.n = sn.a.n = glptr = NULL; |
1285 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; | 1334 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | term_tc; |
1286 | 1335 | ||
1287 | while (!((tc = next_token(xtc)) & iexp)) { | 1336 | while (!((tc = next_token(xtc)) & term_tc)) { |
1288 | 1337 | ||
1289 | if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { | 1338 | if (glptr && (t_info == TI_LESS)) { |
1290 | /* input redirection (<) attached to glptr node */ | 1339 | /* input redirection (<) attached to glptr node */ |
1291 | debug_printf_parse("%s: input redir\n", __func__); | 1340 | debug_printf_parse("%s: input redir\n", __func__); |
1292 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); | 1341 | cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); |
@@ -1317,25 +1366,28 @@ static node *parse_expr(uint32_t iexp) | |||
1317 | next_token(TC_GETLINE); | 1366 | next_token(TC_GETLINE); |
1318 | /* give maximum priority to this pipe */ | 1367 | /* give maximum priority to this pipe */ |
1319 | cn->info &= ~PRIMASK; | 1368 | cn->info &= ~PRIMASK; |
1320 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1369 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1321 | } | 1370 | } |
1322 | } else { | 1371 | } else { |
1323 | cn->r.n = vn; | 1372 | cn->r.n = vn; |
1324 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1373 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1325 | } | 1374 | } |
1326 | vn->a.n = cn; | 1375 | vn->a.n = cn; |
1327 | 1376 | ||
1328 | } else { | 1377 | } else { |
1329 | debug_printf_parse("%s: other\n", __func__); | 1378 | debug_printf_parse("%s: other, t_info:%x\n", __func__, t_info); |
1330 | /* for operands and prefix-unary operators, attach them | 1379 | /* for operands and prefix-unary operators, attach them |
1331 | * to last node */ | 1380 | * to last node */ |
1332 | vn = cn; | 1381 | vn = cn; |
1333 | cn = vn->r.n = new_node(t_info); | 1382 | cn = vn->r.n = new_node(t_info); |
1334 | cn->a.n = vn; | 1383 | cn->a.n = vn; |
1384 | |||
1335 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; | 1385 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; |
1386 | if (t_info == TI_PREINC || t_info == TI_PREDEC) | ||
1387 | xtc = TC_LVALUE | TC_UOPPRE1; | ||
1336 | if (tc & (TC_OPERAND | TC_REGEXP)) { | 1388 | if (tc & (TC_OPERAND | TC_REGEXP)) { |
1337 | debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); | 1389 | debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); |
1338 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; | 1390 | xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | term_tc; |
1339 | /* one should be very careful with switch on tclass - | 1391 | /* one should be very careful with switch on tclass - |
1340 | * only simple tclasses should be used! */ | 1392 | * only simple tclasses should be used! */ |
1341 | switch (tc) { | 1393 | switch (tc) { |
@@ -1392,7 +1444,7 @@ static node *parse_expr(uint32_t iexp) | |||
1392 | case TC_GETLINE: | 1444 | case TC_GETLINE: |
1393 | debug_printf_parse("%s: TC_GETLINE\n", __func__); | 1445 | debug_printf_parse("%s: TC_GETLINE\n", __func__); |
1394 | glptr = cn; | 1446 | glptr = cn; |
1395 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; | 1447 | xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | term_tc; |
1396 | break; | 1448 | break; |
1397 | 1449 | ||
1398 | case TC_BUILTIN: | 1450 | case TC_BUILTIN: |
@@ -1607,6 +1659,8 @@ static void parse_program(char *p) | |||
1607 | func *f; | 1659 | func *f; |
1608 | var *v; | 1660 | var *v; |
1609 | 1661 | ||
1662 | debug_printf_parse("%s()\n", __func__); | ||
1663 | |||
1610 | g_pos = p; | 1664 | g_pos = p; |
1611 | t_lineno = 1; | 1665 | t_lineno = 1; |
1612 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | | 1666 | while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | |
@@ -1749,12 +1803,22 @@ static char* qrealloc(char *b, int n, int *size) | |||
1749 | /* resize field storage space */ | 1803 | /* resize field storage space */ |
1750 | static void fsrealloc(int size) | 1804 | static void fsrealloc(int size) |
1751 | { | 1805 | { |
1752 | int i; | 1806 | int i, newsize; |
1753 | 1807 | ||
1754 | if (size >= maxfields) { | 1808 | if (size >= maxfields) { |
1809 | /* Sanity cap, easier than catering for overflows */ | ||
1810 | if (size > 0xffffff) | ||
1811 | bb_die_memory_exhausted(); | ||
1812 | |||
1755 | i = maxfields; | 1813 | i = maxfields; |
1756 | maxfields = size + 16; | 1814 | maxfields = size + 16; |
1757 | Fields = xrealloc(Fields, maxfields * sizeof(Fields[0])); | 1815 | |
1816 | newsize = maxfields * sizeof(Fields[0]); | ||
1817 | debug_printf_eval("fsrealloc: xrealloc(%p, %u)\n", Fields, newsize); | ||
1818 | Fields = xrealloc(Fields, newsize); | ||
1819 | debug_printf_eval("fsrealloc: Fields=%p..%p\n", Fields, (char*)Fields + newsize - 1); | ||
1820 | /* ^^^ did Fields[] move? debug aid for L.v getting "upstaged" by R.v in evaluate() */ | ||
1821 | |||
1758 | for (; i < maxfields; i++) { | 1822 | for (; i < maxfields; i++) { |
1759 | Fields[i].type = VF_SPECIAL; | 1823 | Fields[i].type = VF_SPECIAL; |
1760 | Fields[i].string = NULL; | 1824 | Fields[i].string = NULL; |
@@ -2633,20 +2697,30 @@ static var *evaluate(node *op, var *res) | |||
2633 | /* execute inevitable things */ | 2697 | /* execute inevitable things */ |
2634 | if (opinfo & OF_RES1) | 2698 | if (opinfo & OF_RES1) |
2635 | L.v = evaluate(op1, v1); | 2699 | L.v = evaluate(op1, v1); |
2636 | if (opinfo & OF_RES2) | ||
2637 | R.v = evaluate(op->r.n, v1+1); | ||
2638 | if (opinfo & OF_STR1) { | 2700 | if (opinfo & OF_STR1) { |
2639 | L.s = getvar_s(L.v); | 2701 | L.s = getvar_s(L.v); |
2640 | debug_printf_eval("L.s:'%s'\n", L.s); | 2702 | debug_printf_eval("L.s:'%s'\n", L.s); |
2641 | } | 2703 | } |
2642 | if (opinfo & OF_STR2) { | ||
2643 | R.s = getvar_s(R.v); | ||
2644 | debug_printf_eval("R.s:'%s'\n", R.s); | ||
2645 | } | ||
2646 | if (opinfo & OF_NUM1) { | 2704 | if (opinfo & OF_NUM1) { |
2647 | L_d = getvar_i(L.v); | 2705 | L_d = getvar_i(L.v); |
2648 | debug_printf_eval("L_d:%f\n", L_d); | 2706 | debug_printf_eval("L_d:%f\n", L_d); |
2649 | } | 2707 | } |
2708 | /* NB: Must get string/numeric values of L (done above) | ||
2709 | * _before_ evaluate()'ing R.v: if both L and R are $NNNs, | ||
2710 | * and right one is large, then L.v points to Fields[NNN1], | ||
2711 | * second evaluate() reallocates and moves (!) Fields[], | ||
2712 | * R.v points to Fields[NNN2] but L.v now points to freed mem! | ||
2713 | * (Seen trying to evaluate "$444 $44444") | ||
2714 | */ | ||
2715 | if (opinfo & OF_RES2) { | ||
2716 | R.v = evaluate(op->r.n, v1+1); | ||
2717 | //TODO: L.v may be invalid now, set L.v to NULL to catch bugs? | ||
2718 | //L.v = NULL; | ||
2719 | } | ||
2720 | if (opinfo & OF_STR2) { | ||
2721 | R.s = getvar_s(R.v); | ||
2722 | debug_printf_eval("R.s:'%s'\n", R.s); | ||
2723 | } | ||
2650 | 2724 | ||
2651 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); | 2725 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); |
2652 | switch (XC(opinfo & OPCLSMASK)) { | 2726 | switch (XC(opinfo & OPCLSMASK)) { |
@@ -2655,6 +2729,7 @@ static var *evaluate(node *op, var *res) | |||
2655 | 2729 | ||
2656 | /* test pattern */ | 2730 | /* test pattern */ |
2657 | case XC( OC_TEST ): | 2731 | case XC( OC_TEST ): |
2732 | debug_printf_eval("TEST\n"); | ||
2658 | if ((op1->info & OPCLSMASK) == OC_COMMA) { | 2733 | if ((op1->info & OPCLSMASK) == OC_COMMA) { |
2659 | /* it's range pattern */ | 2734 | /* it's range pattern */ |
2660 | if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { | 2735 | if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { |
@@ -2672,25 +2747,32 @@ static var *evaluate(node *op, var *res) | |||
2672 | 2747 | ||
2673 | /* just evaluate an expression, also used as unconditional jump */ | 2748 | /* just evaluate an expression, also used as unconditional jump */ |
2674 | case XC( OC_EXEC ): | 2749 | case XC( OC_EXEC ): |
2750 | debug_printf_eval("EXEC\n"); | ||
2675 | break; | 2751 | break; |
2676 | 2752 | ||
2677 | /* branch, used in if-else and various loops */ | 2753 | /* branch, used in if-else and various loops */ |
2678 | case XC( OC_BR ): | 2754 | case XC( OC_BR ): |
2755 | debug_printf_eval("BR\n"); | ||
2679 | op = istrue(L.v) ? op->a.n : op->r.n; | 2756 | op = istrue(L.v) ? op->a.n : op->r.n; |
2680 | break; | 2757 | break; |
2681 | 2758 | ||
2682 | /* initialize for-in loop */ | 2759 | /* initialize for-in loop */ |
2683 | case XC( OC_WALKINIT ): | 2760 | case XC( OC_WALKINIT ): |
2761 | debug_printf_eval("WALKINIT\n"); | ||
2684 | hashwalk_init(L.v, iamarray(R.v)); | 2762 | hashwalk_init(L.v, iamarray(R.v)); |
2685 | break; | 2763 | break; |
2686 | 2764 | ||
2687 | /* get next array item */ | 2765 | /* get next array item */ |
2688 | case XC( OC_WALKNEXT ): | 2766 | case XC( OC_WALKNEXT ): |
2767 | debug_printf_eval("WALKNEXT\n"); | ||
2689 | op = hashwalk_next(L.v) ? op->a.n : op->r.n; | 2768 | op = hashwalk_next(L.v) ? op->a.n : op->r.n; |
2690 | break; | 2769 | break; |
2691 | 2770 | ||
2692 | case XC( OC_PRINT ): | 2771 | case XC( OC_PRINT ): |
2693 | case XC( OC_PRINTF ): { | 2772 | debug_printf_eval("PRINT /\n"); |
2773 | case XC( OC_PRINTF ): | ||
2774 | debug_printf_eval("PRINTF\n"); | ||
2775 | { | ||
2694 | FILE *F = stdout; | 2776 | FILE *F = stdout; |
2695 | IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) | 2777 | IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) |
2696 | 2778 | ||
@@ -2745,22 +2827,28 @@ static var *evaluate(node *op, var *res) | |||
2745 | /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ | 2827 | /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ |
2746 | 2828 | ||
2747 | case XC( OC_NEWSOURCE ): | 2829 | case XC( OC_NEWSOURCE ): |
2830 | debug_printf_eval("NEWSOURCE\n"); | ||
2748 | g_progname = op->l.new_progname; | 2831 | g_progname = op->l.new_progname; |
2749 | break; | 2832 | break; |
2750 | 2833 | ||
2751 | case XC( OC_RETURN ): | 2834 | case XC( OC_RETURN ): |
2835 | debug_printf_eval("RETURN\n"); | ||
2752 | copyvar(res, L.v); | 2836 | copyvar(res, L.v); |
2753 | break; | 2837 | break; |
2754 | 2838 | ||
2755 | case XC( OC_NEXTFILE ): | 2839 | case XC( OC_NEXTFILE ): |
2840 | debug_printf_eval("NEXTFILE\n"); | ||
2756 | nextfile = TRUE; | 2841 | nextfile = TRUE; |
2757 | case XC( OC_NEXT ): | 2842 | case XC( OC_NEXT ): |
2843 | debug_printf_eval("NEXT\n"); | ||
2758 | nextrec = TRUE; | 2844 | nextrec = TRUE; |
2759 | case XC( OC_DONE ): | 2845 | case XC( OC_DONE ): |
2846 | debug_printf_eval("DONE\n"); | ||
2760 | clrvar(res); | 2847 | clrvar(res); |
2761 | break; | 2848 | break; |
2762 | 2849 | ||
2763 | case XC( OC_EXIT ): | 2850 | case XC( OC_EXIT ): |
2851 | debug_printf_eval("EXIT\n"); | ||
2764 | awk_exit(L_d); | 2852 | awk_exit(L_d); |
2765 | 2853 | ||
2766 | /* -- recursive node type -- */ | 2854 | /* -- recursive node type -- */ |
@@ -2780,15 +2868,18 @@ static var *evaluate(node *op, var *res) | |||
2780 | break; | 2868 | break; |
2781 | 2869 | ||
2782 | case XC( OC_IN ): | 2870 | case XC( OC_IN ): |
2871 | debug_printf_eval("IN\n"); | ||
2783 | setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); | 2872 | setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); |
2784 | break; | 2873 | break; |
2785 | 2874 | ||
2786 | case XC( OC_REGEXP ): | 2875 | case XC( OC_REGEXP ): |
2876 | debug_printf_eval("REGEXP\n"); | ||
2787 | op1 = op; | 2877 | op1 = op; |
2788 | L.s = getvar_s(intvar[F0]); | 2878 | L.s = getvar_s(intvar[F0]); |
2789 | goto re_cont; | 2879 | goto re_cont; |
2790 | 2880 | ||
2791 | case XC( OC_MATCH ): | 2881 | case XC( OC_MATCH ): |
2882 | debug_printf_eval("MATCH\n"); | ||
2792 | op1 = op->r.n; | 2883 | op1 = op->r.n; |
2793 | re_cont: | 2884 | re_cont: |
2794 | { | 2885 | { |
@@ -2814,6 +2905,7 @@ static var *evaluate(node *op, var *res) | |||
2814 | break; | 2905 | break; |
2815 | 2906 | ||
2816 | case XC( OC_TERNARY ): | 2907 | case XC( OC_TERNARY ): |
2908 | debug_printf_eval("TERNARY\n"); | ||
2817 | if ((op->r.n->info & OPCLSMASK) != OC_COLON) | 2909 | if ((op->r.n->info & OPCLSMASK) != OC_COLON) |
2818 | syntax_error(EMSG_POSSIBLE_ERROR); | 2910 | syntax_error(EMSG_POSSIBLE_ERROR); |
2819 | res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); | 2911 | res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); |
@@ -2822,6 +2914,7 @@ static var *evaluate(node *op, var *res) | |||
2822 | case XC( OC_FUNC ): { | 2914 | case XC( OC_FUNC ): { |
2823 | var *vbeg, *v; | 2915 | var *vbeg, *v; |
2824 | const char *sv_progname; | 2916 | const char *sv_progname; |
2917 | debug_printf_eval("FUNC\n"); | ||
2825 | 2918 | ||
2826 | /* The body might be empty, still has to eval the args */ | 2919 | /* The body might be empty, still has to eval the args */ |
2827 | if (!op->r.n->info && !op->r.f->body.first) | 2920 | if (!op->r.n->info && !op->r.f->body.first) |
@@ -2851,7 +2944,10 @@ static var *evaluate(node *op, var *res) | |||
2851 | } | 2944 | } |
2852 | 2945 | ||
2853 | case XC( OC_GETLINE ): | 2946 | case XC( OC_GETLINE ): |
2854 | case XC( OC_PGETLINE ): { | 2947 | debug_printf_eval("GETLINE /\n"); |
2948 | case XC( OC_PGETLINE ): | ||
2949 | debug_printf_eval("PGETLINE\n"); | ||
2950 | { | ||
2855 | rstream *rsm; | 2951 | rstream *rsm; |
2856 | int i; | 2952 | int i; |
2857 | 2953 | ||
@@ -2892,6 +2988,7 @@ static var *evaluate(node *op, var *res) | |||
2892 | /* simple builtins */ | 2988 | /* simple builtins */ |
2893 | case XC( OC_FBLTIN ): { | 2989 | case XC( OC_FBLTIN ): { |
2894 | double R_d = R_d; /* for compiler */ | 2990 | double R_d = R_d; /* for compiler */ |
2991 | debug_printf_eval("FBLTIN\n"); | ||
2895 | 2992 | ||
2896 | switch (opn) { | 2993 | switch (opn) { |
2897 | case F_in: | 2994 | case F_in: |
@@ -3005,14 +3102,18 @@ static var *evaluate(node *op, var *res) | |||
3005 | } | 3102 | } |
3006 | 3103 | ||
3007 | case XC( OC_BUILTIN ): | 3104 | case XC( OC_BUILTIN ): |
3105 | debug_printf_eval("BUILTIN\n"); | ||
3008 | res = exec_builtin(op, res); | 3106 | res = exec_builtin(op, res); |
3009 | break; | 3107 | break; |
3010 | 3108 | ||
3011 | case XC( OC_SPRINTF ): | 3109 | case XC( OC_SPRINTF ): |
3110 | debug_printf_eval("SPRINTF\n"); | ||
3012 | setvar_p(res, awk_printf(op1, NULL)); | 3111 | setvar_p(res, awk_printf(op1, NULL)); |
3013 | break; | 3112 | break; |
3014 | 3113 | ||
3015 | case XC( OC_UNARY ): { | 3114 | case XC( OC_UNARY ): |
3115 | debug_printf_eval("UNARY\n"); | ||
3116 | { | ||
3016 | double Ld, R_d; | 3117 | double Ld, R_d; |
3017 | 3118 | ||
3018 | Ld = R_d = getvar_i(R.v); | 3119 | Ld = R_d = getvar_i(R.v); |
@@ -3042,7 +3143,9 @@ static var *evaluate(node *op, var *res) | |||
3042 | break; | 3143 | break; |
3043 | } | 3144 | } |
3044 | 3145 | ||
3045 | case XC( OC_FIELD ): { | 3146 | case XC( OC_FIELD ): |
3147 | debug_printf_eval("FIELD\n"); | ||
3148 | { | ||
3046 | int i = (int)getvar_i(R.v); | 3149 | int i = (int)getvar_i(R.v); |
3047 | if (i < 0) | 3150 | if (i < 0) |
3048 | syntax_error(EMSG_NEGATIVE_FIELD); | 3151 | syntax_error(EMSG_NEGATIVE_FIELD); |
@@ -3059,8 +3162,10 @@ static var *evaluate(node *op, var *res) | |||
3059 | 3162 | ||
3060 | /* concatenation (" ") and index joining (",") */ | 3163 | /* concatenation (" ") and index joining (",") */ |
3061 | case XC( OC_CONCAT ): | 3164 | case XC( OC_CONCAT ): |
3165 | debug_printf_eval("CONCAT /\n"); | ||
3062 | case XC( OC_COMMA ): { | 3166 | case XC( OC_COMMA ): { |
3063 | const char *sep = ""; | 3167 | const char *sep = ""; |
3168 | debug_printf_eval("COMMA\n"); | ||
3064 | if ((opinfo & OPCLSMASK) == OC_COMMA) | 3169 | if ((opinfo & OPCLSMASK) == OC_COMMA) |
3065 | sep = getvar_s(intvar[SUBSEP]); | 3170 | sep = getvar_s(intvar[SUBSEP]); |
3066 | setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); | 3171 | setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); |
@@ -3068,17 +3173,22 @@ static var *evaluate(node *op, var *res) | |||
3068 | } | 3173 | } |
3069 | 3174 | ||
3070 | case XC( OC_LAND ): | 3175 | case XC( OC_LAND ): |
3176 | debug_printf_eval("LAND\n"); | ||
3071 | setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); | 3177 | setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); |
3072 | break; | 3178 | break; |
3073 | 3179 | ||
3074 | case XC( OC_LOR ): | 3180 | case XC( OC_LOR ): |
3181 | debug_printf_eval("LOR\n"); | ||
3075 | setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); | 3182 | setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); |
3076 | break; | 3183 | break; |
3077 | 3184 | ||
3078 | case XC( OC_BINARY ): | 3185 | case XC( OC_BINARY ): |
3079 | case XC( OC_REPLACE ): { | 3186 | debug_printf_eval("BINARY /\n"); |
3187 | case XC( OC_REPLACE ): | ||
3188 | debug_printf_eval("REPLACE\n"); | ||
3189 | { | ||
3080 | double R_d = getvar_i(R.v); | 3190 | double R_d = getvar_i(R.v); |
3081 | debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn); | 3191 | debug_printf_eval("R_d:%f opn:%c\n", R_d, opn); |
3082 | switch (opn) { | 3192 | switch (opn) { |
3083 | case '+': | 3193 | case '+': |
3084 | L_d += R_d; | 3194 | L_d += R_d; |
@@ -3114,6 +3224,7 @@ static var *evaluate(node *op, var *res) | |||
3114 | case XC( OC_COMPARE ): { | 3224 | case XC( OC_COMPARE ): { |
3115 | int i = i; /* for compiler */ | 3225 | int i = i; /* for compiler */ |
3116 | double Ld; | 3226 | double Ld; |
3227 | debug_printf_eval("COMPARE\n"); | ||
3117 | 3228 | ||
3118 | if (is_numeric(L.v) && is_numeric(R.v)) { | 3229 | if (is_numeric(L.v) && is_numeric(R.v)) { |
3119 | Ld = getvar_i(L.v) - getvar_i(R.v); | 3230 | Ld = getvar_i(L.v) - getvar_i(R.v); |
@@ -3162,20 +3273,19 @@ static var *evaluate(node *op, var *res) | |||
3162 | 3273 | ||
3163 | static int awk_exit(int r) | 3274 | static int awk_exit(int r) |
3164 | { | 3275 | { |
3165 | var tv; | ||
3166 | unsigned i; | 3276 | unsigned i; |
3167 | hash_item *hi; | ||
3168 | |||
3169 | zero_out_var(&tv); | ||
3170 | 3277 | ||
3171 | if (!exiting) { | 3278 | if (!exiting) { |
3279 | var tv; | ||
3172 | exiting = TRUE; | 3280 | exiting = TRUE; |
3173 | nextrec = FALSE; | 3281 | nextrec = FALSE; |
3282 | zero_out_var(&tv); | ||
3174 | evaluate(endseq.first, &tv); | 3283 | evaluate(endseq.first, &tv); |
3175 | } | 3284 | } |
3176 | 3285 | ||
3177 | /* waiting for children */ | 3286 | /* waiting for children */ |
3178 | for (i = 0; i < fdhash->csize; i++) { | 3287 | for (i = 0; i < fdhash->csize; i++) { |
3288 | hash_item *hi; | ||
3179 | hi = fdhash->items[i]; | 3289 | hi = fdhash->items[i]; |
3180 | while (hi) { | 3290 | while (hi) { |
3181 | if (hi->data.rs.F && hi->data.rs.is_pipe) | 3291 | if (hi->data.rs.F && hi->data.rs.is_pipe) |
@@ -3255,12 +3365,8 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3255 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 3365 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
3256 | llist_t *list_e = NULL; | 3366 | llist_t *list_e = NULL; |
3257 | #endif | 3367 | #endif |
3258 | int i, j; | 3368 | int i; |
3259 | var *v; | ||
3260 | var tv; | 3369 | var tv; |
3261 | char **envp; | ||
3262 | char *vnames = (char *)vNames; /* cheat */ | ||
3263 | char *vvalues = (char *)vValues; | ||
3264 | 3370 | ||
3265 | INIT_G(); | 3371 | INIT_G(); |
3266 | 3372 | ||
@@ -3269,8 +3375,6 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3269 | if (ENABLE_LOCALE_SUPPORT) | 3375 | if (ENABLE_LOCALE_SUPPORT) |
3270 | setlocale(LC_NUMERIC, "C"); | 3376 | setlocale(LC_NUMERIC, "C"); |
3271 | 3377 | ||
3272 | zero_out_var(&tv); | ||
3273 | |||
3274 | /* allocate global buffer */ | 3378 | /* allocate global buffer */ |
3275 | g_buf = xmalloc(MAXVARFMT + 1); | 3379 | g_buf = xmalloc(MAXVARFMT + 1); |
3276 | 3380 | ||
@@ -3280,16 +3384,21 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3280 | fnhash = hash_init(); | 3384 | fnhash = hash_init(); |
3281 | 3385 | ||
3282 | /* initialize variables */ | 3386 | /* initialize variables */ |
3283 | for (i = 0; *vnames; i++) { | 3387 | { |
3284 | intvar[i] = v = newvar(nextword(&vnames)); | 3388 | char *vnames = (char *)vNames; /* cheat */ |
3285 | if (*vvalues != '\377') | 3389 | char *vvalues = (char *)vValues; |
3286 | setvar_s(v, nextword(&vvalues)); | 3390 | for (i = 0; *vnames; i++) { |
3287 | else | 3391 | var *v; |
3288 | setvar_i(v, 0); | 3392 | intvar[i] = v = newvar(nextword(&vnames)); |
3289 | 3393 | if (*vvalues != '\377') | |
3290 | if (*vnames == '*') { | 3394 | setvar_s(v, nextword(&vvalues)); |
3291 | v->type |= VF_SPECIAL; | 3395 | else |
3292 | vnames++; | 3396 | setvar_i(v, 0); |
3397 | |||
3398 | if (*vnames == '*') { | ||
3399 | v->type |= VF_SPECIAL; | ||
3400 | vnames++; | ||
3401 | } | ||
3293 | } | 3402 | } |
3294 | } | 3403 | } |
3295 | 3404 | ||
@@ -3301,16 +3410,19 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3301 | newfile("/dev/stderr")->F = stderr; | 3410 | newfile("/dev/stderr")->F = stderr; |
3302 | 3411 | ||
3303 | /* Huh, people report that sometimes environ is NULL. Oh well. */ | 3412 | /* Huh, people report that sometimes environ is NULL. Oh well. */ |
3304 | if (environ) for (envp = environ; *envp; envp++) { | 3413 | if (environ) { |
3305 | /* environ is writable, thus we don't strdup it needlessly */ | 3414 | char **envp; |
3306 | char *s = *envp; | 3415 | for (envp = environ; *envp; envp++) { |
3307 | char *s1 = strchr(s, '='); | 3416 | /* environ is writable, thus we don't strdup it needlessly */ |
3308 | if (s1) { | 3417 | char *s = *envp; |
3309 | *s1 = '\0'; | 3418 | char *s1 = strchr(s, '='); |
3310 | /* Both findvar and setvar_u take const char* | 3419 | if (s1) { |
3311 | * as 2nd arg -> environment is not trashed */ | 3420 | *s1 = '\0'; |
3312 | setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); | 3421 | /* Both findvar and setvar_u take const char* |
3313 | *s1 = '='; | 3422 | * as 2nd arg -> environment is not trashed */ |
3423 | setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); | ||
3424 | *s1 = '='; | ||
3425 | } | ||
3314 | } | 3426 | } |
3315 | } | 3427 | } |
3316 | opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); | 3428 | opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); |
@@ -3327,30 +3439,43 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3327 | bb_show_usage(); | 3439 | bb_show_usage(); |
3328 | } | 3440 | } |
3329 | while (list_f) { | 3441 | while (list_f) { |
3330 | char *s = NULL; | 3442 | int fd; |
3331 | FILE *from_file; | 3443 | char *s; |
3332 | 3444 | ||
3333 | g_progname = llist_pop(&list_f); | 3445 | g_progname = llist_pop(&list_f); |
3334 | from_file = xfopen_stdin(g_progname); | 3446 | fd = xopen_stdin(g_progname); |
3335 | /* one byte is reserved for some trick in next_token */ | 3447 | /* 1st byte is reserved for "move name one char back" trick in next_token */ |
3336 | for (i = j = 1; j > 0; i += j) { | 3448 | i = 1; |
3337 | s = xrealloc(s, i + 4096); | 3449 | s = NULL; |
3338 | j = fread(s + i, 1, 4094, from_file); | 3450 | for (;;) { |
3451 | int sz; | ||
3452 | s = xrealloc(s, i + 1000); | ||
3453 | sz = safe_read(fd, s + i, 1000); | ||
3454 | if (sz <= 0) | ||
3455 | break; | ||
3456 | i += sz; | ||
3339 | } | 3457 | } |
3458 | s = xrealloc(s, i + 1); /* trim unused 999 bytes */ | ||
3340 | s[i] = '\0'; | 3459 | s[i] = '\0'; |
3341 | fclose(from_file); | 3460 | close(fd); |
3342 | parse_program(s + 1); | 3461 | parse_program(s + 1); |
3343 | free(s); | 3462 | free(s); |
3344 | } | 3463 | } |
3345 | g_progname = "cmd. line"; | 3464 | g_progname = "cmd. line"; |
3346 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 3465 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |
3347 | while (list_e) { | 3466 | while (list_e) { |
3467 | /* NB: "move name one char back" trick in next_token | ||
3468 | * can use argv[i][-1] here. | ||
3469 | */ | ||
3348 | parse_program(llist_pop(&list_e)); | 3470 | parse_program(llist_pop(&list_e)); |
3349 | } | 3471 | } |
3350 | #endif | 3472 | #endif |
3351 | if (!(opt & (OPT_f | OPT_e))) { | 3473 | if (!(opt & (OPT_f | OPT_e))) { |
3352 | if (!*argv) | 3474 | if (!*argv) |
3353 | bb_show_usage(); | 3475 | bb_show_usage(); |
3476 | /* NB: "move name one char back" trick in next_token | ||
3477 | * can use argv[i][-1] here. | ||
3478 | */ | ||
3354 | parse_program(*argv++); | 3479 | parse_program(*argv++); |
3355 | } | 3480 | } |
3356 | 3481 | ||
@@ -3361,6 +3486,7 @@ int awk_main(int argc UNUSED_PARAM, char **argv) | |||
3361 | setari_u(intvar[ARGV], ++i, *argv++); | 3486 | setari_u(intvar[ARGV], ++i, *argv++); |
3362 | setvar_i(intvar[ARGC], i + 1); | 3487 | setvar_i(intvar[ARGC], i + 1); |
3363 | 3488 | ||
3489 | zero_out_var(&tv); | ||
3364 | evaluate(beginseq.first, &tv); | 3490 | evaluate(beginseq.first, &tv); |
3365 | if (!mainseq.first && !endseq.first) | 3491 | if (!mainseq.first && !endseq.first) |
3366 | awk_exit(EXIT_SUCCESS); | 3492 | awk_exit(EXIT_SUCCESS); |