/* 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 #define DIRSCANNER_BASE \ char root[PATH_MAX]; \ int rootLen; \ char full[PATH_MAX]; \ #if _WIN32 #include 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 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; }