1 /*
2  * $Id: scandir.c,v 1.5 2002-12-22 17:36:26 f Exp $
3  */
4 
5 #include "irc.h"
6 #include "ircaux.h"
7 
8 #ifndef HAVE_SCANDIR
9 
10 #if (!defined(ultrix) && !defined(__386BSD__) && !defined(_HPUX_SOURCE)) || defined(HPUX7)
11 
12 /*
13  * Copyright (c) 1983 Regents of the University of California. All rights
14  * reserved.
15  *
16  * Redistribution and use in source and binary forms are permitted provided that
17  * the above copyright notice and this paragraph are duplicated in all such
18  * forms and that any documentation, advertising materials, and other
19  * materials related to such distribution and use acknowledge that the
20  * software was developed by the University of California, Berkeley.  The
21  * name of the University may not be used to endorse or promote products
22  * derived from this software without specific prior written permission. THIS
23  * SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
25  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 # if defined(LIBC_SCCS) && !defined(lint)
29 static char sccsid[] = "@(#)scandir.c	5.3 (Berkeley) 6/18/88";
30 # endif /* LIBC_SCCS and not lint */
31 
32 # ifndef NULL
33 #  define NULL 0
34 # endif
35 
36 /*
37  * Scan the directory dirname calling select to make a list of selected
38  * directory entries then sort using qsort and compare routine dcomp. Returns
39  * the number of entries and a pointer to a list of pointers to struct direct
40  * (through namelist). Returns -1 if there were any errors.
41  */
42 
43 /*
44  * Mike Sandrof added this for HPUX compatibility in
45  * IRCII on the advice of some HPUX users - 5/11/90
46  * this is no longer valid, as hpux has its own scandir(), june 1993, phone.
47  * at least, for some versions of hpux.. oct 1994, mrg.
48  *
49  * Brett Sivies added POSIX here.
50  */
51 
52 # if defined(XD88) || defined(__SVR4) || defined(POSIX) || defined(__linux__) \
53   || defined(SVR3) || defined(__osf__) || defined(M_UNIX) || defined(_SEQUENT_) \
54   || defined(__QNX__)
55 
56 /*
57 **  SCANDIR
58 **  Scan a directory, collecting all (selected) items into a an array.
59 */
60 #include "scandir.h"
61 
62 int
scandir(Name,dirlist,Selector,Sorter)63 scandir(Name, dirlist, Selector, Sorter)
64 #if defined(__linux__) || defined(__sgi)
65     const char            *Name;
66 #else
67     char		  *Name;
68 #endif
69     struct dirent		***dirlist;
70     int			 (*Selector)();
71     int			 (*Sorter)();
72 {
73     struct dirent	 **names;
74     static  struct dirent	  *E;
75     register DIR	  *Dp;
76     register int	   i;
77     register int	   size = INITIAL_SIZE;
78 
79     if (!(names = (struct dirent **) new_malloc(size * sizeof names[0])) || access(Name, R_OK | X_OK) || !(Dp = opendir(Name)))
80 	return(-1);
81 
82     /* Read entries in the directory. */
83 
84     for (i = 0; (E = readdir(Dp)); )
85 	if (Selector == NULL || (*Selector)(E))
86 	{
87 	    /* User wants them all, or he wants this one. */
88 	    if (++i >= size)
89 	    {
90 		size <<= 1;
91 		names = (struct dirent **) new_realloc((char *)names, size * sizeof names[0]);
92 		if (names == NULL)
93 		{
94 		    closedir(Dp);
95 		    new_free(&names);
96 		    return(-1);
97 		}
98 	    }
99 
100 	    /* Copy the entry. */
101 	    if ((names[i - 1] = (struct dirent *) new_malloc(DIRSIZ(E))) == NULL)
102 	    {
103 		closedir(Dp);
104 		new_free(&names);
105 		return(-1);
106 	    }
107 #ifndef __QNX__
108 	    names[i - 1]->d_ino = E->d_ino;
109 	    names[i - 1]->d_reclen = E->d_reclen;
110 #endif
111 	    (void) strcpy(names[i - 1]->d_name, E->d_name);
112 	}
113 
114     /* Close things off. */
115     names = (struct dirent **) new_realloc((char *) names, (i + 1) * sizeof names[0]);
116     names[i] = 0;
117     *dirlist = names;
118     closedir(Dp);
119 
120     /* Sort? */
121     if (i && Sorter)
122 	qsort((char *)names, i, sizeof names[0], Sorter);
123 
124     return(i);
125 }
126 
127 /**************************** Patched by Flier ******************************/
128 /*
129  * Alphabetic order comparison routine for those who want it.
130  */
131 #ifndef alphasort
alphasort(d1,d2)132 int alphasort(d1, d2)
133 struct dirent **d1, **d2;
134 {
135     return(strcmp((*d1)->d_name, (*d2)->d_name));
136 }
137 #endif
138 /****************************************************************************/
139 
140 #else
141 /* End of Mike Sandrof's change */
142 #include "scandir.h"
143 
scandir(dirname,namelist,select,dcomp)144 int scandir(dirname, namelist, select, dcomp)
145 #ifdef NeXT
146 const char *dirname;
147 #else
148 char *dirname;
149 #endif /* NeXT */
150 struct direct *(*namelist[]);
151 int (*select) (), (*dcomp) ();
152 {
153     register struct direct *d,
154           *p,
155          **names;
156     register int nitems;
157     register char *cp1,
158         *cp2;
159     struct stat stb;
160     long arraysz;
161     DIR *dirp;
162 
163     if (access(dirname, R_OK|X_OK))
164 	return (-1);
165     if ((dirp = opendir(dirname)) == NULL)
166 	return (-1);
167     if (fstat(dirp->dd_fd, &stb) < 0)
168 	return (-1);
169 
170     /*
171      * estimate the array size by taking the size of the directory file and
172      * dividing it by a multiple of the minimum size entry.
173      */
174     arraysz = (stb.st_size / 24);
175     names = (struct direct **) new_malloc(arraysz * sizeof(struct direct *));
176     if (names == NULL)
177 	return (-1);
178 
179     nitems = 0;
180     while ((d = readdir(dirp)) != NULL)
181     {
182 	if (select != NULL && !(*select) (d))
183 	    continue;		/* just selected names */
184 	/*
185 	 * Make a minimum size copy of the data
186 	 */
187 	p = (struct direct *) new_malloc(DIRSIZ(d));
188 	if (p == NULL)
189 	    return (-1);
190 	p->d_ino = d->d_ino;
191 	p->d_reclen = d->d_reclen;
192 # if ! defined(ISC22) && ! defined(ESIX)
193 	p->d_namlen = d->d_namlen;
194 # endif /* ! defined(ISC22) && ! defined(ESIX) */
195 	for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++;);
196 	/*
197 	 * Check to make sure the array has space left and realloc the
198 	 * maximum size.
199 	 */
200 	if (++nitems >= arraysz)
201 	{
202 	    if (fstat(dirp->dd_fd, &stb) < 0)
203 		return (-1);	/* just might have grown */
204 	    arraysz = stb.st_size / 12;
205 	    names = (struct direct **) new_realloc((char *) names,
206 					 arraysz * sizeof(struct direct *));
207 	    if (names == NULL)
208 		return (-1);
209 	}
210 	names[nitems - 1] = p;
211     }
212     closedir(dirp);
213     if (nitems && dcomp != NULL)
214 	qsort(names, nitems, sizeof(struct direct *), dcomp);
215     *namelist = names;
216     return (nitems);
217 }
218 
219 
220 /*
221  * Alphabetic order comparison routine for those who want it.
222  */
alphasort(d1,d2)223 int alphasort(d1, d2)
224 struct direct **d1,
225      **d2;
226 {
227     return (strcmp((*d1)->d_name, (*d2)->d_name));
228 }
229 #endif
230 
231 #endif	/* ultrix || __386BSD__ || BSD */
232 #endif /* !HAVE_SCANDIR */
233