../machine => machine
[unix-history] / usr / src / lib / libc / gen / scandir.c
CommitLineData
bb0cfa24
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
d99e6414
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
bb0cfa24
DF
16 */
17
2ce81398 18#if defined(LIBC_SCCS) && !defined(lint)
901dccca 19static char sccsid[] = "@(#)scandir.c 5.6 (Berkeley) %G%";
d99e6414 20#endif /* LIBC_SCCS and not lint */
455b164d 21
38cb3a9a
RC
22/*
23 * Scan the directory dirname calling select to make a list of selected
24 * directory entries then sort using qsort and compare routine dcomp.
25 * Returns the number of entries and a pointer to a list of pointers to
8c6e64bc 26 * struct dirent (through namelist). Returns -1 if there were any errors.
38cb3a9a
RC
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
8c6e64bc 31#include <dirent.h>
38cb3a9a 32
c5453831
KM
33/*
34 * The DIRSIZ macro gives the minimum record length which will hold
35 * the directory entry. This requires the amount of space in struct dirent
36 * without the d_name field, plus enough space for the name with a terminating
37 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
38 */
39#undef DIRSIZ
40#define DIRSIZ(dp) \
41 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
42
38cb3a9a
RC
43scandir(dirname, namelist, select, dcomp)
44 char *dirname;
8c6e64bc 45 struct dirent *(*namelist[]);
38cb3a9a
RC
46 int (*select)(), (*dcomp)();
47{
8c6e64bc 48 register struct dirent *d, *p, **names;
38cb3a9a 49 register int nitems;
38cb3a9a
RC
50 struct stat stb;
51 long arraysz;
52 DIR *dirp;
53
54 if ((dirp = opendir(dirname)) == NULL)
55 return(-1);
56 if (fstat(dirp->dd_fd, &stb) < 0)
57 return(-1);
58
59 /*
60 * estimate the array size by taking the size of the directory file
61 * and dividing it by a multiple of the minimum size entry.
62 */
63 arraysz = (stb.st_size / 24);
8c6e64bc 64 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
38cb3a9a
RC
65 if (names == NULL)
66 return(-1);
67
68 nitems = 0;
69 while ((d = readdir(dirp)) != NULL) {
70 if (select != NULL && !(*select)(d))
71 continue; /* just selected names */
72 /*
73 * Make a minimum size copy of the data
74 */
8c6e64bc 75 p = (struct dirent *)malloc(DIRSIZ(d));
38cb3a9a
RC
76 if (p == NULL)
77 return(-1);
78 p->d_ino = d->d_ino;
79 p->d_reclen = d->d_reclen;
80 p->d_namlen = d->d_namlen;
901dccca 81 bcopy(d->d_name, p->d_name, p->d_namlen + 1);
38cb3a9a
RC
82 /*
83 * Check to make sure the array has space left and
84 * realloc the maximum size.
85 */
86 if (++nitems >= arraysz) {
71120ea4
RC
87 if (fstat(dirp->dd_fd, &stb) < 0)
88 return(-1); /* just might have grown */
89 arraysz = stb.st_size / 12;
8c6e64bc
KM
90 names = (struct dirent **)realloc((char *)names,
91 arraysz * sizeof(struct dirent *));
38cb3a9a
RC
92 if (names == NULL)
93 return(-1);
94 }
95 names[nitems-1] = p;
96 }
97 closedir(dirp);
98 if (nitems && dcomp != NULL)
8c6e64bc 99 qsort(names, nitems, sizeof(struct dirent *), dcomp);
38cb3a9a
RC
100 *namelist = names;
101 return(nitems);
102}
103
104/*
105 * Alphabetic order comparison routine for those who want it.
106 */
107alphasort(d1, d2)
8c6e64bc 108 struct dirent **d1, **d2;
38cb3a9a
RC
109{
110 return(strcmp((*d1)->d_name, (*d2)->d_name));
111}