summaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-05-11 12:56:43 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-05-11 12:56:43 +0000
commit3e9aaae5dc384ae070c49507a92b1375397954cd (patch)
tree048661e5d8448c8cb39a4453fe36f4e6c8746384 /shell/hush.c
parente0a336747c2061d0d555c4e15287b513831d2947 (diff)
downloadbusybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.tar.gz
busybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.tar.bz2
busybox-w32-3e9aaae5dc384ae070c49507a92b1375397954cd.zip
hush: fix bug in interactive shell introduced yesterday
hush: fix `process subst` (2 bugs) NB: will delete and re-add hush_test in order to change file modes
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c88
1 files changed, 46 insertions, 42 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 32cd65c72..04fb00dc7 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -317,10 +317,10 @@ typedef struct {
317/* I can almost use ordinary FILE *. Is open_memstream() universally 317/* I can almost use ordinary FILE *. Is open_memstream() universally
318 * available? Where is it documented? */ 318 * available? Where is it documented? */
319struct in_str { 319struct in_str {
320 union { 320 const char *p;
321 const char *p; 321 /* eof_flag=1: last char in ->p is really an EOF */
322 int cached_ch; 322 char eof_flag; /* meaningless if ->p == NULL */
323 }; 323 char peek_buf[2];
324#if ENABLE_HUSH_INTERACTIVE 324#if ENABLE_HUSH_INTERACTIVE
325 int __promptme; 325 int __promptme;
326 int promptmode; 326 int promptmode;
@@ -976,7 +976,7 @@ static int b_check_space(o_string *o, int len)
976 976
977static int b_addchr(o_string *o, int ch) 977static int b_addchr(o_string *o, int ch)
978{ 978{
979 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); 979 debug_printf("b_addchr: '%c' o->lengtt=%d o=%p\n", ch, o->length, o);
980 if (b_check_space(o, 1)) 980 if (b_check_space(o, 1))
981 return B_NOSPAC; 981 return B_NOSPAC;
982 o->data[o->length] = ch; 982 o->data[o->length] = ch;
@@ -1079,12 +1079,13 @@ static const char* setup_prompt_string(int promptmode)
1079static line_input_t *line_input_state; 1079static line_input_t *line_input_state;
1080#endif 1080#endif
1081 1081
1082static int get_user_input(struct in_str *i) 1082static void get_user_input(struct in_str *i)
1083{ 1083{
1084 static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2]; 1084 static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
1085 1085
1086 int r; 1086 int r;
1087 const char *prompt_str; 1087 const char *prompt_str;
1088
1088 prompt_str = setup_prompt_string(i->promptmode); 1089 prompt_str = setup_prompt_string(i->promptmode);
1089#if ENABLE_FEATURE_EDITING 1090#if ENABLE_FEATURE_EDITING
1090 /* 1091 /*
@@ -1094,15 +1095,19 @@ static int get_user_input(struct in_str *i)
1094 ** child processes (rob@sysgo.de) 1095 ** child processes (rob@sysgo.de)
1095 */ 1096 */
1096 r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state); 1097 r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state);
1098 i->eof_flag = (r < 0);
1099 if (i->eof_flag) { /* EOF/error detected */
1100 the_command[0] = EOF; /* yes, it will be truncated, it's ok */
1101 the_command[1] = '\0';
1102 }
1097#else 1103#else
1098 fputs(prompt_str, stdout); 1104 fputs(prompt_str, stdout);
1099 fflush(stdout); 1105 fflush(stdout);
1100 the_command[0] = r = fgetc(i->file); 1106 the_command[0] = r = fgetc(i->file);
1101 /*the_command[1] = '\0'; - already is and never changed */ 1107 /*the_command[1] = '\0'; - already is and never changed */
1108 i->eof_flag = (r == EOF);
1102#endif 1109#endif
1103 fflush(stdout);
1104 i->p = the_command; 1110 i->p = the_command;
1105 return r; /* < 0 == EOF. Not meaningful otherwise */
1106} 1111}
1107#endif /* INTERACTIVE */ 1112#endif /* INTERACTIVE */
1108 1113
@@ -1112,33 +1117,30 @@ static int file_get(struct in_str *i)
1112{ 1117{
1113 int ch; 1118 int ch;
1114 1119
1115 ch = 0;
1116 /* If there is data waiting, eat it up */ 1120 /* If there is data waiting, eat it up */
1117 if (i->cached_ch) { 1121 if (i->p && *i->p) {
1118 ch = i->cached_ch ^ 0x100; 1122 take_cached:
1119 if (ch != EOF) 1123 ch = *i->p++;
1120 i->cached_ch = 0; 1124 if (i->eof_flag && !*i->p)
1125 ch = EOF;
1121 } else { 1126 } else {
1122 /* need to double check i->file because we might be doing something 1127 /* need to double check i->file because we might be doing something
1123 * more complicated by now, like sourcing or substituting. */ 1128 * more complicated by now, like sourcing or substituting. */
1124#if ENABLE_HUSH_INTERACTIVE 1129#if ENABLE_HUSH_INTERACTIVE
1125 if (interactive_fd && i->__promptme && i->file == stdin) { 1130 if (interactive_fd && i->__promptme && i->file == stdin) {
1126 while (!i->p || !(interactive_fd && i->p[0])) { 1131 do {
1127 if (get_user_input(i) < 0) 1132 get_user_input(i);
1128 return EOF; 1133 } while (!*i->p); /* need non-empty line */
1129 }
1130 i->promptmode = 2; 1134 i->promptmode = 2;
1131 i->__promptme = 0; 1135 i->__promptme = 0;
1132 if (i->p && *i->p) { 1136 goto take_cached;
1133 ch = *i->p++;
1134 }
1135 } else 1137 } else
1136#endif 1138#endif
1137 { 1139 {
1138 ch = fgetc(i->file); 1140 ch = fgetc(i->file);
1139 } 1141 }
1140 debug_printf("file_get: got a %d\n", ch);
1141 } 1142 }
1143 debug_printf("file_get: got a '%c' %d\n", ch, ch);
1142#if ENABLE_HUSH_INTERACTIVE 1144#if ENABLE_HUSH_INTERACTIVE
1143 if (ch == '\n') 1145 if (ch == '\n')
1144 i->__promptme = 1; 1146 i->__promptme = 1;
@@ -1152,12 +1154,17 @@ static int file_get(struct in_str *i)
1152static int file_peek(struct in_str *i) 1154static int file_peek(struct in_str *i)
1153{ 1155{
1154 int ch; 1156 int ch;
1155 if (i->cached_ch) { 1157 if (i->p && *i->p) {
1156 return i->cached_ch ^ 0x100; 1158 if (i->eof_flag && !i->p[1])
1159 return EOF;
1160 return *i->p;
1157 } 1161 }
1158 ch = fgetc(i->file); 1162 ch = fgetc(i->file);
1159 i->cached_ch = ch ^ 0x100; /* ^ 0x100 so that it is never 0 */ 1163 i->eof_flag = (ch == EOF);
1160 debug_printf("file_peek: got a %d '%c'\n", ch, ch); 1164 i->peek_buf[0] = ch;
1165 i->peek_buf[1] = '\0';
1166 i->p = i->peek_buf;
1167 debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p);
1161 return ch; 1168 return ch;
1162} 1169}
1163 1170
@@ -1182,6 +1189,7 @@ static void setup_string_in_str(struct in_str *i, const char *s)
1182 i->promptmode = 1; 1189 i->promptmode = 1;
1183#endif 1190#endif
1184 i->p = s; 1191 i->p = s;
1192 i->eof_flag = 0;
1185} 1193}
1186 1194
1187static void mark_open(int fd) 1195static void mark_open(int fd)
@@ -2846,11 +2854,12 @@ static FILE *generate_stream_from_list(struct pipe *head)
2846static int process_command_subs(o_string *dest, struct p_context *ctx, 2854static int process_command_subs(o_string *dest, struct p_context *ctx,
2847 struct in_str *input, const char *subst_end) 2855 struct in_str *input, const char *subst_end)
2848{ 2856{
2849 int retcode; 2857 int retcode, ch, eol_cnt;
2850 o_string result = NULL_O_STRING; 2858 o_string result = NULL_O_STRING;
2851 struct p_context inner; 2859 struct p_context inner;
2852 FILE *p; 2860 FILE *p;
2853 struct in_str pipe_str; 2861 struct in_str pipe_str;
2862
2854 initialize_context(&inner); 2863 initialize_context(&inner);
2855 2864
2856 /* recursion to generate command */ 2865 /* recursion to generate command */
@@ -2863,25 +2872,20 @@ static int process_command_subs(o_string *dest, struct p_context *ctx,
2863 p = generate_stream_from_list(inner.list_head); 2872 p = generate_stream_from_list(inner.list_head);
2864 if (p == NULL) return 1; 2873 if (p == NULL) return 1;
2865 mark_open(fileno(p)); 2874 mark_open(fileno(p));
2866// FIXME: need to flag pipe_str to somehow discard all trailing newlines.
2867// Example: echo "TEST`date;echo;echo`BEST"
2868// must produce one line: TEST<date>BEST
2869 setup_file_in_str(&pipe_str, p); 2875 setup_file_in_str(&pipe_str, p);
2870 2876
2871 /* now send results of command back into original context */ 2877 /* now send results of command back into original context */
2872// FIXME: must not do quote parsing of the output! 2878 eol_cnt = 0;
2873// Example: echo "TEST`echo '$(echo ZZ)'`BEST" 2879 while ((ch = b_getch(&pipe_str)) != EOF) {
2874// must produce TEST$(echo ZZ)BEST, not TESTZZBEST. 2880 if (ch == '\n') {
2875// Example: echo "TEST`echo "'"`BEST" 2881 eol_cnt++;
2876// must produce TEST'BEST 2882 continue;
2877// (maybe by setting all chars flagged as literals in map[]?) 2883 }
2878 2884 while (eol_cnt) {
2879 retcode = parse_stream(dest, ctx, &pipe_str, NULL); 2885 b_addqchr(dest, '\n', dest->quote);
2880 /* XXX In case of a syntax error, should we try to kill the child? 2886 eol_cnt--;
2881 * That would be tough to do right, so just read until EOF. */ 2887 }
2882 if (retcode == 1) { 2888 b_addqchr(dest, ch, dest->quote);
2883 while (b_getch(&pipe_str) != EOF)
2884 /* discard */;
2885 } 2889 }
2886 2890
2887 debug_printf("done reading from pipe, pclose()ing\n"); 2891 debug_printf("done reading from pipe, pclose()ing\n");