BSD 4_3_Net_2 release
[unix-history] / usr / src / contrib / isode / dirent / scandir.c
/* used by permission */
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)scandir.c 5.9 (Berkeley) 6/24/90";
#endif /* LIBC_SCCS and not lint */
/*
* Scan the directory dirname calling select to make a list of selected
* directory entries then sort using qsort and compare routine dcomp.
* Returns the number of entries and a pointer to a list of pointers to
* struct dirent (through namelist). Returns -1 if there were any errors.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include "usr.dirent.h"
/*
* The DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This requires the amount of space in struct dirent
* without the d_name field, plus enough space for the name with a terminating
* null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
*/
#undef DIRSIZ
#define DIRSIZ(dp) \
((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
char *malloc (), *realloc ();
scandir(dirname, namelist, select, dcomp)
char *dirname;
struct dirent ***namelist;
int (*select)(), (*dcomp)();
{
register struct dirent *d, *p, **names;
register int nitems;
struct stat stb;
long arraysz;
DIR *dirp;
if ((dirp = opendir(dirname)) == NULL)
return(-1);
if (fstat(dirp->dd_fd, &stb) < 0)
return(-1);
/*
* estimate the array size by taking the size of the directory file
* and dividing it by a multiple of the minimum size entry.
*/
arraysz = (stb.st_size / 24);
names = (struct dirent **)malloc((unsigned int) (arraysz * sizeof(struct dirent *)));
if (names == NULL)
return(-1);
nitems = 0;
while ((d = readdir(dirp)) != NULL) {
if (select != NULL && !(*select)(d))
continue; /* just selected names */
/*
* Make a minimum size copy of the data
*/
/*
p = (struct dirent *)malloc(DIRSIZ(d));
*/
p = (struct dirent *)malloc((unsigned int) d->d_reclen);
if (p == NULL)
return(-1);
/*
p->d_ino = d->d_ino;
p->d_reclen = d->d_reclen;
p->d_namlen = d->d_namlen;
bcopy(d->d_name, p->d_name, p->d_namlen + 1);
*/
bcopy((char *)d, (char *)p, (int)d->d_reclen);
/*
* Check to make sure the array has space left and
* realloc the maximum size.
*/
if (++nitems >= arraysz) {
if (fstat(dirp->dd_fd, &stb) < 0)
return(-1); /* just might have grown */
arraysz = stb.st_size / 12;
names = (struct dirent **)realloc((char *)names,
(unsigned int) arraysz * sizeof(struct dirent *));
if (names == NULL)
return(-1);
}
names[nitems-1] = p;
}
(void) closedir(dirp);
if (nitems && dcomp != NULL)
qsort((char *) names, nitems, sizeof(struct dirent *), dcomp);
*namelist = names;
return(nitems);
}
/*
* Alphabetic order comparison routine for those who want it.
*/
alphasort(d1, d2)
caddr_t d1, d2;
{
return(strcmp((*(struct dirent **)d1)->d_name,
(*(struct dirent **)d2)->d_name));
}