hush: using smallints where we can. save ~20 bytes in code and
some data storage at runtime.
This commit is contained in:
97
shell/hush.c
97
shell/hush.c
@@ -137,9 +137,10 @@ static const char *indenter(int i)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SPECIAL_VAR_SYMBOL 3
|
#define SPECIAL_VAR_SYMBOL 3
|
||||||
#define FLAG_EXIT_FROM_LOOP 1
|
|
||||||
#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
|
#define PARSEFLAG_EXIT_FROM_LOOP 1
|
||||||
#define FLAG_REPARSING (1 << 2) /* >= 2nd pass */
|
#define PARSEFLAG_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
|
||||||
|
#define PARSEFLAG_REPARSING (1 << 2) /* >= 2nd pass */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
REDIRECT_INPUT = 1,
|
REDIRECT_INPUT = 1,
|
||||||
@@ -210,10 +211,10 @@ struct p_context {
|
|||||||
struct pipe *list_head;
|
struct pipe *list_head;
|
||||||
struct pipe *pipe;
|
struct pipe *pipe;
|
||||||
struct redir_struct *pending_redirect;
|
struct redir_struct *pending_redirect;
|
||||||
reserved_style res_w;
|
smallint res_w;
|
||||||
int old_flag; /* for figuring out valid reserved words */
|
smallint parse_type; /* bitmask of PARSEFLAG_xxx, defines type of parser : ";$" common or special symbol */
|
||||||
|
int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */
|
||||||
struct p_context *stack;
|
struct p_context *stack;
|
||||||
int parse_type; /* define type of parser : ";$" common or special symbol */
|
|
||||||
/* How about quoting status? */
|
/* How about quoting status? */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,17 +250,17 @@ struct pipe {
|
|||||||
struct pipe *next;
|
struct pipe *next;
|
||||||
int num_progs; /* total number of programs in job */
|
int num_progs; /* total number of programs in job */
|
||||||
int running_progs; /* number of programs running (not exited) */
|
int running_progs; /* number of programs running (not exited) */
|
||||||
char *cmdbuf; /* buffer various argv's point into */
|
int stopped_progs; /* number of programs alive, but stopped */
|
||||||
#if ENABLE_HUSH_JOB
|
#if ENABLE_HUSH_JOB
|
||||||
int jobid; /* job number */
|
int jobid; /* job number */
|
||||||
char *cmdtext; /* name of job */
|
|
||||||
pid_t pgrp; /* process group ID for the job */
|
pid_t pgrp; /* process group ID for the job */
|
||||||
|
char *cmdtext; /* name of job */
|
||||||
#endif
|
#endif
|
||||||
|
char *cmdbuf; /* buffer various argv's point into */
|
||||||
struct child_prog *progs; /* array of commands in pipe */
|
struct child_prog *progs; /* array of commands in pipe */
|
||||||
int stopped_progs; /* number of programs alive, but stopped */
|
|
||||||
int job_context; /* bitmask defining current context */
|
int job_context; /* bitmask defining current context */
|
||||||
pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
|
smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
|
||||||
reserved_style r_mode; /* supports if, for, while, until */
|
smallint res_word; /* needed for if, for, while, until... */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct close_me {
|
struct close_me {
|
||||||
@@ -271,8 +272,8 @@ struct variables {
|
|||||||
struct variables *next;
|
struct variables *next;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *value;
|
const char *value;
|
||||||
int flg_export;
|
smallint flg_export;
|
||||||
int flg_read_only;
|
smallint flg_read_only;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -703,8 +704,8 @@ static int builtin_eval(char **argv)
|
|||||||
|
|
||||||
if (argv[1]) {
|
if (argv[1]) {
|
||||||
str = make_string(argv + 1);
|
str = make_string(argv + 1);
|
||||||
parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
|
parse_string_outer(str, PARSEFLAG_EXIT_FROM_LOOP |
|
||||||
FLAG_PARSE_SEMICOLON);
|
PARSEFLAG_SEMICOLON);
|
||||||
free(str);
|
free(str);
|
||||||
rcode = last_return_code;
|
rcode = last_return_code;
|
||||||
}
|
}
|
||||||
@@ -1897,10 +1898,11 @@ static void debug_print_tree(struct pipe *pi, int lvl)
|
|||||||
};
|
};
|
||||||
|
|
||||||
int pin, prn;
|
int pin, prn;
|
||||||
|
|
||||||
pin = 0;
|
pin = 0;
|
||||||
while (pi) {
|
while (pi) {
|
||||||
fprintf(stderr, "%*spipe %d r_mode=%s followup=%d %s\n", lvl*2, "",
|
fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "",
|
||||||
pin, RES[pi->r_mode], pi->followup, PIPE[pi->followup]);
|
pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]);
|
||||||
prn = 0;
|
prn = 0;
|
||||||
while (prn < pi->num_progs) {
|
while (prn < pi->num_progs) {
|
||||||
struct child_prog *child = &pi->progs[prn];
|
struct child_prog *child = &pi->progs[prn];
|
||||||
@@ -1942,21 +1944,22 @@ static int run_list_real(struct pipe *pi)
|
|||||||
int rcode = 0; /* probably for gcc only */
|
int rcode = 0; /* probably for gcc only */
|
||||||
int flag_restore = 0;
|
int flag_restore = 0;
|
||||||
int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */
|
int if_code = 0, next_if_code = 0; /* need double-buffer to handle elif */
|
||||||
reserved_style rmode, skip_more_in_this_rmode = RES_XXXX;
|
reserved_style rword;
|
||||||
|
reserved_style skip_more_for_this_rword = RES_XXXX;
|
||||||
|
|
||||||
debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1);
|
debug_printf_exec("run_list_real start lvl %d\n", run_list_level + 1);
|
||||||
|
|
||||||
/* check syntax for "for" */
|
/* check syntax for "for" */
|
||||||
for (rpipe = pi; rpipe; rpipe = rpipe->next) {
|
for (rpipe = pi; rpipe; rpipe = rpipe->next) {
|
||||||
if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR)
|
if ((rpipe->res_word == RES_IN || rpipe->res_word == RES_FOR)
|
||||||
&& (rpipe->next == NULL)
|
&& (rpipe->next == NULL)
|
||||||
) {
|
) {
|
||||||
syntax(); /* unterminated FOR (no IN or no commands after IN) */
|
syntax(); /* unterminated FOR (no IN or no commands after IN) */
|
||||||
debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
|
debug_printf_exec("run_list_real lvl %d return 1\n", run_list_level);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ((rpipe->r_mode == RES_IN && rpipe->next->r_mode == RES_IN && rpipe->next->progs[0].argv != NULL)
|
if ((rpipe->res_word == RES_IN && rpipe->next->res_word == RES_IN && rpipe->next->progs[0].argv != NULL)
|
||||||
|| (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN)
|
|| (rpipe->res_word == RES_FOR && rpipe->next->res_word != RES_IN)
|
||||||
) {
|
) {
|
||||||
/* TODO: what is tested in the first condition? */
|
/* TODO: what is tested in the first condition? */
|
||||||
syntax(); /* 2nd: malformed FOR (not followed by IN) */
|
syntax(); /* 2nd: malformed FOR (not followed by IN) */
|
||||||
@@ -2008,32 +2011,32 @@ static int run_list_real(struct pipe *pi)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (; pi; pi = flag_restore ? rpipe : pi->next) {
|
for (; pi; pi = flag_restore ? rpipe : pi->next) {
|
||||||
rmode = pi->r_mode;
|
rword = pi->res_word;
|
||||||
if (rmode == RES_WHILE || rmode == RES_UNTIL || rmode == RES_FOR) {
|
if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
|
||||||
flag_restore = 0;
|
flag_restore = 0;
|
||||||
if (!rpipe) {
|
if (!rpipe) {
|
||||||
flag_rep = 0;
|
flag_rep = 0;
|
||||||
rpipe = pi;
|
rpipe = pi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_printf_exec(": rmode=%d if_code=%d next_if_code=%d skip_more=%d\n",
|
debug_printf_exec(": rword=%d if_code=%d next_if_code=%d skip_more=%d\n",
|
||||||
rmode, if_code, next_if_code, skip_more_in_this_rmode);
|
rword, if_code, next_if_code, skip_more_for_this_rword);
|
||||||
if (rmode == skip_more_in_this_rmode && flag_skip) {
|
if (rword == skip_more_for_this_rword && flag_skip) {
|
||||||
if (pi->followup == PIPE_SEQ)
|
if (pi->followup == PIPE_SEQ)
|
||||||
flag_skip = 0;
|
flag_skip = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
flag_skip = 1;
|
flag_skip = 1;
|
||||||
skip_more_in_this_rmode = RES_XXXX;
|
skip_more_for_this_rword = RES_XXXX;
|
||||||
if (rmode == RES_THEN || rmode == RES_ELSE)
|
if (rword == RES_THEN || rword == RES_ELSE)
|
||||||
if_code = next_if_code;
|
if_code = next_if_code;
|
||||||
if (rmode == RES_THEN && if_code)
|
if (rword == RES_THEN && if_code)
|
||||||
continue;
|
continue;
|
||||||
if (rmode == RES_ELSE && !if_code)
|
if (rword == RES_ELSE && !if_code)
|
||||||
continue;
|
continue;
|
||||||
if (rmode == RES_ELIF && !if_code)
|
if (rword == RES_ELIF && !if_code)
|
||||||
break;
|
break;
|
||||||
if (rmode == RES_FOR && pi->num_progs) {
|
if (rword == RES_FOR && pi->num_progs) {
|
||||||
if (!for_lcur) {
|
if (!for_lcur) {
|
||||||
/* if no variable values after "in" we skip "for" */
|
/* if no variable values after "in" we skip "for" */
|
||||||
if (!pi->next->progs->argv)
|
if (!pi->next->progs->argv)
|
||||||
@@ -2059,13 +2062,13 @@ static int run_list_real(struct pipe *pi)
|
|||||||
pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
|
pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
|
||||||
pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
|
pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0];
|
||||||
}
|
}
|
||||||
if (rmode == RES_IN)
|
if (rword == RES_IN)
|
||||||
continue;
|
continue;
|
||||||
if (rmode == RES_DO) {
|
if (rword == RES_DO) {
|
||||||
if (!flag_rep)
|
if (!flag_rep)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rmode == RES_DONE) {
|
if (rword == RES_DONE) {
|
||||||
if (flag_rep) {
|
if (flag_rep) {
|
||||||
flag_restore = 1;
|
flag_restore = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -2107,16 +2110,16 @@ static int run_list_real(struct pipe *pi)
|
|||||||
debug_printf_exec(": setting last_return_code=%d\n", rcode);
|
debug_printf_exec(": setting last_return_code=%d\n", rcode);
|
||||||
last_return_code = rcode;
|
last_return_code = rcode;
|
||||||
pi->num_progs = save_num_progs; /* restore number of programs */
|
pi->num_progs = save_num_progs; /* restore number of programs */
|
||||||
if (rmode == RES_IF || rmode == RES_ELIF)
|
if (rword == RES_IF || rword == RES_ELIF)
|
||||||
next_if_code = rcode; /* can be overwritten a number of times */
|
next_if_code = rcode; /* can be overwritten a number of times */
|
||||||
if (rmode == RES_WHILE)
|
if (rword == RES_WHILE)
|
||||||
flag_rep = !last_return_code;
|
flag_rep = !last_return_code;
|
||||||
if (rmode == RES_UNTIL)
|
if (rword == RES_UNTIL)
|
||||||
flag_rep = last_return_code;
|
flag_rep = last_return_code;
|
||||||
if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR)
|
if ((rcode == EXIT_SUCCESS && pi->followup == PIPE_OR)
|
||||||
|| (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND)
|
|| (rcode != EXIT_SUCCESS && pi->followup == PIPE_AND)
|
||||||
) {
|
) {
|
||||||
skip_more_in_this_rmode = rmode;
|
skip_more_for_this_rword = rword;
|
||||||
}
|
}
|
||||||
checkjobs(NULL);
|
checkjobs(NULL);
|
||||||
}
|
}
|
||||||
@@ -2192,7 +2195,7 @@ static int free_pipe_list(struct pipe *head, int indent)
|
|||||||
struct pipe *pi, *next;
|
struct pipe *pi, *next;
|
||||||
|
|
||||||
for (pi = head; pi; pi = next) {
|
for (pi = head; pi; pi = next) {
|
||||||
debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->r_mode);
|
debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
|
||||||
rcode = free_pipe(pi, indent);
|
rcode = free_pipe(pi, indent);
|
||||||
debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
|
debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
|
||||||
next = pi->next;
|
next = pi->next;
|
||||||
@@ -2786,7 +2789,7 @@ static struct pipe *new_pipe(void)
|
|||||||
/*pi->next = NULL;*/
|
/*pi->next = NULL;*/
|
||||||
/*pi->followup = 0; invalid */
|
/*pi->followup = 0; invalid */
|
||||||
if (RES_NONE)
|
if (RES_NONE)
|
||||||
pi->r_mode = RES_NONE;
|
pi->res_word = RES_NONE;
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2898,7 +2901,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
|
|||||||
debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
|
debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!child->argv && (ctx->parse_type & FLAG_PARSE_SEMICOLON)) {
|
if (!child->argv && (ctx->parse_type & PARSEFLAG_SEMICOLON)) {
|
||||||
debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data);
|
debug_printf_parse(": checking '%s' for reserved-ness\n", dest->data);
|
||||||
if (reserved_word(dest, ctx)) {
|
if (reserved_word(dest, ctx)) {
|
||||||
debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
|
debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
|
||||||
@@ -2986,7 +2989,7 @@ static int done_pipe(struct p_context *ctx, pipe_style type)
|
|||||||
debug_printf_parse("done_pipe entered, followup %d\n", type);
|
debug_printf_parse("done_pipe entered, followup %d\n", type);
|
||||||
not_null = done_command(ctx); /* implicit closure of previous command */
|
not_null = done_command(ctx); /* implicit closure of previous command */
|
||||||
ctx->pipe->followup = type;
|
ctx->pipe->followup = type;
|
||||||
ctx->pipe->r_mode = ctx->res_w;
|
ctx->pipe->res_word = ctx->res_w;
|
||||||
/* Without this check, even just <enter> on command line generates
|
/* Without this check, even just <enter> on command line generates
|
||||||
* tree of three NOPs (!). Which is harmless but annoying.
|
* tree of three NOPs (!). Which is harmless but annoying.
|
||||||
* IOW: it is safe to do it unconditionally. */
|
* IOW: it is safe to do it unconditionally. */
|
||||||
@@ -3510,7 +3513,7 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag)
|
|||||||
ctx.parse_type = parse_flag;
|
ctx.parse_type = parse_flag;
|
||||||
initialize_context(&ctx);
|
initialize_context(&ctx);
|
||||||
update_charmap();
|
update_charmap();
|
||||||
if (!(parse_flag & FLAG_PARSE_SEMICOLON) || (parse_flag & FLAG_REPARSING))
|
if (!(parse_flag & PARSEFLAG_SEMICOLON) || (parse_flag & PARSEFLAG_REPARSING))
|
||||||
set_in_charmap(";$&|", CHAR_ORDINARY);
|
set_in_charmap(";$&|", CHAR_ORDINARY);
|
||||||
#if ENABLE_HUSH_INTERACTIVE
|
#if ENABLE_HUSH_INTERACTIVE
|
||||||
inp->promptmode = 1;
|
inp->promptmode = 1;
|
||||||
@@ -3539,7 +3542,7 @@ static int parse_stream_outer(struct in_str *inp, int parse_flag)
|
|||||||
free_pipe_list(ctx.list_head, 0);
|
free_pipe_list(ctx.list_head, 0);
|
||||||
}
|
}
|
||||||
b_free(&temp);
|
b_free(&temp);
|
||||||
} while (rcode != -1 && !(parse_flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
|
} while (rcode != -1 && !(parse_flag & PARSEFLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3555,7 +3558,7 @@ static int parse_file_outer(FILE *f)
|
|||||||
int rcode;
|
int rcode;
|
||||||
struct in_str input;
|
struct in_str input;
|
||||||
setup_file_in_str(&input, f);
|
setup_file_in_str(&input, f);
|
||||||
rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
|
rcode = parse_stream_outer(&input, PARSEFLAG_SEMICOLON);
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3646,7 +3649,7 @@ int hush_main(int argc, char **argv)
|
|||||||
case 'c':
|
case 'c':
|
||||||
global_argv = argv + optind;
|
global_argv = argv + optind;
|
||||||
global_argc = argc - optind;
|
global_argc = argc - optind;
|
||||||
opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
|
opt = parse_string_outer(optarg, PARSEFLAG_SEMICOLON);
|
||||||
goto final_return;
|
goto final_return;
|
||||||
case 'i':
|
case 'i':
|
||||||
/* Well, we cannot just declare interactiveness,
|
/* Well, we cannot just declare interactiveness,
|
||||||
|
Reference in New Issue
Block a user