aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-19 15:37:04 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-01-19 15:52:36 +0100
commit6aad1ddcc9d8fe2303cc444b6ddea2af1fc1dd30 (patch)
treefbcd71e78f202012724cf03c53a19ee60f76d8c7
parent7c44b600f9b2ca545421cb88147275e1351ba81f (diff)
downloadbusybox-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.c56
-rw-r--r--shell/hush_test/hush-vars/var_LINENO1.right8
-rwxr-xr-xshell/hush_test/hush-vars/var_LINENO1.tests6
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 {
612struct command { 613struct 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)
6520static void parse_and_run_file(FILE *f) 6551static 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 @@
12:2
23:3
34:4
45:5
52:2
63:3
74:4
85: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 @@
1env | grep LINENO
2echo 2:$LINENO
3echo 3:$LINENO >&2 \
4| { sleep 0.1; echo 4:$LINENO; }
5echo 5:$LINENO
6test "$1" || . ./var_LINENO1.tests norepeat