Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2019 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 17312328 : size_t IFile::llread(char*ptr,size_t s) { 42 17312328 : plumed_assert(fp); 43 : size_t r; 44 17312328 : if(gzfp) { 45 : #ifdef __PLUMED_HAS_ZLIB 46 3519 : int rr=gzread(gzFile(gzfp),ptr,s); 47 3519 : if(rr==0) eof=true; 48 3519 : if(rr<0) err=true; 49 3519 : 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 17308809 : if(feof(fp)) eof=true; 56 17308809 : if(ferror(fp)) err=true; 57 : } 58 17312328 : return r; 59 : } 60 : 61 161505 : IFile& IFile::advanceField() { 62 161505 : plumed_assert(!inMiddleOfField); 63 : std::string line; 64 : bool done=false; 65 483961 : while(!done) { 66 167297 : getline(line); 67 : // using explicit conversion not to confuse cppcheck 1.86 68 167297 : if(!bool(*this)) {return *this;} 69 160951 : std::vector<std::string> words=Tools::getWords(line); 70 326824 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") { 71 : fields.clear(); 72 7580 : for(unsigned i=2; i<words.size(); i++) { 73 : Field field; 74 : field.name=words[i]; 75 3147 : fields.push_back(field); 76 : } 77 193230 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") { 78 : Field field; 79 2904 : field.name=words[2]; 80 2904 : field.value=words[3]; 81 2904 : field.constant=true; 82 2904 : fields.push_back(field); 83 : } else { 84 : unsigned nf=0; 85 3150302 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++; 86 157404 : Tools::trimComments(line); 87 314808 : words=Tools::getWords(line); 88 157404 : if( words.size()==nf ) { 89 : unsigned j=0; 90 3099537 : for(unsigned i=0; i<fields.size(); i++) { 91 1472189 : if(fields[i].constant) continue; 92 1289524 : fields[i].value=words[j]; 93 644762 : fields[i].read=false; 94 644762 : j++; 95 : } 96 : done=true; 97 2245 : } else if( !words.empty() ) { 98 0 : plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number"); 99 : } 100 : } 101 160951 : } 102 155159 : inMiddleOfField=true; 103 155159 : return *this; 104 : } 105 : 106 1047 : IFile& IFile::open(const std::string&path) { 107 1047 : plumed_massert(!cloned,"file "+path+" appears to be cloned"); 108 1047 : eof=false; 109 1047 : err=false; 110 1047 : fp=NULL; 111 1047 : gzfp=NULL; 112 1047 : bool do_exist=FileExist(path); 113 1051 : plumed_massert(do_exist,"file " + path + " cannot be found"); 114 2092 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r"); 115 2092 : 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 1046 : if(plumed) plumed->insertFile(*this); 123 1046 : return *this; 124 : } 125 : 126 133031 : IFile& IFile::scanFieldList(std::vector<std::string>&s) { 127 133031 : if(!inMiddleOfField) advanceField(); 128 : // using explicit conversion not to confuse cppcheck 1.86 129 133031 : if(!bool(*this)) return *this; 130 132955 : s.clear(); 131 1992570 : for(unsigned i=0; i<fields.size(); i++) 132 863330 : s.push_back(fields[i].name); 133 : return *this; 134 : } 135 : 136 132966 : bool IFile::FieldExist(const std::string& s) { 137 : std::vector<std::string> slist; 138 132966 : scanFieldList(slist); 139 132966 : int mycount = (int) std::count(slist.begin(), slist.end(), s); 140 132966 : if(mycount>0) return true; 141 109530 : else return false; 142 : } 143 : 144 1458796 : IFile& IFile::scanField(const std::string&name,std::string&str) { 145 1458796 : if(!inMiddleOfField) advanceField(); 146 : // using explicit conversion not to confuse cppcheck 1.86 147 1458796 : if(!bool(*this)) return *this; 148 1452526 : unsigned i=findField(name); 149 2905052 : str=fields[i].value; 150 1452526 : fields[i].read=true; 151 1452526 : return *this; 152 : } 153 : 154 645653 : IFile& IFile::scanField(const std::string&name,double &x) { 155 : std::string str; 156 645653 : scanField(name,str); 157 645653 : if(*this) Tools::convert(str,x); 158 645653 : return *this; 159 : } 160 : 161 202277 : IFile& IFile::scanField(const std::string&name,int &x) { 162 : std::string str; 163 202277 : scanField(name,str); 164 202277 : if(*this) Tools::convert(str,x); 165 202277 : return *this; 166 : } 167 : 168 96336 : IFile& IFile::scanField(Value* val) { 169 96336 : double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure 170 96336 : scanField( val->getName(), ff ); 171 96336 : val->set( ff ); 172 192672 : 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 93027 : val->setNotPeriodic(); 179 : } 180 96336 : return *this; 181 : } 182 : 183 155164 : IFile& IFile::scanField() { 184 155164 : if(!ignoreFields) { 185 2438276 : for(unsigned i=0; i<fields.size(); i++) { 186 1169373 : 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 155164 : inMiddleOfField=false; 190 155164 : return *this; 191 : } 192 : 193 1287 : IFile::IFile(): 194 : inMiddleOfField(false), 195 : ignoreFields(false), 196 2574 : noEOL(false) 197 : { 198 1287 : } 199 : 200 2889 : IFile::~IFile() { 201 1287 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n"; 202 1602 : } 203 : 204 293062 : IFile& IFile::getline(std::string &str) { 205 293062 : char tmp=0; 206 : str=""; 207 : fpos_t pos; 208 293062 : fgetpos(fp,&pos); 209 17312323 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) { 210 17019261 : str+=tmp; 211 : } 212 293062 : 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 293062 : if(eof && noEOL) { 217 670 : if(str.length()>0) eof=false; 218 292392 : } else if(eof || err || tmp!='\n') { 219 6367 : eof = true; 220 : str=""; 221 6367 : 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 293062 : return *this; 231 : } 232 : 233 1452526 : unsigned IFile::findField(const std::string&name)const { 234 : unsigned i; 235 18732996 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break; 236 1452526 : if(i>=fields.size()) { 237 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found"); 238 : } 239 1452526 : 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 5744 : void IFile::allowIgnoredFields() { 253 5744 : ignoreFields=true; 254 5744 : } 255 : 256 685 : void IFile::allowNoEOL() { 257 685 : noEOL=true; 258 685 : } 259 : 260 5874 : }