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>
This commit is contained in:
parent
54c2111781
commit
675d24aeaf
127
shell/ash.c
127
shell/ash.c
@ -328,6 +328,8 @@ struct globals_misc {
|
|||||||
/* shell level: 0 for the main shell, 1 for its children, and so on */
|
/* shell level: 0 for the main shell, 1 for its children, and so on */
|
||||||
int shlvl;
|
int shlvl;
|
||||||
#define rootshell (!shlvl)
|
#define rootshell (!shlvl)
|
||||||
|
int errlinno;
|
||||||
|
|
||||||
char *minusc; /* argument to -c option */
|
char *minusc; /* argument to -c option */
|
||||||
|
|
||||||
char *curdir; // = nullstr; /* current working directory */
|
char *curdir; // = nullstr; /* current working directory */
|
||||||
@ -405,6 +407,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
|
|||||||
#define job_warning (G_misc.job_warning)
|
#define job_warning (G_misc.job_warning)
|
||||||
#define rootpid (G_misc.rootpid )
|
#define rootpid (G_misc.rootpid )
|
||||||
#define shlvl (G_misc.shlvl )
|
#define shlvl (G_misc.shlvl )
|
||||||
|
#define errlinno (G_misc.errlinno )
|
||||||
#define minusc (G_misc.minusc )
|
#define minusc (G_misc.minusc )
|
||||||
#define curdir (G_misc.curdir )
|
#define curdir (G_misc.curdir )
|
||||||
#define physdir (G_misc.physdir )
|
#define physdir (G_misc.physdir )
|
||||||
@ -739,6 +742,7 @@ union node;
|
|||||||
|
|
||||||
struct ncmd {
|
struct ncmd {
|
||||||
smallint type; /* Nxxxx */
|
smallint type; /* Nxxxx */
|
||||||
|
int linno;
|
||||||
union node *assign;
|
union node *assign;
|
||||||
union node *args;
|
union node *args;
|
||||||
union node *redirect;
|
union node *redirect;
|
||||||
@ -752,6 +756,7 @@ struct npipe {
|
|||||||
|
|
||||||
struct nredir {
|
struct nredir {
|
||||||
smallint type;
|
smallint type;
|
||||||
|
int linno;
|
||||||
union node *n;
|
union node *n;
|
||||||
union node *redirect;
|
union node *redirect;
|
||||||
};
|
};
|
||||||
@ -771,6 +776,7 @@ struct nif {
|
|||||||
|
|
||||||
struct nfor {
|
struct nfor {
|
||||||
smallint type;
|
smallint type;
|
||||||
|
int linno;
|
||||||
union node *args;
|
union node *args;
|
||||||
union node *body;
|
union node *body;
|
||||||
char *var;
|
char *var;
|
||||||
@ -778,6 +784,7 @@ struct nfor {
|
|||||||
|
|
||||||
struct ncase {
|
struct ncase {
|
||||||
smallint type;
|
smallint type;
|
||||||
|
int linno;
|
||||||
union node *expr;
|
union node *expr;
|
||||||
union node *cases;
|
union node *cases;
|
||||||
};
|
};
|
||||||
@ -789,6 +796,13 @@ struct nclist {
|
|||||||
union node *body;
|
union node *body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ndefun {
|
||||||
|
smallint type;
|
||||||
|
int linno;
|
||||||
|
char *text;
|
||||||
|
union node *body;
|
||||||
|
};
|
||||||
|
|
||||||
struct narg {
|
struct narg {
|
||||||
smallint type;
|
smallint type;
|
||||||
union node *next;
|
union node *next;
|
||||||
@ -840,6 +854,7 @@ union node {
|
|||||||
struct nfor nfor;
|
struct nfor nfor;
|
||||||
struct ncase ncase;
|
struct ncase ncase;
|
||||||
struct nclist nclist;
|
struct nclist nclist;
|
||||||
|
struct ndefun ndefun;
|
||||||
struct narg narg;
|
struct narg narg;
|
||||||
struct nfile nfile;
|
struct nfile nfile;
|
||||||
struct ndup ndup;
|
struct ndup ndup;
|
||||||
@ -1269,7 +1284,6 @@ struct parsefile {
|
|||||||
|
|
||||||
static struct parsefile basepf; /* top level input file */
|
static struct parsefile basepf; /* top level input file */
|
||||||
static struct parsefile *g_parsefile = &basepf; /* current 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 */
|
static char *commandname; /* currently executing command */
|
||||||
|
|
||||||
|
|
||||||
@ -1283,7 +1297,7 @@ ash_vmsg(const char *msg, va_list ap)
|
|||||||
if (strcmp(arg0, commandname))
|
if (strcmp(arg0, commandname))
|
||||||
fprintf(stderr, "%s: ", commandname);
|
fprintf(stderr, "%s: ", commandname);
|
||||||
if (!iflag || g_parsefile->pf_fd > 0)
|
if (!iflag || g_parsefile->pf_fd > 0)
|
||||||
fprintf(stderr, "line %d: ", startlinno);
|
fprintf(stderr, "line %d: ", errlinno);
|
||||||
}
|
}
|
||||||
vfprintf(stderr, msg, ap);
|
vfprintf(stderr, msg, ap);
|
||||||
newline_and_flush(stderr);
|
newline_and_flush(stderr);
|
||||||
@ -1336,6 +1350,7 @@ static void raise_error_syntax(const char *) NORETURN;
|
|||||||
static void
|
static void
|
||||||
raise_error_syntax(const char *msg)
|
raise_error_syntax(const char *msg)
|
||||||
{
|
{
|
||||||
|
errlinno = g_parsefile->linno;
|
||||||
ash_msg_and_raise_error("syntax error: %s", msg);
|
ash_msg_and_raise_error("syntax error: %s", msg);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
@ -2023,6 +2038,7 @@ static const struct {
|
|||||||
#if ENABLE_ASH_GETOPTS
|
#if ENABLE_ASH_GETOPTS
|
||||||
{ VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
|
{ VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
|
||||||
#endif
|
#endif
|
||||||
|
{ VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
|
||||||
#if ENABLE_ASH_RANDOM_SUPPORT
|
#if ENABLE_ASH_RANDOM_SUPPORT
|
||||||
{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
|
{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
|
||||||
#endif
|
#endif
|
||||||
@ -2043,6 +2059,8 @@ struct globals_var {
|
|||||||
int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
|
int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */
|
||||||
struct var *vartab[VTABSIZE];
|
struct var *vartab[VTABSIZE];
|
||||||
struct var varinit[ARRAY_SIZE(varinit_data)];
|
struct var varinit[ARRAY_SIZE(varinit_data)];
|
||||||
|
int lineno;
|
||||||
|
char linenovar[sizeof("LINENO=") + sizeof(int)*3];
|
||||||
};
|
};
|
||||||
extern struct globals_var *const ash_ptr_to_globals_var;
|
extern struct globals_var *const ash_ptr_to_globals_var;
|
||||||
#define G_var (*ash_ptr_to_globals_var)
|
#define G_var (*ash_ptr_to_globals_var)
|
||||||
@ -2051,17 +2069,8 @@ extern struct globals_var *const ash_ptr_to_globals_var;
|
|||||||
#define preverrout_fd (G_var.preverrout_fd)
|
#define preverrout_fd (G_var.preverrout_fd)
|
||||||
#define vartab (G_var.vartab )
|
#define vartab (G_var.vartab )
|
||||||
#define varinit (G_var.varinit )
|
#define varinit (G_var.varinit )
|
||||||
#define INIT_G_var() do { \
|
#define lineno (G_var.lineno )
|
||||||
unsigned i; \
|
#define linenovar (G_var.linenovar )
|
||||||
(*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
|
|
||||||
barrier(); \
|
|
||||||
for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
|
|
||||||
varinit[i].flags = varinit_data[i].flags; \
|
|
||||||
varinit[i].var_text = varinit_data[i].var_text; \
|
|
||||||
varinit[i].var_func = varinit_data[i].var_func; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define vifs varinit[0]
|
#define vifs varinit[0]
|
||||||
#if ENABLE_ASH_MAIL
|
#if ENABLE_ASH_MAIL
|
||||||
# define vmail (&vifs)[1]
|
# define vmail (&vifs)[1]
|
||||||
@ -2075,14 +2084,28 @@ extern struct globals_var *const ash_ptr_to_globals_var;
|
|||||||
#define vps4 (&vps2)[1]
|
#define vps4 (&vps2)[1]
|
||||||
#if ENABLE_ASH_GETOPTS
|
#if ENABLE_ASH_GETOPTS
|
||||||
# define voptind (&vps4)[1]
|
# define voptind (&vps4)[1]
|
||||||
|
# define vlineno (&voptind)[1]
|
||||||
# if ENABLE_ASH_RANDOM_SUPPORT
|
# if ENABLE_ASH_RANDOM_SUPPORT
|
||||||
# define vrandom (&voptind)[1]
|
# define vrandom (&vlineno)[1]
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
|
# define vlineno (&vps4)[1]
|
||||||
# if ENABLE_ASH_RANDOM_SUPPORT
|
# if ENABLE_ASH_RANDOM_SUPPORT
|
||||||
# define vrandom (&vps4)[1]
|
# define vrandom (&vlineno)[1]
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
#define INIT_G_var() do { \
|
||||||
|
unsigned i; \
|
||||||
|
(*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
|
||||||
|
barrier(); \
|
||||||
|
for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
|
||||||
|
varinit[i].flags = varinit_data[i].flags; \
|
||||||
|
varinit[i].var_text = varinit_data[i].var_text; \
|
||||||
|
varinit[i].var_func = varinit_data[i].var_func; \
|
||||||
|
} \
|
||||||
|
strcpy(linenovar, "LINENO="); \
|
||||||
|
vlineno.var_text = linenovar; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following macros access the values of the above variables.
|
* The following macros access the values of the above variables.
|
||||||
@ -2218,9 +2241,13 @@ lookupvar(const char *name)
|
|||||||
if (v->flags & VDYNAMIC)
|
if (v->flags & VDYNAMIC)
|
||||||
v->var_func(NULL);
|
v->var_func(NULL);
|
||||||
#endif
|
#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 var_end(v->var_text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4823,7 +4850,7 @@ cmdtxt(union node *n)
|
|||||||
p = "; done";
|
p = "; done";
|
||||||
goto dodo;
|
goto dodo;
|
||||||
case NDEFUN:
|
case NDEFUN:
|
||||||
cmdputs(n->narg.text);
|
cmdputs(n->ndefun.text);
|
||||||
p = "() { ... }";
|
p = "() { ... }";
|
||||||
goto dotail2;
|
goto dotail2;
|
||||||
case NCMD:
|
case NCMD:
|
||||||
@ -8650,6 +8677,9 @@ calcsize(int funcblocksize, union node *n)
|
|||||||
funcblocksize = calcsize(funcblocksize, n->nclist.next);
|
funcblocksize = calcsize(funcblocksize, n->nclist.next);
|
||||||
break;
|
break;
|
||||||
case NDEFUN:
|
case NDEFUN:
|
||||||
|
funcblocksize = calcsize(funcblocksize, n->ndefun.body);
|
||||||
|
funcblocksize += SHELL_ALIGN(strlen(n->ndefun.text) + 1);
|
||||||
|
break;
|
||||||
case NARG:
|
case NARG:
|
||||||
funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
|
funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
|
||||||
funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
|
funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
|
||||||
@ -8725,6 +8755,7 @@ copynode(union node *n)
|
|||||||
new->ncmd.redirect = copynode(n->ncmd.redirect);
|
new->ncmd.redirect = copynode(n->ncmd.redirect);
|
||||||
new->ncmd.args = copynode(n->ncmd.args);
|
new->ncmd.args = copynode(n->ncmd.args);
|
||||||
new->ncmd.assign = copynode(n->ncmd.assign);
|
new->ncmd.assign = copynode(n->ncmd.assign);
|
||||||
|
new->ncmd.linno = n->ncmd.linno;
|
||||||
break;
|
break;
|
||||||
case NPIPE:
|
case NPIPE:
|
||||||
new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
|
new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
|
||||||
@ -8735,6 +8766,7 @@ copynode(union node *n)
|
|||||||
case NSUBSHELL:
|
case NSUBSHELL:
|
||||||
new->nredir.redirect = copynode(n->nredir.redirect);
|
new->nredir.redirect = copynode(n->nredir.redirect);
|
||||||
new->nredir.n = copynode(n->nredir.n);
|
new->nredir.n = copynode(n->nredir.n);
|
||||||
|
new->nredir.linno = n->nredir.linno;
|
||||||
break;
|
break;
|
||||||
case NAND:
|
case NAND:
|
||||||
case NOR:
|
case NOR:
|
||||||
@ -8753,10 +8785,12 @@ copynode(union node *n)
|
|||||||
new->nfor.var = nodeckstrdup(n->nfor.var);
|
new->nfor.var = nodeckstrdup(n->nfor.var);
|
||||||
new->nfor.body = copynode(n->nfor.body);
|
new->nfor.body = copynode(n->nfor.body);
|
||||||
new->nfor.args = copynode(n->nfor.args);
|
new->nfor.args = copynode(n->nfor.args);
|
||||||
|
new->nfor.linno = n->nfor.linno;
|
||||||
break;
|
break;
|
||||||
case NCASE:
|
case NCASE:
|
||||||
new->ncase.cases = copynode(n->ncase.cases);
|
new->ncase.cases = copynode(n->ncase.cases);
|
||||||
new->ncase.expr = copynode(n->ncase.expr);
|
new->ncase.expr = copynode(n->ncase.expr);
|
||||||
|
new->ncase.linno = n->ncase.linno;
|
||||||
break;
|
break;
|
||||||
case NCLIST:
|
case NCLIST:
|
||||||
new->nclist.body = copynode(n->nclist.body);
|
new->nclist.body = copynode(n->nclist.body);
|
||||||
@ -8764,6 +8798,10 @@ copynode(union node *n)
|
|||||||
new->nclist.next = copynode(n->nclist.next);
|
new->nclist.next = copynode(n->nclist.next);
|
||||||
break;
|
break;
|
||||||
case NDEFUN:
|
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:
|
case NARG:
|
||||||
new->narg.backquote = copynodelist(n->narg.backquote);
|
new->narg.backquote = copynodelist(n->narg.backquote);
|
||||||
new->narg.text = nodeckstrdup(n->narg.text);
|
new->narg.text = nodeckstrdup(n->narg.text);
|
||||||
@ -8832,7 +8870,7 @@ defun(union node *func)
|
|||||||
INT_OFF;
|
INT_OFF;
|
||||||
entry.cmdtype = CMDFUNCTION;
|
entry.cmdtype = CMDFUNCTION;
|
||||||
entry.u.func = copyfunc(func);
|
entry.u.func = copyfunc(func);
|
||||||
addcmdentry(func->narg.text, &entry);
|
addcmdentry(func->ndefun.text, &entry);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8842,8 +8880,8 @@ defun(union node *func)
|
|||||||
#define SKIPFUNC (1 << 2)
|
#define SKIPFUNC (1 << 2)
|
||||||
static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
|
static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
|
||||||
static int skipcount; /* number of levels to skip */
|
static int skipcount; /* number of levels to skip */
|
||||||
static int funcnest; /* depth of function calls */
|
|
||||||
static int loopnest; /* current loop nesting level */
|
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 */
|
/* Forward decl way out to parsing code - dotrap needs it */
|
||||||
static int evalstring(char *s, int flags);
|
static int evalstring(char *s, int flags);
|
||||||
@ -8938,6 +8976,9 @@ evaltree(union node *n, int flags)
|
|||||||
status = !evaltree(n->nnot.com, EV_TESTED);
|
status = !evaltree(n->nnot.com, EV_TESTED);
|
||||||
goto setstatus;
|
goto setstatus;
|
||||||
case NREDIR:
|
case NREDIR:
|
||||||
|
errlinno = lineno = n->nredir.linno;
|
||||||
|
if (funcline)
|
||||||
|
lineno -= funcline - 1;
|
||||||
expredir(n->nredir.redirect);
|
expredir(n->nredir.redirect);
|
||||||
pushredir(n->nredir.redirect);
|
pushredir(n->nredir.redirect);
|
||||||
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
|
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
|
||||||
@ -9092,6 +9133,10 @@ evalfor(union node *n, int flags)
|
|||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
|
errlinno = lineno = n->ncase.linno;
|
||||||
|
if (funcline)
|
||||||
|
lineno -= funcline - 1;
|
||||||
|
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
arglist.list = NULL;
|
arglist.list = NULL;
|
||||||
arglist.lastp = &arglist.list;
|
arglist.lastp = &arglist.list;
|
||||||
@ -9123,6 +9168,10 @@ evalcase(union node *n, int flags)
|
|||||||
struct stackmark smark;
|
struct stackmark smark;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
|
errlinno = lineno = n->ncase.linno;
|
||||||
|
if (funcline)
|
||||||
|
lineno -= funcline - 1;
|
||||||
|
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
arglist.list = NULL;
|
arglist.list = NULL;
|
||||||
arglist.lastp = &arglist.list;
|
arglist.lastp = &arglist.list;
|
||||||
@ -9157,6 +9206,10 @@ evalsubshell(union node *n, int flags)
|
|||||||
int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
|
int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
errlinno = lineno = n->nredir.linno;
|
||||||
|
if (funcline)
|
||||||
|
lineno -= funcline - 1;
|
||||||
|
|
||||||
expredir(n->nredir.redirect);
|
expredir(n->nredir.redirect);
|
||||||
if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
|
if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
|
||||||
goto nofork;
|
goto nofork;
|
||||||
@ -9464,8 +9517,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
|
|||||||
struct jmploc *volatile savehandler;
|
struct jmploc *volatile savehandler;
|
||||||
struct jmploc jmploc;
|
struct jmploc jmploc;
|
||||||
int e;
|
int e;
|
||||||
|
int savefuncline;
|
||||||
|
|
||||||
saveparam = shellparam;
|
saveparam = shellparam;
|
||||||
|
savefuncline = funcline;
|
||||||
savehandler = exception_handler;
|
savehandler = exception_handler;
|
||||||
e = setjmp(jmploc.loc);
|
e = setjmp(jmploc.loc);
|
||||||
if (e) {
|
if (e) {
|
||||||
@ -9475,7 +9530,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
|
|||||||
exception_handler = &jmploc;
|
exception_handler = &jmploc;
|
||||||
shellparam.malloced = 0;
|
shellparam.malloced = 0;
|
||||||
func->count++;
|
func->count++;
|
||||||
funcnest++;
|
funcline = func->n.ndefun.linno;
|
||||||
INT_ON;
|
INT_ON;
|
||||||
shellparam.nparam = argc - 1;
|
shellparam.nparam = argc - 1;
|
||||||
shellparam.p = argv + 1;
|
shellparam.p = argv + 1;
|
||||||
@ -9484,11 +9539,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
|
|||||||
shellparam.optoff = -1;
|
shellparam.optoff = -1;
|
||||||
#endif
|
#endif
|
||||||
pushlocalvars();
|
pushlocalvars();
|
||||||
evaltree(func->n.narg.next, flags & EV_TESTED);
|
evaltree(func->n.ndefun.body, flags & EV_TESTED);
|
||||||
poplocalvars(0);
|
poplocalvars(0);
|
||||||
funcdone:
|
funcdone:
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
funcnest--;
|
funcline = savefuncline;
|
||||||
freefunc(func);
|
freefunc(func);
|
||||||
freeparam(&shellparam);
|
freeparam(&shellparam);
|
||||||
shellparam = saveparam;
|
shellparam = saveparam;
|
||||||
@ -9852,6 +9907,10 @@ evalcommand(union node *cmd, int flags)
|
|||||||
char **nargv;
|
char **nargv;
|
||||||
smallint cmd_is_exec;
|
smallint cmd_is_exec;
|
||||||
|
|
||||||
|
errlinno = lineno = cmd->ncmd.linno;
|
||||||
|
if (funcline)
|
||||||
|
lineno -= funcline - 1;
|
||||||
|
|
||||||
/* First expand the arguments. */
|
/* First expand the arguments. */
|
||||||
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
|
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
|
||||||
setstackmark(&smark);
|
setstackmark(&smark);
|
||||||
@ -9897,7 +9956,7 @@ evalcommand(union node *cmd, int flags)
|
|||||||
*nargv = NULL;
|
*nargv = NULL;
|
||||||
|
|
||||||
lastarg = NULL;
|
lastarg = NULL;
|
||||||
if (iflag && funcnest == 0 && argc > 0)
|
if (iflag && funcline == 0 && argc > 0)
|
||||||
lastarg = nargv[-1];
|
lastarg = nargv[-1];
|
||||||
|
|
||||||
expredir(cmd->ncmd.redirect);
|
expredir(cmd->ncmd.redirect);
|
||||||
@ -11430,6 +11489,7 @@ simplecmd(void)
|
|||||||
union node *vars, **vpp;
|
union node *vars, **vpp;
|
||||||
union node **rpp, *redir;
|
union node **rpp, *redir;
|
||||||
int savecheckkwd;
|
int savecheckkwd;
|
||||||
|
int savelinno;
|
||||||
#if BASH_TEST2
|
#if BASH_TEST2
|
||||||
smallint double_brackets_flag = 0;
|
smallint double_brackets_flag = 0;
|
||||||
#endif
|
#endif
|
||||||
@ -11443,6 +11503,7 @@ simplecmd(void)
|
|||||||
rpp = &redir;
|
rpp = &redir;
|
||||||
|
|
||||||
savecheckkwd = CHKALIAS;
|
savecheckkwd = CHKALIAS;
|
||||||
|
savelinno = g_parsefile->linno;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int t;
|
int t;
|
||||||
checkkwd = savecheckkwd;
|
checkkwd = savecheckkwd;
|
||||||
@ -11532,7 +11593,9 @@ simplecmd(void)
|
|||||||
}
|
}
|
||||||
n->type = NDEFUN;
|
n->type = NDEFUN;
|
||||||
checkkwd = CHKNL | CHKKWD | CHKALIAS;
|
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;
|
return n;
|
||||||
}
|
}
|
||||||
IF_BASH_FUNCTION(function_flag = 0;)
|
IF_BASH_FUNCTION(function_flag = 0;)
|
||||||
@ -11548,6 +11611,7 @@ simplecmd(void)
|
|||||||
*rpp = NULL;
|
*rpp = NULL;
|
||||||
n = stzalloc(sizeof(struct ncmd));
|
n = stzalloc(sizeof(struct ncmd));
|
||||||
n->type = NCMD;
|
n->type = NCMD;
|
||||||
|
n->ncmd.linno = savelinno;
|
||||||
n->ncmd.args = args;
|
n->ncmd.args = args;
|
||||||
n->ncmd.assign = vars;
|
n->ncmd.assign = vars;
|
||||||
n->ncmd.redirect = redir;
|
n->ncmd.redirect = redir;
|
||||||
@ -11563,10 +11627,13 @@ parse_command(void)
|
|||||||
union node *redir, **rpp;
|
union node *redir, **rpp;
|
||||||
union node **rpp2;
|
union node **rpp2;
|
||||||
int t;
|
int t;
|
||||||
|
int savelinno;
|
||||||
|
|
||||||
redir = NULL;
|
redir = NULL;
|
||||||
rpp2 = &redir;
|
rpp2 = &redir;
|
||||||
|
|
||||||
|
savelinno = g_parsefile->linno;
|
||||||
|
|
||||||
switch (readtoken()) {
|
switch (readtoken()) {
|
||||||
default:
|
default:
|
||||||
raise_error_unexpected_syntax(-1);
|
raise_error_unexpected_syntax(-1);
|
||||||
@ -11617,6 +11684,7 @@ parse_command(void)
|
|||||||
raise_error_syntax("bad for loop variable");
|
raise_error_syntax("bad for loop variable");
|
||||||
n1 = stzalloc(sizeof(struct nfor));
|
n1 = stzalloc(sizeof(struct nfor));
|
||||||
n1->type = NFOR;
|
n1->type = NFOR;
|
||||||
|
n1->nfor.linno = savelinno;
|
||||||
n1->nfor.var = wordtext;
|
n1->nfor.var = wordtext;
|
||||||
checkkwd = CHKNL | CHKKWD | CHKALIAS;
|
checkkwd = CHKNL | CHKKWD | CHKALIAS;
|
||||||
if (readtoken() == TIN) {
|
if (readtoken() == TIN) {
|
||||||
@ -11657,6 +11725,7 @@ parse_command(void)
|
|||||||
case TCASE:
|
case TCASE:
|
||||||
n1 = stzalloc(sizeof(struct ncase));
|
n1 = stzalloc(sizeof(struct ncase));
|
||||||
n1->type = NCASE;
|
n1->type = NCASE;
|
||||||
|
n1->ncase.linno = savelinno;
|
||||||
if (readtoken() != TWORD)
|
if (readtoken() != TWORD)
|
||||||
raise_error_unexpected_syntax(TWORD);
|
raise_error_unexpected_syntax(TWORD);
|
||||||
n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
|
n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
|
||||||
@ -11708,6 +11777,7 @@ parse_command(void)
|
|||||||
case TLP:
|
case TLP:
|
||||||
n1 = stzalloc(sizeof(struct nredir));
|
n1 = stzalloc(sizeof(struct nredir));
|
||||||
n1->type = NSUBSHELL;
|
n1->type = NSUBSHELL;
|
||||||
|
n1->nredir.linno = savelinno;
|
||||||
n1->nredir.n = list(0);
|
n1->nredir.n = list(0);
|
||||||
/*n1->nredir.redirect = NULL; - stzalloc did it */
|
/*n1->nredir.redirect = NULL; - stzalloc did it */
|
||||||
t = TRP;
|
t = TRP;
|
||||||
@ -11741,6 +11811,7 @@ parse_command(void)
|
|||||||
if (n1->type != NSUBSHELL) {
|
if (n1->type != NSUBSHELL) {
|
||||||
n2 = stzalloc(sizeof(struct nredir));
|
n2 = stzalloc(sizeof(struct nredir));
|
||||||
n2->type = NREDIR;
|
n2->type = NREDIR;
|
||||||
|
n2->nredir.linno = savelinno;
|
||||||
n2->nredir.n = n1;
|
n2->nredir.n = n1;
|
||||||
n1 = n2;
|
n1 = n2;
|
||||||
}
|
}
|
||||||
@ -11839,10 +11910,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 arinest;) /* levels of arithmetic expansion */
|
||||||
IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
|
IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
|
||||||
int dqvarnest; /* levels of variables expansion within double quotes */
|
int dqvarnest; /* levels of variables expansion within double quotes */
|
||||||
|
|
||||||
IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
|
IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;)
|
||||||
|
|
||||||
startlinno = g_parsefile->linno;
|
|
||||||
bqlist = NULL;
|
bqlist = NULL;
|
||||||
quotef = 0;
|
quotef = 0;
|
||||||
IF_FEATURE_SH_MATH(prevsyntax = 0;)
|
IF_FEATURE_SH_MATH(prevsyntax = 0;)
|
||||||
@ -12019,7 +12088,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
|
|||||||
if (syntax != BASESYNTAX && eofmark == NULL)
|
if (syntax != BASESYNTAX && eofmark == NULL)
|
||||||
raise_error_syntax("unterminated quoted string");
|
raise_error_syntax("unterminated quoted string");
|
||||||
if (varnest != 0) {
|
if (varnest != 0) {
|
||||||
startlinno = g_parsefile->linno;
|
|
||||||
/* { */
|
/* { */
|
||||||
raise_error_syntax("missing '}'");
|
raise_error_syntax("missing '}'");
|
||||||
}
|
}
|
||||||
@ -12411,7 +12479,6 @@ parsebackq: {
|
|||||||
|
|
||||||
case PEOF:
|
case PEOF:
|
||||||
IF_ASH_ALIAS(case PEOA:)
|
IF_ASH_ALIAS(case PEOA:)
|
||||||
startlinno = g_parsefile->linno;
|
|
||||||
raise_error_syntax("EOF in backquote substitution");
|
raise_error_syntax("EOF in backquote substitution");
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
@ -12493,8 +12560,6 @@ parsearith: {
|
|||||||
* quoted.
|
* quoted.
|
||||||
* If the token is TREDIR, then we set redirnode to a structure containing
|
* If the token is TREDIR, then we set redirnode to a structure containing
|
||||||
* the redirection.
|
* 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]
|
* [Change comment: here documents and internal procedures]
|
||||||
* [Readtoken shouldn't have any arguments. Perhaps we should make the
|
* [Readtoken shouldn't have any arguments. Perhaps we should make the
|
||||||
@ -12532,7 +12597,6 @@ xxreadtoken(void)
|
|||||||
return lasttoken;
|
return lasttoken;
|
||||||
}
|
}
|
||||||
setprompt_if(needprompt, 2);
|
setprompt_if(needprompt, 2);
|
||||||
startlinno = g_parsefile->linno;
|
|
||||||
for (;;) { /* until token or start of word found */
|
for (;;) { /* until token or start of word found */
|
||||||
c = pgetc();
|
c = pgetc();
|
||||||
if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
|
if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
|
||||||
@ -12593,7 +12657,6 @@ xxreadtoken(void)
|
|||||||
return lasttoken;
|
return lasttoken;
|
||||||
}
|
}
|
||||||
setprompt_if(needprompt, 2);
|
setprompt_if(needprompt, 2);
|
||||||
startlinno = g_parsefile->linno;
|
|
||||||
for (;;) { /* until token or start of word found */
|
for (;;) { /* until token or start of word found */
|
||||||
c = pgetc();
|
c = pgetc();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -1,498 +0,0 @@
|
|||||||
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) {
|
|
@ -1,8 +1,8 @@
|
|||||||
0
|
0
|
||||||
0
|
0
|
||||||
./emptytick.tests: line 3: : Permission denied
|
./emptytick.tests: line 1: : Permission denied
|
||||||
127
|
127
|
||||||
./emptytick.tests: line 4: : Permission denied
|
./emptytick.tests: line 1: : Permission denied
|
||||||
127
|
127
|
||||||
0
|
0
|
||||||
0
|
0
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
+ true '%s\n' one 'two '"'"'three' four
|
+ true '%s\n' one 'two '"'"'three' four
|
||||||
+ this=command
|
+ this=command
|
||||||
+ 'this=command'
|
+ 'this=command'
|
||||||
./mode_x.tests: line 1: this=command: not found
|
./mode_x.tests: line 10: this=command: not found
|
||||||
+ true
|
+ true
|
||||||
+ true
|
+ true
|
||||||
+ 'if' true
|
+ 'if' true
|
||||||
./mode_x.tests: line 1: if: not found
|
./mode_x.tests: line 14: if: not found
|
||||||
|
Loading…
Reference in New Issue
Block a user