filename.h 7.81 KB
#ifndef STIM_FILENAME_H
#define STIM_FILENAME_H

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef _WIN32
	#include <windows.h>
    #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 <iomanip>
#include <vector>
#include <stack>
#include <algorithm>
#include <iostream>

#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

	//replaces win32 dividers with the Linux standard
	std::string unix_div(std::string s) {
		std::replace( s.begin(), s.end(), '\\', '/');
		return s;
	}

	//break up a filename into a 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){

		loc = unix_div(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('/') + 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('/') + 1 );
		path = stim::parser::split(dir, '/');
	}

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();

	}

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


		//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;					//get the file name
			std::string file_path = dir();
			stim::filename current_file(file_path + 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;
#else
	std::cout<<"File lists aren't currently supported on Unix/Linux systems."<<std::endl;
	exit(1);
#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;
	}

	/// This function replaces a wildcard in the prefix with the specified string
	stim::filename insert(std::string str){

		stim::filename result = *this;				//initialize the result filename to the current filename
		size_t loc = result.prefix.find('*');		//find a wild card in the string
		if(loc == std::string::npos)						//if a wildcard isn't found
			result.prefix += str;							//append the value to the prefix
		else
			result.prefix.replace(loc, 1, str);			//replace the wildcard with the string
		return result;								//return the result
	}

	stim::filename insert(size_t i, size_t n = 2){

		std::stringstream ss;
		ss << std::setw(n) << std::setfill('0') << i;
		return insert(ss.str());
	}

	bool is_relative(){
		return !absolute;
	}

	bool is_absolute(){
		return absolute;
	}









};


}	//end namespace stim


#endif