diff options
author | jilles <jilles@FreeBSD.org> | 2009-06-25 17:10:51 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2009-06-25 17:10:51 +0000 |
commit | a02858661b227e361a74d5d710fbd6ce9028c4d6 (patch) | |
tree | 4b6b5cc8a0757ece7e908fb9549f7460ef231692 /bin/sh | |
parent | 56ea66b4d90c46b1596ea4e0f539a23d372c7665 (diff) | |
download | FreeBSD-src-a02858661b227e361a74d5d710fbd6ce9028c4d6.zip FreeBSD-src-a02858661b227e361a74d5d710fbd6ce9028c4d6.tar.gz |
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
Diffstat (limited to 'bin/sh')
-rw-r--r-- | bin/sh/expand.c | 141 |
1 files changed, 80 insertions, 61 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 2f0b9fd..ac77e8a 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -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 @@ numvar: */ 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++; - 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 + continue; + } + had_param_ch = 0; + ifsspc = strchr(" \t\n", *p); + + /* Ignore IFS whitespace at start */ + if (q == start && ifsspc != NULL) { p++; + start = 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; |