svn commit: trunk/busybox/shell

vda at busybox.net vda at busybox.net
Fri May 11 05:56:44 PDT 2007


Author: vda
Date: 2007-05-11 05:56:43 -0700 (Fri, 11 May 2007)
New Revision: 18608

Log:
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


Removed:
   trunk/busybox/shell/hush_test/

Modified:
   trunk/busybox/shell/hush.c


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2007-05-11 12:50:15 UTC (rev 18607)
+++ trunk/busybox/shell/hush.c	2007-05-11 12:56:43 UTC (rev 18608)
@@ -317,10 +317,10 @@
 /* I can almost use ordinary FILE *.  Is open_memstream() universally
  * available?  Where is it documented? */
 struct in_str {
-	union {
-		const char *p;
-		int cached_ch;
-	};
+	const char *p;
+	/* eof_flag=1: last char in ->p is really an EOF */
+	char eof_flag; /* meaningless if ->p == NULL */
+	char peek_buf[2];
 #if ENABLE_HUSH_INTERACTIVE
 	int __promptme;
 	int promptmode;
@@ -976,7 +976,7 @@
 
 static int b_addchr(o_string *o, int ch)
 {
-	debug_printf("b_addchr: %c %d %p\n", ch, o->length, o);
+	debug_printf("b_addchr: '%c' o->lengtt=%d o=%p\n", ch, o->length, o);
 	if (b_check_space(o, 1))
 		return B_NOSPAC;
 	o->data[o->length] = ch;
@@ -1079,12 +1079,13 @@
 static line_input_t *line_input_state;
 #endif
 
-static int get_user_input(struct in_str *i)
+static void get_user_input(struct in_str *i)
 {
 	static char the_command[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
 
 	int r;
 	const char *prompt_str;
+
 	prompt_str = setup_prompt_string(i->promptmode);
 #if ENABLE_FEATURE_EDITING
 	/*
@@ -1094,15 +1095,19 @@
 	 ** child processes (rob at sysgo.de)
 	 */
 	r = read_line_input(prompt_str, the_command, BUFSIZ-1, line_input_state);
+	i->eof_flag = (r < 0);
+	if (i->eof_flag) { /* EOF/error detected */
+		the_command[0] = EOF; /* yes, it will be truncated, it's ok */
+		the_command[1] = '\0';
+	}
 #else
 	fputs(prompt_str, stdout);
 	fflush(stdout);
 	the_command[0] = r = fgetc(i->file);
 	/*the_command[1] = '\0'; - already is and never changed */
+	i->eof_flag = (r == EOF);
 #endif
-	fflush(stdout);
 	i->p = the_command;
-	return r; /* < 0 == EOF. Not meaningful otherwise */
 }
 #endif  /* INTERACTIVE */
 
@@ -1112,33 +1117,30 @@
 {
 	int ch;
 
-	ch = 0;
 	/* If there is data waiting, eat it up */
-	if (i->cached_ch) {
-		ch = i->cached_ch ^ 0x100;
-		if (ch != EOF)
-			i->cached_ch = 0;
+	if (i->p && *i->p) {
+ take_cached:
+		ch = *i->p++;
+		if (i->eof_flag && !*i->p)
+			ch = EOF;
 	} else {
 		/* need to double check i->file because we might be doing something
 		 * more complicated by now, like sourcing or substituting. */
 #if ENABLE_HUSH_INTERACTIVE
 		if (interactive_fd && i->__promptme && i->file == stdin) {
-			while (!i->p || !(interactive_fd && i->p[0])) {
-				if (get_user_input(i) < 0)
-					return EOF;
-			}
+			do {
+				get_user_input(i);
+			} while (!*i->p); /* need non-empty line */
 			i->promptmode = 2;
 			i->__promptme = 0;
-			if (i->p && *i->p) {
-				ch = *i->p++;
-			}
+			goto take_cached;
 		} else
 #endif
 		{
 			ch = fgetc(i->file);
 		}
-		debug_printf("file_get: got a %d\n", ch);
 	}
+	debug_printf("file_get: got a '%c' %d\n", ch, ch);
 #if ENABLE_HUSH_INTERACTIVE
 	if (ch == '\n')
 		i->__promptme = 1;
@@ -1152,12 +1154,17 @@
 static int file_peek(struct in_str *i)
 {
 	int ch;
-	if (i->cached_ch) {
-		return i->cached_ch ^ 0x100;
+	if (i->p && *i->p) {
+		if (i->eof_flag && !i->p[1])
+			return EOF;
+		return *i->p;
 	}
 	ch = fgetc(i->file);
-	i->cached_ch = ch ^ 0x100; /* ^ 0x100 so that it is never 0 */
-	debug_printf("file_peek: got a %d '%c'\n", ch, ch);
+	i->eof_flag = (ch == EOF);
+	i->peek_buf[0] = ch;
+	i->peek_buf[1] = '\0';
+	i->p = i->peek_buf;
+	debug_printf("file_peek: got a '%c' %d\n", *i->p, *i->p);
 	return ch;
 }
 
@@ -1182,6 +1189,7 @@
 	i->promptmode = 1;
 #endif
 	i->p = s;
+	i->eof_flag = 0;
 }
 
 static void mark_open(int fd)
@@ -2846,11 +2854,12 @@
 static int process_command_subs(o_string *dest, struct p_context *ctx,
 	struct in_str *input, const char *subst_end)
 {
-	int retcode;
+	int retcode, ch, eol_cnt;
 	o_string result = NULL_O_STRING;
 	struct p_context inner;
 	FILE *p;
 	struct in_str pipe_str;
+
 	initialize_context(&inner);
 
 	/* recursion to generate command */
@@ -2863,25 +2872,20 @@
 	p = generate_stream_from_list(inner.list_head);
 	if (p == NULL) return 1;
 	mark_open(fileno(p));
-// FIXME: need to flag pipe_str to somehow discard all trailing newlines.
-// Example: echo "TEST`date;echo;echo`BEST"
-//          must produce one line: TEST<date>BEST
 	setup_file_in_str(&pipe_str, p);
 
 	/* now send results of command back into original context */
-// FIXME: must not do quote parsing of the output!
-// Example: echo "TEST`echo '$(echo ZZ)'`BEST"
-//          must produce TEST$(echo ZZ)BEST, not TESTZZBEST.
-// Example: echo "TEST`echo "'"`BEST"
-//          must produce TEST'BEST
-// (maybe by setting all chars flagged as literals in map[]?)
-
-	retcode = parse_stream(dest, ctx, &pipe_str, NULL);
-	/* XXX In case of a syntax error, should we try to kill the child?
-	 * That would be tough to do right, so just read until EOF. */
-	if (retcode == 1) {
-		while (b_getch(&pipe_str) != EOF)
-			/* discard */;
+	eol_cnt = 0;
+	while ((ch = b_getch(&pipe_str)) != EOF) {
+		if (ch == '\n') {
+			eol_cnt++;
+			continue;
+		}
+		while (eol_cnt) {
+			b_addqchr(dest, '\n', dest->quote);
+			eol_cnt--;
+		}
+		b_addqchr(dest, ch, dest->quote);
 	}
 
 	debug_printf("done reading from pipe, pclose()ing\n");



More information about the busybox-cvs mailing list