Last update July 14, 2006

Public Code /
Dir Walker



Submitted by PeterSmith? 13 July 2006

Requires std.c.linux.errno (PublicCode/LinuxErrno).

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;
  }
}

FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: July 14, 2006 17:08 (diff))