diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-27 22:02:05 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-27 22:02:05 +0100 |
| commit | 675d24aeaff29dbce6dc116a4b7c9f6026ed5069 (patch) | |
| tree | 446b740ec2d9b2fd035821a89dd876f10b27bff4 /shell | |
| parent | 54c2111781e15b1c70bea43593aa67207f9ea118 (diff) | |
| download | busybox-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.c | 127 | ||||
| -rw-r--r-- | shell/ash_LINENO.patch | 498 | ||||
| -rw-r--r-- | shell/ash_test/ash-psubst/emptytick.right | 4 | ||||
| -rw-r--r-- | shell/ash_test/ash-quoting/mode_x.right | 4 |
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 | ||
| 740 | struct ncmd { | 743 | struct 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 | ||
| 753 | struct nredir { | 757 | struct 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 | ||
| 772 | struct nfor { | 777 | struct 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 | ||
| 779 | struct ncase { | 785 | struct 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 | ||
| 799 | struct ndefun { | ||
| 800 | smallint type; | ||
| 801 | int linno; | ||
| 802 | char *text; | ||
| 803 | union node *body; | ||
| 804 | }; | ||
| 805 | |||
| 792 | struct narg { | 806 | struct 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 | ||
| 1270 | static struct parsefile basepf; /* top level input file */ | 1285 | static struct parsefile basepf; /* top level input file */ |
| 1271 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 1286 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
| 1272 | static int startlinno; /* line # where last token started */ | ||
| 1273 | static char *commandname; /* currently executing command */ | 1287 | static 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; | |||
| 1336 | static void | 1350 | static void |
| 1337 | raise_error_syntax(const char *msg) | 1351 | raise_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 | }; |
| 2047 | extern struct globals_var *const ash_ptr_to_globals_var; | 2065 | extern 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) |
| 8843 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 8881 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
| 8844 | static int skipcount; /* number of levels to skip */ | 8882 | static int skipcount; /* number of levels to skip */ |
| 8845 | static int funcnest; /* depth of function calls */ | ||
| 8846 | static int loopnest; /* current loop nesting level */ | 8883 | static int loopnest; /* current loop nesting level */ |
| 8884 | static 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 */ |
| 8849 | static int evalstring(char *s, int flags); | 8887 | static 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 @@ | |||
| 1 | This patch is a backport from dash of the combination of: | ||
| 2 | [SHELL] Add preliminary LINENO support | ||
| 3 | [VAR] Fix varinit ordering that broke fc | ||
| 4 | [SHELL] Improve LINENO support | ||
| 5 | |||
| 6 | Applies cleanly on top of: | ||
| 7 | commit 9832bbaba966f0e52e183f10cd93fad7f8f643fe | ||
| 8 | Date: Tue Aug 15 15:44:41 2017 +0200 | ||
| 9 | |||
| 10 | Testsuite needs some tweaks (line numbers in some messages change). | ||
| 11 | |||
| 12 | Unfortunately, it is somewhat big: | ||
| 13 | |||
| 14 | function old new delta | ||
| 15 | parse_command 1581 1658 +77 | ||
| 16 | calcsize 203 272 +69 | ||
| 17 | copynode 195 257 +62 | ||
| 18 | lookupvar 59 108 +49 | ||
| 19 | evaltree 494 534 +40 | ||
| 20 | evalfor 152 187 +35 | ||
| 21 | evalcase 278 313 +35 | ||
| 22 | evalcommand 1547 1581 +34 | ||
| 23 | evalsubshell 169 199 +30 | ||
| 24 | linenovar - 22 +22 | ||
| 25 | raise_error_syntax 11 29 +18 | ||
| 26 | evalfun 266 280 +14 | ||
| 27 | varinit_data 96 108 +12 | ||
| 28 | cmdtxt 626 631 +5 | ||
| 29 | lineno - 4 +4 | ||
| 30 | funcline - 4 +4 | ||
| 31 | ash_vmsg 144 141 -3 | ||
| 32 | startlinno 4 - -4 | ||
| 33 | funcnest 4 - -4 | ||
| 34 | xxreadtoken 272 259 -13 | ||
| 35 | readtoken1 2635 2594 -41 | ||
| 36 | ------------------------------------------------------------------------------ | ||
| 37 | (add/remove: 3/2 grow/shrink: 13/3 up/down: 510/-65) Total: 445 bytes | ||
| 38 | text data bss dec hex filename | ||
| 39 | 912030 563 5844 918437 e03a5 busybox_old | ||
| 40 | 912473 587 5844 918904 e0578 busybox_unstripped | ||
| 41 | |||
| 42 | diff --git a/shell/ash.c b/shell/ash.c | ||
| 43 | index 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 @@ | |||
| 1 | 0 | 1 | 0 |
| 2 | 0 | 2 | 0 |
| 3 | ./emptytick.tests: line 3: : Permission denied | 3 | ./emptytick.tests: line 1: : Permission denied |
| 4 | 127 | 4 | 127 |
| 5 | ./emptytick.tests: line 4: : Permission denied | 5 | ./emptytick.tests: line 1: : Permission denied |
| 6 | 127 | 6 | 127 |
| 7 | 0 | 7 | 0 |
| 8 | 0 | 8 | 0 |
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 |
