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
6 Applies cleanly on top of:
7 commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe
8 Date: Tue Aug 15 15:44:41 2017 +0200
10 Testsuite needs some tweaks (line numbers in some messages change).
12 Unfortunately, it is somewhat big:
14 function old new delta
15 parse_command 1581 1658 +77
22 evalcommand 1547 1581 +34
23 evalsubshell 169 199 +30
25 raise_error_syntax 11 29 +18
27 varinit_data 96 108 +12
34 xxreadtoken 272 259 -13
35 readtoken1 2635 2594 -41
36 ------------------------------------------------------------------------------
37 (add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes
38 text data bss dec hex filename
39 912030 563 5844 918437 e03a5 busybox_old
40 912473 587 5844 918904 e0578 busybox_unstripped
42 diff --git a/shell/ash.c b/shell/ash.c
43 index 703802f..93a3814 100644
46 @@ -312,6 +312,8 @@ struct globals_misc {
47 /* shell level: 0 for the main shell, 1 for its children, and so on */
49 #define rootshell (!shlvl)
52 char *minusc; /* argument to -c option */
54 char *curdir; // = nullstr; /* current working directory */
55 @@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
56 #define job_warning (G_misc.job_warning)
57 #define rootpid (G_misc.rootpid )
58 #define shlvl (G_misc.shlvl )
59 +#define errlinno (G_misc.errlinno )
60 #define minusc (G_misc.minusc )
61 #define curdir (G_misc.curdir )
62 #define physdir (G_misc.physdir )
63 @@ -723,6 +726,7 @@ union node;
66 smallint type; /* Nxxxx */
71 @@ -736,6 +740,7 @@ struct npipe {
79 @@ -755,6 +760,7 @@ struct nif {
87 @@ -762,6 +768,7 @@ struct nfor {
95 @@ -773,6 +780,13 @@ struct nclist {
109 @@ -824,6 +838,7 @@ union node {
112 struct nclist nclist;
113 + struct ndefun ndefun;
117 @@ -1253,7 +1268,6 @@ struct parsefile {
119 static struct parsefile basepf; /* top level input file */
120 static struct parsefile *g_parsefile = &basepf; /* current input file */
121 -static int startlinno; /* line # where last token started */
122 static char *commandname; /* currently executing command */
125 @@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap)
126 if (strcmp(arg0, commandname))
127 fprintf(stderr, "%s: ", commandname);
128 if (!iflag || g_parsefile->pf_fd > 0)
129 - fprintf(stderr, "line %d: ", startlinno);
130 + fprintf(stderr, "line %d: ", errlinno);
132 vfprintf(stderr, msg, ap);
133 newline_and_flush(stderr);
134 @@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN;
136 raise_error_syntax(const char *msg)
138 + errlinno = g_parsefile->linno;
139 ash_msg_and_raise_error("syntax error: %s", msg);
142 @@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC;
143 static void change_random(const char *) FAST_FUNC;
147 +static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO=";
149 static const struct {
151 const char *var_text;
152 @@ -2014,6 +2032,7 @@ static const struct {
153 #if ENABLE_ASH_GETOPTS
154 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
156 + { VSTRFIXED|VTEXTFIXED , linenovar , NULL },
157 #if ENABLE_ASH_RANDOM_SUPPORT
158 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
160 @@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var;
161 #define vps4 (&vps2)[1]
162 #if ENABLE_ASH_GETOPTS
163 # define voptind (&vps4)[1]
164 +# define vlineno (&voptind)[1]
165 # if ENABLE_ASH_RANDOM_SUPPORT
166 -# define vrandom (&voptind)[1]
167 +# define vrandom (&vlineno)[1]
170 +# define vlineno (&vps4)[1]
171 # if ENABLE_ASH_RANDOM_SUPPORT
172 -# define vrandom (&vps4)[1]
173 +# define vrandom (&vlineno)[1]
177 @@ -2209,8 +2230,12 @@ lookupvar(const char *name)
178 if (v->flags & VDYNAMIC)
181 - if (!(v->flags & VUNSET))
182 + if (!(v->flags & VUNSET)) {
183 + if (v == &vlineno && v->var_text == linenovar) {
184 + fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
186 return var_end(v->var_text);
191 @@ -4783,7 +4808,7 @@ cmdtxt(union node *n)
195 - cmdputs(n->narg.text);
196 + cmdputs(n->ndefun.text);
200 @@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n)
201 funcblocksize = calcsize(funcblocksize, n->nclist.next);
204 + funcblocksize = calcsize(funcblocksize, n->ndefun.body);
205 + funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
208 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
209 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
210 @@ -8626,6 +8654,7 @@ copynode(union node *n)
211 new->ncmd.redirect = copynode(n->ncmd.redirect);
212 new->ncmd.args = copynode(n->ncmd.args);
213 new->ncmd.assign = copynode(n->ncmd.assign);
214 + new->ncmd.linno = n->ncmd.linno;
217 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
218 @@ -8636,6 +8665,7 @@ copynode(union node *n)
220 new->nredir.redirect = copynode(n->nredir.redirect);
221 new->nredir.n = copynode(n->nredir.n);
222 + new->nredir.linno = n->nredir.linno;
226 @@ -8654,10 +8684,12 @@ copynode(union node *n)
227 new->nfor.var = nodeckstrdup(n->nfor.var);
228 new->nfor.body = copynode(n->nfor.body);
229 new->nfor.args = copynode(n->nfor.args);
230 + new->nfor.linno = n->nfor.linno;
233 new->ncase.cases = copynode(n->ncase.cases);
234 new->ncase.expr = copynode(n->ncase.expr);
235 + new->ncase.linno = n->ncase.linno;
238 new->nclist.body = copynode(n->nclist.body);
239 @@ -8665,6 +8697,10 @@ copynode(union node *n)
240 new->nclist.next = copynode(n->nclist.next);
243 + new->ndefun.body = copynode(n->ndefun.body);
244 + new->ndefun.text = nodeckstrdup(n->ndefun.text);
245 + new->ndefun.linno = n->ndefun.linno;
248 new->narg.backquote = copynodelist(n->narg.backquote);
249 new->narg.text = nodeckstrdup(n->narg.text);
250 @@ -8733,7 +8769,7 @@ defun(union node *func)
252 entry.cmdtype = CMDFUNCTION;
253 entry.u.func = copyfunc(func);
254 - addcmdentry(func->narg.text, &entry);
255 + addcmdentry(func->ndefun.text, &entry);
259 @@ -8743,8 +8779,8 @@ defun(union node *func)
260 #define SKIPFUNC (1 << 2)
261 static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
262 static int skipcount; /* number of levels to skip */
263 -static int funcnest; /* depth of function calls */
264 static int loopnest; /* current loop nesting level */
265 +static int funcline; /* starting line number of current function, or 0 if not in a function */
267 /* Forward decl way out to parsing code - dotrap needs it */
268 static int evalstring(char *s, int flags);
269 @@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags)
270 status = !evaltree(n->nnot.com, EV_TESTED);
273 + errlinno = lineno = n->nredir.linno;
275 + lineno -= funcline - 1;
276 expredir(n->nredir.redirect);
277 pushredir(n->nredir.redirect);
278 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
279 @@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags)
280 struct stackmark smark;
283 + errlinno = lineno = n->ncase.linno;
285 + lineno -= funcline - 1;
287 setstackmark(&smark);
289 arglist.lastp = &arglist.list;
290 @@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags)
291 struct stackmark smark;
294 + errlinno = lineno = n->ncase.linno;
296 + lineno -= funcline - 1;
298 setstackmark(&smark);
300 arglist.lastp = &arglist.list;
301 @@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags)
302 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
305 + errlinno = lineno = n->nredir.linno;
307 + lineno -= funcline - 1;
309 expredir(n->nredir.redirect);
310 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
312 @@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
313 struct jmploc *volatile savehandler;
314 struct jmploc jmploc;
318 saveparam = shellparam;
319 + savefuncline = funcline;
320 savehandler = exception_handler;
321 e = setjmp(jmploc.loc);
323 @@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
324 exception_handler = &jmploc;
325 shellparam.malloced = 0;
328 + funcline = func->n.ndefun.linno;
330 shellparam.nparam = argc - 1;
331 shellparam.p = argv + 1;
332 @@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
333 shellparam.optoff = -1;
336 - evaltree(func->n.narg.next, flags & EV_TESTED);
337 + evaltree(func->n.ndefun.body, flags & EV_TESTED);
342 + funcline = savefuncline;
344 freeparam(&shellparam);
345 shellparam = saveparam;
346 @@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags)
348 smallint cmd_is_exec;
350 + errlinno = lineno = cmd->ncmd.linno;
352 + lineno -= funcline - 1;
354 /* First expand the arguments. */
355 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
356 setstackmark(&smark);
357 @@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags)
361 - if (iflag && funcnest == 0 && argc > 0)
362 + if (iflag && funcline == 0 && argc > 0)
365 expredir(cmd->ncmd.redirect);
366 @@ -11317,6 +11374,7 @@ simplecmd(void)
367 union node *vars, **vpp;
368 union node **rpp, *redir;
372 smallint double_brackets_flag = 0;
374 @@ -11330,6 +11388,7 @@ simplecmd(void)
377 savecheckkwd = CHKALIAS;
378 + savelinno = g_parsefile->linno;
381 checkkwd = savecheckkwd;
382 @@ -11419,7 +11478,9 @@ simplecmd(void)
385 checkkwd = CHKNL | CHKKWD | CHKALIAS;
386 - n->narg.next = parse_command();
387 + n->ndefun.text = n->narg.text;
388 + n->ndefun.linno = g_parsefile->linno;
389 + n->ndefun.body = parse_command();
392 IF_BASH_FUNCTION(function_flag = 0;)
393 @@ -11435,6 +11496,7 @@ simplecmd(void)
395 n = stzalloc(sizeof(struct ncmd));
397 + n->ncmd.linno = savelinno;
399 n->ncmd.assign = vars;
400 n->ncmd.redirect = redir;
401 @@ -11450,10 +11512,13 @@ parse_command(void)
402 union node *redir, **rpp;
410 + savelinno = g_parsefile->linno;
412 switch (readtoken()) {
414 raise_error_unexpected_syntax(-1);
415 @@ -11504,6 +11569,7 @@ parse_command(void)
416 raise_error_syntax("bad for loop variable");
417 n1 = stzalloc(sizeof(struct nfor));
419 + n1->nfor.linno = savelinno;
420 n1->nfor.var = wordtext;
421 checkkwd = CHKNL | CHKKWD | CHKALIAS;
422 if (readtoken() == TIN) {
423 @@ -11544,6 +11610,7 @@ parse_command(void)
425 n1 = stzalloc(sizeof(struct ncase));
427 + n1->ncase.linno = savelinno;
428 if (readtoken() != TWORD)
429 raise_error_unexpected_syntax(TWORD);
430 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
431 @@ -11595,6 +11662,7 @@ parse_command(void)
433 n1 = stzalloc(sizeof(struct nredir));
434 n1->type = NSUBSHELL;
435 + n1->nredir.linno = savelinno;
436 n1->nredir.n = list(0);
437 /*n1->nredir.redirect = NULL; - stzalloc did it */
439 @@ -11628,6 +11696,7 @@ parse_command(void)
440 if (n1->type != NSUBSHELL) {
441 n2 = stzalloc(sizeof(struct nredir));
443 + n2->nredir.linno = savelinno;
447 @@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
448 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
449 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
450 int dqvarnest; /* levels of variables expansion within double quotes */
452 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
454 - startlinno = g_parsefile->linno;
457 IF_FEATURE_SH_MATH(prevsyntax = 0;)
458 @@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
459 if (syntax != BASESYNTAX && eofmark == NULL)
460 raise_error_syntax("unterminated quoted string");
462 - startlinno = g_parsefile->linno;
464 raise_error_syntax("missing '}'");
466 @@ -12298,7 +12364,6 @@ parsebackq: {
469 IF_ASH_ALIAS(case PEOA:)
470 - startlinno = g_parsefile->linno;
471 raise_error_syntax("EOF in backquote substitution");
474 @@ -12380,8 +12445,6 @@ parsearith: {
476 * If the token is TREDIR, then we set redirnode to a structure containing
478 - * In all cases, the variable startlinno is set to the number of the line
479 - * on which the token starts.
481 * [Change comment: here documents and internal procedures]
482 * [Readtoken shouldn't have any arguments. Perhaps we should make the
483 @@ -12419,7 +12482,6 @@ xxreadtoken(void)
486 setprompt_if(needprompt, 2);
487 - startlinno = g_parsefile->linno;
488 for (;;) { /* until token or start of word found */
490 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
491 @@ -12480,7 +12542,6 @@ xxreadtoken(void)
494 setprompt_if(needprompt, 2);
495 - startlinno = g_parsefile->linno;
496 for (;;) { /* until token or start of word found */