From fec2b1f79dc2f6bfd96f44719300f9c773d88208 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 17 Aug 2017 16:43:33 +0200 Subject: ash: stage backported LINENO support as a separate patch Looks biggish and not particularly useful, but may be easier to just eat the impact if future backports from dash would be otherwise increasingly difficult. Signed-off-by: Denys Vlasenko --- shell/ash_LINENO.patch | 498 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 shell/ash_LINENO.patch (limited to 'shell/ash_LINENO.patch') diff --git a/shell/ash_LINENO.patch b/shell/ash_LINENO.patch new file mode 100644 index 000000000..a71549d6a --- /dev/null +++ b/shell/ash_LINENO.patch @@ -0,0 +1,498 @@ +This patch is a backport from dash of the combination of: + [SHELL] Add preliminary LINENO support + [VAR] Fix varinit ordering that broke fc + [SHELL] Improve LINENO support + +Applies cleanly on top of: + commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe + Date: Tue Aug 15 15:44:41 2017 +0200 + +Testsuite needs some tweaks (line numbers in some messages change). + +Unfortunately, it is somewhat big: + +function old new delta +parse_command 1581 1658 +77 +calcsize 203 272 +69 +copynode 195 257 +62 +lookupvar 59 108 +49 +evaltree 494 534 +40 +evalfor 152 187 +35 +evalcase 278 313 +35 +evalcommand 1547 1581 +34 +evalsubshell 169 199 +30 +linenovar - 22 +22 +raise_error_syntax 11 29 +18 +evalfun 266 280 +14 +varinit_data 96 108 +12 +cmdtxt 626 631 +5 +lineno - 4 +4 +funcline - 4 +4 +ash_vmsg 144 141 -3 +startlinno 4 - -4 +funcnest 4 - -4 +xxreadtoken 272 259 -13 +readtoken1 2635 2594 -41 +------------------------------------------------------------------------------ +(add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes + text data bss dec hex filename + 912030 563 5844 918437 e03a5 busybox_old + 912473 587 5844 918904 e0578 busybox_unstripped + +diff --git a/shell/ash.c b/shell/ash.c +index 703802f..93a3814 100644 +--- a/shell/ash.c ++++ b/shell/ash.c +@@ -312,6 +312,8 @@ struct globals_misc { + /* shell level: 0 for the main shell, 1 for its children, and so on */ + int shlvl; + #define rootshell (!shlvl) ++ int errlinno; ++ + char *minusc; /* argument to -c option */ + + char *curdir; // = nullstr; /* current working directory */ +@@ -389,6 +391,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; + #define job_warning (G_misc.job_warning) + #define rootpid (G_misc.rootpid ) + #define shlvl (G_misc.shlvl ) ++#define errlinno (G_misc.errlinno ) + #define minusc (G_misc.minusc ) + #define curdir (G_misc.curdir ) + #define physdir (G_misc.physdir ) +@@ -723,6 +726,7 @@ union node; + + struct ncmd { + smallint type; /* Nxxxx */ ++ int linno; + union node *assign; + union node *args; + union node *redirect; +@@ -736,6 +740,7 @@ struct npipe { + + struct nredir { + smallint type; ++ int linno; + union node *n; + union node *redirect; + }; +@@ -755,6 +760,7 @@ struct nif { + + struct nfor { + smallint type; ++ int linno; + union node *args; + union node *body; + char *var; +@@ -762,6 +768,7 @@ struct nfor { + + struct ncase { + smallint type; ++ int linno; + union node *expr; + union node *cases; + }; +@@ -773,6 +780,13 @@ struct nclist { + union node *body; + }; + ++struct ndefun { ++ smallint type; ++ int linno; ++ char *text; ++ union node *body; ++}; ++ + struct narg { + smallint type; + union node *next; +@@ -824,6 +838,7 @@ union node { + struct nfor nfor; + struct ncase ncase; + struct nclist nclist; ++ struct ndefun ndefun; + struct narg narg; + struct nfile nfile; + struct ndup ndup; +@@ -1253,7 +1268,6 @@ struct parsefile { + + static struct parsefile basepf; /* top level input file */ + static struct parsefile *g_parsefile = &basepf; /* current input file */ +-static int startlinno; /* line # where last token started */ + static char *commandname; /* currently executing command */ + + +@@ -1267,7 +1281,7 @@ ash_vmsg(const char *msg, va_list ap) + if (strcmp(arg0, commandname)) + fprintf(stderr, "%s: ", commandname); + if (!iflag || g_parsefile->pf_fd > 0) +- fprintf(stderr, "line %d: ", startlinno); ++ fprintf(stderr, "line %d: ", errlinno); + } + vfprintf(stderr, msg, ap); + newline_and_flush(stderr); +@@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN; + static void + raise_error_syntax(const char *msg) + { ++ errlinno = g_parsefile->linno; + ash_msg_and_raise_error("syntax error: %s", msg); + /* NOTREACHED */ + } +@@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC; + static void change_random(const char *) FAST_FUNC; + #endif + ++static int lineno; ++static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO="; ++ + static const struct { + int flags; + const char *var_text; +@@ -2014,6 +2032,7 @@ static const struct { + #if ENABLE_ASH_GETOPTS + { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, + #endif ++ { VSTRFIXED|VTEXTFIXED , linenovar , NULL }, + #if ENABLE_ASH_RANDOM_SUPPORT + { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, + #endif +@@ -2066,12 +2085,14 @@ extern struct globals_var *const ash_ptr_to_globals_var; + #define vps4 (&vps2)[1] + #if ENABLE_ASH_GETOPTS + # define voptind (&vps4)[1] ++# define vlineno (&voptind)[1] + # if ENABLE_ASH_RANDOM_SUPPORT +-# define vrandom (&voptind)[1] ++# define vrandom (&vlineno)[1] + # endif + #else ++# define vlineno (&vps4)[1] + # if ENABLE_ASH_RANDOM_SUPPORT +-# define vrandom (&vps4)[1] ++# define vrandom (&vlineno)[1] + # endif + #endif + +@@ -2209,8 +2230,12 @@ lookupvar(const char *name) + if (v->flags & VDYNAMIC) + v->var_func(NULL); + #endif +- if (!(v->flags & VUNSET)) ++ if (!(v->flags & VUNSET)) { ++ if (v == &vlineno && v->var_text == linenovar) { ++ fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); ++ } + return var_end(v->var_text); ++ } + } + return NULL; + } +@@ -4783,7 +4808,7 @@ cmdtxt(union node *n) + p = "; done"; + goto dodo; + case NDEFUN: +- cmdputs(n->narg.text); ++ cmdputs(n->ndefun.text); + p = "() { ... }"; + goto dotail2; + case NCMD: +@@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n) + funcblocksize = calcsize(funcblocksize, n->nclist.next); + break; + case NDEFUN: ++ funcblocksize = calcsize(funcblocksize, n->ndefun.body); ++ funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1); ++ break; + case NARG: + funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); + funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ +@@ -8626,6 +8654,7 @@ copynode(union node *n) + new->ncmd.redirect = copynode(n->ncmd.redirect); + new->ncmd.args = copynode(n->ncmd.args); + new->ncmd.assign = copynode(n->ncmd.assign); ++ new->ncmd.linno = n->ncmd.linno; + break; + case NPIPE: + new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); +@@ -8636,6 +8665,7 @@ copynode(union node *n) + case NSUBSHELL: + new->nredir.redirect = copynode(n->nredir.redirect); + new->nredir.n = copynode(n->nredir.n); ++ new->nredir.linno = n->nredir.linno; + break; + case NAND: + case NOR: +@@ -8654,10 +8684,12 @@ copynode(union node *n) + new->nfor.var = nodeckstrdup(n->nfor.var); + new->nfor.body = copynode(n->nfor.body); + new->nfor.args = copynode(n->nfor.args); ++ new->nfor.linno = n->nfor.linno; + break; + case NCASE: + new->ncase.cases = copynode(n->ncase.cases); + new->ncase.expr = copynode(n->ncase.expr); ++ new->ncase.linno = n->ncase.linno; + break; + case NCLIST: + new->nclist.body = copynode(n->nclist.body); +@@ -8665,6 +8697,10 @@ copynode(union node *n) + new->nclist.next = copynode(n->nclist.next); + break; + case NDEFUN: ++ new->ndefun.body = copynode(n->ndefun.body); ++ new->ndefun.text = nodeckstrdup(n->ndefun.text); ++ new->ndefun.linno = n->ndefun.linno; ++ break; + case NARG: + new->narg.backquote = copynodelist(n->narg.backquote); + new->narg.text = nodeckstrdup(n->narg.text); +@@ -8733,7 +8769,7 @@ defun(union node *func) + INT_OFF; + entry.cmdtype = CMDFUNCTION; + entry.u.func = copyfunc(func); +- addcmdentry(func->narg.text, &entry); ++ addcmdentry(func->ndefun.text, &entry); + INT_ON; + } + +@@ -8743,8 +8779,8 @@ defun(union node *func) + #define SKIPFUNC (1 << 2) + static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ + static int skipcount; /* number of levels to skip */ +-static int funcnest; /* depth of function calls */ + static int loopnest; /* current loop nesting level */ ++static int funcline; /* starting line number of current function, or 0 if not in a function */ + + /* Forward decl way out to parsing code - dotrap needs it */ + static int evalstring(char *s, int flags); +@@ -8839,6 +8875,9 @@ evaltree(union node *n, int flags) + status = !evaltree(n->nnot.com, EV_TESTED); + goto setstatus; + case NREDIR: ++ errlinno = lineno = n->nredir.linno; ++ if (funcline) ++ lineno -= funcline - 1; + expredir(n->nredir.redirect); + pushredir(n->nredir.redirect); + status = redirectsafe(n->nredir.redirect, REDIR_PUSH); +@@ -8993,6 +9032,10 @@ evalfor(union node *n, int flags) + struct stackmark smark; + int status = 0; + ++ errlinno = lineno = n->ncase.linno; ++ if (funcline) ++ lineno -= funcline - 1; ++ + setstackmark(&smark); + arglist.list = NULL; + arglist.lastp = &arglist.list; +@@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags) + struct stackmark smark; + int status = 0; + ++ errlinno = lineno = n->ncase.linno; ++ if (funcline) ++ lineno -= funcline - 1; ++ + setstackmark(&smark); + arglist.list = NULL; + arglist.lastp = &arglist.list; +@@ -9058,6 +9105,10 @@ evalsubshell(union node *n, int flags) + int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ + int status; + ++ errlinno = lineno = n->nredir.linno; ++ if (funcline) ++ lineno -= funcline - 1; ++ + expredir(n->nredir.redirect); + if (!backgnd && (flags & EV_EXIT) && !may_have_traps) + goto nofork; +@@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) + struct jmploc *volatile savehandler; + struct jmploc jmploc; + int e; ++ int savefuncline; + + saveparam = shellparam; ++ savefuncline = funcline; + savehandler = exception_handler; + e = setjmp(jmploc.loc); + if (e) { +@@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) + exception_handler = &jmploc; + shellparam.malloced = 0; + func->count++; +- funcnest++; ++ funcline = func->n.ndefun.linno; + INT_ON; + shellparam.nparam = argc - 1; + shellparam.p = argv + 1; +@@ -9385,11 +9438,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) + shellparam.optoff = -1; + #endif + pushlocalvars(); +- evaltree(func->n.narg.next, flags & EV_TESTED); ++ evaltree(func->n.ndefun.body, flags & EV_TESTED); + poplocalvars(0); + funcdone: + INT_OFF; +- funcnest--; ++ funcline = savefuncline; + freefunc(func); + freeparam(&shellparam); + shellparam = saveparam; +@@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags) + char **nargv; + smallint cmd_is_exec; + ++ errlinno = lineno = cmd->ncmd.linno; ++ if (funcline) ++ lineno -= funcline - 1; ++ + /* First expand the arguments. */ + TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); + setstackmark(&smark); +@@ -9798,7 +9855,7 @@ evalcommand(union node *cmd, int flags) + *nargv = NULL; + + lastarg = NULL; +- if (iflag && funcnest == 0 && argc > 0) ++ if (iflag && funcline == 0 && argc > 0) + lastarg = nargv[-1]; + + expredir(cmd->ncmd.redirect); +@@ -11317,6 +11374,7 @@ simplecmd(void) + union node *vars, **vpp; + union node **rpp, *redir; + int savecheckkwd; ++ int savelinno; + #if BASH_TEST2 + smallint double_brackets_flag = 0; + #endif +@@ -11330,6 +11388,7 @@ simplecmd(void) + rpp = &redir; + + savecheckkwd = CHKALIAS; ++ savelinno = g_parsefile->linno; + for (;;) { + int t; + checkkwd = savecheckkwd; +@@ -11419,7 +11478,9 @@ simplecmd(void) + } + n->type = NDEFUN; + checkkwd = CHKNL | CHKKWD | CHKALIAS; +- n->narg.next = parse_command(); ++ n->ndefun.text = n->narg.text; ++ n->ndefun.linno = g_parsefile->linno; ++ n->ndefun.body = parse_command(); + return n; + } + IF_BASH_FUNCTION(function_flag = 0;) +@@ -11435,6 +11496,7 @@ simplecmd(void) + *rpp = NULL; + n = stzalloc(sizeof(struct ncmd)); + n->type = NCMD; ++ n->ncmd.linno = savelinno; + n->ncmd.args = args; + n->ncmd.assign = vars; + n->ncmd.redirect = redir; +@@ -11450,10 +11512,13 @@ parse_command(void) + union node *redir, **rpp; + union node **rpp2; + int t; ++ int savelinno; + + redir = NULL; + rpp2 = &redir; + ++ savelinno = g_parsefile->linno; ++ + switch (readtoken()) { + default: + raise_error_unexpected_syntax(-1); +@@ -11504,6 +11569,7 @@ parse_command(void) + raise_error_syntax("bad for loop variable"); + n1 = stzalloc(sizeof(struct nfor)); + n1->type = NFOR; ++ n1->nfor.linno = savelinno; + n1->nfor.var = wordtext; + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (readtoken() == TIN) { +@@ -11544,6 +11610,7 @@ parse_command(void) + case TCASE: + n1 = stzalloc(sizeof(struct ncase)); + n1->type = NCASE; ++ n1->ncase.linno = savelinno; + if (readtoken() != TWORD) + raise_error_unexpected_syntax(TWORD); + n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); +@@ -11595,6 +11662,7 @@ parse_command(void) + case TLP: + n1 = stzalloc(sizeof(struct nredir)); + n1->type = NSUBSHELL; ++ n1->nredir.linno = savelinno; + n1->nredir.n = list(0); + /*n1->nredir.redirect = NULL; - stzalloc did it */ + t = TRP; +@@ -11628,6 +11696,7 @@ parse_command(void) + if (n1->type != NSUBSHELL) { + n2 = stzalloc(sizeof(struct nredir)); + n2->type = NREDIR; ++ n2->nredir.linno = savelinno; + n2->nredir.n = n1; + n1 = n2; + } +@@ -11726,10 +11795,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) + IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ + IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ + int dqvarnest; /* levels of variables expansion within double quotes */ +- + IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) + +- startlinno = g_parsefile->linno; + bqlist = NULL; + quotef = 0; + IF_FEATURE_SH_MATH(prevsyntax = 0;) +@@ -11906,7 +11973,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) + if (syntax != BASESYNTAX && eofmark == NULL) + raise_error_syntax("unterminated quoted string"); + if (varnest != 0) { +- startlinno = g_parsefile->linno; + /* { */ + raise_error_syntax("missing '}'"); + } +@@ -12298,7 +12364,6 @@ parsebackq: { + + case PEOF: + IF_ASH_ALIAS(case PEOA:) +- startlinno = g_parsefile->linno; + raise_error_syntax("EOF in backquote substitution"); + + case '\n': +@@ -12380,8 +12445,6 @@ parsearith: { + * quoted. + * If the token is TREDIR, then we set redirnode to a structure containing + * the redirection. +- * In all cases, the variable startlinno is set to the number of the line +- * on which the token starts. + * + * [Change comment: here documents and internal procedures] + * [Readtoken shouldn't have any arguments. Perhaps we should make the +@@ -12419,7 +12482,6 @@ xxreadtoken(void) + return lasttoken; + } + setprompt_if(needprompt, 2); +- startlinno = g_parsefile->linno; + for (;;) { /* until token or start of word found */ + c = pgetc(); + if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) +@@ -12480,7 +12542,6 @@ xxreadtoken(void) + return lasttoken; + } + setprompt_if(needprompt, 2); +- startlinno = g_parsefile->linno; + for (;;) { /* until token or start of word found */ + c = pgetc(); + switch (c) { -- cgit v1.2.3