svn commit: trunk/busybox/shell

vda at busybox.net vda at busybox.net
Mon Jun 9 07:50:25 UTC 2008


Author: vda
Date: 2008-06-09 00:50:25 -0700 (Mon, 09 Jun 2008)
New Revision: 22274

Log:
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.



Added:
   trunk/busybox/shell/msh_function.patch


Changeset:
Added: trunk/busybox/shell/msh_function.patch
===================================================================
--- trunk/busybox/shell/msh_function.patch	                        (rev 0)
+++ trunk/busybox/shell/msh_function.patch	2008-06-09 07:50:25 UTC (rev 22274)
@@ -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);




More information about the busybox-cvs mailing list