aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c145
1 files changed, 55 insertions, 90 deletions
diff --git a/shell/hush.c b/shell/hush.c
index efb20d91e..a57d5d811 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -61,7 +61,6 @@
* figure out what to do with backslash-newline
* propagate syntax errors, die on resource errors?
* continuation lines, both explicit and implicit - done?
- * maybe change charmap[] to use 2-bit entries
*
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
@@ -201,30 +200,25 @@ static void debug_print_strings(const char *prefix, char **vv)
* Leak hunting. Use hush_leaktool.sh for post-processing.
*/
#ifdef FOR_HUSH_LEAKTOOL
-/* suppress "warning: no previous prototype..." */
-void *xxmalloc(int lineno, size_t size);
-void *xxrealloc(int lineno, void *ptr, size_t size);
-char *xxstrdup(int lineno, const char *str);
-void xxfree(void *ptr);
-void *xxmalloc(int lineno, size_t size)
+static void *xxmalloc(int lineno, size_t size)
{
void *ptr = xmalloc((size + 0xff) & ~0xff);
fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
return ptr;
}
-void *xxrealloc(int lineno, void *ptr, size_t size)
+static void *xxrealloc(int lineno, void *ptr, size_t size)
{
ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
return ptr;
}
-char *xxstrdup(int lineno, const char *str)
+static char *xxstrdup(int lineno, const char *str)
{
char *ptr = xstrdup(str);
fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
return ptr;
}
-void xxfree(void *ptr)
+static void xxfree(void *ptr)
{
fdprintf(2, "free %p\n", ptr);
free(ptr);
@@ -491,14 +485,6 @@ struct globals {
const char *cwd;
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;
-#endif
-#if ENABLE_HUSH_JOB
- sigjmp_buf toplevel_jb;
-#endif
- unsigned char charmap[256];
- char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
/* Signal and trap handling */
// unsigned count_SIGCHLD;
// unsigned handled_SIGCHLD;
@@ -507,6 +493,13 @@ struct globals {
char **traps; /* char *traps[NSIG] */
sigset_t blocked_set;
sigset_t inherited_set;
+ char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
+#if ENABLE_FEATURE_SH_STANDALONE
+ struct nofork_save_area nofork_save;
+#endif
+#if ENABLE_HUSH_JOB
+ sigjmp_buf toplevel_jb;
+#endif
};
#define G (*ptr_to_globals)
/* Not #defining name to G.name - this quickly gets unwieldy
@@ -1042,9 +1035,7 @@ static struct variable *get_local_var(const char *name)
return NULL;
}
-/* Basically useful version until someone wants to get fancier,
- * see the bash man page under "Parameter Expansion" */
-static const char *lookup_param(const char *src)
+static const char *get_local_var_value(const char *src)
{
struct variable *var = get_local_var(src);
if (var)
@@ -1842,7 +1833,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
o_free(&dest);
}
skip_expand:
- hooks.lookupvar = lookup_param;
+ hooks.lookupvar = get_local_var_value;
hooks.setvar = arith_set_local_var;
hooks.endofname = endofname;
res = arith(exp_str ? exp_str : arg, &errcode, &hooks);
@@ -1898,7 +1889,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
val = G.global_argv[i];
/* else val remains NULL: $N with too big N */
} else
- val = lookup_param(var);
+ val = get_local_var_value(var);
/* handle any expansions */
if (exp_len) {
@@ -4118,7 +4109,7 @@ static int handle_dollar(o_string *dest, struct in_str *input)
static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end)
{
- int ch, m;
+ int ch;
int next;
again:
@@ -4136,7 +4127,6 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote
return 1;
}
next = '\0';
- m = G.charmap[ch];
if (ch != '\n') {
next = i_peek(input);
}
@@ -4206,11 +4196,11 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
{
struct parse_context ctx;
o_string dest = NULL_O_STRING;
- int ch, m;
int redir_fd;
- redir_type redir_style;
- int is_in_dquote;
int next;
+ int is_in_dquote;
+ int ch;
+ redir_type redir_style;
/* Double-quote state is handled in the state variable is_in_dquote.
* A single-quote triggers a bypass of the main loop until its mate is
@@ -4219,6 +4209,10 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
end_trigger ? : 'X');
+ G.ifs = get_local_var_value("IFS");
+ if (G.ifs == NULL)
+ G.ifs = " \t\n";
+
reset:
#if ENABLE_HUSH_INTERACTIVE
input->promptmode = 0; /* PS1 */
@@ -4227,6 +4221,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
initialize_context(&ctx);
is_in_dquote = 0;
while (1) {
+ const char *is_ifs;
+ const char *is_special;
+
if (is_in_dquote) {
if (parse_stream_dquoted(&dest, input, '"')) {
goto parse_error;
@@ -4234,18 +4231,38 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
/* We reached closing '"' */
is_in_dquote = 0;
}
- m = CHAR_IFS;
next = '\0';
ch = i_getch(input);
- if (ch != EOF) {
- m = G.charmap[ch];
- if (ch != '\n') {
- next = i_peek(input);
+ debug_printf_parse(": ch=%c (%d) escape=%d\n",
+ ch, ch, dest.o_escape);
+ if (ch == EOF) {
+ struct pipe *pi;
+ if (done_word(&dest, &ctx)) {
+ goto parse_error;
+ }
+ o_free(&dest);
+ done_pipe(&ctx, PIPE_SEQ);
+ /* If we got nothing... */
+ pi = ctx.list_head;
+ if (pi->num_cmds == 0
+ IF_HAS_KEYWORDS( && pi->res_word == RES_NONE)
+ ) {
+ free_pipe_list(pi, 0);
+ pi = NULL;
}
+ debug_printf_parse("parse_stream return %p\n", pi);
+ return pi;
}
- debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
- ch, ch, m, dest.o_escape);
- if (m == CHAR_ORDINARY) {
+ if (ch != '\n') {
+ next = i_peek(input);
+ }
+
+ is_ifs = strchr(G.ifs, ch);
+ is_special = strchr("<>;&|(){}#'" /* special outside of "str" */
+ "\\$\"" USE_HUSH_TICK("`") /* always special */
+ , ch);
+
+ if (!is_special && !is_ifs) { /* ordinary char */
o_addQchr(&dest, ch);
if ((dest.o_assignment == MAYBE_ASSIGNMENT
|| dest.o_assignment == WORD_IS_KEYWORD)
@@ -4257,27 +4274,7 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
continue;
}
- /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
-
- if (m == CHAR_IFS) {
- if (ch == EOF) {
- struct pipe *pi;
- if (done_word(&dest, &ctx)) {
- goto parse_error;
- }
- o_free(&dest);
- done_pipe(&ctx, PIPE_SEQ);
- /* If we got nothing... */
- pi = ctx.list_head;
- if (pi->num_cmds == 0
- IF_HAS_KEYWORDS( && pi->res_word == RES_NONE)
- ) {
- free_pipe_list(pi, 0);
- pi = NULL;
- }
- debug_printf_parse("parse_stream return %p\n", pi);
- return pi;
- }
+ if (is_ifs) {
if (done_word(&dest, &ctx)) {
goto parse_error;
}
@@ -4317,11 +4314,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
return ctx.list_head;
}
}
- if (m == CHAR_IFS)
+ if (is_ifs)
continue;
- /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */
-
if (dest.o_assignment == MAYBE_ASSIGNMENT) {
/* ch is a special char and thus this word
* cannot be an assignment */
@@ -4579,33 +4574,6 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
}
}
-static void set_in_charmap(const char *set, int code)
-{
- while (*set)
- G.charmap[(unsigned char)*set++] = code;
-}
-
-static void update_charmap(void)
-{
- 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(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(G.ifs, CHAR_IFS); /* are ordinary if quoted */
-}
-
/* Execiting from string: eval, sh -c '...'
* or from file: /etc/profile, . file, sh <script>, sh (intereactive)
* end_trigger controls how often we stop parsing
@@ -4617,15 +4585,12 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
while (1) {
struct pipe *pipe_list;
- update_charmap();
-
pipe_list = parse_stream(inp, end_trigger);
if (!pipe_list) /* EOF */
break;
debug_print_tree(pipe_list, 0);
debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
run_and_free_list(pipe_list);
- /* Loop on syntax errors, return on EOF: */
}
}