Skip to content

Commit

Permalink
add find_files() to common/file.d (dlang#16365)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Apr 15, 2024
1 parent d434acd commit 9a86c4e
Showing 1 changed file with 169 additions and 0 deletions.
169 changes: 169 additions & 0 deletions compiler/src/dmd/common/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,23 @@

module dmd.common.file;

import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
import core.stdc.limits;

import core.stdc.errno : errno;
import core.stdc.stdio : fprintf, remove, rename, stderr;
import core.stdc.stdlib;
import core.stdc.string : strerror, strlen, memcpy;

import dmd.common.smallbuffer;
import dmd.root.filename;
import dmd.root.rmem;

version (Windows)
{
import core.stdc.wchar_;
import core.sys.windows.winbase;
import core.sys.windows.winnls : CP_ACP;
import core.sys.windows.winnt;
Expand All @@ -32,6 +40,7 @@ version (Windows)
}
else version (Posix)
{
import core.sys.posix.dirent;
import core.sys.posix.fcntl;
import core.sys.posix.sys.mman;
import core.sys.posix.sys.stat;
Expand Down Expand Up @@ -587,3 +596,163 @@ private auto ref fakePure(F)(scope F fun) pure
mixin("alias PureFun = " ~ F.stringof ~ " pure;");
return (cast(PureFun) fun)();
}

/***********************************
* Recursively search all the directories and files under dir_path
* for files that match one of the extensions in exts[].
* Pass the matches to sink.
* Params:
* dir_path = root of directories to search
* exts = array of filename extensions to match
* recurse = go into subdirectories
* filenameSink = accepts the resulting matches
* Returns:
* true for failed to open the directory
*/
bool findFiles(const char* dir_path, const char[][] exts, bool recurse, void delegate(const(char)[]) nothrow filenameSink)
{
enum log = false;
if (log) printf("findFiles() dir_path: %s\n", dir_path);
version (Windows)
{
debug
enum BufLength = 10; // trigger any reallocation bugs
else
enum BufLength = 100;
char[BufLength + 1] buf = void;
char* fullPath = buf.ptr;
size_t fullPathLength = BufLength;

// fullPath = dir_path \ *.*
const dir_pathLength = strlen(dir_path);
auto count = dir_pathLength + 1 + 3;
if (count > fullPathLength)
{
fullPathLength = count;
fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
}
memcpy(fullPath, dir_path, dir_pathLength);
strcpy(fullPath + dir_pathLength, "\\*.*".ptr);

if (log) printf("fullPath: %s\n", fullPath);

WIN32_FIND_DATAW ffd = void;
HANDLE hFind = fullPath[0 .. strlen(fullPath)].extendedPathThen!(p => FindFirstFileW(p.ptr, &ffd));
if (hFind == INVALID_HANDLE_VALUE)
return true;

do
{
if (log) wprintf("ffd.cFileName: %s\n", ffd.cFileName.ptr);
if (ffd.cFileName[0] == 0)
continue; // ignore

if (ffd.cFileName[0] == '.')
continue; // ignore files that start with a ., also ignore . and .. directories

const(char)[] name = toNarrowStringz(ffd.cFileName[0 .. wcslen(ffd.cFileName.ptr)], null);
if (log) printf("name: %s\n", name.ptr);

// fullPath = dir_path \ name.ptr
count = dir_pathLength + 1 + name.length;
if (count > fullPathLength)
{
fullPathLength = count;
fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
}
strcpy(fullPath + dir_pathLength + 1, name.ptr);

if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (recurse)
findFiles(fullPath, exts, recurse, filenameSink);
}
else
{
const(char)[] nameExt = FileName.ext(name);
foreach (ext; exts[])
{
if (nameExt == ext)
{
if (log) printf("adding %s\n", fullPath);
filenameSink(fullPath[0 .. count]);
}
}
}
mem.xfree(cast(void*)name.ptr);

} while (FindNextFileW(hFind, &ffd) != 0);

if (fullPath != buf.ptr)
mem.xfree(fullPath);
FindClose(hFind);
if (log) printf("findFiles() exit\n");
return false;
}
else version (Posix)
{
DIR* dir = opendir(dir_path);
if (!dir)
return true;

debug
enum BufLength = 10; // trigger any reallocation bugs
else
enum BufLength = 100;
char[BufLength + 1] buf = void;
char* fullPath = buf.ptr;
size_t fullPathLength = BufLength;

dirent* entry;
while ((entry = readdir(dir)) != null)
{
//printf("entry: %s\n", entry.d_name.ptr);
if (entry.d_name[0] == '.')
continue; // ignore files that start with a .

// fullPath = dir_path / entry.d_name.ptr
const dir_pathLength = strlen(dir_path);
const count = dir_pathLength + 1 + strlen(entry.d_name.ptr);
if (count > fullPathLength)
{
fullPathLength = count;
fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
}
memcpy(fullPath, dir_path, dir_pathLength);
fullPath[dir_pathLength] = '/';
strcpy(fullPath + dir_pathLength + 1, entry.d_name.ptr);

stat_t statbuf;
if (lstat(fullPath, &statbuf) == -1)
continue;

const(char)[] name = entry.d_name.ptr[0 .. strlen(entry.d_name.ptr)]; // convert to D string
if (!name.length)
continue; // ignore

if (S_ISDIR(statbuf.st_mode))
{
if (recurse && !(name == "." || name == ".."))
findFiles(fullPath, exts, recurse, filenameSink);
}
else if (S_ISREG(statbuf.st_mode))
{
foreach (ext; exts)
{
if (FileName.ext(name) == ext)
{
//printf("%s\n", fullPath);
filenameSink(fullPath[0 .. count]);
}
}
}
}

if (fullPath != buf.ptr)
mem.xfree(fullPath);
closedir(dir);
return false;
}
else
static assert(0);
}

0 comments on commit 9a86c4e

Please sign in to comment.