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>
This commit is contained in:
parent
7c44b600f9
commit
6aad1ddcc9
56
shell/hush.c
56
shell/hush.c
@ -361,6 +361,7 @@
|
|||||||
#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
|
#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
|
#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
|
#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
|
||||||
|
#define BASH_LINENO_VAR ENABLE_HUSH_BASH_COMPAT
|
||||||
#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
|
#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
|
||||||
#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
|
#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
|
||||||
|
|
||||||
@ -612,6 +613,9 @@ typedef enum redir_type {
|
|||||||
struct command {
|
struct command {
|
||||||
pid_t pid; /* 0 if exited */
|
pid_t pid; /* 0 if exited */
|
||||||
int assignment_cnt; /* how many argv[i] are assignments? */
|
int assignment_cnt; /* how many argv[i] are assignments? */
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
unsigned lineno;
|
||||||
|
#endif
|
||||||
smallint cmd_type; /* CMD_xxx */
|
smallint cmd_type; /* CMD_xxx */
|
||||||
#define CMD_NORMAL 0
|
#define CMD_NORMAL 0
|
||||||
#define CMD_SUBSHELL 1
|
#define CMD_SUBSHELL 1
|
||||||
@ -930,6 +934,13 @@ struct globals {
|
|||||||
unsigned count_SIGCHLD;
|
unsigned count_SIGCHLD;
|
||||||
unsigned handled_SIGCHLD;
|
unsigned handled_SIGCHLD;
|
||||||
smallint we_have_children;
|
smallint we_have_children;
|
||||||
|
#endif
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
unsigned lineno;
|
||||||
|
char *lineno_var;
|
||||||
|
# define G_lineno_var G.lineno_var
|
||||||
|
#else
|
||||||
|
# define G_lineno_var ((char*)NULL)
|
||||||
#endif
|
#endif
|
||||||
struct FILE_list *FILE_list;
|
struct FILE_list *FILE_list;
|
||||||
/* Which signals have non-DFL handler (even with no traps set)?
|
/* Which signals have non-DFL handler (even with no traps set)?
|
||||||
@ -2135,6 +2146,13 @@ static int set_local_var(char *str, unsigned flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
name_len = eq_sign - str + 1; /* including '=' */
|
name_len = eq_sign - str + 1; /* including '=' */
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
if (G.lineno_var) {
|
||||||
|
if (name_len == 7 && strncmp("LINENO", str, 6) == 0)
|
||||||
|
G.lineno_var = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var_pp = &G.top_var;
|
var_pp = &G.top_var;
|
||||||
while ((cur = *var_pp) != NULL) {
|
while ((cur = *var_pp) != NULL) {
|
||||||
if (strncmp(cur->varstr, str, name_len) != 0) {
|
if (strncmp(cur->varstr, str, name_len) != 0) {
|
||||||
@ -2256,10 +2274,16 @@ static int unset_local_var_len(const char *name, int name_len)
|
|||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
#if ENABLE_HUSH_GETOPTS
|
#if ENABLE_HUSH_GETOPTS
|
||||||
if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
|
if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
|
||||||
G.getopt_count = 0;
|
G.getopt_count = 0;
|
||||||
#endif
|
#endif
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0)
|
||||||
|
G.lineno_var = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
var_pp = &G.top_var;
|
var_pp = &G.top_var;
|
||||||
while ((cur = *var_pp) != NULL) {
|
while ((cur = *var_pp) != NULL) {
|
||||||
if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
|
if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
|
||||||
@ -2578,6 +2602,10 @@ static int i_getch(struct in_str *i)
|
|||||||
out:
|
out:
|
||||||
debug_printf("file_get: got '%c' %d\n", ch, ch);
|
debug_printf("file_get: got '%c' %d\n", ch, ch);
|
||||||
i->last_char = ch;
|
i->last_char = ch;
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
if (ch == '\n')
|
||||||
|
G.lineno++;
|
||||||
|
#endif
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3460,6 +3488,9 @@ static int done_command(struct parse_context *ctx)
|
|||||||
ctx->command = command = &pi->cmds[pi->num_cmds];
|
ctx->command = command = &pi->cmds[pi->num_cmds];
|
||||||
clear_and_ret:
|
clear_and_ret:
|
||||||
memset(command, 0, sizeof(*command));
|
memset(command, 0, sizeof(*command));
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
command->lineno = G.lineno;
|
||||||
|
#endif
|
||||||
return pi->num_cmds; /* used only for 0/nonzero check */
|
return pi->num_cmds; /* used only for 0/nonzero check */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6520,8 +6551,13 @@ static void parse_and_run_string(const char *s)
|
|||||||
static void parse_and_run_file(FILE *f)
|
static void parse_and_run_file(FILE *f)
|
||||||
{
|
{
|
||||||
struct in_str input;
|
struct in_str input;
|
||||||
|
unsigned sv;
|
||||||
|
|
||||||
setup_file_in_str(&input, f);
|
setup_file_in_str(&input, f);
|
||||||
|
sv = G.lineno;
|
||||||
|
G.lineno = 1;
|
||||||
parse_and_run_stream(&input, ';');
|
parse_and_run_stream(&input, ';');
|
||||||
|
G.lineno = sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_HUSH_TICK
|
#if ENABLE_HUSH_TICK
|
||||||
@ -8068,6 +8104,9 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|||||||
char **new_env = NULL;
|
char **new_env = NULL;
|
||||||
struct variable *old_vars = NULL;
|
struct variable *old_vars = NULL;
|
||||||
|
|
||||||
|
if (G_lineno_var)
|
||||||
|
strcpy(G_lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
|
||||||
|
|
||||||
if (argv[command->assignment_cnt] == NULL) {
|
if (argv[command->assignment_cnt] == NULL) {
|
||||||
/* Assignments, but no command */
|
/* Assignments, but no command */
|
||||||
/* Ensure redirects take effect (that is, create files).
|
/* Ensure redirects take effect (that is, create files).
|
||||||
@ -8272,6 +8311,9 @@ static NOINLINE int run_pipe(struct pipe *pi)
|
|||||||
if (cmd_no < pi->num_cmds)
|
if (cmd_no < pi->num_cmds)
|
||||||
xpiped_pair(pipefds);
|
xpiped_pair(pipefds);
|
||||||
|
|
||||||
|
if (G_lineno_var)
|
||||||
|
strcpy(G_lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
|
||||||
|
|
||||||
command->pid = BB_MMU ? fork() : vfork();
|
command->pid = BB_MMU ? fork() : vfork();
|
||||||
if (!command->pid) { /* child */
|
if (!command->pid) { /* child */
|
||||||
#if ENABLE_HUSH_JOB
|
#if ENABLE_HUSH_JOB
|
||||||
@ -8907,17 +8949,19 @@ int hush_main(int argc, char **argv)
|
|||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
G.argv0_for_re_execing = argv[0];
|
G.argv0_for_re_execing = argv[0];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Deal with HUSH_VERSION */
|
/* Deal with HUSH_VERSION */
|
||||||
|
debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
|
||||||
|
unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
|
||||||
shell_ver = xzalloc(sizeof(*shell_ver));
|
shell_ver = xzalloc(sizeof(*shell_ver));
|
||||||
shell_ver->flg_export = 1;
|
shell_ver->flg_export = 1;
|
||||||
shell_ver->flg_read_only = 1;
|
shell_ver->flg_read_only = 1;
|
||||||
/* Code which handles ${var<op>...} needs writable values for all variables,
|
/* Code which handles ${var<op>...} needs writable values for all variables,
|
||||||
* therefore we xstrdup: */
|
* therefore we xstrdup: */
|
||||||
shell_ver->varstr = xstrdup(hush_version_str);
|
shell_ver->varstr = xstrdup(hush_version_str);
|
||||||
|
|
||||||
/* Create shell local variables from the values
|
/* Create shell local variables from the values
|
||||||
* currently living in the environment */
|
* currently living in the environment */
|
||||||
debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
|
|
||||||
unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
|
|
||||||
G.top_var = shell_ver;
|
G.top_var = shell_ver;
|
||||||
cur_var = G.top_var;
|
cur_var = G.top_var;
|
||||||
e = environ;
|
e = environ;
|
||||||
@ -8983,6 +9027,14 @@ int hush_main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if BASH_LINENO_VAR
|
||||||
|
if (BASH_LINENO_VAR) {
|
||||||
|
char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), "");
|
||||||
|
set_local_var(p, /*flags*/ 0);
|
||||||
|
G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLE_FEATURE_EDITING
|
#if ENABLE_FEATURE_EDITING
|
||||||
G.line_input_state = new_line_input_t(FOR_SHELL);
|
G.line_input_state = new_line_input_t(FOR_SHELL);
|
||||||
#endif
|
#endif
|
||||||
|
8
shell/hush_test/hush-vars/var_LINENO1.right
Normal file
8
shell/hush_test/hush-vars/var_LINENO1.right
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
2:2
|
||||||
|
3:3
|
||||||
|
4:4
|
||||||
|
5:5
|
||||||
|
2:2
|
||||||
|
3:3
|
||||||
|
4:4
|
||||||
|
5:5
|
6
shell/hush_test/hush-vars/var_LINENO1.tests
Executable file
6
shell/hush_test/hush-vars/var_LINENO1.tests
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
env | grep LINENO
|
||||||
|
echo 2:$LINENO
|
||||||
|
echo 3:$LINENO >&2 \
|
||||||
|
| { sleep 0.1; echo 4:$LINENO; }
|
||||||
|
echo 5:$LINENO
|
||||||
|
test "$1" || . ./var_LINENO1.tests norepeat
|
Loading…
Reference in New Issue
Block a user