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 : #ifndef __PLUMED_core_CLTool_h 23 : #define __PLUMED_core_CLTool_h 24 : #include <cstdio> 25 : #include <vector> 26 : #include <string> 27 : #include <cstdio> 28 : #include "tools/Tools.h" 29 : #include "tools/Keywords.h" 30 : 31 : namespace PLMD { 32 : 33 : class Communicator; 34 : 35 4690 : class CLToolOptions { 36 : friend class CLTool; 37 : friend class CLToolRegister; 38 : private: 39 : std::vector<std::string> line; 40 : /// The documentation for this command line tool 41 : const Keywords& keys; 42 : static Keywords emptyKeys; 43 : public: 44 : explicit CLToolOptions(const std::string &name); 45 : CLToolOptions(const CLToolOptions& co, const Keywords& k); 46 : }; 47 : 48 : /** 49 : \ingroup INHERIT 50 : This is the abstract base class to use for implementing new command line tool, within it there 51 : is \ref AddingACLTool "information" as to how to go about implemneting a new tool. 52 : */ 53 : 54 : class CLTool { 55 : private: 56 : /// The name of this command line tool 57 : const std::string name; 58 : /// The list of keywords for this CLTool 59 : const Keywords& keywords; 60 : /// The data read in from the command line stored in a map with the keywords 61 : std::map<std::string,std::string> inputData; 62 : /// Read the arguments from the command line 63 : bool readCommandLineArgs( int argc, char**argv, FILE*out ); 64 : /// Read the arguments from an input file specified on the command line 65 : bool readInputFile( int argc, char**argv, FILE* in, FILE*out ); 66 : /// Set arguments from the default options provided to Keywords 67 : void setRemainingToDefault(FILE* out); 68 : public: 69 : /// Set the input data: 70 : void setInputData(const std::map<std::string,std::string>&inputData) { 71 : this->inputData=inputData; 72 0 : } 73 : const std::map<std::string,std::string>&getInputData() { 74 : return this->inputData; 75 : } 76 : protected: 77 : /// Get the value of one of the command line arguments 78 : template<class T> 79 : bool parse(const std::string&key,T&t); 80 : /// Find out whether one of the command line flags is present or not 81 : void parseFlag(const std::string&key,bool&t); 82 : /// Crash the command line tool with an error 83 : [[noreturn]] void error(const std::string& msg); 84 : template<class T> 85 : bool parseVector(const std::string&key,std::vector<T>&t); 86 : public: 87 : /// How is the input specified on the command line or in an input file 88 : enum {unset,commandline,ifile} inputdata; 89 : /// Create the help keywords 90 : static void registerKeywords( Keywords& keys ); 91 : explicit CLTool(const CLToolOptions& co ); 92 : /// Read the arguments from the command line 93 : bool readInput( int argc, char**argv, FILE* in, FILE*out ); 94 : /// virtual function mapping to the specific main for each tool 95 : virtual int main( FILE* in, FILE*out, Communicator&pc )=0; 96 : /// virtual function returning a one-line descriptor for the tool 97 0 : virtual std::string description()const {return "(no description available)";} 98 : /// virtual destructor to allow inheritance 99 2345 : virtual ~CLTool() {} 100 : }; 101 : 102 : template<class T> 103 23694 : bool CLTool::parse(const std::string&key,T&t) { 104 23694 : plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); 105 47388 : if(keywords.style(key,"compulsory") ) { 106 0 : if(inputData.count(key)==0) error("missing data for keyword " + key); 107 3709 : bool check=Tools::convertNoexcept(inputData[key],t); 108 3709 : if(!check) error("data input for keyword " + key + " has wrong type"); 109 : return true; 110 : } 111 18243 : if( inputData.count(key)==0 ) return false; 112 1742 : Tools::convert(inputData[key],t); 113 1742 : return true; 114 : } 115 : // very limited support and check: take more from core/Action.h parseVector 116 : template<class T> 117 366 : bool CLTool::parseVector(const std::string&key,std::vector<T>&t) { 118 : 119 : // Check keyword has been registered 120 366 : plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); 121 : // initial size 122 366 : unsigned size=t.size(); 123 : bool skipcheck=false; 124 366 : if(size==0) skipcheck=true; // if the vector in input has size zero, skip the check if size of input vector is the same of argument read 125 : 126 : // check if there is some value 127 : 128 732 : plumed_massert(inputData[key]!="false","compulsory keyword "+std::string(key)+"has no data"); 129 366 : std::vector<std::string> words=Tools::getWords(inputData[key],"\t\n ,"); 130 366 : t.resize(0); 131 366 : if(words.size()==0)return false; 132 : 133 773 : for(unsigned i=0; i<words.size(); ++i) { 134 : T v; 135 487 : Tools::convert(words[i],v); 136 487 : t.push_back(v); 137 : } 138 : // check the size 139 286 : if( !skipcheck && t.size()!=size ) { 140 0 : plumed_merror("vector read in for keyword "+key+" has wrong size" ); 141 : } 142 : std::string def; 143 : T val; 144 572 : if ( keywords.style(key,"compulsory") && t.size()==0 ) { 145 0 : if( keywords.getDefaultValue(key,def) ) { 146 0 : if( def.length()==0 || !Tools::convertNoexcept(def,val) ) { 147 0 : plumed_merror("ERROR in keyword "+key+ " has weird default value" ); 148 : } else { 149 : // GB: before it was like this, but clearly if t.size()==0 this was not doing anything 150 : // for(unsigned i=0; i<t.size(); ++i) t[i]=val; 151 0 : t.resize(1); 152 0 : t[0]=val; 153 : } 154 : } else { 155 0 : plumed_merror("keyword " + key + " is compulsory for this action"); 156 : } 157 : } 158 : return true; 159 366 : } 160 : 161 : 162 : 163 : } 164 : 165 : #endif