Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Mar 2009 22:09:12 +0000 (UTC)
From:      Stefan Farfeleder <stefanf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r190295 - head/bin/sh
Message-ID:  <200903222209.n2MM9Cuk085475@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: stefanf
Date: Sun Mar 22 22:09:12 2009
New Revision: 190295
URL: http://svn.freebsd.org/changeset/base/190295

Log:
  Improve the IFS handling of the read built-in.
  
  Obtained from:	NetBSD
  Submitted by:	Jilles Tjoelker

Modified:
  head/bin/sh/miscbltin.c

Modified: head/bin/sh/miscbltin.c
==============================================================================
--- head/bin/sh/miscbltin.c	Sun Mar 22 22:08:30 2009	(r190294)
+++ head/bin/sh/miscbltin.c	Sun Mar 22 22:09:12 2009	(r190295)
@@ -73,6 +73,16 @@ int ulimitcmd(int, char **);
  * ordinary characters.
  *
  * This uses unbuffered input, which may be avoidable in some cases.
+ *
+ * Note that if IFS=' :' then read x y should work so that:
+ * 'a b'	x='a', y='b'
+ * ' a b '	x='a', y='b'
+ * ':b'		x='',  y='b'
+ * ':'		x='',  y=''
+ * '::'		x='',  y=''
+ * ': :'	x='',  y=''
+ * ':::'	x='',  y='::'
+ * ':b c:'	x='',  y='b c:'
  */
 
 int
@@ -88,6 +98,8 @@ readcmd(int argc __unused, char **argv _
 	int startword;
 	int status;
 	int i;
+	int is_ifs;
+	int saveall = 0;
 	struct timeval tv;
 	char *tvptr;
 	fd_set ifds;
@@ -167,7 +179,7 @@ readcmd(int argc __unused, char **argv _
 	}
 
 	status = 0;
-	startword = 1;
+	startword = 2;
 	backslash = 0;
 	STARTSTACKSTR(p);
 	for (;;) {
@@ -189,22 +201,68 @@ readcmd(int argc __unused, char **argv _
 		}
 		if (c == '\n')
 			break;
-		if (startword && *ifs == ' ' && strchr(ifs, c)) {
+		if (strchr(ifs, c))
+			is_ifs = strchr(" \t\n", c) ? 1 : 2;
+		else
+			is_ifs = 0;
+
+		if (startword != 0) {
+			if (is_ifs == 1) {
+				/* Ignore leading IFS whitespace */
+				if (saveall)
+					STPUTC(c, p);
+				continue;
+			}
+			if (is_ifs == 2 && startword == 1) {
+				/* Only one non-whitespace IFS per word */
+				startword = 2;
+				if (saveall)
+					STPUTC(c, p);
+				continue;
+			}
+		}
+
+		if (is_ifs == 0) {
+			/* append this character to the current variable */
+			startword = 0;
+			if (saveall)
+				/* Not just a spare terminator */
+				saveall++;
+			STPUTC(c, p);
 			continue;
 		}
-		startword = 0;
-		if (ap[1] != NULL && strchr(ifs, c) != NULL) {
-			STACKSTRNUL(p);
-			setvar(*ap, stackblock(), 0);
-			ap++;
-			startword = 1;
-			STARTSTACKSTR(p);
-		} else {
+
+		/* end of variable... */
+		startword = is_ifs;
+
+		if (ap[1] == NULL) {
+			/* Last variable needs all IFS chars */
+			saveall++;
 			STPUTC(c, p);
+			continue;
 		}
+
+		STACKSTRNUL(p);
+		setvar(*ap, stackblock(), 0);
+		ap++;
+		STARTSTACKSTR(p);
 	}
 	STACKSTRNUL(p);
+
+	/* Remove trailing IFS chars */
+	for (; stackblock() <= --p; *p = 0) {
+		if (!strchr(ifs, *p))
+			break;
+		if (strchr(" \t\n", *p))
+			/* Always remove whitespace */
+			continue;
+		if (saveall > 1)
+			/* Don't remove non-whitespace unless it was naked */
+			break;
+	}
 	setvar(*ap, stackblock(), 0);
+
+	/* Set any remaining args to "" */
 	while (*++ap != NULL)
 		setvar(*ap, nullstr, 0);
 	return status;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903222209.n2MM9Cuk085475>