video.c: don't display pre-rolled pictures
[vlc.git] / 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.6 $
13  * $Author: sam $
14  * $Date: 2002/11/13 20:51:04 $
15  *
16  */
17
18 #include "config.h"
19
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 #ifdef HAVE_ERRNO_H
24 #   include <errno.h>
25 #else
26     static int errno;
27     /* FIXME: anything clever to put here? */
28 #   define EFAULT 12
29 #   define ENOTDIR 12
30 #   define ENOENT 12
31 #   define ENOMEM 12
32 #   define EINVAL 12
33 #endif
34 #include <string.h>
35 #ifndef UNDER_CE
36 #   include <io.h>
37 #   include <direct.h>
38 #else
39 #   define FILENAME_MAX (260)
40 #endif
41
42 #define WIN32_LEAN_AND_MEAN
43 #include <windows.h> /* for GetFileAttributes */
44
45 #include <tchar.h>
46 #define SUFFIX  "*"
47 #define SLASH   "\\"
48
49 struct dirent
50 {
51         long            d_ino;          /* Always zero. */
52         unsigned short  d_reclen;       /* Always zero. */
53         unsigned short  d_namlen;       /* Length of name in d_name. */
54         char            d_name[FILENAME_MAX]; /* File name. */
55 };
56
57 typedef struct
58 {
59         /* disk transfer area for this dir */
60         WIN32_FIND_DATA         dd_dta;
61
62         /* dirent struct to return from dir (NOTE: this makes this thread
63          * safe as long as only one thread uses a particular DIR struct at
64          * a time) */
65         struct dirent           dd_dir;
66
67         /* findnext handle */
68         HANDLE                  dd_handle;
69
70         /*
71          * Status of search:
72          *   0 = not started yet (next entry to read is first entry)
73          *  -1 = off the end
74          *   positive = 0 based index of next entry
75          */
76         int                     dd_stat;
77
78         /* given path for dir with search pattern (struct is extended) */
79         char                    dd_name[1];
80 } DIR;
81
82 /*
83  * opendir
84  *
85  * Returns a pointer to a DIR structure appropriately filled in to begin
86  * searching a directory.
87  */
88 DIR * 
89 vlc_opendir (const CHAR *szPath)
90 {
91   DIR *nd;
92   unsigned int rc;
93   CHAR szFullPath[MAX_PATH];
94
95   errno = 0;
96
97   if (!szPath)
98     {
99       errno = EFAULT;
100       return (DIR *) 0;
101     }
102
103   if (szPath[0] == '\0')
104     {
105       errno = ENOTDIR;
106       return (DIR *) 0;
107     }
108
109   /* Attempt to determine if the given path really is a directory. */
110 #ifdef UNICODE
111   {
112     wchar_t szPathTmp[MAX_PATH];
113     mbstowcs( szPathTmp, szPath, MAX_PATH );
114     szPathTmp[MAX_PATH-1] = 0;
115     rc = GetFileAttributes (szPathTmp);
116   }
117 #else
118   rc = GetFileAttributes (szPath);
119 #endif
120   if (rc == (unsigned int)-1)
121     {
122       /* call GetLastError for more error info */
123       errno = ENOENT;
124       return (DIR *) 0;
125     }
126   if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
127     {
128       /* Error, entry exists but not a directory. */
129       errno = ENOTDIR;
130       return (DIR *) 0;
131     }
132
133   /* Make an absolute pathname.  */
134 #if defined( UNDER_CE )
135   if (szPath[0] == '\\' || szPath[0] == '/')
136     {
137       sprintf (szFullPath, "%s", szPath);
138       szFullPath[0] = '\\';
139     }
140   else
141     {
142       wchar_t szFullPathTmp[MAX_PATH];
143       if (GetModuleFileName( NULL, szFullPathTmp, MAX_PATH ) )
144         {
145           wcstombs( szFullPath, szFullPathTmp, MAX_PATH );
146           szFullPath[MAX_PATH-1] = 0;
147         }
148       else
149         {
150           /* FIXME: if I wasn't lazy, I'd check for overflows here. */
151           sprintf (szFullPath, "\\%s", szPath );
152         }
153     }
154 #else
155   _fullpath (szFullPath, szPath, MAX_PATH);
156 #endif
157
158   /* Allocate enough space to store DIR structure and the complete
159    * directory path given. */
160   nd = (DIR *) malloc (sizeof (DIR) + strlen (szFullPath) + sizeof (SLASH) +
161                        sizeof (SUFFIX));
162
163   if (!nd)
164     {
165       /* Error, out of memory. */
166       errno = ENOMEM;
167       return (DIR *) 0;
168     }
169
170   /* Create the search expression. */
171   strcpy (nd->dd_name, szFullPath);
172
173   /* Add on a slash if the path does not end with one. */
174   if (nd->dd_name[0] != '\0' &&
175       nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
176       nd->dd_name[strlen (nd->dd_name) - 1] != '\\')
177     {
178       strcat (nd->dd_name, SLASH);
179     }
180
181   /* Add on the search pattern */
182   strcat (nd->dd_name, SUFFIX);
183
184   /* Initialize handle so that a premature closedir doesn't try
185    * to call FindClose on it. */
186   nd->dd_handle = INVALID_HANDLE_VALUE;
187
188   /* Initialize the status. */
189   nd->dd_stat = 0;
190
191   /* Initialize the dirent structure. ino and reclen are invalid under
192    * Win32, and name simply points at the appropriate part of the
193    * findfirst_t structure. */
194   nd->dd_dir.d_ino = 0;
195   nd->dd_dir.d_reclen = 0;
196   nd->dd_dir.d_namlen = 0;
197   memset (nd->dd_dir.d_name, 0, FILENAME_MAX);
198
199   return nd;
200 }
201
202
203 /*
204  * readdir
205  *
206  * Return a pointer to a dirent structure filled with the information on the
207  * next entry in the directory.
208  */
209 struct dirent *
210 vlc_readdir (DIR * dirp)
211 {
212   errno = 0;
213
214   /* Check for valid DIR struct. */
215   if (!dirp)
216     {
217       errno = EFAULT;
218       return (struct dirent *) 0;
219     }
220
221   if (dirp->dd_stat < 0)
222     {
223       /* We have already returned all files in the directory
224        * (or the structure has an invalid dd_stat). */
225       return (struct dirent *) 0;
226     }
227   else if (dirp->dd_stat == 0)
228     {
229 #ifdef UNICODE
230         wchar_t dd_name[MAX_PATH];
231         mbstowcs( dd_name, dirp->dd_name, MAX_PATH );
232         dd_name[MAX_PATH-1] = 0;
233 #else
234         char *dd_name = dirp->dd_name;
235 #endif
236       /* We haven't started the search yet. */
237       /* Start the search */
238       dirp->dd_handle = FindFirstFile (dd_name, &(dirp->dd_dta));
239
240           if (dirp->dd_handle == INVALID_HANDLE_VALUE)
241         {
242           /* Whoops! Seems there are no files in that
243            * directory. */
244           dirp->dd_stat = -1;
245         }
246       else
247         {
248           dirp->dd_stat = 1;
249         }
250     }
251   else
252     {
253       /* Get the next search entry. */
254       if (!FindNextFile ((HANDLE)dirp->dd_handle, &(dirp->dd_dta)))
255         {
256           /* We are off the end or otherwise error. */
257           FindClose ((HANDLE)dirp->dd_handle);
258           dirp->dd_handle = INVALID_HANDLE_VALUE;
259           dirp->dd_stat = -1;
260         }
261       else
262         {
263           /* Update the status to indicate the correct
264            * number. */
265           dirp->dd_stat++;
266         }
267     }
268
269   if (dirp->dd_stat > 0)
270     {
271       /* Successfully got an entry */
272
273 #ifdef UNICODE
274       char d_name[MAX_PATH];
275       wcstombs( d_name, dirp->dd_dta.cFileName, MAX_PATH );
276       d_name[MAX_PATH-1] = 0;
277 #else
278       char *d_name = dirp->dd_dta.cFileName;
279 #endif
280
281       strcpy (dirp->dd_dir.d_name, d_name);
282       dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name);
283       return &dirp->dd_dir;
284     }
285
286   return (struct dirent *) 0;
287 }
288
289
290 /*
291  * closedir
292  *
293  * Frees up resources allocated by opendir.
294  */
295 int
296 vlc_closedir (DIR * dirp)
297 {
298   int rc;
299
300   errno = 0;
301   rc = 0;
302
303   if (!dirp)
304     {
305       errno = EFAULT;
306       return -1;
307     }
308
309   if (dirp->dd_handle != INVALID_HANDLE_VALUE)
310     {
311       rc = FindClose ((HANDLE)dirp->dd_handle);
312     }
313
314   /* Delete the dir structure. */
315   free (dirp);
316
317   return rc;
318 }
319
320 /*
321  * rewinddir
322  *
323  * Return to the beginning of the directory "stream". We simply call findclose
324  * and then reset things like an opendir.
325  */
326 void
327 vlc_rewinddir (DIR * dirp)
328 {
329   errno = 0;
330
331   if (!dirp)
332     {
333       errno = EFAULT;
334       return;
335     }
336
337   if (dirp->dd_handle != INVALID_HANDLE_VALUE)
338     {
339       FindClose ((HANDLE)dirp->dd_handle);
340     }
341
342   dirp->dd_handle = INVALID_HANDLE_VALUE;
343   dirp->dd_stat = 0;
344 }
345
346 /*
347  * telldir
348  *
349  * Returns the "position" in the "directory stream" which can be used with
350  * seekdir to go back to an old entry. We simply return the value in stat.
351  */
352 long
353 vlc_telldir (DIR * dirp)
354 {
355   errno = 0;
356
357   if (!dirp)
358     {
359       errno = EFAULT;
360       return -1;
361     }
362   return dirp->dd_stat;
363 }
364
365 /*
366  * seekdir
367  *
368  * Seek to an entry previously returned by telldir. We rewind the directory
369  * and call readdir repeatedly until either dd_stat is the position number
370  * or -1 (off the end). This is not perfect, in that the directory may
371  * have changed while we weren't looking. But that is probably the case with
372  * any such system.
373  */
374 void
375 vlc_seekdir (DIR * dirp, long lPos)
376 {
377   errno = 0;
378
379   if (!dirp)
380     {
381       errno = EFAULT;
382       return;
383     }
384
385   if (lPos < -1)
386     {
387       /* Seeking to an invalid position. */
388       errno = EINVAL;
389       return;
390     }
391   else if (lPos == -1)
392     {
393       /* Seek past end. */
394       if (dirp->dd_handle != INVALID_HANDLE_VALUE)
395         {
396           FindClose ((HANDLE)dirp->dd_handle);
397         }
398       dirp->dd_handle = INVALID_HANDLE_VALUE;
399       dirp->dd_stat = -1;
400     }
401   else
402     {
403       /* Rewind and read forward to the appropriate index. */
404       vlc_rewinddir (dirp);
405
406       while ((dirp->dd_stat < lPos) && vlc_readdir (dirp))
407         ;
408     }
409 }