From owner-svn-src-head@FreeBSD.ORG Sun Mar 22 22:09:13 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 37A81106566C; Sun, 22 Mar 2009 22:09:13 +0000 (UTC) (envelope-from stefanf@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0CCF58FC25; Sun, 22 Mar 2009 22:09:13 +0000 (UTC) (envelope-from stefanf@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n2MM9C6r085476; Sun, 22 Mar 2009 22:09:12 GMT (envelope-from stefanf@svn.freebsd.org) Received: (from stefanf@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n2MM9Cuk085475; Sun, 22 Mar 2009 22:09:12 GMT (envelope-from stefanf@svn.freebsd.org) Message-Id: <200903222209.n2MM9Cuk085475@svn.freebsd.org> From: Stefan Farfeleder Date: Sun, 22 Mar 2009 22:09:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r190295 - head/bin/sh X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 22 Mar 2009 22:09:14 -0000 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;