hush: use G.xxx instead of #define xxx G.xxx. We have too many globals
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 29 Jul 2008 19:43:10 +0000 (19:43 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 29 Jul 2008 19:43:10 +0000 (19:43 -0000)
 there and #defines get messy. Remove one write-only G.variable.

shell/hush.c

index f65405563b2c3ed1b1acded6c6ebfd558d862e67..b471bd845f1e6cdfde26a2000f646582381bfe6f 100644 (file)
@@ -427,9 +427,10 @@ struct globals {
        line_input_t *line_input_state;
 #endif
        pid_t root_pid;
+       pid_t last_bg_pid;
 #if ENABLE_HUSH_JOB
        int run_list_level;
-       pid_t saved_task_pgrp;
+//     pid_t saved_task_pgrp;
        pid_t saved_tty_pgrp;
        int last_jobid;
        struct pipe *job_list;
@@ -448,10 +449,9 @@ struct globals {
        unsigned depth_break_continue;
        unsigned depth_of_loop;
 #endif
-       pid_t last_bg_pid;
        const char *ifs;
        const char *cwd;
-       struct variable *top_var; /* = &shell_ver (set in main()) */
+       struct variable *top_var; /* = &G.shell_ver (set in main()) */
        struct variable shell_ver;
 #if ENABLE_FEATURE_SH_STANDALONE
        struct nofork_save_area nofork_save;
@@ -464,53 +464,9 @@ struct globals {
 };
 
 #define G (*ptr_to_globals)
-
-#if !ENABLE_HUSH_INTERACTIVE
-enum { interactive_fd = 0 };
-#endif
-#if !ENABLE_HUSH_JOB
-enum { run_list_level = 0 };
-#endif
-
-#if ENABLE_HUSH_INTERACTIVE
-#define interactive_fd   (G.interactive_fd  )
-#define PS1              (G.PS1             )
-#define PS2              (G.PS2             )
-#endif
-#if ENABLE_FEATURE_EDITING
-#define line_input_state (G.line_input_state)
-#endif
-#define root_pid         (G.root_pid        )
-#if ENABLE_HUSH_JOB
-#define run_list_level   (G.run_list_level  )
-#define saved_task_pgrp  (G.saved_task_pgrp )
-#define saved_tty_pgrp   (G.saved_tty_pgrp  )
-#define last_jobid       (G.last_jobid      )
-#define job_list         (G.job_list        )
-#define toplevel_list    (G.toplevel_list   )
-#define toplevel_jb      (G.toplevel_jb     )
-#define ctrl_z_flag      (G.ctrl_z_flag     )
-#endif /* JOB */
-#define global_argv      (G.global_argv     )
-#define global_argc      (G.global_argc     )
-#define last_return_code (G.last_return_code)
-#define ifs              (G.ifs             )
-#define flag_break_continue  (G.flag_break_continue )
-#define depth_break_continue (G.depth_break_continue)
-#define depth_of_loop    (G.depth_of_loop   )
-#define fake_mode        (G.fake_mode       )
-#define cwd              (G.cwd             )
-#define last_bg_pid      (G.last_bg_pid     )
-#define top_var          (G.top_var         )
-#define shell_ver        (G.shell_ver       )
-#if ENABLE_FEATURE_SH_STANDALONE
-#define nofork_save      (G.nofork_save     )
-#endif
-#if ENABLE_HUSH_JOB
-#define toplevel_jb      (G.toplevel_jb     )
-#endif
-#define charmap          (G.charmap         )
-#define user_input_buf   (G.user_input_buf  )
+/* Not #defining name to G.name - this quickly gets unwieldy
+ * (too many defines). Also, I actually prefer to see when a variable
+ * is global, thus "G." prefix is a useful hint */
 #define INIT_G() do { \
        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 } while (0)
@@ -522,23 +478,29 @@ enum { run_list_level = 0 };
 /* Normal */
 static void syntax(const char *msg)
 {
+#if ENABLE_HUSH_INTERACTIVE
        /* Was using fancy stuff:
-        * (interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...)
+        * (G.interactive_fd ? bb_error_msg : bb_error_msg_and_die)(...params...)
         * but it SEGVs. ?! Oh well... explicit temp ptr works around that */
        void FAST_FUNC (*fp)(const char *s, ...);
-
-       fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
+       fp = (G.interactive_fd ? bb_error_msg : bb_error_msg_and_die);
        fp(msg ? "%s: %s" : "syntax error", "syntax error", msg);
+#else
+       bb_error_msg_and_die(msg ? "%s: %s" : "syntax error", "syntax error", msg);
+#endif
 }
 
 #else
 /* Debug */
 static void syntax_lineno(int line)
 {
+#if ENABLE_HUSH_INTERACTIVE
        void FAST_FUNC (*fp)(const char *s, ...);
-
-       fp = (interactive_fd ? bb_error_msg : bb_error_msg_and_die);
+       fp = (G.interactive_fd ? bb_error_msg : bb_error_msg_and_die);
        fp("syntax error hush.c:%d", line);
+#else
+       bb_error_msg_and_die("syntax error hush.c:%d", line);
+#endif
 }
 #define syntax(str) syntax_lineno(__LINE__)
 #endif
@@ -844,7 +806,7 @@ static void handler_ctrl_c(int sig UNUSED_PARAM)
 {
        debug_printf_jobs("got sig %d\n", sig);
 // as usual we can have all kinds of nasty problems with leaked malloc data here
-       siglongjmp(toplevel_jb, 1);
+       siglongjmp(G.toplevel_jb, 1);
 }
 
 static void handler_ctrl_z(int sig UNUSED_PARAM)
@@ -855,7 +817,7 @@ static void handler_ctrl_z(int sig UNUSED_PARAM)
        pid = fork();
        if (pid < 0) /* can't fork. Pretend there was no ctrl-Z */
                return;
-       ctrl_z_flag = 1;
+       G.ctrl_z_flag = 1;
        if (!pid) { /* child */
                if (ENABLE_HUSH_JOB)
                        die_sleep = 0; /* let nofork's xfuncs die */
@@ -870,13 +832,13 @@ static void handler_ctrl_z(int sig UNUSED_PARAM)
        }
        /* parent */
        /* finish filling up pipe info */
-       toplevel_list->pgrp = pid; /* child is in its own pgrp */
-       toplevel_list->progs[0].pid = pid;
+       G.toplevel_list->pgrp = pid; /* child is in its own pgrp */
+       G.toplevel_list->progs[0].pid = pid;
        /* parent needs to longjmp out of running nofork.
         * we will "return" exitcode 0, with child put in background */
 // as usual we can have all kinds of nasty problems with leaked malloc data here
        debug_printf_jobs("siglongjmp in parent\n");
-       siglongjmp(toplevel_jb, 1);
+       siglongjmp(G.toplevel_jb, 1);
 }
 
 /* Restores tty foreground process group, and exits.
@@ -890,8 +852,10 @@ static void sigexit(int sig)
        /* Disable all signals: job control, SIGPIPE, etc. */
        sigprocmask_allsigs(SIG_BLOCK);
 
-       if (interactive_fd)
-               tcsetpgrp(interactive_fd, saved_tty_pgrp);
+#if ENABLE_HUSH_INTERACTIVE
+       if (G.interactive_fd)
+               tcsetpgrp(G.interactive_fd, G.saved_tty_pgrp);
+#endif
 
        /* Not a signal, just exit */
        if (sig <= 0)
@@ -919,12 +883,12 @@ static void hush_exit(int exitcode)
 
 static const char *set_cwd(void)
 {
-       if (cwd == bb_msg_unknown)
-               cwd = NULL;     /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */
-       cwd = xrealloc_getcwd_or_warn((char *)cwd);
-       if (!cwd)
-               cwd = bb_msg_unknown;
-       return cwd;
+       if (G.cwd == bb_msg_unknown)
+               G.cwd = NULL;     /* xrealloc_getcwd_or_warn(arg) calls free(arg)! */
+       G.cwd = xrealloc_getcwd_or_warn((char *)G.cwd);
+       if (!G.cwd)
+               G.cwd = bb_msg_unknown;
+       return G.cwd;
 }
 
 
@@ -1224,11 +1188,11 @@ static int static_peek(struct in_str *i)
 static void cmdedit_set_initial_prompt(void)
 {
 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
-       PS1 = NULL;
+       G.PS1 = NULL;
 #else
-       PS1 = getenv("PS1");
-       if (PS1 == NULL)
-               PS1 = "\\w \\$ ";
+       G.PS1 = getenv("PS1");
+       if (G.PS1 == NULL)
+               G.PS1 = "\\w \\$ ";
 #endif
 }
 #endif /* EDITING */
@@ -1240,14 +1204,14 @@ static const char* setup_prompt_string(int promptmode)
 #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT
        /* Set up the prompt */
        if (promptmode == 0) { /* PS1 */
-               free((char*)PS1);
-               PS1 = xasprintf("%s %c ", cwd, (geteuid() != 0) ? '$' : '#');
-               prompt_str = PS1;
+               free((char*)G.PS1);
+               G.PS1 = xasprintf("%s %c ", G.cwd, (geteuid() != 0) ? '$' : '#');
+               prompt_str = G.PS1;
        } else {
-               prompt_str = PS2;
+               prompt_str = G.PS2;
        }
 #else
-       prompt_str = (promptmode == 0) ? PS1 : PS2;
+       prompt_str = (promptmode == 0) ? G.PS1 : G.PS2;
 #endif
        debug_printf("result '%s'\n", prompt_str);
        return prompt_str;
@@ -1263,21 +1227,21 @@ static void get_user_input(struct in_str *i)
        /* Enable command line editing only while a command line
         * is actually being read */
        do {
-               r = read_line_input(prompt_str, user_input_buf, BUFSIZ-1, line_input_state);
+               r = read_line_input(prompt_str, G.user_input_buf, BUFSIZ-1, G.line_input_state);
        } while (r == 0); /* repeat if Ctrl-C */
        i->eof_flag = (r < 0);
        if (i->eof_flag) { /* EOF/error detected */
-               user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
-               user_input_buf[1] = '\0';
+               G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */
+               G.user_input_buf[1] = '\0';
        }
 #else
        fputs(prompt_str, stdout);
        fflush(stdout);
-       user_input_buf[0] = r = fgetc(i->file);
-       /*user_input_buf[1] = '\0'; - already is and never changed */
+       G.user_input_buf[0] = r = fgetc(i->file);
+       /*G.user_input_buf[1] = '\0'; - already is and never changed */
        i->eof_flag = (r == EOF);
 #endif
-       i->p = user_input_buf;
+       i->p = G.user_input_buf;
 }
 
 #endif  /* INTERACTIVE */
