17#define CDEBUG(...)     Ase::debug ("crawler", __VA_ARGS__) 
   22ResourceCrawler::ResourceCrawler() :
 
   23  folder (this, 
"folder"),
 
   24  entries (this, 
"entries")
 
   28FileCrawler::FileCrawler (
const String &cwd, 
bool constraindir, 
bool constrainfile) :
 
   29  cwd_ (
"/"), constraindir_ (constraindir), constrainfile_ (constrainfile)
 
   32    assign_ (encodefs (cwd), 
false, 
false);
 
   37FileCrawler::list_entries ()
 
   40  DIR *dir = 
opendir (cwd_.c_str());
 
   42    CDEBUG (
"%s: opendir('%s'): %s", __func__, cwd_, 
strerror (
errno));
 
   44  String cwdfile = cwd_ + 
"/";
 
   53          struct stat statbuf = { 0, };
 
   54          if (0 != 
fstatat (
dirfd (dir), de->d_name, &statbuf, AT_NO_AUTOMOUNT))
 
   56          is_dir = S_ISDIR (statbuf.st_mode);
 
   57          is_reg = S_ISREG (statbuf.st_mode);
 
   58          size = statbuf.st_size;
 
   59          mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
 
   61      if (!is_reg && !is_dir)
 
   64        .
type = is_dir ? ResourceType::FOLDER : ResourceType::FILE,
 
   66        .uri = 
encodefs (cwdfile + de->d_name) + (is_dir ? 
"/" : 
""),
 
   68      r.
size = is_dir && size > 0 ? -size : size;
 
 
   77FileCrawler::expand_fsdir (
const String &fsdir)
 
   80    return Path::dir_terminate (cwd_);
 
   83  String dir = Path::xdg_dir (fsdir);
 
   85    return Path::dir_terminate (dir);
 
 
   91FileCrawler::current_folder ()
 
   94    .
type = ResourceType::FOLDER,
 
   96    .uri = 
encodefs (Path::dir_terminate (cwd_)),
 
   98  struct stat statbuf = { 0, };
 
   99  if (
lstat (cwd_.c_str(), &statbuf) == 0)
 
  101      r.size = statbuf.st_size;
 
  102      r.mtime = statbuf.st_mtim.tv_sec * 1000 + statbuf.st_mtim.tv_nsec / 1000000;
 
 
  108FileCrawler::get_folder()
 const 
 
  114FileCrawler::set_folder (
const Resource &newfolder)
 
  116  assign_ (newfolder.
uri, 
false);
 
  120FileCrawler::get_entries()
 const 
 
  126FileCrawler::set_entries (
const ResourceS &newentries)
 
  133FileCrawler::assign_ (
const String &utf8path, 
bool existingfile, 
bool notify)
 
  138      dir.
find (
"/") == dir.npos &&
 
  144        dir = Path::xdg_dir (&dir[1]);
 
  145      if (dir.
empty() || dir == 
"/") 
 
  149  Fs::path p = Path::expand_tilde (dir);
 
  160  if (Path::check (p, 
"d"))             
 
  161    cwd_ = Path::dir_terminate (p);
 
  162  else if (Path::check (p, 
"e")) {      
 
  165  } 
else if (constraindir_) {           
 
  166    while (p.
string().size() > 1 &&
 
  167           !Path::check (p, 
"d")) {
 
  168      filename = !existingfile || Path::check (p, 
"e") ? p.
filename() : 
"";
 
  173    filename = !existingfile || Path::check (p, 
"e") ? p.
filename() : 
"";
 
  177  while (cwd_.size() > 1 && cwd_.back() == 
'/')
 
  178    cwd_.resize (cwd_.size() - 1);
 
  183      emit_notify (
"current");
 
  184      emit_notify (
"entries");
 
  186  return { cwd_, filename };
 
 
  191FileCrawler::canonify_fspath (
const String &fscwd, 
const String &fsfragment, 
bool constraindir, 
bool constrainfile)
 
  194  Fs::path p = Path::expand_tilde (fsfragment);
 
  206  if (Path::check (p, 
"d"))     
 
  207    return Path::dir_terminate (p);
 
  208  if (Path::check (p, 
"e"))     
 
  217  if (constrainfile && !Path::check (p, 
"e"))
 
  220  if (Path::check (p, 
"d"))
 
  221    return Path::dir_terminate (p);
 
 
  227FileCrawler::canonify (
const String &utf8cwd, 
const String &utf8fragment, 
bool constraindir, 
bool constrainfile)
 
 
  248  FileCrawlerP cp = FileCrawler::make_shared (
"/dev", 
true, 
false);
 
  251  r = c.canonify_fspath (
"", 
"/dev/N°…Diŕ/N°…Fílė", 1, 1); e = 
"/dev/";        
TCMP (r, ==, e);
 
  252  r = c.canonify_fspath (
".", 
".", 1, 1); e = 
"/dev/";                         
TCMP (r, ==, e);
 
  253  r = c.canonify_fspath (
"", 
"/dev/N°…Diŕ/null", 1, 1); e = 
"/dev/null";       
TCMP (r, ==, e);
 
  254  r = c.canonify_fspath (
"", 
"/tmp/N°…Diŕ/N°…Fílė", 1, 0); e = 
"/tmp/N°…Fílė"; 
TCMP (r, ==, e);
 
  255  r = c.canonify_fspath (
"", 
"/tmp/N°…Diŕ//.//", 0, 0); e = 
"/tmp/N°…Diŕ/";    
TCMP (r, ==, e);
 
  256  r = c.canonify_fspath (
"", 
"/tmp/N°…Diŕ//..//", 0, 0); e = 
"/tmp/";          
TCMP (r, ==, e);
 
  257  r = c.canonify_fspath (
"N°…Diŕ", 
"N°…Fílė", 1, 1); e = 
"/dev/";              
TCMP (r, ==, e);
 
  258  r = c.canonify_fspath (
"/N°…Diŕ", 
"N°…Fílė", 1, 1); e = 
"/";                 
TCMP (r, ==, e);
 
Class implementing a file system crawler.
 
ResourceS list_entries()
List all entries in the current folder.
 
Resource current_folder()
Return the current folder.
 
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
 
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
 
T lexically_normal(T... args)
 
String cwd()
Return the current working directoy, including symlinks used in $PWD if available.
 
The Anklang C++ API namespace.
 
ResourceType type
Resource classification.
 
bool string_isupper(const String &str)
Check if all string characters are Unicode upper case characters.
 
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
 
String string_toupper(const String &str)
Convert all string characters into Unicode upper case characters.
 
std::string decodefs(const std::string &utf8str)
Decode UTF-8 string back into file system path representation, extracting surrogate code points as by...
 
std::string anklang_runpath(RPath rpath, const String &segment)
Retrieve various resource paths at runtime.
 
String uri
Unique resource identifier.
 
std::string displayfs(const std::string &utf8str)
Convert UTF-8 encoded file system path into human readable display format, the conversion is lossy bu...
 
bool string_endswith(const String &string, const String &fragment)
Returns whether string ends with fragment.
 
std::string encodefs(const std::string &fschars)
Encode a file system path consisting of bytes into UTF-8, using surrogate code points to store non UT...
 
Description of a resource, possibly nested.
 
T relative_path(T... args)
 
#define TCMP(a, cmp, b)
Compare a and b according to operator cmp, verbose on failiure.