File system searches

This page describes how to search through the file system from within your database plugin.

Motivation

You should be interested in this page if the following is true:

  • Your file format should be allowed to open any one of a group of files
  • When one file is opened, it should be as if all the files were opened
  • You need knowledge of which files are available and which aren't, hence the need for a file system search
  • It is not an option to make a "meta-file" that has all of the files listed
  • You want to do this in an "approved" way that will be OS-agnostic

Gameplan

The key function is called "ReadAndProcessDirectory". This function takes a callback and the callback is called one time for each file in the directory.

It's arguments are:

  1. a directory of interest
  2. a callback
  3. a void * argument, which will be the "this" pointer for your file format.

Example

Identifying the directory

You will need to extract the directory of interest from the filename for the file that was opened. This filename is fully qualified with its directory.

    char slashChar = '/';
  #if defined(_WIN32)
    slashChar = '\\';
  #endif
  
    int last_slash = -1;
    while (fileOpened.find(slashChar, last_slash+1) != string::npos)
    {
        last_slash = fileOpened.find(slashChar, last_slash+1);
    }
  
    dir = fileOpened.substr(0, last_slash);

Calling ReadAndProcessDirectory

  // At top of file: #include <Utility.h>
  
    ReadAndProcessDirectory(dir, CheckFileCallback, this);

My CheckFileCallback function is called once for each file in the directory. It looks like:

  static void
  CheckFileCallback(void *args, const std::string &fname, bool isDir,
                  bool perms, long filesize)
  {
    avtCEAucdFileFormat *ff = (avtCEAucdFileFormat *) args;
    ff->AddFileInThisDirectory(fname);
  }

What to do with the files

My "AddFileInThisDirectory" studies the filename to see if the input filename matches the file that was opened in terms of the root.

  void
  avtCEAucdFileFormat::AddFileInThisDirectory(const std::string &filenameWithDir)
  {
    char slashChar = '/';
  #if defined(_WIN32)
    slashChar = '\\';
  #endif
  
    int last_slash = -1;
    while (filenameWithDir.find(slashChar, last_slash+1) != string::npos)
    {
        last_slash = filenameWithDir.find(slashChar, last_slash+1);
    }
  
    // Filename is filenameWithDir without the directory qualification.
    std::string filename = filenameWithDir.substr(last_slash+1);
  
    std::string rootCandidate = "U_" + stem;
    if (filename == rootCandidate)
        root = filenameWithDir;
    else
    {
        char underscore = '_';
        if (filename.find(underscore, 0) == string::npos)
            return; // can't be a match.
        int start = filename.find(underscore, 0)+1;
        int stop = -1;
        if (filename.find(underscore, start) == string::npos)
        {
            std::string extension = ".inp";
            if (filename.find(extension, start) == string::npos)
                return; // no second underscore, no extension.
            stop = filename.find(extension, start);
        }
        else
            stop = filename.find(underscore, start);
        std::string file_stem = filename.substr(start, stop-start);
        if (file_stem == stem)
            domains.push_back(filenameWithDir);
    }
  }