LCOV - code coverage report
Current view: top level - tools - IFile.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 145 151 96.0 %
Date: 2024-10-18 14:00:25 Functions: 22 25 88.0 %

          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   113811710 : size_t IFile::llread(char*ptr,size_t s) {
      42   113811710 :   plumed_assert(fp);
      43             :   size_t r;
      44   113811710 :   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   113808188 :     if(std::feof(fp))   eof=true;
      56   113808188 :     if(std::ferror(fp)) err=true;
      57             :   }
      58   113811710 :   return r;
      59             : }
      60             : 
      61     1575060 : IFile& IFile::advanceField() {
      62     1575060 :   plumed_assert(!inMiddleOfField);
      63             :   std::string line;
      64             :   bool done=false;
      65     3151955 :   while(!done) {
      66     1583336 :     getline(line);
      67             : // using explicit conversion not to confuse cppcheck 1.86
      68     1583336 :     if(!bool(*this)) {return *this;}
      69     1576895 :     std::vector<std::string> words=Tools::getWords(line);
      70     3153597 :     if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
      71         743 :       fields.clear();
      72        4925 :       for(unsigned i=2; i<words.size(); i++) {
      73             :         Field field;
      74             :         field.name=words[i];
      75        4182 :         fields.push_back(field);
      76             :       }
      77     1597874 :     } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
      78             :       Field field;
      79             :       field.name=words[2];
      80             :       field.value=words[3];
      81        3275 :       field.constant=true;
      82        3275 :       fields.push_back(field);
      83             :     } else {
      84             :       unsigned nf=0;
      85    18110234 :       for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++;
      86     1572877 :       Tools::trimComments(line);
      87     3145754 :       words=Tools::getWords(line);
      88     1572877 :       if( words.size()==nf ) {
      89             :         unsigned j=0;
      90    18055607 :         for(unsigned i=0; i<fields.size(); i++) {
      91    16486988 :           if(fields[i].constant) continue;
      92     7618069 :           fields[i].value=words[j];
      93     7618069 :           fields[i].read=false;
      94     7618069 :           j++;
      95             :         }
      96             :         done=true;
      97        4258 :       } 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     1576895 :   }
     102     1568619 :   inMiddleOfField=true;
     103     1568619 :   return *this;
     104             : }
     105             : 
     106        1527 : IFile& IFile::open(const std::string&path) {
     107        1527 :   plumed_massert(!cloned,"file "+path+" appears to be cloned");
     108        1527 :   eof=false;
     109        1527 :   err=false;
     110        1527 :   fp=NULL;
     111        1527 :   gzfp=NULL;
     112        1527 :   bool do_exist=FileExist(path);
     113        1529 :   plumed_massert(do_exist,"file " + path + " cannot be found");
     114        1526 :   fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
     115        3052 :   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        1526 :   if(plumed) plumed->insertFile(*this);
     123        1526 :   return *this;
     124             : }
     125             : 
     126     1138913 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
     127     1138913 :   if(!inMiddleOfField) advanceField();
     128             : // using explicit conversion not to confuse cppcheck 1.86
     129     1138913 :   if(!bool(*this)) return *this;
     130             :   s.clear();
     131     9200224 :   for(unsigned i=0; i<fields.size(); i++)
     132     8061387 :     s.push_back(fields[i].name);
     133             :   return *this;
     134             : }
     135             : 
     136     1138809 : bool IFile::FieldExist(const std::string& s) {
     137             :   std::vector<std::string> slist;
     138     1138809 :   scanFieldList(slist);
     139     1138809 :   int mycount = (int) std::count(slist.begin(), slist.end(), s);
     140     1138809 :   if(mycount>0) return true;
     141     1115436 :   else return false;
     142     1138809 : }
     143             : 
     144    16619614 : IFile& IFile::scanField(const std::string&name,std::string&str) {
     145    16619614 :   if(!inMiddleOfField) advanceField();
     146             : // using explicit conversion not to confuse cppcheck 1.86
     147    16619614 :   if(!bool(*this)) return *this;
     148    16613249 :   unsigned i=findField(name);
     149    16613249 :   str=fields[i].value;
     150    16613249 :   fields[i].read=true;
     151    16613249 :   return *this;
     152             : }
     153             : 
     154     7519268 : IFile& IFile::scanField(const std::string&name,double &x) {
     155             :   std::string str;
     156     7519268 :   scanField(name,str);
     157     7519268 :   if(*this) Tools::convert(str,x);
     158     7519268 :   return *this;
     159             : }
     160             : 
     161     2466976 : IFile& IFile::scanField(const std::string&name,int &x) {
     162             :   std::string str;
     163     2466976 :   scanField(name,str);
     164     2466976 :   if(*this) Tools::convert(str,x);
     165     2466976 :   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           0 : IFile& IFile::scanField(const std::string&name,long long int &x) {
     176             :   std::string str;
     177           0 :   scanField(name,str);
     178           0 :   if(*this) Tools::convert(str,x);
     179           0 :   return *this;
     180             : }
     181             : 
     182          17 : IFile& IFile::scanField(const std::string&name,unsigned &x) {
     183             :   std::string str;
     184          17 :   scanField(name,str);
     185          17 :   if(*this) Tools::convert(str,x);
     186          17 :   return *this;
     187             : }
     188             : 
     189           1 : IFile& IFile::scanField(const std::string&name,long unsigned &x) {
     190             :   std::string str;
     191           1 :   scanField(name,str);
     192           1 :   if(*this) Tools::convert(str,x);
     193           1 :   return *this;
     194             : }
     195             : 
     196          14 : IFile& IFile::scanField(const std::string&name,long long unsigned &x) {
     197             :   std::string str;
     198          14 :   scanField(name,str);
     199          14 :   if(*this) Tools::convert(str,x);
     200          14 :   return *this;
     201             : }
     202             : 
     203     1102208 : IFile& IFile::scanField(Value* val) {
     204     1102208 :   double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure
     205     1102208 :   scanField(  val->getName(), ff );
     206     1102208 :   val->set( ff );
     207     2204416 :   if( FieldExist("min_" + val->getName() ) ) {
     208             :     std::string min, max;
     209        3309 :     scanField("min_" + val->getName(), min );
     210        3309 :     scanField("max_" + val->getName(), max );
     211        3309 :     val->setDomain( min, max );
     212             :   } else {
     213     1098899 :     val->setNotPeriodic();
     214             :   }
     215     1102208 :   return *this;
     216             : }
     217             : 
     218     1568630 : IFile& IFile::scanField() {
     219     1568630 :   if(!ignoreFields) {
     220    16352929 :     for(unsigned i=0; i<fields.size(); i++) {
     221    14998619 :       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" );
     222             :     }
     223             :   }
     224     1568630 :   inMiddleOfField=false;
     225     1568630 :   return *this;
     226             : }
     227             : 
     228       11813 : IFile::IFile():
     229       11813 :   inMiddleOfField(false),
     230       11813 :   ignoreFields(false),
     231       11813 :   noEOL(false)
     232             : {
     233       11813 : }
     234             : 
     235       12164 : IFile::~IFile() {
     236       11813 :   if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
     237       12164 : }
     238             : 
     239     1729624 : IFile& IFile::getline(std::string &str) {
     240     1729624 :   char tmp=0;
     241             :   str="";
     242             :   fpos_t pos;
     243     1729624 :   fgetpos(fp,&pos);
     244   113811657 :   while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
     245   112082033 :     str+=tmp;
     246             :   }
     247     1729624 :   if(tmp=='\r') {
     248          53 :     llread(&tmp,1);
     249          53 :     plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
     250             :   }
     251     1729624 :   if(eof && noEOL) {
     252        1017 :     if(str.length()>0) eof=false;
     253     1728607 :   } else if(eof || err || tmp!='\n') {
     254        6480 :     eof = true;
     255             :     str="";
     256        6480 :     if(!err) fsetpos(fp,&pos);
     257             : // there was a fsetpos here that apparently is not necessary
     258             : //  fsetpos(fp,&pos);
     259             : // I think it was necessary to have rewind working correctly
     260             : // after end of file. Since rewind is not used now anywhere,
     261             : // it should be ok not to reset position.
     262             : // This is necessary so that eof works properly for emacs files
     263             : // with no endline at end of file.
     264             :   }
     265     1729624 :   return *this;
     266             : }
     267             : 
     268    16613249 : unsigned IFile::findField(const std::string&name)const {
     269             :   unsigned i;
     270   106738583 :   for(i=0; i<fields.size(); i++) if(fields[i].name==name) break;
     271    16613249 :   if(i>=fields.size()) {
     272           0 :     plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
     273             :   }
     274    16613249 :   return i;
     275             : }
     276             : 
     277        6135 : void IFile::reset(bool reset) {
     278        6135 :   eof = reset;
     279        6135 :   err = reset;
     280        6135 :   if(!reset && fp) clearerr(fp);
     281             : #ifdef __PLUMED_HAS_ZLIB
     282        6135 :   if(!reset && gzfp) gzclearerr(gzFile(gzfp));
     283             : #endif
     284        6135 :   return;
     285             : }
     286             : 
     287        5790 : void IFile::allowIgnoredFields() {
     288        5790 :   ignoreFields=true;
     289        5790 : }
     290             : 
     291        1031 : void IFile::allowNoEOL() {
     292        1031 :   noEOL=true;
     293        1031 : }
     294             : 
     295             : }

Generated by: LCOV version 1.16