Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/bin/sh Fix the way the 'read' builtin processes IFS. In par...
details: https://anonhg.NetBSD.org/src/rev/965904ecdb13
branches: trunk
changeset: 579608:965904ecdb13
user: dsl <dsl%NetBSD.org@localhost>
date: Sat Mar 19 14:22:50 2005 +0000
description:
Fix the way the 'read' builtin processes IFS. In particular:
- IFS whitespace is now processes correctly,
- Trailing non-whitespace IFS characters are added to the last variable
iff a subsequent variable would have been assigned a non-null string.
Now passes the 'read' tests in http://www.research.att.com/~gsf/public/ifs.sh
diffstat:
bin/sh/miscbltin.c | 116 +++++++++++++++++++++++++++++++++++++---------------
1 files changed, 83 insertions(+), 33 deletions(-)
diffs (187 lines):
diff -r 1c3d05eff441 -r 965904ecdb13 bin/sh/miscbltin.c
--- a/bin/sh/miscbltin.c Sat Mar 19 13:00:55 2005 +0000
+++ b/bin/sh/miscbltin.c Sat Mar 19 14:22:50 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: miscbltin.c,v 1.34 2004/04/19 01:36:32 lukem Exp $ */
+/* $NetBSD: miscbltin.c,v 1.35 2005/03/19 14:22:50 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
#else
-__RCSID("$NetBSD: miscbltin.c,v 1.34 2004/04/19 01:36:32 lukem Exp $");
+__RCSID("$NetBSD: miscbltin.c,v 1.35 2005/03/19 14:22:50 dsl Exp $");
#endif
#endif /* not lint */
@@ -69,25 +69,36 @@
/*
- * The read builtin. The -e option causes backslashes to escape the
- * following character.
+ * The read builtin.
+ * Backslahes escape the next char unless -r is specified.
*
* 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
readcmd(int argc, char **argv)
{
char **ap;
- int backslash;
char c;
int rflag;
char *prompt;
- char *ifs;
+ const char *ifs;
char *p;
int startword;
int status;
int i;
+ int is_ifs;
+ int saveall = 0;
rflag = 0;
prompt = NULL;
@@ -97,17 +108,20 @@
else
rflag = 1;
}
+
if (prompt && isatty(0)) {
out2str(prompt);
flushall();
}
+
if (*(ap = argptr) == NULL)
error("arg count");
+
if ((ifs = bltinlookup("IFS", 1)) == NULL)
- ifs = nullstr;
+ ifs = " \t\n";
+
status = 0;
- startword = 1;
- backslash = 0;
+ startword = 2;
STARTSTACKSTR(p);
for (;;) {
if (read(0, &c, 1) != 1) {
@@ -116,43 +130,79 @@
}
if (c == '\0')
continue;
- if (backslash) {
- backslash = 0;
+ if (c == '\\' && !rflag) {
+ if (read(0, &c, 1) != 1) {
+ status = 1;
+ break;
+ }
if (c != '\n')
STPUTC(c, p);
continue;
}
- if (!rflag && c == '\\') {
- backslash++;
- continue;
- }
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 (backslash && c == '\\') {
- if (read(0, &c, 1) != 1) {
- status = 1;
- break;
- }
+
+ /* end of variable... */
+ startword = is_ifs;
+
+ if (ap[1] == NULL) {
+ /* Last variable needs all IFS chars */
+ saveall++;
STPUTC(c, p);
- } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
- STACKSTRNUL(p);
- setvar(*ap, stackblock(), 0);
- ap++;
- startword = 1;
- STARTSTACKSTR(p);
- } else {
- STPUTC(c, p);
+ continue;
}
+
+ STACKSTRNUL(p);
+ setvar(*ap, stackblock(), 0);
+ ap++;
+ STARTSTACKSTR(p);
}
STACKSTRNUL(p);
- /* Remove trailing blanks */
- while (stackblock() <= --p && strchr(ifs, *p) != NULL)
- *p = '\0';
+
+ /* 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;
Home |
Main Index |
Thread Index |
Old Index