hush: get rid of charmap[]
function old new delta parse_stream 1447 1508 +61 get_local_var_value - 31 +31 run_list 2018 2020 +2 pseudo_exec_argv 151 149 -2 maybe_set_sighandler 50 47 -3 hush_exit 93 90 -3 builtin_wait 275 272 -3 check_and_run_traps 169 164 -5 hush_main 985 977 -8 file_get 260 240 -20 builtin_trap 438 414 -24 set_in_charmap 30 - -30 lookup_param 31 - -31 parse_and_run_stream 153 54 -99 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 2/9 up/down: 94/-228) Total: -134 bytes
This commit is contained in:
145
shell/hush.c
145
shell/hush.c
@ -61,7 +61,6 @@
|
|||||||
* figure out what to do with backslash-newline
|
* figure out what to do with backslash-newline
|
||||||
* propagate syntax errors, die on resource errors?
|
* propagate syntax errors, die on resource errors?
|
||||||
* continuation lines, both explicit and implicit - done?
|
* 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.
|
* 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.
|
* Leak hunting. Use hush_leaktool.sh for post-processing.
|
||||||
*/
|
*/
|
||||||
#ifdef FOR_HUSH_LEAKTOOL
|
#ifdef FOR_HUSH_LEAKTOOL
|
||||||
/* suppress "warning: no previous prototype..." */
|
static void *xxmalloc(int lineno, size_t size)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
void *ptr = xmalloc((size + 0xff) & ~0xff);
|
void *ptr = xmalloc((size + 0xff) & ~0xff);
|
||||||
fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
|
fdprintf(2, "line %d: malloc %p\n", lineno, ptr);
|
||||||
return 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);
|
ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
|
||||||
fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
|
fdprintf(2, "line %d: realloc %p\n", lineno, ptr);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
char *xxstrdup(int lineno, const char *str)
|
static char *xxstrdup(int lineno, const char *str)
|
||||||
{
|
{
|
||||||
char *ptr = xstrdup(str);
|
char *ptr = xstrdup(str);
|
||||||
fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
|
fdprintf(2, "line %d: strdup %p\n", lineno, ptr);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
void xxfree(void *ptr)
|
static void xxfree(void *ptr)
|
||||||
{
|
{
|
||||||
fdprintf(2, "free %p\n", ptr);
|
fdprintf(2, "free %p\n", ptr);
|
||||||
free(ptr);
|
free(ptr);
|
||||||
@ -491,14 +485,6 @@ struct globals {
|
|||||||
const char *cwd;
|
const char *cwd;
|
||||||
struct variable *top_var; /* = &G.shell_ver (set in main()) */
|
struct variable *top_var; /* = &G.shell_ver (set in main()) */
|
||||||
struct variable shell_ver;
|
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 */
|
/* Signal and trap handling */
|
||||||
// unsigned count_SIGCHLD;
|
// unsigned count_SIGCHLD;
|
||||||
// unsigned handled_SIGCHLD;
|
// unsigned handled_SIGCHLD;
|
||||||
@ -507,6 +493,13 @@ struct globals {
|
|||||||
char **traps; /* char *traps[NSIG] */
|
char **traps; /* char *traps[NSIG] */
|
||||||
sigset_t blocked_set;
|
sigset_t blocked_set;
|
||||||
sigset_t inherited_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)
|
#define G (*ptr_to_globals)
|
||||||
/* Not #defining name to G.name - this quickly gets unwieldy
|
/* 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Basically useful version until someone wants to get fancier,
|
static const char *get_local_var_value(const char *src)
|
||||||
* see the bash man page under "Parameter Expansion" */
|
|
||||||
static const char *lookup_param(const char *src)
|
|
||||||
{
|
{
|
||||||
struct variable *var = get_local_var(src);
|
struct variable *var = get_local_var(src);
|
||||||
if (var)
|
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);
|
o_free(&dest);
|
||||||
}
|
}
|
||||||
skip_expand:
|
skip_expand:
|
||||||
hooks.lookupvar = lookup_param;
|
hooks.lookupvar = get_local_var_value;
|
||||||
hooks.setvar = arith_set_local_var;
|
hooks.setvar = arith_set_local_var;
|
||||||
hooks.endofname = endofname;
|
hooks.endofname = endofname;
|
||||||
res = arith(exp_str ? exp_str : arg, &errcode, &hooks);
|
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];
|
val = G.global_argv[i];
|
||||||
/* else val remains NULL: $N with too big N */
|
/* else val remains NULL: $N with too big N */
|
||||||
} else
|
} else
|
||||||
val = lookup_param(var);
|
val = get_local_var_value(var);
|
||||||
|
|
||||||
/* handle any expansions */
|
/* handle any expansions */
|
||||||
if (exp_len) {
|
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)
|
static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end)
|
||||||
{
|
{
|
||||||
int ch, m;
|
int ch;
|
||||||
int next;
|
int next;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
@ -4136,7 +4127,6 @@ static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
next = '\0';
|
next = '\0';
|
||||||
m = G.charmap[ch];
|
|
||||||
if (ch != '\n') {
|
if (ch != '\n') {
|
||||||
next = i_peek(input);
|
next = i_peek(input);
|
||||||
}
|
}
|
||||||
@ -4206,11 +4196,11 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
|
|||||||
{
|
{
|
||||||
struct parse_context ctx;
|
struct parse_context ctx;
|
||||||
o_string dest = NULL_O_STRING;
|
o_string dest = NULL_O_STRING;
|
||||||
int ch, m;
|
|
||||||
int redir_fd;
|
int redir_fd;
|
||||||
redir_type redir_style;
|
|
||||||
int is_in_dquote;
|
|
||||||
int next;
|
int next;
|
||||||
|
int is_in_dquote;
|
||||||
|
int ch;
|
||||||
|
redir_type redir_style;
|
||||||
|
|
||||||
/* Double-quote state is handled in the state variable is_in_dquote.
|
/* 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
|
* 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",
|
debug_printf_parse("parse_stream entered, end_trigger='%c'\n",
|
||||||
end_trigger ? : 'X');
|
end_trigger ? : 'X');
|
||||||
|
|
||||||
|
G.ifs = get_local_var_value("IFS");
|
||||||
|
if (G.ifs == NULL)
|
||||||
|
G.ifs = " \t\n";
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
#if ENABLE_HUSH_INTERACTIVE
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
input->promptmode = 0; /* PS1 */
|
input->promptmode = 0; /* PS1 */
|
||||||
@ -4227,6 +4221,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
|
|||||||
initialize_context(&ctx);
|
initialize_context(&ctx);
|
||||||
is_in_dquote = 0;
|
is_in_dquote = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
const char *is_ifs;
|
||||||
|
const char *is_special;
|
||||||
|
|
||||||
if (is_in_dquote) {
|
if (is_in_dquote) {
|
||||||
if (parse_stream_dquoted(&dest, input, '"')) {
|
if (parse_stream_dquoted(&dest, input, '"')) {
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
@ -4234,18 +4231,38 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
|
|||||||
/* We reached closing '"' */
|
/* We reached closing '"' */
|
||||||
is_in_dquote = 0;
|
is_in_dquote = 0;
|
||||||
}
|
}
|
||||||
m = CHAR_IFS;
|
|
||||||
next = '\0';
|
next = '\0';
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
if (ch != EOF) {
|
debug_printf_parse(": ch=%c (%d) escape=%d\n",
|
||||||
m = G.charmap[ch];
|
ch, ch, dest.o_escape);
|
||||||
if (ch != '\n') {
|
if (ch == EOF) {
|
||||||
next = i_peek(input);
|
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",
|
if (ch != '\n') {
|
||||||
ch, ch, m, dest.o_escape);
|
next = i_peek(input);
|
||||||
if (m == CHAR_ORDINARY) {
|
}
|
||||||
|
|
||||||
|
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);
|
o_addQchr(&dest, ch);
|
||||||
if ((dest.o_assignment == MAYBE_ASSIGNMENT
|
if ((dest.o_assignment == MAYBE_ASSIGNMENT
|
||||||
|| dest.o_assignment == WORD_IS_KEYWORD)
|
|| dest.o_assignment == WORD_IS_KEYWORD)
|
||||||
@ -4257,27 +4274,7 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) */
|
if (is_ifs) {
|
||||||
|
|
||||||
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 (done_word(&dest, &ctx)) {
|
if (done_word(&dest, &ctx)) {
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
}
|
}
|
||||||
@ -4317,11 +4314,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger)
|
|||||||
return ctx.list_head;
|
return ctx.list_head;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m == CHAR_IFS)
|
if (is_ifs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */
|
|
||||||
|
|
||||||
if (dest.o_assignment == MAYBE_ASSIGNMENT) {
|
if (dest.o_assignment == MAYBE_ASSIGNMENT) {
|
||||||
/* ch is a special char and thus this word
|
/* ch is a special char and thus this word
|
||||||
* cannot be an assignment */
|
* 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 '...'
|
/* Execiting from string: eval, sh -c '...'
|
||||||
* or from file: /etc/profile, . file, sh <script>, sh (intereactive)
|
* or from file: /etc/profile, . file, sh <script>, sh (intereactive)
|
||||||
* end_trigger controls how often we stop parsing
|
* 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) {
|
while (1) {
|
||||||
struct pipe *pipe_list;
|
struct pipe *pipe_list;
|
||||||
|
|
||||||
update_charmap();
|
|
||||||
|
|
||||||
pipe_list = parse_stream(inp, end_trigger);
|
pipe_list = parse_stream(inp, end_trigger);
|
||||||
if (!pipe_list) /* EOF */
|
if (!pipe_list) /* EOF */
|
||||||
break;
|
break;
|
||||||
debug_print_tree(pipe_list, 0);
|
debug_print_tree(pipe_list, 0);
|
||||||
debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
|
debug_printf_exec("parse_and_run_stream: run_and_free_list\n");
|
||||||
run_and_free_list(pipe_list);
|
run_and_free_list(pipe_list);
|
||||||
/* Loop on syntax errors, return on EOF: */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user