module std.filepath;
private import std.c.linux.linux;
private import std.c.linux.errno;
private import std.c.stdlib;
private import std.regexp;
private import std.string;
private import std.stdio;
unittest{
}
Walker walk(char[] path, char[] pattern = null, bool depthfirst = true)
{
if(depthfirst == false)
{
return new ForwardWalker(path, pattern);
}
else
{
return new BackwardWalker(path, pattern);
}
}
class Walker
{
char[] root;
RegExp matcher;
bool backwards;
alias int delegate(inout Path file) foreachdg;
this(char[] path, char[] pattern)
{
root = path;
if( pattern !is null )
{
matcher = new RegExp(pattern, "");
}
}
Path[] getDirList(Path dirp)
{
DIR* curDir;
dirent* dp;
Path[] contents;
curDir = opendir(toStringz(dirp.fullpath));
if( curDir !is null )
{
while( (dp = readdir(curDir)) != cast(dirent*)null )
{
char[] d_name = (dp.d_name)[0..strlen( dp.d_name)];
if( ! ( d_name == "." || d_name == "..") )
{
Path p = Path( Path.join( dirp.fullpath, d_name ) );
contents ~= p;
}
}
closedir(curDir);
if( getErrno() == EBADF )
{
writefln("WTF: %s", dirp.fullpath);
}
}
else
{
/*
EACCES Permission denied.
EMFILE Too many file descriptors in use by process.
ENFILE Too many files are currently open in the system.
ENOENT Directory does not exist, or name is an empty string.
ENOMEM Insufficient memory to complete the operation.
ENOTDIR name is not a directory.
*/
switch( getErrno() )
{
case EACCES:
break;
default:
writefln("Error %d: %s", getErrno(), dirp.fullpath);
}
}
return contents;
}
int opApply(foreachdg dg)
{
return 0;
}
}
class ForwardWalker : Walker
{
this(char[] path, char[] pattern)
{
super( path, pattern);
}
int opApply(foreachdg dg)
{
int walkForward(Path curDir)
{
int retcode;
retcode = dg(curDir);
if(retcode != 0)
return retcode;
foreach( Path p; getDirList(curDir) )
{
if( p.isDir() )
{
retcode = walkForward( p );
} else {
retcode = dg( p );
}
if(retcode != 0)
return retcode;
}
return 0;
}
return walkForward( Path( root ));
}
}
class BackwardWalker : Walker
{
this(char[] path, char[] pattern)
{
super( path, pattern);
}
int opApply(foreachdg dg)
{
int retcode;
int walkBackward(Path curDir)
{
foreach( Path p; getDirList(curDir) )
{
if( p.isDir() )
{
retcode = walkBackward( p );
} else {
retcode = dg( p );
}
if(retcode != 0)
return retcode;
}
retcode = dg(curDir);
if(retcode != 0)
return retcode;
return 0;
}
return walkBackward( Path( root ));
}
}
struct Path
{
char[] fullpath;
const char dirsep = '/';
struct_stat statData;
void stat()
{
std.c.linux.linux.stat( toStringz(fullpath), &statData );
}
void lstat()
{
std.c.linux.linux.lstat( toStringz(fullpath), &statData );
}
void ensureStat()
{
if(statData == struct_stat.init)
{
lstat();
}
}
bool isDir()
{
ensureStat();
return (statData.st_mode & S_IFMT) == S_IFDIR;
}
bool isFile()
{
ensureStat();
return (statData.st_mode & S_IFMT) == S_IFREG;
}
bool isLink()
{
ensureStat();
return (statData.st_mode & S_IFMT) == S_IFLNK;
}
bool isSocket()
{
ensureStat();
return (statData.st_mode & S_IFMT) == S_IFSOCK;
}
/+
/*
IMPLEMENT THESE WHEN WE HAVE A DATETIME CLASS
*/
DateTime accessTime()
{
}
DateTime modificationTime()
{
}
DateTime creationTime()
{
}
+/
static char[] join( char[] base, char[] addition )
{
char[][] words;
words ~= base;
words ~= addition;
if( base[$-1] == dirsep)
return std.string.join(words, "");
else if( addition[0] == dirsep)
return addition;
else
return std.string.join(words, "" ~ dirsep);
}
static Path opCall( char[] path )
{
Path newPath;
newPath.fullpath = path;
return newPath;
}
} |