#ifndef STIM_FILENAME_H #define STIM_FILENAME_H #include /* defines FILENAME_MAX */ #include #include #include #include #include #include // set OS dependent defines, including: // 1) path division character ('/' or '\') used for output only // 2) command for getting the current working directory // 3) header files for getting the current working directory // 4) include BOOST filesystem class if compiling on GCC #define STIM_DIV '/' #ifdef _WIN32 #include #include #define GetCurrentDir _getcwd #define STIM_FILENAME_DIV '\\' #else #ifdef BOOST_PRECOMPILED #include #endif #include #define GetCurrentDir getcwd #define STIM_FILENAME_DIV '/' #endif namespace stim{ class filepath{ protected: std::string _drive; //drive on which the file is located (used for Windows) std::vector _path; //path for the specified file (list of hierarchical directories) /// replaces win32 dividers with the Linux standard (used internally by default) std::string unix_div(std::string s) { std::replace( s.begin(), s.end(), '\\', '/'); return s; } /// gets the directory hierarchy for the current working directory static std::string cwd(){ char cCurrentPath[FILENAME_MAX]; if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){ std::cout<<"ERROR getting current working directory."< &absolute, std::vector relative){ std::string current = cwd(); //get the current directory as a string std::string current_drive; std::vector current_dir; parse_path(current_drive, current_dir, current); //get the current drive and directories drive = current_drive; //all relative paths have to be relative to the current drive if (current_dir.size() > 0) { // step through each directory in the relative path, adjusting the current directory // index depending on whether the relative path is specified with '.' or '..' int current_i = (int)current_dir.size() - 1; int relative_i; for (relative_i = 0; relative_i < relative.size(); relative_i++) { if (relative[relative_i] == "..") current_i--; else if (relative[relative_i] != ".") break; } if (current_i < 0) { std::cerr << "ERROR stim::filepath - relative path is incompatible with working directory" << std::endl; exit(1); } absolute.clear(); for (size_t i = 0; i <= current_i; i++) { absolute.push_back(current_dir[i]); } for (size_t i = relative_i; i < relative.size(); i++) { absolute.push_back(relative[i]); } } else { if (relative[0] == ".") relative = std::vector(relative.begin() + 1, relative.end()); absolute = relative; } } /// Parses a directory string into a drive (NULL if not Windows) and list of hierarchical directories void parse_path(std::string &drive, std::vector &absolute, std::string dir){ drive = ""; //initialize the drive to NULL (it will stay that way for Windows) std::vector path; bool relative = true; //the default path is relative if(dir.length() == 0) return; //return if the file locator is empty std::string unix_dir = unix_div(dir); //replace any Windows division characters with Unix if(unix_dir.length() > 1 && unix_dir[1] == ':'){ //if a drive identifier is given if(unix_dir[0] > 64 && unix_dir[0] < 91) //if the drive letter is upper case drive = unix_dir[0] + 32; //convert it to lower case else if(unix_dir[0] > 96 && unix_dir[0] < 123) //if the drive character is lower case drive = unix_dir[0]; //store it as-is else{ //otherwise throw an error std::cerr<<"ERROR stim::filename - drive letter is invalid: "< 0) { //if there is a directory specified, remove surrounding slashes if (unix_dir[0] == '/') { //if there is a leading slash relative = false; //the path is not relative unix_dir = unix_dir.substr(1, unix_dir.length() - 1); //remove the slash } } if(unix_dir.size() > 0){ if(unix_dir[unix_dir.size()-1] == '/') unix_dir = unix_dir.substr(0, unix_dir.length() - 1); } path = stim::parser::split(unix_dir, '/'); //split up the directory structure if(relative) get_absolute(drive, absolute, path); else absolute = path; } public: filepath(){ _drive = ""; } filepath(const stim::filepath& p){ *this = p; } filepath(const std::string s){ parse_path(_drive, _path, s); } stim::filepath& operator=(const std::string s){ parse_path(_drive, _path, s); //parse the string to get the drive and relative path return *this; } std::string str(){ std::stringstream ss; if(_drive != "") //if a drive letter is specified ss<<_drive<<":"; //add it to the string for(size_t i = 0; i < _path.size(); i++) ss< get_list(){ //this is OS dependent, so we're starting with Windows //the Unix version requires Boost #ifdef _WIN32 HANDLE hFind = INVALID_HANDLE_VALUE; //allocate data structures for looping through files WIN32_FIND_DATAA FindFileData; std::vector file_list; //initialize a list to hold all matching filenames std::string path_string = str(); hFind = FindFirstFileA(path_string.c_str(), &FindFileData); //find the first file that matches the specified file path if (hFind == INVALID_HANDLE_VALUE) { //if there are no matching files //printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error return file_list; } else { std::string file_name = FindFileData.cFileName; //save the file name std::string file_path = path(); //the file is in the specified directory, so save it stim::filename current_file(file_path + file_name); //create a stim::filename structure representing this file if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '\0')) file_list.push_back(current_file); //push the new stim::filename to the file list // List all the other files in the directory. while (FindNextFileA(hFind, &FindFileData) != 0){ //iterate until there are no more matching files if(!(FindFileData.cFileName[0] == '.' && FindFileData.cFileName[1] == '.' && FindFileData.cFileName[2] == '\0')){ //account for the possibility of the '..' filename file_name = FindFileData.cFileName; //save the next file current_file = fname(file_name); //append the directory file_list.push_back(current_file); //push it to the list } } FindClose(hFind); //close the file data structure } return file_list; //return the list of files #elif BOOST_PRECOMPILED boost::filesystem::path p(path()); //create a path from the current filename std::vector file_list; if(boost::filesystem::exists(p)){ if(boost::filesystem::is_directory(p)){ typedef std::vector vec; // store paths, vec v; // so we can sort them later std::copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(v)); std::sort(v.begin(), v.end()); // sort, since directory iteration // is not ordered on some file systems //compare file names to the current template (look for wild cards) for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it) { //if the filename is a wild card *or* it matches the read file name if( _prefix == "*" || _prefix == (*it).filename().stem().string()){ //if the extension is a wild card *or* it matches the read file extension if( _extension == "*" || "." + _extension == (*it).filename().extension().string()){ file_list.push_back((*it).string()); //include it in the final list } } } } } return file_list; #else std::cout<<"ERROR: UNIX systems don't support file lists without the Boost precompiled libraries."<