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.
This commit is contained in:
parent
ed9d621cf4
commit
2d0529c9bc
350
shell/msh_function.patch
Normal file
350
shell/msh_function.patch
Normal file
@ -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);
|
Loading…
Reference in New Issue
Block a user