diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-19 15:37:04 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-19 15:52:36 +0100 |
commit | 6aad1ddcc9d8fe2303cc444b6ddea2af1fc1dd30 (patch) | |
tree | fbcd71e78f202012724cf03c53a19ee60f76d8c7 | |
parent | 7c44b600f9b2ca545421cb88147275e1351ba81f (diff) | |
download | busybox-w32-6aad1ddcc9d8fe2303cc444b6ddea2af1fc1dd30.tar.gz busybox-w32-6aad1ddcc9d8fe2303cc444b6ddea2af1fc1dd30.tar.bz2 busybox-w32-6aad1ddcc9d8fe2303cc444b6ddea2af1fc1dd30.zip |
hush: implement $LINENO bashism
function old new delta
run_pipe 1697 1774 +77
unset_local_var_len 258 301 +43
hush_main 1009 1051 +42
set_local_var 516 554 +38
parse_and_run_file 42 75 +33
i_getch 96 116 +20
.rodata 18858 18876 +18
done_command 106 122 +16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 8/0 up/down: 287/0) Total: 287 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 56 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_LINENO1.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_LINENO1.tests | 6 |
3 files changed, 68 insertions, 2 deletions
diff --git a/shell/hush.c b/shell/hush.c index 79d7a53dd..8ba48de95 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -361,6 +361,7 @@ | |||
361 | #define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT | 361 | #define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT |
362 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT | 362 | #define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT |
363 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT | 363 | #define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT |
364 | #define BASH_LINENO_VAR ENABLE_HUSH_BASH_COMPAT | ||
364 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | 365 | #define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) |
365 | #define BASH_READ_D ENABLE_HUSH_BASH_COMPAT | 366 | #define BASH_READ_D ENABLE_HUSH_BASH_COMPAT |
366 | 367 | ||
@@ -612,6 +613,9 @@ typedef enum redir_type { | |||
612 | struct command { | 613 | struct command { |
613 | pid_t pid; /* 0 if exited */ | 614 | pid_t pid; /* 0 if exited */ |
614 | int assignment_cnt; /* how many argv[i] are assignments? */ | 615 | int assignment_cnt; /* how many argv[i] are assignments? */ |
616 | #if BASH_LINENO_VAR | ||
617 | unsigned lineno; | ||
618 | #endif | ||
615 | smallint cmd_type; /* CMD_xxx */ | 619 | smallint cmd_type; /* CMD_xxx */ |
616 | #define CMD_NORMAL 0 | 620 | #define CMD_NORMAL 0 |
617 | #define CMD_SUBSHELL 1 | 621 | #define CMD_SUBSHELL 1 |
@@ -931,6 +935,13 @@ struct globals { | |||
931 | unsigned handled_SIGCHLD; | 935 | unsigned handled_SIGCHLD; |
932 | smallint we_have_children; | 936 | smallint we_have_children; |
933 | #endif | 937 | #endif |
938 | #if BASH_LINENO_VAR | ||
939 | unsigned lineno; | ||
940 | char *lineno_var; | ||
941 | # define G_lineno_var G.lineno_var | ||
942 | #else | ||
943 | # define G_lineno_var ((char*)NULL) | ||
944 | #endif | ||
934 | struct FILE_list *FILE_list; | 945 | struct FILE_list *FILE_list; |
935 | /* Which signals have non-DFL handler (even with no traps set)? | 946 | /* Which signals have non-DFL handler (even with no traps set)? |
936 | * Set at the start to: | 947 | * Set at the start to: |
@@ -2135,6 +2146,13 @@ static int set_local_var(char *str, unsigned flags) | |||
2135 | } | 2146 | } |
2136 | 2147 | ||
2137 | name_len = eq_sign - str + 1; /* including '=' */ | 2148 | name_len = eq_sign - str + 1; /* including '=' */ |
2149 | #if BASH_LINENO_VAR | ||
2150 | if (G.lineno_var) { | ||
2151 | if (name_len == 7 && strncmp("LINENO", str, 6) == 0) | ||
2152 | G.lineno_var = NULL; | ||
2153 | } | ||
2154 | #endif | ||
2155 | |||
2138 | var_pp = &G.top_var; | 2156 | var_pp = &G.top_var; |
2139 | while ((cur = *var_pp) != NULL) { | 2157 | while ((cur = *var_pp) != NULL) { |
2140 | if (strncmp(cur->varstr, str, name_len) != 0) { | 2158 | if (strncmp(cur->varstr, str, name_len) != 0) { |
@@ -2256,10 +2274,16 @@ static int unset_local_var_len(const char *name, int name_len) | |||
2256 | 2274 | ||
2257 | if (!name) | 2275 | if (!name) |
2258 | return EXIT_SUCCESS; | 2276 | return EXIT_SUCCESS; |
2277 | |||
2259 | #if ENABLE_HUSH_GETOPTS | 2278 | #if ENABLE_HUSH_GETOPTS |
2260 | if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0) | 2279 | if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0) |
2261 | G.getopt_count = 0; | 2280 | G.getopt_count = 0; |
2262 | #endif | 2281 | #endif |
2282 | #if BASH_LINENO_VAR | ||
2283 | if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0) | ||
2284 | G.lineno_var = NULL; | ||
2285 | #endif | ||
2286 | |||
2263 | var_pp = &G.top_var; | 2287 | var_pp = &G.top_var; |
2264 | while ((cur = *var_pp) != NULL) { | 2288 | while ((cur = *var_pp) != NULL) { |
2265 | if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { | 2289 | if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { |
@@ -2578,6 +2602,10 @@ static int i_getch(struct in_str *i) | |||
2578 | out: | 2602 | out: |
2579 | debug_printf("file_get: got '%c' %d\n", ch, ch); | 2603 | debug_printf("file_get: got '%c' %d\n", ch, ch); |
2580 | i->last_char = ch; | 2604 | i->last_char = ch; |
2605 | #if BASH_LINENO_VAR | ||
2606 | if (ch == '\n') | ||
2607 | G.lineno++; | ||
2608 | #endif | ||
2581 | return ch; | 2609 | return ch; |
2582 | } | 2610 | } |
2583 | 2611 | ||
@@ -3460,6 +3488,9 @@ static int done_command(struct parse_context *ctx) | |||
3460 | ctx->command = command = &pi->cmds[pi->num_cmds]; | 3488 | ctx->command = command = &pi->cmds[pi->num_cmds]; |
3461 | clear_and_ret: | 3489 | clear_and_ret: |
3462 | memset(command, 0, sizeof(*command)); | 3490 | memset(command, 0, sizeof(*command)); |
3491 | #if BASH_LINENO_VAR | ||
3492 | command->lineno = G.lineno; | ||
3493 | #endif | ||
3463 | return pi->num_cmds; /* used only for 0/nonzero check */ | 3494 | return pi->num_cmds; /* used only for 0/nonzero check */ |
3464 | } | 3495 | } |
3465 | 3496 | ||
@@ -6520,8 +6551,13 @@ static void parse_and_run_string(const char *s) | |||
6520 | static void parse_and_run_file(FILE *f) | 6551 | static void parse_and_run_file(FILE *f) |
6521 | { | 6552 | { |
6522 | struct in_str input; | 6553 | struct in_str input; |
6554 | unsigned sv; | ||
6555 | |||
6523 | setup_file_in_str(&input, f); | 6556 | setup_file_in_str(&input, f); |
6557 | sv = G.lineno; | ||
6558 | G.lineno = 1; | ||
6524 | parse_and_run_stream(&input, ';'); | 6559 | parse_and_run_stream(&input, ';'); |
6560 | G.lineno = sv; | ||
6525 | } | 6561 | } |
6526 | 6562 | ||
6527 | #if ENABLE_HUSH_TICK | 6563 | #if ENABLE_HUSH_TICK |
@@ -8068,6 +8104,9 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
8068 | char **new_env = NULL; | 8104 | char **new_env = NULL; |
8069 | struct variable *old_vars = NULL; | 8105 | struct variable *old_vars = NULL; |
8070 | 8106 | ||
8107 | if (G_lineno_var) | ||
8108 | strcpy(G_lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); | ||
8109 | |||
8071 | if (argv[command->assignment_cnt] == NULL) { | 8110 | if (argv[command->assignment_cnt] == NULL) { |
8072 | /* Assignments, but no command */ | 8111 | /* Assignments, but no command */ |
8073 | /* Ensure redirects take effect (that is, create files). | 8112 | /* Ensure redirects take effect (that is, create files). |
@@ -8272,6 +8311,9 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
8272 | if (cmd_no < pi->num_cmds) | 8311 | if (cmd_no < pi->num_cmds) |
8273 | xpiped_pair(pipefds); | 8312 | xpiped_pair(pipefds); |
8274 | 8313 | ||
8314 | if (G_lineno_var) | ||
8315 | strcpy(G_lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); | ||
8316 | |||
8275 | command->pid = BB_MMU ? fork() : vfork(); | 8317 | command->pid = BB_MMU ? fork() : vfork(); |
8276 | if (!command->pid) { /* child */ | 8318 | if (!command->pid) { /* child */ |
8277 | #if ENABLE_HUSH_JOB | 8319 | #if ENABLE_HUSH_JOB |
@@ -8907,17 +8949,19 @@ int hush_main(int argc, char **argv) | |||
8907 | #if !BB_MMU | 8949 | #if !BB_MMU |
8908 | G.argv0_for_re_execing = argv[0]; | 8950 | G.argv0_for_re_execing = argv[0]; |
8909 | #endif | 8951 | #endif |
8952 | |||
8910 | /* Deal with HUSH_VERSION */ | 8953 | /* Deal with HUSH_VERSION */ |
8954 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | ||
8955 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ | ||
8911 | shell_ver = xzalloc(sizeof(*shell_ver)); | 8956 | shell_ver = xzalloc(sizeof(*shell_ver)); |
8912 | shell_ver->flg_export = 1; | 8957 | shell_ver->flg_export = 1; |
8913 | shell_ver->flg_read_only = 1; | 8958 | shell_ver->flg_read_only = 1; |
8914 | /* Code which handles ${var<op>...} needs writable values for all variables, | 8959 | /* Code which handles ${var<op>...} needs writable values for all variables, |
8915 | * therefore we xstrdup: */ | 8960 | * therefore we xstrdup: */ |
8916 | shell_ver->varstr = xstrdup(hush_version_str); | 8961 | shell_ver->varstr = xstrdup(hush_version_str); |
8962 | |||
8917 | /* Create shell local variables from the values | 8963 | /* Create shell local variables from the values |
8918 | * currently living in the environment */ | 8964 | * currently living in the environment */ |
8919 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | ||
8920 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ | ||
8921 | G.top_var = shell_ver; | 8965 | G.top_var = shell_ver; |
8922 | cur_var = G.top_var; | 8966 | cur_var = G.top_var; |
8923 | e = environ; | 8967 | e = environ; |
@@ -8983,6 +9027,14 @@ int hush_main(int argc, char **argv) | |||
8983 | */ | 9027 | */ |
8984 | #endif | 9028 | #endif |
8985 | 9029 | ||
9030 | #if BASH_LINENO_VAR | ||
9031 | if (BASH_LINENO_VAR) { | ||
9032 | char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), ""); | ||
9033 | set_local_var(p, /*flags*/ 0); | ||
9034 | G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */ | ||
9035 | } | ||
9036 | #endif | ||
9037 | |||
8986 | #if ENABLE_FEATURE_EDITING | 9038 | #if ENABLE_FEATURE_EDITING |
8987 | G.line_input_state = new_line_input_t(FOR_SHELL); | 9039 | G.line_input_state = new_line_input_t(FOR_SHELL); |
8988 | #endif | 9040 | #endif |
diff --git a/shell/hush_test/hush-vars/var_LINENO1.right b/shell/hush_test/hush-vars/var_LINENO1.right new file mode 100644 index 000000000..31e1a4478 --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO1.right | |||
@@ -0,0 +1,8 @@ | |||
1 | 2:2 | ||
2 | 3:3 | ||
3 | 4:4 | ||
4 | 5:5 | ||
5 | 2:2 | ||
6 | 3:3 | ||
7 | 4:4 | ||
8 | 5:5 | ||
diff --git a/shell/hush_test/hush-vars/var_LINENO1.tests b/shell/hush_test/hush-vars/var_LINENO1.tests new file mode 100755 index 000000000..851b52cf5 --- /dev/null +++ b/shell/hush_test/hush-vars/var_LINENO1.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | env | grep LINENO | ||
2 | echo 2:$LINENO | ||
3 | echo 3:$LINENO >&2 \ | ||
4 | | { sleep 0.1; echo 4:$LINENO; } | ||
5 | echo 5:$LINENO | ||
6 | test "$1" || . ./var_LINENO1.tests norepeat | ||