diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-02 16:31:29 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-02 16:31:29 +0000 |
commit | 2f1d394214c968181e9ab320f2c66f905f8352cf (patch) | |
tree | af349bf87374251f9c49c2edeeb8fc0168d70d92 /shell | |
parent | b29eb6ed255ad87f49b70220d254810063c7ebf3 (diff) | |
download | busybox-w32-2f1d394214c968181e9ab320f2c66f905f8352cf.tar.gz busybox-w32-2f1d394214c968181e9ab320f2c66f905f8352cf.tar.bz2 busybox-w32-2f1d394214c968181e9ab320f2c66f905f8352cf.zip |
hush: make
a=55; echo $(($a + 1)) $((1 + $((2)) + `echo $a`))
work as expected
function old new delta
handle_dollar - 667 +667
parse_stream_dquoted - 316 +316
expand_variables 2124 2272 +148
is_assignment 134 215 +81
parse_stream 2038 1240 -798
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/1 up/down: 1212/-798) Total: 414 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 220 |
1 files changed, 164 insertions, 56 deletions
diff --git a/shell/hush.c b/shell/hush.c index 3725191d8..64b6e87e8 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1510,7 +1510,7 @@ static void debug_print_list(const char *prefix, o_string *o, int n) | |||
1510 | } | 1510 | } |
1511 | if (n) { | 1511 | if (n) { |
1512 | const char *p = o->data + (int)list[n - 1] + string_start; | 1512 | const char *p = o->data + (int)list[n - 1] + string_start; |
1513 | fprintf(stderr, " total_sz:%ld\n", (p + strlen(p) + 1) - o->data); | 1513 | fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); |
1514 | } | 1514 | } |
1515 | } | 1515 | } |
1516 | #else | 1516 | #else |
@@ -1644,6 +1644,14 @@ static char **o_finalize_list(o_string *o, int n) | |||
1644 | } | 1644 | } |
1645 | 1645 | ||
1646 | 1646 | ||
1647 | /* Expansion can recurse */ | ||
1648 | #if ENABLE_HUSH_TICK | ||
1649 | static int process_command_subs(o_string *dest, | ||
1650 | struct in_str *input, const char *subst_end); | ||
1651 | #endif | ||
1652 | static char *expand_string_to_string(const char *str); | ||
1653 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); | ||
1654 | |||
1647 | /* expand_strvec_to_strvec() takes a list of strings, expands | 1655 | /* expand_strvec_to_strvec() takes a list of strings, expands |
1648 | * all variable references within and returns a pointer to | 1656 | * all variable references within and returns a pointer to |
1649 | * a list of expanded strings, possibly with larger number | 1657 | * a list of expanded strings, possibly with larger number |
@@ -1678,11 +1686,6 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
1678 | return n; | 1686 | return n; |
1679 | } | 1687 | } |
1680 | 1688 | ||
1681 | #if ENABLE_HUSH_TICK | ||
1682 | static int process_command_subs(o_string *dest, | ||
1683 | struct in_str *input, const char *subst_end); | ||
1684 | #endif | ||
1685 | |||
1686 | /* Expand all variable references in given string, adding words to list[] | 1689 | /* Expand all variable references in given string, adding words to list[] |
1687 | * at n, n+1,... positions. Return updated n (so that list[n] is next one | 1690 | * at n, n+1,... positions. Return updated n (so that list[n] is next one |
1688 | * to be filled). This routine is extremely tricky: has to deal with | 1691 | * to be filled). This routine is extremely tricky: has to deal with |
@@ -1710,6 +1713,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1710 | #if ENABLE_HUSH_TICK | 1713 | #if ENABLE_HUSH_TICK |
1711 | o_string subst_result = NULL_O_STRING; | 1714 | o_string subst_result = NULL_O_STRING; |
1712 | #endif | 1715 | #endif |
1716 | #if ENABLE_SH_MATH_SUPPORT | ||
1717 | char arith_buf[sizeof(arith_t)*3 + 2]; | ||
1718 | #endif | ||
1713 | o_addstr(output, arg, p - arg); | 1719 | o_addstr(output, arg, p - arg); |
1714 | debug_print_list("expand_vars_to_list[1]", output, n); | 1720 | debug_print_list("expand_vars_to_list[1]", output, n); |
1715 | arg = ++p; | 1721 | arg = ++p; |
@@ -1720,6 +1726,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1720 | * expand to nothing (not even an empty string) */ | 1726 | * expand to nothing (not even an empty string) */ |
1721 | if ((first_ch & 0x7f) != '@') | 1727 | if ((first_ch & 0x7f) != '@') |
1722 | ored_ch |= first_ch; | 1728 | ored_ch |= first_ch; |
1729 | |||
1723 | val = NULL; | 1730 | val = NULL; |
1724 | switch (first_ch & 0x7f) { | 1731 | switch (first_ch & 0x7f) { |
1725 | /* Highest bit in first_ch indicates that var is double-quoted */ | 1732 | /* Highest bit in first_ch indicates that var is double-quoted */ |
@@ -1803,19 +1810,52 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1803 | } | 1810 | } |
1804 | #endif | 1811 | #endif |
1805 | #if ENABLE_SH_MATH_SUPPORT | 1812 | #if ENABLE_SH_MATH_SUPPORT |
1806 | case '+': { /* <SPECIAL_VAR_SYMBOL>(cmd<SPECIAL_VAR_SYMBOL> */ | 1813 | case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ |
1807 | arith_eval_hooks_t hooks; | 1814 | arith_eval_hooks_t hooks; |
1808 | arith_t res; | 1815 | arith_t res; |
1809 | char buf[30]; | ||
1810 | int errcode; | 1816 | int errcode; |
1817 | char *exp_str; | ||
1811 | 1818 | ||
1812 | *p = '\0'; | 1819 | arg++; /* skip '+' */ |
1813 | ++arg; | 1820 | *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ |
1814 | debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); | 1821 | debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); |
1822 | |||
1823 | /* Optional: skip expansion if expr is simple ("a + 3", "i++" etc) */ | ||
1824 | exp_str = arg; | ||
1825 | while (1) { | ||
1826 | unsigned char c = *exp_str++; | ||
1827 | if (c == '\0') { | ||
1828 | exp_str = NULL; | ||
1829 | goto skip_expand; | ||
1830 | } | ||
1831 | if (isdigit(c)) | ||
1832 | continue; | ||
1833 | if (strchr(" \t+-*/%_", c) != NULL) | ||
1834 | continue; | ||
1835 | c |= 0x20; /* tolower */ | ||
1836 | if (c >= 'a' && c <= 'z') | ||
1837 | continue; | ||
1838 | break; | ||
1839 | } | ||
1840 | /* We need to expand. Example: "echo $(($a + 1)) $((1 + $((2)) ))" */ | ||
1841 | { | ||
1842 | struct in_str input; | ||
1843 | o_string dest = NULL_O_STRING; | ||
1844 | |||
1845 | setup_string_in_str(&input, arg); | ||
1846 | parse_stream_dquoted(&dest, &input, EOF); | ||
1847 | //bb_error_msg("'%s' -> '%s'", arg, dest.data); | ||
1848 | exp_str = expand_string_to_string(dest.data); | ||
1849 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); | ||
1850 | o_free(&dest); | ||
1851 | } | ||
1852 | skip_expand: | ||
1815 | hooks.lookupvar = lookup_param; | 1853 | hooks.lookupvar = lookup_param; |
1816 | hooks.setvar = arith_set_local_var; | 1854 | hooks.setvar = arith_set_local_var; |
1817 | hooks.endofname = endofname; | 1855 | hooks.endofname = endofname; |
1818 | res = arith(arg, &errcode, &hooks); | 1856 | res = arith(exp_str ? exp_str : arg, &errcode, &hooks); |
1857 | free(exp_str); | ||
1858 | |||
1819 | if (errcode < 0) { | 1859 | if (errcode < 0) { |
1820 | switch (errcode) { | 1860 | switch (errcode) { |
1821 | case -3: maybe_die("arith", "exponent less than 0"); break; | 1861 | case -3: maybe_die("arith", "exponent less than 0"); break; |
@@ -1824,9 +1864,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1824 | default: maybe_die("arith", "syntax error"); break; | 1864 | default: maybe_die("arith", "syntax error"); break; |
1825 | } | 1865 | } |
1826 | } | 1866 | } |
1827 | sprintf(buf, arith_t_fmt, res); | ||
1828 | o_addstrauto(output, buf); | ||
1829 | debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); | 1867 | debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); |
1868 | sprintf(arith_buf, arith_t_fmt, res); | ||
1869 | val = arith_buf; | ||
1830 | break; | 1870 | break; |
1831 | } | 1871 | } |
1832 | #endif | 1872 | #endif |
@@ -1918,13 +1958,14 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1918 | } else { /* quoted $VAR, val will be appended below */ | 1958 | } else { /* quoted $VAR, val will be appended below */ |
1919 | debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); | 1959 | debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); |
1920 | } | 1960 | } |
1921 | } | 1961 | } /* default: */ |
1922 | } | 1962 | } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ |
1963 | |||
1923 | if (val) { | 1964 | if (val) { |
1924 | o_addQstr(output, val, strlen(val)); | 1965 | o_addQstr(output, val, strlen(val)); |
1925 | } | 1966 | } |
1926 | /* Do the check to avoid writing to a const string */ | 1967 | /* Do the check to avoid writing to a const string */ |
1927 | if (p && *p != SPECIAL_VAR_SYMBOL) | 1968 | if (*p != SPECIAL_VAR_SYMBOL) |
1928 | *p = SPECIAL_VAR_SYMBOL; | 1969 | *p = SPECIAL_VAR_SYMBOL; |
1929 | 1970 | ||
1930 | #if ENABLE_HUSH_TICK | 1971 | #if ENABLE_HUSH_TICK |
@@ -3756,11 +3797,11 @@ static int process_command_subs(o_string *dest, | |||
3756 | } | 3797 | } |
3757 | 3798 | ||
3758 | debug_printf("done reading from pipe, pclose()ing\n"); | 3799 | debug_printf("done reading from pipe, pclose()ing\n"); |
3759 | /* This is the step that waits for the child. Should be pretty | 3800 | /* Note: we got EOF, and we just close the read end of the pipe. |
3760 | * safe, since we just read an EOF from its stdout. We could try | 3801 | * We do not wait for the `cmd` child to terminate. bash and ash do. |
3761 | * to do better, by using waitpid, and keeping track of background jobs | 3802 | * Try this: |
3762 | * at the same time. That would be a lot of work, and contrary | 3803 | * echo `echo Hi; exec 1>&-; sleep 2` |
3763 | * to the KISS philosophy of this program. */ | 3804 | */ |
3764 | retcode = fclose(p); | 3805 | retcode = fclose(p); |
3765 | free_pipe_list(inner.list_head, /* indent: */ 0); | 3806 | free_pipe_list(inner.list_head, /* indent: */ 0); |
3766 | debug_printf("closed FILE from child, retcode=%d\n", retcode); | 3807 | debug_printf("closed FILE from child, retcode=%d\n", retcode); |
@@ -4056,7 +4097,7 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
4056 | if (i_peek(input) == '(') { | 4097 | if (i_peek(input) == '(') { |
4057 | i_getch(input); | 4098 | i_getch(input); |
4058 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4099 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4059 | o_addchr(dest, quote_mask | '+'); | 4100 | o_addchr(dest, /*quote_mask |*/ '+'); |
4060 | add_till_closing_paren(dest, input, true); | 4101 | add_till_closing_paren(dest, input, true); |
4061 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4102 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4062 | break; | 4103 | break; |
@@ -4093,6 +4134,86 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
4093 | return 0; | 4134 | return 0; |
4094 | } | 4135 | } |
4095 | 4136 | ||
4137 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end) | ||
4138 | { | ||
4139 | int ch, m; | ||
4140 | int next; | ||
4141 | |||
4142 | again: | ||
4143 | ch = i_getch(input); | ||
4144 | if (ch == dquote_end) { /* may be only '"' or EOF */ | ||
4145 | dest->nonnull = 1; | ||
4146 | if (dest->o_assignment == NOT_ASSIGNMENT) | ||
4147 | dest->o_quote ^= 1; | ||
4148 | debug_printf_parse("parse_stream_dquoted return 0\n"); | ||
4149 | return 0; | ||
4150 | } | ||
4151 | if (ch == EOF) { | ||
4152 | syntax("unterminated \""); | ||
4153 | debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n"); | ||
4154 | return 1; | ||
4155 | } | ||
4156 | next = '\0'; | ||
4157 | m = G.charmap[ch]; | ||
4158 | if (ch != '\n') { | ||
4159 | next = i_peek(input); | ||
4160 | } | ||
4161 | debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", | ||
4162 | ch, ch, m, dest->o_quote); | ||
4163 | if (m != CHAR_SPECIAL) { | ||
4164 | o_addQchr(dest, ch); | ||
4165 | if ((dest->o_assignment == MAYBE_ASSIGNMENT | ||
4166 | || dest->o_assignment == WORD_IS_KEYWORD) | ||
4167 | && ch == '=' | ||
4168 | && is_assignment(dest->data) | ||
4169 | ) { | ||
4170 | dest->o_assignment = DEFINITELY_ASSIGNMENT; | ||
4171 | } | ||
4172 | goto again; | ||
4173 | } | ||
4174 | if (ch == '\\') { | ||
4175 | if (next == EOF) { | ||
4176 | syntax("\\<eof>"); | ||
4177 | debug_printf_parse("parse_stream_dquoted return 1: \\<eof>\n"); | ||
4178 | return 1; | ||
4179 | } | ||
4180 | /* bash: | ||
4181 | * "The backslash retains its special meaning [in "..."] | ||
4182 | * only when followed by one of the following characters: | ||
4183 | * $, `, ", \, or <newline>. A double quote may be quoted | ||
4184 | * within double quotes by preceding it with a backslash. | ||
4185 | * If enabled, history expansion will be performed unless | ||
4186 | * an ! appearing in double quotes is escaped using | ||
4187 | * a backslash. The backslash preceding the ! is not removed." | ||
4188 | */ | ||
4189 | if (strchr("$`\"\\", next) != NULL) { | ||
4190 | o_addqchr(dest, i_getch(input)); | ||
4191 | } else { | ||
4192 | o_addqchr(dest, '\\'); | ||
4193 | } | ||
4194 | goto again; | ||
4195 | } | ||
4196 | if (ch == '$') { | ||
4197 | if (handle_dollar(dest, input) != 0) { | ||
4198 | debug_printf_parse("parse_stream_dquoted return 1: handle_dollar returned non-0\n"); | ||
4199 | return 1; | ||
4200 | } | ||
4201 | goto again; | ||
4202 | } | ||
4203 | #if ENABLE_HUSH_TICK | ||
4204 | if (ch == '`') { | ||
4205 | //int pos = dest->length; | ||
4206 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
4207 | o_addchr(dest, 0x80 | '`'); | ||
4208 | add_till_backquote(dest, input); | ||
4209 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||
4210 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); | ||
4211 | /* fall through */ | ||
4212 | } | ||
4213 | #endif | ||
4214 | goto again; | ||
4215 | } | ||
4216 | |||
4096 | /* Scan input, call done_word() whenever full IFS delimited word was seen. | 4217 | /* Scan input, call done_word() whenever full IFS delimited word was seen. |
4097 | * Call done_pipe if '\n' was seen (and end_trigger != NULL). | 4218 | * Call done_pipe if '\n' was seen (and end_trigger != NULL). |
4098 | * Return code is 0 if end_trigger char is met, | 4219 | * Return code is 0 if end_trigger char is met, |
@@ -4104,7 +4225,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4104 | int ch, m; | 4225 | int ch, m; |
4105 | int redir_fd; | 4226 | int redir_fd; |
4106 | redir_type redir_style; | 4227 | redir_type redir_style; |
4107 | int shadow_quote = dest->o_quote; | 4228 | int is_in_dquote; |
4108 | int next; | 4229 | int next; |
4109 | 4230 | ||
4110 | /* Only double-quote state is handled in the state variable dest->o_quote. | 4231 | /* Only double-quote state is handled in the state variable dest->o_quote. |
@@ -4113,7 +4234,14 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4113 | 4234 | ||
4114 | debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); | 4235 | debug_printf_parse("parse_stream entered, end_trigger='%s' dest->o_assignment:%d\n", end_trigger, dest->o_assignment); |
4115 | 4236 | ||
4237 | is_in_dquote = dest->o_quote; | ||
4116 | while (1) { | 4238 | while (1) { |
4239 | if (is_in_dquote) { | ||
4240 | if (parse_stream_dquoted(dest, input, '"')) | ||
4241 | return 1; /* propagate parse error */ | ||
4242 | /* If we're here, we reached closing '"' */ | ||
4243 | is_in_dquote = 0; | ||
4244 | } | ||
4117 | m = CHAR_IFS; | 4245 | m = CHAR_IFS; |
4118 | next = '\0'; | 4246 | next = '\0'; |
4119 | ch = i_getch(input); | 4247 | ch = i_getch(input); |
@@ -4125,14 +4253,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4125 | } | 4253 | } |
4126 | debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", | 4254 | debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", |
4127 | ch, ch, m, dest->o_quote); | 4255 | ch, ch, m, dest->o_quote); |
4128 | if (m == CHAR_ORDINARY | 4256 | if (m == CHAR_ORDINARY) { |
4129 | || (m != CHAR_SPECIAL && shadow_quote) | ||
4130 | ) { | ||
4131 | if (ch == EOF) { | ||
4132 | syntax("unterminated \""); | ||
4133 | debug_printf_parse("parse_stream return 1: unterminated \"\n"); | ||
4134 | return 1; | ||
4135 | } | ||
4136 | o_addQchr(dest, ch); | 4257 | o_addQchr(dest, ch); |
4137 | if ((dest->o_assignment == MAYBE_ASSIGNMENT | 4258 | if ((dest->o_assignment == MAYBE_ASSIGNMENT |
4138 | || dest->o_assignment == WORD_IS_KEYWORD) | 4259 | || dest->o_assignment == WORD_IS_KEYWORD) |
@@ -4143,6 +4264,8 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4143 | } | 4264 | } |
4144 | continue; | 4265 | continue; |
4145 | } | 4266 | } |
4267 | /* m is SPECIAL ($,`), IFS, or ORDINARY_IF_QUOTED (*,#) | ||
4268 | */ | ||
4146 | if (m == CHAR_IFS) { | 4269 | if (m == CHAR_IFS) { |
4147 | if (done_word(dest, ctx)) { | 4270 | if (done_word(dest, ctx)) { |
4148 | debug_printf_parse("parse_stream return 1: done_word!=0\n"); | 4271 | debug_printf_parse("parse_stream return 1: done_word!=0\n"); |
@@ -4152,7 +4275,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4152 | break; | 4275 | break; |
4153 | /* If we aren't performing a substitution, treat | 4276 | /* If we aren't performing a substitution, treat |
4154 | * a newline as a command separator. | 4277 | * a newline as a command separator. |
4155 | * [why we don't handle it exactly like ';'? --vda] */ | 4278 | * [why don't we handle it exactly like ';'? --vda] */ |
4156 | if (end_trigger && ch == '\n') { | 4279 | if (end_trigger && ch == '\n') { |
4157 | #if ENABLE_HUSH_CASE | 4280 | #if ENABLE_HUSH_CASE |
4158 | /* "case ... in <newline> word) ..." - | 4281 | /* "case ... in <newline> word) ..." - |
@@ -4168,7 +4291,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4168 | } | 4291 | } |
4169 | } | 4292 | } |
4170 | if (end_trigger) { | 4293 | if (end_trigger) { |
4171 | if (!shadow_quote && strchr(end_trigger, ch)) { | 4294 | if (strchr(end_trigger, ch)) { |
4172 | /* Special case: (...word) makes last word terminate, | 4295 | /* Special case: (...word) makes last word terminate, |
4173 | * as if ';' is seen */ | 4296 | * as if ';' is seen */ |
4174 | if (ch == ')') { | 4297 | if (ch == ')') { |
@@ -4188,15 +4311,17 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4188 | if (m == CHAR_IFS) | 4311 | if (m == CHAR_IFS) |
4189 | continue; | 4312 | continue; |
4190 | 4313 | ||
4314 | /* m is SPECIAL (e.g. $,`) or ORDINARY_IF_QUOTED (*,#) */ | ||
4315 | |||
4191 | if (dest->o_assignment == MAYBE_ASSIGNMENT) { | 4316 | if (dest->o_assignment == MAYBE_ASSIGNMENT) { |
4192 | /* ch is a special char and thus this word | 4317 | /* ch is a special char and thus this word |
4193 | * cannot be an assignment: */ | 4318 | * cannot be an assignment */ |
4194 | dest->o_assignment = NOT_ASSIGNMENT; | 4319 | dest->o_assignment = NOT_ASSIGNMENT; |
4195 | } | 4320 | } |
4196 | 4321 | ||
4197 | switch (ch) { | 4322 | switch (ch) { |
4198 | case '#': | 4323 | case '#': |
4199 | if (dest->length == 0 && !shadow_quote) { | 4324 | if (dest->length == 0) { |
4200 | while (1) { | 4325 | while (1) { |
4201 | ch = i_peek(input); | 4326 | ch = i_peek(input); |
4202 | if (ch == EOF || ch == '\n') | 4327 | if (ch == EOF || ch == '\n') |
@@ -4213,25 +4338,8 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4213 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); | 4338 | debug_printf_parse("parse_stream return 1: \\<eof>\n"); |
4214 | return 1; | 4339 | return 1; |
4215 | } | 4340 | } |
4216 | /* bash: | 4341 | o_addchr(dest, '\\'); |
4217 | * "The backslash retains its special meaning [in "..."] | 4342 | o_addchr(dest, i_getch(input)); |
4218 | * only when followed by one of the following characters: | ||
4219 | * $, `, ", \, or <newline>. A double quote may be quoted | ||
4220 | * within double quotes by preceding it with a backslash. | ||
4221 | * If enabled, history expansion will be performed unless | ||
4222 | * an ! appearing in double quotes is escaped using | ||
4223 | * a backslash. The backslash preceding the ! is not removed." | ||
4224 | */ | ||
4225 | if (shadow_quote) { //NOT SURE dest->o_quote) { | ||
4226 | if (strchr("$`\"\\", next) != NULL) { | ||
4227 | o_addqchr(dest, i_getch(input)); | ||
4228 | } else { | ||
4229 | o_addqchr(dest, '\\'); | ||
4230 | } | ||
4231 | } else { | ||
4232 | o_addchr(dest, '\\'); | ||
4233 | o_addchr(dest, i_getch(input)); | ||
4234 | } | ||
4235 | break; | 4343 | break; |
4236 | case '$': | 4344 | case '$': |
4237 | if (handle_dollar(dest, input) != 0) { | 4345 | if (handle_dollar(dest, input) != 0) { |
@@ -4258,7 +4366,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4258 | break; | 4366 | break; |
4259 | case '"': | 4367 | case '"': |
4260 | dest->nonnull = 1; | 4368 | dest->nonnull = 1; |
4261 | shadow_quote ^= 1; /* invert */ | 4369 | is_in_dquote ^= 1; /* invert */ |
4262 | if (dest->o_assignment == NOT_ASSIGNMENT) | 4370 | if (dest->o_assignment == NOT_ASSIGNMENT) |
4263 | dest->o_quote ^= 1; | 4371 | dest->o_quote ^= 1; |
4264 | break; | 4372 | break; |
@@ -4266,7 +4374,7 @@ static int parse_stream(o_string *dest, struct parse_context *ctx, | |||
4266 | case '`': { | 4374 | case '`': { |
4267 | //int pos = dest->length; | 4375 | //int pos = dest->length; |
4268 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4376 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4269 | o_addchr(dest, shadow_quote /*or dest->o_quote??*/ ? 0x80 | '`' : '`'); | 4377 | o_addchr(dest, '`'); |
4270 | add_till_backquote(dest, input); | 4378 | add_till_backquote(dest, input); |
4271 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4379 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4272 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); | 4380 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); |