LCOV - code coverage report
Current view: top level - core - CLToolMain.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 109 135 80.7 %
Date: 2024-10-11 08:09:47 Functions: 5 5 100.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 "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 <memory>
      36             : #include <unordered_map>
      37             : 
      38             : namespace PLMD {
      39             : 
      40        3445 : CLToolMain::CLToolMain():
      41        3445 :   argc(0),
      42        3445 :   in(stdin),
      43        3445 :   out(stdout)
      44             : {
      45        3445 : }
      46             : 
      47        6890 : CLToolMain::~CLToolMain() {
      48             : // empty destructor to delete unique_ptr
      49        6890 : }
      50             : 
      51             : #define CHECK_NULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"CLTool " + word + "\")");
      52             : 
      53       10668 : void CLToolMain::cmd(const std::string& word,const TypesafePtr & val) {
      54             : 
      55             : // Enumerate all possible commands:
      56             :   enum {
      57             : #include "CLToolMainEnum.inc"
      58             :   };
      59             : 
      60             : // Static object (initialized once) containing the map of commands:
      61             :   const static std::unordered_map<std::string, int> word_map = {
      62             : #include "CLToolMainMap.inc"
      63       41655 :   };
      64             : 
      65       10668 :   std::vector<std::string> words=Tools::getWords(word);
      66       10668 :   unsigned nw=words.size();
      67       10668 :   if(nw==0) {
      68             :     // do nothing
      69             :   } else {
      70             :     int iword=-1;
      71             :     const char*const*v;
      72             :     const char*vv;
      73             :     const auto it=word_map.find(words[0]);
      74       10668 :     if(it!=word_map.end()) iword=it->second;
      75       10668 :     switch(iword) {
      76             :     case cmd_setArgc:
      77        3441 :       CHECK_NULL(val,word);
      78        3441 :       argc=val.get<int>();
      79        3441 :       break;
      80             :     case cmd_setArgv:
      81        3441 :       CHECK_NULL(val,word);
      82        3441 :       v=val.get<const char*const*>(argc);
      83       23258 :       for(int i=0; i<argc; ++i) argv.push_back(std::string(v[i]));
      84             :       break;
      85             :     case cmd_setArgvLine:
      86           4 :       CHECK_NULL(val,word);
      87             :       vv=val.get<const char*>();
      88           4 :       argv=Tools::getWords(vv);
      89           4 :       break;
      90             :     case cmd_setIn:
      91           0 :       CHECK_NULL(val,word);
      92           0 :       in=val.get<FILE*>();
      93           0 :       break;
      94             :     case cmd_setOut:
      95           1 :       CHECK_NULL(val,word);
      96           1 :       out=val.get<FILE*>();
      97           1 :       break;
      98         336 :     case cmd_setMPIComm:
      99         336 :       comm.Set_comm(val);
     100             :       break;
     101           0 :     case cmd_setMPIFComm:
     102           0 :       comm.Set_fcomm(val);
     103             :       break;
     104             :     case cmd_run:
     105        3445 :       CHECK_NULL(val,word);
     106        3445 :       argc=argv.size();
     107             :       {
     108       23270 :         int n=0; for(int i=0; i<argc; ++i) n+=argv[i].length()+1;
     109        3445 :         std::vector<char> args(n);
     110        3445 :         std::vector<char*> vvv(argc);
     111             :         char* ptr=&args[0];
     112       23270 :         for(int i=0; i<argc; ++i) {
     113       19825 :           vvv[i]=ptr;
     114      174134 :           for(unsigned c=0; c<argv[i].length(); ++c) {
     115      154309 :             *ptr=argv[i][c]; ptr++;
     116             :           }
     117       19825 :           *ptr=0; ptr++;
     118             :         }
     119        3445 :         val.set(int(run(argc,&vvv[0],in,out,comm)));
     120             :       }
     121        3445 :       break;
     122           0 :     default:
     123           0 :       plumed_merror("cannot interpret cmd(\"CLTool " + word + "\"). check plumed developers manual to see the available commands.");
     124             :       break;
     125             :     }
     126             :   }
     127       10668 : }
     128             : 
     129             : /**
     130             : This is the entry point to the command line tools
     131             : included in the plumed library.
     132             : */
     133             : 
     134        3445 : int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc) {
     135             :   int i;
     136             :   bool printhelp=false;
     137             : 
     138        3445 :   DLLoader dlloader;
     139             : 
     140        3445 :   std::string root=config::getPlumedRoot();
     141             : 
     142             :   bool standalone_executable=false;
     143             : 
     144             : // Start parsing options
     145        3445 :   std::string prefix("");
     146        3445 :   std::string a("");
     147        6550 :   for(i=1; i<argc; i++) {
     148       13100 :     a=prefix+argv[i];
     149        6550 :     if(a.length()==0) continue;
     150       19650 :     if(a=="help" || a=="-h" || a=="--help") {
     151             :       printhelp=true;
     152             :       break;
     153        6546 :     } else if(a=="--has-mpi") {
     154           0 :       if(Communicator::initialized()) return 0;
     155           0 :       else return 1;
     156        6546 :     } else if(a=="--has-cregex") {
     157           0 :       return (config::hasCregex()?0:1);
     158        6546 :     } else if(a=="--has-dlopen") {
     159           0 :       return (config::hasDlopen()?0:1);
     160        6546 :     } else if(a=="--has-molfile") {
     161           0 :       return (config::hasMolfile()?0:1);
     162        6546 :     } else if(a=="--has-external-molfile") {
     163           0 :       return (config::hasExternalMolfile()?0:1);
     164        6546 :     } else if(a=="--has-zlib") {
     165           0 :       return (config::hasZlib()?0:1);
     166        6546 :     } else if(a=="--has-xdrfile") {
     167             :       return 0; // always ok
     168        6546 :     } else if(a=="--is-installed") {
     169         619 :       return (config::isInstalled()?0:1);
     170        5927 :     } else if(a=="--no-mpi") {
     171             : // this is ignored, as it is parsed in main
     172        3105 :       continue;
     173        2822 :     } else if(a=="--mpi") {
     174             : // this is ignored, as it is parsed in main
     175           0 :       continue;
     176        2822 :     } else if(a=="--standalone-executable") {
     177             :       standalone_executable=true;
     178        5644 :     } else if(Tools::startWith(a,"--load=")) {
     179           0 :       a.erase(0,a.find("=")+1);
     180             :       prefix="";
     181           0 :       void *p=dlloader.load(a);
     182           0 :       if(!p) {
     183           0 :         std::fprintf(stderr,"ERROR: cannot load library %s\n",a.c_str());
     184           0 :         std::fprintf(stderr,"ERROR: %s\n",dlloader.error().c_str());
     185             :         return 1;
     186             :       }
     187        2822 :     } else if(a=="--load") {
     188             :       prefix="--load=";
     189        2822 :     } else if(a[0]=='-') {
     190           0 :       std::string msg="ERROR: Unknown option " +a;
     191           0 :       std::fprintf(stderr,"%s\n",msg.c_str());
     192             :       return 1;
     193             :     } else break;
     194             :   }
     195             : 
     196             : // Check if plumedRoot/patches/ directory exists (as a further check)
     197        2826 :   if(!standalone_executable) {
     198        2826 :     std::vector<std::string> files=Tools::ls(root);
     199        2826 :     if(find(files.begin(),files.end(),"patches")==files.end()) {
     200             :       std::string msg=
     201           0 :         "WARNING: I cannot find "+root+"/patches/ directory. Set PLUMED_ROOT or reinstall PLUMED\n\n";
     202           0 :       std::fprintf(stderr,"%s",msg.c_str());
     203             :     }
     204        2826 :   }
     205             : 
     206             : // Build list of available C++ tools:
     207        2826 :   std::vector<std::string> availableCxx=cltoolRegister().list();
     208             : // Build list of available shell tools:
     209             :   std::vector<std::string> availableShell;
     210        2826 :   if(!standalone_executable) {
     211             :     std::vector<std::string> tmp;
     212        5652 :     tmp=Tools::ls(std::string(root+"/scripts"));
     213       22608 :     for(unsigned j=0; j<tmp.size(); ++j) {
     214       19782 :       size_t ff=tmp[j].find(".sh");
     215       19782 :       if(ff==std::string::npos) tmp[j].erase();
     216       19782 :       else                 tmp[j].erase(ff);
     217             :     }
     218       22608 :     for(unsigned j=0; j<tmp.size(); ++j) if(tmp[j].length()>0) availableShell.push_back(tmp[j]);
     219        2826 :   }
     220             : 
     221        2826 :   if(printhelp) {
     222             :     std::string msg=
     223             :       "Usage: plumed [options] [command] [command options]\n"
     224             :       "  plumed [command] -h|--help: to print help for a specific command\n"
     225             :       "Options:\n"
     226             :       "  [help|-h|--help]          : to print this help\n"
     227             :       "  [--is-installed]          : fails if plumed is not installed\n"
     228             :       "  [--has-mpi]               : fails if plumed is running without MPI\n"
     229             :       "  [--has-dlopen]            : fails if plumed is compiled without dlopen\n"
     230             :       "  [--load LIB]              : loads a shared object (typically a plugin library)\n"
     231             :       "  [--standalone-executable] : tells plumed not to look for commands implemented as scripts\n"
     232           4 :       "Commands:\n";
     233             :     std::fprintf(out,"%s",msg.c_str());
     234          64 :     for(unsigned j=0; j<availableCxx.size(); ++j) {
     235         120 :       auto cl=cltoolRegister().create(CLToolOptions(availableCxx[j]));
     236          60 :       plumed_assert(cl);
     237         176 :       std::string manual=availableCxx[j]+" : "+cl->description();
     238             :       std::fprintf(out,"  plumed %s\n", manual.c_str());
     239          60 :     }
     240          32 :     for(unsigned j=0; j<availableShell.size(); ++j) {
     241             :       std::string manual;
     242             : #ifdef __PLUMED_HAS_POPEN
     243          56 :       std::string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+availableShell[j]+".sh\" --description";
     244          28 :       FILE *fp=popen(cmd.c_str(),"r");
     245             :       std::string line;
     246          56 :       while(Tools::getline(fp,line))manual+=line;
     247          28 :       pclose(fp);
     248             : #else
     249             :       manual="(doc not avail)";
     250             : #endif
     251          56 :       manual= availableShell[j]+" : "+manual;
     252             :       std::fprintf(out,"  plumed %s\n", manual.c_str());
     253             :     }
     254             :     return 0;
     255             :   }
     256        2822 :   if(i==argc) {
     257             :     std::fprintf(out,"%s","Nothing to do. Use 'plumed help' for help\n");
     258             :     return 0;
     259             :   }
     260             : 
     261             : // this is the command to be executed:
     262        2822 :   std::string command(argv[i]);
     263             : 
     264        2822 :   if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()) {
     265        4570 :     auto cl=cltoolRegister().create(CLToolOptions(command));
     266        2285 :     plumed_assert(cl);
     267             :     // Read the command line options (returns false if we are just printing help)
     268        2285 :     if( !cl->readInput( argc-i,&argv[i],in,out ) ) { return 0; }
     269        2285 :     int ret=cl->main(in,out,pc);
     270             :     return ret;
     271        2285 :   }
     272             : 
     273         537 :   if(find(availableShell.begin(),availableShell.end(),command)!=availableShell.end()) {
     274         537 :     plumed_massert(in==stdin,"shell tools can only work on stdin");
     275         537 :     plumed_massert(out==stdout,"shell tools can only work on stdin");
     276        1074 :     std::string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+command+".sh\"";
     277        2034 :     for(int j=i+1; j<argc; j++) cmd+=std::string(" ")+argv[j];
     278         537 :     int r=std::system(cmd.c_str());
     279             : // this is necessary since system seems to return numbers which are multiple
     280             : // of 256. this would make the interpretation by the shell wrong
     281             : // I just return 1 in case of failure and 0 in case of success
     282         537 :     if(r!=0) return 1;
     283         426 :     else return 0;
     284             :   }
     285             : 
     286           0 :   std::string msg="ERROR: unknown command " + command + ". Use 'plumed help' for help";
     287           0 :   std::fprintf(stderr,"%s\n",msg.c_str());
     288             :   return 1;
     289             : 
     290        6271 : }
     291             : }

Generated by: LCOV version 1.15