// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_file #define tools_file #include "gzip" #include "forit" #include #include #include #include "path" //suffix #include "S_STRING" #ifdef TOOLS_MEM #include "mem" #endif namespace tools { namespace file { inline bool exists(const std::string& a_string) { FILE* file = ::fopen(a_string.c_str(),"rb"); if(!file) return false; ::fclose(file); return true; } inline bool size(const std::string& a_file,long& a_size){ FILE* file = ::fopen(a_file.c_str(),"rb"); if(!file) { a_size = 0L; return false; } //::rewind(file); ::fseek(file,0L,SEEK_END); a_size = ::ftell(file); ::fclose(file); return true; } inline bool is_empty(const std::string& a_file){ long sz; if(!size(a_file,sz)) return true; //if not existing, consider it empty. return (sz==0L)?true:false; } inline bool write(const std::string& a_file,const std::string& a_string) { // a_string could contain \n separated lines. FILE* file = ::fopen(a_file.c_str(),"wb"); if(!file) return false; if(::fprintf(file,"%s",a_string.c_str())<0) { ::fclose(file); return false; } ::fclose(file); return true; } inline bool write(const std::string& a_file,const std::vector& a_text){ FILE* file = ::fopen(a_file.c_str(),"wb"); if(!file) return false; tools_vforcit(std::string,a_text,it) { if(::fprintf(file,"%s\n",(*it).c_str())<0) { ::fclose(file); return false; } } ::fclose(file); return true; } inline bool read_buff(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) { a_length = ::fread(a_buff,1,a_lbuf,a_file); return true; } inline bool read_cstring(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) { if(::fgets(a_buff,a_lbuf,a_file)==NULL) { a_length = 0; return false; //EOF } size_t l = ::strlen(a_buff); // On Windows, editors when saving binary files, // put \r\n at place of \n ; we then look for \r\n. if( (l>=2) && (a_buff[l-2]=='\r') && (a_buff[l-1]=='\n') ) { a_buff[l-2] = '\0'; l -= 2; } else if( (l>=1) && (a_buff[l-1]=='\n') ) { a_buff[l-1] = '\0'; l -= 1; } a_length = l; return true; } inline bool read(const std::string& a_file,std::vector& a_text){ a_text.clear(); FILE* file = ::fopen(a_file.c_str(),"rb"); if(!file) return false; unsigned int BUFSIZE = 65536; char* buffer = new char[BUFSIZE+1]; if(!buffer) {::fclose(file);return false;} while(true) { size_t l; if(!read_cstring(file,buffer,BUFSIZE,l)) break; // EOF. a_text.push_back(buffer); } delete [] buffer; ::fclose(file); return true; } inline bool read_num(const std::string& a_file,std::vector::size_type a_num,std::vector& a_text,const std::string& a_cmt = ""){ a_text.clear(); FILE* file = ::fopen(a_file.c_str(),"rb"); if(!file) return false; unsigned int BUFSIZE = 65536; char* buffer = new char[BUFSIZE+1]; if(!buffer) {::fclose(file);return false;} while(true) { size_t l; if(!read_cstring(file,buffer,BUFSIZE,l)) break; // EOF. if(a_cmt.size()&&(!strncmp(a_cmt.c_str(),buffer,a_cmt.size()))) continue; if(a_text.size()& a_txt,bool& a_is){ //a_sep = 0; a_is = false; if(a_txt.empty()) return true; //guess sep from first data line : char sep = 0; {const char* buffer = a_txt[0].c_str(); //::printf("debug : |%s|\n",buffer); const char* pos = buffer; char* end; {double d = ::strtod(pos,&end);(void)d;} //::printf("debug : d first %g\n",d); if(end==pos) return true; //not starting with a number. //end==mx is ok, one column only. sep = *end;} //::printf("debug : %d\n",sep); unsigned int first_coln = 0; tools_vforcit(std::string,a_txt,it) { const char* buffer = (*it).c_str(); //::printf("debug : |%s|\n",buffer); const char* pos = buffer; const char* mx = buffer+(*it).size(); unsigned int coln = 0; while(true) { char* end; {double d = ::strtod(pos,&end);(void)d;} if(end==pos) break; //::printf("debug : d %g\n",d); if(*end!=sep) return true; coln++; pos = end+1; if(pos>mx) break; } //::printf("debug : coln %d\n",coln); if(it==a_txt.begin()) { first_coln = coln; } else { if(coln!=first_coln) return true; } } //a_sep = sep; a_is = true; return true; } inline bool is_csv(const std::string& a_file,bool& a_is){ // look at suffix. Some file can't be guessed. if(suffix(a_file)=="csv") {a_is = true;return true;} //try to guess : std::vector txt; if(!file::read_num(a_file,3,txt,"#")) {a_is=false;return false;} return is_csv(txt,a_is); } inline bool is_hippo(const std::string& a_file,bool& a_is){ //if((suffix(a_file)=="hiptxt")||(suffix(a_file)=="tnt")) { // a_is = true; // return true; //} std::vector txt; if(!file::read_num(a_file,5,txt)) return false; //skip two first lines (title and labels). std::vector htxt; for(unsigned int i=2;i text; if(!file::read(a_from,text)) return false; return file::write(a_to,text); } */ inline bool found(const std::string& a_file,const std::string& a_what,std::vector& a_found){ a_found.clear(); std::vector text; if(!file::read(a_file,text)) return false; tools_vforcit(std::string,text,it) { if((*it).find(a_what)!=std::string::npos) { a_found.push_back(*it); } } return true; } inline bool std_remove(const std::string& a_file) { if(a_file.empty()) return true; return (::remove(a_file.c_str()) ==0 ? true : false); } inline bool std_remove(std::vector& a_files) { bool status = true; tools_vforit(std::string,a_files,it) { if(!std_remove(*it)) status = false; } a_files.clear(); return status; } inline bool std_rename(const std::string& a_from,const std::string& a_to) { //NOTE : a_from must not be a path ! // Darwin is ok with a path but not Linux ! // For example : // ::rename("/tmp/tmp01"."x"); // return -1 on Linux. // To do the upper then someone must use move. // But there is no move in the standard lib C ! return (::rename(a_from.c_str(),a_to.c_str()) == 0 ? true : false); } ////////////////////////////////////////////////////////////////////////////// /// by using C system //////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// inline std::string quote(const std::string& a_path) { if(a_path.find(' ')==std::string::npos) return a_path; // path with spaces : if(a_path[0]=='"') return a_path; //Already in double quote. return std::string("\"")+a_path+"\""; } // used in OnX/BaseUI. inline bool mv(const std::string& a_from,const std::string& a_to){ if(a_to==a_from) return true; #ifdef WIN32 std::string cmd = "MOVE /Y"; #else std::string cmd = "/bin/mv"; #endif cmd += " "; cmd += quote(a_from); cmd += " "; cmd += quote(a_to); int ret = ::system(cmd.c_str()); return (ret==(-1)?false:true); } inline bool cp(const std::string& a_from,const std::string& a_to) { if(a_to==a_from) return true; #ifdef WIN32 std::string cmd = "COPY /Y"; #else std::string cmd = "/bin/cp"; #endif cmd += " "; cmd += quote(a_from); cmd += " "; cmd += quote(a_to); int ret = ::system(cmd.c_str()); return (ret==(-1)?false:true); } inline bool rm(const std::string& a_file){ // WARNING : do not confuse with file::std_remove which is // an encapsulation of the remove of stdio.h that // does not support wildcards. #ifdef WIN32 std::string cmd = "DEL /Q"; #else std::string cmd = "/bin/rm -f"; #endif cmd += " "; cmd += quote(a_file); int ret = ::system(cmd.c_str()); return (ret==(-1)?false:true); } /* class holder { public: TOOLS_SCLASS(tools::file::holder) public: holder(const std::string& a_path):m_path(a_path){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } virtual ~holder() { std_remove(m_path); #ifdef TOOLS_MEM mem::decrement(s_class().c_str()); #endif } public: holder(const holder& a_from):m_path(a_from.m_path){ #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } holder& operator=(const holder& a_from){ m_path = a_from.m_path; return *this; } protected: std::string m_path; }; */ }} #include "file_reader" namespace tools { class FILE_reader : public virtual file::reader { public: //file_reader virtual bool open(const std::string& a_file) { if(m_FILE) return false; m_FILE = ::fopen(a_file.c_str(),"rb"); if(!m_FILE) return false; return true; } virtual void close() { if(!m_FILE) return; ::fclose(m_FILE); m_FILE = 0; } virtual bool is_open() const {return m_FILE?true:false;} virtual bool read(char* a_buff,unsigned int a_lbuf,size_t& a_length) { a_length = ::fread(a_buff,1,a_lbuf,m_FILE); return true; } virtual bool get_line(char* a_buff,unsigned int a_lbuf) { return ::fgets(a_buff,a_lbuf,m_FILE)==NULL?false:true; } virtual bool eof() const { #if defined(_MSC_VER) && _MSC_VER <= 1400 return feof(m_FILE)?true:false; #else return ::feof(m_FILE)?true:false; #endif } public: FILE_reader():m_FILE(0){} virtual ~FILE_reader() {if(m_FILE) ::fclose(m_FILE);} protected: FILE_reader(const FILE_reader& a_from) :file::reader(a_from) ,m_FILE(0) {} FILE_reader& operator=(const FILE_reader&){return *this;} protected: FILE* m_FILE; }; } #include "file_format" //backcomp #endif