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
This commit is contained in:
Konstantin Belousov 2010-01-05 20:20:31 +00:00
parent 7b331f63c5
commit f5636f881b
2 changed files with 33 additions and 4 deletions

View File

@ -92,6 +92,18 @@ __opendir2(const char *name, int flags)
return __opendir_common(fd, name, 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).
*/
@ -240,8 +252,8 @@ __opendir_common(int fd, const char *name, int flags)
/*
* 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;

View File

@ -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 dirent ***namelist,
}
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, const struct dirent **d2)
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));
}