Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-2018 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 :
36 : using namespace std;
37 : namespace PLMD {
38 :
39 828 : CLToolMain::CLToolMain():
40 : argc(0),
41 : in(stdin),
42 : out(stdout),
43 828 : comm(*new Communicator)
44 : {
45 828 : }
46 :
47 2484 : CLToolMain::~CLToolMain() {
48 828 : delete &comm;
49 1656 : }
50 :
51 : #define CHECK_NULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"CLTool " + word + "\")");
52 :
53 2653 : void CLToolMain::cmd(const std::string& word,void*val) {
54 : if(false) {
55 2653 : } else if(word=="setArgc") {
56 828 : CHECK_NULL(val,word);
57 828 : argc=*static_cast<int*>(val);
58 1825 : } else if(word=="setArgv") {
59 828 : CHECK_NULL(val,word);
60 828 : char**v=static_cast<char**>(val);
61 828 : for(int i=0; i<argc; ++i) argv.push_back(string(v[i]));
62 997 : } else if(word=="setArgvLine") {
63 0 : CHECK_NULL(val,word);
64 0 : const char*v=static_cast<char*>(val);
65 0 : argv=Tools::getWords(v);
66 997 : } else if(word=="setIn") {
67 0 : CHECK_NULL(val,word);
68 0 : in=static_cast<FILE*>(val);
69 997 : } else if(word=="setOut") {
70 0 : CHECK_NULL(val,word);
71 0 : out=static_cast<FILE*>(val);
72 997 : } else if(word=="setMPIComm") {
73 169 : comm.Set_comm(val);
74 828 : } else if(word=="setMPIFComm") {
75 0 : comm.Set_fcomm(val);
76 828 : } else if(word=="run") {
77 828 : CHECK_NULL(val,word);
78 828 : argc=argv.size();
79 828 : char**v=new char* [argc];
80 6877 : for(int i=0; i<argc; ++i) {
81 6049 : v[i]=new char [argv[i].length()+1];
82 6049 : for(unsigned c=0; c<argv[i].length(); ++c) v[i][c]=argv[i][c];
83 6049 : v[i][argv[i].length()]=0;
84 : }
85 828 : int ret=run(argc,v,in,out,comm);
86 828 : for(int i=0; i<argc; ++i) delete [] v[i];
87 828 : delete [] v;
88 828 : *static_cast<int*>(val)=ret;
89 : } else {
90 0 : plumed_merror("cannot interpret cmd(\"CLTool " + word + "\"). check plumed developers manual to see the available commands.");
91 : }
92 2653 : }
93 :
94 : /**
95 : This is the entry point to the command line tools
96 : included in the plumed library.
97 : */
98 :
99 828 : int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc) {
100 : int i;
101 828 : bool printhelp=false;
102 :
103 828 : DLLoader dlloader;
104 :
105 1656 : string root=config::getPlumedRoot();
106 :
107 828 : bool standalone_executable=false;
108 :
109 : // Start parsing options
110 1656 : string prefix("");
111 1656 : string a("");
112 1487 : for(i=1; i<argc; i++) {
113 1487 : a=prefix+argv[i];
114 1487 : if(a.length()==0) continue;
115 1487 : if(a=="help" || a=="-h" || a=="--help") {
116 0 : printhelp=true;
117 0 : break;
118 1487 : } else if(a=="--has-mpi") {
119 0 : if(Communicator::initialized()) return 0;
120 0 : else return 1;
121 1487 : } else if(a=="--has-matheval") {
122 0 : return (config::hasMatheval()?0:1);
123 1487 : } else if(a=="--has-cregex") {
124 0 : return (config::hasCregex()?0:1);
125 1487 : } else if(a=="--has-dlopen") {
126 0 : return (config::hasDlopen()?0:1);
127 1487 : } else if(a=="--has-molfile") {
128 0 : return (config::hasMolfile()?0:1);
129 1487 : } else if(a=="--has-external-molfile") {
130 0 : return (config::hasExternalMolfile()?0:1);
131 1487 : } else if(a=="--has-zlib") {
132 0 : return (config::hasZlib()?0:1);
133 1487 : } else if(a=="--has-xdrfile") {
134 0 : return (config::hasXdrfile()?0:1);
135 1487 : } else if(a=="--is-installed") {
136 10 : return (config::isInstalled()?0:1);
137 1477 : } else if(a=="--no-mpi") {
138 : // this is ignored, as it is parsed in main
139 659 : if(i>1) {
140 0 : fprintf(stderr,"--no-mpi option can only be used as the first option");
141 0 : return 1;
142 : }
143 818 : } else if(a=="--mpi") {
144 : // this is ignored, as it is parsed in main
145 0 : if(i>1) {
146 0 : fprintf(stderr,"--mpi option can only be used as the first option");
147 0 : return 1;
148 : }
149 818 : } else if(a=="--standalone-executable") {
150 0 : standalone_executable=true;
151 818 : } else if(Tools::startWith(a,"--load=")) {
152 0 : a.erase(0,a.find("=")+1);
153 0 : prefix="";
154 0 : void *p=dlloader.load(a);
155 0 : if(!p) {
156 0 : fprintf(stderr,"ERROR: cannot load library %s\n",a.c_str());
157 0 : fprintf(stderr,"ERROR: %s\n",dlloader.error().c_str());
158 0 : return 1;
159 : }
160 818 : } else if(a=="--load") {
161 0 : prefix="--load=";
162 818 : } else if(a[0]=='-') {
163 0 : string msg="ERROR: Unknown option " +a;
164 0 : fprintf(stderr,"%s\n",msg.c_str());
165 0 : return 1;
166 818 : } else break;
167 : }
168 :
169 : // Check if plumedRoot/patches/ directory exists (as a further check)
170 818 : if(!standalone_executable) {
171 818 : vector<string> files=Tools::ls(root);
172 818 : if(find(files.begin(),files.end(),"patches")==files.end()) {
173 : string msg=
174 0 : "WARNING: I cannot find "+root+"/patches/ directory. Set PLUMED_ROOT or reinstall PLUMED\n\n";
175 0 : fprintf(stderr,"%s",msg.c_str());
176 818 : }
177 : }
178 :
179 : // Build list of available C++ tools:
180 1636 : vector<string> availableCxx=cltoolRegister().list();
181 : // Build list of available shell tools:
182 1636 : vector<string> availableShell;
183 818 : if(!standalone_executable) {
184 818 : vector<string> tmp;
185 818 : tmp=Tools::ls(string(root+"/scripts"));
186 6544 : for(unsigned j=0; j<tmp.size(); ++j) {
187 5726 : size_t ff=tmp[j].find(".sh");
188 5726 : if(ff==string::npos) tmp[j].erase();
189 4908 : else tmp[j].erase(ff);
190 : }
191 818 : for(unsigned j=0; j<tmp.size(); ++j) if(tmp[j].length()>0) availableShell.push_back(tmp[j]);
192 : }
193 :
194 818 : if(printhelp) {
195 : string msg=
196 : "Usage: plumed [options] [command] [command options]\n"
197 : " plumed [command] -h|--help: to print help for a specific command\n"
198 : "Options:\n"
199 : " [help|-h|--help] : to print this help\n"
200 : " [--is-installed] : fails if plumed is not installed\n"
201 : " [--has-mpi] : fails if plumed is running without MPI\n"
202 : " [--has-matheval] : fails if plumed is compiled without matheval\n"
203 : " [--has-dlopen] : fails if plumed is compiled without dlopen\n"
204 : " [--load LIB] : loads a shared object (typically a plugin library)\n"
205 : " [--standalone-executable] : tells plumed not to look for commands implemented as scripts\n"
206 0 : "Commands:\n";
207 0 : fprintf(out,"%s",msg.c_str());
208 0 : for(unsigned j=0; j<availableCxx.size(); ++j) {
209 0 : CLTool *cl=cltoolRegister().create(CLToolOptions(availableCxx[j]));
210 0 : plumed_assert(cl);
211 0 : string manual=availableCxx[j]+" : "+cl->description();
212 0 : delete cl;
213 0 : fprintf(out," plumed %s\n", manual.c_str());
214 0 : }
215 0 : for(unsigned j=0; j<availableShell.size(); ++j) {
216 0 : string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+availableShell[j]+".sh\" --description";
217 0 : FILE *fp=popen(cmd.c_str(),"r");
218 0 : string line,manual;
219 0 : while(Tools::getline(fp,line))manual+=line;
220 0 : pclose(fp);
221 0 : manual= availableShell[j]+" : "+manual;
222 0 : fprintf(out," plumed %s\n", manual.c_str());
223 0 : }
224 0 : return 0;
225 : }
226 818 : if(i==argc) {
227 0 : fprintf(out,"%s","Nothing to do. Use 'plumed help' for help\n");
228 0 : return 0;
229 : }
230 :
231 : // this is the command to be executed:
232 1636 : string command(argv[i]);
233 :
234 818 : if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()) {
235 724 : CLTool *cl=cltoolRegister().create(CLToolOptions(command));
236 724 : plumed_assert(cl);
237 : // Read the command line options (returns false if we are just printing help)
238 724 : if( !cl->readInput( argc-i,&argv[i],in,out ) ) { delete cl; return 0; }
239 724 : int ret=cl->main(in,out,pc);
240 724 : delete cl;
241 724 : return ret;
242 : }
243 :
244 94 : if(find(availableShell.begin(),availableShell.end(),command)!=availableShell.end()) {
245 94 : plumed_massert(in==stdin,"shell tools can only work on stdin");
246 94 : plumed_massert(out==stdout,"shell tools can only work on stdin");
247 94 : string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+command+".sh\"";
248 94 : for(int j=i+1; j<argc; j++) cmd+=string(" ")+argv[j];
249 94 : int r=system(cmd.c_str());
250 : // this is necessary since system seems to return numbers which are multiple
251 : // of 256. this would make the interpretation by the shell wrong
252 : // I just return 1 in case of failure and 0 in case of success
253 94 : if(r!=0) return 1;
254 94 : else return 0;
255 : }
256 :
257 0 : string msg="ERROR: unknown command " + command + ". Use 'plumed help' for help";
258 0 : fprintf(stderr,"%s\n",msg.c_str());
259 828 : return 1;
260 :
261 : }
262 2523 : }
|