Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/shell/msh_function.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (show annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years ago) by niro
File size: 8646 byte(s)
-updated to busybox-1.13.4
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.
4
5 Function-related code is delimited by comments of the form
6 //funccode:start
7 ...
8 //funccode:end
9 for ease of grepping
10
11 An example of buggy behavior:
12
13 #f() {
14 # echo foo
15 # echo test`echo bar >&2`
16 # echo END f
17 #}
18
19 function g {
20 # echo 2 foo
21 # echo 2 test`echo 2 bar >&2`
22 # f
23 echo END g
24 # echo "1:'$1' 2:'$2'"
25 }
26
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)
29 echo DRY RUN
30 echo 2 foo
31 echo 2 test`echo 2 bar >&2`
32 echo END g
33 echo "1:'$1' 2:'$2'"
34 echo foo
35 echo test`echo bar >&2`
36 echo END f
37 echo END DRY RUN
38
39 exit
40
41 # This would fail too
42 g "$1-one" "two$2"
43 echo DONE
44
45
46
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)
51
52 //#define MSHDEBUG 4
53
54 +/* Used only in "function" support code */
55 +#ifdef KSDBG //funccode:start
56 + #define KSDBG_PRINT_FUNCNAME fprintf(stderr, "in %s\n", __FUNCTION__)
57 +#else
58 + #define KSDBG_PRINT_FUNCNAME ((void)0)
59 +#endif
60 +//funccode:end
61 +
62 #ifdef MSHDEBUG
63 static int mshdbg = MSHDEBUG;
64
65 @@ -220,6 +228,9 @@ struct op {
66 #define TASYNC 16 /* c & */
67 /* Added to support "." file expansion */
68 #define TDOT 17
69 +#define TFUNC 18 //funccode:start
70 +#define TRETURN 19
71 + //funccode:end
72
73 /* Strings for names to make debug easier */
74 #ifdef MSHDEBUG
75 @@ -319,6 +330,27 @@ struct region {
76 int area;
77 };
78
79 +static int func_finished; //funccode:start
80 +struct func {
81 + char* name;
82 + int begin_addr; /* pos in buffer of function */
83 + int end_addr;
84 +};
85 +#define MAX_FUNCS 100
86 +
87 +static struct func funcs[MAX_FUNCS];
88 +
89 +/* the max DEPTH of function call */
90 +#define MAX_DEPTH 100
91 +static struct _frame_s {
92 + int argc;
93 + char **argv;
94 + int saved_return_addr;
95 +} frame[MAX_DEPTH];
96 +
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
100
101 /* -------- grammar stuff -------- */
102 typedef union {
103 @@ -347,6 +379,8 @@ typedef union {
104 #define IN 272
105 /* Added for "." file expansion */
106 #define DOT 273
107 +#define FUNC 274 //funccode:start
108 +#define RETURN 275 //funccode:end
109
110 #define YYERRCODE 300
111
112 @@ -1722,6 +1756,40 @@ static struct op *simple(void)
113 (void) synio(0);
114 break;
115
116 + case FUNC: { //funccode:start
117 + int stop_flag;
118 + int number_brace;
119 + int func_begin;
120 + int func_end;
121 + int c;
122 + while ((c = my_getc(0)) == ' ' || c == '\t'|| c == '\n') /* skip whitespace */
123 + continue;
124 + stop_flag = 1;
125 + number_brace = 0;
126 + func_begin = global_env.iobase->argp->afpos;
127 + while (stop_flag) {
128 + if (c == '{')
129 + number_brace++;
130 + if (c == '}')
131 + number_brace--;
132 + if (!number_brace) /* if we reach the brace of most outsite */
133 + stop_flag = 0;
134 + c = my_getc(0);
135 + }
136 + unget(c);
137 + unget(c);
138 + func_end = global_env.iobase->argp->afpos;
139 + register_func(func_begin, func_end);
140 + peeksym = 0;
141 + t = NULL;
142 + return t;
143 + }
144 + case RETURN:
145 + func_finished = 1;
146 + peeksym = 0;
147 + t = NULL;
148 + return t; //funccode:end
149 +
150 case WORD:
151 if (t == NULL) {
152 t = newtp();
153 @@ -2265,6 +2333,13 @@ static int yylex(int cf)
154 case ')':
155 startl = 1;
156 return c;
157 + case '{': //funccode:start
158 + c = collect(c, '}');
159 + if (c != '\0')
160 + return c;
161 + break;
162 + case '}':
163 + return RETURN; //funccode:end
164 }
165
166 unget(c);
167 @@ -2293,9 +2368,172 @@ static int yylex(int cf)
168 }
169
170 yylval.cp = strsave(line, areanum);
171 + /* To identify a subroutine */ //funccode:start
172 + c = my_getc(0);
173 + if (c && any(c, "(")) {
174 + c = my_getc(0);
175 + if (c && any(c, ")"))
176 + return FUNC;
177 + zzerr();
178 + } else
179 + unget(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" */
185 + if (ret == WORD)
186 + return (FUNC);
187 + zzerr();
188 + }
189 + {
190 + struct func* f = find_func(yylval.cp);
191 + if (f != NULL) {
192 + exec_func(f);
193 + return RETURN;
194 + }
195 + }
196 + if (yylval.cp != NULL && strcmp(yylval.cp, "return") == 0) {
197 + return RETURN;
198 + } //funccode:end
199 return WORD;
200 }
201
202 +static void register_func(int begin, int end) //funccode:start
203 +{
204 + struct func *p;
205 + int i;
206 + for (i = 0; i < MAX_FUNCS; i++) {
207 + if (funcs[i].name == NULL) {
208 + p = &funcs[i];
209 + break;
210 + }
211 + }
212 + if (i == MAX_FUNCS) {
213 + fprintf(stderr, "Too much functions beyond limit\n");
214 + leave();
215 + }
216 + p->name = xstrdup(yylval.cp);
217 + //fprintf(stderr, "register function,%d,%d,%s\n", begin, end, p->name);
218 + KSDBG_PRINT_FUNCNAME;
219 + /* io stream */
220 + p->begin_addr = begin;
221 + p->end_addr = end;
222 +}
223 +
224 +static struct func* find_func(char* name)
225 +{
226 + int i;
227 + for (i = 0; i < MAX_FUNCS; i++) {
228 + if (funcs[i].name == NULL)
229 + continue;
230 + if (!strcmp(funcs[i].name, name))
231 + return &funcs[i];
232 + }
233 + KSDBG_PRINT_FUNCNAME;
234 + //fprintf(stderr, "not found the function %s\n", name);
235 + return NULL;
236 + //zzerr();
237 +}
238 +
239 +/* Begin to execute the function */
240 +static int cur_frame = 0;
241 +
242 +static void exec_func(struct func* f)
243 +{
244 + int c;
245 + int temp_argc;
246 + char** temp_argv;
247 + struct iobuf *bp;
248 +
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;
252 +
253 + cur_frame++;
254 + /* do some argument parse and set arguments */
255 + temp_argv = xmalloc(sizeof(char *));
256 + temp_argv[0] = xstrdup(f->name);
257 + temp_argc = 0;
258 + global_env.iop->argp->afpos--;
259 + global_env.iop->argp->afbuf->bufp--;
260 +// unget(c);
261 + while (((c = yylex(0)) != '\n') && (yylval.cp != NULL)) {
262 + temp_argc++;
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);
269 + } else {
270 + temp_argv[temp_argc] = xstrdup(yylval.cp);
271 + //fprintf(stderr, "ARG:%s\n", yylval.cp);
272 + }
273 + }
274 + /*
275 + global_env.iop->argp->afpos--;
276 + global_env.iop->argp->afbuf->bufp--;
277 + */
278 + dolc = temp_argc;
279 + dolv = temp_argv;
280 + //unget(c);
281 + //while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
282 + // continue;
283 + //unget(c);
284 + frame[cur_frame].saved_return_addr = global_env.iop->argp->afpos;
285 +
286 + /* get function begin address and execute this function */
287 +
288 + bp = global_env.iop->argp->afbuf;
289 + bp->bufp = &(bp->buf[f->begin_addr]);
290 + global_env.iop->argp->afpos = f->begin_addr;
291 +
292 + /* func_finished=0 means we are in a function and func_finished=1 means we are executing a function */
293 + func_finished = 0;
294 +
295 + //fprintf(stderr, "exec function %s\n", f->name);
296 + KSDBG_PRINT_FUNCNAME;
297 + for (;;) {
298 + //fprintf(stderr, "afpos=%d,%s\n", global_env.iop->argp->afpos, yylval.cp);
299 + if (global_env.iop->argp->afpos == f->end_addr)
300 + break;
301 + onecommand();
302 + /* we return from a function, when func_finished = 1 */
303 + if (func_finished)
304 + break;
305 + }
306 +
307 + {
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 */
311 + if (dolc)
312 + ret--;
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]);
316 + }
317 + /*
318 + fprintf(stderr, "******** after execution ********************\n");
319 + fprintf(stderr, " %s \n############# %d\n", global_env.iop->argp->afbuf->bufp, ret);
320 + fprintf(stderr, "*******************************\n");
321 + */
322 + /* we return to previous frame */
323 + cur_frame--;
324 + /* free some space occupied by argument */
325 + while (dolc--)
326 + free(dolv[dolc]);
327 + free(dolv);
328 +
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)
335 + func_finished = 0;
336 +} //funccode:end
337
338 static int collect(int c, int c1)
339 {
340 @@ -2601,6 +2839,10 @@ static int execute(struct op *t, int *pi
341 execute(t->right->right, pin, pout, /* no_fork: */ 0);
342 }
343 break;
344 + case TFUNC: //funccode:start
345 + break;
346 + case TRETURN:
347 + break; //funccode:end
348
349 case TCASE:
350 cp = evalstr(t->str, DOSUB | DOTRIM);