1 This is a "function" patch for msh which is in use by some busybox
2 users. Unfortunately it is far too buggy to be applied, but maybe
3 it's a useful starting point for future work.
5 Function-related code is delimited by comments of the form
11 An example of buggy behavior:
15 # echo test`echo bar >&2`
21 # echo 2 test`echo 2 bar >&2`
24 # echo "1:'$1' 2:'$2'"
27 # Even this first block fails - it does not even call functions!
28 # (replacing "echo END g" above with "echo END" makes it run ok)
31 echo 2 test`echo 2 bar >&2`
35 echo test`echo bar >&2`
47 diff -d -urpN busybox.7/shell/msh.c busybox.8/shell/msh.c
48 --- busybox.7/shell/msh.c 2008-06-09 09:34:45.000000000 +0200
49 +++ busybox.8/shell/msh.c 2008-06-09 09:38:17.000000000 +0200
50 @@ -89,6 +89,14 @@ static char *itoa(int n)
54 +/* Used only in "function" support code */
55 +#ifdef KSDBG //funccode:start
56 + #define KSDBG_PRINT_FUNCNAME fprintf(stderr, "in %s\n", __FUNCTION__)
58 + #define KSDBG_PRINT_FUNCNAME ((void)0)
63 static int mshdbg = MSHDEBUG;
65 @@ -220,6 +228,9 @@ struct op {
66 #define TASYNC 16 /* c & */
67 /* Added to support "." file expansion */
69 +#define TFUNC 18 //funccode:start
73 /* Strings for names to make debug easier */
75 @@ -319,6 +330,27 @@ struct region {
79 +static int func_finished; //funccode:start
82 + int begin_addr; /* pos in buffer of function */
85 +#define MAX_FUNCS 100
87 +static struct func funcs[MAX_FUNCS];
89 +/* the max DEPTH of function call */
90 +#define MAX_DEPTH 100
91 +static struct _frame_s {
94 + int saved_return_addr;
97 +static void register_func(int begin, int end);
98 +static struct func* find_func(char* name);
99 +static void exec_func(struct func* f); //funccode:end
101 /* -------- grammar stuff -------- */
103 @@ -347,6 +379,8 @@ typedef union {
105 /* Added for "." file expansion */
107 +#define FUNC 274 //funccode:start
108 +#define RETURN 275 //funccode:end
110 #define YYERRCODE 300
112 @@ -1722,6 +1756,40 @@ static struct op *simple(void)
116 + case FUNC: { //funccode:start
122 + while ((c = my_getc(0)) == ' ' || c == '\t'|| c == '\n') /* skip whitespace */
126 + func_begin = global_env.iobase->argp->afpos;
127 + while (stop_flag) {
132 + if (!number_brace) /* if we reach the brace of most outsite */
138 + func_end = global_env.iobase->argp->afpos;
139 + register_func(func_begin, func_end);
148 + return t; //funccode:end
153 @@ -2265,6 +2333,13 @@ static int yylex(int cf)
157 + case '{': //funccode:start
158 + c = collect(c, '}');
163 + return RETURN; //funccode:end
167 @@ -2293,9 +2368,172 @@ static int yylex(int cf)
170 yylval.cp = strsave(line, areanum);
171 + /* To identify a subroutine */ //funccode:start
173 + if (c && any(c, "(")) {
175 + if (c && any(c, ")"))
180 + /* read the first char */
181 + /* To identify a function */
182 + if (strcmp(yylval.cp, "function") == 0) {
183 + int ret = yylex(0);
184 + /* read the function name after "function" */
190 + struct func* f = find_func(yylval.cp);
196 + if (yylval.cp != NULL && strcmp(yylval.cp, "return") == 0) {
202 +static void register_func(int begin, int end) //funccode:start
206 + for (i = 0; i < MAX_FUNCS; i++) {
207 + if (funcs[i].name == NULL) {
212 + if (i == MAX_FUNCS) {
213 + fprintf(stderr, "Too much functions beyond limit\n");
216 + p->name = xstrdup(yylval.cp);
217 + //fprintf(stderr, "register function,%d,%d,%s\n", begin, end, p->name);
218 + KSDBG_PRINT_FUNCNAME;
220 + p->begin_addr = begin;
224 +static struct func* find_func(char* name)
227 + for (i = 0; i < MAX_FUNCS; i++) {
228 + if (funcs[i].name == NULL)
230 + if (!strcmp(funcs[i].name, name))
233 + KSDBG_PRINT_FUNCNAME;
234 + //fprintf(stderr, "not found the function %s\n", name);
239 +/* Begin to execute the function */
240 +static int cur_frame = 0;
242 +static void exec_func(struct func* f)
249 + /* create a new frame, save the argument and return address to this frame */
250 + frame[cur_frame].argc = dolc;
251 + frame[cur_frame].argv = dolv;
254 + /* do some argument parse and set arguments */
255 + temp_argv = xmalloc(sizeof(char *));
256 + temp_argv[0] = xstrdup(f->name);
258 + global_env.iop->argp->afpos--;
259 + global_env.iop->argp->afbuf->bufp--;
261 + while (((c = yylex(0)) != '\n') && (yylval.cp != NULL)) {
263 + temp_argv = xrealloc(temp_argv, sizeof(char *) * (temp_argc+1));
264 + /* parse $ var if passed argument is a variable */
265 + if (yylval.cp[0] == '$') {
266 + struct var *arg = lookup(&yylval.cp[1]);
267 + temp_argv[temp_argc] = xstrdup(arg->value);
268 + //fprintf(stderr, "arg->value=%s\n", arg->value);
270 + temp_argv[temp_argc] = xstrdup(yylval.cp);
271 + //fprintf(stderr, "ARG:%s\n", yylval.cp);
275 + global_env.iop->argp->afpos--;
276 + global_env.iop->argp->afbuf->bufp--;
281 + //while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
284 + frame[cur_frame].saved_return_addr = global_env.iop->argp->afpos;
286 + /* get function begin address and execute this function */
288 + bp = global_env.iop->argp->afbuf;
289 + bp->bufp = &(bp->buf[f->begin_addr]);
290 + global_env.iop->argp->afpos = f->begin_addr;
292 + /* func_finished=0 means we are in a function and func_finished=1 means we are executing a function */
295 + //fprintf(stderr, "exec function %s\n", f->name);
296 + KSDBG_PRINT_FUNCNAME;
298 + //fprintf(stderr, "afpos=%d,%s\n", global_env.iop->argp->afpos, yylval.cp);
299 + if (global_env.iop->argp->afpos == f->end_addr)
302 + /* we return from a function, when func_finished = 1 */
308 + //fprintf(stderr, "%s is finished @%d!\n", f->name, global_env.iop->argp->afpos);
309 + int ret = frame[cur_frame].saved_return_addr;
310 + /* workaround code for \n */
313 + /* get return address from current frame and jump to */
314 + global_env.iop->argp->afpos = ret;
315 + global_env.iop->argp->afbuf->bufp = &(global_env.iop->argp->afbuf->buf[ret]);
318 + fprintf(stderr, "******** after execution ********************\n");
319 + fprintf(stderr, " %s \n############# %d\n", global_env.iop->argp->afbuf->bufp, ret);
320 + fprintf(stderr, "*******************************\n");
322 + /* we return to previous frame */
324 + /* free some space occupied by argument */
329 + /* recover argument for last function */
330 + dolv = frame[cur_frame].argv;
331 + dolc = frame[cur_frame].argc;
332 + /* If we are not in the outest frame, we should set
333 + * func_finished to 0 that means we still in some function */
334 + if (cur_frame != 0)
338 static int collect(int c, int c1)
340 @@ -2601,6 +2839,10 @@ static int execute(struct op *t, int *pi
341 execute(t->right->right, pin, pout, /* no_fork: */ 0);
344 + case TFUNC: //funccode:start
347 + break; //funccode:end
350 cp = evalstr(t->str, DOSUB | DOTRIM);