diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 330 |
1 files changed, 251 insertions, 79 deletions
diff --git a/shell/ash.c b/shell/ash.c index 81845dc60..36ddda1bc 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -66,6 +66,22 @@ | |||
66 | //config: default y | 66 | //config: default y |
67 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH | 67 | //config: depends on ASH || SH_IS_ASH || BASH_IS_ASH |
68 | //config: | 68 | //config: |
69 | //config:config ASH_BASH_SOURCE_CURDIR | ||
70 | //config: bool "'source' and '.' builtins search current directory after $PATH" | ||
71 | //config: default n # do not encourage non-standard behavior | ||
72 | //config: depends on ASH_BASH_COMPAT | ||
73 | //config: help | ||
74 | //config: This is not compliant with standards. Avoid if possible. | ||
75 | //config: | ||
76 | //config:config ASH_BASH_NOT_FOUND_HOOK | ||
77 | //config: bool "command_not_found_handle hook support" | ||
78 | //config: default y | ||
79 | //config: depends on ASH_BASH_COMPAT | ||
80 | //config: help | ||
81 | //config: Enable support for the 'command_not_found_handle' hook function, | ||
82 | //config: from GNU bash, which allows for alternative command not found | ||
83 | //config: handling. | ||
84 | //config: | ||
69 | //config:config ASH_JOB_CONTROL | 85 | //config:config ASH_JOB_CONTROL |
70 | //config: bool "Job control" | 86 | //config: bool "Job control" |
71 | //config: default y | 87 | //config: default y |
@@ -278,6 +294,19 @@ typedef long arith_t; | |||
278 | # error "Do not even bother, ash will not run on NOMMU machine" | 294 | # error "Do not even bother, ash will not run on NOMMU machine" |
279 | #endif | 295 | #endif |
280 | 296 | ||
297 | /* We use a trick to have more optimized code (fewer pointer reloads): | ||
298 | * ash.c: extern struct globals *const ash_ptr_to_globals; | ||
299 | * ash_ptr_hack.c: struct globals *ash_ptr_to_globals; | ||
300 | * This way, compiler in ash.c knows the pointer can not change. | ||
301 | * | ||
302 | * However, this may break on weird arches or toolchains. In this case, | ||
303 | * set "-DBB_GLOBAL_CONST=''" in CONFIG_EXTRA_CFLAGS to disable | ||
304 | * this optimization. | ||
305 | */ | ||
306 | #ifndef BB_GLOBAL_CONST | ||
307 | # define BB_GLOBAL_CONST const | ||
308 | #endif | ||
309 | |||
281 | #if ENABLE_PLATFORM_MINGW32 | 310 | #if ENABLE_PLATFORM_MINGW32 |
282 | union node; | 311 | union node; |
283 | struct strlist; | 312 | struct strlist; |
@@ -393,6 +422,8 @@ struct globals_misc { | |||
393 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 422 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
394 | int shlvl; | 423 | int shlvl; |
395 | #define rootshell (!shlvl) | 424 | #define rootshell (!shlvl) |
425 | int errlinno; | ||
426 | |||
396 | char *minusc; /* argument to -c option */ | 427 | char *minusc; /* argument to -c option */ |
397 | 428 | ||
398 | char *curdir; // = nullstr; /* current working directory */ | 429 | char *curdir; // = nullstr; /* current working directory */ |
@@ -469,13 +500,14 @@ struct globals_misc { | |||
469 | #endif | 500 | #endif |
470 | pid_t backgndpid; /* pid of last background process */ | 501 | pid_t backgndpid; /* pid of last background process */ |
471 | }; | 502 | }; |
472 | extern struct globals_misc *const ash_ptr_to_globals_misc; | 503 | extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; |
473 | #define G_misc (*ash_ptr_to_globals_misc) | 504 | #define G_misc (*ash_ptr_to_globals_misc) |
474 | #define exitstatus (G_misc.exitstatus ) | 505 | #define exitstatus (G_misc.exitstatus ) |
475 | #define back_exitstatus (G_misc.back_exitstatus ) | 506 | #define back_exitstatus (G_misc.back_exitstatus ) |
476 | #define job_warning (G_misc.job_warning) | 507 | #define job_warning (G_misc.job_warning) |
477 | #define rootpid (G_misc.rootpid ) | 508 | #define rootpid (G_misc.rootpid ) |
478 | #define shlvl (G_misc.shlvl ) | 509 | #define shlvl (G_misc.shlvl ) |
510 | #define errlinno (G_misc.errlinno ) | ||
479 | #define minusc (G_misc.minusc ) | 511 | #define minusc (G_misc.minusc ) |
480 | #define curdir (G_misc.curdir ) | 512 | #define curdir (G_misc.curdir ) |
481 | #define physdir (G_misc.physdir ) | 513 | #define physdir (G_misc.physdir ) |
@@ -810,6 +842,7 @@ union node; | |||
810 | 842 | ||
811 | struct ncmd { | 843 | struct ncmd { |
812 | smallint type; /* Nxxxx */ | 844 | smallint type; /* Nxxxx */ |
845 | int linno; | ||
813 | union node *assign; | 846 | union node *assign; |
814 | union node *args; | 847 | union node *args; |
815 | union node *redirect; | 848 | union node *redirect; |
@@ -823,6 +856,7 @@ struct npipe { | |||
823 | 856 | ||
824 | struct nredir { | 857 | struct nredir { |
825 | smallint type; | 858 | smallint type; |
859 | int linno; | ||
826 | union node *n; | 860 | union node *n; |
827 | union node *redirect; | 861 | union node *redirect; |
828 | }; | 862 | }; |
@@ -842,6 +876,7 @@ struct nif { | |||
842 | 876 | ||
843 | struct nfor { | 877 | struct nfor { |
844 | smallint type; | 878 | smallint type; |
879 | int linno; | ||
845 | union node *args; | 880 | union node *args; |
846 | union node *body; | 881 | union node *body; |
847 | char *var; | 882 | char *var; |
@@ -849,6 +884,7 @@ struct nfor { | |||
849 | 884 | ||
850 | struct ncase { | 885 | struct ncase { |
851 | smallint type; | 886 | smallint type; |
887 | int linno; | ||
852 | union node *expr; | 888 | union node *expr; |
853 | union node *cases; | 889 | union node *cases; |
854 | }; | 890 | }; |
@@ -860,6 +896,13 @@ struct nclist { | |||
860 | union node *body; | 896 | union node *body; |
861 | }; | 897 | }; |
862 | 898 | ||
899 | struct ndefun { | ||
900 | smallint type; | ||
901 | int linno; | ||
902 | char *text; | ||
903 | union node *body; | ||
904 | }; | ||
905 | |||
863 | struct narg { | 906 | struct narg { |
864 | smallint type; | 907 | smallint type; |
865 | union node *next; | 908 | union node *next; |
@@ -911,6 +954,7 @@ union node { | |||
911 | struct nfor nfor; | 954 | struct nfor nfor; |
912 | struct ncase ncase; | 955 | struct ncase ncase; |
913 | struct nclist nclist; | 956 | struct nclist nclist; |
957 | struct ndefun ndefun; | ||
914 | struct narg narg; | 958 | struct narg narg; |
915 | struct nfile nfile; | 959 | struct nfile nfile; |
916 | struct ndup ndup; | 960 | struct ndup ndup; |
@@ -1340,7 +1384,6 @@ struct parsefile { | |||
1340 | 1384 | ||
1341 | static struct parsefile basepf; /* top level input file */ | 1385 | static struct parsefile basepf; /* top level input file */ |
1342 | static struct parsefile *g_parsefile = &basepf; /* current input file */ | 1386 | static struct parsefile *g_parsefile = &basepf; /* current input file */ |
1343 | static int startlinno; /* line # where last token started */ | ||
1344 | static char *commandname; /* currently executing command */ | 1387 | static char *commandname; /* currently executing command */ |
1345 | 1388 | ||
1346 | 1389 | ||
@@ -1354,7 +1397,7 @@ ash_vmsg(const char *msg, va_list ap) | |||
1354 | if (strcmp(arg0, commandname)) | 1397 | if (strcmp(arg0, commandname)) |
1355 | fprintf(stderr, "%s: ", commandname); | 1398 | fprintf(stderr, "%s: ", commandname); |
1356 | if (!iflag || g_parsefile->pf_fd > 0) | 1399 | if (!iflag || g_parsefile->pf_fd > 0) |
1357 | fprintf(stderr, "line %d: ", startlinno); | 1400 | fprintf(stderr, "line %d: ", errlinno); |
1358 | } | 1401 | } |
1359 | vfprintf(stderr, msg, ap); | 1402 | vfprintf(stderr, msg, ap); |
1360 | newline_and_flush(stderr); | 1403 | newline_and_flush(stderr); |
@@ -1407,6 +1450,7 @@ static void raise_error_syntax(const char *) NORETURN; | |||
1407 | static void | 1450 | static void |
1408 | raise_error_syntax(const char *msg) | 1451 | raise_error_syntax(const char *msg) |
1409 | { | 1452 | { |
1453 | errlinno = g_parsefile->linno; | ||
1410 | ash_msg_and_raise_error("syntax error: %s", msg); | 1454 | ash_msg_and_raise_error("syntax error: %s", msg); |
1411 | /* NOTREACHED */ | 1455 | /* NOTREACHED */ |
1412 | } | 1456 | } |
@@ -1529,7 +1573,7 @@ struct globals_memstack { | |||
1529 | size_t g_stacknleft; // = MINSIZE; | 1573 | size_t g_stacknleft; // = MINSIZE; |
1530 | struct stack_block stackbase; | 1574 | struct stack_block stackbase; |
1531 | }; | 1575 | }; |
1532 | extern struct globals_memstack *const ash_ptr_to_globals_memstack; | 1576 | extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; |
1533 | #define G_memstack (*ash_ptr_to_globals_memstack) | 1577 | #define G_memstack (*ash_ptr_to_globals_memstack) |
1534 | #define g_stackp (G_memstack.g_stackp ) | 1578 | #define g_stackp (G_memstack.g_stackp ) |
1535 | #define g_stacknxt (G_memstack.g_stacknxt ) | 1579 | #define g_stacknxt (G_memstack.g_stacknxt ) |
@@ -1619,7 +1663,7 @@ sstrdup(const char *p) | |||
1619 | return memcpy(stalloc(len), p, len); | 1663 | return memcpy(stalloc(len), p, len); |
1620 | } | 1664 | } |
1621 | 1665 | ||
1622 | static inline void | 1666 | static ALWAYS_INLINE void |
1623 | grabstackblock(size_t len) | 1667 | grabstackblock(size_t len) |
1624 | { | 1668 | { |
1625 | stalloc(len); | 1669 | stalloc(len); |
@@ -2094,6 +2138,7 @@ static const struct { | |||
2094 | #if ENABLE_ASH_GETOPTS | 2138 | #if ENABLE_ASH_GETOPTS |
2095 | { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, | 2139 | { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, |
2096 | #endif | 2140 | #endif |
2141 | { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL }, | ||
2097 | #if ENABLE_ASH_RANDOM_SUPPORT | 2142 | #if ENABLE_ASH_RANDOM_SUPPORT |
2098 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, | 2143 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, |
2099 | #endif | 2144 | #endif |
@@ -2114,25 +2159,18 @@ struct globals_var { | |||
2114 | int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */ | 2159 | int preverrout_fd; /* stderr fd: usually 2, unless redirect moved it */ |
2115 | struct var *vartab[VTABSIZE]; | 2160 | struct var *vartab[VTABSIZE]; |
2116 | struct var varinit[ARRAY_SIZE(varinit_data)]; | 2161 | struct var varinit[ARRAY_SIZE(varinit_data)]; |
2162 | int lineno; | ||
2163 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; | ||
2117 | }; | 2164 | }; |
2118 | extern struct globals_var *const ash_ptr_to_globals_var; | 2165 | extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; |
2119 | #define G_var (*ash_ptr_to_globals_var) | 2166 | #define G_var (*ash_ptr_to_globals_var) |
2120 | #define shellparam (G_var.shellparam ) | 2167 | #define shellparam (G_var.shellparam ) |
2121 | //#define redirlist (G_var.redirlist ) | 2168 | //#define redirlist (G_var.redirlist ) |
2122 | #define preverrout_fd (G_var.preverrout_fd) | 2169 | #define preverrout_fd (G_var.preverrout_fd) |
2123 | #define vartab (G_var.vartab ) | 2170 | #define vartab (G_var.vartab ) |
2124 | #define varinit (G_var.varinit ) | 2171 | #define varinit (G_var.varinit ) |
2125 | #define INIT_G_var() do { \ | 2172 | #define lineno (G_var.lineno ) |
2126 | unsigned i; \ | 2173 | #define linenovar (G_var.linenovar ) |
2127 | (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ | ||
2128 | barrier(); \ | ||
2129 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ | ||
2130 | varinit[i].flags = varinit_data[i].flags; \ | ||
2131 | varinit[i].var_text = varinit_data[i].var_text; \ | ||
2132 | varinit[i].var_func = varinit_data[i].var_func; \ | ||
2133 | } \ | ||
2134 | } while (0) | ||
2135 | |||
2136 | #define vifs varinit[0] | 2174 | #define vifs varinit[0] |
2137 | #if ENABLE_ASH_MAIL | 2175 | #if ENABLE_ASH_MAIL |
2138 | # define vmail (&vifs)[1] | 2176 | # define vmail (&vifs)[1] |
@@ -2146,14 +2184,28 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
2146 | #define vps4 (&vps2)[1] | 2184 | #define vps4 (&vps2)[1] |
2147 | #if ENABLE_ASH_GETOPTS | 2185 | #if ENABLE_ASH_GETOPTS |
2148 | # define voptind (&vps4)[1] | 2186 | # define voptind (&vps4)[1] |
2187 | # define vlineno (&voptind)[1] | ||
2149 | # if ENABLE_ASH_RANDOM_SUPPORT | 2188 | # if ENABLE_ASH_RANDOM_SUPPORT |
2150 | # define vrandom (&voptind)[1] | 2189 | # define vrandom (&vlineno)[1] |
2151 | # endif | 2190 | # endif |
2152 | #else | 2191 | #else |
2192 | # define vlineno (&vps4)[1] | ||
2153 | # if ENABLE_ASH_RANDOM_SUPPORT | 2193 | # if ENABLE_ASH_RANDOM_SUPPORT |
2154 | # define vrandom (&vps4)[1] | 2194 | # define vrandom (&vlineno)[1] |
2155 | # endif | 2195 | # endif |
2156 | #endif | 2196 | #endif |
2197 | #define INIT_G_var() do { \ | ||
2198 | unsigned i; \ | ||
2199 | (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ | ||
2200 | barrier(); \ | ||
2201 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ | ||
2202 | varinit[i].flags = varinit_data[i].flags; \ | ||
2203 | varinit[i].var_text = varinit_data[i].var_text; \ | ||
2204 | varinit[i].var_func = varinit_data[i].var_func; \ | ||
2205 | } \ | ||
2206 | strcpy(linenovar, "LINENO="); \ | ||
2207 | vlineno.var_text = linenovar; \ | ||
2208 | } while (0) | ||
2157 | 2209 | ||
2158 | /* | 2210 | /* |
2159 | * The following macros access the values of the above variables. | 2211 | * The following macros access the values of the above variables. |
@@ -2289,8 +2341,12 @@ lookupvar(const char *name) | |||
2289 | if (v->flags & VDYNAMIC) | 2341 | if (v->flags & VDYNAMIC) |
2290 | v->var_func(NULL); | 2342 | v->var_func(NULL); |
2291 | #endif | 2343 | #endif |
2292 | if (!(v->flags & VUNSET)) | 2344 | if (!(v->flags & VUNSET)) { |
2345 | if (v == &vlineno && v->var_text == linenovar) { | ||
2346 | fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); | ||
2347 | } | ||
2293 | return var_end(v->var_text); | 2348 | return var_end(v->var_text); |
2349 | } | ||
2294 | } | 2350 | } |
2295 | return NULL; | 2351 | return NULL; |
2296 | } | 2352 | } |
@@ -5125,7 +5181,7 @@ cmdtxt(union node *n) | |||
5125 | p = "; done"; | 5181 | p = "; done"; |
5126 | goto dodo; | 5182 | goto dodo; |
5127 | case NDEFUN: | 5183 | case NDEFUN: |
5128 | cmdputs(n->narg.text); | 5184 | cmdputs(n->ndefun.text); |
5129 | p = "() { ... }"; | 5185 | p = "() { ... }"; |
5130 | goto dotail2; | 5186 | goto dotail2; |
5131 | case NCMD: | 5187 | case NCMD: |
@@ -6151,6 +6207,26 @@ ash_arith(const char *s) | |||
6151 | return result; | 6207 | return result; |
6152 | } | 6208 | } |
6153 | #endif | 6209 | #endif |
6210 | #if BASH_SUBSTR | ||
6211 | # if ENABLE_FEATURE_SH_MATH | ||
6212 | static int substr_atoi(const char *s) | ||
6213 | { | ||
6214 | arith_t t = ash_arith(s); | ||
6215 | if (sizeof(t) > sizeof(int)) { | ||
6216 | /* clamp very large or very large negative nums for ${v:N:M}: | ||
6217 | * else "${v:0:0x100000001}" would work as "${v:0:1}" | ||
6218 | */ | ||
6219 | if (t > INT_MAX) | ||
6220 | t = INT_MAX; | ||
6221 | if (t < INT_MIN) | ||
6222 | t = INT_MIN; | ||
6223 | } | ||
6224 | return t; | ||
6225 | } | ||
6226 | # else | ||
6227 | # define substr_atoi(s) number(s) | ||
6228 | # endif | ||
6229 | #endif | ||
6154 | 6230 | ||
6155 | /* | 6231 | /* |
6156 | * expandarg flags | 6232 | * expandarg flags |
@@ -6182,7 +6258,6 @@ ash_arith(const char *s) | |||
6182 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ | 6258 | #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ |
6183 | #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ | 6259 | #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ |
6184 | #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ | 6260 | #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ |
6185 | #define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */ | ||
6186 | 6261 | ||
6187 | /* Add CTLESC when necessary. */ | 6262 | /* Add CTLESC when necessary. */ |
6188 | #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) | 6263 | #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) |
@@ -6363,8 +6438,12 @@ esclen(const char *start, const char *p) | |||
6363 | /* | 6438 | /* |
6364 | * Remove any CTLESC characters from a string. | 6439 | * Remove any CTLESC characters from a string. |
6365 | */ | 6440 | */ |
6441 | #if !BASH_PATTERN_SUBST | ||
6442 | #define rmescapes(str, flag, slash_position) \ | ||
6443 | rmescapes(str, flag) | ||
6444 | #endif | ||
6366 | static char * | 6445 | static char * |
6367 | rmescapes(char *str, int flag) | 6446 | rmescapes(char *str, int flag, int *slash_position) |
6368 | { | 6447 | { |
6369 | static const char qchars[] ALIGN1 = { | 6448 | static const char qchars[] ALIGN1 = { |
6370 | IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; | 6449 | IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; |
@@ -6373,9 +6452,8 @@ rmescapes(char *str, int flag) | |||
6373 | unsigned inquotes; | 6452 | unsigned inquotes; |
6374 | unsigned protect_against_glob; | 6453 | unsigned protect_against_glob; |
6375 | unsigned globbing; | 6454 | unsigned globbing; |
6376 | IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;) | ||
6377 | 6455 | ||
6378 | p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash)); | 6456 | p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash_position)); |
6379 | if (!p) | 6457 | if (!p) |
6380 | return str; | 6458 | return str; |
6381 | 6459 | ||
@@ -6455,10 +6533,11 @@ rmescapes(char *str, int flag) | |||
6455 | goto copy; | 6533 | goto copy; |
6456 | } | 6534 | } |
6457 | #if BASH_PATTERN_SUBST | 6535 | #if BASH_PATTERN_SUBST |
6458 | else if (*p == '/' && slash) { | 6536 | else if (slash_position && p == str + *slash_position) { |
6459 | /* stop handling globbing and mark location of slash */ | 6537 | /* stop handling globbing */ |
6460 | globbing = slash = 0; | 6538 | globbing = 0; |
6461 | *p = CTLESC; | 6539 | *slash_position = q - r; |
6540 | slash_position = NULL; | ||
6462 | } | 6541 | } |
6463 | #endif | 6542 | #endif |
6464 | protect_against_glob = globbing; | 6543 | protect_against_glob = globbing; |
@@ -6482,7 +6561,7 @@ rmescapes(char *str, int flag) | |||
6482 | static char * | 6561 | static char * |
6483 | preglob(const char *pattern, int flag) | 6562 | preglob(const char *pattern, int flag) |
6484 | { | 6563 | { |
6485 | return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); | 6564 | return rmescapes((char *)pattern, flag | RMESCAPE_GLOB, NULL); |
6486 | } | 6565 | } |
6487 | 6566 | ||
6488 | /* | 6567 | /* |
@@ -6837,7 +6916,7 @@ expari(int flag) | |||
6837 | expdest = p; | 6916 | expdest = p; |
6838 | 6917 | ||
6839 | if (flag & QUOTES_ESC) | 6918 | if (flag & QUOTES_ESC) |
6840 | rmescapes(p + 1, 0); | 6919 | rmescapes(p + 1, 0, NULL); |
6841 | 6920 | ||
6842 | len = cvtnum(ash_arith(p + 1)); | 6921 | len = cvtnum(ash_arith(p + 1)); |
6843 | 6922 | ||
@@ -7125,20 +7204,58 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7125 | char *rmesc, *rmescend; | 7204 | char *rmesc, *rmescend; |
7126 | char *str; | 7205 | char *str; |
7127 | int amount, resetloc; | 7206 | int amount, resetloc; |
7207 | int argstr_flags; | ||
7128 | IF_BASH_PATTERN_SUBST(int workloc;) | 7208 | IF_BASH_PATTERN_SUBST(int workloc;) |
7129 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) | 7209 | IF_BASH_PATTERN_SUBST(int slash_pos;) |
7210 | IF_BASH_PATTERN_SUBST(char *repl;) | ||
7130 | int zero; | 7211 | int zero; |
7131 | char *(*scan)(char*, char*, char*, char*, int, int); | 7212 | char *(*scan)(char*, char*, char*, char*, int, int); |
7132 | 7213 | ||
7133 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", | 7214 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", |
7134 | // p, varname, strloc, subtype, startloc, varflags, quotes); | 7215 | // p, varname, strloc, subtype, startloc, varflags, quotes); |
7135 | 7216 | ||
7136 | argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? | 7217 | #if BASH_PATTERN_SUBST |
7137 | (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0) | 7218 | /* For "${v/pattern/repl}", we must find the delimiter _before_ |
7138 | ); | 7219 | * argstr() call expands possible variable references in pattern: |
7220 | * think about "v=a; a=a/; echo ${v/$a/r}" case. | ||
7221 | */ | ||
7222 | repl = NULL; | ||
7223 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { | ||
7224 | /* Find '/' and replace with NUL */ | ||
7225 | repl = p; | ||
7226 | for (;;) { | ||
7227 | /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */ | ||
7228 | if (*repl == '\0') { | ||
7229 | repl = NULL; | ||
7230 | break; | ||
7231 | } | ||
7232 | if (*repl == '/') { | ||
7233 | *repl = '\0'; | ||
7234 | break; | ||
7235 | } | ||
7236 | if ((unsigned char)*repl == CTLESC && repl[1]) | ||
7237 | repl++; | ||
7238 | repl++; | ||
7239 | } | ||
7240 | } | ||
7241 | #endif | ||
7242 | argstr_flags = EXP_TILDE; | ||
7243 | if (subtype != VSASSIGN && subtype != VSQUESTION) | ||
7244 | argstr_flags |= (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE); | ||
7245 | argstr(p, argstr_flags); | ||
7246 | #if BASH_PATTERN_SUBST | ||
7247 | slash_pos = -1; | ||
7248 | if (repl) { | ||
7249 | slash_pos = expdest - ((char *)stackblock() + strloc); | ||
7250 | STPUTC('/', expdest); | ||
7251 | argstr(repl + 1, argstr_flags); | ||
7252 | *repl = '/'; | ||
7253 | } | ||
7254 | #endif | ||
7139 | STPUTC('\0', expdest); | 7255 | STPUTC('\0', expdest); |
7140 | argbackq = saveargbackq; | 7256 | argbackq = saveargbackq; |
7141 | startp = (char *)stackblock() + startloc; | 7257 | startp = (char *)stackblock() + startloc; |
7258 | //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc); | ||
7142 | 7259 | ||
7143 | switch (subtype) { | 7260 | switch (subtype) { |
7144 | case VSASSIGN: | 7261 | case VSASSIGN: |
@@ -7158,13 +7275,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7158 | 7275 | ||
7159 | loc = str = stackblock() + strloc; | 7276 | loc = str = stackblock() + strloc; |
7160 | 7277 | ||
7161 | # if !ENABLE_FEATURE_SH_MATH | ||
7162 | # define ash_arith number | ||
7163 | # endif | ||
7164 | /* Read POS in ${var:POS:LEN} */ | 7278 | /* Read POS in ${var:POS:LEN} */ |
7165 | colon = strchr(loc, ':'); | 7279 | colon = strchr(loc, ':'); |
7166 | if (colon) *colon = '\0'; | 7280 | if (colon) *colon = '\0'; |
7167 | pos = ash_arith(loc); | 7281 | pos = substr_atoi(loc); |
7168 | if (colon) *colon = ':'; | 7282 | if (colon) *colon = ':'; |
7169 | 7283 | ||
7170 | /* Read LEN in ${var:POS:LEN} */ | 7284 | /* Read LEN in ${var:POS:LEN} */ |
@@ -7172,7 +7286,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7172 | /* *loc != '\0', guaranteed by parser */ | 7286 | /* *loc != '\0', guaranteed by parser */ |
7173 | if (quotes) { | 7287 | if (quotes) { |
7174 | char *ptr; | 7288 | char *ptr; |
7175 | |||
7176 | /* Adjust the length by the number of escapes */ | 7289 | /* Adjust the length by the number of escapes */ |
7177 | for (ptr = startp; ptr < (str - 1); ptr++) { | 7290 | for (ptr = startp; ptr < (str - 1); ptr++) { |
7178 | if ((unsigned char)*ptr == CTLESC) { | 7291 | if ((unsigned char)*ptr == CTLESC) { |
@@ -7184,19 +7297,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7184 | orig_len = len; | 7297 | orig_len = len; |
7185 | if (*loc++ == ':') { | 7298 | if (*loc++ == ':') { |
7186 | /* ${var::LEN} */ | 7299 | /* ${var::LEN} */ |
7187 | len = ash_arith(loc); | 7300 | len = substr_atoi(loc); |
7188 | } else { | 7301 | } else { |
7189 | /* Skip POS in ${var:POS:LEN} */ | 7302 | /* Skip POS in ${var:POS:LEN} */ |
7190 | len = orig_len; | 7303 | len = orig_len; |
7191 | while (*loc && *loc != ':') { | 7304 | while (*loc && *loc != ':') |
7192 | loc++; | 7305 | loc++; |
7193 | } | 7306 | if (*loc++ == ':') |
7194 | if (*loc++ == ':') { | 7307 | len = substr_atoi(loc); |
7195 | len = ash_arith(loc); | ||
7196 | } | ||
7197 | } | 7308 | } |
7198 | # undef ash_arith | ||
7199 | |||
7200 | if (pos < 0) { | 7309 | if (pos < 0) { |
7201 | /* ${VAR:$((-n)):l} starts n chars from the end */ | 7310 | /* ${VAR:$((-n)):l} starts n chars from the end */ |
7202 | pos = orig_len + pos; | 7311 | pos = orig_len + pos; |
@@ -7236,6 +7345,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7236 | resetloc = expdest - (char *)stackblock(); | 7345 | resetloc = expdest - (char *)stackblock(); |
7237 | 7346 | ||
7238 | #if BASH_PATTERN_SUBST | 7347 | #if BASH_PATTERN_SUBST |
7348 | repl = NULL; | ||
7349 | |||
7239 | /* We'll comeback here if we grow the stack while handling | 7350 | /* We'll comeback here if we grow the stack while handling |
7240 | * a VSREPLACE or VSREPLACEALL, since our pointers into the | 7351 | * a VSREPLACE or VSREPLACEALL, since our pointers into the |
7241 | * stack will need rebasing, and we'll need to remove our work | 7352 | * stack will need rebasing, and we'll need to remove our work |
@@ -7250,8 +7361,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7250 | 7361 | ||
7251 | rmesc = startp; | 7362 | rmesc = startp; |
7252 | rmescend = (char *)stackblock() + strloc; | 7363 | rmescend = (char *)stackblock() + strloc; |
7364 | //bb_error_msg("str7:'%s'", rmescend); | ||
7253 | if (quotes) { | 7365 | if (quotes) { |
7254 | rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); | 7366 | //TODO: how to handle slash_pos here if string changes (shortens?) |
7367 | rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW, NULL); | ||
7255 | if (rmesc != startp) { | 7368 | if (rmesc != startp) { |
7256 | rmescend = expdest; | 7369 | rmescend = expdest; |
7257 | startp = (char *)stackblock() + startloc; | 7370 | startp = (char *)stackblock() + startloc; |
@@ -7264,12 +7377,13 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7264 | * The result is a_\_z_c (not a\_\_z_c)! | 7377 | * The result is a_\_z_c (not a\_\_z_c)! |
7265 | * | 7378 | * |
7266 | * The search pattern and replace string treat backslashes differently! | 7379 | * The search pattern and replace string treat backslashes differently! |
7267 | * RMESCAPE_SLASH causes preglob to work differently on the pattern | 7380 | * "&slash_pos" causes rmescapes() to work differently on the pattern |
7268 | * and string. It's only used on the first call. | 7381 | * and string. It's only used on the first call. |
7269 | */ | 7382 | */ |
7270 | preglob(str, IF_BASH_PATTERN_SUBST( | 7383 | //bb_error_msg("str8:'%s' slash_pos:%d", str, slash_pos); |
7271 | (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? | 7384 | rmescapes(str, RMESCAPE_GLOB, |
7272 | RMESCAPE_SLASH : ) 0); | 7385 | repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos) |
7386 | ); | ||
7273 | 7387 | ||
7274 | #if BASH_PATTERN_SUBST | 7388 | #if BASH_PATTERN_SUBST |
7275 | workloc = expdest - (char *)stackblock(); | 7389 | workloc = expdest - (char *)stackblock(); |
@@ -7278,11 +7392,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7278 | char *idx, *end; | 7392 | char *idx, *end; |
7279 | 7393 | ||
7280 | if (!repl) { | 7394 | if (!repl) { |
7281 | repl = strchr(str, CTLESC); | 7395 | //bb_error_msg("str9:'%s' slash_pos:%d", str, slash_pos); |
7282 | if (repl) | 7396 | repl = nullstr; |
7397 | if (slash_pos >= 0) { | ||
7398 | repl = str + slash_pos; | ||
7283 | *repl++ = '\0'; | 7399 | *repl++ = '\0'; |
7284 | else | 7400 | } |
7285 | repl = nullstr; | ||
7286 | } | 7401 | } |
7287 | //bb_error_msg("str:'%s' repl:'%s'", str, repl); | 7402 | //bb_error_msg("str:'%s' repl:'%s'", str, repl); |
7288 | 7403 | ||
@@ -7802,7 +7917,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7802 | INT_ON; | 7917 | INT_ON; |
7803 | nometa: | 7918 | nometa: |
7804 | *exparg.lastp = str; | 7919 | *exparg.lastp = str; |
7805 | rmescapes(str->text, 0); | 7920 | rmescapes(str->text, 0, NULL); |
7806 | exparg.lastp = &str->next; | 7921 | exparg.lastp = &str->next; |
7807 | break; | 7922 | break; |
7808 | default: /* GLOB_NOSPACE */ | 7923 | default: /* GLOB_NOSPACE */ |
@@ -8031,7 +8146,7 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
8031 | */ | 8146 | */ |
8032 | nometa: | 8147 | nometa: |
8033 | *exparg.lastp = str; | 8148 | *exparg.lastp = str; |
8034 | rmescapes(str->text, 0); | 8149 | rmescapes(str->text, 0, NULL); |
8035 | exparg.lastp = &str->next; | 8150 | exparg.lastp = &str->next; |
8036 | } else { | 8151 | } else { |
8037 | *exparg.lastp = NULL; | 8152 | *exparg.lastp = NULL; |
@@ -8970,6 +9085,10 @@ calcsize(union node *n) | |||
8970 | IF_PLATFORM_MINGW32(nodeptrsize += 3); | 9085 | IF_PLATFORM_MINGW32(nodeptrsize += 3); |
8971 | break; | 9086 | break; |
8972 | case NDEFUN: | 9087 | case NDEFUN: |
9088 | calcsize(n->ndefun.body); | ||
9089 | funcstringsize += strlen(n->ndefun.text) + 1; | ||
9090 | IF_PLATFORM_MINGW32(nodeptrsize += 2); | ||
9091 | break; | ||
8973 | case NARG: | 9092 | case NARG: |
8974 | sizenodelist(n->narg.backquote); | 9093 | sizenodelist(n->narg.backquote); |
8975 | funcstringsize += strlen(n->narg.text) + 1; | 9094 | funcstringsize += strlen(n->narg.text) + 1; |
@@ -9067,6 +9186,7 @@ copynode(union node *n) | |||
9067 | new->ncmd.redirect = copynode(n->ncmd.redirect); | 9186 | new->ncmd.redirect = copynode(n->ncmd.redirect); |
9068 | new->ncmd.args = copynode(n->ncmd.args); | 9187 | new->ncmd.args = copynode(n->ncmd.args); |
9069 | new->ncmd.assign = copynode(n->ncmd.assign); | 9188 | new->ncmd.assign = copynode(n->ncmd.assign); |
9189 | new->ncmd.linno = n->ncmd.linno; | ||
9070 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); | 9190 | SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign); |
9071 | break; | 9191 | break; |
9072 | case NPIPE: | 9192 | case NPIPE: |
@@ -9079,6 +9199,7 @@ copynode(union node *n) | |||
9079 | case NSUBSHELL: | 9199 | case NSUBSHELL: |
9080 | new->nredir.redirect = copynode(n->nredir.redirect); | 9200 | new->nredir.redirect = copynode(n->nredir.redirect); |
9081 | new->nredir.n = copynode(n->nredir.n); | 9201 | new->nredir.n = copynode(n->nredir.n); |
9202 | new->nredir.linno = n->nredir.linno; | ||
9082 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); | 9203 | SAVE_PTR2(new->nredir.redirect,new->nredir.n); |
9083 | break; | 9204 | break; |
9084 | case NAND: | 9205 | case NAND: |
@@ -9100,11 +9221,13 @@ copynode(union node *n) | |||
9100 | new->nfor.var = nodeckstrdup(n->nfor.var); | 9221 | new->nfor.var = nodeckstrdup(n->nfor.var); |
9101 | new->nfor.body = copynode(n->nfor.body); | 9222 | new->nfor.body = copynode(n->nfor.body); |
9102 | new->nfor.args = copynode(n->nfor.args); | 9223 | new->nfor.args = copynode(n->nfor.args); |
9224 | new->nfor.linno = n->nfor.linno; | ||
9103 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); | 9225 | SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args); |
9104 | break; | 9226 | break; |
9105 | case NCASE: | 9227 | case NCASE: |
9106 | new->ncase.cases = copynode(n->ncase.cases); | 9228 | new->ncase.cases = copynode(n->ncase.cases); |
9107 | new->ncase.expr = copynode(n->ncase.expr); | 9229 | new->ncase.expr = copynode(n->ncase.expr); |
9230 | new->ncase.linno = n->ncase.linno; | ||
9108 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); | 9231 | SAVE_PTR2(new->ncase.cases,new->ncase.expr); |
9109 | break; | 9232 | break; |
9110 | case NCLIST: | 9233 | case NCLIST: |
@@ -9114,6 +9237,11 @@ copynode(union node *n) | |||
9114 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); | 9237 | SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next); |
9115 | break; | 9238 | break; |
9116 | case NDEFUN: | 9239 | case NDEFUN: |
9240 | new->ndefun.body = copynode(n->ndefun.body); | ||
9241 | new->ndefun.text = nodeckstrdup(n->ndefun.text); | ||
9242 | new->ndefun.linno = n->ndefun.linno; | ||
9243 | SAVE_PTR2(new->ndefun.body,new->ndefun.text); | ||
9244 | break; | ||
9117 | case NARG: | 9245 | case NARG: |
9118 | new->narg.backquote = copynodelist(n->narg.backquote); | 9246 | new->narg.backquote = copynodelist(n->narg.backquote); |
9119 | new->narg.text = nodeckstrdup(n->narg.text); | 9247 | new->narg.text = nodeckstrdup(n->narg.text); |
@@ -9190,7 +9318,7 @@ defun(union node *func) | |||
9190 | INT_OFF; | 9318 | INT_OFF; |
9191 | entry.cmdtype = CMDFUNCTION; | 9319 | entry.cmdtype = CMDFUNCTION; |
9192 | entry.u.func = copyfunc(func); | 9320 | entry.u.func = copyfunc(func); |
9193 | addcmdentry(func->narg.text, &entry); | 9321 | addcmdentry(func->ndefun.text, &entry); |
9194 | INT_ON; | 9322 | INT_ON; |
9195 | } | 9323 | } |
9196 | 9324 | ||
@@ -9200,8 +9328,8 @@ defun(union node *func) | |||
9200 | #define SKIPFUNC (1 << 2) | 9328 | #define SKIPFUNC (1 << 2) |
9201 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ | 9329 | static smallint evalskip; /* set to SKIPxxx if we are skipping commands */ |
9202 | static int skipcount; /* number of levels to skip */ | 9330 | static int skipcount; /* number of levels to skip */ |
9203 | static int funcnest; /* depth of function calls */ | ||
9204 | static int loopnest; /* current loop nesting level */ | 9331 | static int loopnest; /* current loop nesting level */ |
9332 | static int funcline; /* starting line number of current function, or 0 if not in a function */ | ||
9205 | 9333 | ||
9206 | /* Forward decl way out to parsing code - dotrap needs it */ | 9334 | /* Forward decl way out to parsing code - dotrap needs it */ |
9207 | static int evalstring(char *s, int flags); | 9335 | static int evalstring(char *s, int flags); |
@@ -9296,6 +9424,9 @@ evaltree(union node *n, int flags) | |||
9296 | status = !evaltree(n->nnot.com, EV_TESTED); | 9424 | status = !evaltree(n->nnot.com, EV_TESTED); |
9297 | goto setstatus; | 9425 | goto setstatus; |
9298 | case NREDIR: | 9426 | case NREDIR: |
9427 | errlinno = lineno = n->nredir.linno; | ||
9428 | if (funcline) | ||
9429 | lineno -= funcline - 1; | ||
9299 | expredir(n->nredir.redirect); | 9430 | expredir(n->nredir.redirect); |
9300 | pushredir(n->nredir.redirect); | 9431 | pushredir(n->nredir.redirect); |
9301 | status = redirectsafe(n->nredir.redirect, REDIR_PUSH); | 9432 | status = redirectsafe(n->nredir.redirect, REDIR_PUSH); |
@@ -9450,6 +9581,10 @@ evalfor(union node *n, int flags) | |||
9450 | struct stackmark smark; | 9581 | struct stackmark smark; |
9451 | int status = 0; | 9582 | int status = 0; |
9452 | 9583 | ||
9584 | errlinno = lineno = n->ncase.linno; | ||
9585 | if (funcline) | ||
9586 | lineno -= funcline - 1; | ||
9587 | |||
9453 | setstackmark(&smark); | 9588 | setstackmark(&smark); |
9454 | arglist.list = NULL; | 9589 | arglist.list = NULL; |
9455 | arglist.lastp = &arglist.list; | 9590 | arglist.lastp = &arglist.list; |
@@ -9481,6 +9616,10 @@ evalcase(union node *n, int flags) | |||
9481 | struct stackmark smark; | 9616 | struct stackmark smark; |
9482 | int status = 0; | 9617 | int status = 0; |
9483 | 9618 | ||
9619 | errlinno = lineno = n->ncase.linno; | ||
9620 | if (funcline) | ||
9621 | lineno -= funcline - 1; | ||
9622 | |||
9484 | setstackmark(&smark); | 9623 | setstackmark(&smark); |
9485 | arglist.list = NULL; | 9624 | arglist.list = NULL; |
9486 | arglist.lastp = &arglist.list; | 9625 | arglist.lastp = &arglist.list; |
@@ -9516,6 +9655,10 @@ evalsubshell(union node *n, int flags) | |||
9516 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ | 9655 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
9517 | int status; | 9656 | int status; |
9518 | 9657 | ||
9658 | errlinno = lineno = n->nredir.linno; | ||
9659 | if (funcline) | ||
9660 | lineno -= funcline - 1; | ||
9661 | |||
9519 | expredir(n->nredir.redirect); | 9662 | expredir(n->nredir.redirect); |
9520 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 9663 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
9521 | goto nofork; | 9664 | goto nofork; |
@@ -9846,8 +9989,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
9846 | struct jmploc *volatile savehandler; | 9989 | struct jmploc *volatile savehandler; |
9847 | struct jmploc jmploc; | 9990 | struct jmploc jmploc; |
9848 | int e; | 9991 | int e; |
9992 | int savefuncline; | ||
9849 | 9993 | ||
9850 | saveparam = shellparam; | 9994 | saveparam = shellparam; |
9995 | savefuncline = funcline; | ||
9851 | savehandler = exception_handler; | 9996 | savehandler = exception_handler; |
9852 | e = setjmp(jmploc.loc); | 9997 | e = setjmp(jmploc.loc); |
9853 | if (e) { | 9998 | if (e) { |
@@ -9857,7 +10002,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
9857 | exception_handler = &jmploc; | 10002 | exception_handler = &jmploc; |
9858 | shellparam.malloced = 0; | 10003 | shellparam.malloced = 0; |
9859 | func->count++; | 10004 | func->count++; |
9860 | funcnest++; | 10005 | funcline = func->n.ndefun.linno; |
9861 | INT_ON; | 10006 | INT_ON; |
9862 | shellparam.nparam = argc - 1; | 10007 | shellparam.nparam = argc - 1; |
9863 | shellparam.p = argv + 1; | 10008 | shellparam.p = argv + 1; |
@@ -9866,11 +10011,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
9866 | shellparam.optoff = -1; | 10011 | shellparam.optoff = -1; |
9867 | #endif | 10012 | #endif |
9868 | pushlocalvars(); | 10013 | pushlocalvars(); |
9869 | evaltree(func->n.narg.next, flags & EV_TESTED); | 10014 | evaltree(func->n.ndefun.body, flags & EV_TESTED); |
9870 | poplocalvars(0); | 10015 | poplocalvars(0); |
9871 | funcdone: | 10016 | funcdone: |
9872 | INT_OFF; | 10017 | INT_OFF; |
9873 | funcnest--; | 10018 | funcline = savefuncline; |
9874 | freefunc(func); | 10019 | freefunc(func); |
9875 | freeparam(&shellparam); | 10020 | freeparam(&shellparam); |
9876 | shellparam = saveparam; | 10021 | shellparam = saveparam; |
@@ -10235,6 +10380,10 @@ evalcommand(union node *cmd, int flags) | |||
10235 | char **nargv; | 10380 | char **nargv; |
10236 | smallint cmd_is_exec; | 10381 | smallint cmd_is_exec; |
10237 | 10382 | ||
10383 | errlinno = lineno = cmd->ncmd.linno; | ||
10384 | if (funcline) | ||
10385 | lineno -= funcline - 1; | ||
10386 | |||
10238 | /* First expand the arguments. */ | 10387 | /* First expand the arguments. */ |
10239 | TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); | 10388 | TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); |
10240 | setstackmark(&smark); | 10389 | setstackmark(&smark); |
@@ -10280,7 +10429,7 @@ evalcommand(union node *cmd, int flags) | |||
10280 | *nargv = NULL; | 10429 | *nargv = NULL; |
10281 | 10430 | ||
10282 | lastarg = NULL; | 10431 | lastarg = NULL; |
10283 | if (iflag && funcnest == 0 && argc > 0) | 10432 | if (iflag && funcline == 0 && argc > 0) |
10284 | lastarg = nargv[-1]; | 10433 | lastarg = nargv[-1]; |
10285 | 10434 | ||
10286 | expredir(cmd->ncmd.redirect); | 10435 | expredir(cmd->ncmd.redirect); |
@@ -10410,7 +10559,9 @@ evalcommand(union node *cmd, int flags) | |||
10410 | switch (cmdentry.cmdtype) { | 10559 | switch (cmdentry.cmdtype) { |
10411 | default: { | 10560 | default: { |
10412 | 10561 | ||
10413 | #if ENABLE_FEATURE_SH_NOFORK | 10562 | #if ENABLE_FEATURE_SH_STANDALONE \ |
10563 | && ENABLE_FEATURE_SH_NOFORK \ | ||
10564 | && NUM_APPLETS > 1 | ||
10414 | /* (1) BUG: if variables are set, we need to fork, or save/restore them | 10565 | /* (1) BUG: if variables are set, we need to fork, or save/restore them |
10415 | * around run_nofork_applet() call. | 10566 | * around run_nofork_applet() call. |
10416 | * (2) Should this check also be done in forkshell()? | 10567 | * (2) Should this check also be done in forkshell()? |
@@ -11341,7 +11492,7 @@ shiftcmd(int argc UNUSED_PARAM, char **argv) | |||
11341 | if (argv[1]) | 11492 | if (argv[1]) |
11342 | n = number(argv[1]); | 11493 | n = number(argv[1]); |
11343 | if (n > shellparam.nparam) | 11494 | if (n > shellparam.nparam) |
11344 | n = 0; /* bash compat, was = shellparam.nparam; */ | 11495 | return 1; |
11345 | INT_OFF; | 11496 | INT_OFF; |
11346 | shellparam.nparam -= n; | 11497 | shellparam.nparam -= n; |
11347 | for (ap1 = shellparam.p; --n >= 0; ap1++) { | 11498 | for (ap1 = shellparam.p; --n >= 0; ap1++) { |
@@ -11811,7 +11962,7 @@ parsefname(void) | |||
11811 | if (quoteflag == 0) | 11962 | if (quoteflag == 0) |
11812 | n->type = NXHERE; | 11963 | n->type = NXHERE; |
11813 | TRACE(("Here document %d\n", n->type)); | 11964 | TRACE(("Here document %d\n", n->type)); |
11814 | rmescapes(wordtext, 0); | 11965 | rmescapes(wordtext, 0, NULL); |
11815 | here->eofmark = wordtext; | 11966 | here->eofmark = wordtext; |
11816 | here->next = NULL; | 11967 | here->next = NULL; |
11817 | if (heredoclist == NULL) | 11968 | if (heredoclist == NULL) |
@@ -11836,6 +11987,7 @@ simplecmd(void) | |||
11836 | union node *vars, **vpp; | 11987 | union node *vars, **vpp; |
11837 | union node **rpp, *redir; | 11988 | union node **rpp, *redir; |
11838 | int savecheckkwd; | 11989 | int savecheckkwd; |
11990 | int savelinno; | ||
11839 | #if BASH_TEST2 | 11991 | #if BASH_TEST2 |
11840 | smallint double_brackets_flag = 0; | 11992 | smallint double_brackets_flag = 0; |
11841 | #endif | 11993 | #endif |
@@ -11849,6 +12001,7 @@ simplecmd(void) | |||
11849 | rpp = &redir; | 12001 | rpp = &redir; |
11850 | 12002 | ||
11851 | savecheckkwd = CHKALIAS; | 12003 | savecheckkwd = CHKALIAS; |
12004 | savelinno = g_parsefile->linno; | ||
11852 | for (;;) { | 12005 | for (;;) { |
11853 | int t; | 12006 | int t; |
11854 | checkkwd = savecheckkwd; | 12007 | checkkwd = savecheckkwd; |
@@ -11938,7 +12091,9 @@ simplecmd(void) | |||
11938 | } | 12091 | } |
11939 | n->type = NDEFUN; | 12092 | n->type = NDEFUN; |
11940 | checkkwd = CHKNL | CHKKWD | CHKALIAS; | 12093 | checkkwd = CHKNL | CHKKWD | CHKALIAS; |
11941 | n->narg.next = parse_command(); | 12094 | n->ndefun.text = n->narg.text; |
12095 | n->ndefun.linno = g_parsefile->linno; | ||
12096 | n->ndefun.body = parse_command(); | ||
11942 | return n; | 12097 | return n; |
11943 | } | 12098 | } |
11944 | IF_BASH_FUNCTION(function_flag = 0;) | 12099 | IF_BASH_FUNCTION(function_flag = 0;) |
@@ -11954,6 +12109,7 @@ simplecmd(void) | |||
11954 | *rpp = NULL; | 12109 | *rpp = NULL; |
11955 | n = stzalloc(sizeof(struct ncmd)); | 12110 | n = stzalloc(sizeof(struct ncmd)); |
11956 | n->type = NCMD; | 12111 | n->type = NCMD; |
12112 | n->ncmd.linno = savelinno; | ||
11957 | n->ncmd.args = args; | 12113 | n->ncmd.args = args; |
11958 | n->ncmd.assign = vars; | 12114 | n->ncmd.assign = vars; |
11959 | n->ncmd.redirect = redir; | 12115 | n->ncmd.redirect = redir; |
@@ -11969,10 +12125,13 @@ parse_command(void) | |||
11969 | union node *redir, **rpp; | 12125 | union node *redir, **rpp; |
11970 | union node **rpp2; | 12126 | union node **rpp2; |
11971 | int t; | 12127 | int t; |
12128 | int savelinno; | ||
11972 | 12129 | ||
11973 | redir = NULL; | 12130 | redir = NULL; |
11974 | rpp2 = &redir; | 12131 | rpp2 = &redir; |
11975 | 12132 | ||
12133 | savelinno = g_parsefile->linno; | ||
12134 | |||
11976 | switch (readtoken()) { | 12135 | switch (readtoken()) { |
11977 | default: | 12136 | default: |
11978 | raise_error_unexpected_syntax(-1); | 12137 | raise_error_unexpected_syntax(-1); |
@@ -12023,6 +12182,7 @@ parse_command(void) | |||
12023 | raise_error_syntax("bad for loop variable"); | 12182 | raise_error_syntax("bad for loop variable"); |
12024 | n1 = stzalloc(sizeof(struct nfor)); | 12183 | n1 = stzalloc(sizeof(struct nfor)); |
12025 | n1->type = NFOR; | 12184 | n1->type = NFOR; |
12185 | n1->nfor.linno = savelinno; | ||
12026 | n1->nfor.var = wordtext; | 12186 | n1->nfor.var = wordtext; |
12027 | checkkwd = CHKNL | CHKKWD | CHKALIAS; | 12187 | checkkwd = CHKNL | CHKKWD | CHKALIAS; |
12028 | if (readtoken() == TIN) { | 12188 | if (readtoken() == TIN) { |
@@ -12063,6 +12223,7 @@ parse_command(void) | |||
12063 | case TCASE: | 12223 | case TCASE: |
12064 | n1 = stzalloc(sizeof(struct ncase)); | 12224 | n1 = stzalloc(sizeof(struct ncase)); |
12065 | n1->type = NCASE; | 12225 | n1->type = NCASE; |
12226 | n1->ncase.linno = savelinno; | ||
12066 | if (readtoken() != TWORD) | 12227 | if (readtoken() != TWORD) |
12067 | raise_error_unexpected_syntax(TWORD); | 12228 | raise_error_unexpected_syntax(TWORD); |
12068 | n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); | 12229 | n1->ncase.expr = n2 = stzalloc(sizeof(struct narg)); |
@@ -12114,6 +12275,7 @@ parse_command(void) | |||
12114 | case TLP: | 12275 | case TLP: |
12115 | n1 = stzalloc(sizeof(struct nredir)); | 12276 | n1 = stzalloc(sizeof(struct nredir)); |
12116 | n1->type = NSUBSHELL; | 12277 | n1->type = NSUBSHELL; |
12278 | n1->nredir.linno = savelinno; | ||
12117 | n1->nredir.n = list(0); | 12279 | n1->nredir.n = list(0); |
12118 | /*n1->nredir.redirect = NULL; - stzalloc did it */ | 12280 | /*n1->nredir.redirect = NULL; - stzalloc did it */ |
12119 | t = TRP; | 12281 | t = TRP; |
@@ -12147,6 +12309,7 @@ parse_command(void) | |||
12147 | if (n1->type != NSUBSHELL) { | 12309 | if (n1->type != NSUBSHELL) { |
12148 | n2 = stzalloc(sizeof(struct nredir)); | 12310 | n2 = stzalloc(sizeof(struct nredir)); |
12149 | n2->type = NREDIR; | 12311 | n2->type = NREDIR; |
12312 | n2->nredir.linno = savelinno; | ||
12150 | n2->nredir.n = n1; | 12313 | n2->nredir.n = n1; |
12151 | n1 = n2; | 12314 | n1 = n2; |
12152 | } | 12315 | } |
@@ -12245,10 +12408,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12245 | IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ | 12408 | IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ |
12246 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ | 12409 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ |
12247 | int dqvarnest; /* levels of variables expansion within double quotes */ | 12410 | int dqvarnest; /* levels of variables expansion within double quotes */ |
12248 | |||
12249 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) | 12411 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) |
12250 | 12412 | ||
12251 | startlinno = g_parsefile->linno; | ||
12252 | bqlist = NULL; | 12413 | bqlist = NULL; |
12253 | quotef = 0; | 12414 | quotef = 0; |
12254 | IF_FEATURE_SH_MATH(prevsyntax = 0;) | 12415 | IF_FEATURE_SH_MATH(prevsyntax = 0;) |
@@ -12425,7 +12586,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12425 | if (syntax != BASESYNTAX && eofmark == NULL) | 12586 | if (syntax != BASESYNTAX && eofmark == NULL) |
12426 | raise_error_syntax("unterminated quoted string"); | 12587 | raise_error_syntax("unterminated quoted string"); |
12427 | if (varnest != 0) { | 12588 | if (varnest != 0) { |
12428 | startlinno = g_parsefile->linno; | ||
12429 | /* { */ | 12589 | /* { */ |
12430 | raise_error_syntax("missing '}'"); | 12590 | raise_error_syntax("missing '}'"); |
12431 | } | 12591 | } |
@@ -12817,7 +12977,6 @@ parsebackq: { | |||
12817 | 12977 | ||
12818 | case PEOF: | 12978 | case PEOF: |
12819 | IF_ASH_ALIAS(case PEOA:) | 12979 | IF_ASH_ALIAS(case PEOA:) |
12820 | startlinno = g_parsefile->linno; | ||
12821 | raise_error_syntax("EOF in backquote substitution"); | 12980 | raise_error_syntax("EOF in backquote substitution"); |
12822 | 12981 | ||
12823 | case '\n': | 12982 | case '\n': |
@@ -12899,8 +13058,6 @@ parsearith: { | |||
12899 | * quoted. | 13058 | * quoted. |
12900 | * If the token is TREDIR, then we set redirnode to a structure containing | 13059 | * If the token is TREDIR, then we set redirnode to a structure containing |
12901 | * the redirection. | 13060 | * the redirection. |
12902 | * In all cases, the variable startlinno is set to the number of the line | ||
12903 | * on which the token starts. | ||
12904 | * | 13061 | * |
12905 | * [Change comment: here documents and internal procedures] | 13062 | * [Change comment: here documents and internal procedures] |
12906 | * [Readtoken shouldn't have any arguments. Perhaps we should make the | 13063 | * [Readtoken shouldn't have any arguments. Perhaps we should make the |
@@ -12938,7 +13095,6 @@ xxreadtoken(void) | |||
12938 | return lasttoken; | 13095 | return lasttoken; |
12939 | } | 13096 | } |
12940 | setprompt_if(needprompt, 2); | 13097 | setprompt_if(needprompt, 2); |
12941 | startlinno = g_parsefile->linno; | ||
12942 | for (;;) { /* until token or start of word found */ | 13098 | for (;;) { /* until token or start of word found */ |
12943 | c = pgetc(); | 13099 | c = pgetc(); |
12944 | if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) | 13100 | if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) |
@@ -12999,7 +13155,6 @@ xxreadtoken(void) | |||
12999 | return lasttoken; | 13155 | return lasttoken; |
13000 | } | 13156 | } |
13001 | setprompt_if(needprompt, 2); | 13157 | setprompt_if(needprompt, 2); |
13002 | startlinno = g_parsefile->linno; | ||
13003 | for (;;) { /* until token or start of word found */ | 13158 | for (;;) { /* until token or start of word found */ |
13004 | c = pgetc(); | 13159 | c = pgetc(); |
13005 | switch (c) { | 13160 | switch (c) { |
@@ -13391,10 +13546,14 @@ find_dot_file(char *name) | |||
13391 | if (fullname != name) | 13546 | if (fullname != name) |
13392 | stunalloc(fullname); | 13547 | stunalloc(fullname); |
13393 | } | 13548 | } |
13549 | /* not found in PATH */ | ||
13394 | 13550 | ||
13395 | /* not found in the PATH */ | 13551 | #if ENABLE_ASH_BASH_SOURCE_CURDIR |
13552 | return name; | ||
13553 | #else | ||
13396 | ash_msg_and_raise_error("%s: not found", name); | 13554 | ash_msg_and_raise_error("%s: not found", name); |
13397 | /* NOTREACHED */ | 13555 | /* NOTREACHED */ |
13556 | #endif | ||
13398 | } | 13557 | } |
13399 | 13558 | ||
13400 | static int FAST_FUNC | 13559 | static int FAST_FUNC |
@@ -13689,8 +13848,21 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13689 | /* We failed. If there was an entry for this command, delete it */ | 13848 | /* We failed. If there was an entry for this command, delete it */ |
13690 | if (cmdp && updatetbl) | 13849 | if (cmdp && updatetbl) |
13691 | delete_cmd_entry(); | 13850 | delete_cmd_entry(); |
13692 | if (act & DO_ERR) | 13851 | if (act & DO_ERR) { |
13852 | #if ENABLE_ASH_BASH_NOT_FOUND_HOOK | ||
13853 | struct tblentry *hookp = cmdlookup("command_not_found_handle", 0); | ||
13854 | if (hookp && hookp->cmdtype == CMDFUNCTION) { | ||
13855 | char *argv[3]; | ||
13856 | argv[0] = (char*) "command_not_found_handle"; | ||
13857 | argv[1] = name; | ||
13858 | argv[2] = NULL; | ||
13859 | evalfun(hookp->param.func, 2, argv, 0); | ||
13860 | entry->cmdtype = CMDUNKNOWN; | ||
13861 | return; | ||
13862 | } | ||
13863 | #endif | ||
13693 | ash_msg("%s: %s", name, errmsg(e, "not found")); | 13864 | ash_msg("%s: %s", name, errmsg(e, "not found")); |
13865 | } | ||
13694 | entry->cmdtype = CMDUNKNOWN; | 13866 | entry->cmdtype = CMDUNKNOWN; |
13695 | return; | 13867 | return; |
13696 | 13868 | ||