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 8732184 : size_t IFile::llread(char*ptr,size_t s) {
42 8732184 : plumed_assert(fp);
43 : size_t r;
44 8732184 : 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 : r=fread(ptr,1,s,fp);
55 8728746 : if(feof(fp)) eof=true;
56 8728746 : if(ferror(fp)) err=true;
57 : }
58 8732184 : return r;
59 : }
60 :
61 117552 : IFile& IFile::advanceField() {
62 117552 : plumed_assert(!inMiddleOfField);
63 : std::string line;
64 : bool done=false;
65 351262 : while(!done) {
66 123141 : getline(line);
67 : // using explicit conversion not to confuse cppcheck 1.86
68 123141 : if(!bool(*this)) {return *this;}
69 233710 : std::vector<std::string> words=Tools::getWords(line);
70 234879 : if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
71 584 : fields.clear();
72 9508 : for(unsigned i=2; i<words.size(); i++) {
73 : Field field;
74 : field.name=words[i];
75 2780 : fields.push_back(field);
76 : }
77 125975 : } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
78 : Field field;
79 : field.name=words[2];
80 : field.value=words[3];
81 2771 : field.constant=true;
82 2771 : fields.push_back(field);
83 : } else {
84 : unsigned nf=0;
85 4222325 : for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++;
86 113500 : Tools::trimComments(line);
87 227000 : words=Tools::getWords(line);
88 113500 : if( words.size()==nf ) {
89 : unsigned j=0;
90 4145290 : for(unsigned i=0; i<fields.size(); i++) {
91 1307586 : if(fields[i].constant) continue;
92 1004792 : fields[i].value=words[j];
93 502396 : fields[i].read=false;
94 502396 : j++;
95 : }
96 : 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 : }
102 111266 : inMiddleOfField=true;
103 111266 : return *this;
104 : }
105 :
106 861 : IFile& IFile::open(const std::string&path) {
107 861 : plumed_massert(!cloned,"file "+path+" appears to be cloned");
108 861 : eof=false;
109 861 : err=false;
110 861 : fp=NULL;
111 861 : gzfp=NULL;
112 861 : bool do_exist=FileExist(path);
113 865 : plumed_massert(do_exist,"file " + path + " cannot be found");
114 1720 : fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
115 1720 : 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 860 : if(plumed) plumed->insertFile(*this);
123 860 : return *this;
124 : }
125 :
126 40461 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
127 40461 : if(!inMiddleOfField) advanceField();
128 : // using explicit conversion not to confuse cppcheck 1.86
129 40461 : if(!bool(*this)) return *this;
130 40385 : s.clear();
131 1360882 : for(unsigned i=0; i<fields.size(); i++)
132 426704 : s.push_back(fields[i].name);
133 : return *this;
134 : }
135 :
136 40406 : bool IFile::FieldExist(const std::string& s) {
137 40406 : std::vector<std::string> slist;
138 40406 : scanFieldList(slist);
139 40406 : int mycount = (int) std::count(slist.begin(), slist.end(), s);
140 40406 : if(mycount>0) return true;
141 25409 : else return false;
142 : }
143 :
144 1276552 : IFile& IFile::scanField(const std::string&name,std::string&str) {
145 1276552 : if(!inMiddleOfField) advanceField();
146 : // using explicit conversion not to confuse cppcheck 1.86
147 1276552 : if(!bool(*this)) return *this;
148 1270342 : unsigned i=findField(name);
149 2540684 : str=fields[i].value;
150 1270342 : fields[i].read=true;
151 1270342 : return *this;
152 : }
153 :
154 481857 : IFile& IFile::scanField(const std::string&name,double &x) {
155 : std::string str;
156 481857 : scanField(name,str);
157 481857 : if(*this) Tools::convert(str,x);
158 481857 : return *this;
159 : }
160 :
161 202586 : IFile& IFile::scanField(const std::string&name,int &x) {
162 : std::string str;
163 202586 : scanField(name,str);
164 202586 : if(*this) Tools::convert(str,x);
165 202586 : return *this;
166 : }
167 :
168 9033 : IFile& IFile::scanField(Value* val) {
169 9033 : double ff=NAN; // this is to be sure a NAN value is replaced upon failure
170 9033 : scanField( val->getName(), ff );
171 9033 : val->set( ff );
172 18066 : if( FieldExist("min_" + val->getName() ) ) {
173 : 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 9033 : val->setNotPeriodic();
179 : }
180 9033 : return *this;
181 : }
182 :
183 111270 : IFile& IFile::scanField() {
184 111270 : if(!ignoreFields) {
185 3715088 : for(unsigned i=0; i<fields.size(); i++) {
186 1172350 : 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 111270 : inMiddleOfField=false;
190 111270 : return *this;
191 : }
192 :
193 1075 : IFile::IFile():
194 : inMiddleOfField(false),
195 : ignoreFields(false),
196 2150 : noEOL(false)
197 : {
198 1075 : }
199 :
200 2410 : IFile::~IFile() {
201 1075 : if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
202 1335 : }
203 :
204 142880 : IFile& IFile::getline(std::string &str) {
205 142880 : char tmp=0;
206 : str="";
207 : fpos_t pos;
208 142880 : fgetpos(fp,&pos);
209 8732179 : while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
210 8589299 : str+=tmp;
211 : }
212 142880 : 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 142880 : if(eof && noEOL) {
217 557 : if(str.length()>0) eof=false;
218 142323 : } else if(eof || err || tmp!='\n') {
219 6293 : eof = true;
220 : 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 142880 : return *this;
231 : }
232 :
233 1270342 : unsigned IFile::findField(const std::string&name)const {
234 : unsigned i;
235 24712053 : for(i=0; i<fields.size(); i++) if(fields[i].name==name) break;
236 1270342 : if(i>=fields.size()) {
237 0 : plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
238 : }
239 1270342 : 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 572 : void IFile::allowNoEOL() {
257 572 : noEOL=true;
258 572 : }
259 :
260 4839 : }
|