Contents of /tags/mkinitrd-6_1_7/busybox/shell/msh_function.patch
Parent Directory | Revision Log
Revision 909 -
(show annotations)
(download)
Fri Oct 16 13:40:14 2009 UTC (14 years, 11 months ago) by niro
File size: 8646 byte(s)
Fri Oct 16 13:40:14 2009 UTC (14 years, 11 months ago) by niro
File size: 8646 byte(s)
tagged 'mkinitrd-6_1_7'
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); |