aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-01-27 22:02:05 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-01-27 22:02:05 +0100
commit675d24aeaff29dbce6dc116a4b7c9f6026ed5069 (patch)
tree446b740ec2d9b2fd035821a89dd876f10b27bff4 /shell
parent54c2111781e15b1c70bea43593aa67207f9ea118 (diff)
downloadbusybox-w32-675d24aeaff29dbce6dc116a4b7c9f6026ed5069.tar.gz
busybox-w32-675d24aeaff29dbce6dc116a4b7c9f6026ed5069.tar.bz2
busybox-w32-675d24aeaff29dbce6dc116a4b7c9f6026ed5069.zip
ash: add LINENO support
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 function old new delta parse_command 1604 1677 +73 calcsize 156 223 +67 copynode 196 258 +62 evalcommand 1546 1606 +60 ash_main 1046 1103 +57 lookupvar 51 106 +55 evalcase 269 317 +48 evaltree 501 547 +46 evalfor 156 200 +44 evalsubshell 156 195 +39 raise_error_syntax 11 29 +18 varinit_data 120 132 +12 evalfun 270 280 +10 funcline - 4 +4 cmdtxt 569 572 +3 trapcmd 306 304 -2 ash_vmsg 153 150 -3 startlinno 4 - -4 funcnest 4 - -4 xxreadtoken 263 250 -13 readtoken1 2645 2602 -43 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 14/4 up/down: 598/-69) Total: 529 bytes text data bss dec hex filename 932834 481 6864 940179 e5893 busybox_old 933375 481 6856 940712 e5aa8 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c127
-rw-r--r--shell/ash_LINENO.patch498
-rw-r--r--shell/ash_test/ash-psubst/emptytick.right4
-rw-r--r--shell/ash_test/ash-quoting/mode_x.right4
4 files changed, 99 insertions, 534 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 3fff88168..6b7386f79 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -328,6 +328,8 @@ struct globals_misc {
328 /* shell level: 0 for the main shell, 1 for its children, and so on */ 328 /* shell level: 0 for the main shell, 1 for its children, and so on */
329 int shlvl; 329 int shlvl;
330#define rootshell (!shlvl) 330#define rootshell (!shlvl)
331 int errlinno;
332
331 char *minusc; /* argument to -c option */ 333 char *minusc; /* argument to -c option */
332 334
333 char *curdir; // = nullstr; /* current working directory */ 335 char *curdir; // = nullstr; /* current working directory */
@@ -405,6 +407,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
405#define job_warning (G_misc.job_warning) 407#define job_warning (G_misc.job_warning)
406#define rootpid (G_misc.rootpid ) 408#define rootpid (G_misc.rootpid )
407#define shlvl (G_misc.shlvl ) 409#define shlvl (G_misc.shlvl )
410#define errlinno (G_misc.errlinno )
408#define minusc (G_misc.minusc ) 411#define minusc (G_misc.minusc )
409#define curdir (G_misc.curdir ) 412#define curdir (G_misc.curdir )
410#define physdir (G_misc.physdir ) 413#define physdir (G_misc.physdir )
@@ -739,6 +742,7 @@ union node;
739 742
740struct ncmd { 743struct ncmd {
741 smallint type; /* Nxxxx */ 744 smallint type; /* Nxxxx */
745 int linno;
742 union node *assign; 746 union node *assign;
743 union node *args; 747 union node *args;
744 union node *redirect; 748 union node *redirect;
@@ -752,6 +756,7 @@ struct npipe {
752 756
753struct nredir { 757struct nredir {
754 smallint type; 758 smallint type;
759 int linno;
755 union node *n; 760 union node *n;
756 union node *redirect; 761 union node *redirect;
757}; 762};
@@ -771,6 +776,7 @@ struct nif {
771 776
772struct nfor { 777struct nfor {
773 smallint type; 778 smallint type;
779 int linno;
774 union node *args; 780 union node *args;
775 union node *body; 781 union node *body;
776 char *var; 782 char *var;
@@ -778,6 +784,7 @@ struct nfor {
778 784
779struct ncase { 785struct ncase {
780 smallint type; 786 smallint type;
787 int linno;
781 union node *expr; 788 union node *expr;
782 union node *cases; 789 union node *cases;
783}; 790};
@@ -789,6 +796,13 @@ struct nclist {
789 union node *body; 796 union node *body;
790}; 797};
791 798
799struct ndefun {
800 smallint type;
801 int linno;
802 char *text;
803 union node *body;
804};
805
792struct narg { 806struct narg {
793 smallint type; 807 smallint type;
794 union node *next; 808 union node *next;
@@ -840,6 +854,7 @@ union node {
840 struct nfor nfor; 854 struct nfor nfor;
841 struct ncase ncase; 855 struct ncase ncase;
842 struct nclist nclist; 856 struct nclist nclist;
857 struct ndefun ndefun;
843 struct narg narg; 858 struct narg narg;
844 struct nfile nfile; 859 struct nfile nfile;
845 struct ndup ndup; 860 struct ndup ndup;
@@ -1269,7 +1284,6 @@ struct parsefile {
1269 1284
1270static struct parsefile basepf; /* top level input file */ 1285static struct parsefile basepf; /* top level input file */
1271static struct parsefile *g_parsefile = &basepf; /* current input file */ 1286static struct parsefile *g_parsefile = &basepf; /* current input file */
1272static int startlinno; /* line # where last token started */
1273static char *commandname; /* currently executing command */ 1287static char *commandname; /* currently executing command */
1274 1288
1275 1289
@@ -1283,7 +1297,7 @@ ash_vmsg(const char *msg, va_list ap)
1283 if (strcmp(arg0, commandname)) 1297 if (strcmp(arg0, commandname))
1284 fprintf(stderr, "%s: ", commandname); 1298 fprintf(stderr, "%s: ", commandname);
1285 if (!iflag || g_parsefile->pf_fd > 0) 1299 if (!iflag || g_parsefile->pf_fd > 0)
1286 fprintf(stderr, "line %d: ", startlinno); 1300 fprintf(stderr, "line %d: ", errlinno);
1287 } 1301 }
1288 vfprintf(stderr, msg, ap); 1302 vfprintf(stderr, msg, ap);
1289 newline_and_flush(stderr); 1303 newline_and_flush(stderr);
@@ -1336,6 +1350,7 @@ static void raise_error_syntax(const char *) NORETURN;
1336static void 1350static void
1337raise_error_syntax(const char *msg) 1351raise_error_syntax(const char *msg)
1338{ 1352{
1353 errlinno = g_parsefile->linno;
1339 ash_msg_and_raise_error("syntax error: %s", msg); 1354 ash_msg_and_raise_error("syntax error: %s", msg);
1340 /* NOTREACHED */ 1355 /* NOTREACHED */
1341} 1356}
@@ -2023,6 +2038,7 @@ static const struct {
2023#if ENABLE_ASH_GETOPTS 2038#if ENABLE_ASH_GETOPTS
2024 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, 2039 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
2025#endif 2040#endif
2041 { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
2026#if ENABLE_ASH_RANDOM_SUPPORT 2042#if ENABLE_ASH_RANDOM_SUPPORT
2027 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, 2043 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
2028#endif 2044#endif
@@ -2043,6 +2059,8 @@ struct globals_var {
2043 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */ 2059 int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
2044 struct var *vartab[VTABSIZE]; 2060 struct var *vartab[VTABSIZE];
2045 struct var varinit[ARRAY_SIZE(varinit_data)]; 2061 struct var varinit[ARRAY_SIZE(varinit_data)];
2062 int lineno;
2063 char linenovar[sizeof("LINENO=") + sizeof(int)*3];
2046}; 2064};
2047extern struct globals_var *const ash_ptr_to_globals_var; 2065extern struct globals_var *const ash_ptr_to_globals_var;
2048#define G_var (*ash_ptr_to_globals_var) 2066#define G_var (*ash_ptr_to_globals_var)
@@ -2051,17 +2069,8 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2051#define preverrout_fd (G_var.preverrout_fd) 2069#define preverrout_fd (G_var.preverrout_fd)
2052#define vartab (G_var.vartab ) 2070#define vartab (G_var.vartab )
2053#define varinit (G_var.varinit ) 2071#define varinit (G_var.varinit )
2054#define INIT_G_var() do { \ 2072#define lineno (G_var.lineno )
2055 unsigned i; \ 2073#define linenovar (G_var.linenovar )
2056 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2057 barrier(); \
2058 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2059 varinit[i].flags = varinit_data[i].flags; \
2060 varinit[i].var_text = varinit_data[i].var_text; \
2061 varinit[i].var_func = varinit_data[i].var_func; \
2062 } \
2063} while (0)
2064
2065#define vifs varinit[0] 2074#define vifs varinit[0]
2066#if ENABLE_ASH_MAIL 2075#if ENABLE_ASH_MAIL
2067# define vmail (&vifs)[1] 2076# define vmail (&vifs)[1]
@@ -2075,14 +2084,28 @@ extern struct globals_var *const ash_ptr_to_globals_var;
2075#define vps4 (&vps2)[1] 2084#define vps4 (&vps2)[1]
2076#if ENABLE_ASH_GETOPTS 2085#if ENABLE_ASH_GETOPTS
2077# define voptind (&vps4)[1] 2086# define voptind (&vps4)[1]
2087# define vlineno (&voptind)[1]
2078# if ENABLE_ASH_RANDOM_SUPPORT 2088# if ENABLE_ASH_RANDOM_SUPPORT
2079# define vrandom (&voptind)[1] 2089# define vrandom (&vlineno)[1]
2080# endif 2090# endif
2081#else 2091#else
2092# define vlineno (&vps4)[1]
2082# if ENABLE_ASH_RANDOM_SUPPORT 2093# if ENABLE_ASH_RANDOM_SUPPORT
2083# define vrandom (&vps4)[1] 2094# define vrandom (&vlineno)[1]
2084# endif 2095# endif
2085#endif 2096#endif
2097#define INIT_G_var() do { \
2098 unsigned i; \
2099 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
2100 barrier(); \
2101 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2102 varinit[i].flags = varinit_data[i].flags; \
2103 varinit[i].var_text = varinit_data[i].var_text; \
2104 varinit[i].var_func = varinit_data[i].var_func; \
2105 } \
2106 strcpy(linenovar, "LINENO="); \
2107 vlineno.var_text = linenovar; \
2108} while (0)
2086 2109
2087/* 2110/*
2088 * The following macros access the values of the above variables. 2111 * The following macros access the values of the above variables.
@@ -2218,8 +2241,12 @@ lookupvar(const char *name)
2218 if (v->flags & VDYNAMIC) 2241 if (v->flags & VDYNAMIC)
2219 v->var_func(NULL); 2242 v->var_func(NULL);
2220#endif 2243#endif
2221 if (!(v->flags & VUNSET)) 2244 if (!(v->flags & VUNSET)) {
2245 if (v == &vlineno && v->var_text == linenovar) {
2246 fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
2247 }
2222 return var_end(v->var_text); 2248 return var_end(v->var_text);
2249 }
2223 } 2250 }
2224 return NULL; 2251 return NULL;
2225} 2252}
@@ -4823,7 +4850,7 @@ cmdtxt(union node *n)
4823 p = "; done"; 4850 p = "; done";
4824 goto dodo; 4851 goto dodo;
4825 case NDEFUN: 4852 case NDEFUN:
4826 cmdputs(n->narg.text); 4853 cmdputs(n->ndefun.text);
4827 p = "() { ... }"; 4854 p = "() { ... }";
4828 goto dotail2; 4855 goto dotail2;
4829 case NCMD: 4856 case NCMD:
@@ -8650,6 +8677,9 @@ calcsize(int funcblocksize, union node *n)
8650 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8677 funcblocksize = calcsize(funcblocksize, n->nclist.next);
8651 break; 8678 break;
8652 case NDEFUN: 8679 case NDEFUN:
8680 funcblocksize = calcsize(funcblocksize, n->ndefun.body);
8681 funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
8682 break;
8653 case NARG: 8683 case NARG:
8654 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8684 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
8655 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8685 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
@@ -8725,6 +8755,7 @@ copynode(union node *n)
8725 new->ncmd.redirect = copynode(n->ncmd.redirect); 8755 new->ncmd.redirect = copynode(n->ncmd.redirect);
8726 new->ncmd.args = copynode(n->ncmd.args); 8756 new->ncmd.args = copynode(n->ncmd.args);
8727 new->ncmd.assign = copynode(n->ncmd.assign); 8757 new->ncmd.assign = copynode(n->ncmd.assign);
8758 new->ncmd.linno = n->ncmd.linno;
8728 break; 8759 break;
8729 case NPIPE: 8760 case NPIPE:
8730 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8761 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
@@ -8735,6 +8766,7 @@ copynode(union node *n)
8735 case NSUBSHELL: 8766 case NSUBSHELL:
8736 new->nredir.redirect = copynode(n->nredir.redirect); 8767 new->nredir.redirect = copynode(n->nredir.redirect);
8737 new->nredir.n = copynode(n->nredir.n); 8768 new->nredir.n = copynode(n->nredir.n);
8769 new->nredir.linno = n->nredir.linno;
8738 break; 8770 break;
8739 case NAND: 8771 case NAND:
8740 case NOR: 8772 case NOR:
@@ -8753,10 +8785,12 @@ copynode(union node *n)
8753 new->nfor.var = nodeckstrdup(n->nfor.var); 8785 new->nfor.var = nodeckstrdup(n->nfor.var);
8754 new->nfor.body = copynode(n->nfor.body); 8786 new->nfor.body = copynode(n->nfor.body);
8755 new->nfor.args = copynode(n->nfor.args); 8787 new->nfor.args = copynode(n->nfor.args);
8788 new->nfor.linno = n->nfor.linno;
8756 break; 8789 break;
8757 case NCASE: 8790 case NCASE:
8758 new->ncase.cases = copynode(n->ncase.cases); 8791 new->ncase.cases = copynode(n->ncase.cases);
8759 new->ncase.expr = copynode(n->ncase.expr); 8792 new->ncase.expr = copynode(n->ncase.expr);
8793 new->ncase.linno = n->ncase.linno;
8760 break; 8794 break;
8761 case NCLIST: 8795 case NCLIST:
8762 new->nclist.body = copynode(n->nclist.body); 8796 new->nclist.body = copynode(n->nclist.body);
@@ -8764,6 +8798,10 @@ copynode(union node *n)
8764 new->nclist.next = copynode(n->nclist.next); 8798 new->nclist.next = copynode(n->nclist.next);
8765 break; 8799 break;
8766 case NDEFUN: 8800 case NDEFUN:
8801 new->ndefun.body = copynode(n->ndefun.body);
8802 new->ndefun.text = nodeckstrdup(n->ndefun.text);
8803 new->ndefun.linno = n->ndefun.linno;
8804 break;
8767 case NARG: 8805 case NARG:
8768 new->narg.backquote = copynodelist(n->narg.backquote); 8806 new->narg.backquote = copynodelist(n->narg.backquote);
8769 new->narg.text = nodeckstrdup(n->narg.text); 8807 new->narg.text = nodeckstrdup(n->narg.text);
@@ -8832,7 +8870,7 @@ defun(union node *func)
8832 INT_OFF; 8870 INT_OFF;
8833 entry.cmdtype = CMDFUNCTION; 8871 entry.cmdtype = CMDFUNCTION;
8834 entry.u.func = copyfunc(func); 8872 entry.u.func = copyfunc(func);
8835 addcmdentry(func->narg.text, &entry); 8873 addcmdentry(func->ndefun.text, &entry);
8836 INT_ON; 8874 INT_ON;
8837} 8875}
8838 8876
@@ -8842,8 +8880,8 @@ defun(union node *func)
8842#define SKIPFUNC (1 << 2) 8880#define SKIPFUNC (1 << 2)
8843static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ 8881static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
8844static int skipcount; /* number of levels to skip */ 8882static int skipcount; /* number of levels to skip */
8845static int funcnest; /* depth of function calls */
8846static int loopnest; /* current loop nesting level */ 8883static int loopnest; /* current loop nesting level */
8884static int funcline; /* starting line number of current function, or 0 if not in a function */
8847 8885
8848/* Forward decl way out to parsing code - dotrap needs it */ 8886/* Forward decl way out to parsing code - dotrap needs it */
8849static int evalstring(char *s, int flags); 8887static int evalstring(char *s, int flags);
@@ -8938,6 +8976,9 @@ evaltree(union node *n, int flags)
8938 status = !evaltree(n->nnot.com, EV_TESTED); 8976 status = !evaltree(n->nnot.com, EV_TESTED);
8939 goto setstatus; 8977 goto setstatus;
8940 case NREDIR: 8978 case NREDIR:
8979 errlinno = lineno = n->nredir.linno;
8980 if (funcline)
8981 lineno -= funcline - 1;
8941 expredir(n->nredir.redirect); 8982 expredir(n->nredir.redirect);
8942 pushredir(n->nredir.redirect); 8983 pushredir(n->nredir.redirect);
8943 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 8984 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
@@ -9092,6 +9133,10 @@ evalfor(union node *n, int flags)
9092 struct stackmark smark; 9133 struct stackmark smark;
9093 int status = 0; 9134 int status = 0;
9094 9135
9136 errlinno = lineno = n->ncase.linno;
9137 if (funcline)
9138 lineno -= funcline - 1;
9139
9095 setstackmark(&smark); 9140 setstackmark(&smark);
9096 arglist.list = NULL; 9141 arglist.list = NULL;
9097 arglist.lastp = &arglist.list; 9142 arglist.lastp = &arglist.list;
@@ -9123,6 +9168,10 @@ evalcase(union node *n, int flags)
9123 struct stackmark smark; 9168 struct stackmark smark;
9124 int status = 0; 9169 int status = 0;
9125 9170
9171 errlinno = lineno = n->ncase.linno;
9172 if (funcline)
9173 lineno -= funcline - 1;
9174
9126 setstackmark(&smark); 9175 setstackmark(&smark);
9127 arglist.list = NULL; 9176 arglist.list = NULL;
9128 arglist.lastp = &arglist.list; 9177 arglist.lastp = &arglist.list;
@@ -9157,6 +9206,10 @@ evalsubshell(union node *n, int flags)
9157 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 9206 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9158 int status; 9207 int status;
9159 9208
9209 errlinno = lineno = n->nredir.linno;
9210 if (funcline)
9211 lineno -= funcline - 1;
9212
9160 expredir(n->nredir.redirect); 9213 expredir(n->nredir.redirect);
9161 if (!backgnd && (flags & EV_EXIT) && !may_have_traps) 9214 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
9162 goto nofork; 9215 goto nofork;
@@ -9464,8 +9517,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9464 struct jmploc *volatile savehandler; 9517 struct jmploc *volatile savehandler;
9465 struct jmploc jmploc; 9518 struct jmploc jmploc;
9466 int e; 9519 int e;
9520 int savefuncline;
9467 9521
9468 saveparam = shellparam; 9522 saveparam = shellparam;
9523 savefuncline = funcline;
9469 savehandler = exception_handler; 9524 savehandler = exception_handler;
9470 e = setjmp(jmploc.loc); 9525 e = setjmp(jmploc.loc);
9471 if (e) { 9526 if (e) {
@@ -9475,7 +9530,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9475 exception_handler = &jmploc; 9530 exception_handler = &jmploc;
9476 shellparam.malloced = 0; 9531 shellparam.malloced = 0;
9477 func->count++; 9532 func->count++;
9478 funcnest++; 9533 funcline = func->n.ndefun.linno;
9479 INT_ON; 9534 INT_ON;
9480 shellparam.nparam = argc - 1; 9535 shellparam.nparam = argc - 1;
9481 shellparam.p = argv + 1; 9536 shellparam.p = argv + 1;
@@ -9484,11 +9539,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
9484 shellparam.optoff = -1; 9539 shellparam.optoff = -1;
9485#endif 9540#endif
9486 pushlocalvars(); 9541 pushlocalvars();
9487 evaltree(func->n.narg.next, flags & EV_TESTED); 9542 evaltree(func->n.ndefun.body, flags & EV_TESTED);
9488 poplocalvars(0); 9543 poplocalvars(0);
9489 funcdone: 9544 funcdone:
9490 INT_OFF; 9545 INT_OFF;
9491 funcnest--; 9546 funcline = savefuncline;
9492 freefunc(func); 9547 freefunc(func);
9493 freeparam(&shellparam); 9548 freeparam(&shellparam);
9494 shellparam = saveparam; 9549 shellparam = saveparam;
@@ -9852,6 +9907,10 @@ evalcommand(union node *cmd, int flags)
9852 char **nargv; 9907 char **nargv;
9853 smallint cmd_is_exec; 9908 smallint cmd_is_exec;
9854 9909
9910 errlinno = lineno = cmd->ncmd.linno;
9911 if (funcline)
9912 lineno -= funcline - 1;
9913
9855 /* First expand the arguments. */ 9914 /* First expand the arguments. */
9856 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 9915 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9857 setstackmark(&smark); 9916 setstackmark(&smark);
@@ -9897,7 +9956,7 @@ evalcommand(union node *cmd, int flags)
9897 *nargv = NULL; 9956 *nargv = NULL;
9898 9957
9899 lastarg = NULL; 9958 lastarg = NULL;
9900 if (iflag && funcnest == 0 && argc > 0) 9959 if (iflag && funcline == 0 && argc > 0)
9901 lastarg = nargv[-1]; 9960 lastarg = nargv[-1];
9902 9961
9903 expredir(cmd->ncmd.redirect); 9962 expredir(cmd->ncmd.redirect);
@@ -11430,6 +11489,7 @@ simplecmd(void)
11430 union node *vars, **vpp; 11489 union node *vars, **vpp;
11431 union node **rpp, *redir; 11490 union node **rpp, *redir;
11432 int savecheckkwd; 11491 int savecheckkwd;
11492 int savelinno;
11433#if BASH_TEST2 11493#if BASH_TEST2
11434 smallint double_brackets_flag = 0; 11494 smallint double_brackets_flag = 0;
11435#endif 11495#endif
@@ -11443,6 +11503,7 @@ simplecmd(void)
11443 rpp = &redir; 11503 rpp = &redir;
11444 11504
11445 savecheckkwd = CHKALIAS; 11505 savecheckkwd = CHKALIAS;
11506 savelinno = g_parsefile->linno;
11446 for (;;) { 11507 for (;;) {
11447 int t; 11508 int t;
11448 checkkwd = savecheckkwd; 11509 checkkwd = savecheckkwd;
@@ -11532,7 +11593,9 @@ simplecmd(void)
11532 } 11593 }
11533 n->type = NDEFUN; 11594 n->type = NDEFUN;
11534 checkkwd = CHKNL | CHKKWD | CHKALIAS; 11595 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11535 n->narg.next = parse_command(); 11596 n->ndefun.text = n->narg.text;
11597 n->ndefun.linno = g_parsefile->linno;
11598 n->ndefun.body = parse_command();
11536 return n; 11599 return n;
11537 } 11600 }
11538 IF_BASH_FUNCTION(function_flag = 0;) 11601 IF_BASH_FUNCTION(function_flag = 0;)
@@ -11548,6 +11611,7 @@ simplecmd(void)
11548 *rpp = NULL; 11611 *rpp = NULL;
11549 n = stzalloc(sizeof(struct ncmd)); 11612 n = stzalloc(sizeof(struct ncmd));
11550 n->type = NCMD; 11613 n->type = NCMD;
11614 n->ncmd.linno = savelinno;
11551 n->ncmd.args = args; 11615 n->ncmd.args = args;
11552 n->ncmd.assign = vars; 11616 n->ncmd.assign = vars;
11553 n->ncmd.redirect = redir; 11617 n->ncmd.redirect = redir;
@@ -11563,10 +11627,13 @@ parse_command(void)
11563 union node *redir, **rpp; 11627 union node *redir, **rpp;
11564 union node **rpp2; 11628 union node **rpp2;
11565 int t; 11629 int t;
11630 int savelinno;
11566 11631
11567 redir = NULL; 11632 redir = NULL;
11568 rpp2 = &redir; 11633 rpp2 = &redir;
11569 11634
11635 savelinno = g_parsefile->linno;
11636
11570 switch (readtoken()) { 11637 switch (readtoken()) {
11571 default: 11638 default:
11572 raise_error_unexpected_syntax(-1); 11639 raise_error_unexpected_syntax(-1);
@@ -11617,6 +11684,7 @@ parse_command(void)
11617 raise_error_syntax("bad for loop variable"); 11684 raise_error_syntax("bad for loop variable");
11618 n1 = stzalloc(sizeof(struct nfor)); 11685 n1 = stzalloc(sizeof(struct nfor));
11619 n1->type = NFOR; 11686 n1->type = NFOR;
11687 n1->nfor.linno = savelinno;
11620 n1->nfor.var = wordtext; 11688 n1->nfor.var = wordtext;
11621 checkkwd = CHKNL | CHKKWD | CHKALIAS; 11689 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11622 if (readtoken() == TIN) { 11690 if (readtoken() == TIN) {
@@ -11657,6 +11725,7 @@ parse_command(void)
11657 case TCASE: 11725 case TCASE:
11658 n1 = stzalloc(sizeof(struct ncase)); 11726 n1 = stzalloc(sizeof(struct ncase));
11659 n1->type = NCASE; 11727 n1->type = NCASE;
11728 n1->ncase.linno = savelinno;
11660 if (readtoken() != TWORD) 11729 if (readtoken() != TWORD)
11661 raise_error_unexpected_syntax(TWORD); 11730 raise_error_unexpected_syntax(TWORD);
11662 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); 11731 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
@@ -11708,6 +11777,7 @@ parse_command(void)
11708 case TLP: 11777 case TLP:
11709 n1 = stzalloc(sizeof(struct nredir)); 11778 n1 = stzalloc(sizeof(struct nredir));
11710 n1->type = NSUBSHELL; 11779 n1->type = NSUBSHELL;
11780 n1->nredir.linno = savelinno;
11711 n1->nredir.n = list(0); 11781 n1->nredir.n = list(0);
11712 /*n1->nredir.redirect = NULL; - stzalloc did it */ 11782 /*n1->nredir.redirect = NULL; - stzalloc did it */
11713 t = TRP; 11783 t = TRP;
@@ -11741,6 +11811,7 @@ parse_command(void)
11741 if (n1->type != NSUBSHELL) { 11811 if (n1->type != NSUBSHELL) {
11742 n2 = stzalloc(sizeof(struct nredir)); 11812 n2 = stzalloc(sizeof(struct nredir));
11743 n2->type = NREDIR; 11813 n2->type = NREDIR;
11814 n2->nredir.linno = savelinno;
11744 n2->nredir.n = n1; 11815 n2->nredir.n = n1;
11745 n1 = n2; 11816 n1 = n2;
11746 } 11817 }
@@ -11839,10 +11910,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11839 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ 11910 IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
11840 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ 11911 IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
11841 int dqvarnest; /* levels of variables expansion within double quotes */ 11912 int dqvarnest; /* levels of variables expansion within double quotes */
11842
11843 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) 11913 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
11844 11914
11845 startlinno = g_parsefile->linno;
11846 bqlist = NULL; 11915 bqlist = NULL;
11847 quotef = 0; 11916 quotef = 0;
11848 IF_FEATURE_SH_MATH(prevsyntax = 0;) 11917 IF_FEATURE_SH_MATH(prevsyntax = 0;)
@@ -12019,7 +12088,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12019 if (syntax != BASESYNTAX && eofmark == NULL) 12088 if (syntax != BASESYNTAX && eofmark == NULL)
12020 raise_error_syntax("unterminated quoted string"); 12089 raise_error_syntax("unterminated quoted string");
12021 if (varnest != 0) { 12090 if (varnest != 0) {
12022 startlinno = g_parsefile->linno;
12023 /* { */ 12091 /* { */
12024 raise_error_syntax("missing '}'"); 12092 raise_error_syntax("missing '}'");
12025 } 12093 }
@@ -12411,7 +12479,6 @@ parsebackq: {
12411 12479
12412 case PEOF: 12480 case PEOF:
12413 IF_ASH_ALIAS(case PEOA:) 12481 IF_ASH_ALIAS(case PEOA:)
12414 startlinno = g_parsefile->linno;
12415 raise_error_syntax("EOF in backquote substitution"); 12482 raise_error_syntax("EOF in backquote substitution");
12416 12483
12417 case '\n': 12484 case '\n':
@@ -12493,8 +12560,6 @@ parsearith: {
12493 * quoted. 12560 * quoted.
12494 * If the token is TREDIR, then we set redirnode to a structure containing 12561 * If the token is TREDIR, then we set redirnode to a structure containing
12495 * the redirection. 12562 * the redirection.
12496 * In all cases, the variable startlinno is set to the number of the line
12497 * on which the token starts.
12498 * 12563 *
12499 * [Change comment: here documents and internal procedures] 12564 * [Change comment: here documents and internal procedures]
12500 * [Readtoken shouldn't have any arguments. Perhaps we should make the 12565 * [Readtoken shouldn't have any arguments. Perhaps we should make the
@@ -12532,7 +12597,6 @@ xxreadtoken(void)
12532 return lasttoken; 12597 return lasttoken;
12533 } 12598 }
12534 setprompt_if(needprompt, 2); 12599 setprompt_if(needprompt, 2);
12535 startlinno = g_parsefile->linno;
12536 for (;;) { /* until token or start of word found */ 12600 for (;;) { /* until token or start of word found */
12537 c = pgetc(); 12601 c = pgetc();
12538 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) 12602 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
@@ -12593,7 +12657,6 @@ xxreadtoken(void)
12593 return lasttoken; 12657 return lasttoken;
12594 } 12658 }
12595 setprompt_if(needprompt, 2); 12659 setprompt_if(needprompt, 2);
12596 startlinno = g_parsefile->linno;
12597 for (;;) { /* until token or start of word found */ 12660 for (;;) { /* until token or start of word found */
12598 c = pgetc(); 12661 c = pgetc();
12599 switch (c) { 12662 switch (c) {
diff --git a/shell/ash_LINENO.patch b/shell/ash_LINENO.patch
deleted file mode 100644
index a71549d6a..000000000
--- a/shell/ash_LINENO.patch
+++ /dev/null
@@ -1,498 +0,0 @@
1This 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
6Applies cleanly on top of:
7 commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe
8 Date: Tue Aug 15 15:44:41 2017 +0200
9
10Testsuite needs some tweaks (line numbers in some messages change).
11
12Unfortunately, it is somewhat big:
13
14function old new delta
15parse_command 1581 1658 +77
16calcsize 203 272 +69
17copynode 195 257 +62
18lookupvar 59 108 +49
19evaltree 494 534 +40
20evalfor 152 187 +35
21evalcase 278 313 +35
22evalcommand 1547 1581 +34
23evalsubshell 169 199 +30
24linenovar - 22 +22
25raise_error_syntax 11 29 +18
26evalfun 266 280 +14
27varinit_data 96 108 +12
28cmdtxt 626 631 +5
29lineno - 4 +4
30funcline - 4 +4
31ash_vmsg 144 141 -3
32startlinno 4 - -4
33funcnest 4 - -4
34xxreadtoken 272 259 -13
35readtoken1 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
41
42diff --git a/shell/ash.c b/shell/ash.c
43index 703802f..93a3814 100644
44--- a/shell/ash.c
45+++ b/shell/ash.c
46@@ -312,6 +312,8 @@ struct globals_misc {
47 /* shell level: 0 for the main shell, 1 for its children, and so on */
48 int shlvl;
49 #define rootshell (!shlvl)
50+ int errlinno;
51+
52 char *minusc; /* argument to -c option */
53
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;
64
65 struct ncmd {
66 smallint type; /* Nxxxx */
67+ int linno;
68 union node *assign;
69 union node *args;
70 union node *redirect;
71@@ -736,6 +740,7 @@ struct npipe {
72
73 struct nredir {
74 smallint type;
75+ int linno;
76 union node *n;
77 union node *redirect;
78 };
79@@ -755,6 +760,7 @@ struct nif {
80
81 struct nfor {
82 smallint type;
83+ int linno;
84 union node *args;
85 union node *body;
86 char *var;
87@@ -762,6 +768,7 @@ struct nfor {
88
89 struct ncase {
90 smallint type;
91+ int linno;
92 union node *expr;
93 union node *cases;
94 };
95@@ -773,6 +780,13 @@ struct nclist {
96 union node *body;
97 };
98
99+struct ndefun {
100+ smallint type;
101+ int linno;
102+ char *text;
103+ union node *body;
104+};
105+
106 struct narg {
107 smallint type;
108 union node *next;
109@@ -824,6 +838,7 @@ union node {
110 struct nfor nfor;
111 struct ncase ncase;
112 struct nclist nclist;
113+ struct ndefun ndefun;
114 struct narg narg;
115 struct nfile nfile;
116 struct ndup ndup;
117@@ -1253,7 +1268,6 @@ struct parsefile {
118
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 */
123
124
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);
131 }
132 vfprintf(stderr, msg, ap);
133 newline_and_flush(stderr);
134@@ -1327,6 +1341,7 @@ static void raise_error_syntax(const char *) NORETURN;
135 static void
136 raise_error_syntax(const char *msg)
137 {
138+ errlinno = g_parsefile->linno;
139 ash_msg_and_raise_error("syntax error: %s", msg);
140 /* NOTREACHED */
141 }
142@@ -1993,6 +2008,9 @@ static void changepath(const char *) FAST_FUNC;
143 static void change_random(const char *) FAST_FUNC;
144 #endif
145
146+static int lineno;
147+static char linenovar[sizeof("LINENO=%d") + sizeof(int)*3] = "LINENO=";
148+
149 static const struct {
150 int flags;
151 const char *var_text;
152@@ -2014,6 +2032,7 @@ static const struct {
153 #if ENABLE_ASH_GETOPTS
154 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
155 #endif
156+ { VSTRFIXED|VTEXTFIXED , linenovar , NULL },
157 #if ENABLE_ASH_RANDOM_SUPPORT
158 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
159 #endif
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]
168 # endif
169 #else
170+# define vlineno (&vps4)[1]
171 # if ENABLE_ASH_RANDOM_SUPPORT
172-# define vrandom (&vps4)[1]
173+# define vrandom (&vlineno)[1]
174 # endif
175 #endif
176
177@@ -2209,8 +2230,12 @@ lookupvar(const char *name)
178 if (v->flags & VDYNAMIC)
179 v->var_func(NULL);
180 #endif
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);
185+ }
186 return var_end(v->var_text);
187+ }
188 }
189 return NULL;
190 }
191@@ -4783,7 +4808,7 @@ cmdtxt(union node *n)
192 p = "; done";
193 goto dodo;
194 case NDEFUN:
195- cmdputs(n->narg.text);
196+ cmdputs(n->ndefun.text);
197 p = "() { ... }";
198 goto dotail2;
199 case NCMD:
200@@ -8551,6 +8576,9 @@ calcsize(int funcblocksize, union node *n)
201 funcblocksize = calcsize(funcblocksize, n->nclist.next);
202 break;
203 case NDEFUN:
204+ funcblocksize = calcsize(funcblocksize, n->ndefun.body);
205+ funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
206+ break;
207 case NARG:
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;
215 break;
216 case NPIPE:
217 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
218@@ -8636,6 +8665,7 @@ copynode(union node *n)
219 case NSUBSHELL:
220 new->nredir.redirect = copynode(n->nredir.redirect);
221 new->nredir.n = copynode(n->nredir.n);
222+ new->nredir.linno = n->nredir.linno;
223 break;
224 case NAND:
225 case NOR:
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;
231 break;
232 case NCASE:
233 new->ncase.cases = copynode(n->ncase.cases);
234 new->ncase.expr = copynode(n->ncase.expr);
235+ new->ncase.linno = n->ncase.linno;
236 break;
237 case NCLIST:
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);
241 break;
242 case NDEFUN:
243+ new->ndefun.body = copynode(n->ndefun.body);
244+ new->ndefun.text = nodeckstrdup(n->ndefun.text);
245+ new->ndefun.linno = n->ndefun.linno;
246+ break;
247 case NARG:
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)
251 INT_OFF;
252 entry.cmdtype = CMDFUNCTION;
253 entry.u.func = copyfunc(func);
254- addcmdentry(func->narg.text, &entry);
255+ addcmdentry(func->ndefun.text, &entry);
256 INT_ON;
257 }
258
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 */
266
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);
271 goto setstatus;
272 case NREDIR:
273+ errlinno = lineno = n->nredir.linno;
274+ if (funcline)
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;
281 int status = 0;
282
283+ errlinno = lineno = n->ncase.linno;
284+ if (funcline)
285+ lineno -= funcline - 1;
286+
287 setstackmark(&smark);
288 arglist.list = NULL;
289 arglist.lastp = &arglist.list;
290@@ -9024,6 +9067,10 @@ evalcase(union node *n, int flags)
291 struct stackmark smark;
292 int status = 0;
293
294+ errlinno = lineno = n->ncase.linno;
295+ if (funcline)
296+ lineno -= funcline - 1;
297+
298 setstackmark(&smark);
299 arglist.list = NULL;
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) */
303 int status;
304
305+ errlinno = lineno = n->nredir.linno;
306+ if (funcline)
307+ lineno -= funcline - 1;
308+
309 expredir(n->nredir.redirect);
310 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
311 goto nofork;
312@@ -9365,8 +9416,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
313 struct jmploc *volatile savehandler;
314 struct jmploc jmploc;
315 int e;
316+ int savefuncline;
317
318 saveparam = shellparam;
319+ savefuncline = funcline;
320 savehandler = exception_handler;
321 e = setjmp(jmploc.loc);
322 if (e) {
323@@ -9376,7 +9429,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
324 exception_handler = &jmploc;
325 shellparam.malloced = 0;
326 func->count++;
327- funcnest++;
328+ funcline = func->n.ndefun.linno;
329 INT_ON;
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;
334 #endif
335 pushlocalvars();
336- evaltree(func->n.narg.next, flags & EV_TESTED);
337+ evaltree(func->n.ndefun.body, flags & EV_TESTED);
338 poplocalvars(0);
339 funcdone:
340 INT_OFF;
341- funcnest--;
342+ funcline = savefuncline;
343 freefunc(func);
344 freeparam(&shellparam);
345 shellparam = saveparam;
346@@ -9753,6 +9806,10 @@ evalcommand(union node *cmd, int flags)
347 char **nargv;
348 smallint cmd_is_exec;
349
350+ errlinno = lineno = cmd->ncmd.linno;
351+ if (funcline)
352+ lineno -= funcline - 1;
353+
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)
358 *nargv = NULL;
359
360 lastarg = NULL;
361- if (iflag && funcnest == 0 && argc > 0)
362+ if (iflag && funcline == 0 && argc > 0)
363 lastarg = nargv[-1];
364
365 expredir(cmd->ncmd.redirect);
366@@ -11317,6 +11374,7 @@ simplecmd(void)
367 union node *vars, **vpp;
368 union node **rpp, *redir;
369 int savecheckkwd;
370+ int savelinno;
371 #if BASH_TEST2
372 smallint double_brackets_flag = 0;
373 #endif
374@@ -11330,6 +11388,7 @@ simplecmd(void)
375 rpp = &redir;
376
377 savecheckkwd = CHKALIAS;
378+ savelinno = g_parsefile->linno;
379 for (;;) {
380 int t;
381 checkkwd = savecheckkwd;
382@@ -11419,7 +11478,9 @@ simplecmd(void)
383 }
384 n->type = NDEFUN;
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();
390 return n;
391 }
392 IF_BASH_FUNCTION(function_flag = 0;)
393@@ -11435,6 +11496,7 @@ simplecmd(void)
394 *rpp = NULL;
395 n = stzalloc(sizeof(struct ncmd));
396 n->type = NCMD;
397+ n->ncmd.linno = savelinno;
398 n->ncmd.args = args;
399 n->ncmd.assign = vars;
400 n->ncmd.redirect = redir;
401@@ -11450,10 +11512,13 @@ parse_command(void)
402 union node *redir, **rpp;
403 union node **rpp2;
404 int t;
405+ int savelinno;
406
407 redir = NULL;
408 rpp2 = &redir;
409
410+ savelinno = g_parsefile->linno;
411+
412 switch (readtoken()) {
413 default:
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));
418 n1->type = 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)
424 case TCASE:
425 n1 = stzalloc(sizeof(struct ncase));
426 n1->type = 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)
432 case TLP:
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 */
438 t = TRP;
439@@ -11628,6 +11696,7 @@ parse_command(void)
440 if (n1->type != NSUBSHELL) {
441 n2 = stzalloc(sizeof(struct nredir));
442 n2->type = NREDIR;
443+ n2->nredir.linno = savelinno;
444 n2->nredir.n = n1;
445 n1 = n2;
446 }
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 */
451-
452 IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
453
454- startlinno = g_parsefile->linno;
455 bqlist = NULL;
456 quotef = 0;
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");
461 if (varnest != 0) {
462- startlinno = g_parsefile->linno;
463 /* { */
464 raise_error_syntax("missing '}'");
465 }
466@@ -12298,7 +12364,6 @@ parsebackq: {
467
468 case PEOF:
469 IF_ASH_ALIAS(case PEOA:)
470- startlinno = g_parsefile->linno;
471 raise_error_syntax("EOF in backquote substitution");
472
473 case '\n':
474@@ -12380,8 +12445,6 @@ parsearith: {
475 * quoted.
476 * If the token is TREDIR, then we set redirnode to a structure containing
477 * the redirection.
478- * In all cases, the variable startlinno is set to the number of the line
479- * on which the token starts.
480 *
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)
484 return lasttoken;
485 }
486 setprompt_if(needprompt, 2);
487- startlinno = g_parsefile->linno;
488 for (;;) { /* until token or start of word found */
489 c = pgetc();
490 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
491@@ -12480,7 +12542,6 @@ xxreadtoken(void)
492 return lasttoken;
493 }
494 setprompt_if(needprompt, 2);
495- startlinno = g_parsefile->linno;
496 for (;;) { /* until token or start of word found */
497 c = pgetc();
498 switch (c) {
diff --git a/shell/ash_test/ash-psubst/emptytick.right b/shell/ash_test/ash-psubst/emptytick.right
index 7629deba6..459c4f735 100644
--- a/shell/ash_test/ash-psubst/emptytick.right
+++ b/shell/ash_test/ash-psubst/emptytick.right
@@ -1,8 +1,8 @@
10 10
20 20
3./emptytick.tests: line 3: : Permission denied 3./emptytick.tests: line 1: : Permission denied
4127 4127
5./emptytick.tests: line 4: : Permission denied 5./emptytick.tests: line 1: : Permission denied
6127 6127
70 70
80 80
diff --git a/shell/ash_test/ash-quoting/mode_x.right b/shell/ash_test/ash-quoting/mode_x.right
index c2dd3550c..d1f670af6 100644
--- a/shell/ash_test/ash-quoting/mode_x.right
+++ b/shell/ash_test/ash-quoting/mode_x.right
@@ -3,8 +3,8 @@
3+ true '%s\n' one 'two '"'"'three' four 3+ true '%s\n' one 'two '"'"'three' four
4+ this=command 4+ this=command
5+ 'this=command' 5+ 'this=command'
6./mode_x.tests: line 1: this=command: not found 6./mode_x.tests: line 10: this=command: not found
7+ true 7+ true
8+ true 8+ true
9+ 'if' true 9+ 'if' true
10./mode_x.tests: line 1: if: not found 10./mode_x.tests: line 14: if: not found