od_bloaty: fix debug code
[oweals/busybox.git] / shell / hush.c
index fc8940d3d1083d78fd4d6c4b04446ad3b4be65aa..7b83c736c1ec8e77632be08d8226f9c58496ebd6 100644 (file)
 #define BASH_SUBSTR        ENABLE_HUSH_BASH_COMPAT
 #define BASH_SOURCE        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_READ_D        ENABLE_HUSH_BASH_COMPAT
 
@@ -612,6 +613,9 @@ typedef enum redir_type {
 struct command {
        pid_t pid;                  /* 0 if exited */
        int assignment_cnt;         /* how many argv[i] are assignments? */
+#if BASH_LINENO_VAR
+       unsigned lineno;
+#endif
        smallint cmd_type;          /* CMD_xxx */
 #define CMD_NORMAL   0
 #define CMD_SUBSHELL 1
@@ -930,6 +934,10 @@ struct globals {
        unsigned count_SIGCHLD;
        unsigned handled_SIGCHLD;
        smallint we_have_children;
+#endif
+#if BASH_LINENO_VAR
+       unsigned lineno;
+       char *lineno_var;
 #endif
        struct FILE_list *FILE_list;
        /* Which signals have non-DFL handler (even with no traps set)?
@@ -1928,7 +1936,7 @@ static void hush_exit(int exitcode)
        if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
                char *argv[3];
                /* argv[0] is unused */
-               argv[1] = G_traps[0];
+               argv[1] = xstrdup(G_traps[0]); /* copy, since EXIT trap handler may modify G_traps[0] */
                argv[2] = NULL;
                G.exiting = 1; /* prevent EXIT trap recursion */
                /* Note: G_traps[0] is not cleared!
@@ -2135,6 +2143,13 @@ static int set_local_var(char *str, unsigned flags)
        }
 
        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;
        while ((cur = *var_pp) != NULL) {
                if (strncmp(cur->varstr, str, name_len) != 0) {
@@ -2256,10 +2271,16 @@ static int unset_local_var_len(const char *name, int name_len)
 
        if (!name)
                return EXIT_SUCCESS;
+
 #if ENABLE_HUSH_GETOPTS
        if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
                G.getopt_count = 0;
 #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;
        while ((cur = *var_pp) != NULL) {
                if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
@@ -2578,6 +2599,10 @@ static int i_getch(struct in_str *i)
  out:
        debug_printf("file_get: got '%c' %d\n", ch, ch);
        i->last_char = ch;
+#if BASH_LINENO_VAR
+       if (ch == '\n')
+               G.lineno++;
+#endif
        return ch;
 }
 
@@ -3460,6 +3485,9 @@ static int done_command(struct parse_context *ctx)
        ctx->command = command = &pi->cmds[pi->num_cmds];
  clear_and_ret:
        memset(command, 0, sizeof(*command));
+#if BASH_LINENO_VAR
+       command->lineno = G.lineno;
+#endif
        return pi->num_cmds; /* used only for 0/nonzero check */
 }
 
@@ -5225,6 +5253,11 @@ static struct pipe *parse_stream(char **pstring,
                                        nommu_addchr(&ctx.as_string, ch);
                                        if (ch == '\'')
                                                break;
+                                       if (ch == SPECIAL_VAR_SYMBOL) {
+                                               /* Convert raw ^C to corresponding special variable reference */
+                                               o_addchr(&dest, SPECIAL_VAR_SYMBOL);
+                                               o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS);
+                                       }
                                        o_addqchr(&dest, ch);
                                }
                        }
@@ -6515,8 +6548,17 @@ static void parse_and_run_string(const char *s)
 static void parse_and_run_file(FILE *f)
 {
        struct in_str input;
+#if BASH_LINENO_VAR
+       unsigned sv;
+
+       sv = G.lineno;
+       G.lineno = 1;
+#endif
        setup_file_in_str(&input, f);
        parse_and_run_stream(&input, ';');
+#if BASH_LINENO_VAR
+       G.lineno = sv;
+#endif
 }
 
 #if ENABLE_HUSH_TICK
@@ -8063,6 +8105,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
                char **new_env = NULL;
                struct variable *old_vars = NULL;
 
+#if BASH_LINENO_VAR
+               if (G.lineno_var)
+                       strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
+#endif
+
                if (argv[command->assignment_cnt] == NULL) {
                        /* Assignments, but no command */
                        /* Ensure redirects take effect (that is, create files).
@@ -8267,6 +8314,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
                if (cmd_no < pi->num_cmds)
                        xpiped_pair(pipefds);
 
+#if BASH_LINENO_VAR
+               if (G.lineno_var)
+                       strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
+#endif
+
                command->pid = BB_MMU ? fork() : vfork();
                if (!command->pid) { /* child */
 #if ENABLE_HUSH_JOB
@@ -8902,17 +8954,19 @@ int hush_main(int argc, char **argv)
 #if !BB_MMU
        G.argv0_for_re_execing = argv[0];
 #endif
+
        /* 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->flg_export = 1;
        shell_ver->flg_read_only = 1;
        /* Code which handles ${var<op>...} needs writable values for all variables,
         * therefore we xstrdup: */
        shell_ver->varstr = xstrdup(hush_version_str);
+
        /* Create shell local variables from the values
         * 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;
        cur_var = G.top_var;
        e = environ;
@@ -8978,6 +9032,14 @@ int hush_main(int argc, char **argv)
         */
 #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
        G.line_input_state = new_line_input_t(FOR_SHELL);
 #endif