filename.h 7.02 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"
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();
	}

	//*****************************************************************************************************************
	// output is the directory and the prefix and the extension of the files, which are looking for in that directory. 
	std::string dir_fname(){
		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;
		}

		
		for(unsigned int d = 0; d < path.size(); d++)
			ss<<path[d]<<STIM_FILENAME_DIV;
		ss<<get_name();

		return ss.str();

	}
	
	// output is the directory and the name of the file which are found in that given directory
	std::string f_name(std::string file_name){
		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;

		stim::filename fn = file_name;
			std::string fn_prefix = fn.prefix;
			std::string fn_ext = fn.ext;
		ss<<fn_prefix + '.' + fn_ext;

		return ss.str();

	}

	
#ifdef _WIN32
#include <windows.h>
	//get a list of files matching the current template
	std::vector<stim::filename> get_list(){

		//stim::filename file_path;
		stim::filename filepath(dir_fname());
		HANDLE            hFind = INVALID_HANDLE_VALUE;
		WIN32_FIND_DATAA   FindFileData;
		std::vector<stim::filename> file_list;
		
		hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData);

		if (hFind == INVALID_HANDLE_VALUE) {
		printf ("Invalid file handle. Error is %u.\n", GetLastError());
		} 
		else {
			std::string file_name = FindFileData.cFileName;
			stim::filename current_file(f_name(file_name));
			file_list.push_back(current_file);

			// List all the other files in the directory.
			while (FindNextFileA(hFind, &FindFileData) != 0){
				file_name = FindFileData.cFileName;
				current_file = (f_name(file_name));
				file_list.push_back(current_file);
			}
			FindClose(hFind);

		return file_list;
	}
	
	}
#endif
	//**************************************************************************************************

	//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