18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/utils/dirscanner.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "android/utils/bufprint.h"
1418fe86e8245878f3b7a2813bd59b8cfcf636e15cDavid 'Digit' Turner#include "android/utils/system.h"
1518fe86e8245878f3b7a2813bd59b8cfcf636e15cDavid 'Digit' Turner#include "android/utils/path.h"
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <stddef.h>
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  DIRSCANNER_BASE     \
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char  root[PATH_MAX];    \
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int   rootLen;           \
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char  full[PATH_MAX];    \
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#if _WIN32
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <io.h>
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct DirScanner {
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DIRSCANNER_BASE
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    intptr_t            findIndex1;
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct _finddata_t  findData;
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* note: findIndex1 contains the find index + 1
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *       so a value of 0 means 'invalid'
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_dirScannerInit( DirScanner*  s )
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*  p   = s->root + s->rootLen;
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*  end = s->root + sizeof s->root;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int    ret;
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* create file spec by appending \* to root */
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    p = bufprint(p, end, "\\*");
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (p >= end)
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = _findfirst(s->root, &s->findData);
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->findIndex1 = ret+1;
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_dirScanner_done( DirScanner*  s )
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->findIndex1 > 0) {
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        _findclose(s->findIndex1-1);
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->findIndex1 = 0;
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconst char*
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectdirScanner_next( DirScanner*  s )
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*  ret = NULL;
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!s || s->findIndex1 <= 0)
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (ret == NULL) {
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = s->findData.name;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ignore special directories */
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = NULL;
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* find next one */
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (_findnext(s->findIndex1-1, &s->findData) < 0) {
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            _dirScanner_done(s);
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else /* !_WIN32 */
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <dirent.h>
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct DirScanner {
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DIRSCANNER_BASE
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DIR*            dir;
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct dirent*  entry;
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_dirScannerInit( DirScanner*  s )
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->dir = opendir(s->root);
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->dir == NULL)
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->entry = NULL;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project_dirScanner_done( DirScanner*  s )
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->dir) {
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        closedir(s->dir);
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->dir = NULL;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconst char*
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectdirScanner_next( DirScanner*  s )
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*  ret = NULL;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!s || s->dir == NULL)
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (;;)
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* read new entry if needed */
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->entry = readdir(s->dir);
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (s->entry == NULL) {
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            _dirScanner_done(s);
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ignore special directories */
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = s->entry->d_name;
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!strcmp(ret,".") || !strcmp(ret,"..")) {
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = NULL;
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            continue;
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* !_WIN32 */
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectDirScanner*
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectdirScanner_new ( const char*  rootPath )
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15318fe86e8245878f3b7a2813bd59b8cfcf636e15cDavid 'Digit' Turner    DirScanner*  s   = android_alloc0(sizeof *s);
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*        p   = s->root;
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*        end = p + sizeof s->root;
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    p = bufprint(p, end, "%s", rootPath);
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (p >= end)
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto FAIL;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->rootLen = (p - s->root);
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (_dirScannerInit(s) < 0)
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto FAIL;
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return s;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectFAIL:
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dirScanner_free(s);
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return NULL;
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectdirScanner_free( DirScanner*  s )
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!s)
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    _dirScanner_done(s);
18118fe86e8245878f3b7a2813bd59b8cfcf636e15cDavid 'Digit' Turner    AFREE(s);
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconst char*
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectdirScanner_nextFull( DirScanner*  s )
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char*  name = dirScanner_next(s);
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*        p;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char*        end;
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (name == NULL)
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    p   = s->full;
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    end = p + sizeof s->full;
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (p >= end) {
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ignore if the full name is too long */
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return dirScanner_nextFull(s);
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return s->full;
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
205