Improve IFS expansion using code from NetBSD.

We now pass the ifs.sh testsuite.

PR:		standards/79067
Approved by:	ed (mentor) (implicit)
Obtained from:	NetBSD
This commit is contained in:
jilles 2009-06-25 17:10:51 +00:00
parent 56ea66b4d9
commit a02858661b

View File

@ -82,7 +82,7 @@ struct ifsregion {
struct ifsregion *next; /* next region in list */
int begoff; /* offset of start of region */
int endoff; /* offset of end of region */
int nulonly; /* search for nul bytes only */
int inquotes; /* search for nul bytes only */
};
@ -936,13 +936,19 @@ varvalue(char *name, int quoted, int subtype, int flag)
*/
STATIC void
recordregion(int start, int end, int nulonly)
recordregion(int start, int end, int inquotes)
{
struct ifsregion *ifsp;
if (ifslastp == NULL) {
ifsp = &ifsfirst;
} else {
if (ifslastp->endoff == start
&& ifslastp->inquotes == inquotes) {
/* extend previous area */
ifslastp->endoff = end;
return;
}
ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
ifslastp->next = ifsp;
}
@ -950,7 +956,7 @@ recordregion(int start, int end, int nulonly)
ifslastp->next = NULL;
ifslastp->begoff = start;
ifslastp->endoff = end;
ifslastp->nulonly = nulonly;
ifslastp->inquotes = inquotes;
}
@ -969,75 +975,88 @@ ifsbreakup(char *string, struct arglist *arglist)
char *p;
char *q;
char *ifs;
int ifsspc;
int nulonly;
const char *ifsspc;
int had_param_ch = 0;
start = string;
ifsspc = 0;
nulonly = 0;
if (ifslastp != NULL) {
ifsp = &ifsfirst;
do {
p = string + ifsp->begoff;
nulonly = ifsp->nulonly;
ifs = nulonly ? nullstr :
( ifsset() ? ifsval() : " \t\n" );
ifsspc = 0;
while (p < string + ifsp->endoff) {
q = p;
if (*p == CTLESC)
if (ifslastp == NULL) {
/* Return entire argument, IFS doesn't apply to any of it */
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = start;
*arglist->lastp = sp;
arglist->lastp = &sp->next;
return;
}
ifs = ifsset() ? ifsval() : " \t\n";
for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
p = string + ifsp->begoff;
while (p < string + ifsp->endoff) {
had_param_ch = 1;
q = p;
if (*p == CTLESC)
p++;
if (ifsp->inquotes) {
/* Only NULs (should be from "$@") end args */
if (*p != 0) {
p++;
if (strchr(ifs, *p)) {
if (!nulonly)
ifsspc = (strchr(" \t\n", *p) != NULL);
/* Ignore IFS whitespace at start */
if (q == start && ifsspc) {
p++;
start = p;
continue;
}
*q = '\0';
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = start;
*arglist->lastp = sp;
arglist->lastp = &sp->next;
continue;
}
ifsspc = NULL;
} else {
if (!strchr(ifs, *p)) {
p++;
continue;
}
had_param_ch = 0;
ifsspc = strchr(" \t\n", *p);
/* Ignore IFS whitespace at start */
if (q == start && ifsspc != NULL) {
p++;
if (!nulonly) {
for (;;) {
if (p >= string + ifsp->endoff) {
break;
}
q = p;
if (*p == CTLESC)
p++;
if (strchr(ifs, *p) == NULL ) {
p = q;
break;
} else if (strchr(" \t\n",*p) == NULL) {
if (ifsspc) {
p++;
ifsspc = 0;
} else {
p = q;
break;
}
} else
p++;
}
}
start = p;
} else
p++;
continue;
}
}
} while ((ifsp = ifsp->next) != NULL);
if (*start || (!ifsspc && start > string)) {
/* Save this argument... */
*q = '\0';
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = start;
*arglist->lastp = sp;
arglist->lastp = &sp->next;
p++;
if (ifsspc != NULL) {
/* Ignore further trailing IFS whitespace */
for (; p < string + ifsp->endoff; p++) {
q = p;
if (*p == CTLESC)
p++;
if (strchr(ifs, *p) == NULL) {
p = q;
break;
}
if (strchr(" \t\n", *p) == NULL) {
p++;
break;
}
}
}
start = p;
}
} else {
}
/*
* Save anything left as an argument.
* Traditionally we have treated 'IFS=':'; set -- x$IFS' as
* generating 2 arguments, the second of which is empty.
* Some recent clarification of the Posix spec say that it
* should only generate one....
*/
if (had_param_ch || *start != 0) {
sp = (struct strlist *)stalloc(sizeof *sp);
sp->text = start;
*arglist->lastp = sp;