filename.h 6.11 KB
#ifndef STIM_FILENAME_H
#define STIM_FILENAME_H

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef _WIN32
    #include <direct.h>
    #define GetCurrentDir _getcwd
	#define STIM_FILENAME_DIV '\\'
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
	#define STIM_FILENAME_DIV '/'
 #endif

#include <string>
#include <sstream>
#include <vector>
#include <stack>
#include <algorithm>

#include "../parser/parser.h"

#include <boost/filesystem.hpp>

namespace stim{

//filename class designed to work with both Windows and Unix

class filename{

private:
	void init(){

		absolute = false;

	}

protected:

	std::string drive;				//drive letter (for Windows)
	std::vector<std::string> path;	//directory hierarchy
	std::string prefix;				//file prefix (without extension)
	std::string	ext;				//file extension

	bool absolute;					//filename is an absolute path

	//replace any incorrect dividers with the appropriate version for the OS
	std::string parse_div(std::string s) {
		#ifdef _WIN32
			std::replace( s.begin(), s.end(), '/', '\\');
		#else
			std::replace( s.begin(), s.end(), '\\', '/');
		#endif

		return s;
	}

	//parse the file name (prefix and extension)
	void parse_name(std::string fname){

		//find the extension
		size_t xpos = fname.find_last_of('.');			//find the position of the extension period (if there is one)
		if(xpos != std::string::npos){						//split the prefix and extension
			prefix = fname.substr(0, xpos);
			ext = fname.substr(xpos + 1);
		}
		else
			prefix = fname;
	}

	//parse a file locator string
	void parse(std::string loc){

		//determine the drive (if Windows)
		drive = "";		
		#ifdef _WIN32
			//if the second character is a colon, the character right before it is the drive
			if(loc[1] == ':'){
				absolute = true;			//this is an absolute path
				drive = loc[0];				//copy the drive letter
				loc = loc.substr(3);		//remove the drive information from the locator string
			}
		#else
			if(loc[0] == STIM_FILENAME_DIV){
				absolute = true;
				loc = loc.substr(1);
			}
		#endif

		//determine the file name
		std::string fname = loc.substr( loc.find_last_of(STIM_FILENAME_DIV) + 1 );	//find the file name (including extension)

		//parse the file name
		parse_name(fname);

		//find the directory hierarchy
		std::string dir = loc.substr(0, loc.find_last_of(STIM_FILENAME_DIV) + 1 );
		path = stim::parser::split(dir, STIM_FILENAME_DIV);
	}

public:

	filename(){
		init();
	}

	filename(std::string loc){
		init();
		parse(loc);
	}



	std::string get_name(){
		if(prefix == "" && ext == "")
			return "";
		else
			return prefix + "." + ext;
	}

	std::string get_extension(){
		return ext;
	}

	std::string get_prefix(){
		return prefix;
	}

	std::string dir(){
		std::stringstream ss;

		//if the path is absolute
		if(absolute){
			//output the drive letter if in Windows
			#ifdef _WIN32
				ss<<drive<<":";
			#endif
			ss<<STIM_FILENAME_DIV;
		}

		//output the directory
		for(unsigned int d = 0; d < path.size(); d++)
			ss<<path[d]<<STIM_FILENAME_DIV;

		return ss.str();

	}

	std::string str(){

		std::stringstream ss;

		ss<<dir()<<get_name();

		return ss.str();
	}

	//get a list of files matching the current tamplate
	std::vector<stim::filename> get_list(){

		boost::filesystem::path p(dir());	//create a path from the current filename

		std::vector<stim::filename> file_list;

		if(boost::filesystem::exists(p)){
			if(boost::filesystem::is_directory(p)){

				typedef std::vector<boost::filesystem::path> 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( ext == "*" || "." + ext == (*it).filename().extension().string()){

							file_list.push_back((*it).string());	//include it in the final list
						}
					}

				}
			}
		}

		return file_list;
	}

	//gets the current working directory
	static stim::filename cwd(){


		char cCurrentPath[FILENAME_MAX];

		 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){
			 std::cout<<"ERROR getting current working directory."<<std::endl;
			 exit(1);
		 }

		 std::cout<<cCurrentPath<<std::endl;
		 return stim::filename(std::string(cCurrentPath) + STIM_FILENAME_DIV);
	}

	void set_name(std::string fname){
		parse_name(fname);
	}

	//get a path relative to the current one
	stim::filename get_relative(std::string rel){

		std::vector<std::string> rel_path = stim::parser::split(rel, STIM_FILENAME_DIV);

		//if the relative path doesn't contain a file, add a blank string to be used as the filename
		if(rel[rel.size()-1] == STIM_FILENAME_DIV)
			rel_path.push_back("");

		//create a stack representing the current absolute path
		std::stack<std::string, std::vector<std::string> > s(path);

		//for each token in the relative path
		for(int d=0; d<rel_path.size() - 1; d++){

			//if the token is a double-dot, pop a directory off of the stack
			if(rel_path[d] == "..")
				s.pop();
			else
				s.push(rel_path[d]);
		}

		std::string* end   = &s.top() + 1;
		std::string* begin = end - s.size();
		std::vector<std::string> result_path(begin, end);

		//create a new path to be returned
		stim::filename result = *this;
		result.path = result_path;
		result.set_name(rel_path.back());

		return result;
	}

	bool is_relative(){
		return !absolute;
	}

	bool is_absolute(){
		return absolute;
	}









};


}	//end namespace stim

#endif