blob: 9c6a39c444683f83f6b95863f6a7ebc871455120 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12#include "android/utils/dirscanner.h"
13#include "android/utils/bufprint.h"
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +020014#include "android/utils/system.h"
15#include "android/utils/path.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080016#include <stddef.h>
17
18#define DIRSCANNER_BASE \
19 char root[PATH_MAX]; \
20 int rootLen; \
21 char full[PATH_MAX]; \
22
23
24#if _WIN32
25
26#include <io.h>
27
28struct DirScanner {
29 DIRSCANNER_BASE
30 intptr_t findIndex1;
31 struct _finddata_t findData;
32};
33
34/* note: findIndex1 contains the find index + 1
35 * so a value of 0 means 'invalid'
36 */
37
38static int
39_dirScannerInit( DirScanner* s )
40{
41 char* p = s->root + s->rootLen;
42 char* end = s->root + sizeof s->root;
43 int ret;
44
45 /* create file spec by appending \* to root */
46 p = bufprint(p, end, "\\*");
47 if (p >= end)
48 return -1;
49
50 ret = _findfirst(s->root, &s->findData);
51
52 s->findIndex1 = ret+1;
53 return ret;
54}
55
56static void
57_dirScanner_done( DirScanner* s )
58{
59 if (s->findIndex1 > 0) {
60 _findclose(s->findIndex1-1);
61 s->findIndex1 = 0;
62 }
63}
64
65const char*
66dirScanner_next( DirScanner* s )
67{
68 char* ret = NULL;
69
70 if (!s || s->findIndex1 <= 0)
71 return NULL;
72
73 while (ret == NULL) {
74 ret = s->findData.name;
75
76 /* ignore special directories */
77 if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
78 ret = NULL;
79 }
80 /* find next one */
81 if (_findnext(s->findIndex1-1, &s->findData) < 0) {
82 _dirScanner_done(s);
83 break;
84 }
85 }
86 return ret;
87}
88
89#else /* !_WIN32 */
90
91#include <dirent.h>
92struct DirScanner {
93 DIRSCANNER_BASE
94 DIR* dir;
95 struct dirent* entry;
96};
97
98static int
99_dirScannerInit( DirScanner* s )
100{
101 s->dir = opendir(s->root);
102
103 if (s->dir == NULL)
104 return -1;
105
106 s->entry = NULL;
107 return 0;
108}
109
110static void
111_dirScanner_done( DirScanner* s )
112{
113 if (s->dir) {
114 closedir(s->dir);
115 s->dir = NULL;
116 }
117}
118
119const char*
120dirScanner_next( DirScanner* s )
121{
122 char* ret = NULL;
123
124 if (!s || s->dir == NULL)
125 return NULL;
126
127 for (;;)
128 {
129 /* read new entry if needed */
130 s->entry = readdir(s->dir);
131 if (s->entry == NULL) {
132 _dirScanner_done(s);
133 break;
134 }
135
136 /* ignore special directories */
137 ret = s->entry->d_name;
138
139 if (!strcmp(ret,".") || !strcmp(ret,"..")) {
140 ret = NULL;
141 continue;
142 }
143 break;
144 }
145 return ret;
146}
147
148#endif /* !_WIN32 */
149
150DirScanner*
151dirScanner_new ( const char* rootPath )
152{
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +0200153 DirScanner* s = android_alloc0(sizeof *s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800154 char* p = s->root;
155 char* end = p + sizeof s->root;
156
157 p = bufprint(p, end, "%s", rootPath);
158 if (p >= end)
159 goto FAIL;
160
161 s->rootLen = (p - s->root);
162
163 if (_dirScannerInit(s) < 0)
164 goto FAIL;
165
166 return s;
167
168FAIL:
169 dirScanner_free(s);
170 return NULL;
171}
172
173
174void
175dirScanner_free( DirScanner* s )
176{
177 if (!s)
178 return;
179
180 _dirScanner_done(s);
David 'Digit' Turner18fe86e2010-10-19 08:07:11 +0200181 AFREE(s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800182}
183
184
185const char*
186dirScanner_nextFull( DirScanner* s )
187{
188 const char* name = dirScanner_next(s);
189 char* p;
190 char* end;
191
192 if (name == NULL)
193 return NULL;
194
195 p = s->full;
196 end = p + sizeof s->full;
197
198 p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
199 if (p >= end) {
200 /* ignore if the full name is too long */
201 return dirScanner_nextFull(s);
202 }
203 return s->full;
204}