hush: next small step towards functions

This commit is contained in:
Denis Vlasenko 2008-10-14 12:43:13 +00:00
parent ded6ad34ed
commit 371de4acf7

View File

@ -96,6 +96,12 @@
#endif #endif
/* Keep unconditionally on for now */
#define HUSH_DEBUG 1
/* In progress... */
#define ENABLE_HUSH_FUNCTIONS 0
/* If you comment out one of these below, it will be #defined later /* If you comment out one of these below, it will be #defined later
* to perform debug printfs to stderr: */ * to perform debug printfs to stderr: */
#define debug_printf(...) do {} while (0) #define debug_printf(...) do {} while (0)
@ -218,8 +224,6 @@ void xxfree(void *ptr)
#endif #endif
/* Keep unconditionally on for now */
#define HUSH_DEBUG 1
/* Do we support ANY keywords? */ /* Do we support ANY keywords? */
#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE #if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
#define HAS_KEYWORDS 1 #define HAS_KEYWORDS 1
@ -307,7 +311,7 @@ struct command {
pid_t pid; /* 0 if exited */ pid_t pid; /* 0 if exited */
int assignment_cnt; /* how many argv[i] are assignments? */ int assignment_cnt; /* how many argv[i] are assignments? */
smallint is_stopped; /* is the command currently running? */ smallint is_stopped; /* is the command currently running? */
smallint subshell; /* flag, non-zero if group must be forked */ smallint grp_type;
struct pipe *group; /* if non-NULL, this "prog" is {} group, struct pipe *group; /* if non-NULL, this "prog" is {} group,
* subshell, or a compound statement */ * subshell, or a compound statement */
char **argv; /* command name and arguments */ char **argv; /* command name and arguments */
@ -319,6 +323,11 @@ struct command {
* Example: argv[0]=='.^C*^C.' here: echo .$*. * Example: argv[0]=='.^C*^C.' here: echo .$*.
* References of the form ^C`cmd arg^C are `cmd arg` substitutions. * References of the form ^C`cmd arg^C are `cmd arg` substitutions.
*/ */
#define GRP_NORMAL 0
#define GRP_SUBSHELL 1
#if ENABLE_HUSH_FUNCTIONS
#define GRP_FUNCTION 2
#endif
struct pipe { struct pipe {
struct pipe *next; struct pipe *next;
@ -1016,12 +1025,14 @@ static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len)
static void o_addqchr(o_string *o, int ch) static void o_addqchr(o_string *o, int ch)
{ {
int sz = 1; int sz = 1;
if (strchr("*?[\\", ch)) { char *found = strchr("*?[\\", ch);
if (found)
sz++; sz++;
o_grow_by(o, sz);
if (found) {
o->data[o->length] = '\\'; o->data[o->length] = '\\';
o->length++; o->length++;
} }
o_grow_by(o, sz);
o->data[o->length] = ch; o->data[o->length] = ch;
o->length++; o->length++;
o->data[o->length] = '\0'; o->data[o->length] = '\0';
@ -1834,7 +1845,15 @@ static int run_pipe(struct pipe *pi)
*/ */
command = &(pi->cmds[0]); command = &(pi->cmds[0]);
if (single_and_fg && command->group && command->subshell == 0) { #if ENABLE_HUSH_FUNCTIONS
if (single_and_fg && command->group && command->grp_type == GRP_FUNCTION) {
/* We "execute" function definition */
bb_error_msg("here we ought to remember function definition, and go on");
return EXIT_SUCCESS;
}
#endif
if (single_and_fg && command->group && command->grp_type == GRP_NORMAL) {
debug_printf("non-subshell grouping\n"); debug_printf("non-subshell grouping\n");
setup_redirects(command, squirrel); setup_redirects(command, squirrel);
debug_printf_exec(": run_list\n"); debug_printf_exec(": run_list\n");
@ -2023,7 +2042,7 @@ static int run_pipe(struct pipe *pi)
#ifndef debug_print_tree #ifndef debug_print_tree
static void debug_print_tree(struct pipe *pi, int lvl) static void debug_print_tree(struct pipe *pi, int lvl)
{ {
static const char *PIPE[] = { static const char *const PIPE[] = {
[PIPE_SEQ] = "SEQ", [PIPE_SEQ] = "SEQ",
[PIPE_AND] = "AND", [PIPE_AND] = "AND",
[PIPE_OR ] = "OR" , [PIPE_OR ] = "OR" ,
@ -2057,6 +2076,13 @@ static void debug_print_tree(struct pipe *pi, int lvl)
[RES_XXXX ] = "XXXX" , [RES_XXXX ] = "XXXX" ,
[RES_SNTX ] = "SNTX" , [RES_SNTX ] = "SNTX" ,
}; };
static const char *const GRPTYPE[] = {
"()",
"{}",
#if ENABLE_HUSH_FUNCTIONS
"func()",
#endif
};
int pin, prn; int pin, prn;
@ -2072,7 +2098,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
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) { if (command->group) {
fprintf(stderr, " group %s: (argv=%p)\n", fprintf(stderr, " group %s: (argv=%p)\n",
(command->subshell ? "()" : "{}"), GRPTYPE[command->grp_type],
argv); argv);
debug_print_tree(command->group, lvl+1); debug_print_tree(command->group, lvl+1);
prn++; prn++;
@ -2443,7 +2469,7 @@ static int free_pipe(struct pipe *pi, int indent)
free_strings(command->argv); free_strings(command->argv);
command->argv = NULL; command->argv = NULL;
} else if (command->group) { } else if (command->group) {
debug_printf_clean("%s begin group (subshell:%d)\n", indenter(indent), command->subshell); debug_printf_clean("%s begin group (grp_type:%d)\n", indenter(indent), command->grp_type);
ret_code = free_pipe_list(command->group, indent+3); ret_code = free_pipe_list(command->group, indent+3);
debug_printf_clean("%s end group\n", indenter(indent)); debug_printf_clean("%s end group\n", indenter(indent));
} else { } else {
@ -2572,7 +2598,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
#if ENABLE_HUSH_TICK #if ENABLE_HUSH_TICK
o_string subst_result = NULL_O_STRING; o_string subst_result = NULL_O_STRING;
#endif #endif
o_addstr(output, arg, p - arg); o_addstr(output, arg, p - arg);
debug_print_list("expand_vars_to_list[1]", output, n); debug_print_list("expand_vars_to_list[1]", output, n);
arg = ++p; arg = ++p;
@ -3100,7 +3125,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
done_pipe(ctx, PIPE_SEQ); done_pipe(ctx, PIPE_SEQ);
old = ctx->stack; old = ctx->stack;
old->command->group = ctx->list_head; old->command->group = ctx->list_head;
old->command->subshell = 0; old->command->grp_type = GRP_NORMAL;
*ctx = *old; /* physical copy */ *ctx = *old; /* physical copy */
free(old); free(old);
} }
@ -3461,15 +3486,24 @@ static int process_command_subs(o_string *dest,
static int parse_group(o_string *dest, struct parse_context *ctx, static int parse_group(o_string *dest, struct parse_context *ctx,
struct in_str *input, int ch) struct in_str *input, int ch)
{ {
/* NB: parse_group may create and use its own o_string, /* dest contains characters seen prior to ( or {.
* without any code changes. It just so happens that code is smaller * Typically it's empty, but for functions defs,
* if we (ab)use caller's one. */ * it contains function name (without '()'). */
int rcode; int rcode;
const char *endch = NULL; const char *endch = NULL;
struct parse_context sub; struct parse_context sub;
struct command *command = ctx->command; struct command *command = ctx->command;
debug_printf_parse("parse_group entered\n"); debug_printf_parse("parse_group entered\n");
#if ENABLE_HUSH_FUNCTIONS
if (ch == 'F') { /* function definition? */
bb_error_msg("aha '%s' is a function, parsing it...", dest->data);
//command->fname = dest->data;
command->grp_type = GRP_FUNCTION;
//TODO: review every o_reset() location... do they handle all o_string fields correctly?
memset(dest, 0, sizeof(*dest));
}
#endif
if (command->argv /* word [word](... */ if (command->argv /* word [word](... */
|| dest->length /* word(... */ || dest->length /* word(... */
|| dest->nonnull /* ""(... */ || dest->nonnull /* ""(... */
@ -3482,11 +3516,8 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
endch = "}"; endch = "}";
if (ch == '(') { if (ch == '(') {
endch = ")"; endch = ")";
command->subshell = 1; command->grp_type = GRP_SUBSHELL;
} }
//TODO if (ch == 'F') { /* function definition */
// command->subshell = 2;
// }
rcode = parse_stream(dest, &sub, input, endch); rcode = parse_stream(dest, &sub, input, endch);
if (rcode == 0) { if (rcode == 0) {
done_word(dest, &sub); /* finish off the final word in the subcontext */ done_word(dest, &sub); /* finish off the final word in the subcontext */
@ -3988,16 +4019,18 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
continue; continue;
} }
#endif #endif
#if 0 /* TODO: implement functions */ #if ENABLE_HUSH_FUNCTIONS
if (dest->length != 0 /* not just () but word() */ if (dest->length != 0 /* not just () but word() */
&& dest->nonnull == 0 /* not a"b"c() */ && dest->nonnull == 0 /* not a"b"c() */
&& ctx->command->argv == NULL /* it's the first word */ && ctx->command->argv == NULL /* it's the first word */
//TODO: "func ( ) {...}" - note spaces - is valid format too in bash
&& i_peek(input) == ')' && i_peek(input) == ')'
&& !match_reserved_word(dest) && !match_reserved_word(dest)
) { ) {
bb_error_msg("seems like a function definition"); bb_error_msg("seems like a function definition");
i_getch(input); i_getch(input);
do { do {
//TODO: do it properly.
ch = i_getch(input); ch = i_getch(input);
} while (ch == ' ' || ch == '\n'); } while (ch == ' ' || ch == '\n');
if (ch != '{') { if (ch != '{') {
@ -4005,6 +4038,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx,
debug_printf_parse("parse_stream return 1\n"); debug_printf_parse("parse_stream return 1\n");
return 1; return 1;
} }
ch = 'F'; /* magic value */
} }
#endif #endif
case '{': case '{':