LCOV - code coverage report
Current view: top level - tools - Tools.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 206 219 94.1 %
Date: 2018-12-19 07:49:13 Functions: 26 32 81.2 %

          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 : }

Generated by: LCOV version 1.13