ftpd: simplify PORT check by assuming IP = peer's IP.
[oweals/busybox.git] / shell / msh_function.patch
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);