Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2020 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "IFile.h" 23 : #include "Exception.h" 24 : #include "core/Action.h" 25 : #include "core/PlumedMain.h" 26 : #include "core/Value.h" 27 : #include "Communicator.h" 28 : #include "Tools.h" 29 : #include <cstdarg> 30 : #include <cstring> 31 : #include <cmath> 32 : 33 : #include <iostream> 34 : #include <string> 35 : #ifdef __PLUMED_HAS_ZLIB 36 : #include <zlib.h> 37 : #endif 38 : 39 : namespace PLMD { 40 : 41 15771295 : size_t IFile::llread(char*ptr,size_t s) { 42 15771295 : plumed_assert(fp); 43 : size_t r; 44 15771295 : if(gzfp) { 45 : #ifdef __PLUMED_HAS_ZLIB 46 3522 : int rr=gzread(gzFile(gzfp),ptr,s); 47 3522 : if(rr==0) eof=true; 48 3522 : if(rr<0) err=true; 49 3522 : r=rr; 50 : #else 51 : plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked"); 52 : #endif 53 : } else { 54 : r=fread(ptr,1,s,fp); 55 15767773 : if(feof(fp)) eof=true; 56 15767773 : if(ferror(fp)) err=true; 57 : } 58 15771295 : return r; 59 : } 60 : 61 122798 : IFile& IFile::advanceField() { 62 122798 : plumed_assert(!inMiddleOfField); 63 : std::string line; 64 : bool done=false; 65 367192 : while(!done) { 66 128513 : getline(line); 67 : // using explicit conversion not to confuse cppcheck 1.86 68 128513 : if(!bool(*this)) {return *this;} 69 244394 : std::vector<std::string> words=Tools::getWords(line); 70 245678 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") { 71 611 : fields.clear(); 72 10030 : for(unsigned i=2; i<words.size(); i++) { 73 : Field field; 74 : field.name=words[i]; 75 2936 : fields.push_back(field); 76 : } 77 131476 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") { 78 : Field field; 79 : field.name=words[2]; 80 : field.value=words[3]; 81 2864 : field.constant=true; 82 2864 : fields.push_back(field); 83 : } else { 84 : unsigned nf=0; 85 4367445 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++; 86 118722 : Tools::trimComments(line); 87 237444 : words=Tools::getWords(line); 88 118722 : if( words.size()==nf ) { 89 : unsigned j=0; 90 4290284 : for(unsigned i=0; i<fields.size(); i++) { 91 1352440 : if(fields[i].constant) continue; 92 1054050 : fields[i].value=words[j]; 93 527025 : fields[i].read=false; 94 527025 : j++; 95 : } 96 : done=true; 97 2240 : } else if( !words.empty() ) { 98 0 : plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number"); 99 : } 100 : } 101 : } 102 116482 : inMiddleOfField=true; 103 116482 : return *this; 104 : } 105 : 106 972 : IFile& IFile::open(const std::string&path) { 107 972 : plumed_massert(!cloned,"file "+path+" appears to be cloned"); 108 972 : eof=false; 109 972 : err=false; 110 972 : fp=NULL; 111 972 : gzfp=NULL; 112 972 : bool do_exist=FileExist(path); 113 976 : plumed_massert(do_exist,"file " + path + " cannot be found"); 114 1942 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r"); 115 1942 : if(Tools::extension(this->path)=="gz") { 116 : #ifdef __PLUMED_HAS_ZLIB 117 12 : gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"r"); 118 : #else 119 : plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked"); 120 : #endif 121 : } 122 971 : if(plumed) plumed->insertFile(*this); 123 971 : return *this; 124 : } 125 : 126 54339 : IFile& IFile::scanFieldList(std::vector<std::string>&s) { 127 54339 : if(!inMiddleOfField) advanceField(); 128 : // using explicit conversion not to confuse cppcheck 1.86 129 54339 : if(!bool(*this)) return *this; 130 54263 : s.clear(); 131 1908442 : for(unsigned i=0; i<fields.size(); i++) 132 599972 : s.push_back(fields[i].name); 133 : return *this; 134 : } 135 : 136 54282 : bool IFile::FieldExist(const std::string& s) { 137 54282 : std::vector<std::string> slist; 138 54282 : scanFieldList(slist); 139 54282 : int mycount = (int) std::count(slist.begin(), slist.end(), s); 140 54282 : if(mycount>0) return true; 141 29608 : else return false; 142 : } 143 : 144 1314590 : IFile& IFile::scanField(const std::string&name,std::string&str) { 145 1314590 : if(!inMiddleOfField) advanceField(); 146 : // using explicit conversion not to confuse cppcheck 1.86 147 1314590 : if(!bool(*this)) return *this; 148 1308350 : unsigned i=findField(name); 149 2616700 : str=fields[i].value; 150 1308350 : fields[i].read=true; 151 1308350 : return *this; 152 : } 153 : 154 500649 : IFile& IFile::scanField(const std::string&name,double &x) { 155 : std::string str; 156 500649 : scanField(name,str); 157 500649 : if(*this) Tools::convert(str,x); 158 500649 : return *this; 159 : } 160 : 161 204245 : IFile& IFile::scanField(const std::string&name,int &x) { 162 : std::string str; 163 204245 : scanField(name,str); 164 204245 : if(*this) Tools::convert(str,x); 165 204245 : return *this; 166 : } 167 : 168 15150 : IFile& IFile::scanField(Value* val) { 169 15150 : double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure 170 15150 : scanField( val->getName(), ff ); 171 15150 : val->set( ff ); 172 30300 : if( FieldExist("min_" + val->getName() ) ) { 173 : std::string min, max; 174 6618 : scanField("min_" + val->getName(), min ); 175 6618 : scanField("max_" + val->getName(), max ); 176 3309 : val->setDomain( min, max ); 177 : } else { 178 11841 : val->setNotPeriodic(); 179 : } 180 15150 : return *this; 181 : } 182 : 183 116484 : IFile& IFile::scanField() { 184 116484 : if(!ignoreFields) { 185 3762511 : for(unsigned i=0; i<fields.size(); i++) { 186 1186993 : plumed_massert(fields[i].read,"field "+fields[i].name+" was not read: all the fields need to be read otherwise you could miss important infos" ); 187 : } 188 : } 189 116484 : inMiddleOfField=false; 190 116484 : return *this; 191 : } 192 : 193 1210 : IFile::IFile(): 194 : inMiddleOfField(false), 195 : ignoreFields(false), 196 2420 : noEOL(false) 197 : { 198 1210 : } 199 : 200 2713 : IFile::~IFile() { 201 1210 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n"; 202 1503 : } 203 : 204 250329 : IFile& IFile::getline(std::string &str) { 205 250329 : char tmp=0; 206 : str=""; 207 : fpos_t pos; 208 250329 : fgetpos(fp,&pos); 209 15771290 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) { 210 15520961 : str+=tmp; 211 : } 212 250329 : if(tmp=='\r') { 213 5 : llread(&tmp,1); 214 5 : plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines"); 215 : } 216 250329 : if(eof && noEOL) { 217 635 : if(str.length()>0) eof=false; 218 249694 : } else if(eof || err || tmp!='\n') { 219 6329 : eof = true; 220 : str=""; 221 6329 : if(!err) fsetpos(fp,&pos); 222 : // there was a fsetpos here that apparently is not necessary 223 : // fsetpos(fp,&pos); 224 : // I think it was necessary to have rewind working correctly 225 : // after end of file. Since rewind is not used now anywhere, 226 : // it should be ok not to reset position. 227 : // This is necessary so that eof works properly for emacs files 228 : // with no endline at end of file. 229 : } 230 250329 : return *this; 231 : } 232 : 233 1308350 : unsigned IFile::findField(const std::string&name)const { 234 : unsigned i; 235 25365009 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break; 236 1308350 : if(i>=fields.size()) { 237 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found"); 238 : } 239 1308350 : return i; 240 : } 241 : 242 6114 : void IFile::reset(bool reset) { 243 6114 : eof = reset; 244 6114 : err = reset; 245 6114 : if(!reset && fp) clearerr(fp); 246 : #ifdef __PLUMED_HAS_ZLIB 247 6114 : if(!reset && gzfp) gzclearerr(gzFile(gzfp)); 248 : #endif 249 6114 : return; 250 : } 251 : 252 5736 : void IFile::allowIgnoredFields() { 253 5736 : ignoreFields=true; 254 5736 : } 255 : 256 650 : void IFile::allowNoEOL() { 257 650 : noEOL=true; 258 650 : } 259 : 260 5517 : }