]> git.saurik.com Git - apple/libc.git/blobdiff - gen/scandir.c
Libc-262.tar.gz
[apple/libc.git] / gen / scandir.c
diff --git a/gen/scandir.c b/gen/scandir.c
new file mode 100644 (file)
index 0000000..d963bbd
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/*
+ * 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 <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * 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
+ * d_name field, plus enough space for the name and a terminating nul byte
+ * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
+ */
+#undef DIRSIZ
+#define DIRSIZ(dp)                                                     \
+       ((sizeof(struct dirent) - sizeof(dp)->d_name) +                 \
+           (((dp)->d_namlen + 1 + 3) &~ 3))
+
+int
+scandir(dirname, namelist, select, dcomp)
+       const char *dirname;
+       struct dirent ***namelist;
+       int (*select) __P((struct dirent *));
+       int (*dcomp) __P((const void *, const void *));
+{
+       register struct dirent *d, *p, **names;
+       register size_t 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(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));
+               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);
+               /*
+                * 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,
+                               arraysz * sizeof(struct dirent *));
+                       if (names == NULL)
+                               return(-1);
+               }
+               names[nitems-1] = p;
+       }
+       closedir(dirp);
+       if (nitems && dcomp != NULL)
+               qsort(names, nitems, sizeof(struct dirent *), dcomp);
+       *namelist = names;
+       return(nitems);
+}
+
+/*
+ * Alphabetic order comparison routine for those who want it.
+ */
+int
+alphasort(d1, d2)
+       const void *d1;
+       const void *d2;
+{
+       return(strcmp((*(struct dirent **)d1)->d_name,
+           (*(struct dirent **)d2)->d_name));
+}