ash_LINENO.patch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. This patch is a backport from dash of the combination of:
  2. [SHELL] Add preliminary LINENO support
  3. [VAR] Fix varinit ordering that broke fc
  4. [SHELL] Improve LINENO support
  5. Applies cleanly on top of:
  6. commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe
  7. Date: Tue Aug 15 15:44:41 2017 +0200
  8. Testsuite needs some tweaks (line numbers in some messages change).
  9. Unfortunately, it is somewhat big:
  10. function old new delta
  11. parse_command 1581 1658 +77
  12. calcsize 203 272 +69
  13. copynode 195 257 +62
  14. lookupvar 59 108 +49
  15. evaltree 494 534 +40
  16. evalfor 152 187 +35
  17. evalcase 278 313 +35
  18. evalcommand 1547 1581 +34
  19. evalsubshell 169 199 +30
  20. linenovar - 22 +22
  21. raise_error_syntax 11 29 +18
  22. evalfun 266 280 +14
  23. varinit_data 96 108 +12
  24. cmdtxt 626 631 +5
  25. lineno - 4 +4
  26. funcline - 4 +4
  27. ash_vmsg 144 141 -3
  28. startlinno 4 - -4
  29. funcnest 4 - -4
  30. xxreadtoken 272 259 -13
  31. readtoken1 2635 2594 -41
  32. ------------------------------------------------------------------------------
  33. (add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes
  34. text data bss dec hex filename
  35. 912030 563 5844 918437 e03a5 busybox_old
  36. 912473 587 5844 918904 e0578 busybox_unstripped
  37. diff --git a/shell/ash.c b/shell/ash.c
  38. index 703802f..93a3814 100644
  39. --- a/shell/ash.c
  40. +++ b/shell/ash.c
  41. @@ -312,6 +312,8 @@ struct globals_misc {
  42. /* shell level: 0 for the main shell, 1 for its children, and so on */
  43. int shlvl;
  44. #define rootshell (!shlvl)
  45. + int errlinno;
  46. +
  47. char *minusc; /* argument to -c option */
  48. char *curdir; // = nullstr; /* current working directory */
  49. @@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
  50. #define job_warning (G_misc.job_warning)
  51. #define rootpid (G_misc.rootpid )
  52. #define shlvl (G_misc.shlvl )
  53. +#define errlinno (G_misc.errlinno )
  54. #define minusc (G_misc.minusc )
  55. #define curdir (G_misc.curdir )
  56. #define physdir (G_misc.physdir )
  57. @@ -723,6 +726,7 @@ union node;
  58. struct ncmd {
  59. smallint type; /* Nxxxx */
  60. + int linno;
  61. union node *assign;
  62. union node *args;
  63. union node *redirect;
  64. @@ -736,6 +740,7 @@ struct npipe {
  65. struct nredir {
  66. smallint type;
  67. + int linno;
  68. union node *n;
  69. union node *redirect;
  70. };
  71. @@ -755,6 +760,7 @@ struct nif {
  72. struct nfor {
  73. smallint type;
  74. + int linno;
  75. union node *args;
  76. union node *body;
  77. char *var;
  78. @@ -762,6 +768,7 @@ struct nfor {
  79. struct ncase {
  80. smallint type;
  81. + int linno;
  82. union node *expr;
  83. union node *cases;
  84. };
  85. @@ -773,6 +780,13 @@ struct nclist {
  86. union node *body;
  87. };
  88. +struct ndefun {
  89. + smallint type;
  90. + int linno;
  91. + char *text;
  92. + union node *body;
  93. +};
  94. +
  95. struct narg {
  96. smallint type;
  97. union node *next;
  98. @@ -824,6 +838,7 @@ union node {
  99. struct nfor nfor;
  100. struct ncase ncase;
  101. struct nclist nclist;
  102. + struct ndefun ndefun;
  103. struct narg narg;
  104. struct nfile nfile;
  105. struct ndup ndup;
  106. @@ -1253,7 +1268,6 @@ struct parsefile {
  107. static struct parsefile basepf; /* top level input file */
  108. static struct parsefile *g_parsefile = &basepf; /* current input file */
  109. -static int startlinno; /* line # where last token started */
  110. static char *commandname; /* currently executing command */
  111. @@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap)
  112. if (strcmp(arg0, commandname))
  113. fprintf(stderr, "%s: ", commandname);
  114. if (!iflag || g_parsefile->pf_fd > 0)
  115. - fprintf(stderr, "line %d: ", startlinno);
  116. + fprintf(stderr, "line %d: ", errlinno);
  117. }
  118. vfprintf(stderr, msg, ap);
  119. newline_and_flush(stderr);
  120. @@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN;
  121. static void
  122. raise_error_syntax(const char *msg)
  123. {
  124. + errlinno = g_parsefile->linno;
  125. ash_msg_and_raise_error("syntax error: %s", msg);
  126. /* NOTREACHED */
  127. }
  128. @@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC;
  129. static void change_random(const char *) FAST_FUNC;
  130. #endif
  131. +static int lineno;
  132. +static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO=";
  133. +
  134. static const struct {
  135. int flags;
  136. const char *var_text;
  137. @@ -2014,6 +2032,7 @@ static const struct {
  138. #if ENABLE_ASH_GETOPTS
  139. { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
  140. #endif
  141. + { VSTRFIXED|VTEXTFIXED , linenovar , NULL },
  142. #if ENABLE_ASH_RANDOM_SUPPORT
  143. { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
  144. #endif
  145. @@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var;
  146. #define vps4 (&vps2)[1]
  147. #if ENABLE_ASH_GETOPTS
  148. # define voptind (&vps4)[1]
  149. +# define vlineno (&voptind)[1]
  150. # if ENABLE_ASH_RANDOM_SUPPORT
  151. -# define vrandom (&voptind)[1]
  152. +# define vrandom (&vlineno)[1]
  153. # endif
  154. #else
  155. +# define vlineno (&vps4)[1]
  156. # if ENABLE_ASH_RANDOM_SUPPORT
  157. -# define vrandom (&vps4)[1]
  158. +# define vrandom (&vlineno)[1]
  159. # endif
  160. #endif
  161. @@ -2209,8 +2230,12 @@ lookupvar(const char *name)
  162. if (v->flags & VDYNAMIC)
  163. v->var_func(NULL);
  164. #endif
  165. - if (!(v->flags & VUNSET))
  166. + if (!(v->flags & VUNSET)) {
  167. + if (v == &vlineno && v->var_text == linenovar) {
  168. + fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
  169. + }
  170. return var_end(v->var_text);
  171. + }
  172. }
  173. return NULL;
  174. }
  175. @@ -4783,7 +4808,7 @@ cmdtxt(union node *n)
  176. p = "; done";
  177. goto dodo;
  178. case NDEFUN:
  179. - cmdputs(n->narg.text);
  180. + cmdputs(n->ndefun.text);
  181. p = "() { ... }";
  182. goto dotail2;
  183. case NCMD:
  184. @@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n)
  185. funcblocksize = calcsize(funcblocksize, n->nclist.next);
  186. break;
  187. case NDEFUN:
  188. + funcblocksize = calcsize(funcblocksize, n->ndefun.body);
  189. + funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
  190. + break;
  191. case NARG:
  192. funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
  193. funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
  194. @@ -8626,6 +8654,7 @@ copynode(union node *n)
  195. new->ncmd.redirect = copynode(n->ncmd.redirect);
  196. new->ncmd.args = copynode(n->ncmd.args);
  197. new->ncmd.assign = copynode(n->ncmd.assign);
  198. + new->ncmd.linno = n->ncmd.linno;
  199. break;
  200. case NPIPE:
  201. new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
  202. @@ -8636,6 +8665,7 @@ copynode(union node *n)
  203. case NSUBSHELL:
  204. new->nredir.redirect = copynode(n->nredir.redirect);
  205. new->nredir.n = copynode(n->nredir.n);
  206. + new->nredir.linno = n->nredir.linno;
  207. break;
  208. case NAND:
  209. case NOR:
  210. @@ -8654,10 +8684,12 @@ copynode(union node *n)
  211. new->nfor.var = nodeckstrdup(n->nfor.var);
  212. new->nfor.body = copynode(n->nfor.body);
  213. new->nfor.args = copynode(n->nfor.args);
  214. + new->nfor.linno = n->nfor.linno;
  215. break;
  216. case NCASE:
  217. new->ncase.cases = copynode(n->ncase.cases);
  218. new->ncase.expr = copynode(n->ncase.expr);
  219. + new->ncase.linno = n->ncase.linno;
  220. break;
  221. case NCLIST:
  222. new->nclist.body = copynode(n->nclist.body);
  223. @@ -8665,6 +8697,10 @@ copynode(union node *n)
  224. new->nclist.next = copynode(n->nclist.next);
  225. break;
  226. case NDEFUN:
  227. + new->ndefun.body = copynode(n->ndefun.body);
  228. + new->ndefun.text = nodeckstrdup(n->ndefun.text);
  229. + new->ndefun.linno = n->ndefun.linno;
  230. + break;
  231. case NARG:
  232. new->narg.backquote = copynodelist(n->narg.backquote);
  233. new->narg.text = nodeckstrdup(n->narg.text);
  234. @@ -8733,7 +8769,7 @@ defun(union node *func)
  235. INT_OFF;
  236. entry.cmdtype = CMDFUNCTION;
  237. entry.u.func = copyfunc(func);
  238. - addcmdentry(func->narg.text, &entry);
  239. + addcmdentry(func->ndefun.text, &entry);
  240. INT_ON;
  241. }
  242. @@ -8743,8 +8779,8 @@ defun(union node *func)
  243. #define SKIPFUNC (1 << 2)
  244. static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
  245. static int skipcount; /* number of levels to skip */
  246. -static int funcnest; /* depth of function calls */
  247. static int loopnest; /* current loop nesting level */
  248. +static int funcline; /* starting line number of current function, or 0 if not in a function */
  249. /* Forward decl way out to parsing code - dotrap needs it */
  250. static int evalstring(char *s, int flags);
  251. @@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags)
  252. status = !evaltree(n->nnot.com, EV_TESTED);
  253. goto setstatus;
  254. case NREDIR:
  255. + errlinno = lineno = n->nredir.linno;
  256. + if (funcline)
  257. + lineno -= funcline - 1;
  258. expredir(n->nredir.redirect);
  259. pushredir(n->nredir.redirect);
  260. status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
  261. @@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags)
  262. struct stackmark smark;
  263. int status = 0;
  264. + errlinno = lineno = n->ncase.linno;
  265. + if (funcline)
  266. + lineno -= funcline - 1;
  267. +
  268. setstackmark(&smark);
  269. arglist.list = NULL;
  270. arglist.lastp = &arglist.list;
  271. @@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags)
  272. struct stackmark smark;
  273. int status = 0;
  274. + errlinno = lineno = n->ncase.linno;
  275. + if (funcline)
  276. + lineno -= funcline - 1;
  277. +
  278. setstackmark(&smark);
  279. arglist.list = NULL;
  280. arglist.lastp = &arglist.list;
  281. @@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags)
  282. int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
  283. int status;
  284. + errlinno = lineno = n->nredir.linno;
  285. + if (funcline)
  286. + lineno -= funcline - 1;
  287. +
  288. expredir(n->nredir.redirect);
  289. if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
  290. goto nofork;
  291. @@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
  292. struct jmploc *volatile savehandler;
  293. struct jmploc jmploc;
  294. int e;
  295. + int savefuncline;
  296. saveparam = shellparam;
  297. + savefuncline = funcline;
  298. savehandler = exception_handler;
  299. e = setjmp(jmploc.loc);
  300. if (e) {
  301. @@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
  302. exception_handler = &jmploc;
  303. shellparam.malloced = 0;
  304. func->count++;
  305. - funcnest++;
  306. + funcline = func->n.ndefun.linno;
  307. INT_ON;
  308. shellparam.nparam = argc - 1;
  309. shellparam.p = argv + 1;
  310. @@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
  311. shellparam.optoff = -1;
  312. #endif
  313. pushlocalvars();
  314. - evaltree(func->n.narg.next, flags & EV_TESTED);
  315. + evaltree(func->n.ndefun.body, flags & EV_TESTED);
  316. poplocalvars(0);
  317. funcdone:
  318. INT_OFF;
  319. - funcnest--;
  320. + funcline = savefuncline;
  321. freefunc(func);
  322. freeparam(&shellparam);
  323. shellparam = saveparam;
  324. @@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags)
  325. char **nargv;
  326. smallint cmd_is_exec;
  327. + errlinno = lineno = cmd->ncmd.linno;
  328. + if (funcline)
  329. + lineno -= funcline - 1;
  330. +
  331. /* First expand the arguments. */
  332. TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
  333. setstackmark(&smark);
  334. @@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags)
  335. *nargv = NULL;
  336. lastarg = NULL;
  337. - if (iflag && funcnest == 0 && argc > 0)
  338. + if (iflag && funcline == 0 && argc > 0)
  339. lastarg = nargv[-1];
  340. expredir(cmd->ncmd.redirect);
  341. @@ -11317,6 +11374,7 @@ simplecmd(void)
  342. union node *vars, **vpp;
  343. union node **rpp, *redir;
  344. int savecheckkwd;
  345. + int savelinno;
  346. #if BASH_TEST2
  347. smallint double_brackets_flag = 0;
  348. #endif
  349. @@ -11330,6 +11388,7 @@ simplecmd(void)
  350. rpp = &redir;
  351. savecheckkwd = CHKALIAS;
  352. + savelinno = g_parsefile->linno;
  353. for (;;) {
  354. int t;
  355. checkkwd = savecheckkwd;
  356. @@ -11419,7 +11478,9 @@ simplecmd(void)
  357. }
  358. n->type = NDEFUN;
  359. checkkwd = CHKNL | CHKKWD | CHKALIAS;
  360. - n->narg.next = parse_command();
  361. + n->ndefun.text = n->narg.text;
  362. + n->ndefun.linno = g_parsefile->linno;
  363. + n->ndefun.body = parse_command();
  364. return n;
  365. }
  366. IF_BASH_FUNCTION(function_flag = 0;)
  367. @@ -11435,6 +11496,7 @@ simplecmd(void)
  368. *rpp = NULL;
  369. n = stzalloc(sizeof(struct ncmd));
  370. n->type = NCMD;
  371. + n->ncmd.linno = savelinno;
  372. n->ncmd.args = args;
  373. n->ncmd.assign = vars;
  374. n->ncmd.redirect = redir;
  375. @@ -11450,10 +11512,13 @@ parse_command(void)
  376. union node *redir, **rpp;
  377. union node **rpp2;
  378. int t;
  379. + int savelinno;
  380. redir = NULL;
  381. rpp2 = &redir;
  382. + savelinno = g_parsefile->linno;
  383. +
  384. switch (readtoken()) {
  385. default:
  386. raise_error_unexpected_syntax(-1);
  387. @@ -11504,6 +11569,7 @@ parse_command(void)
  388. raise_error_syntax("bad for loop variable");
  389. n1 = stzalloc(sizeof(struct nfor));
  390. n1->type = NFOR;
  391. + n1->nfor.linno = savelinno;
  392. n1->nfor.var = wordtext;
  393. checkkwd = CHKNL | CHKKWD | CHKALIAS;
  394. if (readtoken() == TIN) {
  395. @@ -11544,6 +11610,7 @@ parse_command(void)
  396. case TCASE:
  397. n1 = stzalloc(sizeof(struct ncase));
  398. n1->type = NCASE;
  399. + n1->ncase.linno = savelinno;
  400. if (readtoken() != TWORD)
  401. raise_error_unexpected_syntax(TWORD);
  402. n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
  403. @@ -11595,6 +11662,7 @@ parse_command(void)
  404. case TLP:
  405. n1 = stzalloc(sizeof(struct nredir));
  406. n1->type = NSUBSHELL;
  407. + n1->nredir.linno = savelinno;
  408. n1->nredir.n = list(0);
  409. /*n1->nredir.redirect = NULL; - stzalloc did it */
  410. t = TRP;
  411. @@ -11628,6 +11696,7 @@ parse_command(void)
  412. if (n1->type != NSUBSHELL) {
  413. n2 = stzalloc(sizeof(struct nredir));
  414. n2->type = NREDIR;
  415. + n2->nredir.linno = savelinno;
  416. n2->nredir.n = n1;
  417. n1 = n2;
  418. }
  419. @@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
  420. IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
  421. IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
  422. int dqvarnest; /* levels of variables expansion within double quotes */
  423. -
  424. IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
  425. - startlinno = g_parsefile->linno;
  426. bqlist = NULL;
  427. quotef = 0;
  428. IF_FEATURE_SH_MATH(prevsyntax = 0;)
  429. @@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
  430. if (syntax != BASESYNTAX && eofmark == NULL)
  431. raise_error_syntax("unterminated quoted string");
  432. if (varnest != 0) {
  433. - startlinno = g_parsefile->linno;
  434. /* { */
  435. raise_error_syntax("missing '}'");
  436. }
  437. @@ -12298,7 +12364,6 @@ parsebackq: {
  438. case PEOF:
  439. IF_ASH_ALIAS(case PEOA:)
  440. - startlinno = g_parsefile->linno;
  441. raise_error_syntax("EOF in backquote substitution");
  442. case '\n':
  443. @@ -12380,8 +12445,6 @@ parsearith: {
  444. * quoted.
  445. * If the token is TREDIR, then we set redirnode to a structure containing
  446. * the redirection.
  447. - * In all cases, the variable startlinno is set to the number of the line
  448. - * on which the token starts.
  449. *
  450. * [Change comment: here documents and internal procedures]
  451. * [Readtoken shouldn't have any arguments. Perhaps we should make the
  452. @@ -12419,7 +12482,6 @@ xxreadtoken(void)
  453. return lasttoken;
  454. }
  455. setprompt_if(needprompt, 2);
  456. - startlinno = g_parsefile->linno;
  457. for (;;) { /* until token or start of word found */
  458. c = pgetc();
  459. if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
  460. @@ -12480,7 +12542,6 @@ xxreadtoken(void)
  461. return lasttoken;
  462. }
  463. setprompt_if(needprompt, 2);
  464. - startlinno = g_parsefile->linno;
  465. for (;;) { /* until token or start of word found */
  466. c = pgetc();
  467. switch (c) {