summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2009-06-25 17:10:51 +0000
committerjilles <jilles@FreeBSD.org>2009-06-25 17:10:51 +0000
commita02858661b227e361a74d5d710fbd6ce9028c4d6 (patch)
tree4b6b5cc8a0757ece7e908fb9549f7460ef231692 /bin/sh/expand.c
parent56ea66b4d90c46b1596ea4e0f539a23d372c7665 (diff)
downloadFreeBSD-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/expand.c')
-rw-r--r--bin/sh/expand.c141
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;
OpenPOWER on IntegriCloud