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 99942797 : size_t IFile::llread(char*ptr,size_t s) {
42 99942797 : plumed_assert(fp);
43 : size_t r;
44 99942797 : 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 99939275 : if(std::feof(fp)) eof=true;
56 99939275 : if(std::ferror(fp)) err=true;
57 : }
58 99942797 : return r;
59 : }
60 :
61 1325672 : IFile& IFile::advanceField() {
62 1325672 : plumed_assert(!inMiddleOfField);
63 : std::string line;
64 : bool done=false;
65 2653152 : while(!done) {
66 1333890 : getline(line);
67 : // using explicit conversion not to confuse cppcheck 1.86
68 1333890 : if(!bool(*this)) {return *this;}
69 1327480 : std::vector<std::string> words=Tools::getWords(line);
70 2654715 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
71 711 : fields.clear();
72 4712 : for(unsigned i=2; i<words.size(); i++) {
73 : Field field;
74 : field.name=words[i];
75 4001 : fields.push_back(field);
76 : }
77 1348445 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
78 : Field field;
79 : field.name=words[2];
80 : field.value=words[3];
81 3252 : field.constant=true;
82 3252 : fields.push_back(field);
83 : } else {
84 : unsigned nf=0;
85 17100318 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++;
86 1323517 : Tools::trimComments(line);
87 2647034 : words=Tools::getWords(line);
88 1323517 : if( words.size()==nf ) {
89 : unsigned j=0;
90 17045706 : for(unsigned i=0; i<fields.size(); i++) {
91 15726444 : if(fields[i].constant) continue;
92 6859893 : fields[i].value=words[j];
93 6859893 : fields[i].read=false;
94 6859893 : j++;
95 : }
96 : done=true;
97 4255 : } 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 1327480 : }
102 1319262 : inMiddleOfField=true;
103 1319262 : return *this;
104 : }
105 :
106 1227 : IFile& IFile::open(const std::string&path) {
107 1227 : plumed_massert(!cloned,"file "+path+" appears to be cloned");
108 1227 : eof=false;
109 1227 : err=false;
110 1227 : fp=NULL;
111 1227 : gzfp=NULL;
112 1227 : bool do_exist=FileExist(path);
113 1229 : plumed_massert(do_exist,"file " + path + " cannot be found");
114 1226 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
115 2452 : 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 1226 : if(plumed) plumed->insertFile(*this);
123 1226 : return *this;
124 : }
125 :
126 1138136 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
127 1138136 : if(!inMiddleOfField) advanceField();
128 : // using explicit conversion not to confuse cppcheck 1.86
129 1138136 : if(!bool(*this)) return *this;
130 1138060 : s.clear();
131 9188677 : for(unsigned i=0; i<fields.size(); i++)
132 8050617 : s.push_back(fields[i].name);
133 : return *this;
134 : }
135 :
136 1138039 : bool IFile::FieldExist(const std::string& s) {
137 : std::vector<std::string> slist;
138 1138039 : scanFieldList(slist);
139 1138039 : int mycount = (int) std::count(slist.begin(), slist.end(), s);
140 1138039 : if(mycount>0) return true;
141 1114761 : else return false;
142 1138039 : }
143 :
144 15855443 : IFile& IFile::scanField(const std::string&name,std::string&str) {
145 15855443 : if(!inMiddleOfField) advanceField();
146 : // using explicit conversion not to confuse cppcheck 1.86
147 15855443 : if(!bool(*this)) return *this;
148 15849109 : unsigned i=findField(name);
149 15849109 : str=fields[i].value;
150 15849109 : fields[i].read=true;
151 15849109 : return *this;
152 : }
153 :
154 7009069 : IFile& IFile::scanField(const std::string&name,double &x) {
155 : std::string str;
156 7009069 : scanField(name,str);
157 7009069 : if(*this) Tools::convert(str,x);
158 7009069 : return *this;
159 : }
160 :
161 2213283 : IFile& IFile::scanField(const std::string&name,int &x) {
162 : std::string str;
163 2213283 : scanField(name,str);
164 2213283 : if(*this) Tools::convert(str,x);
165 2213283 : 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 17 : IFile& IFile::scanField(const std::string&name,unsigned &x) {
176 : std::string str;
177 17 : scanField(name,str);
178 17 : if(*this) Tools::convert(str,x);
179 17 : return *this;
180 : }
181 :
182 15 : IFile& IFile::scanField(const std::string&name,long unsigned &x) {
183 : std::string str;
184 15 : scanField(name,str);
185 15 : if(*this) Tools::convert(str,x);
186 15 : return *this;
187 : }
188 :
189 1101714 : IFile& IFile::scanField(Value* val) {
190 1101714 : double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure
191 1101714 : scanField( val->getName(), ff );
192 1101714 : val->set( ff );
193 2203428 : if( FieldExist("min_" + val->getName() ) ) {
194 : std::string min, max;
195 3309 : scanField("min_" + val->getName(), min );
196 3309 : scanField("max_" + val->getName(), max );
197 3309 : val->setDomain( min, max );
198 : } else {
199 1098405 : val->setNotPeriodic();
200 : }
201 1101714 : return *this;
202 : }
203 :
204 1319265 : IFile& IFile::scanField() {
205 1319265 : if(!ignoreFields) {
206 15343350 : for(unsigned i=0; i<fields.size(); i++) {
207 14238658 : 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" );
208 : }
209 : }
210 1319265 : inMiddleOfField=false;
211 1319265 : return *this;
212 : }
213 :
214 11484 : IFile::IFile():
215 11484 : inMiddleOfField(false),
216 11484 : ignoreFields(false),
217 11484 : noEOL(false)
218 : {
219 11484 : }
220 :
221 11825 : IFile::~IFile() {
222 11484 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
223 11825 : }
224 :
225 1469739 : IFile& IFile::getline(std::string &str) {
226 1469739 : char tmp=0;
227 : str="";
228 : fpos_t pos;
229 1469739 : fgetpos(fp,&pos);
230 99942744 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
231 98473005 : str+=tmp;
232 : }
233 1469739 : if(tmp=='\r') {
234 53 : llread(&tmp,1);
235 53 : plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
236 : }
237 1469739 : if(eof && noEOL) {
238 777 : if(str.length()>0) eof=false;
239 1468962 : } else if(eof || err || tmp!='\n') {
240 6436 : eof = true;
241 : str="";
242 6436 : if(!err) fsetpos(fp,&pos);
243 : // there was a fsetpos here that apparently is not necessary
244 : // fsetpos(fp,&pos);
245 : // I think it was necessary to have rewind working correctly
246 : // after end of file. Since rewind is not used now anywhere,
247 : // it should be ok not to reset position.
248 : // This is necessary so that eof works properly for emacs files
249 : // with no endline at end of file.
250 : }
251 1469739 : return *this;
252 : }
253 :
254 15849109 : unsigned IFile::findField(const std::string&name)const {
255 : unsigned i;
256 105136881 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break;
257 15849109 : if(i>=fields.size()) {
258 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
259 : }
260 15849109 : return i;
261 : }
262 :
263 6135 : void IFile::reset(bool reset) {
264 6135 : eof = reset;
265 6135 : err = reset;
266 6135 : if(!reset && fp) clearerr(fp);
267 : #ifdef __PLUMED_HAS_ZLIB
268 6135 : if(!reset && gzfp) gzclearerr(gzFile(gzfp));
269 : #endif
270 6135 : return;
271 : }
272 :
273 5778 : void IFile::allowIgnoredFields() {
274 5778 : ignoreFields=true;
275 5778 : }
276 :
277 792 : void IFile::allowNoEOL() {
278 792 : noEOL=true;
279 792 : }
280 :
281 : }
|