aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-06-09 07:50:25 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-06-09 07:50:25 +0000
commit2d0529c9bc0c4fedefa816d6b6d371b1d5b8c32e (patch)
treef463caa29402d1808eaef06b0637d6501624ad5d
parented9d621cf481a180a586f8e62867484c803723fa (diff)
downloadbusybox-2d0529c9bc0c4fedefa816d6b6d371b1d5b8c32e.tar.gz
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.
-rw-r--r--shell/msh_function.patch350
1 files changed, 350 insertions, 0 deletions
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);