@@ -1300,7 +1264,7 @@ static int file_get(struct in_str *i)
                /* need to double check i->file because we might be doing something
                 * more complicated by now, like sourcing or substituting. */
 #if ENABLE_HUSH_INTERACTIVE
-               if (interactive_fd && i->promptme && i->file == stdin) {
+               if (G.interactive_fd && i->promptme && i->file == stdin) {
                        do {
                                get_user_input(i);
                        } while (!*i->p); /* need non-empty line */
@@ -1561,15 +1525,15 @@ static void insert_bg_job(struct pipe *pi)
 
        /* Linear search for the ID of the job to use */
        pi->jobid = 1;
-       for (thejob = job_list; thejob; thejob = thejob->next)
+       for (thejob = G.job_list; thejob; thejob = thejob->next)
                if (thejob->jobid >= pi->jobid)
                        pi->jobid = thejob->jobid + 1;
 
        /* Add thejob to the list of running jobs */
-       if (!job_list) {
-               thejob = job_list = xmalloc(sizeof(*thejob));
+       if (!G.job_list) {
+               thejob = G.job_list = xmalloc(sizeof(*thejob));
        } else {
-               for (thejob = job_list; thejob->next; thejob = thejob->next)
+               for (thejob = G.job_list; thejob->next; thejob = thejob->next)
                        continue;
                thejob->next = xmalloc(sizeof(*thejob));
                thejob = thejob->next;
@@ -1591,26 +1555,26 @@ static void insert_bg_job(struct pipe *pi)
        /* We don't wait for background thejobs to return -- append it
           to the list of backgrounded thejobs and leave it alone */
        printf("[%d] %d %s\n", thejob->jobid, thejob->progs[0].pid, thejob->cmdtext);
-       last_bg_pid = thejob->progs[0].pid;
-       last_jobid = thejob->jobid;
+       G.last_bg_pid = thejob->progs[0].pid;
+       G.last_jobid = thejob->jobid;
 }
 
 static void remove_bg_job(struct pipe *pi)
 {
        struct pipe *prev_pipe;
 
-       if (pi == job_list) {
-               job_list = pi->next;
+       if (pi == G.job_list) {
+               G.job_list = pi->next;
        } else {
-               prev_pipe = job_list;
+               prev_pipe = G.job_list;
                while (prev_pipe->next != pi)
                        prev_pipe = prev_pipe->next;
                prev_pipe->next = pi->next;
        }
-       if (job_list)
-               last_jobid = job_list->jobid;
+       if (G.job_list)
+               G.last_jobid = G.job_list->jobid;
        else
-               last_jobid = 0;
+               G.last_jobid = 0;
 }
 
 /* Remove a backgrounded job */
@@ -1705,7 +1669,7 @@ static int checkjobs(struct pipe* fg_pipe)
 #if ENABLE_HUSH_JOB
                /* We asked to wait for bg or orphaned children */
                /* No need to remember exitcode in this case */
-               for (pi = job_list; pi; pi = pi->next) {
+               for (pi = G.job_list; pi; pi = pi->next) {
                        for (i = 0; i < pi->num_progs; i++) {
                                if (pi->progs[i].pid == childpid)
                                        goto found_pi_and_prognum;
@@ -1748,8 +1712,8 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
        /* Job finished, move the shell to the foreground */
        p = getpgid(0); /* pgid of our process */
        debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p);
-       tcsetpgrp(interactive_fd, p);
-//     if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY)
+       tcsetpgrp(G.interactive_fd, p);
+//     if (tcsetpgrp(G.interactive_fd, p) && errno != ENOTTY)
 //             bb_perror_msg("tcsetpgrp-4a");
        return rcode;
 }
@@ -1865,9 +1829,9 @@ static int run_pipe(struct pipe *pi)
                        int a = find_applet_by_name(argv_expanded[0]);
                        if (a >= 0 && APPLET_IS_NOFORK(a)) {
                                setup_redirects(child, squirrel);
-                               save_nofork_data(&nofork_save);
+                               save_nofork_data(&G.nofork_save);
                                debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
-                               rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
+                               rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded);
                                free(argv_expanded);
                                restore_redirects(squirrel);
                                debug_printf_exec("run_pipe return %d\n", rcode);
@@ -1916,7 +1880,7 @@ static int run_pipe(struct pipe *pi)
 #if ENABLE_HUSH_JOB
                        /* Every child adds itself to new process group
                         * with pgid == pid_of_first_child_in_pipe */
-                       if (run_list_level == 1 && interactive_fd) {
+                       if (G.run_list_level == 1 && G.interactive_fd) {
                                pid_t pgrp;
                                /* Don't do pgrp restore anymore on fatal signals */
                                set_fatal_sighandler(SIG_DFL);
@@ -1926,7 +1890,7 @@ static int run_pipe(struct pipe *pi)
                                if (setpgid(0, pgrp) == 0 && pi->followup != PIPE_BG) {
                                        /* We do it in *every* child, not just first,
                                         * to avoid races */
-                                       tcsetpgrp(interactive_fd, pgrp);
+                                       tcsetpgrp(G.interactive_fd, pgrp);
                                }
                        }
 #endif
@@ -2072,7 +2036,7 @@ static int run_list(struct pipe *pi)
        /*enum reserved_style*/ smallint rword = RES_NONE;
        /*enum reserved_style*/ smallint skip_more_for_this_rword = RES_XXXX;
 
-       debug_printf_exec("run_list start lvl %d\n", run_list_level + 1);
+       debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1);
 
 #if ENABLE_HUSH_LOOPS
        /* Check syntax for "for" */
@@ -2082,7 +2046,7 @@ static int run_list(struct pipe *pi)
                /* current word is FOR or IN (BOLD in comments below) */
                if (cpipe->next == NULL) {
                        syntax("malformed for");
-                       debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
+                       debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
                        return 1;
                }
                /* "FOR v; do ..." and "for v IN a b; do..." are ok */
@@ -2093,7 +2057,7 @@ static int run_list(struct pipe *pi)
                 || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */
                ) {
                        syntax("malformed for");
-                       debug_printf_exec("run_list lvl %d return 1\n", run_list_level);
+                       debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
                        return 1;
                }
        }
@@ -2108,22 +2072,22 @@ static int run_list(struct pipe *pi)
         * We are saving state before entering outermost list ("while...done")
         * so that ctrl-Z will correctly background _entire_ outermost list,
         * not just a part of it (like "sleep 1 | exit 2") */
-       if (++run_list_level == 1 && interactive_fd) {
-               if (sigsetjmp(toplevel_jb, 1)) {
+       if (++G.run_list_level == 1 && G.interactive_fd) {
+               if (sigsetjmp(G.toplevel_jb, 1)) {
                        /* ctrl-Z forked and we are parent; or ctrl-C.
                         * Sighandler has longjmped us here */
                        signal(SIGINT, SIG_IGN);
                        signal(SIGTSTP, SIG_IGN);
                        /* Restore level (we can be coming from deep inside
                         * nested levels) */
-                       run_list_level = 1;
+                       G.run_list_level = 1;
 #if ENABLE_FEATURE_SH_STANDALONE
-                       if (nofork_save.saved) { /* if save area is valid */
+                       if (G.nofork_save.saved) { /* if save area is valid */
                                debug_printf_jobs("exiting nofork early\n");
-                               restore_nofork_data(&nofork_save);
+                               restore_nofork_data(&G.nofork_save);
                        }
 #endif
-                       if (ctrl_z_flag) {
+                       if (G.ctrl_z_flag) {
                                /* ctrl-Z has forked and stored pid of the child in pi->pid.
                                 * Remember this child as background job */
                                insert_bg_job(pi);
@@ -2132,15 +2096,15 @@ static int run_list(struct pipe *pi)
                                bb_putchar('\n');
                        }
                        USE_HUSH_LOOPS(loop_top = NULL;)
-                       USE_HUSH_LOOPS(depth_of_loop = 0;)
+                       USE_HUSH_LOOPS(G.depth_of_loop = 0;)
                        rcode = 0;
                        goto ret;
                }
                /* ctrl-Z handler will store pid etc in pi */
-               toplevel_list = pi;
-               ctrl_z_flag = 0;
+               G.toplevel_list = pi;
+               G.ctrl_z_flag = 0;
 #if ENABLE_FEATURE_SH_STANDALONE
-               nofork_save.saved = 0; /* in case we will run a nofork later */
+               G.nofork_save.saved = 0; /* in case we will run a nofork later */
 #endif
                signal_SA_RESTART_empty_mask(SIGTSTP, handler_ctrl_z);
                signal(SIGINT, handler_ctrl_c);
@@ -2155,11 +2119,11 @@ static int run_list(struct pipe *pi)
                                rword, cond_code, skip_more_for_this_rword);
 #if ENABLE_HUSH_LOOPS
                if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
-                && loop_top == NULL /* avoid bumping depth_of_loop twice */
+                && loop_top == NULL /* avoid bumping G.depth_of_loop twice */
                ) {
                        /* start of a loop: remember where loop starts */
                        loop_top = pi;
-                       depth_of_loop++;
+                       G.depth_of_loop++;
                }
 #endif
                if (rword == skip_more_for_this_rword && flag_skip) {
@@ -2268,7 +2232,7 @@ static int run_list(struct pipe *pi)
                {
                        int r;
 #if ENABLE_HUSH_LOOPS
-                       flag_break_continue = 0;
+                       G.flag_break_continue = 0;
 #endif
                        rcode = r = run_pipe(pi); /* NB: rcode is a smallint */
                        if (r != -1) {
@@ -2276,17 +2240,17 @@ static int run_list(struct pipe *pi)
                                 * and we don't need to wait for anything. */
 #if ENABLE_HUSH_LOOPS
                                /* was it "break" or "continue"? */
-                               if (flag_break_continue) {
-                                       smallint fbc = flag_break_continue;
+                               if (G.flag_break_continue) {
+                                       smallint fbc = G.flag_break_continue;
                                        /* we might fall into outer *loop*,
                                         * don't want to break it too */
                                        if (loop_top) {
-                                               depth_break_continue--;
-                                               if (depth_break_continue == 0)
-                                                       flag_break_continue = 0;
+                                               G.depth_break_continue--;
+                                               if (G.depth_break_continue == 0)
+                                                       G.flag_break_continue = 0;
                                                /* else: e.g. "continue 2" should *break* once, *then* continue */
                                        } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */
-                                       if (depth_break_continue != 0 || fbc == BC_BREAK)
+                                       if (G.depth_break_continue != 0 || fbc == BC_BREAK)
                                                goto check_jobs_and_break;
                                        /* "continue": simulate end of loop */
                                        rword = RES_DONE;
@@ -2299,13 +2263,13 @@ static int run_list(struct pipe *pi)
                                 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
                                 * I'm NOT treating inner &'s as jobs */
 #if ENABLE_HUSH_JOB
-                               if (run_list_level == 1)
+                               if (G.run_list_level == 1)
                                        insert_bg_job(pi);
 #endif
                                rcode = 0; /* EXIT_SUCCESS */
                        } else {
 #if ENABLE_HUSH_JOB
-                               if (run_list_level == 1 && interactive_fd) {
+                               if (G.run_list_level == 1 && G.interactive_fd) {
                                        /* waits for completion, then fg's main shell */
                                        rcode = checkjobs_and_fg_shell(pi);
                                        debug_printf_exec(": checkjobs_and_fg_shell returned %d\n", rcode);
@@ -2318,7 +2282,7 @@ static int run_list(struct pipe *pi)
                        }
                }
                debug_printf_exec(": setting last_return_code=%d\n", rcode);
-               last_return_code = rcode;
+               G.last_return_code = rcode;
 
                /* Analyze how result affects subsequent commands */
 #if ENABLE_HUSH_IF
@@ -2349,22 +2313,22 @@ static int run_list(struct pipe *pi)
        } /* for (pi) */
 
 #if ENABLE_HUSH_JOB
-       if (ctrl_z_flag) {
+       if (G.ctrl_z_flag) {
                /* ctrl-Z forked somewhere in the past, we are the child,
                 * and now we completed running the list. Exit. */
 //TODO: _exit?
                exit(rcode);
        }
  ret:
-       if (!--run_list_level && interactive_fd) {
+       if (!--G.run_list_level && G.interactive_fd) {
                signal(SIGTSTP, SIG_IGN);
                signal(SIGINT, SIG_IGN);
        }
 #endif
-       debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
+       debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
 #if ENABLE_HUSH_LOOPS
        if (loop_top)
-               depth_of_loop--;
+               G.depth_of_loop--;
        free(for_list);
 #endif
 #if ENABLE_HUSH_CASE
@@ -2449,7 +2413,7 @@ static int run_and_free_list(struct pipe *pi)
 {
        int rcode = 0;
        debug_printf_exec("run_and_free_list entered\n");
-       if (!fake_mode) {
+       if (!G.fake_mode) {
                debug_printf_exec(": run_list with %d members\n", pi->num_progs);
                rcode = run_list(pi);
        }
@@ -2472,12 +2436,12 @@ static int run_and_free_list(struct pipe *pi)
  * Caller can deallocate entire list by single free(list). */
 
 /* Store given string, finalizing the word and starting new one whenever
- * we encounter ifs char(s). This is used for expanding variable values.
+ * we encounter IFS char(s). This is used for expanding variable values.
  * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
 static int expand_on_ifs(o_string *output, int n, const char *str)
 {
        while (1) {
-               int word_len = strcspn(str, ifs);
+               int word_len = strcspn(str, G.ifs);
                if (word_len) {
                        if (output->o_quote || !output->o_glob)
                                o_addQstr(output, str, word_len);
@@ -2490,7 +2454,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
                o_addchr(output, '\0');
                debug_print_list("expand_on_ifs", output, n);
                n = o_save_ptr(output, n);
-               str += strspn(str, ifs); /* skip ifs chars */
+               str += strspn(str, G.ifs); /* skip ifs chars */
        }
        debug_print_list("expand_on_ifs[1]", output, n);
        return n;
@@ -2540,31 +2504,31 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
                switch (first_ch & 0x7f) {
                /* Highest bit in first_ch indicates that var is double-quoted */
                case '$': /* pid */
-                       val = utoa(root_pid);
+                       val = utoa(G.root_pid);
                        break;
                case '!': /* bg pid */
-                       val = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
+                       val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)"";
                        break;
                case '?': /* exitcode */
-                       val = utoa(last_return_code);
+                       val = utoa(G.last_return_code);
                        break;
                case '#': /* argc */
-                       val = utoa(global_argc ? global_argc-1 : 0);
+                       val = utoa(G.global_argc ? G.global_argc-1 : 0);
                        break;
                case '*':
                case '@':
                        i = 1;
-                       if (!global_argv[i])
+                       if (!G.global_argv[i])
                                break;
                        ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
                        if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
                                smallint sv = output->o_quote;
                                /* unquoted var's contents should be globbed, so don't quote */
                                output->o_quote = 0;
-                               while (global_argv[i]) {
-                                       n = expand_on_ifs(output, n, global_argv[i]);
-                                       debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1);
-                                       if (global_argv[i++][0] && global_argv[i]) {
+                               while (G.global_argv[i]) {
+                                       n = expand_on_ifs(output, n, G.global_argv[i]);
+                                       debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
+                                       if (G.global_argv[i++][0] && G.global_argv[i]) {
                                                /* this argv[] is not empty and not last:
                                                 * put terminating NUL, start new word */
                                                o_addchr(output, '\0');
@@ -2579,8 +2543,8 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
                         * and in this case should treat it like '$*' - see 'else...' below */
                        if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
                                while (1) {
-                                       o_addQstr(output, global_argv[i], strlen(global_argv[i]));
-                                       if (++i >= global_argc)
+                                       o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
+                                       if (++i >= G.global_argc)
                                                break;
                                        o_addchr(output, '\0');
                                        debug_print_list("expand_vars_to_list[4]", output, n);
@@ -2588,11 +2552,11 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
                                }
                        } else { /* quoted $*: add as one word */
                                while (1) {
-                                       o_addQstr(output, global_argv[i], strlen(global_argv[i]));
-                                       if (!global_argv[++i])
+                                       o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i]));
+                                       if (!G.global_argv[++i])
                                                break;
-                                       if (ifs[0])
-                                               o_addchr(output, ifs[0]);
+                                       if (G.ifs[0])
+                                               o_addchr(output, G.ifs[0]);
                                }
                        }
                        break;
@@ -2620,8 +2584,8 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
                        arg[0] = first_ch & 0x7f;
                        if (isdigit(arg[0])) {
                                i = xatoi_u(arg);
-                               if (i < global_argc)
-                                       val = global_argv[i];
+                               if (i < G.global_argc)
+                                       val = G.global_argv[i];
                                /* else val remains NULL: $N with too big N */
                        } else
                                val = lookup_param(arg);
@@ -2736,7 +2700,7 @@ static char* expand_strvec_to_string(char **argv)
                        if (HUSH_DEBUG)
                                if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
                                        bb_error_msg_and_die("BUG in varexp3");
-                       list[n][-1] = ' '; /* TODO: or to ifs[0]? */
+                       list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */
                        n++;
                }
        }
@@ -2755,7 +2719,7 @@ static struct variable *get_local_var(const char *name)
        if (!name)
                return NULL;
        len = strlen(name);
-       for (cur = top_var; cur; cur = cur->next) {
+       for (cur = G.top_var; cur; cur = cur->next) {
                if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=')
                        return cur;
        }
@@ -2777,7 +2741,7 @@ static int set_local_var(char *str, int flg_export)
        }
 
        name_len = value - str + 1; /* including '=' */
-       cur = top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
+       cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
        while (1) {
                if (strncmp(cur->varstr, str, name_len) != 0) {
                        if (!cur->next) {
@@ -2838,7 +2802,7 @@ static void unset_local_var(const char *name)
        if (!name)
                return;
        name_len = strlen(name);
-       cur = top_var;
+       cur = G.top_var;
        while (cur) {
                if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
                        if (cur->flg_read_only) {
@@ -3319,7 +3283,7 @@ static FILE *generate_stream_from_list(struct pipe *head)
                xmove_fd(channel[1], 1);
                /* Prevent it from trying to handle ctrl-z etc */
 #if ENABLE_HUSH_JOB
-               run_list_level = 1;
+               G.run_list_level = 1;
 #endif
                /* Process substitution is not considered to be usual
                 * 'command execution'.
@@ -3654,7 +3618,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
                next = '\0';
                ch = i_getch(input);
                if (ch != EOF) {
-                       m = charmap[ch];
+                       m = G.charmap[ch];
                        if (ch != '\n') {
                                next = i_peek(input);
                        }
@@ -3915,29 +3879,28 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
 static void set_in_charmap(const char *set, int code)
 {
        while (*set)
-               charmap[(unsigned char)*set++] = code;
+               G.charmap[(unsigned char)*set++] = code;
 }
 
 static void update_charmap(void)
 {
-       /* char *ifs and char charmap[256] are both globals. */
-       ifs = getenv("IFS");
-       if (ifs == NULL)
-               ifs = " \t\n";
+       G.ifs = getenv("IFS");
+       if (G.ifs == NULL)
+               G.ifs = " \t\n";
        /* Precompute a list of 'flow through' behavior so it can be treated
         * quickly up front.  Computation is necessary because of IFS.
         * Special case handling of IFS == " \t\n" is not implemented.
         * The charmap[] array only really needs two bits each,
         * and on most machines that would be faster (reduced L1 cache use).
         */
-       memset(charmap, CHAR_ORDINARY, sizeof(charmap));
+       memset(G.charmap, CHAR_ORDINARY, sizeof(G.charmap));
 #if ENABLE_HUSH_TICK
        set_in_charmap("\\$\"`", CHAR_SPECIAL);
 #else
        set_in_charmap("\\$\"", CHAR_SPECIAL);
 #endif
        set_in_charmap("<>;&|(){}#'", CHAR_ORDINARY_IF_QUOTED);
-       set_in_charmap(ifs, CHAR_IFS);  /* are ordinary if quoted */
+       set_in_charmap(G.ifs, CHAR_IFS);  /* are ordinary if quoted */
 }
 
 /* Most recursion does not come through here, the exception is
@@ -4016,13 +3979,14 @@ static void setup_job_control(void)
 {
        pid_t shell_pgrp;
 
-       saved_task_pgrp = shell_pgrp = getpgrp();
-       debug_printf_jobs("saved_task_pgrp=%d\n", saved_task_pgrp);
-       close_on_exec_on(interactive_fd);
+//     G.saved_task_pgrp =
+       shell_pgrp = getpgrp();
+//     debug_printf_jobs("saved_task_pgrp=%d\n", G.saved_task_pgrp);
+       close_on_exec_on(G.interactive_fd);
 
        /* If we were ran as 'hush &',
         * sleep until we are in the foreground.  */
-       while (tcgetpgrp(interactive_fd) != shell_pgrp) {
+       while (tcgetpgrp(G.interactive_fd) != shell_pgrp) {
                /* Send TTIN to ourself (should stop us) */
                kill(- shell_pgrp, SIGTTIN);
                shell_pgrp = getpgrp();
@@ -4039,7 +4003,7 @@ static void setup_job_control(void)
        /* Put ourselves in our own process group.  */
        setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
        /* Grab control of the terminal.  */
-       tcsetpgrp(interactive_fd, getpid());
+       tcsetpgrp(G.interactive_fd, getpid());
 }
 #endif
 
@@ -4063,15 +4027,15 @@ int hush_main(int argc, char **argv)
 
        INIT_G();
 
-       root_pid = getpid();
+       G.root_pid = getpid();
 
        /* Deal with HUSH_VERSION */
-       shell_ver = const_shell_ver; /* copying struct here */
-       top_var = &shell_ver;
+       G.shell_ver = const_shell_ver; /* copying struct here */
+       G.top_var = &G.shell_ver;
        unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
        /* Initialize our shell local variables with the values
         * currently living in the environment */
-       cur_var = top_var;
+       cur_var = G.top_var;
        e = environ;
        if (e) while (*e) {
                char *value = strchr(*e, '=');
@@ -4087,22 +4051,22 @@ int hush_main(int argc, char **argv)
        putenv((char *)version_str); /* reinstate HUSH_VERSION */
 
 #if ENABLE_FEATURE_EDITING
-       line_input_state = new_line_input_t(FOR_SHELL);
+       G.line_input_state = new_line_input_t(FOR_SHELL);
 #endif
        /* XXX what should these be while sourcing /etc/profile? */
-       global_argc = argc;
-       global_argv = argv;
+       G.global_argc = argc;
+       G.global_argv = argv;
        /* Initialize some more globals to non-zero values */
        set_cwd();
 #if ENABLE_HUSH_INTERACTIVE
 #if ENABLE_FEATURE_EDITING
        cmdedit_set_initial_prompt();
 #endif
-       PS2 = "> ";
+       G.PS2 = "> ";
 #endif
 
        if (EXIT_SUCCESS) /* otherwise is already done */
-               last_return_code = EXIT_SUCCESS;
+               G.last_return_code = EXIT_SUCCESS;
 
        if (argv[0] && argv[0][0] == '-') {
                debug_printf("sourcing /etc/profile\n");
@@ -4118,17 +4082,17 @@ int hush_main(int argc, char **argv)
        while ((opt = getopt(argc, argv, "c:xif")) > 0) {
                switch (opt) {
                case 'c':
-                       global_argv = argv + optind;
-                       global_argc = argc - optind;
+                       G.global_argv = argv + optind;
+                       G.global_argc = argc - optind;
                        opt = parse_and_run_string(optarg, 0 /* parse_flag */);
                        goto final_return;
                case 'i':
                        /* Well, we cannot just declare interactiveness,
                         * we have to have some stuff (ctty, etc) */
-                       /* interactive_fd++; */
+                       /* G.interactive_fd++; */
                        break;
                case 'f':
-                       fake_mode = 1;
+                       G.fake_mode = 1;
                        break;
                default:
 #ifndef BB_VER
@@ -4151,25 +4115,25 @@ int hush_main(int argc, char **argv)
        if (argv[optind] == NULL && input == stdin
         && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
        ) {
-               saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
-               debug_printf("saved_tty_pgrp=%d\n", saved_tty_pgrp);
-               if (saved_tty_pgrp >= 0) {
+               G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
+               debug_printf("saved_tty_pgrp=%d\n", G.saved_tty_pgrp);
+               if (G.saved_tty_pgrp >= 0) {
                        /* try to dup to high fd#, >= 255 */
-                       interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
-                       if (interactive_fd < 0) {
+                       G.interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
+                       if (G.interactive_fd < 0) {
                                /* try to dup to any fd */
-                               interactive_fd = dup(STDIN_FILENO);
-                               if (interactive_fd < 0)
+                               G.interactive_fd = dup(STDIN_FILENO);
+                               if (G.interactive_fd < 0)
                                        /* give up */
-                                       interactive_fd = 0;
+                                       G.interactive_fd = 0;
                        }
                        // TODO: track & disallow any attempts of user
                        // to (inadvertently) close/redirect it
                }
        }
-       debug_printf("interactive_fd=%d\n", interactive_fd);
-       if (interactive_fd) {
-               fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
+       debug_printf("G.interactive_fd=%d\n", G.interactive_fd);
+       if (G.interactive_fd) {
+               fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
                /* Looks like they want an interactive shell */
                setup_job_control();
                /* -1 is special - makes xfuncs longjmp, not exit
@@ -4189,16 +4153,16 @@ int hush_main(int argc, char **argv)
        if (argv[optind] == NULL && input == stdin
         && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
        ) {
-               interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
-               if (interactive_fd < 0) {
+               G.interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
+               if (G.interactive_fd < 0) {
                        /* try to dup to any fd */
-                       interactive_fd = dup(STDIN_FILENO);
-                       if (interactive_fd < 0)
+                       G.interactive_fd = dup(STDIN_FILENO);
+                       if (G.interactive_fd < 0)
                                /* give up */
-                               interactive_fd = 0;
+                               G.interactive_fd = 0;
                }
-               if (interactive_fd) {
-                       fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
+               if (G.interactive_fd) {
+                       fcntl(G.interactive_fd, F_SETFD, FD_CLOEXEC);
                        set_misc_sighandler(SIG_IGN);
                }
        }
@@ -4208,8 +4172,8 @@ int hush_main(int argc, char **argv)
                opt = parse_and_run_file(stdin);
        } else {
                debug_printf("\nrunning script '%s'\n", argv[optind]);
-               global_argv = argv + optind;
-               global_argc = argc - optind;
+               G.global_argv = argv + optind;
+               G.global_argc = argc - optind;
                input = xfopen_for_read(argv[optind]);
                fcntl(fileno(input), F_SETFD, FD_CLOEXEC);
                opt = parse_and_run_file(input);
@@ -4219,9 +4183,9 @@ int hush_main(int argc, char **argv)
 
 #if ENABLE_FEATURE_CLEAN_UP
        fclose(input);
-       if (cwd != bb_msg_unknown)
-               free((char*)cwd);
-       cur_var = top_var->next;
+       if (G.cwd != bb_msg_unknown)
+               free((char*)G.cwd);
+       cur_var = G.top_var->next;
        while (cur_var) {
                struct variable *tmp = cur_var;
                if (!cur_var->max_len)
@@ -4230,7 +4194,7 @@ int hush_main(int argc, char **argv)
                free(tmp);
        }
 #endif
-       hush_exit(opt ? opt : last_return_code);
+       hush_exit(opt ? opt : G.last_return_code);
 }
 
 
@@ -4280,7 +4244,7 @@ static int builtin_eval(char **argv)
                char *str = expand_strvec_to_string(argv + 1);
                parse_and_run_string(str, PARSEFLAG_EXIT_FROM_LOOP);
                free(str);
-               rcode = last_return_code;
+               rcode = G.last_return_code;
        }
        return rcode;
 }
@@ -4323,7 +4287,7 @@ static int builtin_exit(char **argv)
 // TODO: warn if we have background jobs: "There are stopped jobs"
 // On second consecutive 'exit', exit anyway.
        if (argv[1] == NULL)
-               hush_exit(last_return_code);
+               hush_exit(G.last_return_code);
        /* mimic bash: exit 123abc == exit 255 + error msg */
        xfunc_error_retval = 255;
        /* bash: exit -2 == exit 254, no error msg */
@@ -4373,12 +4337,12 @@ static int builtin_fg_bg(char **argv)
        int i, jobnum;
        struct pipe *pi;
 
-       if (!interactive_fd)
+       if (!G.interactive_fd)
                return EXIT_FAILURE;
        /* If they gave us no args, assume they want the last backgrounded task */
        if (!argv[1]) {
-               for (pi = job_list; pi; pi = pi->next) {
-                       if (pi->jobid == last_jobid) {
+               for (pi = G.job_list; pi; pi = pi->next) {
+                       if (pi->jobid == G.last_jobid) {
                                goto found;
                        }
                }
@@ -4389,7 +4353,7 @@ static int builtin_fg_bg(char **argv)
                bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]);
                return EXIT_FAILURE;
        }
-       for (pi = job_list; pi; pi = pi->next) {
+       for (pi = G.job_list; pi; pi = pi->next) {
                if (pi->jobid == jobnum) {
                        goto found;
                }
@@ -4401,7 +4365,7 @@ static int builtin_fg_bg(char **argv)
        // of job being foregrounded (like "sleep 1 | cat")
        if (*argv[0] == 'f') {
                /* Put the job into the foreground.  */
-               tcsetpgrp(interactive_fd, pi->pgrp);
+               tcsetpgrp(G.interactive_fd, pi->pgrp);
        }
 
        /* Restart the processes in the job */
@@ -4451,7 +4415,7 @@ static int builtin_jobs(char **argv UNUSED_PARAM)
        struct pipe *job;
        const char *status_string;
 
-       for (job = job_list; job; job = job->next) {
+       for (job = G.job_list; job; job = job->next) {
                if (job->alive_progs == job->stopped_progs)
                        status_string = "Stopped";
                else
@@ -4485,7 +4449,7 @@ static int builtin_set(char **argv)
        struct variable *e;
 
        if (temp == NULL)
-               for (e = top_var; e; e = e->next)
+               for (e = G.top_var; e; e = e->next)
                        puts(e->varstr);
        else
                set_local_var(xstrdup(temp), 0);
@@ -4499,10 +4463,10 @@ static int builtin_shift(char **argv)
        if (argv[1]) {
                n = atoi(argv[1]);
        }
-       if (n >= 0 && n < global_argc) {
-               global_argv[n] = global_argv[0];
-               global_argc -= n;
-               global_argv += n;
+       if (n >= 0 && n < G.global_argc) {
+               G.global_argv[n] = G.global_argv[0];
+               G.global_argc -= n;
+               G.global_argv += n;
                return EXIT_SUCCESS;
        }
        return EXIT_FAILURE;
@@ -4525,9 +4489,9 @@ static int builtin_source(char **argv)
        close_on_exec_on(fileno(input));
 
        /* Now run the file */
-       /* XXX argv and argc are broken; need to save old global_argv
+       /* XXX argv and argc are broken; need to save old G.global_argv
         * (pointer only is OK!) on this stack frame,
-        * set global_argv=argv+1, recurse, and restore. */
+        * set G.global_argv=argv+1, recurse, and restore. */
        status = parse_and_run_file(input);
        fclose(input);
        return status;
@@ -4561,29 +4525,29 @@ static int builtin_unset(char **argv)
 #if ENABLE_HUSH_LOOPS
 static int builtin_break(char **argv)
 {
-       if (depth_of_loop == 0) {
+       if (G.depth_of_loop == 0) {
                bb_error_msg("%s: only meaningful in a loop", "break");
                return EXIT_SUCCESS; /* bash compat */
        }
-       flag_break_continue++; /* BC_BREAK = 1 */
-       depth_break_continue = 1;
+       G.flag_break_continue++; /* BC_BREAK = 1 */
+       G.depth_break_continue = 1;
        if (argv[1]) {
-               depth_break_continue = bb_strtou(argv[1], NULL, 10);
-               if (errno || !depth_break_continue || argv[2]) {
+               G.depth_break_continue = bb_strtou(argv[1], NULL, 10);
+               if (errno || !G.depth_break_continue || argv[2]) {
                        bb_error_msg("bad arguments");
-                       flag_break_continue = BC_BREAK;
-                       depth_break_continue = UINT_MAX;
+                       G.flag_break_continue = BC_BREAK;
+                       G.depth_break_continue = UINT_MAX;
                }
        }
-       if (depth_of_loop < depth_break_continue)
-               depth_break_continue = depth_of_loop;
+       if (G.depth_of_loop < G.depth_break_continue)
+               G.depth_break_continue = G.depth_of_loop;
        return EXIT_SUCCESS;
 }
 
 static int builtin_continue(char **argv)
 {
-       if (depth_of_loop) {
-               flag_break_continue++; /* BC_CONTINUE = 2 = 1+1 */
+       if (G.depth_of_loop) {
+               G.flag_break_continue = 1; /* BC_CONTINUE = 2 = 1+1 */
                return builtin_break(argv);
        }
        bb_error_msg("%s: only meaningful in a loop", "continue");