blob: 9c6a39c444683f83f6b95863f6a7ebc871455120 [file] [log] [blame]
/* Copyright (C) 2007-2008 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
*/
#include "android/utils/dirscanner.h"
#include "android/utils/bufprint.h"
#include "android/utils/system.h"
#include "android/utils/path.h"
#include <stddef.h>
#define DIRSCANNER_BASE \
char root[PATH_MAX]; \
int rootLen; \
char full[PATH_MAX]; \
#if _WIN32
#include <io.h>
struct DirScanner {
DIRSCANNER_BASE
intptr_t findIndex1;
struct _finddata_t findData;
};
/* note: findIndex1 contains the find index + 1
* so a value of 0 means 'invalid'
*/
static int
_dirScannerInit( DirScanner* s )
{
char* p = s->root + s->rootLen;
char* end = s->root + sizeof s->root;
int ret;
/* create file spec by appending \* to root */
p = bufprint(p, end, "\\*");
if (p >= end)
return -1;
ret = _findfirst(s->root, &s->findData);
s->findIndex1 = ret+1;
return ret;
}
static void
_dirScanner_done( DirScanner* s )
{
if (s->findIndex1 > 0) {
_findclose(s->findIndex1-1);
s->findIndex1 = 0;
}
}
const char*
dirScanner_next( DirScanner* s )
{
char* ret = NULL;
if (!s || s->findIndex1 <= 0)
return NULL;
while (ret == NULL) {
ret = s->findData.name;
/* ignore special directories */
if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
ret = NULL;
}
/* find next one */
if (_findnext(s->findIndex1-1, &s->findData) < 0) {
_dirScanner_done(s);
break;
}
}
return ret;
}
#else /* !_WIN32 */
#include <dirent.h>
struct DirScanner {
DIRSCANNER_BASE
DIR* dir;
struct dirent* entry;
};
static int
_dirScannerInit( DirScanner* s )
{
s->dir = opendir(s->root);
if (s->dir == NULL)
return -1;
s->entry = NULL;
return 0;
}
static void
_dirScanner_done( DirScanner* s )
{
if (s->dir) {
closedir(s->dir);
s->dir = NULL;
}
}
const char*
dirScanner_next( DirScanner* s )
{
char* ret = NULL;
if (!s || s->dir == NULL)
return NULL;
for (;;)
{
/* read new entry if needed */
s->entry = readdir(s->dir);
if (s->entry == NULL) {
_dirScanner_done(s);
break;
}
/* ignore special directories */
ret = s->entry->d_name;
if (!strcmp(ret,".") || !strcmp(ret,"..")) {
ret = NULL;
continue;
}
break;
}
return ret;
}
#endif /* !_WIN32 */
DirScanner*
dirScanner_new ( const char* rootPath )
{
DirScanner* s = android_alloc0(sizeof *s);
char* p = s->root;
char* end = p + sizeof s->root;
p = bufprint(p, end, "%s", rootPath);
if (p >= end)
goto FAIL;
s->rootLen = (p - s->root);
if (_dirScannerInit(s) < 0)
goto FAIL;
return s;
FAIL:
dirScanner_free(s);
return NULL;
}
void
dirScanner_free( DirScanner* s )
{
if (!s)
return;
_dirScanner_done(s);
AFREE(s);
}
const char*
dirScanner_nextFull( DirScanner* s )
{
const char* name = dirScanner_next(s);
char* p;
char* end;
if (name == NULL)
return NULL;
p = s->full;
end = p + sizeof s->full;
p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
if (p >= end) {
/* ignore if the full name is too long */
return dirScanner_nextFull(s);
}
return s->full;
}