LCOV - code coverage report
Current view: top level - core - CLToolMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 99 150 66.0 %
Date: 2020-11-18 11:20:57 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2019 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 "CLToolMain.h"
      23             : #include "config/Config.h"
      24             : #include "tools/Exception.h"
      25             : #include "tools/Communicator.h"
      26             : #include "CLTool.h"
      27             : #include "CLToolRegister.h"
      28             : #include "tools/Tools.h"
      29             : #include "tools/DLLoader.h"
      30             : #include <string>
      31             : #include <cstdlib>
      32             : #include <cstdio>
      33             : #include <iostream>
      34             : #include <algorithm>
      35             : #include <unordered_map>
      36             : 
      37             : using namespace std;
      38             : 
      39             : #include "CLToolMainEnum.inc"
      40             : 
      41             : namespace PLMD {
      42             : 
      43       10292 : const std::unordered_map<std::string, int> & clToolMainWordMap() {
      44       11889 :   static std::unordered_map<std::string, int> word_map;
      45             :   static bool init=false;
      46       10292 :   if(!init) {
      47             : #include "CLToolMainMap.inc"
      48             :   }
      49       10292 :   init=true;
      50       10292 :   return word_map;
      51             : }
      52             : 
      53        1597 : CLToolMain::CLToolMain():
      54             :   argc(0),
      55             :   in(stdin),
      56             :   out(stdout),
      57        3194 :   comm(*new Communicator)
      58             : {
      59        1597 : }
      60             : 
      61        4791 : CLToolMain::~CLToolMain() {
      62        1597 :   delete &comm;
      63        3194 : }
      64             : 
      65             : #define CHECK_NULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"CLTool " + word + "\")");
      66             : 
      67        5146 : void CLToolMain::cmd(const std::string& word,void*val) {
      68             : 
      69       10292 :   std::vector<std::string> words=Tools::getWords(word);
      70        5146 :   unsigned nw=words.size();
      71        5146 :   if(nw==0) {
      72             :     // do nothing
      73             :   } else {
      74             :     int iword=-1;
      75             :     char**v;
      76             :     char*vv;
      77        5146 :     const auto it=clToolMainWordMap().find(words[0]);
      78        5146 :     if(it!=clToolMainWordMap().end()) iword=it->second;
      79        5146 :     switch(iword) {
      80        1597 :     case cmd_setArgc:
      81        1597 :       CHECK_NULL(val,word);
      82        1597 :       argc=*static_cast<int*>(val);
      83        1597 :       break;
      84        1597 :     case cmd_setArgv:
      85        1597 :       CHECK_NULL(val,word);
      86             :       v=static_cast<char**>(val);
      87       24159 :       for(int i=0; i<argc; ++i) argv.push_back(string(v[i]));
      88             :       break;
      89           0 :     case cmd_setArgvLine:
      90           0 :       CHECK_NULL(val,word);
      91             :       vv=static_cast<char*>(val);
      92           0 :       argv=Tools::getWords(vv);
      93           0 :       break;
      94           0 :     case cmd_setIn:
      95           0 :       CHECK_NULL(val,word);
      96           0 :       in=static_cast<FILE*>(val);
      97           0 :       break;
      98           0 :     case cmd_setOut:
      99           0 :       CHECK_NULL(val,word);
     100           0 :       out=static_cast<FILE*>(val);
     101           0 :       break;
     102         355 :     case cmd_setMPIComm:
     103         355 :       comm.Set_comm(val);
     104             :       break;
     105           0 :     case cmd_setMPIFComm:
     106           0 :       comm.Set_fcomm(val);
     107             :       break;
     108        1597 :     case cmd_run:
     109        1597 :       CHECK_NULL(val,word);
     110        1597 :       argc=argv.size();
     111             :       {
     112       24159 :         int n=0; for(int i=0; i<argc; ++i) n+=argv[i].length()+1;
     113        1597 :         std::vector<char> args(n);
     114        1597 :         std::vector<char*> vvv(argc);
     115             :         char* ptr=&args[0];
     116       24159 :         for(int i=0; i<argc; ++i) {
     117       22562 :           vvv[i]=ptr;
     118      290798 :           for(unsigned c=0; c<argv[i].length(); ++c) {
     119       89412 :             *ptr=argv[i][c]; ptr++;
     120             :           }
     121       11281 :           *ptr=0; ptr++;
     122             :         }
     123        3194 :         int ret=run(argc,&vvv[0],in,out,comm);
     124        1597 :         *static_cast<int*>(val)=ret;
     125             :       }
     126        1597 :       break;
     127           0 :     default:
     128           0 :       plumed_merror("cannot interpret cmd(\"CLTool " + word + "\"). check plumed developers manual to see the available commands.");
     129             :       break;
     130             :     }
     131             :   }
     132        5146 : }
     133             : 
     134             : /**
     135             : This is the entry point to the command line tools
     136             : included in the plumed library.
     137             : */
     138             : 
     139        1597 : int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc) {
     140             :   int i;
     141             :   bool printhelp=false;
     142             : 
     143        3194 :   DLLoader dlloader;
     144             : 
     145        1597 :   string root=config::getPlumedRoot();
     146             : 
     147             :   bool standalone_executable=false;
     148             : 
     149             : // Start parsing options
     150        1597 :   string prefix("");
     151        1597 :   string a("");
     152        4081 :   for(i=1; i<argc; i++) {
     153        5678 :     a=prefix+argv[i];
     154        2839 :     if(a.length()==0) continue;
     155        8517 :     if(a=="help" || a=="-h" || a=="--help") {
     156             :       printhelp=true;
     157             :       break;
     158        2839 :     } else if(a=="--has-mpi") {
     159           0 :       if(Communicator::initialized()) return 0;
     160           0 :       else return 1;
     161        2839 :     } else if(a=="--has-matheval") {
     162           0 :       return (config::hasMatheval()?0:1);
     163        2839 :     } else if(a=="--has-cregex") {
     164           0 :       return (config::hasCregex()?0:1);
     165        2839 :     } else if(a=="--has-dlopen") {
     166           0 :       return (config::hasDlopen()?0:1);
     167        2839 :     } else if(a=="--has-molfile") {
     168           0 :       return (config::hasMolfile()?0:1);
     169        2839 :     } else if(a=="--has-external-molfile") {
     170           0 :       return (config::hasExternalMolfile()?0:1);
     171        2839 :     } else if(a=="--has-zlib") {
     172           0 :       return (config::hasZlib()?0:1);
     173        2839 :     } else if(a=="--has-xdrfile") {
     174           0 :       return (config::hasXdrfile()?0:1);
     175        2839 :     } else if(a=="--is-installed") {
     176          13 :       return (config::isInstalled()?0:1);
     177        2826 :     } else if(a=="--no-mpi") {
     178             : // this is ignored, as it is parsed in main
     179        1242 :       if(i>1) {
     180           0 :         fprintf(stderr,"--no-mpi option can only be used as the first option");
     181             :         return 1;
     182             :       }
     183        1584 :     } else if(a=="--mpi") {
     184             : // this is ignored, as it is parsed in main
     185           0 :       if(i>1) {
     186           0 :         fprintf(stderr,"--mpi option can only be used as the first option");
     187             :         return 1;
     188             :       }
     189        1584 :     } else if(a=="--standalone-executable") {
     190             :       standalone_executable=true;
     191        3168 :     } else if(Tools::startWith(a,"--load=")) {
     192           0 :       a.erase(0,a.find("=")+1);
     193             :       prefix="";
     194           0 :       void *p=dlloader.load(a);
     195           0 :       if(!p) {
     196           0 :         fprintf(stderr,"ERROR: cannot load library %s\n",a.c_str());
     197           0 :         fprintf(stderr,"ERROR: %s\n",dlloader.error().c_str());
     198             :         return 1;
     199             :       }
     200        1584 :     } else if(a=="--load") {
     201             :       prefix="--load=";
     202        1584 :     } else if(a[0]=='-') {
     203           0 :       string msg="ERROR: Unknown option " +a;
     204           0 :       fprintf(stderr,"%s\n",msg.c_str());
     205             :       return 1;
     206             :     } else break;
     207             :   }
     208             : 
     209             : // Check if plumedRoot/patches/ directory exists (as a further check)
     210        1584 :   if(!standalone_executable) {
     211        3168 :     vector<string> files=Tools::ls(root);
     212        3168 :     if(find(files.begin(),files.end(),"patches")==files.end()) {
     213             :       string msg=
     214           0 :         "WARNING: I cannot find "+root+"/patches/ directory. Set PLUMED_ROOT or reinstall PLUMED\n\n";
     215           0 :       fprintf(stderr,"%s",msg.c_str());
     216             :     }
     217             :   }
     218             : 
     219             : // Build list of available C++ tools:
     220        3168 :   vector<string> availableCxx=cltoolRegister().list();
     221             : // Build list of available shell tools:
     222        1584 :   vector<string> availableShell;
     223        1584 :   if(!standalone_executable) {
     224        1584 :     vector<string> tmp;
     225        4752 :     tmp=Tools::ls(string(root+"/scripts"));
     226       36432 :     for(unsigned j=0; j<tmp.size(); ++j) {
     227             :       size_t ff=tmp[j].find(".sh");
     228       12672 :       if(ff==string::npos) tmp[j].erase();
     229        9504 :       else                 tmp[j].erase(ff);
     230             :     }
     231       36432 :     for(unsigned j=0; j<tmp.size(); ++j) if(tmp[j].length()>0) availableShell.push_back(tmp[j]);
     232             :   }
     233             : 
     234        1584 :   if(printhelp) {
     235             :     string msg=
     236             :       "Usage: plumed [options] [command] [command options]\n"
     237             :       "  plumed [command] -h|--help: to print help for a specific command\n"
     238             :       "Options:\n"
     239             :       "  [help|-h|--help]          : to print this help\n"
     240             :       "  [--is-installed]          : fails if plumed is not installed\n"
     241             :       "  [--has-mpi]               : fails if plumed is running without MPI\n"
     242             :       "  [--has-matheval]          : fails if plumed is compiled without matheval\n"
     243             :       "  [--has-dlopen]            : fails if plumed is compiled without dlopen\n"
     244             :       "  [--load LIB]              : loads a shared object (typically a plugin library)\n"
     245             :       "  [--standalone-executable] : tells plumed not to look for commands implemented as scripts\n"
     246           0 :       "Commands:\n";
     247             :     fprintf(out,"%s",msg.c_str());
     248           0 :     for(unsigned j=0; j<availableCxx.size(); ++j) {
     249           0 :       CLTool *cl=cltoolRegister().create(CLToolOptions(availableCxx[j]));
     250           0 :       plumed_assert(cl);
     251           0 :       string manual=availableCxx[j]+" : "+cl->description();
     252           0 :       delete cl;
     253             :       fprintf(out,"  plumed %s\n", manual.c_str());
     254             :     }
     255           0 :     for(unsigned j=0; j<availableShell.size(); ++j) {
     256           0 :       string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+availableShell[j]+".sh\" --description";
     257           0 :       FILE *fp=popen(cmd.c_str(),"r");
     258             :       string line,manual;
     259           0 :       while(Tools::getline(fp,line))manual+=line;
     260           0 :       pclose(fp);
     261           0 :       manual= availableShell[j]+" : "+manual;
     262             :       fprintf(out,"  plumed %s\n", manual.c_str());
     263             :     }
     264             :     return 0;
     265             :   }
     266        1584 :   if(i==argc) {
     267             :     fprintf(out,"%s","Nothing to do. Use 'plumed help' for help\n");
     268             :     return 0;
     269             :   }
     270             : 
     271             : // this is the command to be executed:
     272        1584 :   string command(argv[i]);
     273             : 
     274        3168 :   if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()) {
     275        2490 :     CLTool *cl=cltoolRegister().create(CLToolOptions(command));
     276        1245 :     plumed_assert(cl);
     277             :     // Read the command line options (returns false if we are just printing help)
     278        1245 :     if( !cl->readInput( argc-i,&argv[i],in,out ) ) { delete cl; return 0; }
     279        1245 :     int ret=cl->main(in,out,pc);
     280        1245 :     delete cl;
     281        1245 :     return ret;
     282             :   }
     283             : 
     284         678 :   if(find(availableShell.begin(),availableShell.end(),command)!=availableShell.end()) {
     285         339 :     plumed_massert(in==stdin,"shell tools can only work on stdin");
     286         339 :     plumed_massert(out==stdout,"shell tools can only work on stdin");
     287        2034 :     string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+command+".sh\"";
     288        2229 :     for(int j=i+1; j<argc; j++) cmd+=string(" ")+argv[j];
     289         339 :     int r=system(cmd.c_str());
     290             : // this is necessary since system seems to return numbers which are multiple
     291             : // of 256. this would make the interpretation by the shell wrong
     292             : // I just return 1 in case of failure and 0 in case of success
     293         339 :     if(r!=0) return 1;
     294         267 :     else return 0;
     295             :   }
     296             : 
     297           0 :   string msg="ERROR: unknown command " + command + ". Use 'plumed help' for help";
     298           0 :   fprintf(stderr,"%s\n",msg.c_str());
     299             :   return 1;
     300             : 
     301             : }
     302        4839 : }

Generated by: LCOV version 1.13