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