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 8713381 : size_t IFile::llread(char*ptr,size_t s) {
42 8713381 : plumed_assert(fp);
43 : size_t r;
44 8713381 : if(gzfp) {
45 : #ifdef __PLUMED_HAS_ZLIB
46 3438 : int rr=gzread(gzFile(gzfp),ptr,s);
47 3438 : if(rr==0) eof=true;
48 3438 : if(rr<0) err=true;
49 3438 : r=rr;
50 : #else
51 : plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
52 : #endif
53 : } else {
54 8709943 : r=fread(ptr,1,s,fp);
55 8709943 : if(feof(fp)) eof=true;
56 8709943 : if(ferror(fp)) err=true;
57 : }
58 8713381 : return r;
59 : }
60 :
61 117452 : IFile& IFile::advanceField() {
62 117452 : plumed_assert(!inMiddleOfField);
63 117452 : std::string line;
64 117452 : bool done=false;
65 351659 : while(!done) {
66 123041 : getline(line);
67 : // using explicit conversion not to confuse cppcheck 1.86
68 123041 : if(!bool(*this)) {return *this;}
69 116755 : std::vector<std::string> words=Tools::getWords(line);
70 116755 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
71 584 : fields.clear();
72 3364 : for(unsigned i=2; i<words.size(); i++) {
73 2780 : Field field;
74 2780 : field.name=words[i];
75 2780 : fields.push_back(field);
76 2780 : }
77 116171 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
78 2771 : Field field;
79 2771 : field.name=words[2];
80 2771 : field.value=words[3];
81 2771 : field.constant=true;
82 2771 : fields.push_back(field);
83 : } else {
84 113400 : unsigned nf=0;
85 113400 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++;
86 113400 : Tools::trimComments(line);
87 113400 : words=Tools::getWords(line);
88 113400 : if( words.size()==nf ) {
89 111166 : unsigned j=0;
90 1417852 : for(unsigned i=0; i<fields.size(); i++) {
91 1306686 : if(fields[i].constant) continue;
92 501596 : fields[i].value=words[j];
93 501596 : fields[i].read=false;
94 501596 : j++;
95 : }
96 111166 : done=true;
97 2234 : } else if( !words.empty() ) {
98 0 : plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number");
99 : }
100 : }
101 116755 : }
102 111166 : inMiddleOfField=true;
103 111166 : return *this;
104 : }
105 :
106 859 : IFile& IFile::open(const std::string&path) {
107 859 : plumed_massert(!cloned,"file "+path+" appears to be cloned");
108 859 : eof=false;
109 859 : err=false;
110 859 : fp=NULL;
111 859 : gzfp=NULL;
112 859 : bool do_exist=FileExist(path);
113 859 : plumed_massert(do_exist,"file " + path + " cannot be found");
114 858 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
115 858 : 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 858 : if(plumed) plumed->insertFile(*this);
123 858 : return *this;
124 : }
125 :
126 39961 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
127 39961 : if(!inMiddleOfField) advanceField();
128 : // using explicit conversion not to confuse cppcheck 1.86
129 39961 : if(!bool(*this)) return *this;
130 39885 : s.clear();
131 462089 : for(unsigned i=0; i<fields.size(); i++)
132 422204 : s.push_back(fields[i].name);
133 39885 : return *this;
134 : }
135 :
136 39906 : bool IFile::FieldExist(const std::string& s) {
137 39906 : std::vector<std::string> slist;
138 39906 : scanFieldList(slist);
139 39906 : int mycount = (int) std::count(slist.begin(), slist.end(), s);
140 39906 : if(mycount>0) return true;
141 25009 : else return false;
142 : }
143 :
144 1275652 : IFile& IFile::scanField(const std::string&name,std::string&str) {
145 1275652 : if(!inMiddleOfField) advanceField();
146 : // using explicit conversion not to confuse cppcheck 1.86
147 1275652 : if(!bool(*this)) return *this;
148 1269442 : unsigned i=findField(name);
149 1269442 : str=fields[i].value;
150 1269442 : fields[i].read=true;
151 1269442 : return *this;
152 : }
153 :
154 481057 : IFile& IFile::scanField(const std::string&name,double &x) {
155 481057 : std::string str;
156 481057 : scanField(name,str);
157 481057 : if(*this) Tools::convert(str,x);
158 481057 : return *this;
159 : }
160 :
161 202586 : IFile& IFile::scanField(const std::string&name,int &x) {
162 202586 : std::string str;
163 202586 : scanField(name,str);
164 202586 : if(*this) Tools::convert(str,x);
165 202586 : return *this;
166 : }
167 :
168 8833 : IFile& IFile::scanField(Value* val) {
169 8833 : double ff=NAN; // this is to be sure a NAN value is replaced upon failure
170 8833 : scanField( val->getName(), ff );
171 8833 : val->set( ff );
172 8833 : if( FieldExist("min_" + val->getName() ) ) {
173 0 : std::string min, max;
174 0 : scanField("min_" + val->getName(), min );
175 0 : scanField("max_" + val->getName(), max );
176 0 : val->setDomain( min, max );
177 : } else {
178 8833 : val->setNotPeriodic();
179 : }
180 8833 : return *this;
181 : }
182 :
183 111170 : IFile& IFile::scanField() {
184 111170 : if(!ignoreFields) {
185 1270369 : for(unsigned i=0; i<fields.size(); i++) {
186 1171450 : 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 111170 : inMiddleOfField=false;
190 111170 : return *this;
191 : }
192 :
193 1073 : IFile::IFile():
194 : inMiddleOfField(false),
195 : ignoreFields(false),
196 1073 : noEOL(false)
197 : {
198 1073 : }
199 :
200 3479 : IFile::~IFile() {
201 1073 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
202 2406 : }
203 :
204 142699 : IFile& IFile::getline(std::string &str) {
205 142699 : char tmp=0;
206 142699 : str="";
207 : fpos_t pos;
208 142699 : fgetpos(fp,&pos);
209 8856075 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
210 8570677 : str+=tmp;
211 : }
212 142699 : 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 142699 : if(eof && noEOL) {
217 555 : if(str.length()>0) eof=false;
218 142144 : } else if(eof || err || tmp!='\n') {
219 6293 : eof = true;
220 6293 : str="";
221 6293 : 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 142699 : return *this;
231 : }
232 :
233 1269442 : unsigned IFile::findField(const std::string&name)const {
234 : unsigned i;
235 1269442 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break;
236 1269442 : if(i>=fields.size()) {
237 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
238 : }
239 1269442 : return i;
240 : }
241 :
242 6111 : void IFile::reset(bool reset) {
243 6111 : eof = reset;
244 6111 : err = reset;
245 6111 : if(!reset && fp) clearerr(fp);
246 : #ifdef __PLUMED_HAS_ZLIB
247 6111 : if(!reset && gzfp) gzclearerr(gzFile(gzfp));
248 : #endif
249 6111 : return;
250 : }
251 :
252 5715 : void IFile::allowIgnoredFields() {
253 5715 : ignoreFields=true;
254 5715 : }
255 :
256 570 : void IFile::allowNoEOL() {
257 570 : noEOL=true;
258 570 : }
259 :
260 4821 : }
|