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