PageRenderTime 46ms CodeModel.GetById 1ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/visualizations/XBMCProjectM/libprojectM/win32-dirent.cpp

http://github.com/xbmc/xbmc
C++ | 231 lines | 217 code | 5 blank | 9 comment | 2 complexity | 68bc19ea194fc50c024c06f509d7a9d6 MD5 | raw file
  1/*
  2
  3    Implementation of POSIX directory browsing functions and types for Win32.
  4
  5    Author:  Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
  6    History: Created March 1997. Updated June 2003.
  7    Rights:  See end of file.
  8
  9*/
 10
 11#include "win32-dirent.h"
 12#include <errno.h>
 13#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
 14#include <stdlib.h>
 15#include <string.h>
 16
 17#ifdef __cplusplus
 18extern "C"
 19{
 20#endif
 21
 22struct DIR
 23{
 24    long                handle; /* -1 for failed rewind */
 25    struct _finddata_t  info;
 26    struct dirent       result; /* d_name null iff first time */
 27    char                *name;  /* null-terminated char string */
 28};
 29
 30DIR *opendir(const char *name)
 31{
 32    DIR *dir = 0;
 33
 34    if(name && name[0])
 35    {
 36        size_t base_length = strlen(name);
 37        const char *all = /* search pattern must end with suitable wildcard */
 38            strchr("/\\", name[base_length - 1]) ? "" : "/";
 39
 40        if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
 41           (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
 42        {
 43            strcat(strcpy(dir->name, name), all);
 44
 45            if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1)
 46            {
 47                dir->result.d_name = 0;
 48            }
 49            else /* rollback */
 50            {
 51                free(dir->name);
 52                free(dir);
 53                dir = 0;
 54            }
 55        }
 56        else /* rollback */
 57        {
 58            free(dir);
 59            dir   = 0;
 60            errno = ENOMEM;
 61        }
 62    }
 63    else
 64    {
 65        errno = EINVAL;
 66    }
 67
 68    return dir;
 69}
 70
 71int closedir(DIR *dir)
 72{
 73    int result = -1;
 74
 75    if(dir)
 76    {
 77        if(dir->handle != -1)
 78        {
 79            result = _findclose(dir->handle);
 80        }
 81
 82        free(dir->name);
 83        free(dir);
 84    }
 85
 86    if(result == -1) /* map all errors to EBADF */
 87    {
 88        errno = EBADF;
 89    }
 90
 91    return result;
 92}
 93
 94struct dirent *readdir(DIR *dir)
 95{
 96    struct dirent *result = 0;
 97
 98    if(dir && dir->handle != -1)
 99    {
100        if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
101        {
102            result         = &dir->result;
103            result->d_name = dir->info.name;
104        }
105    }
106    else
107    {
108        errno = EBADF;
109    }
110
111    return result;
112}
113
114void rewinddir(DIR *dir)
115{
116    if(dir && dir->handle != -1)
117    {
118        _findclose(dir->handle);
119        dir->handle = (long) _findfirst(dir->name, &dir->info);
120        dir->result.d_name = 0;
121    }
122    else
123    {
124        errno = EBADF;
125    }
126}
127
128// helper for scandir below
129static void scandir_free_dir_entries(struct dirent*** namelist, int entries) {
130	int i;
131	if (!*namelist) return;
132	for (i = 0; i < entries; ++i) {
133		free((*namelist)[i]);
134	}
135	free(*namelist);
136	*namelist = 0;
137}
138
139// returns the number of directory entries select or -1 if an error occurs
140int scandir(
141	const char* dir, 
142	struct dirent*** namelist, 
143	int(*filter)(const struct dirent*),
144	int(*compar)(const void*, const void*)
145) {
146	int entries = 0;
147	int max_entries = 1024; // assume 2*512 = 1024 entries (used for allocation)
148	DIR* d;
149	
150	*namelist = 0;
151	
152	// open directory
153	d = opendir(dir);
154	if (!d) return -1;
155	
156	// iterate
157	while (1) {
158		struct dirent* ent = readdir(d);
159		if (!ent) break;
160		
161		// add if no filter or filter returns non-zero
162		if (filter && (0 == filter(ent))) continue;
163		
164		// resize our buffer if there is not enough room
165		if (!*namelist || entries >= max_entries) {
166			struct dirent** new_entries;
167			
168			max_entries *= 2;
169			new_entries = (struct dirent **)realloc(*namelist, max_entries);
170			if (!new_entries) {
171				scandir_free_dir_entries(namelist, entries);
172				closedir(d);
173				errno = ENOMEM;
174				return -1;
175			}
176			
177			*namelist = new_entries;
178		}
179
180		// allocate new entry
181		(*namelist)[entries] = (struct dirent *)malloc(sizeof(struct dirent) + strlen(ent->d_name) + 1);
182		if (!(*namelist)[entries]) {
183			scandir_free_dir_entries(namelist, entries);
184			closedir(d);
185			errno = ENOMEM;
186			return -1;	
187		}
188		
189		// copy entry info
190		*(*namelist)[entries] = *ent;
191		
192		// and then we tack the string onto the end
193		{
194			char* dest = (char*)((*namelist)[entries]) + sizeof(struct dirent);
195			strcpy(dest, ent->d_name);
196			(*namelist)[entries]->d_name = dest;
197		}
198
199		++entries;
200	}
201	
202	// sort
203	if (*namelist && compar) qsort(*namelist, entries, sizeof((*namelist)[0]), compar);
204	
205	return entries;
206}
207
208int alphasort(const void* lhs, const void* rhs) {
209	const struct dirent* lhs_ent = *(struct dirent**)lhs;
210	const struct dirent* rhs_ent = *(struct dirent**)rhs;
211	return _strcmpi(lhs_ent->d_name, rhs_ent->d_name);
212}
213
214#ifdef __cplusplus
215}
216#endif
217
218/*
219
220    Copyright Kevlin Henney, 1997, 2003. All rights reserved.
221
222    Permission to use, copy, modify, and distribute this software and its
223    documentation for any purpose is hereby granted without fee, provided
224    that this copyright and permissions notice appear in all copies and
225    derivatives.
226    
227    This software is supplied "as is" without express or implied warranty.
228
229    But that said, if there are any problems please get in touch.
230
231*/