7 * Derived from DIRLIB.C by Matt J. Weinstein
9 * This note appears in the DIRLIB.H
11 * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
15 * Updated by Jeremy Bettis <jeremy@hksys.com>
17 * Significantly revised and rewinddir, seekdir and telldir added by Colin
19 * Peters <colin@fu.is.saga-u.ac.jp>
23 * Resource leaks fixed by <steve.lhomme@free.fr>
55 #define SUFFIX _T("*")
57 #define SLASH _T("\\")
65 #define WIN32_LEAN_AND_MEAN
67 #include <windows.h> /* for GetFileAttributes */
77 * Returns a pointer to a DIR structure appropriately filled in to begin
79 * searching a directory.
84 _topendir (const _TCHAR * szPath)
92 _TCHAR szFullPath[MAX_PATH];
107 if (szPath[0] == _T ('\0')) {
117 /* Attempt to determine if the given path really is a directory. */
119 rc = GetFileAttributes (szPath);
121 if (rc == (unsigned int) -1) {
124 /* call GetLastError for more error info */
132 if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) {
135 /* Error, entry exists but not a directory. */
145 /* Make an absolute pathname. */
147 _tfullpath (szFullPath, szPath, MAX_PATH);
151 /* Allocate enough space to store DIR structure and the complete
153 * directory path given. */
155 nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen (szFullPath) +
156 _tcslen (SLASH) + _tcslen (SUFFIX) + 1) * sizeof (_TCHAR));
162 /* Error, out of memory. */
172 /* Create the search expression. */
174 _tcscpy (nd->dd_name, szFullPath);
178 /* Add on a slash if the path does not end with one. */
180 if (nd->dd_name[0] != _T ('\0')
181 && nd->dd_name[_tcslen (nd->dd_name) - 1] != _T ('/')
182 && nd->dd_name[_tcslen (nd->dd_name) - 1] != _T ('\\')) {
184 _tcscat (nd->dd_name, SLASH);
190 /* Add on the search pattern */
192 _tcscat (nd->dd_name, SUFFIX);
196 /* Initialize handle to -1 so that a premature closedir doesn't try
198 * to call _findclose on it. */
204 /* Initialize the status. */
210 /* Initialize the dirent structure. ino and reclen are invalid under
212 * Win32, and name simply points at the appropriate part of the
214 * findfirst_t structure. */
216 nd->dd_dir.d_ino = 0;
218 nd->dd_dir.d_reclen = 0;
220 nd->dd_dir.d_namlen = 0;
223 // Added by jcsston 02/04/2004, memset was writing to a bad pointer
225 nd->dd_dir.d_name = malloc (FILENAME_MAX);
230 memset (nd->dd_dir.d_name, 0, FILENAME_MAX);
247 * Return a pointer to a dirent structure filled with the information on the
249 * next entry in the directory.
254 _treaddir (_TDIR * dirp)
261 /* Check for valid DIR struct. */
267 return (struct _tdirent *) 0;
272 if (dirp->dd_stat < 0) {
275 /* We have already returned all files in the directory
277 * (or the structure has an invalid dd_stat). */
279 return (struct _tdirent *) 0;
281 } else if (dirp->dd_stat == 0) {
284 /* We haven't started the search yet. */
286 /* Start the search */
288 dirp->dd_handle = (long) _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
291 if (dirp->dd_handle == -1) {
294 /* Whoops! Seems there are no files in that
309 /* Get the next search entry. */
311 if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta))) {
314 /* We are off the end or otherwise error.
316 _findnext sets errno to ENOENT if no more file
320 DWORD winerr = GetLastError ();
323 if (winerr == ERROR_NO_MORE_FILES)
327 _findclose (dirp->dd_handle);
329 dirp->dd_handle = -1;
336 /* Update the status to indicate the correct
347 if (dirp->dd_stat > 0) {
350 /* Successfully got an entry. Everything about the file is
352 * already appropriately filled in except the length of the
356 dirp->dd_dir.d_namlen = (unsigned short) _tcslen (dirp->dd_dta.name);
358 _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
360 return &dirp->dd_dir;
365 return (struct _tdirent *) 0;
378 * Frees up resources allocated by opendir.
383 _tclosedir (_TDIR * dirp)
404 if (dirp->dd_handle != -1) {
406 rc = _findclose (dirp->dd_handle);
411 if (dirp->dd_dir.d_name)
413 free (dirp->dd_dir.d_name);
417 /* Delete the dir structure. */
435 * Return to the beginning of the directory "stream". We simply call findclose
437 * and then reset things like an opendir.
442 _trewinddir (_TDIR * dirp)
457 if (dirp->dd_handle != -1) {
459 _findclose (dirp->dd_handle);
464 dirp->dd_handle = -1;
479 * Returns the "position" in the "directory stream" which can be used with
481 * seekdir to go back to an old entry. We simply return the value in stat.
486 _ttelldir (_TDIR * dirp)
500 return dirp->dd_stat;
513 * Seek to an entry previously returned by telldir. We rewind the directory
515 * and call readdir repeatedly until either dd_stat is the position number
517 * or -1 (off the end). This is not perfect, in that the directory may
519 * have changed while we weren't looking. But that is probably the case with
526 _tseekdir (_TDIR * dirp, long lPos)
544 /* Seeking to an invalid position. */
550 } else if (lPos == -1) {
555 if (dirp->dd_handle != -1) {
557 _findclose (dirp->dd_handle);
561 dirp->dd_handle = -1;
568 /* Rewind and read forward to the appropriate index. */
573 while ((dirp->dd_stat < lPos) && _treaddir (dirp));