Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2018 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 "Tools.h"
23 : #include "AtomNumber.h"
24 : #include "Exception.h"
25 : #include "IFile.h"
26 : #include <cstring>
27 : #include <dirent.h>
28 : #include <iostream>
29 :
30 : using namespace std;
31 : namespace PLMD {
32 :
33 : template<class T>
34 1352213 : bool Tools::convertToAny(const string & str,T & t) {
35 1352213 : istringstream istr(str.c_str());
36 1352213 : bool ok=static_cast<bool>(istr>>t);
37 1352214 : if(!ok) return false;
38 2695860 : string remaining;
39 1347930 : istr>>remaining;
40 2700146 : return remaining.length()==0;
41 : }
42 :
43 109268 : bool Tools::convert(const string & str,int & t) {
44 109268 : return convertToAny(str,t);
45 : }
46 :
47 8 : bool Tools::convert(const string & str,long int & t) {
48 8 : return convertToAny(str,t);
49 : }
50 :
51 384130 : bool Tools::convert(const string & str,unsigned & t) {
52 384130 : return convertToAny(str,t);
53 : }
54 :
55 135840 : bool Tools::convert(const string & str,AtomNumber &a) {
56 : unsigned i;
57 135840 : bool r=convert(str,i);
58 135840 : if(r) a.setSerial(i);
59 135840 : return r;
60 : }
61 :
62 : template<class T>
63 2922891 : bool Tools::convertToReal(const string & str,T & t) {
64 2922891 : if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
65 1032037 : t=pi; return true;
66 1890855 : } else if(str=="-PI" || str=="-pi") {
67 1032031 : t=-pi; return true;
68 858823 : } else if( str.find("PI")!=std::string::npos ) {
69 0 : std::size_t pi_start=str.find_first_of("PI");
70 0 : if(str.substr(pi_start)!="PI") return false;
71 0 : istringstream nstr(str.substr(0,pi_start));
72 0 : T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
73 0 : if(!ok) return false;
74 0 : t=ff*pi;
75 0 : std::string remains; nstr>>remains;
76 0 : return remains.length()==0;
77 858823 : } else if( str.find("pi")!=std::string::npos ) {
78 13 : std::size_t pi_start=str.find_first_of("pi");
79 13 : if(str.substr(pi_start)!="pi") return false;
80 13 : istringstream nstr(str.substr(0,pi_start));
81 13 : T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
82 13 : if(!ok) return false;
83 13 : t=ff*pi;
84 26 : std::string remains; nstr>>remains;
85 26 : return remains.length()==0;
86 858809 : } else if(str=="NAN") {
87 2 : t=NAN;
88 2 : return true;
89 : }
90 858807 : return convertToAny(str,t);
91 : }
92 :
93 0 : bool Tools::convert(const string & str,float & t) {
94 0 : return convertToReal(str,t);
95 : }
96 :
97 2922890 : bool Tools::convert(const string & str,double & t) {
98 2922890 : return convertToReal(str,t);
99 : }
100 :
101 0 : bool Tools::convert(const string & str,long double & t) {
102 0 : return convertToReal(str,t);
103 : }
104 :
105 13536 : bool Tools::convert(const string & str,string & t) {
106 13536 : t=str;
107 13536 : return true;
108 : }
109 :
110 348653 : vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) {
111 348653 : plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available");
112 348653 : plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{',
113 0 : "only ( [ { allowed as parenthesis");
114 348653 : if(!separators) separators=" \t\n";
115 348653 : const string sep(separators);
116 348653 : char openpar=parenthesis[0];
117 : char closepar;
118 348653 : if(openpar=='(') closepar=')';
119 348653 : if(openpar=='[') closepar=']';
120 348653 : if(openpar=='{') closepar='}';
121 348653 : vector<string> words;
122 697306 : string word;
123 348653 : int parenthesisLevel=0;
124 348653 : if(parlevel) parenthesisLevel=*parlevel;
125 13975708 : for(unsigned i=0; i<line.length(); i++) {
126 13627055 : bool found=false;
127 13627055 : bool onParenthesis=false;
128 13627055 : if(line[i]==openpar || line[i]==closepar) onParenthesis=true;
129 13627055 : if(line[i]==closepar) {
130 1111 : parenthesisLevel--;
131 1111 : plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'");
132 : }
133 13627055 : if(parenthesisLevel==0) for(unsigned j=0; j<sep.length(); j++) if(line[i]==sep[j]) found=true;
134 : // If at parenthesis level zero (outer)
135 13627055 : if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]);
136 13627055 : if(onParenthesis) word.push_back(' ');
137 13627055 : if(line[i]==openpar) parenthesisLevel++;
138 13627055 : if(found && word.length()>0) {
139 737993 : if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
140 737993 : words.push_back(word);
141 737993 : word.clear();
142 : }
143 : }
144 348653 : if(word.length()>0) {
145 244612 : if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
146 244612 : words.push_back(word);
147 : }
148 348653 : if(parlevel) *parlevel=parenthesisLevel;
149 697306 : return words;
150 : }
151 :
152 2563 : bool Tools::getParsedLine(IFile& ifile,vector<string> & words) {
153 2563 : string line("");
154 2563 : words.clear();
155 : bool stat;
156 2563 : bool inside=false;
157 2563 : int parlevel=0;
158 2563 : bool mergenext=false;
159 8836 : while((stat=ifile.getline(line))) {
160 6065 : trimComments(line);
161 6065 : trim(line);
162 6065 : if(line.length()==0) continue;
163 4629 : vector<string> w=getWords(line,NULL,&parlevel);
164 4629 : if(!w.empty()) {
165 4629 : if(inside && *(w.begin())=="...") {
166 211 : inside=false;
167 211 : if(w.size()==2) plumed_massert(w[1]==words[0],"second word in terminating \"...\" "+w[1]+" line, if present, should be equal to first word of directive: "+words[0]);
168 211 : plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words");
169 211 : w.clear();
170 4418 : } else if(*(w.end()-1)=="...") {
171 211 : inside=true;
172 211 : w.erase(w.end()-1);
173 : };
174 4629 : int i0=0;
175 4629 : if(mergenext && words.size()>0 && w.size()>0) {
176 11 : words[words.size()-1]+=" "+w[0];
177 11 : i0=1;
178 : }
179 4629 : for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]);
180 : }
181 4629 : mergenext=(parlevel>0);
182 4629 : if(!inside)break;
183 2274 : }
184 2563 : plumed_massert(parlevel==0,"non matching parenthesis");
185 2563 : if(words.size()>0) return true;
186 208 : return stat;
187 : }
188 :
189 :
190 1458905 : bool Tools::getline(FILE* fp,string & line) {
191 1458905 : line="";
192 1458905 : const int bufferlength=1024;
193 : char buffer[bufferlength];
194 : bool ret;
195 1458905 : for(int i=0; i<bufferlength; i++) buffer[i]='\0';
196 2917810 : while((ret=fgets(buffer,bufferlength,fp))) {
197 1458499 : line.append(buffer);
198 1458499 : unsigned ss=strlen(buffer);
199 1458499 : if(ss>0) if(buffer[ss-1]=='\n') break;
200 : };
201 1458905 : if(line.length()>0) if(*(line.end()-1)=='\n') line.erase(line.end()-1);
202 1458905 : if(line.length()>0) if(*(line.end()-1)=='\r') line.erase(line.end()-1);
203 1458905 : return ret;
204 : }
205 :
206 72156 : void Tools::trim(string & s) {
207 72156 : size_t n=s.find_last_not_of(" \t");
208 72156 : s=s.substr(0,n+1);
209 72156 : }
210 :
211 66896 : void Tools::trimComments(string & s) {
212 66896 : size_t n=s.find_first_of("#");
213 66896 : s=s.substr(0,n);
214 66896 : }
215 :
216 26743 : bool Tools::getKey(vector<string>& line,const string & key,string & s) {
217 26743 : s.clear();
218 176755 : for(vector<string>::iterator p=line.begin(); p!=line.end(); ++p) {
219 162747 : if((*p).length()==0) continue;
220 162747 : string x=(*p).substr(0,key.length());
221 162747 : if(x==key) {
222 12735 : if((*p).length()==key.length())return false;
223 12735 : string tmp=(*p).substr(key.length(),(*p).length());
224 12735 : line.erase(p);
225 12735 : s=tmp;
226 12735 : return true;
227 : }
228 150012 : };
229 14008 : return false;
230 : }
231 :
232 2440 : void Tools::interpretRanges(std::vector<std::string>&s) {
233 2440 : vector<string> news;
234 8113 : for(vector<string>::iterator p=s.begin(); p!=s.end(); ++p) {
235 5673 : news.push_back(*p);
236 5673 : size_t dash=p->find("-");
237 10622 : if(dash==string::npos) continue;
238 : int first;
239 1088 : if(!Tools::convert(p->substr(0,dash),first)) continue;
240 724 : int stride=1;
241 : int second;
242 724 : size_t colon=p->substr(dash+1).find(":");
243 724 : if(colon!=string::npos) {
244 40 : if(!Tools::convert(p->substr(dash+1).substr(0,colon),second) ||
245 30 : !Tools::convert(p->substr(dash+1).substr(colon+1),stride)) continue;
246 : } else {
247 714 : if(!Tools::convert(p->substr(dash+1),second)) continue;
248 : }
249 724 : news.resize(news.size()-1);
250 724 : if(first<=second) {
251 723 : plumed_massert(stride>0,"interpreting ranges "+ *p + ", stride should be positive");
252 70406 : for(int i=first; i<=second; i+=stride) {
253 69683 : string ss;
254 69683 : convert(i,ss);
255 69683 : news.push_back(ss);
256 69683 : }
257 : } else {
258 1 : plumed_massert(stride<0,"interpreting ranges "+ *p + ", stride should be positive");
259 3 : for(int i=first; i>=second; i+=stride) {
260 2 : string ss;
261 2 : convert(i,ss);
262 2 : news.push_back(ss);
263 2 : }
264 : }
265 : }
266 2440 : s=news;
267 2440 : }
268 :
269 2347 : void Tools::interpretLabel(vector<string>&s) {
270 2362 : if(s.size()<2)return;
271 2332 : string s0=s[0];
272 2332 : unsigned l=s0.length();
273 2332 : if(l<1) return;
274 2332 : if(s0[l-1]==':') {
275 1143 : s[0]=s[1];
276 1143 : s[1]="LABEL="+s0.substr(0,l-1);
277 2332 : }
278 : }
279 :
280 1636 : vector<string> Tools::ls(const string&d) {
281 : DIR*dir;
282 1636 : vector<string> result;
283 1636 : if ((dir=opendir(d.c_str()))) {
284 : #if defined(__PLUMED_HAS_READDIR_R)
285 : struct dirent ent;
286 : #endif
287 : while(true) {
288 : struct dirent *res;
289 : #if defined(__PLUMED_HAS_READDIR_R)
290 24130 : readdir_r(dir,&ent,&res);
291 : #else
292 : // cppcheck complains about this:
293 : // (portability) Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.
294 : // since we use it only if readdir_r is not available, I suppress the warning
295 : // GB
296 : // cppcheck-suppress readdirCalled
297 : res=readdir(dir);
298 : #endif
299 24130 : if(!res) break;
300 22494 : if(string(res->d_name)!="." && string(res->d_name)!="..") result.push_back(res->d_name);
301 : }
302 24130 : closedir (dir);
303 : }
304 1636 : return result;
305 : }
306 :
307 448 : void Tools::stripLeadingAndTrailingBlanks( std::string& str ) {
308 448 : std::size_t first=str.find_first_not_of(' ');
309 448 : std::size_t last=str.find_last_not_of(' ');
310 448 : if( first<=last && first!=std::string::npos) str=str.substr(first,last+1);
311 448 : }
312 :
313 2589 : std::string Tools::extension(const std::string&s) {
314 2589 : size_t n=s.find_last_of(".");
315 2589 : std::string ext;
316 2589 : if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) {
317 1188 : ext=s.substr(n+1);
318 1188 : if(ext.find("/")!=std::string::npos) ext="";
319 1188 : string base=s.substr(0,n);
320 1188 : if(base.length()==0) ext="";
321 1188 : if(base.length()>0 && base[base.length()-1]=='/') ext="";
322 : }
323 2589 : return ext;
324 : }
325 :
326 431811 : bool Tools::startWith(const std::string & full,const std::string &start) {
327 431811 : return (full.substr(0,start.length())==start);
328 : }
329 :
330 21293 : bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) {
331 21293 : const std::string search(key+"=");
332 359350 : for(vector<string>::const_iterator p=line.begin(); p!=line.end(); ++p) {
333 346473 : if(startWith(*p,search)) return true;
334 : }
335 12877 : return false;
336 : }
337 :
338 :
339 :
340 2523 : }
|