From 2d0529c9bc0c4fedefa816d6b6d371b1d5b8c32e Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 9 Jun 2008 07:50:25 +0000 Subject: [PATCH] msh_function.patch: picked it up in the wild. Fixed allocation bugs (it was allocating one too small vectors) but it still is very buggy, thus not applied. --- shell/msh_function.patch | 350 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 shell/msh_function.patch diff --git a/shell/msh_function.patch b/shell/msh_function.patch new file mode 100644 index 000000000..b02b291e1 --- /dev/null +++ b/shell/msh_function.patch @@ -0,0 +1,350 @@ +This is a "function" patch for msh which is in use by some busybox +users. Unfortunately it is far too buggy to be applied, but maybe +it's a useful starting point for future work. + +Function-related code is delimited by comments of the form + //funccode:start + ... + //funccode:end +for ease of grepping + +An example of buggy behavior: + +#f() { +# echo foo +# echo test`echo bar >&2` +# echo END f +#} + +function g { +# echo 2 foo +# echo 2 test`echo 2 bar >&2` +# f + echo END g +# echo "1:'$1' 2:'$2'" +} + +# Even this first block fails - it does not even call functions! +# (replacing "echo END g" above with "echo END" makes it run ok) +echo DRY RUN + echo 2 foo + echo 2 test`echo 2 bar >&2` + echo END g + echo "1:'$1' 2:'$2'" + echo foo + echo test`echo bar >&2` + echo END f +echo END DRY RUN + +exit + +# This would fail too +g "$1-one" "two$2" +echo DONE + + + +diff -d -urpN busybox.7/shell/msh.c busybox.8/shell/msh.c +--- busybox.7/shell/msh.c 2008-06-09 09:34:45.000000000 +0200 ++++ busybox.8/shell/msh.c 2008-06-09 09:38:17.000000000 +0200 +@@ -89,6 +89,14 @@ static char *itoa(int n) + + //#define MSHDEBUG 4 + ++/* Used only in "function" support code */ ++#ifdef KSDBG //funccode:start ++ #define KSDBG_PRINT_FUNCNAME fprintf(stderr, "in %s\n", __FUNCTION__) ++#else ++ #define KSDBG_PRINT_FUNCNAME ((void)0) ++#endif ++//funccode:end ++ + #ifdef MSHDEBUG + static int mshdbg = MSHDEBUG; + +@@ -220,6 +228,9 @@ struct op { + #define TASYNC 16 /* c & */ + /* Added to support "." file expansion */ + #define TDOT 17 ++#define TFUNC 18 //funccode:start ++#define TRETURN 19 ++ //funccode:end + + /* Strings for names to make debug easier */ + #ifdef MSHDEBUG +@@ -319,6 +330,27 @@ struct region { + int area; + }; + ++static int func_finished; //funccode:start ++struct func { ++ char* name; ++ int begin_addr; /* pos in buffer of function */ ++ int end_addr; ++}; ++#define MAX_FUNCS 100 ++ ++static struct func funcs[MAX_FUNCS]; ++ ++/* the max DEPTH of function call */ ++#define MAX_DEPTH 100 ++static struct _frame_s { ++ int argc; ++ char **argv; ++ int saved_return_addr; ++} frame[MAX_DEPTH]; ++ ++static void register_func(int begin, int end); ++static struct func* find_func(char* name); ++static void exec_func(struct func* f); //funccode:end + + /* -------- grammar stuff -------- */ + typedef union { +@@ -347,6 +379,8 @@ typedef union { + #define IN 272 + /* Added for "." file expansion */ + #define DOT 273 ++#define FUNC 274 //funccode:start ++#define RETURN 275 //funccode:end + + #define YYERRCODE 300 + +@@ -1722,6 +1756,40 @@ static struct op *simple(void) + (void) synio(0); + break; + ++ case FUNC: { //funccode:start ++ int stop_flag; ++ int number_brace; ++ int func_begin; ++ int func_end; ++ int c; ++ while ((c = my_getc(0)) == ' ' || c == '\t'|| c == '\n') /* skip whitespace */ ++ continue; ++ stop_flag = 1; ++ number_brace = 0; ++ func_begin = global_env.iobase->argp->afpos; ++ while (stop_flag) { ++ if (c == '{') ++ number_brace++; ++ if (c == '}') ++ number_brace--; ++ if (!number_brace) /* if we reach the brace of most outsite */ ++ stop_flag = 0; ++ c = my_getc(0); ++ } ++ unget(c); ++ unget(c); ++ func_end = global_env.iobase->argp->afpos; ++ register_func(func_begin, func_end); ++ peeksym = 0; ++ t = NULL; ++ return t; ++ } ++ case RETURN: ++ func_finished = 1; ++ peeksym = 0; ++ t = NULL; ++ return t; //funccode:end ++ + case WORD: + if (t == NULL) { + t = newtp(); +@@ -2265,6 +2333,13 @@ static int yylex(int cf) + case ')': + startl = 1; + return c; ++ case '{': //funccode:start ++ c = collect(c, '}'); ++ if (c != '\0') ++ return c; ++ break; ++ case '}': ++ return RETURN; //funccode:end + } + + unget(c); +@@ -2293,9 +2368,172 @@ static int yylex(int cf) + } + + yylval.cp = strsave(line, areanum); ++ /* To identify a subroutine */ //funccode:start ++ c = my_getc(0); ++ if (c && any(c, "(")) { ++ c = my_getc(0); ++ if (c && any(c, ")")) ++ return FUNC; ++ zzerr(); ++ } else ++ unget(c); ++ /* read the first char */ ++ /* To identify a function */ ++ if (strcmp(yylval.cp, "function") == 0) { ++ int ret = yylex(0); ++ /* read the function name after "function" */ ++ if (ret == WORD) ++ return (FUNC); ++ zzerr(); ++ } ++ { ++ struct func* f = find_func(yylval.cp); ++ if (f != NULL) { ++ exec_func(f); ++ return RETURN; ++ } ++ } ++ if (yylval.cp != NULL && strcmp(yylval.cp, "return") == 0) { ++ return RETURN; ++ } //funccode:end + return WORD; + } + ++static void register_func(int begin, int end) //funccode:start ++{ ++ struct func *p; ++ int i; ++ for (i = 0; i < MAX_FUNCS; i++) { ++ if (funcs[i].name == NULL) { ++ p = &funcs[i]; ++ break; ++ } ++ } ++ if (i == MAX_FUNCS) { ++ fprintf(stderr, "Too much functions beyond limit\n"); ++ leave(); ++ } ++ p->name = xstrdup(yylval.cp); ++ //fprintf(stderr, "register function,%d,%d,%s\n", begin, end, p->name); ++ KSDBG_PRINT_FUNCNAME; ++ /* io stream */ ++ p->begin_addr = begin; ++ p->end_addr = end; ++} ++ ++static struct func* find_func(char* name) ++{ ++ int i; ++ for (i = 0; i < MAX_FUNCS; i++) { ++ if (funcs[i].name == NULL) ++ continue; ++ if (!strcmp(funcs[i].name, name)) ++ return &funcs[i]; ++ } ++ KSDBG_PRINT_FUNCNAME; ++ //fprintf(stderr, "not found the function %s\n", name); ++ return NULL; ++ //zzerr(); ++} ++ ++/* Begin to execute the function */ ++static int cur_frame = 0; ++ ++static void exec_func(struct func* f) ++{ ++ int c; ++ int temp_argc; ++ char** temp_argv; ++ struct iobuf *bp; ++ ++ /* create a new frame, save the argument and return address to this frame */ ++ frame[cur_frame].argc = dolc; ++ frame[cur_frame].argv = dolv; ++ ++ cur_frame++; ++ /* do some argment parse and set arguments */ ++ temp_argv = xmalloc(sizeof(char *)); ++ temp_argv[0] = xstrdup(f->name); ++ temp_argc = 0; ++ global_env.iop->argp->afpos--; ++ global_env.iop->argp->afbuf->bufp--; ++// unget(c); ++ while (((c = yylex(0)) != '\n') && (yylval.cp != NULL)) { ++ temp_argc++; ++ temp_argv = xrealloc(temp_argv, sizeof(char *) * (temp_argc+1)); ++ /* parse $ var if passed argument is a variable */ ++ if (yylval.cp[0] == '$') { ++ struct var *arg = lookup(&yylval.cp[1]); ++ temp_argv[temp_argc] = xstrdup(arg->value); ++ //fprintf(stderr, "arg->value=%s\n", arg->value); ++ } else { ++ temp_argv[temp_argc] = xstrdup(yylval.cp); ++ //fprintf(stderr, "ARG:%s\n", yylval.cp); ++ } ++ } ++ /* ++ global_env.iop->argp->afpos--; ++ global_env.iop->argp->afbuf->bufp--; ++ */ ++ dolc = temp_argc; ++ dolv = temp_argv; ++ //unget(c); ++ //while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */ ++ // continue; ++ //unget(c); ++ frame[cur_frame].saved_return_addr = global_env.iop->argp->afpos; ++ ++ /* get function begin address and execute this function */ ++ ++ bp = global_env.iop->argp->afbuf; ++ bp->bufp = &(bp->buf[f->begin_addr]); ++ global_env.iop->argp->afpos = f->begin_addr; ++ ++ /* func_finished=0 means we are in a function and func_finished=1 means we are executing a function */ ++ func_finished = 0; ++ ++ //fprintf(stderr, "exec function %s\n", f->name); ++ KSDBG_PRINT_FUNCNAME; ++ for (;;) { ++ //fprintf(stderr, "afpos=%d,%s\n", global_env.iop->argp->afpos, yylval.cp); ++ if (global_env.iop->argp->afpos == f->end_addr) ++ break; ++ onecommand(); ++ /* we return from a function, when func_finished = 1 */ ++ if (func_finished) ++ break; ++ } ++ ++ { ++ //fprintf(stderr, "%s is finished @%d!\n", f->name, global_env.iop->argp->afpos); ++ int ret = frame[cur_frame].saved_return_addr; ++ /* workaround code for \n */ ++ if (dolc) ++ ret--; ++ /* get return address from current frame and jump to */ ++ global_env.iop->argp->afpos = ret; ++ global_env.iop->argp->afbuf->bufp = &(global_env.iop->argp->afbuf->buf[ret]); ++ } ++ /* ++ fprintf(stderr, "******** after execution ********************\n"); ++ fprintf(stderr, " %s \n############# %d\n", global_env.iop->argp->afbuf->bufp, ret); ++ fprintf(stderr, "*******************************\n"); ++ */ ++ /* we return to previous frame */ ++ cur_frame--; ++ /* free some space occupied by argument */ ++ while (dolc--) ++ free(dolv[dolc]); ++ free(dolv); ++ ++ /* recover argument for last function */ ++ dolv = frame[cur_frame].argv; ++ dolc = frame[cur_frame].argc; ++ /* If we are not in the outest frame, we should set ++ * func_finished to 0 that means we still in some function */ ++ if (cur_frame != 0) ++ func_finished = 0; ++} //funccode:end + + static int collect(int c, int c1) + { +@@ -2601,6 +2839,10 @@ static int execute(struct op *t, int *pi + execute(t->right->right, pin, pout, /* no_fork: */ 0); + } + break; ++ case TFUNC: //funccode:start ++ break; ++ case TRETURN: ++ break; //funccode:end + + case TCASE: + cp = evalstr(t->str, DOSUB | DOTRIM); -- 2.25.1