diff options
Diffstat (limited to 'shell/msh_function.patch')
| -rw-r--r-- | shell/msh_function.patch | 350 |
1 files changed, 0 insertions, 350 deletions
diff --git a/shell/msh_function.patch b/shell/msh_function.patch deleted file mode 100644 index 270b9eeff..000000000 --- a/shell/msh_function.patch +++ /dev/null | |||
| @@ -1,350 +0,0 @@ | |||
| 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); | ||
