mirror of
https://github.com/sheumann/hush.git
synced 2024-11-09 02:09:01 +00:00
2d0529c9bc
Fixed allocation bugs (it was allocating one too small vectors) but it still is very buggy, thus not applied.
351 lines
8.5 KiB
Diff
351 lines
8.5 KiB
Diff
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);
|