awk: more efficient -f FILE, document what "some trick in next_token" is

function                                             old     new   delta
awk_main                                             890     898      +8

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2021-06-25 19:38:27 +02:00
parent 53a7a9cd8c
commit 8c5da0323b

View File

@ -1217,6 +1217,8 @@ static uint32_t next_token(uint32_t expected)
if (!isalnum_(*p)) if (!isalnum_(*p))
syntax_error(EMSG_UNEXP_TOKEN); /* no */ syntax_error(EMSG_UNEXP_TOKEN); /* no */
/* yes */ /* yes */
/* "move name one char back" trick: we need a byte for NUL terminator */
/* NB: this results in argv[i][-1] being used (!!!) in e.g. "awk -e 'NAME'" case */
t_string = --p; t_string = --p;
while (isalnum_(*++p)) { while (isalnum_(*++p)) {
p[-1] = *p; p[-1] = *p;
@ -3345,7 +3347,7 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
llist_t *list_e = NULL; llist_t *list_e = NULL;
#endif #endif
int i, j; int i;
var *v; var *v;
var tv; var tv;
char **envp; char **envp;
@ -3417,30 +3419,43 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
bb_show_usage(); bb_show_usage();
} }
while (list_f) { while (list_f) {
char *s = NULL; int fd;
FILE *from_file; char *s;
g_progname = llist_pop(&list_f); g_progname = llist_pop(&list_f);
from_file = xfopen_stdin(g_progname); fd = xopen_stdin(g_progname);
/* one byte is reserved for some trick in next_token */ /* 1st byte is reserved for "move name one char back" trick in next_token */
for (i = j = 1; j > 0; i += j) { i = 1;
s = xrealloc(s, i + 4096); s = NULL;
j = fread(s + i, 1, 4094, from_file); for (;;) {
int sz;
s = xrealloc(s, i + 1000);
sz = safe_read(fd, s + i, 1000);
if (sz <= 0)
break;
i += sz;
} }
s = xrealloc(s, i + 1); /* trim unused 999 bytes */
s[i] = '\0'; s[i] = '\0';
fclose(from_file); close(fd);
parse_program(s + 1); parse_program(s + 1);
free(s); free(s);
} }
g_progname = "cmd. line"; g_progname = "cmd. line";
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
while (list_e) { while (list_e) {
/* NB: "move name one char back" trick in next_token
* can use argv[i][-1] here.
*/
parse_program(llist_pop(&list_e)); parse_program(llist_pop(&list_e));
} }
#endif #endif
if (!(opt & (OPT_f | OPT_e))) { if (!(opt & (OPT_f | OPT_e))) {
if (!*argv) if (!*argv)
bb_show_usage(); bb_show_usage();
/* NB: "move name one char back" trick in next_token
* can use argv[i][-1] here.
*/
parse_program(*argv++); parse_program(*argv++);
} }