Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-2023 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 113804330 : size_t IFile::llread(char*ptr,size_t s) {
42 113804330 : plumed_assert(fp);
43 : size_t r;
44 113804330 : 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=std::fread(ptr,1,s,fp);
55 113800808 : if(std::feof(fp)) eof=true;
56 113800808 : if(std::ferror(fp)) err=true;
57 : }
58 113804330 : return r;
59 : }
60 :
61 1575014 : IFile& IFile::advanceField() {
62 1575014 : plumed_assert(!inMiddleOfField);
63 : std::string line;
64 : bool done=false;
65 3151871 : while(!done) {
66 1583296 : getline(line);
67 : // using explicit conversion not to confuse cppcheck 1.86
68 1583296 : if(!bool(*this)) {return *this;}
69 1576857 : std::vector<std::string> words=Tools::getWords(line);
70 3153527 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
71 745 : fields.clear();
72 4943 : for(unsigned i=2; i<words.size(); i++) {
73 : Field field;
74 : field.name=words[i];
75 4198 : fields.push_back(field);
76 : }
77 1597842 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
78 : Field field;
79 : field.name=words[2];
80 : field.value=words[3];
81 3279 : field.constant=true;
82 3279 : fields.push_back(field);
83 : } else {
84 : unsigned nf=0;
85 18109750 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++;
86 1572833 : Tools::trimComments(line);
87 3145666 : words=Tools::getWords(line);
88 1572833 : if( words.size()==nf ) {
89 : unsigned j=0;
90 18055123 : for(unsigned i=0; i<fields.size(); i++) {
91 16486548 : if(fields[i].constant) continue;
92 7617717 : fields[i].value=words[j];
93 7617717 : fields[i].read=false;
94 7617717 : j++;
95 : }
96 : done=true;
97 4258 : } else if( !words.empty() ) {
98 0 : plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number\n this is the faulty line:\n"+line);
99 : }
100 : }
101 1576857 : }
102 1568575 : inMiddleOfField=true;
103 1568575 : return *this;
104 : }
105 :
106 1527 : IFile& IFile::open(const std::string&path) {
107 1527 : plumed_massert(!cloned,"file "+path+" appears to be cloned");
108 1527 : eof=false;
109 1527 : err=false;
110 1527 : fp=NULL;
111 1527 : gzfp=NULL;
112 1527 : bool do_exist=FileExist(path);
113 1529 : plumed_massert(do_exist,"file " + path + " cannot be found");
114 1526 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
115 3052 : if(Tools::extension(this->path)=="gz") {
116 : #ifdef __PLUMED_HAS_ZLIB
117 6 : 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 1526 : if(plumed) plumed->insertFile(*this);
123 1526 : return *this;
124 : }
125 :
126 1138649 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
127 1138649 : if(!inMiddleOfField) advanceField();
128 : // using explicit conversion not to confuse cppcheck 1.86
129 1138649 : if(!bool(*this)) return *this;
130 : s.clear();
131 9197320 : for(unsigned i=0; i<fields.size(); i++)
132 8058747 : s.push_back(fields[i].name);
133 : return *this;
134 : }
135 :
136 1138545 : bool IFile::FieldExist(const std::string& s) {
137 : std::vector<std::string> slist;
138 1138545 : scanFieldList(slist);
139 1138545 : int mycount = (int) std::count(slist.begin(), slist.end(), s);
140 1138545 : if(mycount>0) return true;
141 1115260 : else return false;
142 1138545 : }
143 :
144 16619172 : IFile& IFile::scanField(const std::string&name,std::string&str) {
145 16619172 : if(!inMiddleOfField) advanceField();
146 : // using explicit conversion not to confuse cppcheck 1.86
147 16619172 : if(!bool(*this)) return *this;
148 16612809 : unsigned i=findField(name);
149 16612809 : str=fields[i].value;
150 16612809 : fields[i].read=true;
151 16612809 : return *this;
152 : }
153 :
154 7518914 : IFile& IFile::scanField(const std::string&name,double &x) {
155 : std::string str;
156 7518914 : scanField(name,str);
157 7518914 : if(*this) Tools::convert(str,x);
158 7518914 : return *this;
159 : }
160 :
161 2466976 : IFile& IFile::scanField(const std::string&name,int &x) {
162 : std::string str;
163 2466976 : scanField(name,str);
164 2466976 : if(*this) Tools::convert(str,x);
165 2466976 : return *this;
166 : }
167 :
168 1 : IFile& IFile::scanField(const std::string&name,long int &x) {
169 : std::string str;
170 1 : scanField(name,str);
171 1 : if(*this) Tools::convert(str,x);
172 1 : return *this;
173 : }
174 :
175 0 : IFile& IFile::scanField(const std::string&name,long long int &x) {
176 : std::string str;
177 0 : scanField(name,str);
178 0 : if(*this) Tools::convert(str,x);
179 0 : return *this;
180 : }
181 :
182 17 : IFile& IFile::scanField(const std::string&name,unsigned &x) {
183 : std::string str;
184 17 : scanField(name,str);
185 17 : if(*this) Tools::convert(str,x);
186 17 : return *this;
187 : }
188 :
189 1 : IFile& IFile::scanField(const std::string&name,long unsigned &x) {
190 : std::string str;
191 1 : scanField(name,str);
192 1 : if(*this) Tools::convert(str,x);
193 1 : return *this;
194 : }
195 :
196 14 : IFile& IFile::scanField(const std::string&name,long long unsigned &x) {
197 : std::string str;
198 14 : scanField(name,str);
199 14 : if(*this) Tools::convert(str,x);
200 14 : return *this;
201 : }
202 :
203 1102120 : IFile& IFile::scanField(Value* val) {
204 1102120 : double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure
205 1102120 : scanField( val->getName(), ff );
206 1102120 : val->set( ff );
207 2204240 : if( FieldExist("min_" + val->getName() ) ) {
208 : std::string min, max;
209 3309 : scanField("min_" + val->getName(), min );
210 3309 : scanField("max_" + val->getName(), max );
211 3309 : val->setDomain( min, max );
212 : } else {
213 1098811 : val->setNotPeriodic();
214 : }
215 1102120 : return *this;
216 : }
217 :
218 1568586 : IFile& IFile::scanField() {
219 1568586 : if(!ignoreFields) {
220 16352445 : for(unsigned i=0; i<fields.size(); i++) {
221 14998179 : 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" );
222 : }
223 : }
224 1568586 : inMiddleOfField=false;
225 1568586 : return *this;
226 : }
227 :
228 11813 : IFile::IFile():
229 11813 : inMiddleOfField(false),
230 11813 : ignoreFields(false),
231 11813 : noEOL(false)
232 : {
233 11813 : }
234 :
235 12164 : IFile::~IFile() {
236 11813 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
237 12164 : }
238 :
239 1729584 : IFile& IFile::getline(std::string &str) {
240 1729584 : char tmp=0;
241 : str="";
242 : fpos_t pos;
243 1729584 : fgetpos(fp,&pos);
244 113804277 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
245 112074693 : str+=tmp;
246 : }
247 1729584 : if(tmp=='\r') {
248 53 : llread(&tmp,1);
249 53 : plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
250 : }
251 1729584 : if(eof && noEOL) {
252 1017 : if(str.length()>0) eof=false;
253 1728567 : } else if(eof || err || tmp!='\n') {
254 6478 : eof = true;
255 : str="";
256 6478 : if(!err) fsetpos(fp,&pos);
257 : // there was a fsetpos here that apparently is not necessary
258 : // fsetpos(fp,&pos);
259 : // I think it was necessary to have rewind working correctly
260 : // after end of file. Since rewind is not used now anywhere,
261 : // it should be ok not to reset position.
262 : // This is necessary so that eof works properly for emacs files
263 : // with no endline at end of file.
264 : }
265 1729584 : return *this;
266 : }
267 :
268 16612809 : unsigned IFile::findField(const std::string&name)const {
269 : unsigned i;
270 106736163 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break;
271 16612809 : if(i>=fields.size()) {
272 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
273 : }
274 16612809 : return i;
275 : }
276 :
277 6133 : void IFile::reset(bool reset) {
278 6133 : eof = reset;
279 6133 : err = reset;
280 6133 : if(!reset && fp) clearerr(fp);
281 : #ifdef __PLUMED_HAS_ZLIB
282 6133 : if(!reset && gzfp) gzclearerr(gzFile(gzfp));
283 : #endif
284 6133 : return;
285 : }
286 :
287 5790 : void IFile::allowIgnoredFields() {
288 5790 : ignoreFields=true;
289 5790 : }
290 :
291 1031 : void IFile::allowNoEOL() {
292 1031 : noEOL=true;
293 1031 : }
294 :
295 : }
|