summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-16 22:18:54 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-16 22:18:54 +0000
commitc666f71e3b91285d66260567b0b4c57332e0ff1f (patch)
treef48578f6c1779923692e1d0ba4e2a45d35b83e36 /shell/hush.c
parent831dcc439cdaef1062e09ca9af55f5c931889845 (diff)
downloadbusybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.tar.gz
busybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.tar.bz2
busybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.zip
hush: take care of several easy FIXMEs. -228 bytes.
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c192
1 files changed, 68 insertions, 124 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 84f2870f2..7a4d7f934 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -124,6 +124,7 @@ static const char *indenter(int i)
124 return &blanks[sizeof(blanks) - i - 1]; 124 return &blanks[sizeof(blanks) - i - 1];
125} 125}
126#define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__) 126#define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__)
127#define DEBUG_CLEAN 1
127#endif 128#endif
128 129
129 130
@@ -232,10 +233,10 @@ struct child_prog {
232 glob_t glob_result; /* result of parameter globbing */ 233 glob_t glob_result; /* result of parameter globbing */
233 int is_stopped; /* is the program currently running? */ 234 int is_stopped; /* is the program currently running? */
234 struct pipe *family; /* pointer back to the child's parent pipe */ 235 struct pipe *family; /* pointer back to the child's parent pipe */
235 int sp; /* number of SPECIAL_VAR_SYMBOL */ 236 //sp counting seems to be broken... so commented out, grep for '//sp:'
237 //sp: int sp; /* number of SPECIAL_VAR_SYMBOL */
236 int type; 238 int type;
237}; 239};
238// sp counting seems to be broken...
239/* argv vector may contain variable references (^Cvar^C, ^C0^C etc) 240/* argv vector may contain variable references (^Cvar^C, ^C0^C etc)
240 * and on execution these are substituted with their values. 241 * and on execution these are substituted with their values.
241 * Substitution can make _several_ words out of one argv[n]! 242 * Substitution can make _several_ words out of one argv[n]!
@@ -383,7 +384,6 @@ static int b_check_space(o_string *o, int len);
383static int b_addchr(o_string *o, int ch); 384static int b_addchr(o_string *o, int ch);
384static void b_reset(o_string *o); 385static void b_reset(o_string *o);
385static int b_addqchr(o_string *o, int ch, int quote); 386static int b_addqchr(o_string *o, int ch, int quote);
386//static int b_adduint(o_string *o, unsigned i);
387/* in_str manipulations: */ 387/* in_str manipulations: */
388static int static_get(struct in_str *i); 388static int static_get(struct in_str *i);
389static int static_peek(struct in_str *i); 389static int static_peek(struct in_str *i);
@@ -396,7 +396,10 @@ static void mark_open(int fd);
396static void mark_closed(int fd); 396static void mark_closed(int fd);
397static void close_all(void); 397static void close_all(void);
398/* "run" the final data structures: */ 398/* "run" the final data structures: */
399//TODO: remove indent argument from non-debug build! 399#if !defined(DEBUG_CLEAN)
400#define free_pipe_list(head, indent) free_pipe_list(head)
401#define free_pipe(pi, indent) free_pipe(pi)
402#endif
400static int free_pipe_list(struct pipe *head, int indent); 403static int free_pipe_list(struct pipe *head, int indent);
401static int free_pipe(struct pipe *pi, int indent); 404static int free_pipe(struct pipe *pi, int indent);
402/* really run the final data structures: */ 405/* really run the final data structures: */
@@ -425,7 +428,6 @@ static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *inp
425static const char *lookup_param(const char *src); 428static const char *lookup_param(const char *src);
426static char *make_string(char **inp); 429static char *make_string(char **inp);
427static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 430static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
428//static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
429static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); 431static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger);
430/* setup: */ 432/* setup: */
431static int parse_stream_outer(struct in_str *inp, int parse_flag); 433static int parse_stream_outer(struct in_str *inp, int parse_flag);
@@ -708,9 +710,8 @@ static int builtin_export(char **argv)
708 return EXIT_SUCCESS; 710 return EXIT_SUCCESS;
709 } 711 }
710 712
711 name = strdup(name); 713 name = xstrdup(name);
712 714 {
713 if (name) {
714 const char *value = strchr(name, '='); 715 const char *value = strchr(name, '=');
715 716
716 if (!value) { 717 if (!value) {
@@ -721,13 +722,9 @@ static int builtin_export(char **argv)
721 if (value) { 722 if (value) {
722 size_t ln = strlen(name); 723 size_t ln = strlen(name);
723 724
724 tmp = realloc(name, ln+strlen(value)+2); 725 tmp = xrealloc(name, ln+strlen(value)+2);
725 if (tmp == NULL) 726 sprintf(tmp+ln, "=%s", value);
726 res = -1; 727 name = tmp;
727 else {
728 sprintf(tmp+ln, "=%s", value);
729 name = tmp;
730 }
731 } else { 728 } else {
732 /* bash does not return an error when trying to export 729 /* bash does not return an error when trying to export
733 * an undefined variable. Do likewise. */ 730 * an undefined variable. Do likewise. */
@@ -967,13 +964,9 @@ static int b_check_space(o_string *o, int len)
967 /* It would be easy to drop a more restrictive policy 964 /* It would be easy to drop a more restrictive policy
968 * in here, such as setting a maximum string length */ 965 * in here, such as setting a maximum string length */
969 if (o->length + len > o->maxlen) { 966 if (o->length + len > o->maxlen) {
970 char *old_data = o->data;
971 /* assert(data == NULL || o->maxlen != 0); */ 967 /* assert(data == NULL || o->maxlen != 0); */
972 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); 968 o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK);
973 o->data = realloc(o->data, 1 + o->maxlen); 969 o->data = xrealloc(o->data, 1 + o->maxlen);
974 if (o->data == NULL) {
975 free(old_data);
976 }
977 } 970 }
978 return o->data == NULL; 971 return o->data == NULL;
979} 972}
@@ -1019,17 +1012,6 @@ static int b_addqchr(o_string *o, int ch, int quote)
1019 return b_addchr(o, ch); 1012 return b_addchr(o, ch);
1020} 1013}
1021 1014
1022//static int b_adduint(o_string *o, unsigned i)
1023//{
1024// int r;
1025// char buf[sizeof(unsigned)*3 + 1];
1026// char *p = buf;
1027// *(utoa_to_buf(i, buf, sizeof(buf))) = '\0';
1028// /* no escape checking necessary */
1029// do r = b_addchr(o, *p++); while (r == 0 && *p);
1030// return r;
1031//}
1032//
1033static int static_get(struct in_str *i) 1015static int static_get(struct in_str *i)
1034{ 1016{
1035 int ch = *i->p++; 1017 int ch = *i->p++;
@@ -1286,7 +1268,7 @@ static void pseudo_exec_argv(char **argv)
1286 const struct built_in_command *x; 1268 const struct built_in_command *x;
1287 1269
1288 for (i = 0; is_assignment(argv[i]); i++) { 1270 for (i = 0; is_assignment(argv[i]); i++) {
1289 debug_printf("pid %d environment modification: %s\n", 1271 debug_printf_exec("pid %d environment modification: %s\n",
1290 getpid(), argv[i]); 1272 getpid(), argv[i]);
1291// FIXME: vfork case?? 1273// FIXME: vfork case??
1292 p = insert_var_value(argv[i]); 1274 p = insert_var_value(argv[i]);
@@ -1317,23 +1299,27 @@ static void pseudo_exec_argv(char **argv)
1317 } 1299 }
1318 } 1300 }
1319 1301
1320 /* Check if the command matches any busybox internal commands 1302 /* Check if the command matches any busybox applets */
1321 * ("applets") here.
1322 * FIXME: This feature is not 100% safe, since
1323 * BusyBox is not fully reentrant, so we have no guarantee the things
1324 * from the .bss are still zeroed, or that things from .data are still
1325 * at their defaults. We could exec ourself from /proc/self/exe, but I
1326 * really dislike relying on /proc for things. We could exec ourself
1327 * from global_argv[0], but if we are in a chroot, we may not be able
1328 * to find ourself... */
1329#if ENABLE_FEATURE_SH_STANDALONE 1303#if ENABLE_FEATURE_SH_STANDALONE
1330 debug_printf("running applet %s\n", argv[0]); 1304 if (strchr(argv[0], '/') == NULL) {
1331// FIXME: check NOEXEC bit, and EXEC if not set! 1305 const struct bb_applet *a = find_applet_by_name(argv[0]);
1332 run_applet_and_exit(argv[0], argv); 1306 if (a) {
1333// is it ok that run_applet_and_exit() does exit(), not _exit()? 1307 if (a->noexec) {
1334// NB: IIRC on NOMMU we are after _vfork_, not fork! 1308 current_applet = a;
1309 debug_printf_exec("running applet '%s'\n", argv[0]);
1310// is it ok that run_current_applet_and_exit() does exit(), not _exit()?
1311 run_current_applet_and_exit(argv);
1312 }
1313 /* re-exec ourselves with the new arguments */
1314 debug_printf_exec("re-execing applet '%s'\n", argv[0]);
1315 execvp(CONFIG_BUSYBOX_EXEC_PATH, argv);
1316 /* If they called chroot or otherwise made the binary no longer
1317 * executable, fall through */
1318 }
1319 }
1335#endif 1320#endif
1336 debug_printf("exec of %s\n", argv[0]); 1321
1322 debug_printf_exec("execing '%s'\n", argv[0]);
1337 execvp(argv[0], argv); 1323 execvp(argv[0], argv);
1338 bb_perror_msg("cannot exec '%s'", argv[0]); 1324 bb_perror_msg("cannot exec '%s'", argv[0]);
1339 _exit(1); 1325 _exit(1);
@@ -1426,16 +1412,7 @@ static void insert_bg_job(struct pipe *pi)
1426// TODO: do we really need to have so many fields which are just dead weight 1412// TODO: do we really need to have so many fields which are just dead weight
1427// at execution stage? 1413// at execution stage?
1428 thejob->progs[i].pid = pi->progs[i].pid; 1414 thejob->progs[i].pid = pi->progs[i].pid;
1429 //rest: 1415 /* all other fields are not used and stay zero */
1430 //char **argv; /* program name and arguments */
1431 //struct pipe *group; /* if non-NULL, first in group or subshell */
1432 //int subshell; /* flag, non-zero if group must be forked */
1433 //struct redir_struct *redirects; /* I/O redirections */
1434 //glob_t glob_result; /* result of parameter globbing */
1435 //int is_stopped; /* is the program currently running? */
1436 //struct pipe *family; /* pointer back to the child's parent pipe */
1437 //int sp; /* number of SPECIAL_VAR_SYMBOL */
1438 //int type;
1439 } 1416 }
1440 thejob->next = NULL; 1417 thejob->next = NULL;
1441 thejob->cmdtext = xstrdup(get_cmdtext(pi)); 1418 thejob->cmdtext = xstrdup(get_cmdtext(pi));
@@ -1594,10 +1571,6 @@ static int checkjobs(struct pipe* fg_pipe)
1594 1571
1595 if (childpid && errno != ECHILD) 1572 if (childpid && errno != ECHILD)
1596 bb_perror_msg("waitpid"); 1573 bb_perror_msg("waitpid");
1597
1598 /* move the shell to the foreground */
1599 //if (interactive_fd && tcsetpgrp(interactive_fd, getpgid(0)))
1600 // bb_perror_msg("tcsetpgrp-2");
1601 return rcode; 1574 return rcode;
1602} 1575}
1603 1576
@@ -1669,7 +1642,7 @@ static int run_pipe_real(struct pipe *pi)
1669 } 1642 }
1670 1643
1671 if (single_fg && child->argv != NULL) { 1644 if (single_fg && child->argv != NULL) {
1672 char **argv_expanded, **free_me; 1645 char **argv_expanded;
1673 char **argv = child->argv; 1646 char **argv = child->argv;
1674 1647
1675 for (i = 0; is_assignment(argv[i]); i++) 1648 for (i = 0; is_assignment(argv[i]); i++)
@@ -1704,13 +1677,12 @@ static int run_pipe_real(struct pipe *pi)
1704 for (i = 0; is_assignment(argv[i]); i++) { 1677 for (i = 0; is_assignment(argv[i]); i++) {
1705 p = insert_var_value(argv[i]); 1678 p = insert_var_value(argv[i]);
1706 if (p != argv[i]) { 1679 if (p != argv[i]) {
1707 child->sp--; 1680 //sp: child->sp--;
1708 putenv(p); 1681 putenv(p);
1709 } else { 1682 } else {
1710 putenv(xstrdup(p)); 1683 putenv(xstrdup(p));
1711 } 1684 }
1712 } 1685 }
1713 free_me = NULL;
1714 for (x = bltins; x->cmd; x++) { 1686 for (x = bltins; x->cmd; x++) {
1715 if (strcmp(argv[i], x->cmd) == 0) { 1687 if (strcmp(argv[i], x->cmd) == 0) {
1716 if (x->function == builtin_exec && argv[i+1] == NULL) { 1688 if (x->function == builtin_exec && argv[i+1] == NULL) {
@@ -1723,14 +1695,12 @@ static int run_pipe_real(struct pipe *pi)
1723 * This is perfect for work that comes after exec(). 1695 * This is perfect for work that comes after exec().
1724 * Is it really safe for inline use? Experimentally, 1696 * Is it really safe for inline use? Experimentally,
1725 * things seem to work with glibc. */ 1697 * things seem to work with glibc. */
1726// TODO: fflush(NULL)?
1727 setup_redirects(child, squirrel); 1698 setup_redirects(child, squirrel);
1728 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); 1699 debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
1729 argv_expanded = argv + i; 1700 //sp: if (child->sp) /* btw we can do it unconditionally... */
1730 if (child->sp) /* btw we can do it unconditionally... */ 1701 argv_expanded = do_variable_expansion(argv + i);
1731 free_me = argv_expanded = do_variable_expansion(argv + i);
1732 rcode = x->function(argv_expanded); 1702 rcode = x->function(argv_expanded);
1733 free(free_me); 1703 free(argv_expanded);
1734 restore_redirects(squirrel); 1704 restore_redirects(squirrel);
1735 debug_printf_exec("run_pipe_real return %d\n", rcode); 1705 debug_printf_exec("run_pipe_real return %d\n", rcode);
1736 return rcode; 1706 return rcode;
@@ -1743,11 +1713,11 @@ static int run_pipe_real(struct pipe *pi)
1743 setup_redirects(child, squirrel); 1713 setup_redirects(child, squirrel);
1744 save_nofork_data(&nofork_save); 1714 save_nofork_data(&nofork_save);
1745 argv_expanded = argv + i; 1715 argv_expanded = argv + i;
1746 if (child->sp) 1716 //sp: if (child->sp)
1747 free_me = argv_expanded = do_variable_expansion(argv + i); 1717 argv_expanded = do_variable_expansion(argv + i);
1748 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); 1718 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
1749 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); 1719 rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
1750 free(free_me); 1720 free(argv_expanded);
1751 restore_redirects(squirrel); 1721 restore_redirects(squirrel);
1752 debug_printf_exec("run_pipe_real return %d\n", rcode); 1722 debug_printf_exec("run_pipe_real return %d\n", rcode);
1753 return rcode; 1723 return rcode;
@@ -1802,7 +1772,7 @@ static int run_pipe_real(struct pipe *pi)
1802 } 1772 }
1803 } 1773 }
1804#endif 1774#endif
1805 // in non-interactive case fatal sigs are already SIG_DFL 1775 /* in non-interactive case fatal sigs are already SIG_DFL */
1806 close_all(); 1776 close_all();
1807 if (nextin != 0) { 1777 if (nextin != 0) {
1808 dup2(nextin, 0); 1778 dup2(nextin, 0);
@@ -1833,13 +1803,6 @@ static int run_pipe_real(struct pipe *pi)
1833 if (pi->pgrp < 0) 1803 if (pi->pgrp < 0)
1834 pi->pgrp = child->pid; 1804 pi->pgrp = child->pid;
1835#endif 1805#endif
1836
1837 /* Don't check for errors. The child may be dead already,
1838 * in which case setpgid returns error code EACCES. */
1839 //why we do it at all?? child does it itself
1840 //if (interactive_fd)
1841 // setpgid(child->pid, pi->pgrp);
1842
1843 if (nextin != 0) 1806 if (nextin != 0)
1844 close(nextin); 1807 close(nextin);
1845 if (nextout != 1) 1808 if (nextout != 1)
@@ -1911,8 +1874,8 @@ static void debug_print_tree(struct pipe *pi, int lvl)
1911} 1874}
1912#endif 1875#endif
1913 1876
1914// NB: called by pseudo_exec, and therefore must not modify any 1877/* NB: called by pseudo_exec, and therefore must not modify any
1915// global data until exec/_exit (we can be a child after vfork!) 1878 * global data until exec/_exit (we can be a child after vfork!) */
1916static int run_list_real(struct pipe *pi) 1879static int run_list_real(struct pipe *pi)
1917{ 1880{
1918#if ENABLE_HUSH_JOB 1881#if ENABLE_HUSH_JOB
@@ -2224,9 +2187,7 @@ static int globhack(const char *src, int flags, glob_t *pglob)
2224 if (*s == '\\') s++; 2187 if (*s == '\\') s++;
2225 cnt++; 2188 cnt++;
2226 } 2189 }
2227 dest = malloc(cnt); 2190 dest = xmalloc(cnt);
2228 if (!dest)
2229 return GLOB_NOSPACE;
2230 if (!(flags & GLOB_APPEND)) { 2191 if (!(flags & GLOB_APPEND)) {
2231 pglob->gl_pathv = NULL; 2192 pglob->gl_pathv = NULL;
2232 pglob->gl_pathc = 0; 2193 pglob->gl_pathc = 0;
@@ -2234,9 +2195,7 @@ static int globhack(const char *src, int flags, glob_t *pglob)
2234 pglob->gl_offs = 0; 2195 pglob->gl_offs = 0;
2235 } 2196 }
2236 pathc = ++pglob->gl_pathc; 2197 pathc = ++pglob->gl_pathc;
2237 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv)); 2198 pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv));
2238 if (pglob->gl_pathv == NULL)
2239 return GLOB_NOSPACE;
2240 pglob->gl_pathv[pathc-1] = dest; 2199 pglob->gl_pathv[pathc-1] = dest;
2241 pglob->gl_pathv[pathc] = NULL; 2200 pglob->gl_pathv[pathc] = NULL;
2242 for (s = src; s && *s; s++, dest++) { 2201 for (s = src; s && *s; s++, dest++) {
@@ -2312,8 +2271,8 @@ static int count_ifs(const char *str)
2312 while (1) { 2271 while (1) {
2313 str += strcspn(str, ifs); 2272 str += strcspn(str, ifs);
2314 if (!*str) break; 2273 if (!*str) break;
2315 str++; // str += strspn(str, ifs); ? 2274 str++; /* str += strspn(str, ifs); */
2316 cnt++; // cnt += strspn(str, ifs); ? 2275 cnt++; /* cnt += strspn(str, ifs); - but this code is larger */
2317 } 2276 }
2318 debug_printf_expand(" return %d\n", cnt); 2277 debug_printf_expand(" return %d\n", cnt);
2319 return cnt; 2278 return cnt;
@@ -2704,31 +2663,23 @@ static int set_local_var(const char *s, int flg_export)
2704 if (flg_export > 0 || cur->flg_export > 1) 2663 if (flg_export > 0 || cur->flg_export > 1)
2705 cur->flg_export = 1; 2664 cur->flg_export = 1;
2706 free((char*)cur->value); 2665 free((char*)cur->value);
2707 cur->value = strdup(value); 2666 cur->value = xstrdup(value);
2708 } 2667 }
2709 goto skip; 2668 goto skip;
2710 } 2669 }
2711 } 2670 }
2712 2671
2713// TODO: need simpler/generic rollback on malloc failure - see ash 2672 cur = xzalloc(sizeof(*cur));
2714 cur = malloc(sizeof(*cur)); 2673 cur->name = xstrdup(name);
2715 if (!cur) { 2674 cur->value = xstrdup(value);
2716 result = -1; 2675 /*cur->next = 0;*/
2717 } else { 2676 cur->flg_export = flg_export;
2718 cur->name = strdup(name); 2677 /*cur->flg_read_only = 0;*/
2719 if (!cur->name) { 2678 {
2720 free(cur); 2679 struct variables *bottom = top_vars;
2721 result = -1; 2680 while (bottom->next)
2722 } else { 2681 bottom = bottom->next;
2723 struct variables *bottom = top_vars; 2682 bottom->next = cur;
2724 cur->value = strdup(value);
2725 cur->next = 0;
2726 cur->flg_export = flg_export;
2727 cur->flg_read_only = 0;
2728 while (bottom->next)
2729 bottom = bottom->next;
2730 bottom->next = cur;
2731 }
2732 } 2683 }
2733 skip: 2684 skip:
2734 if (result == 0 && cur->flg_export == 1) { 2685 if (result == 0 && cur->flg_export == 1) {
@@ -3019,7 +2970,7 @@ static int done_command(struct p_context *ctx)
3019 /*child->group = NULL;*/ 2970 /*child->group = NULL;*/
3020 /*child->glob_result.gl_pathv = NULL;*/ 2971 /*child->glob_result.gl_pathv = NULL;*/
3021 child->family = pi; 2972 child->family = pi;
3022 /*child->sp = 0;*/ 2973 //sp: /*child->sp = 0;*/
3023 child->type = ctx->parse_type; 2974 child->type = ctx->parse_type;
3024 2975
3025 ctx->child = child; 2976 ctx->child = child;
@@ -3268,7 +3219,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3268 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); 3219 debug_printf_parse("handle_dollar entered: ch='%c'\n", ch);
3269 if (isalpha(ch)) { 3220 if (isalpha(ch)) {
3270 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3221 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3271 ctx->child->sp++; 3222 //sp: ctx->child->sp++;
3272 while (1) { 3223 while (1) {
3273 debug_printf_parse(": '%c'\n", ch); 3224 debug_printf_parse(": '%c'\n", ch);
3274 b_getch(input); 3225 b_getch(input);
@@ -3282,7 +3233,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3282 } else if (isdigit(ch)) { 3233 } else if (isdigit(ch)) {
3283 make_one_char_var: 3234 make_one_char_var:
3284 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3235 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3285 ctx->child->sp++; 3236 //sp: ctx->child->sp++;
3286 debug_printf_parse(": '%c'\n", ch); 3237 debug_printf_parse(": '%c'\n", ch);
3287 b_getch(input); 3238 b_getch(input);
3288 b_addchr(dest, ch | quote_mask); 3239 b_addchr(dest, ch | quote_mask);
@@ -3297,7 +3248,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3297 goto make_one_char_var; 3248 goto make_one_char_var;
3298 case '{': 3249 case '{':
3299 b_addchr(dest, SPECIAL_VAR_SYMBOL); 3250 b_addchr(dest, SPECIAL_VAR_SYMBOL);
3300 ctx->child->sp++; 3251 //sp: ctx->child->sp++;
3301 b_getch(input); 3252 b_getch(input);
3302 /* XXX maybe someone will try to escape the '}' */ 3253 /* XXX maybe someone will try to escape the '}' */
3303 while (1) { 3254 while (1) {
@@ -3332,13 +3283,6 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
3332 return 0; 3283 return 0;
3333} 3284}
3334 3285
3335//static int parse_string(o_string *dest, struct p_context *ctx, const char *src)
3336//{
3337// struct in_str foo;
3338// setup_string_in_str(&foo, src);
3339// return parse_stream(dest, ctx, &foo, NULL);
3340//}
3341//
3342/* return code is 0 for normal exit, 1 for syntax error */ 3286/* return code is 0 for normal exit, 1 for syntax error */
3343static int parse_stream(o_string *dest, struct p_context *ctx, 3287static int parse_stream(o_string *dest, struct p_context *ctx,
3344 struct in_str *input, const char *end_trigger) 3288 struct in_str *input, const char *end_trigger)
@@ -3711,9 +3655,9 @@ int hush_main(int argc, char **argv)
3711 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); 3655 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
3712 goto final_return; 3656 goto final_return;
3713 case 'i': 3657 case 'i':
3714 // Well, we cannot just declare interactiveness, 3658 /* Well, we cannot just declare interactiveness,
3715 // we have to have some stuff (ctty, etc) 3659 * we have to have some stuff (ctty, etc) */
3716 /*interactive_fd++;*/ 3660 /* interactive_fd++; */
3717 break; 3661 break;
3718 case 'f': 3662 case 'f':
3719 fake_mode++; 3663 fake_mode++;