aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-02-18 09:11:07 +0000
committerRon Yorston <rmy@pobox.com>2020-02-18 10:16:24 +0000
commitd7a88599bd88035b1eeae276140f0ce9e405c271 (patch)
tree88ce3b05250cdb046130d5c443db3f03adff95c5
parent56d1d4639c705537a8661ff0005392b82b0ee039 (diff)
parent22c75924daa41b7ea097796afd4baafa2fc99d05 (diff)
downloadbusybox-w32-d7a88599bd88035b1eeae276140f0ce9e405c271.tar.gz
busybox-w32-d7a88599bd88035b1eeae276140f0ce9e405c271.tar.bz2
busybox-w32-d7a88599bd88035b1eeae276140f0ce9e405c271.zip
Merge branch 'busybox' into merge
-rw-r--r--include/libbb.h2
-rw-r--r--shell/ash.c330
-rw-r--r--shell/ash_test/ash-psubst/tick_in_heredoc.right5
-rwxr-xr-xshell/ash_test/ash-psubst/tick_in_heredoc.tests7
-rw-r--r--shell/ash_test/ash-vars/var_10.right3
-rwxr-xr-xshell/ash_test/ash-vars/var_10.tests4
-rw-r--r--shell/hush_test/hush-psubst/tick_in_heredoc.right5
-rwxr-xr-xshell/hush_test/hush-psubst/tick_in_heredoc.tests7
-rw-r--r--shell/hush_test/hush-vars/var_10.right3
-rwxr-xr-xshell/hush_test/hush-vars/var_10.tests4
10 files changed, 236 insertions, 134 deletions
diff --git a/include/libbb.h b/include/libbb.h
index cbb178c0b..8979665b2 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -2210,9 +2210,11 @@ extern const char bb_busybox_exec_path[] ALIGN1;
2210#if !ENABLE_PLATFORM_MINGW32 2210#if !ENABLE_PLATFORM_MINGW32
2211#define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH 2211#define BB_PATH_ROOT_PATH "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH
2212#define PATH_SEP ':' 2212#define PATH_SEP ':'
2213#define PATH_SEP_STR ":"
2213#else 2214#else
2214#define BB_PATH_ROOT_PATH "PATH=/sbin;/usr/sbin;/bin;/usr/bin" BB_ADDITIONAL_PATH 2215#define BB_PATH_ROOT_PATH "PATH=/sbin;/usr/sbin;/bin;/usr/bin" BB_ADDITIONAL_PATH
2215#define PATH_SEP ';' 2216#define PATH_SEP ';'
2217#define PATH_SEP_STR ";"
2216#endif 2218#endif
2217extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */ 2219extern const char bb_PATH_root_path[] ALIGN1; /* BB_PATH_ROOT_PATH */
2218#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) 2220#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
diff --git a/shell/ash.c b/shell/ash.c
index c6eb930e4..4c143b8e9 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1900,6 +1900,15 @@ growstackstr(void)
1900 return (char *)stackblock() + len; 1900 return (char *)stackblock() + len;
1901} 1901}
1902 1902
1903static char *
1904growstackto(size_t len)
1905{
1906 while (stackblocksize() < len)
1907 growstackblock();
1908
1909 return stackblock();
1910}
1911
1903/* 1912/*
1904 * Called from CHECKSTRSPACE. 1913 * Called from CHECKSTRSPACE.
1905 */ 1914 */
@@ -1907,18 +1916,8 @@ static char *
1907makestrspace(size_t newlen, char *p) 1916makestrspace(size_t newlen, char *p)
1908{ 1917{
1909 size_t len = p - g_stacknxt; 1918 size_t len = p - g_stacknxt;
1910 size_t size;
1911 1919
1912 for (;;) { 1920 return growstackto(len + newlen) + len;
1913 size_t nleft;
1914
1915 size = stackblocksize();
1916 nleft = size - len;
1917 if (nleft >= newlen)
1918 break;
1919 growstackblock();
1920 }
1921 return (char *)stackblock() + len;
1922} 1921}
1923 1922
1924static char * 1923static char *
@@ -2775,53 +2774,103 @@ listvars(int on, int off, struct strlist *lp, char ***end)
2775} 2774}
2776 2775
2777 2776
2778/* ============ Path search helper 2777/* ============ Path search helper */
2779 * 2778static const char *
2779legal_pathopt(const char *opt, const char *term, int magic)
2780{
2781 switch (magic) {
2782 case 0:
2783 opt = NULL;
2784 break;
2785
2786 case 1:
2787 opt = prefix(opt, "builtin") ?: prefix(opt, "func");
2788 break;
2789
2790 default:
2791 opt += strcspn(opt, term);
2792 break;
2793 }
2794
2795 if (opt && *opt == '%')
2796 opt++;
2797
2798 return opt;
2799}
2800
2801/*
2780 * The variable path (passed by reference) should be set to the start 2802 * The variable path (passed by reference) should be set to the start
2781 * of the path before the first call; path_advance will update 2803 * of the path before the first call; padvance will update
2782 * this value as it proceeds. Successive calls to path_advance will return 2804 * this value as it proceeds. Successive calls to padvance will return
2783 * the possible path expansions in sequence. If an option (indicated by 2805 * the possible path expansions in sequence. If an option (indicated by
2784 * a percent sign) appears in the path entry then the global variable 2806 * a percent sign) appears in the path entry then the global variable
2785 * pathopt will be set to point to it; otherwise pathopt will be set to 2807 * pathopt will be set to point to it; otherwise pathopt will be set to
2786 * NULL. 2808 * NULL.
2809 *
2810 * If magic is 0 then pathopt recognition will be disabled. If magic is
2811 * 1 we shall recognise %builtin/%func. Otherwise we shall accept any
2812 * pathopt.
2787 */ 2813 */
2788static const char *pathopt; /* set by path_advance */ 2814static const char *pathopt; /* set by padvance */
2789 2815
2790static char * 2816static int
2791path_advance(const char **path, const char *name) 2817padvance_magic(const char **path, const char *name, int magic)
2792{ 2818{
2819 const char *term = "%"PATH_SEP_STR;
2820 const char *lpathopt;
2793 const char *p; 2821 const char *p;
2794 char *q; 2822 char *q;
2795 const char *start; 2823 const char *start;
2824 size_t qlen;
2796 size_t len; 2825 size_t len;
2797 2826
2798 if (*path == NULL) 2827 if (*path == NULL)
2799 return NULL; 2828 return -1;
2829
2830 lpathopt = NULL;
2800 start = *path; 2831 start = *path;
2801 for (p = start; *p && *p != PATH_SEP && *p != '%'; p++)
2802 continue;
2803 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2804 2832
2833 if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
2834 lpathopt = start + 1;
2835 start = p;
2836 term = PATH_SEP_STR;
2837 }
2838
2839 len = strcspn(start, term);
2840 p = start + len;
2841
2842 if (*p == '%') {
2843 size_t extra = strchrnul(p, PATH_SEP) - p;
2844
2845 if (legal_pathopt(p + 1, term, magic))
2846 lpathopt = p + 1;
2847 else
2848 len += extra;
2849
2850 p += extra;
2851 }
2852
2853 pathopt = lpathopt;
2854 *path = *p == PATH_SEP ? p + 1 : NULL;
2855
2856 /* "2" is for '/' and '\0' */
2805 /* reserve space for suffix on WIN32 */ 2857 /* reserve space for suffix on WIN32 */
2806 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len)) 2858 qlen = len + strlen(name) + 2 IF_PLATFORM_MINGW32(+ 4);
2807 growstackblock(); 2859 q = growstackto(qlen);
2808 q = stackblock(); 2860
2809 if (p != start) { 2861 if (len) {
2810 q = mempcpy(q, start, p - start); 2862 q = mempcpy(q, start, len);
2811 *q++ = '/'; 2863 *q++ = '/';
2812 } 2864 }
2813 strcpy(q, name); 2865 strcpy(q, name);
2814 pathopt = NULL; 2866
2815 if (*p == '%') { 2867 return qlen;
2816 pathopt = ++p; 2868}
2817 while (*p && *p != PATH_SEP) 2869
2818 p++; 2870static int
2819 } 2871padvance(const char **path, const char *name)
2820 if (*p == PATH_SEP) 2872{
2821 *path = p + 1; 2873 return padvance_magic(path, name, 1);
2822 else
2823 *path = NULL;
2824 return stalloc(len);
2825} 2874}
2826 2875
2827 2876
@@ -3179,6 +3228,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3179 char c; 3228 char c;
3180 struct stat statb; 3229 struct stat statb;
3181 int flags; 3230 int flags;
3231 int len;
3182 3232
3183 flags = cdopt(); 3233 flags = cdopt();
3184 dest = *argptr; 3234 dest = *argptr;
@@ -3208,9 +3258,10 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3208 if (!*dest) 3258 if (!*dest)
3209 dest = "."; 3259 dest = ".";
3210 path = bltinlookup("CDPATH"); 3260 path = bltinlookup("CDPATH");
3211 while (path) { 3261 while (p = path, (len = padvance(&path, dest)) >= 0) {
3212 c = *path; 3262 c = *p;
3213 p = path_advance(&path, dest); 3263 p = stalloc(len);
3264
3214 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 3265 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
3215 if (c && c != PATH_SEP) 3266 if (c && c != PATH_SEP)
3216 flags |= CD_PRINT; 3267 flags |= CD_PRINT;
@@ -7109,8 +7160,8 @@ expbackq(union node *cmd, int flag)
7109 7160
7110 /* Eat all trailing newlines */ 7161 /* Eat all trailing newlines */
7111 dest = expdest; 7162 dest = expdest;
7112 for (; dest > (char *)stackblock() && (dest[-1] == '\n' || 7163 for (; dest > ((char *)stackblock() + startloc) && (dest[-1] == '\n'
7113 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));) 7164 IF_PLATFORM_MINGW32(|| dest[-1] == '\r'));)
7114 STUNPUTC(dest); 7165 STUNPUTC(dest);
7115 expdest = dest; 7166 expdest = dest;
7116 7167
@@ -8718,13 +8769,13 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8718 } else { 8769 } else {
8719 try_PATH: 8770 try_PATH:
8720 e = ENOENT; 8771 e = ENOENT;
8721 while ((cmdname = path_advance(&path, prog)) != NULL) { 8772 while (padvance(&path, argv[0]) >= 0) {
8773 cmdname = stackblock();
8722 if (--idx < 0 && pathopt == NULL) { 8774 if (--idx < 0 && pathopt == NULL) {
8723 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp); 8775 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
8724 if (errno != ENOENT && errno != ENOTDIR) 8776 if (errno != ENOENT && errno != ENOTDIR)
8725 e = errno; 8777 e = errno;
8726 } 8778 }
8727 stunalloc(cmdname);
8728 } 8779 }
8729 } 8780 }
8730 8781
@@ -8757,9 +8808,9 @@ printentry(struct tblentry *cmdp)
8757 idx = cmdp->param.index; 8808 idx = cmdp->param.index;
8758 path = pathval(); 8809 path = pathval();
8759 do { 8810 do {
8760 name = path_advance(&path, cmdp->cmdname); 8811 padvance(&path, cmdp->cmdname);
8761 stunalloc(name);
8762 } while (--idx >= 0); 8812 } while (--idx >= 0);
8813 name = stackblock();
8763#if ENABLE_PLATFORM_MINGW32 8814#if ENABLE_PLATFORM_MINGW32
8764 add_win32_extension(name); 8815 add_win32_extension(name);
8765#endif 8816#endif
@@ -8767,11 +8818,10 @@ printentry(struct tblentry *cmdp)
8767} 8818}
8768 8819
8769/* 8820/*
8770 * Clear out command entries. The argument specifies the first entry in 8821 * Clear out command entries.
8771 * PATH which has changed.
8772 */ 8822 */
8773static void 8823static void
8774clearcmdentry(int firstchange) 8824clearcmdentry(void)
8775{ 8825{
8776 struct tblentry **tblp; 8826 struct tblentry **tblp;
8777 struct tblentry **pp; 8827 struct tblentry **pp;
@@ -8781,10 +8831,11 @@ clearcmdentry(int firstchange)
8781 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { 8831 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
8782 pp = tblp; 8832 pp = tblp;
8783 while ((cmdp = *pp) != NULL) { 8833 while ((cmdp = *pp) != NULL) {
8784 if ((cmdp->cmdtype == CMDNORMAL && 8834 if (cmdp->cmdtype == CMDNORMAL
8785 cmdp->param.index >= firstchange) 8835 || (cmdp->cmdtype == CMDBUILTIN
8786 || (cmdp->cmdtype == CMDBUILTIN && 8836 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8787 builtinloc >= firstchange) 8837 && builtinloc > 0
8838 )
8788 ) { 8839 ) {
8789 *pp = cmdp->next; 8840 *pp = cmdp->next;
8790 free(cmdp); 8841 free(cmdp);
@@ -8884,7 +8935,7 @@ hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8884 char *name; 8935 char *name;
8885 8936
8886 if (nextopt("r") != '\0') { 8937 if (nextopt("r") != '\0') {
8887 clearcmdentry(0); 8938 clearcmdentry();
8888 return 0; 8939 return 0;
8889 } 8940 }
8890 8941
@@ -8903,7 +8954,11 @@ hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8903 cmdp = cmdlookup(name, 0); 8954 cmdp = cmdlookup(name, 0);
8904 if (cmdp != NULL 8955 if (cmdp != NULL
8905 && (cmdp->cmdtype == CMDNORMAL 8956 && (cmdp->cmdtype == CMDNORMAL
8906 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) 8957 || (cmdp->cmdtype == CMDBUILTIN
8958 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
8959 && builtinloc > 0
8960 )
8961 )
8907 ) { 8962 ) {
8908 delete_cmd_entry(); 8963 delete_cmd_entry();
8909 } 8964 }
@@ -8945,42 +9000,28 @@ hashcd(void)
8945 * Called with interrupts off. 9000 * Called with interrupts off.
8946 */ 9001 */
8947static void FAST_FUNC 9002static void FAST_FUNC
8948changepath(const char *new) 9003changepath(const char *newval)
8949{ 9004{
8950 const char *old; 9005 const char *new;
8951 int firstchange;
8952 int idx; 9006 int idx;
8953 int idx_bltin; 9007 int bltin;
8954 9008
8955 old = pathval(); 9009 new = newval;
8956 firstchange = 9999; /* assume no change */
8957 idx = 0; 9010 idx = 0;
8958 idx_bltin = -1; 9011 bltin = -1;
8959 for (;;) { 9012 for (;;) {
8960 if (*old != *new) { 9013 if (*new == '%' && prefix(new + 1, "builtin")) {
8961 firstchange = idx; 9014 bltin = idx;
8962 if ((*old == '\0' && *new == PATH_SEP) 9015 break;
8963 || (*old == PATH_SEP && *new == '\0')
8964 ) {
8965 firstchange++;
8966 }
8967 old = new; /* ignore subsequent differences */
8968 } 9016 }
8969 if (*new == '\0') 9017 new = strchr(new, PATH_SEP);
9018 if (!new)
8970 break; 9019 break;
8971 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 9020 idx++;
8972 idx_bltin = idx;
8973 if (*new == PATH_SEP)
8974 idx++;
8975 new++; 9021 new++;
8976 old++;
8977 } 9022 }
8978 if (builtinloc < 0 && idx_bltin >= 0) 9023 builtinloc = bltin;
8979 builtinloc = idx_bltin; /* zap builtins */ 9024 clearcmdentry();
8980 if (builtinloc >= 0 && idx_bltin < 0)
8981 firstchange = 0;
8982 clearcmdentry(firstchange);
8983 builtinloc = idx_bltin;
8984} 9025}
8985enum { 9026enum {
8986 TEOF, 9027 TEOF,
@@ -9155,9 +9196,9 @@ describe_command(char *command, const char *path, int describe_command_verbose)
9155 p = command; 9196 p = command;
9156 } else { 9197 } else {
9157 do { 9198 do {
9158 p = path_advance(&path, command); 9199 padvance(&path, command);
9159 stunalloc(p);
9160 } while (--j >= 0); 9200 } while (--j >= 0);
9201 p = stackblock();
9161 } 9202 }
9162#if ENABLE_PLATFORM_MINGW32 9203#if ENABLE_PLATFORM_MINGW32
9163 add_win32_extension(p); 9204 add_win32_extension(p);
@@ -11736,8 +11777,12 @@ chkmail(void)
11736 mpath = mpathset() ? mpathval() : mailval(); 11777 mpath = mpathset() ? mpathval() : mailval();
11737 new_hash = 0; 11778 new_hash = 0;
11738 for (;;) { 11779 for (;;) {
11739 p = path_advance(&mpath, nullstr); 11780 int len;
11740 if (p == NULL) 11781
11782 len = padvance_magic(&mpath, nullstr, 2);
11783 if (!len)
11784 break;
11785 p = stackblock();
11741 break; 11786 break;
11742 if (*p == '\0') 11787 if (*p == '\0')
11743 continue; 11788 continue;
@@ -13338,7 +13383,7 @@ parsesub: {
13338 do { 13383 do {
13339 STPUTC(c, out); 13384 STPUTC(c, out);
13340 c = pgetc_eatbnl(); 13385 c = pgetc_eatbnl();
13341 } while (isdigit(c)); 13386 } while (!subtype && isdigit(c));
13342 } else if (c != '}') { 13387 } else if (c != '}') {
13343 /* $[{[#]]<specialchar>[}] */ 13388 /* $[{[#]]<specialchar>[}] */
13344 int cc = c; 13389 int cc = c;
@@ -13469,6 +13514,7 @@ parsebackq: {
13469 union node *n; 13514 union node *n;
13470 char *str; 13515 char *str;
13471 size_t savelen; 13516 size_t savelen;
13517 struct heredoc *saveheredoclist;
13472 smallint saveprompt = 0; 13518 smallint saveprompt = 0;
13473 13519
13474 str = NULL; 13520 str = NULL;
@@ -13544,6 +13590,9 @@ parsebackq: {
13544 *nlpp = stzalloc(sizeof(**nlpp)); 13590 *nlpp = stzalloc(sizeof(**nlpp));
13545 /* (*nlpp)->next = NULL; - stzalloc did it */ 13591 /* (*nlpp)->next = NULL; - stzalloc did it */
13546 13592
13593 saveheredoclist = heredoclist;
13594 heredoclist = NULL;
13595
13547 if (oldstyle) { 13596 if (oldstyle) {
13548 saveprompt = doprompt; 13597 saveprompt = doprompt;
13549 doprompt = 0; 13598 doprompt = 0;
@@ -13553,21 +13602,22 @@ parsebackq: {
13553 13602
13554 if (oldstyle) 13603 if (oldstyle)
13555 doprompt = saveprompt; 13604 doprompt = saveprompt;
13556 else if (readtoken() != TRP) 13605 else {
13557 raise_error_unexpected_syntax(TRP); 13606 if (readtoken() != TRP)
13607 raise_error_unexpected_syntax(TRP);
13608 setinputstring(nullstr);
13609 parseheredoc();
13610 }
13611
13612 heredoclist = saveheredoclist;
13558 13613
13559 (*nlpp)->n = n; 13614 (*nlpp)->n = n;
13560 if (oldstyle) { 13615 /* Start reading from old file again. */
13561 /* 13616 popfile();
13562 * Start reading from old file again, ignoring any pushed back 13617 /* Ignore any pushed back tokens left from the backquote parsing. */
13563 * tokens left from the backquote parsing 13618 if (oldstyle)
13564 */
13565 popfile();
13566 tokpushback = 0; 13619 tokpushback = 0;
13567 } 13620 out = growstackto(savelen + 1);
13568 while (stackblocksize() <= savelen)
13569 growstackblock();
13570 STARTSTACKSTR(out);
13571 if (str) { 13621 if (str) {
13572 memcpy(out, str, savelen); 13622 memcpy(out, str, savelen);
13573 STADJUST(savelen, out); 13623 STADJUST(savelen, out);
@@ -14078,33 +14128,32 @@ cmdloop(int top)
14078 * search for the file, which is necessary to find sub-commands. 14128 * search for the file, which is necessary to find sub-commands.
14079 */ 14129 */
14080static char * 14130static char *
14081find_dot_file(char *name) 14131find_dot_file(char *basename)
14082{ 14132{
14083 char *fullname; 14133 char *fullname;
14084 const char *path = pathval(); 14134 const char *path = pathval();
14085 struct stat statb; 14135 struct stat statb;
14136 int len;
14086 14137
14087 /* don't try this for absolute or relative paths */ 14138 /* don't try this for absolute or relative paths */
14088 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) 14139 if (strchr(basename, '/') IF_PLATFORM_MINGW32(|| strchr(basename, '\\')))
14089 return name; 14140 return basename;
14090 14141
14091 while ((fullname = path_advance(&path, name)) != NULL) { 14142 while ((len = padvance(&path, basename)) >= 0) {
14092 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 14143 fullname = stackblock();
14093 /* 14144 if ((!pathopt || *pathopt == 'f')
14094 * Don't bother freeing here, since it will 14145 && !stat(fullname, &statb) && S_ISREG(statb.st_mode)
14095 * be freed by the caller. 14146 ) {
14096 */ 14147 /* This will be freed by the caller. */
14097 return fullname; 14148 return stalloc(len);
14098 } 14149 }
14099 if (fullname != name)
14100 stunalloc(fullname);
14101 } 14150 }
14102 /* not found in PATH */ 14151 /* not found in PATH */
14103 14152
14104#if ENABLE_ASH_BASH_SOURCE_CURDIR 14153#if ENABLE_ASH_BASH_SOURCE_CURDIR
14105 return name; 14154 return basename;
14106#else 14155#else
14107 ash_msg_and_raise_error("%s: not found", name); 14156 ash_msg_and_raise_error("%s: not found", basename);
14108 /* NOTREACHED */ 14157 /* NOTREACHED */
14109#endif 14158#endif
14110} 14159}
@@ -14207,6 +14256,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14207 int e; 14256 int e;
14208 int updatetbl; 14257 int updatetbl;
14209 struct builtincmd *bcmd; 14258 struct builtincmd *bcmd;
14259 int len;
14210 14260
14211 /* If name contains a slash, don't use PATH or hash table */ 14261 /* If name contains a slash, don't use PATH or hash table */
14212 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { 14262 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
@@ -14255,7 +14305,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14255 bit = DO_NOFUNC; 14305 bit = DO_NOFUNC;
14256 break; 14306 break;
14257 case CMDBUILTIN: 14307 case CMDBUILTIN:
14258 bit = DO_ALTBLTIN; 14308 bit = IS_BUILTIN_REGULAR(cmdp->param.cmd) ? 0 : DO_ALTBLTIN;
14259 break; 14309 break;
14260 } 14310 }
14261 if (act & bit) { 14311 if (act & bit) {
@@ -14302,20 +14352,20 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14302 e = ENOENT; 14352 e = ENOENT;
14303 idx = -1; 14353 idx = -1;
14304 loop: 14354 loop:
14305 while ((fullname = path_advance(&path, name)) != NULL) { 14355 while ((len = padvance(&path, name)) >= 0) {
14306 stunalloc(fullname); 14356 const char *lpathopt = pathopt;
14307 /* NB: code below will still use fullname 14357
14308 * despite it being "unallocated" */ 14358 fullname = stackblock();
14309 idx++; 14359 idx++;
14310 if (pathopt) { 14360 if (lpathopt) {
14311 if (prefix(pathopt, "builtin")) { 14361 if (*lpathopt == 'b') {
14312 if (bcmd) 14362 if (bcmd)
14313 goto builtin_success; 14363 goto builtin_success;
14314 continue; 14364 continue;
14315 } 14365 } else if (!(act & DO_NOFUNC)) {
14316 if ((act & DO_NOFUNC) 14366 /* handled below */
14317 || !prefix(pathopt, "func") 14367 } else {
14318 ) { /* ignore unimplemented options */ 14368 /* ignore unimplemented options */
14319 continue; 14369 continue;
14320 } 14370 }
14321 } 14371 }
@@ -14341,8 +14391,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14341 e = EACCES; /* if we fail, this will be the error */ 14391 e = EACCES; /* if we fail, this will be the error */
14342 if (!S_ISREG(statb.st_mode)) 14392 if (!S_ISREG(statb.st_mode))
14343 continue; 14393 continue;
14344 if (pathopt) { /* this is a %func directory */ 14394 if (lpathopt) { /* this is a %func directory */
14345 stalloc(strlen(fullname) + 1); 14395 stalloc(len);
14346 /* NB: stalloc will return space pointed by fullname 14396 /* NB: stalloc will return space pointed by fullname
14347 * (because we don't have any intervening allocations 14397 * (because we don't have any intervening allocations
14348 * between stunalloc above and this stalloc) */ 14398 * between stunalloc above and this stalloc) */
@@ -15145,11 +15195,11 @@ read_profile(const char *name)
15145 15195
15146/* 15196/*
15147 * This routine is called when an error or an interrupt occurs in an 15197 * This routine is called when an error or an interrupt occurs in an
15148 * interactive shell and control is returned to the main command loop. 15198 * interactive shell and control is returned to the main command loop
15149 * (In dash, this function is auto-generated by build machinery). 15199 * but prior to exitshell.
15150 */ 15200 */
15151static void 15201static void
15152reset(void) 15202exitreset(void)
15153{ 15203{
15154 /* from eval.c: */ 15204 /* from eval.c: */
15155 evalskip = 0; 15205 evalskip = 0;
@@ -15162,14 +15212,23 @@ reset(void)
15162 /* from expand.c: */ 15212 /* from expand.c: */
15163 ifsfree(); 15213 ifsfree();
15164 15214
15215 /* from redir.c: */
15216 unwindredir(NULL);
15217}
15218
15219/*
15220 * This routine is called when an error or an interrupt occurs in an
15221 * interactive shell and control is returned to the main command loop.
15222 * (In dash, this function is auto-generated by build machinery).
15223 */
15224static void
15225reset(void)
15226{
15165 /* from input.c: */ 15227 /* from input.c: */
15166 g_parsefile->left_in_buffer = 0; 15228 g_parsefile->left_in_buffer = 0;
15167 g_parsefile->left_in_line = 0; /* clear input buffer */ 15229 g_parsefile->left_in_line = 0; /* clear input buffer */
15168 popallfiles(); 15230 popallfiles();
15169 15231
15170 /* from redir.c: */
15171 unwindredir(NULL);
15172
15173 /* from var.c: */ 15232 /* from var.c: */
15174 unwindlocalvars(NULL); 15233 unwindlocalvars(NULL);
15175} 15234}
@@ -15220,13 +15279,16 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15220 smallint e; 15279 smallint e;
15221 smallint s; 15280 smallint s;
15222 15281
15223 reset(); 15282 exitreset();
15224 15283
15225 e = exception_type; 15284 e = exception_type;
15226 s = state; 15285 s = state;
15227 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 15286 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
15228 exitshell(); 15287 exitshell();
15229 } 15288 }
15289
15290 reset();
15291
15230 if (e == EXINT) { 15292 if (e == EXINT) {
15231 newline_and_flush(stderr); 15293 newline_and_flush(stderr);
15232 } 15294 }
diff --git a/shell/ash_test/ash-psubst/tick_in_heredoc.right b/shell/ash_test/ash-psubst/tick_in_heredoc.right
new file mode 100644
index 000000000..7e7bac6d3
--- /dev/null
+++ b/shell/ash_test/ash-psubst/tick_in_heredoc.right
@@ -0,0 +1,5 @@
11
2
32
4
53
diff --git a/shell/ash_test/ash-psubst/tick_in_heredoc.tests b/shell/ash_test/ash-psubst/tick_in_heredoc.tests
new file mode 100755
index 000000000..c8eb8f4f4
--- /dev/null
+++ b/shell/ash_test/ash-psubst/tick_in_heredoc.tests
@@ -0,0 +1,7 @@
1cat <<END
21
3$(echo "")
42
5`echo ""`
63
7END
diff --git a/shell/ash_test/ash-vars/var_10.right b/shell/ash_test/ash-vars/var_10.right
new file mode 100644
index 000000000..675ab45f6
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_10.right
@@ -0,0 +1,3 @@
1Zero:0
2One:1
3Done:0
diff --git a/shell/ash_test/ash-vars/var_10.tests b/shell/ash_test/ash-vars/var_10.tests
new file mode 100755
index 000000000..7364efb55
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_10.tests
@@ -0,0 +1,4 @@
1set -- : 2 3 4 5 6 7 8 9 ten eleven
2echo Zero$10
3echo One$11
4echo Done:$?
diff --git a/shell/hush_test/hush-psubst/tick_in_heredoc.right b/shell/hush_test/hush-psubst/tick_in_heredoc.right
new file mode 100644
index 000000000..7e7bac6d3
--- /dev/null
+++ b/shell/hush_test/hush-psubst/tick_in_heredoc.right
@@ -0,0 +1,5 @@
11
2
32
4
53
diff --git a/shell/hush_test/hush-psubst/tick_in_heredoc.tests b/shell/hush_test/hush-psubst/tick_in_heredoc.tests
new file mode 100755
index 000000000..c8eb8f4f4
--- /dev/null
+++ b/shell/hush_test/hush-psubst/tick_in_heredoc.tests
@@ -0,0 +1,7 @@
1cat <<END
21
3$(echo "")
42
5`echo ""`
63
7END
diff --git a/shell/hush_test/hush-vars/var_10.right b/shell/hush_test/hush-vars/var_10.right
new file mode 100644
index 000000000..675ab45f6
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_10.right
@@ -0,0 +1,3 @@
1Zero:0
2One:1
3Done:0
diff --git a/shell/hush_test/hush-vars/var_10.tests b/shell/hush_test/hush-vars/var_10.tests
new file mode 100755
index 000000000..7364efb55
--- /dev/null
+++ b/shell/hush_test/hush-vars/var_10.tests
@@ -0,0 +1,4 @@
1set -- : 2 3 4 5 6 7 8 9 ten eleven
2echo Zero$10
3echo One$11
4echo Done:$?