LCOV - code coverage report
Current view: top level - tools - IFile.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 166 175 94.9 %
Date: 2025-03-25 09:33:27 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   114075813 : size_t IFile::llread(char*ptr,size_t s) {
      42   114075813 :   plumed_assert(fp);
      43             :   size_t r;
      44   114075813 :   if(gzfp) {
      45             : #ifdef __PLUMED_HAS_ZLIB
      46        3522 :     int rr=gzread(gzFile(gzfp),ptr,s);
      47        3522 :     if(rr==0) {
      48           6 :       eof=true;
      49             :     }
      50        3522 :     if(rr<0) {
      51           0 :       err=true;
      52             :     }
      53        3522 :     r=rr;
      54             : #else
      55             :     plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
      56             : #endif
      57             :   } else {
      58             :     r=std::fread(ptr,1,s,fp);
      59   114072291 :     if(std::feof(fp)) {
      60        7525 :       eof=true;
      61             :     }
      62   114072291 :     if(std::ferror(fp)) {
      63           0 :       err=true;
      64             :     }
      65             :   }
      66   114075813 :   return r;
      67             : }
      68             : 
      69     1575514 : IFile& IFile::advanceField() {
      70     1575514 :   plumed_assert(!inMiddleOfField);
      71             :   std::string line;
      72             :   bool done=false;
      73     3152880 :   while(!done) {
      74     1583815 :     getline(line);
      75             : // using explicit conversion not to confuse cppcheck 1.86
      76     1583815 :     if(!bool(*this)) {
      77        6449 :       return *this;
      78             :     }
      79     1577366 :     std::vector<std::string> words=Tools::getWords(line);
      80     3154564 :     if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") {
      81         764 :       fields.clear();
      82        5145 :       for(unsigned i=2; i<words.size(); i++) {
      83             :         Field field;
      84             :         field.name=words[i];
      85        4381 :         fields.push_back(field);
      86             :       }
      87     1598332 :     } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") {
      88             :       Field field;
      89             :       field.name=words[2];
      90             :       field.value=words[3];
      91        3279 :       field.constant=true;
      92        3279 :       fields.push_back(field);
      93             :     } else {
      94             :       unsigned nf=0;
      95    18115293 :       for(unsigned i=0; i<fields.size(); i++)
      96    16541970 :         if(!fields[i].constant) {
      97     7641188 :           nf++;
      98             :         }
      99     1573323 :       Tools::trimComments(line);
     100     3146646 :       words=Tools::getWords(line);
     101     1573323 :       if( words.size()==nf ) {
     102             :         unsigned j=0;
     103    18060666 :         for(unsigned i=0; i<fields.size(); i++) {
     104    16491601 :           if(fields[i].constant) {
     105     8869613 :             continue;
     106             :           }
     107     7621988 :           fields[i].value=words[j];
     108     7621988 :           fields[i].read=false;
     109     7621988 :           j++;
     110             :         }
     111             :         done=true;
     112        4258 :       } else if( !words.empty() ) {
     113           0 :         plumed_merror("file " + getPath() + ": mismatch between number of fields in file and expected number\n this is the faulty line:\n"+line);
     114             :       }
     115             :     }
     116     1577366 :   }
     117     1569065 :   inMiddleOfField=true;
     118     1569065 :   return *this;
     119             : }
     120             : 
     121        1572 : IFile& IFile::open(const std::string&path) {
     122        1572 :   plumed_massert(!cloned,"file "+path+" appears to be cloned");
     123        1572 :   eof=false;
     124        1572 :   err=false;
     125        1572 :   fp=NULL;
     126        1572 :   gzfp=NULL;
     127        1572 :   bool do_exist=FileExist(path);
     128        1574 :   plumed_massert(do_exist,"file " + path + " cannot be found");
     129        1571 :   fp=std::fopen(const_cast<char*>(this->path.c_str()),"r");
     130        3142 :   if(Tools::extension(this->path)=="gz") {
     131             : #ifdef __PLUMED_HAS_ZLIB
     132           6 :     gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"r");
     133             : #else
     134             :     plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
     135             : #endif
     136             :   }
     137        1571 :   if(plumed) {
     138        1323 :     plumed->insertFile(*this);
     139             :   }
     140        1571 :   return *this;
     141             : }
     142             : 
     143     1140995 : IFile& IFile::scanFieldList(std::vector<std::string>&s) {
     144     1140995 :   if(!inMiddleOfField) {
     145         611 :     advanceField();
     146             :   }
     147             : // using explicit conversion not to confuse cppcheck 1.86
     148     1140995 :   if(!bool(*this)) {
     149             :     return *this;
     150             :   }
     151             :   s.clear();
     152     9223126 :   for(unsigned i=0; i<fields.size(); i++) {
     153     8082207 :     s.push_back(fields[i].name);
     154             :   }
     155             :   return *this;
     156             : }
     157             : 
     158     1140891 : bool IFile::FieldExist(const std::string& s) {
     159             :   std::vector<std::string> slist;
     160     1140891 :   scanFieldList(slist);
     161     1140891 :   int mycount = (int) std::count(slist.begin(), slist.end(), s);
     162     1140891 :   if(mycount>0) {
     163             :     return true;
     164             :   } else {
     165     1116824 :     return false;
     166             :   }
     167     1140891 : }
     168             : 
     169    16624235 : IFile& IFile::scanField(const std::string&name,std::string&str) {
     170    16624235 :   if(!inMiddleOfField) {
     171     1574903 :     advanceField();
     172             :   }
     173             : // using explicit conversion not to confuse cppcheck 1.86
     174    16624235 :   if(!bool(*this)) {
     175             :     return *this;
     176             :   }
     177    16617862 :   unsigned i=findField(name);
     178    16617862 :   str=fields[i].value;
     179    16617862 :   fields[i].read=true;
     180    16617862 :   return *this;
     181             : }
     182             : 
     183     7523005 : IFile& IFile::scanField(const std::string&name,double &x) {
     184             :   std::string str;
     185     7523005 :   scanField(name,str);
     186     7523005 :   if(*this) {
     187     7516680 :     Tools::convert(str,x);
     188             :   }
     189     7523005 :   return *this;
     190             : }
     191             : 
     192     2467166 : IFile& IFile::scanField(const std::string&name,int &x) {
     193             :   std::string str;
     194     2467166 :   scanField(name,str);
     195     2467166 :   if(*this) {
     196     2467123 :     Tools::convert(str,x);
     197             :   }
     198     2467166 :   return *this;
     199             : }
     200             : 
     201           1 : IFile& IFile::scanField(const std::string&name,long int &x) {
     202             :   std::string str;
     203           1 :   scanField(name,str);
     204           1 :   if(*this) {
     205           1 :     Tools::convert(str,x);
     206             :   }
     207           1 :   return *this;
     208             : }
     209             : 
     210           0 : IFile& IFile::scanField(const std::string&name,long long int &x) {
     211             :   std::string str;
     212           0 :   scanField(name,str);
     213           0 :   if(*this) {
     214           0 :     Tools::convert(str,x);
     215             :   }
     216           0 :   return *this;
     217             : }
     218             : 
     219          17 : IFile& IFile::scanField(const std::string&name,unsigned &x) {
     220             :   std::string str;
     221          17 :   scanField(name,str);
     222          17 :   if(*this) {
     223          17 :     Tools::convert(str,x);
     224             :   }
     225          17 :   return *this;
     226             : }
     227             : 
     228           1 : IFile& IFile::scanField(const std::string&name,long unsigned &x) {
     229             :   std::string str;
     230           1 :   scanField(name,str);
     231           1 :   if(*this) {
     232           1 :     Tools::convert(str,x);
     233             :   }
     234           1 :   return *this;
     235             : }
     236             : 
     237          14 : IFile& IFile::scanField(const std::string&name,long long unsigned &x) {
     238             :   std::string str;
     239          14 :   scanField(name,str);
     240          14 :   if(*this) {
     241          14 :     Tools::convert(str,x);
     242             :   }
     243          14 :   return *this;
     244             : }
     245             : 
     246     1102902 : IFile& IFile::scanField(Value* val) {
     247     1102902 :   double ff=std::numeric_limits<double>::quiet_NaN(); // this is to be sure a NaN value is replaced upon failure
     248     1102902 :   scanField(  val->getName(), ff );
     249     1102902 :   val->set( ff );
     250     2205804 :   if( FieldExist("min_" + val->getName() ) ) {
     251             :     std::string min, max;
     252        3309 :     scanField("min_" + val->getName(), min );
     253        3309 :     scanField("max_" + val->getName(), max );
     254        3309 :     val->setDomain( min, max );
     255             :   } else {
     256     1099593 :     val->setNotPeriodic();
     257             :   }
     258     1102902 :   return *this;
     259             : }
     260             : 
     261     1569076 : IFile& IFile::scanField() {
     262     1569076 :   if(!ignoreFields) {
     263    16357988 :     for(unsigned i=0; i<fields.size(); i++) {
     264    15003232 :       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" );
     265             :     }
     266             :   }
     267     1569076 :   inMiddleOfField=false;
     268     1569076 :   return *this;
     269             : }
     270             : 
     271       11875 : IFile::IFile():
     272       11875 :   inMiddleOfField(false),
     273       11875 :   ignoreFields(false),
     274       11875 :   noEOL(false) {
     275       11875 : }
     276             : 
     277       12236 : IFile::~IFile() {
     278       11875 :   if(inMiddleOfField) {
     279           4 :     std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n";
     280             :   }
     281       12236 : }
     282             : 
     283     1733216 : IFile& IFile::getline(std::string &str) {
     284     1733216 :   char tmp=0;
     285             :   str="";
     286             :   fpos_t pos;
     287     1733216 :   fgetpos(fp,&pos);
     288   114075760 :   while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) {
     289   112342544 :     str+=tmp;
     290             :   }
     291     1733216 :   if(tmp=='\r') {
     292          53 :     llread(&tmp,1);
     293          53 :     plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines");
     294             :   }
     295     1733216 :   if(eof && noEOL) {
     296        1038 :     if(str.length()>0) {
     297           3 :       eof=false;
     298             :     }
     299     1732178 :   } else if(eof || err || tmp!='\n') {
     300        6493 :     eof = true;
     301             :     str="";
     302        6493 :     if(!err) {
     303        6493 :       fsetpos(fp,&pos);
     304             :     }
     305             : // there was a fsetpos here that apparently is not necessary
     306             : //  fsetpos(fp,&pos);
     307             : // I think it was necessary to have rewind working correctly
     308             : // after end of file. Since rewind is not used now anywhere,
     309             : // it should be ok not to reset position.
     310             : // This is necessary so that eof works properly for emacs files
     311             : // with no endline at end of file.
     312             :   }
     313     1733216 :   return *this;
     314             : }
     315             : 
     316    16617862 : unsigned IFile::findField(const std::string&name)const {
     317             :   unsigned i;
     318   106764940 :   for(i=0; i<fields.size(); i++)
     319   106764940 :     if(fields[i].name==name) {
     320             :       break;
     321             :     }
     322    16617862 :   if(i>=fields.size()) {
     323           0 :     plumed_merror("file " + getPath() + ": field " + name + " cannot be found");
     324             :   }
     325    16617862 :   return i;
     326             : }
     327             : 
     328        6133 : void IFile::reset(bool reset) {
     329        6133 :   eof = reset;
     330        6133 :   err = reset;
     331        6133 :   if(!reset && fp) {
     332        6133 :     clearerr(fp);
     333             :   }
     334             : #ifdef __PLUMED_HAS_ZLIB
     335        6133 :   if(!reset && gzfp) {
     336           3 :     gzclearerr(gzFile(gzfp));
     337             :   }
     338             : #endif
     339        6133 :   return;
     340             : }
     341             : 
     342        5790 : void IFile::allowIgnoredFields() {
     343        5790 :   ignoreFields=true;
     344        5790 : }
     345             : 
     346        1052 : void IFile::allowNoEOL() {
     347        1052 :   noEOL=true;
     348        1052 : }
     349             : 
     350             : }

Generated by: LCOV version 1.16