msh_function.patch 8.4 KB

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