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 114026712 : size_t IFile::llread(char*ptr,size_t s) {
42 114026712 : plumed_assert(fp);
43 : size_t r;
44 114026712 : if(gzfp) {
45 : #ifdef __PLUMED_HAS_ZLIB
46 3522 : int rr=gzread(gzFile(gzfp),ptr,s);
47 3522 : if(rr==0) {
48 6 : eof=true;
49 : }
50 3522 : if(rr<0) {
51 0 : err=true;
52 : }
53 3522 : r=rr;
54 : #else
55 : plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
56 : #endif
57 : } else {
58 : r=std::fread(ptr,1,s,fp);
59 114023190 : if(std::feof(fp)) {
60 7532 : eof=true;
61 : }
62 114023190 : if(std::ferror(fp)) {
63 0 : err=true;
64 : }
65 : }
66 114026712 : return r;
67 : }
68 :
69 1575220 : IFile& IFile::advanceField() {
70 1575220 : plumed_assert(!inMiddleOfField);
71 : std::string line;
72 : bool done=false;
73 3152289 : while(!done) {
74 1583521 : getline(line);
75 : // using explicit conversion not to confuse cppcheck 1.86
76 1583521 : if(!bool(*this)) {
77 6452 : return *this;
78 : }
79 1577069 : std::vector<std::string> words=Tools::getWords(line);
80 3153970 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
81 764 : fields.clear();
82 5145 : for(unsigned i=2; i<words.size(); i++) {
83 : Field field;
84 : field.name=words[i];
85 4381 : fields.push_back(field);
86 : }
87 1598035 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
88 : Field field;
89 : field.name=words[2];
90 : field.value=words[3];
91 3279 : field.constant=true;
92 3279 : fields.push_back(field);
93 : } else {
94 : unsigned nf=0;
95 18112026 : for(unsigned i=0; i<fields.size(); i++)
96 16539000 : if(!fields[i].constant) {
97 7638812 : nf++;
98 : }
99 1573026 : Tools::trimComments(line);
100 3146052 : words=Tools::getWords(line);
101 1573026 : if( words.size()==nf ) {
102 : unsigned j=0;
103 18057399 : for(unsigned i=0; i<fields.size(); i++) {
104 16488631 : if(fields[i].constant) {
105 8869019 : continue;
106 : }
107 7619612 : fields[i].value=words[j];
108 7619612 : fields[i].read=false;
109 7619612 : j++;
110 : }
111 : done=true;
112 4258 : } else if( !words.empty() ) {
113 0 : plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number\n this is the faulty line:\n"+line);
114 : }
115 : }
116 1577069 : }
117 1568768 : inMiddleOfField=true;
118 1568768 : return *this;
119 : }
120 :
121 1576 : IFile& IFile::open(const std::string&path) {
122 1576 : plumed_massert(!cloned,"file "+path+" appears to be cloned");
123 1576 : eof=false;
124 1576 : err=false;
125 1576 : fp=NULL;
126 1576 : gzfp=NULL;
127 1576 : bool do_exist=FileExist(path);
128 1578 : plumed_massert(do_exist,"file " + path + " cannot be found");
129 1575 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
130 3150 : if(Tools::extension(this->path)=="gz") {
131 : #ifdef __PLUMED_HAS_ZLIB
132 6 : gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"r");
133 : #else
134 : plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
135 : #endif
136 : }
137 1575 : if(plumed) {
138 1327 : plumed->insertFile(*this);
139 : }
140 1575 : return *this;
141 : }
142 :
143 1139213 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
144 1139213 : if(!inMiddleOfField) {
145 611 : advanceField();
146 : }
147 : // using explicit conversion not to confuse cppcheck 1.86
148 1139213 : if(!bool(*this)) {
149 : return *this;
150 : }
151 : s.clear();
152 9203524 : for(unsigned i=0; i<fields.size(); i++) {
153 8064387 : s.push_back(fields[i].name);
154 : }
155 : return *this;
156 : }
157 :
158 1139109 : bool IFile::FieldExist(const std::string& s) {
159 : std::vector<std::string> slist;
160 1139109 : scanFieldList(slist);
161 1139109 : int mycount = (int) std::count(slist.begin(), slist.end(), s);
162 1139109 : if(mycount>0) {
163 : return true;
164 : } else {
165 1115636 : return false;
166 : }
167 1139109 : }
168 :
169 16621268 : IFile& IFile::scanField(const std::string&name,std::string&str) {
170 16621268 : if(!inMiddleOfField) {
171 1574609 : advanceField();
172 : }
173 : // using explicit conversion not to confuse cppcheck 1.86
174 16621268 : if(!bool(*this)) {
175 : return *this;
176 : }
177 16614892 : unsigned i=findField(name);
178 16614892 : str=fields[i].value;
179 16614892 : fields[i].read=true;
180 16614892 : return *this;
181 : }
182 :
183 7520632 : IFile& IFile::scanField(const std::string&name,double &x) {
184 : std::string str;
185 7520632 : scanField(name,str);
186 7520632 : if(*this) {
187 7514304 : Tools::convert(str,x);
188 : }
189 7520632 : return *this;
190 : }
191 :
192 2467166 : IFile& IFile::scanField(const std::string&name,int &x) {
193 : std::string str;
194 2467166 : scanField(name,str);
195 2467166 : if(*this) {
196 2467123 : Tools::convert(str,x);
197 : }
198 2467166 : return *this;
199 : }
200 :
201 1 : IFile& IFile::scanField(const std::string&name,long int &x) {
202 : std::string str;
203 1 : scanField(name,str);
204 1 : if(*this) {
205 1 : Tools::convert(str,x);
206 : }
207 1 : return *this;
208 : }
209 :
210 0 : IFile& IFile::scanField(const std::string&name,long long int &x) {
211 : std::string str;
212 0 : scanField(name,str);
213 0 : if(*this) {
214 0 : Tools::convert(str,x);
215 : }
216 0 : return *this;
217 : }
218 :
219 17 : IFile& IFile::scanField(const std::string&name,unsigned &x) {
220 : std::string str;
221 17 : scanField(name,str);
222 17 : if(*this) {
223 17 : Tools::convert(str,x);
224 : }
225 17 : return *this;
226 : }
227 :
228 1 : IFile& IFile::scanField(const std::string&name,long unsigned &x) {
229 : std::string str;
230 1 : scanField(name,str);
231 1 : if(*this) {
232 1 : Tools::convert(str,x);
233 : }
234 1 : return *this;
235 : }
236 :
237 14 : IFile& IFile::scanField(const std::string&name,long long unsigned &x) {
238 : std::string str;
239 14 : scanField(name,str);
240 14 : if(*this) {
241 14 : Tools::convert(str,x);
242 : }
243 14 : return *this;
244 : }
245 :
246 1102308 : IFile& IFile::scanField(Value* val) {
247 1102308 : double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure
248 1102308 : scanField( val->getName(), ff );
249 1102308 : val->set( ff );
250 2204616 : if( FieldExist("min_" + val->getName() ) ) {
251 : std::string min, max;
252 3309 : scanField("min_" + val->getName(), min );
253 3309 : scanField("max_" + val->getName(), max );
254 3309 : val->setDomain( min, max );
255 : } else {
256 1098999 : val->setNotPeriodic();
257 : }
258 1102308 : return *this;
259 : }
260 :
261 1568779 : IFile& IFile::scanField() {
262 1568779 : if(!ignoreFields) {
263 16354721 : for(unsigned i=0; i<fields.size(); i++) {
264 15000262 : 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" );
265 : }
266 : }
267 1568779 : inMiddleOfField=false;
268 1568779 : return *this;
269 : }
270 :
271 11879 : IFile::IFile():
272 11879 : inMiddleOfField(false),
273 11879 : ignoreFields(false),
274 11879 : noEOL(false) {
275 11879 : }
276 :
277 12240 : IFile::~IFile() {
278 11879 : if(inMiddleOfField) {
279 4 : std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
280 : }
281 12240 : }
282 :
283 1733052 : IFile& IFile::getline(std::string &str) {
284 1733052 : char tmp=0;
285 : str="";
286 : fpos_t pos;
287 1733052 : fgetpos(fp,&pos);
288 114026659 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
289 112293607 : str+=tmp;
290 : }
291 1733052 : if(tmp=='\r') {
292 53 : llread(&tmp,1);
293 53 : plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
294 : }
295 1733052 : if(eof && noEOL) {
296 1042 : if(str.length()>0) {
297 3 : eof=false;
298 : }
299 1732010 : } else if(eof || err || tmp!='\n') {
300 6496 : eof = true;
301 : str="";
302 6496 : if(!err) {
303 6496 : fsetpos(fp,&pos);
304 : }
305 : // there was a fsetpos here that apparently is not necessary
306 : // fsetpos(fp,&pos);
307 : // I think it was necessary to have rewind working correctly
308 : // after end of file. Since rewind is not used now anywhere,
309 : // it should be ok not to reset position.
310 : // This is necessary so that eof works properly for emacs files
311 : // with no endline at end of file.
312 : }
313 1733052 : return *this;
314 : }
315 :
316 16614892 : unsigned IFile::findField(const std::string&name)const {
317 : unsigned i;
318 106748605 : for(i=0; i<fields.size(); i++)
319 106748605 : if(fields[i].name==name) {
320 : break;
321 : }
322 16614892 : if(i>=fields.size()) {
323 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
324 : }
325 16614892 : return i;
326 : }
327 :
328 6136 : void IFile::reset(bool reset) {
329 6136 : eof = reset;
330 6136 : err = reset;
331 6136 : if(!reset && fp) {
332 6136 : clearerr(fp);
333 : }
334 : #ifdef __PLUMED_HAS_ZLIB
335 6136 : if(!reset && gzfp) {
336 3 : gzclearerr(gzFile(gzfp));
337 : }
338 : #endif
339 6136 : return;
340 : }
341 :
342 5790 : void IFile::allowIgnoredFields() {
343 5790 : ignoreFields=true;
344 5790 : }
345 :
346 1056 : void IFile::allowNoEOL() {
347 1056 : noEOL=true;
348 1056 : }
349 :
350 : }
|