Improve the IFS handling of the read built-in.
Obtained from: NetBSD Submitted by: Jilles Tjoelker
This commit is contained in:
parent
c0055de891
commit
7836b44d7b
@ -73,6 +73,16 @@ int ulimitcmd(int, char **);
|
|||||||
* ordinary characters.
|
* ordinary characters.
|
||||||
*
|
*
|
||||||
* This uses unbuffered input, which may be avoidable in some cases.
|
* 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
|
int
|
||||||
@ -88,6 +98,8 @@ readcmd(int argc __unused, char **argv __unused)
|
|||||||
int startword;
|
int startword;
|
||||||
int status;
|
int status;
|
||||||
int i;
|
int i;
|
||||||
|
int is_ifs;
|
||||||
|
int saveall = 0;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
char *tvptr;
|
char *tvptr;
|
||||||
fd_set ifds;
|
fd_set ifds;
|
||||||
@ -167,7 +179,7 @@ readcmd(int argc __unused, char **argv __unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
startword = 1;
|
startword = 2;
|
||||||
backslash = 0;
|
backslash = 0;
|
||||||
STARTSTACKSTR(p);
|
STARTSTACKSTR(p);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -189,22 +201,68 @@ readcmd(int argc __unused, char **argv __unused)
|
|||||||
}
|
}
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
break;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
startword = 0;
|
|
||||||
if (ap[1] != NULL && strchr(ifs, c) != NULL) {
|
/* end of variable... */
|
||||||
STACKSTRNUL(p);
|
startword = is_ifs;
|
||||||
setvar(*ap, stackblock(), 0);
|
|
||||||
ap++;
|
if (ap[1] == NULL) {
|
||||||
startword = 1;
|
/* Last variable needs all IFS chars */
|
||||||
STARTSTACKSTR(p);
|
saveall++;
|
||||||
} else {
|
|
||||||
STPUTC(c, p);
|
STPUTC(c, p);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STACKSTRNUL(p);
|
||||||
|
setvar(*ap, stackblock(), 0);
|
||||||
|
ap++;
|
||||||
|
STARTSTACKSTR(p);
|
||||||
}
|
}
|
||||||
STACKSTRNUL(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);
|
setvar(*ap, stackblock(), 0);
|
||||||
|
|
||||||
|
/* Set any remaining args to "" */
|
||||||
while (*++ap != NULL)
|
while (*++ap != NULL)
|
||||||
setvar(*ap, nullstr, 0);
|
setvar(*ap, nullstr, 0);
|
||||||
return status;
|
return status;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user