]> git.sesse.net Git - vlc/blob - src/extras/dirent.c
* ./Makefile.am: added a "update-vlc.dsp" rule to create the MSVC project
[vlc] / src / extras / dirent.c
1 /*
2  * dirent.c
3  *
4  * Derived from DIRLIB.C by Matt J. Weinstein 
5  * This note appears in the DIRLIB.H
6  * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
7  *
8  * Updated by Jeremy Bettis <jeremy@hksys.com>
9  * Significantly revised and rewinddir, seekdir and telldir added by Colin
10  * Peters <colin@fu.is.saga-u.ac.jp>
11  *      
12  * $Revision: 1.1 $
13  * $Author: sam $
14  * $Date: 2002/11/09 16:34:52 $
15  *
16  */
17
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <io.h>
22 #include <direct.h>
23 #include <dirent.h>
24
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h> /* for GetFileAttributes */
27
28 #define SUFFIX  "*"
29 #define SLASH   "\\"
30
31 /*
32  * opendir
33  *
34  * Returns a pointer to a DIR structure appropriately filled in to begin
35  * searching a directory.
36  */
37 DIR * 
38 opendir (const CHAR *szPath)
39 {
40   DIR *nd;
41   unsigned int rc;
42   CHAR szFullPath[MAX_PATH];
43         
44   errno = 0;
45
46   if (!szPath)
47     {
48       errno = EFAULT;
49       return (DIR *) 0;
50     }
51
52   if (szPath[0] == '\0')
53     {
54       errno = ENOTDIR;
55       return (DIR *) 0;
56     }
57
58   /* Attempt to determine if the given path really is a directory. */
59   rc = GetFileAttributes (szPath);
60   if (rc == -1)
61     {
62       /* call GetLastError for more error info */
63       errno = ENOENT;
64       return (DIR *) 0;
65     }
66   if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
67     {
68       /* Error, entry exists but not a directory. */
69       errno = ENOTDIR;
70       return (DIR *) 0;
71     }
72
73   /* Make an absolute pathname.  */
74   _fullpath (szFullPath, szPath, MAX_PATH);
75
76   /* Allocate enough space to store DIR structure and the complete
77    * directory path given. */
78   nd = (DIR *) malloc (sizeof (DIR) + strlen (szFullPath) + strlen (SLASH) +
79                        strlen (SUFFIX));
80
81   if (!nd)
82     {
83       /* Error, out of memory. */
84       errno = ENOMEM;
85       return (DIR *) 0;
86     }
87
88   /* Create the search expression. */
89   strcpy (nd->dd_name, szFullPath);
90
91   /* Add on a slash if the path does not end with one. */
92   if (nd->dd_name[0] != '\0' &&
93       nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
94       nd->dd_name[strlen (nd->dd_name) - 1] != '\\')
95     {
96       strcat (nd->dd_name, SLASH);
97     }
98
99   /* Add on the search pattern */
100   strcat (nd->dd_name, SUFFIX);
101
102   /* Initialize handle to -1 so that a premature closedir doesn't try
103    * to call _findclose on it. */
104   nd->dd_handle = -1;
105
106   /* Initialize the status. */
107   nd->dd_stat = 0;
108
109   /* Initialize the dirent structure. ino and reclen are invalid under
110    * Win32, and name simply points at the appropriate part of the
111    * findfirst_t structure. */
112   nd->dd_dir.d_ino = 0;
113   nd->dd_dir.d_reclen = 0;
114   nd->dd_dir.d_namlen = 0;
115   nd->dd_dir.d_name = nd->dd_dta.name;
116
117   return nd;
118 }
119
120
121 /*
122  * readdir
123  *
124  * Return a pointer to a dirent structure filled with the information on the
125  * next entry in the directory.
126  */
127 struct dirent *
128 readdir (DIR * dirp)
129 {
130   errno = 0;
131
132   /* Check for valid DIR struct. */
133   if (!dirp)
134     {
135       errno = EFAULT;
136       return (struct dirent *) 0;
137     }
138
139   if (dirp->dd_dir.d_name != dirp->dd_dta.name)
140     {
141       /* The structure does not seem to be set up correctly. */
142       errno = EINVAL;
143       return (struct dirent *) 0;
144     }
145
146   if (dirp->dd_stat < 0)
147     {
148       /* We have already returned all files in the directory
149        * (or the structure has an invalid dd_stat). */
150       return (struct dirent *) 0;
151     }
152   else if (dirp->dd_stat == 0)
153     {
154       /* We haven't started the search yet. */
155       /* Start the search */
156       dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta));
157
158           if (dirp->dd_handle == -1)
159         {
160           /* Whoops! Seems there are no files in that
161            * directory. */
162           dirp->dd_stat = -1;
163         }
164       else
165         {
166           dirp->dd_stat = 1;
167         }
168     }
169   else
170     {
171       /* Get the next search entry. */
172       if (_findnext (dirp->dd_handle, &(dirp->dd_dta)))
173         {
174           /* We are off the end or otherwise error. */
175           _findclose (dirp->dd_handle);
176           dirp->dd_handle = -1;
177           dirp->dd_stat = -1;
178         }
179       else
180         {
181           /* Update the status to indicate the correct
182            * number. */
183           dirp->dd_stat++;
184         }
185     }
186
187   if (dirp->dd_stat > 0)
188     {
189       /* Successfully got an entry. Everything about the file is
190        * already appropriately filled in except the length of the
191        * file name. */
192       dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name);
193       return &dirp->dd_dir;
194     }
195
196   return (struct dirent *) 0;
197 }
198
199
200 /*
201  * closedir
202  *
203  * Frees up resources allocated by opendir.
204  */
205 int
206 closedir (DIR * dirp)
207 {
208   int rc;
209
210   errno = 0;
211   rc = 0;
212
213   if (!dirp)
214     {
215       errno = EFAULT;
216       return -1;
217     }
218
219   if (dirp->dd_handle != -1)
220     {
221       rc = _findclose (dirp->dd_handle);
222     }
223
224   /* Delete the dir structure. */
225   free (dirp);
226
227   return rc;
228 }
229
230 /*
231  * rewinddir
232  *
233  * Return to the beginning of the directory "stream". We simply call findclose
234  * and then reset things like an opendir.
235  */
236 void
237 rewinddir (DIR * dirp)
238 {
239   errno = 0;
240
241   if (!dirp)
242     {
243       errno = EFAULT;
244       return;
245     }
246
247   if (dirp->dd_handle != -1)
248     {
249       _findclose (dirp->dd_handle);
250     }
251
252   dirp->dd_handle = -1;
253   dirp->dd_stat = 0;
254 }
255
256 /*
257  * telldir
258  *
259  * Returns the "position" in the "directory stream" which can be used with
260  * seekdir to go back to an old entry. We simply return the value in stat.
261  */
262 long
263 telldir (DIR * dirp)
264 {
265   errno = 0;
266
267   if (!dirp)
268     {
269       errno = EFAULT;
270       return -1;
271     }
272   return dirp->dd_stat;
273 }
274
275 /*
276  * seekdir
277  *
278  * Seek to an entry previously returned by telldir. We rewind the directory
279  * and call readdir repeatedly until either dd_stat is the position number
280  * or -1 (off the end). This is not perfect, in that the directory may
281  * have changed while we weren't looking. But that is probably the case with
282  * any such system.
283  */
284 void
285 seekdir (DIR * dirp, long lPos)
286 {
287   errno = 0;
288
289   if (!dirp)
290     {
291       errno = EFAULT;
292       return;
293     }
294
295   if (lPos < -1)
296     {
297       /* Seeking to an invalid position. */
298       errno = EINVAL;
299       return;
300     }
301   else if (lPos == -1)
302     {
303       /* Seek past end. */
304       if (dirp->dd_handle != -1)
305         {
306           _findclose (dirp->dd_handle);
307         }
308       dirp->dd_handle = -1;
309       dirp->dd_stat = -1;
310     }
311   else
312     {
313       /* Rewind and read forward to the appropriate index. */
314       rewinddir (dirp);
315
316       while ((dirp->dd_stat < lPos) && readdir (dirp))
317         ;
318     }
319 }