aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c287
1 files changed, 152 insertions, 135 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 6ae42c8b5..0ac42c90b 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1517,13 +1517,16 @@ static int o_save_ptr_helper(o_string *o, int n)
list = (char**)o->data;
memmove(list + n + 0x10, list + n, string_len);
o->length += 0x10 * sizeof(list[0]);
- } else
- debug_printf_list("list[%d]=%d string_start=%d\n", n, string_len, string_start);
+ } else {
+ debug_printf_list("list[%d]=%d string_start=%d\n",
+ n, string_len, string_start);
+ }
} else {
/* We have empty slot at list[n], reuse without growth */
string_start = ((n+1 + 0xf) & ~0xf) * sizeof(list[0]); /* NB: n+1! */
string_len = o->length - string_start;
- debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n", n, string_len, string_start);
+ debug_printf_list("list[%d]=%d string_start=%d (empty slot)\n",
+ n, string_len, string_start);
o->has_empty_slot = 0;
}
list[n] = (char*)(ptrdiff_t)string_len;
@@ -1917,7 +1920,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
}
arg[0] = first_ch;
-
#if ENABLE_HUSH_TICK
store_val:
#endif
@@ -2203,8 +2205,12 @@ typedef struct nommu_save_t {
* XXX no exit() here. If you don't exec, use _exit instead.
* The at_exit handlers apparently confuse the calling process,
* in particular stdin handling. Not sure why? -- because of vfork! (vda) */
-static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
-static void pseudo_exec_argv(nommu_save_t *nommu_save, char **argv, int assignment_cnt, char **argv_expanded)
+static void pseudo_exec_argv(nommu_save_t *nommu_save,
+ char **argv, int assignment_cnt,
+ char **argv_expanded) NORETURN;
+static void pseudo_exec_argv(nommu_save_t *nommu_save,
+ char **argv, int assignment_cnt,
+ char **argv_expanded)
{
int rcode;
char **new_env;
@@ -2279,8 +2285,12 @@ static int run_list(struct pipe *pi);
/* Called after [v]fork() in run_pipe()
*/
-static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded) NORETURN;
-static void pseudo_exec(nommu_save_t *nommu_save, struct command *command, char **argv_expanded)
+static void pseudo_exec(nommu_save_t *nommu_save,
+ struct command *command,
+ char **argv_expanded) NORETURN;
+static void pseudo_exec(nommu_save_t *nommu_save,
+ struct command *command,
+ char **argv_expanded)
{
if (command->argv)
pseudo_exec_argv(nommu_save, command->argv, command->assignment_cnt, argv_expanded);
@@ -2655,7 +2665,8 @@ static int run_pipe(struct pipe *pi)
setup_redirects(command, squirrel);
new_env = expand_assignments(argv, command->assignment_cnt);
old_env = putenv_all_and_save_old(new_env);
- debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]);
+ debug_printf_exec(": builtin '%s' '%s'...\n",
+ x->cmd, argv_expanded[1]);
rcode = x->function(argv_expanded) & 0xff;
#if ENABLE_FEATURE_SH_STANDALONE
clean_up_and_ret:
@@ -2677,7 +2688,8 @@ static int run_pipe(struct pipe *pi)
save_nofork_data(&G.nofork_save);
new_env = expand_assignments(argv, command->assignment_cnt);
old_env = putenv_all_and_save_old(new_env);
- debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
+ debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
+ argv_expanded[0], argv_expanded[1]);
rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded);
goto clean_up_and_ret;
}
@@ -2701,7 +2713,8 @@ static int run_pipe(struct pipe *pi)
#endif
command = &(pi->cmds[i]);
if (command->argv) {
- debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]);
+ debug_printf_exec(": pipe member '%s' '%s'...\n",
+ command->argv[0], command->argv[1]);
} else
debug_printf_exec(": pipe member with no argv\n");
@@ -2841,7 +2854,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
struct command *command = &pi->cmds[prn];
char **argv = command->argv;
- fprintf(stderr, "%*s prog %d assignment_cnt:%d", lvl*2, "", prn, command->assignment_cnt);
+ fprintf(stderr, "%*s prog %d assignment_cnt:%d",
+ lvl*2, "", prn,
+ command->assignment_cnt);
if (command->group) {
fprintf(stderr, " group %s: (argv=%p)\n",
GRPTYPE[command->grp_type],
@@ -3046,8 +3061,9 @@ static int run_list(struct pipe *pi)
pi->cmds[0].argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
pi->cmds[0].assignment_cnt = 1;
}
- if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */
- continue;
+ if (rword == RES_IN) {
+ continue; /* "for v IN list;..." - "in" has no cmds anyway */
+ }
if (rword == RES_DONE) {
continue; /* "done" has no cmds too */
}
@@ -3603,7 +3619,8 @@ static int done_word(o_string *word, struct parse_context *ctx)
debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
if (reserved_word(word, ctx)) {
o_reset(word);
- debug_printf_parse("done_word return %d\n", (ctx->ctx_res_w == RES_SNTX));
+ debug_printf_parse("done_word return %d\n",
+ (ctx->ctx_res_w == RES_SNTX));
return (ctx->ctx_res_w == RES_SNTX);
}
}
@@ -3800,7 +3817,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
|| dest->nonnull /* ""(... */
) {
syntax(NULL);
- debug_printf_parse("parse_group return 1: syntax error, groups and arglists don't mix\n");
+ debug_printf_parse("parse_group return 1: "
+ "syntax error, groups and arglists don't mix\n");
return 1;
}
endch = '}';
@@ -3812,7 +3830,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
/* empty ()/{} or parse error? */
if (!pipe_list || pipe_list == ERR_PTR) {
syntax(NULL);
- debug_printf_parse("parse_group return 1: parse_stream returned %p\n", pipe_list);
+ debug_printf_parse("parse_group return 1: "
+ "parse_stream returned %p\n", pipe_list);
return 1;
}
command->group = pipe_list;
@@ -3910,7 +3929,7 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db
break;
if (ch == '(')
count++;
- if (ch == ')')
+ if (ch == ')') {
if (--count < 0) {
if (!dbl)
break;
@@ -3919,6 +3938,7 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db
break;
}
}
+ }
o_addchr(dest, ch);
if (ch == '\'') {
add_till_single_quote(dest, input);
@@ -3971,136 +3991,130 @@ static int handle_dollar(o_string *dest, struct in_str *input)
o_addchr(dest, ch | quote_mask);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
} else switch (ch) {
- case '$': /* pid */
- case '!': /* last bg pid */
- case '?': /* last exit code */
- case '#': /* number of args */
- case '*': /* args */
- case '@': /* args */
- goto make_one_char_var;
- case '{': {
- bool first_char, all_digits;
+ case '$': /* pid */
+ case '!': /* last bg pid */
+ case '?': /* last exit code */
+ case '#': /* number of args */
+ case '*': /* args */
+ case '@': /* args */
+ goto make_one_char_var;
+ case '{': {
+ bool first_char, all_digits;
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- i_getch(input);
- /* XXX maybe someone will try to escape the '}' */
- expansion = 0;
- first_char = true;
- all_digits = false;
- while (1) {
- ch = i_getch(input);
- if (ch == '}')
- break;
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ i_getch(input);
+ /* XXX maybe someone will try to escape the '}' */
+ expansion = 0;
+ first_char = true;
+ all_digits = false;
+ while (1) {
+ ch = i_getch(input);
+ if (ch == '}')
+ break;
- if (first_char) {
- if (ch == '#')
- /* ${#var}: length of var contents */
- goto char_ok;
- else if (isdigit(ch)) {
- all_digits = true;
- goto char_ok;
- }
+ if (first_char) {
+ if (ch == '#')
+ /* ${#var}: length of var contents */
+ goto char_ok;
+ else if (isdigit(ch)) {
+ all_digits = true;
+ goto char_ok;
}
+ }
- if (expansion < 2 &&
- ((all_digits && !isdigit(ch)) ||
- (!all_digits && !isalnum(ch) && ch != '_')))
- {
- /* handle parameter expansions
- * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
- */
- if (first_char)
- goto case_default;
- switch (ch) {
- case ':': /* null modifier */
- if (expansion == 0) {
- debug_printf_parse(": null modifier\n");
- ++expansion;
- break;
- }
- goto case_default;
-
+ if (expansion < 2
+ && ( (all_digits && !isdigit(ch))
+ || (!all_digits && !isalnum(ch) && ch != '_')
+ )
+ ) {
+ /* handle parameter expansions
+ * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
+ */
+ if (first_char)
+ goto case_default;
+ switch (ch) {
+ case ':': /* null modifier */
+ if (expansion == 0) {
+ debug_printf_parse(": null modifier\n");
+ ++expansion;
+ break;
+ }
+ goto case_default;
#if 0 /* not implemented yet :( */
- case '#': /* remove prefix */
- case '%': /* remove suffix */
- if (expansion == 0) {
- debug_printf_parse(": remove suffix/prefix\n");
- expansion = 2;
- break;
- }
- goto case_default;
-#endif
-
- case '-': /* default value */
- case '=': /* assign default */
- case '+': /* alternative */
- case '?': /* error indicate */
- debug_printf_parse(": parameter expansion\n");
- expansion = 2;
- break;
-
- default:
- case_default:
- syntax("unterminated ${name}");
- debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
- return 1;
- }
+ case '#': /* remove prefix */
+ case '%': /* remove suffix */
+ if (expansion == 0) {
+ debug_printf_parse(": remove suffix/prefix\n");
+ expansion = 2;
+ break;
+ }
+ goto case_default;
+#endif
+ case '-': /* default value */
+ case '=': /* assign default */
+ case '+': /* alternative */
+ case '?': /* error indicate */
+ debug_printf_parse(": parameter expansion\n");
+ expansion = 2;
+ break;
+ default:
+ case_default:
+ syntax("unterminated ${name}");
+ debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
+ return 1;
}
-
- char_ok:
- debug_printf_parse(": '%c'\n", ch);
- o_addchr(dest, ch | quote_mask);
- quote_mask = 0;
- first_char = false;
}
+ char_ok:
+ debug_printf_parse(": '%c'\n", ch);
+ o_addchr(dest, ch | quote_mask);
+ quote_mask = 0;
+ first_char = false;
+ }
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ break;
+ }
+ case '(': {
+ i_getch(input);
+#if ENABLE_SH_MATH_SUPPORT
+ if (i_peek(input) == '(') {
+ i_getch(input);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, /*quote_mask |*/ '+');
+ add_till_closing_paren(dest, input, true);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
}
- case '(': {
- i_getch(input);
-
-#if ENABLE_SH_MATH_SUPPORT
- if (i_peek(input) == '(') {
- i_getch(input);
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- o_addchr(dest, /*quote_mask |*/ '+');
- add_till_closing_paren(dest, input, true);
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- break;
- }
#endif
-
#if ENABLE_HUSH_TICK
- //int pos = dest->length;
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
- o_addchr(dest, quote_mask | '`');
- add_till_closing_paren(dest, input, false);
- //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
- o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ //int pos = dest->length;
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
+ o_addchr(dest, quote_mask | '`');
+ add_till_closing_paren(dest, input, false);
+ //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
+ o_addchr(dest, SPECIAL_VAR_SYMBOL);
#endif
- break;
+ break;
+ }
+ case '_':
+ i_getch(input);
+ ch = i_peek(input);
+ if (isalnum(ch)) { /* it's $_name or $_123 */
+ ch = '_';
+ goto make_var;
}
- case '_':
- i_getch(input);
- ch = i_peek(input);
- if (isalnum(ch)) { /* it's $_name or $_123 */
- ch = '_';
- goto make_var;
- }
- /* else: it's $_ */
- case '-':
- /* still unhandled, but should be eventually */
- bb_error_msg("unhandled syntax: $%c", ch);
- return 1;
- break;
- default:
- o_addQchr(dest, '$');
+ /* else: it's $_ */
+ /* TODO: */
+ /* $_ Shell or shell script name; or last cmd name */
+ /* $- Option flags set by set builtin or shell options (-i etc) */
+ default:
+ o_addQchr(dest, '$');
}
debug_printf_parse("handle_dollar return 0\n");
return 0;
}
-static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end)
+static int parse_stream_dquoted(o_string *dest,
+ struct in_str *input, int dquote_end)
{
int ch;
int next;
@@ -4149,7 +4163,8 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote
}
if (ch == '$') {
if (handle_dollar(dest, input) != 0) {
- debug_printf_parse("parse_stream_dquoted return 1: handle_dollar returned non-0\n");
+ debug_printf_parse("parse_stream_dquoted return 1: "
+ "handle_dollar returned non-0\n");
return 1;
}
goto again;
@@ -4196,8 +4211,8 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
/* 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
- * found. When recursing, quote state is passed in via dest->o_escape. */
-
+ * found. When recursing, quote state is passed in via dest->o_escape.
+ */
debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
end_trigger ? : 'X');
@@ -4338,7 +4353,8 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
break;
case '$':
if (handle_dollar(&dest, input) != 0) {
- debug_printf_parse("parse_stream parse error: handle_dollar returned non-0\n");
+ debug_printf_parse("parse_stream parse error: "
+ "handle_dollar returned non-0\n");
goto parse_error;
}
break;
@@ -4532,8 +4548,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
/* Clean up allocated tree.
* Samples for finding leaks on syntax error recovery path.
- * Execute them from interactive shell and watch pmap `pidof hush`.
- * while if false; then false; fi do break; done (bash accepts it)
+ * Run them from interactive shell, watch pmap `pidof hush`.
+ * while if false; then false; fi do break; done
+ * (bash accepts it)
* while if false; then false; fi; do break; fi
*/
pctx = &ctx;