about summary refs log tree commit diff
path: root/Src/glob.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2016-07-18 16:56:34 +0100
committerPeter Stephenson <pws@zsh.org>2016-07-18 16:57:38 +0100
commit72e5fe7aab91e21d0d746ec7137a6e4e0b405e39 (patch)
treec6797d412f818c92bc502c1e6cf8d6f4887b737e /Src/glob.c
parentbd707b47875a5bc61b2bea2d7ffd2ed8738afcce (diff)
downloadzsh-72e5fe7aab91e21d0d746ec7137a6e4e0b405e39.tar.gz
zsh-72e5fe7aab91e21d0d746ec7137a6e4e0b405e39.tar.xz
zsh-72e5fe7aab91e21d0d746ec7137a6e4e0b405e39.zip
38879: Unmetafy file names for glob sort.
Test using Polish UTF-8 collation sequence that'w known to
cause the problems.
Diffstat (limited to 'Src/glob.c')
-rw-r--r--Src/glob.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/Src/glob.c b/Src/glob.c
index 2051016ec..146b4dbbc 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -41,7 +41,10 @@
 typedef struct gmatch *Gmatch;
 
 struct gmatch {
+    /* Metafied file name */
     char *name;
+    /* Unmetafied file name; embedded nulls can't occur in file names */
+    char *uname;
     /*
      * Array of sort strings:  one for each GS_EXEC sort type in
      * the glob qualifiers.
@@ -911,7 +914,8 @@ gmatchcmp(Gmatch a, Gmatch b)
     for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
 	switch (s->tp & ~GS_DESC) {
 	case GS_NAME:
-	    r = zstrcmp(b->name, a->name, gf_numsort ? SORTIT_NUMERICALLY : 0);
+	    r = zstrcmp(b->uname, a->uname,
+			gf_numsort ? SORTIT_NUMERICALLY : 0);
 	    break;
 	case GS_DEPTH:
 	    {
@@ -1859,6 +1863,7 @@ zglob(LinkList list, LinkNode np, int nountok)
 	int nexecs = 0;
 	struct globsort *sortp;
 	struct globsort *lastsortp = gf_sortlist + gf_nsorts;
+	Gmatch gmptr;
 
 	/* First find out if there are any GS_EXECs, counting them. */
 	for (sortp = gf_sortlist; sortp < lastsortp; sortp++)
@@ -1910,6 +1915,29 @@ zglob(LinkList list, LinkNode np, int nountok)
 	    }
 	}
 
+	/*
+	 * Where necessary, create unmetafied version of names
+	 * for comparison.  If no Meta characters just point
+	 * to original string.  All on heap.
+	 */
+	for (gmptr = matchbuf; gmptr < matchptr; gmptr++)
+	{
+	    char *nptr;
+	    for (nptr = gmptr->name; *nptr; nptr++)
+	    {
+		if (*nptr == Meta)
+		    break;
+	    }
+	    if (*nptr == Meta)
+	    {
+		int dummy;
+		gmptr->uname = dupstring(gmptr->name);
+		unmetafy(gmptr->uname, &dummy);
+	    } else {
+		gmptr->uname = gmptr->name;
+	    }
+	}
+
 	/* Sort arguments in to lexical (and possibly numeric) order. *
 	 * This is reversed to facilitate insertion into the list.    */
 	qsort((void *) & matchbuf[0], matchct, sizeof(struct gmatch),