svn commit: r201604 - head/lib/libc/gen

Konstantin Belousov kib at FreeBSD.org
Tue Jan 5 20:20:32 UTC 2010


Author: kib
Date: Tue Jan  5 20:20:31 2010
New Revision: 201604
URL: http://svn.freebsd.org/changeset/base/201604

Log:
  Do not rely on behaviour undefined by ANSI C, use thunks to adapt
  alphasort-like interface to the comparision function required by
  qsort() and qsort_r().
  
  For opendir() thunk and alphasort(), comment on why we deviated from
  POSIX by using strcmp() instead of strcoll().
  
  Requested and reviewed by:	bde
  MFC after:	2 weeks

Modified:
  head/lib/libc/gen/opendir.c
  head/lib/libc/gen/scandir.c

Modified: head/lib/libc/gen/opendir.c
==============================================================================
--- head/lib/libc/gen/opendir.c	Tue Jan  5 20:18:41 2010	(r201603)
+++ head/lib/libc/gen/opendir.c	Tue Jan  5 20:20:31 2010	(r201604)
@@ -93,6 +93,18 @@ __opendir2(const char *name, int flags)
 }
 
 /*
+ * POSIX 2008 and XSI 7 require alphasort() to call strcoll() for
+ * directory entries ordering.  Use local copy that uses strcmp().
+ */
+static int
+opendir_alphasort(const void *p1, const void *p2)
+{
+
+	return (strcmp((*(const struct dirent **)p1)->d_name,
+	    (*(const struct dirent **)p2)->d_name));
+}
+
+/*
  * Common routine for opendir(3), __opendir2(3) and fdopendir(3).
  */
 static DIR *
@@ -240,8 +252,8 @@ __opendir_common(int fd, const char *nam
 				/*
 				 * This sort must be stable.
 				 */
-				mergesort(dpv, n, sizeof(*dpv), (int (*)(const
-				    void *, const void *))alphasort);
+				mergesort(dpv, n, sizeof(*dpv),
+				    opendir_alphasort);
 
 				dpv[n] = NULL;
 				xp = NULL;

Modified: head/lib/libc/gen/scandir.c
==============================================================================
--- head/lib/libc/gen/scandir.c	Tue Jan  5 20:18:41 2010	(r201603)
+++ head/lib/libc/gen/scandir.c	Tue Jan  5 20:20:31 2010	(r201604)
@@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include "un-namespace.h"
 
+static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
+
 /*
  * The DIRSIZ macro is the minimum record length which will hold the directory
  * entry.  This requires the amount of space in struct dirent without the
@@ -109,8 +111,8 @@ scandir(const char *dirname, struct dire
 	}
 	closedir(dirp);
 	if (nitems && dcomp != NULL)
-		qsort(names, nitems, sizeof(struct dirent *),
-		    (int (*)(const void *, const void *))dcomp);
+		qsort_r(names, nitems, sizeof(struct dirent *),
+		    &dcomp, alphasort_thunk);
 	*namelist = names;
 	return (nitems);
 
@@ -124,6 +126,12 @@ fail:
 
 /*
  * Alphabetic order comparison routine for those who want it.
+ *
+ * XXXKIB POSIX 2008 requires the alphasort() to use strcoll().  Keep
+ * strcmp() for now, since environment locale settings could have no
+ * relevance for the byte sequence of the file name. Moreover, it
+ * might be even invalid sequence in current locale, and then
+ * behaviour of alphasort would be undefined.
  */
 int
 alphasort(const struct dirent **d1, const struct dirent **d2)
@@ -131,3 +139,12 @@ alphasort(const struct dirent **d1, cons
 
 	return (strcmp((*d1)->d_name, (*d2)->d_name));
 }
+
+static int
+alphasort_thunk(void *thunk, const void *p1, const void *p2)
+{
+	int (*dc)(const struct dirent **, const struct dirent **);
+
+	dc = *(int (**)(const struct dirent **, const struct dirent **))thunk;
+	return (dc((const struct dirent **)p1, (const struct dirent **)p2));
+}


More information about the svn-src-all mailing list