ash: stage backported LINENO support as a separate patch
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 17 Aug 2017 14:43:33 +0000 (16:43 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 17 Aug 2017 14:43:33 +0000 (16:43 +0200)
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 <vda.linux@googlemail.com>
shell/ash_LINENO.patch [new file with mode: 0644]

diff --git a/shell/ash_LINENO.patch b/shell/ash_LINENO.patch
new file mode 100644 (file)
index 0000000..a71549d
--- /dev/null
@@ -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) {