Author: jilles
Date: Thu Jun 25 17:10:51 2009
New Revision: 194975
URL: http://svn.freebsd.org/changeset/base/194975

Log:
  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

Modified:
  head/bin/sh/expand.c

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c        Thu Jun 25 16:48:13 2009        (r194974)
+++ head/bin/sh/expand.c        Thu Jun 25 17:10:51 2009        (r194975)
@@ -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 nul
        ifslastp->next = NULL;
        ifslastp->begoff = start;
        ifslastp->endoff = end;
-       ifslastp->nulonly = nulonly;
+       ifslastp->inquotes = inquotes;
 }
 
 
@@ -969,75 +975,88 @@ ifsbreakup(char *string, struct 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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to