source: Sophya/trunk/SophyaLib/SysTools/commander.cc@ 3616

Last change on this file since 3616 was 3615, checked in by cmv, 16 years ago

Modifs relatives a l'introduction de RandomGeneratorInterface + delete de srandgen.c, cmv 01/05/2009

File size: 67.2 KB
Line 
1#include "sopnamsp.h"
2#include "commander.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <ctype.h>
7#include <math.h>
8#include <signal.h>
9
10#include "strutil.h"
11#include "strutilxx.h"
12#include "cexpre.h"
13#include "rpneval.h"
14#include "srandgen.h"
15#include "zthread.h"
16
17
18namespace SOPHYA {
19
20//--------------------------------------------------
21// Pour ecrire une valeur double sous forme de string
22// sans perte de precision, et si possible de maniere
23// lisible (%g, sinon format adapte jusqu'a %.17e)
24static char cval_strbuff_[80];
25////1er essai binaire: char * cval_dble2str(double v)
26////1er essai binaire: {
27////1er essai binaire: char* str1 = cval_strbuff_;
28////1er essai binaire: sprintf(str1,"%g",v);
29////1er essai binaire: char* str2 = cval_strbuff_+32;
30////1er essai binaire: sprintf(str2,"%.17e",v);
31////1er essai binaire: double x1 = atof(str1);
32////1er essai binaire: double x2 = atof(str2);
33////1er essai binaire: double fx = fabs(v);
34////1er essai binaire: if (fx>0. && fabs(x2-x1)/fx>1e-12) return str2;
35////1er essai binaire: else return str1;
36////1er essai binaire: }
37char * cval_dble2str(double v)
38{
39 char* strgood = cval_strbuff_; sprintf(strgood,"%g",v);
40 char* strfull = cval_strbuff_+32; sprintf(strfull,"%.17e",v);
41 char* strform = cval_strbuff_+64;
42 double x1 = atof(strfull), fx = fabs(x1);
43 if(fx>0.) {
44 for(int i=7;i<=17;i+=2) { // increment de 2 pour aller + vite
45 double x2 = atof(strgood);
46 if(fabs(x2-x1)/fx<1.e-16) break;
47 sprintf(strform,"%%.%de",i);
48 sprintf(strgood,strform,v);
49 }
50 }
51 return strgood;
52}
53//--------------------------------------------------
54
55// Differents code de retour specifiques
56#define CMD_RETURN_RC 99900
57#define CMD_BREAK_RC 99990
58#define CMD_BREAKEXE_RC 99999
59
60// ------------------------------------------------------------
61// Bloc de commandes (Foreach, ...)
62// Classe CommanderBloc
63// ------------------------------------------------------------
64/*!
65 \internal
66 \class SOPHYA::CommanderBloc
67 \ingroup SysTools
68 Class for internal use by class Commander to handle loops
69*/
70class CommanderBloc {
71public:
72 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat,
73 BT_ForeachLineInFile };
74
75 CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args);
76 ~CommanderBloc();
77 inline CommanderBloc* Parent() { return(parent); }
78 inline bool CheckOK() { return blkok; }
79 inline void AddLine(string& line)
80 { lines.push_back(line); bloclineid.push_back(lines.size()); }
81 void AddLine(string& line, string& kw);
82 inline void AddBloc(CommanderBloc* blk)
83 { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
84
85 // Execution complete du bloc (boucle)
86 int Execute();
87 // Execution pour un element de bloc
88 int ExecuteOnce(string& lvv);
89
90 inline int& TestLevel() { return testlevel; }
91 inline int& LoopLevel() { return looplevel; }
92 inline bool CheckBloc()
93 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
94
95protected:
96 Commander* _commander;
97 CommanderBloc* parent;
98 bool blkok; // true -> block OK
99 BType typ; // foreach , integer loop, float loop, test
100 string varname;
101 string filename; // forinfile bloc
102 vector<string> strlist;
103 vector<string> lines;
104 vector<CommanderBloc *> blocs;
105 vector<int> bloclineid;
106 int i1,i2,di;
107 float f1,f2,df;
108 int testlevel; // niveau d'imbrication des if
109 int looplevel; // niveau d'imbrication des for/foreach
110 bool scrdef; // true -> commande defscript ds for/foreach
111};
112
113/* --Methode-- */
114CommanderBloc::CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args)
115{
116_commander = piac;
117parent = par;
118blkok = false;
119typ = BT_None;
120i1 = 0; i2 = -1; di = 1;
121f1 = 0.; f2 = -1.; df = 1.;
122testlevel = looplevel = 0;
123scrdef = false;
124
125if ((args.size() < 2) || !isalpha((int)args[0][0]) ) return;
126if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return;
127if (!piac->CheckVarName(args[0])) return;
128varname = args[0];
129
130//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
131if (kw == "forinfile") {
132 filename = args[1];
133 typ = BT_ForeachLineInFile;
134 blkok = true;
135}
136else if (kw == "foreach" ) { // This is a foreach bloc with string list
137 if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
138 // foreach varname ( w1 w2 w3 ... )
139 for(unsigned int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
140 }
141 else {
142 // foreach varname WordVectorName
143 if (!piac->GetVar(args[1], strlist)) return;
144 }
145 if (strlist.size() < 1) return;
146 typ = BT_ForeachList;
147 blkok = true;
148}
149else { // This is an integer or float loop
150 size_t l = args[1].length();
151 size_t p = args[1].find(':');
152 size_t pp = args[1].find('.');
153 bool fl = (pp < l) ? true : false; // Float loop or integer loop
154 if (p >= l) return; // Syntaxe error
155 string a1 = args[1].substr(0, p);
156 string aa = args[1].substr(p+1);
157 p = aa.find(':');
158 string a2, a3;
159 bool hasa3 = false;
160 if (p < aa.length() ) {
161 a2 = aa.substr(0,p);
162 a3 = aa.substr(p+1);
163 hasa3 = true;
164 }
165 else a2 = aa;
166 if (fl) {
167 typ = BT_ForeachFloat;
168 blkok = true;
169 f1 = atof(a1.c_str());
170 f2 = atof(a2.c_str());
171 if (hasa3) df = atof(a3.c_str());
172 else df = 1.;
173 }
174 else {
175 typ = BT_ForeachInt;
176 blkok = true;
177 i1 = atoi(a1.c_str());
178 i2 = atoi(a2.c_str());
179 if (hasa3) di = atoi(a3.c_str());
180 else di = 1;
181 }
182 }
183}
184
185/* --Methode-- */
186CommanderBloc::~CommanderBloc()
187{
188for(unsigned int k=0; k<blocs.size(); k++) delete blocs[k];
189}
190
191/* --Methode-- */
192void CommanderBloc::AddLine(string& line, string& kw)
193{
194 AddLine(line);
195 if (kw == "if") testlevel++;
196 else if (kw == "endif") testlevel--;
197 else if ((kw == "for") || (kw == "foreach")) looplevel++;
198 else if (kw == "end") looplevel--;
199 else if (kw == "defscript") scrdef = true;
200}
201
202/* --Methode-- */
203int CommanderBloc::Execute()
204{
205int k=0;
206char buff[32];
207int rcc = 0;
208
209int mxloop = _commander->GetMaxLoopLimit();
210
211if (typ == BT_ForeachLineInFile) { // foreach line in file loop
212 ifstream is(filename.c_str());
213 string line;
214 while (!is.eof()) {
215 rcc = 0;
216 line = "";
217 getline(is,line);
218 if (is.good() || is.eof()) {
219 rcc = ExecuteOnce(line);
220 if (rcc == CMD_BREAKEXE_RC) return rcc;
221 else if (rcc == CMD_BREAK_RC) break;
222 }
223 }
224}
225else if (typ == BT_ForeachList) { // foreach string loop
226 for(unsigned int k=0; k<strlist.size(); k++) {
227 rcc = ExecuteOnce(strlist[k]);
228 if (rcc == CMD_BREAKEXE_RC) return rcc;
229 else if (rcc == CMD_BREAK_RC) break;
230 }
231}
232else if (typ == BT_ForeachInt) { // Integer loop
233 for(int i=i1; i<i2; i+=di) {
234 k++;
235 if ((mxloop>0) && (k > mxloop)) {
236 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
237 break;
238 }
239 sprintf(buff, "%d", i);
240 string lvv = buff;
241 rcc = ExecuteOnce(lvv);
242 if (rcc == CMD_BREAKEXE_RC) return rcc;
243 else if (rcc == CMD_BREAK_RC) break;
244 }
245}
246else if (typ == BT_ForeachFloat) { // float loop
247 for(double f=f1; f<f2; f+=df) {
248 k++;
249 if ((mxloop>0) && (k > mxloop)) {
250 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
251 break;
252 }
253 string lvv = cval_dble2str(f);
254 rcc = ExecuteOnce(lvv);
255 if (rcc == CMD_BREAKEXE_RC) return rcc;
256 else if (rcc == CMD_BREAK_RC) break;
257 }
258}
259return(rcc);
260}
261
262/* --Methode-- */
263int CommanderBloc::ExecuteOnce(string& lvv)
264{
265 unsigned int kj=0;
266 int kk=0;
267 int rcc = 0;
268 _commander->SetVar(varname, lvv);
269 for(kj=0; kj<bloclineid.size(); kj++) {
270 rcc = 0;
271 kk = bloclineid[kj];
272 if (kk > 0)
273 rcc = _commander->Interpret(lines[kk-1]);
274 else
275 rcc = blocs[-kk-1]->Execute();
276 if (rcc == CMD_BREAKEXE_RC) return (rcc);
277 if (rcc == CMD_BREAK_RC) break;
278 }
279 return rcc;
280}
281
282// ---------------------------------------------------------------
283// Classe CommanderScript
284// Definition et execution d'un script de Commander
285// script : Une liste de commande Commander - Lors de l'execution,
286// les variables-argument $# $0 $1 sont definies.
287// ---------------------------------------------------------------
288
289/*!
290 \internal
291 \class SOPHYA::CommanderScript
292 \ingroup SysTools
293 Class for internal use by class Commander to handle functions
294 or scripts
295*/
296
297class CommanderScript {
298public:
299 CommanderScript(Commander* piac, string const& name, string const& comm);
300 virtual ~CommanderScript();
301
302 void AddLine(string& line, string& kw);
303 virtual int Execute(vector<string>& args);
304
305 inline string& Name() { return mName; }
306 inline string& Comment() { return mComm; }
307 inline int& TestLevel() { return testlevel; }
308 inline int& LoopLevel() { return looplevel; }
309 inline bool CheckScript()
310 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)&&fgok); }
311
312protected:
313 Commander* _commander;
314 string mName;
315 string mComm;
316 vector<string> lines;
317 int testlevel; // niveau d'imbrication des if
318 int looplevel; // niveau d'imbrication des for/foreach
319 bool scrdef; // true -> commande defscript ds for/foreach
320 bool fgok; // Script name OK
321
322};
323
324/* --Methode-- */
325CommanderScript::CommanderScript(Commander* piac, string const& name,
326 string const& comm)
327{
328_commander = piac;
329testlevel = looplevel = 0;
330scrdef = false;
331mName = name;
332if (!isalpha(name[0])) fgok = false;
333else fgok = true;
334mComm = comm;
335}
336
337/* --Methode-- */
338CommanderScript::~CommanderScript()
339{
340}
341
342/* --Methode-- */
343void CommanderScript::AddLine(string& line, string& kw)
344{
345 if (kw == "if") testlevel++;
346 else if (kw == "endif") testlevel--;
347 else if ((kw == "for") || (kw == "foreach")) looplevel++;
348 else if (kw == "end") looplevel--;
349 else if (kw == "defscript") scrdef = true;
350 lines.push_back(line);
351}
352
353/* --Methode-- */
354int CommanderScript::Execute(vector<string>& args)
355{
356 int rcc=-2;
357 if (!CheckScript()) return(-1);
358 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
359 for(unsigned int k=0; k<lines.size(); k++) {
360 rcc = _commander->Interpret(lines[k]);
361 if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break;
362 }
363 return(rcc);
364}
365
366
367// ------------------------------------------------------------
368// Classe CommandExeThr
369// ------------------------------------------------------------
370/*!
371 \internal
372 \class SOPHYA::CommandExeThr
373 \ingroup SysTools
374 Class for internal use by class Commander for command execution in separate threads.
375 The command execution is carried in method run() which has its own exception handling bloc.
376*/
377class CommandExeThr : public ZThread {
378public:
379 CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
380 vector<string>& args, string& toks);
381 virtual void run();
382 inline uint_8 Id() { return _id; }
383 inline bool IfDone() { return _fgdone; }
384 inline string& Tokens() { return _toks; }
385 inline string& Keyword() { return _keyw; }
386protected:
387 uint_8 _id;
388 CmdExecutor * _cmdex;
389 string _keyw, _toks;
390 vector<string> _args;
391 bool _fgdone;
392};
393
394/* --Methode-- */
395CommandExeThr::CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
396 vector<string>& args, string& toks)
397{
398 _id = id;
399 _cmdex = cmdex;
400 _keyw = keyw;
401 _args = args;
402 _args.erase(_args.end()-1);
403 _toks = toks;
404 for(size_t k=_toks.size()-1; k>0; k--)
405 if (_toks[k] == '&') { _toks[k] = ' '; break; }
406 _fgdone = false;
407}
408
409/* --Methode-- */
410void CommandExeThr::run()
411{
412 int rc = 0;
413 try {
414 rc = _cmdex->Execute(_keyw, _args, _toks);
415 }
416 catch (PThrowable& exc) {
417 cout << "CommandExeThr::run() Catched Exception Msg()= "
418 << exc.Msg() << endl;
419 rc = -77;
420 }
421 catch (std::exception& sex) {
422 cout << "CommandExeThr::run() Catched std::exception what()= "
423 << sex.what() << endl;
424 rc = -78;
425 }
426 catch (...) {
427 cout << "CommandExeThr::run() Catched unknown (...) exception " << endl;
428 rc = -79;
429 }
430 _fgdone = true;
431 setRC(rc);
432}
433
434// ------------------------------------------------------------
435// Classe Commander
436// ------------------------------------------------------------
437typedef void (* DlModuleInitEndFunction) ();
438
439/*!
440 \class Commander
441 \ingroup SysTools
442 \brief Simple command interpreter
443
444 This Simple command interpreter with c-shell like syntax
445 can be used to add scripting capabilities
446 to applications.
447
448 Although the interpreter has many limitations compared to
449 c-shell, or Tcl , it provides some interesting possibilities:
450
451 - Extended arithmetic operations (c-like and RPN)
452 - Simple and vector variables
453 - Script definition
454 - Command execution in separate threads
455 - Dynamic Load
456
457 \sa CmdExecutor CExpressionEvaluator RPNExpressionEvaluator
458
459 Usage example:
460 \code
461 #include "commander.h"
462 ...
463 Commander cmd;
464 char* ss[3] = {"foreach f ( AA bbb CCCC ddddd )", "echo $f" , "end"};
465 for(int k=0; k<3; k++) {
466 string line = ss[k];
467 cmd.Interpret(line);
468 }
469 \endcode
470*/
471
472#define _MAGENTA_ 1
473
474static Commander* cur_commander = NULL;
475/* --Methode-- */
476/*!
477 \brief Constructor. Initializes variable list and copies \c history.pic to \c hisold.pic
478 if \b fgsigstop == true , calls ZThread::ActivateExitOnSignal()
479*/
480Commander::Commander(bool fgsigzt)
481{
482system("cp history.pic hisold.pic");
483hist.open("history.pic");
484histon = true;
485trace = false; timing = false;
486gltimer = NULL;
487felevel = 0;
488
489mulinecmd = "";
490mulinefg = false;
491spromptmul = "Cmd> ";
492SetCurrentPrompt(spromptmul);
493SetDefaultPrompt(spromptmul);
494curscript = NULL;
495
496_xstatus = 0;
497 _retstr = "";
498
499// Controle du flot d'execution
500 fgexebrk = false;
501
502CmdBlks.push(NULL);
503list<char> xtx;
504TestsStack.push(xtx);
505curtestresult = true;
506
507// Pour la numerotation et l'identification des threads
508ThrId = 0;
509
510// Numero de help-groupe courant - Le premier groupe ajoute aura un gid = 1
511// gid = 0 n'existe pas : c'est le groupe de toutes les commandes
512cmdgrpid = 0;
513
514string grp = "Commander";
515string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
516AddHelpGroup(grp, gdesc);
517
518string kw = "Commander";
519string usage;
520usage = ">>> (Commander) Interpreter's keywords : \n";
521usage += " > set varname string # To set a variable, $varname \n";
522usage += " > unset varname # clear variable definition \n";
523usage += " > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n";
524usage += " > varname = ArithmeticExpression # C-like Expression evaluation \n";
525usage += " > varname = 'String' # Set variable vname \n";
526usage += " > var2words varname wordvarname [sep] # to break varname into words \n";
527usage += " > echo string # output string \n";
528usage += " > echo2file filename string # Append the string to the specified file \n";
529usage += " > alias name string # define a command alias \n";
530usage += " > foreach varname ( string-list ) # Loop \n";
531usage += " > for varname i1:i2[:di] # Integer loop \n";
532usage += " > for varname f1:f2[:df] # Float loop \n";
533usage += " > forinfile varname FileName # Loop over lines in file \n";
534usage += " > end # end loops \n";
535usage += " > if ( test ) then # Conditional test : a == != < > <= >= b \n";
536usage += " > else # Conditional \n";
537usage += " > endif # End of conditional if bloc \n";
538usage += " > break # Delete (clears) all test and loop blocs \n";
539usage += " > return # Stops command execution from a file \n";
540usage += " > defscript endscript # Command script definition \n";
541usage += " > listvars # List of variable names and values \n";
542usage += " > listalias # List of alias names and values \n";
543usage += " > listcommands # List of all known commands \n";
544usage += " > listscripts # List of all known scripts \n";
545usage += " > clearcript # Clear a script definition \n";
546usage += " > thrlist # List of command execution threads (& as the last character) \n";
547usage += " > clearthrlist # Removes finished threads from the list \n";
548usage += " > killthr Id # Try to stop a given thread (ThrId=id) by sending SIGUSR1 \n";
549usage += " > cancelthr Id # Try to cancel a given thread (ThrId=id) \n";
550usage += " > waitthr # Waits until all active threads have finished (join()) \n";
551usage += " > exec filename # Execute commands from file \n";
552usage += " > help <command_name> # <command_name> usage info \n";
553usage += " > sleep nsec # sleep nsec seconds \n";
554usage += " > readstdin varname # reads a line from stdin into $varname \n";
555usage += " > timingon timingoff traceon traceoff \n";
556RegisterHelp(kw, usage, grp);
557
558kw = "RPNEvaluator";
559usage = " Reverse Polish Notation (HP calculator like) expression evaluation \n";
560usage += " >> Stack: \n";
561usage += " ... (4) (3) z=(2) y=(1) x=(0)=Stack.Top() \n";
562usage += " >> Examples: \n";
563usage += " - sin(PI/6): pi 6 / sin \n";
564usage += " - 1*2*...*5: 1 2 3 4 5 product \n";
565usage += " - x=x+y: x = $x $y * \n";
566usage += " >>> Stack operations : \n";
567usage += " print x<>y pop push (duplicate x) \n";
568usage += " >>> Constants (Cst pushed to stack): \n";
569usage += " pi e \n";
570usage += " >>> Arithmetic operators (x,y) --> x@y \n";
571usage += " + - * / % ( (int)y % (int)x )\n";
572usage += " >>> F(X): x --> F(x) \n";
573usage += " chs sqrt sq log log10 exp \n";
574usage += " fabs floor ceil \n";
575usage += " cos sin tan acos asin atan deg2rad rad2deg \n";
576usage += " >>> F(X,Y): (x,y) --> F(x,y) \n";
577usage += " pow atan2 \n";
578usage += " >>> F(): random number generators \n";
579usage += " rand (flat 0..1) norand (normal/gaussian) \n";
580usage += " >>> Stack sum/product/mean/sigma/sigma^2 \n";
581usage += " sum product mean sigma sigma2 sigmean (y->sigma x->mean) \n";
582RegisterHelp(kw, usage, grp);
583
584kw = "autoiniranf";
585usage = "> Automatic random number generator initialisation\n";
586usage += " by AutoInitRand(int lp) \n";
587usage += " Usage: autoiniranf";
588RegisterCommand(kw, usage, NULL, grp);
589
590kw = "CExpEvaluator";
591usage = "> Evaluation of C-like expression (used in V = C-like-Expression) \n";
592usage += " >>> Arithmetic operators, parenthesis ( + - * / ) \n";
593usage += " >>> Functions : sqrt fabs floor hypot \n";
594usage += " ... exp log log10 pow ; sinh cosh tanh \n";
595usage += " ... sin cos tan asin acos atan atan2 \n";
596usage += " ... rand01() randpm1() gaurand() \n";
597usage += " >>> Constants : Pi = M_PI E = M_E \n";
598usage += " Example: x = 5.*(2.+sin(0.3*Pi))";
599RegisterCommand(kw, usage, NULL, grp);
600
601kw = "shell execute";
602usage = "> shell command_string # Execute shell command\n";
603usage += "> cshell command_string # Execute cshell command\n";
604usage += "---Examples:\n";
605usage += " > shell ls\n";
606usage += " > cshell echo '$LD_LIBRARY_PATH'; map2cl -h; ls\n";
607usage += " > shell myfile.csh [arg1] [arg2] [...]\n";
608usage += " (where the first line of \"myfile.csh\" is \"#!/bin/csh\")\n";
609RegisterCommand(kw, usage, NULL, grp);
610
611
612AddInterpreter(this);
613curcmdi = this;
614if (fgsigzt) ZThread::ActivateExitOnSignal(SIGUSR1);
615}
616
617/* --Methode-- */
618Commander::~Commander()
619{
620hist.close();
621if (gltimer) { delete gltimer; gltimer = NULL; }
622Modmap::iterator it;
623for(it = modmap.begin(); it != modmap.end(); it++) {
624 string name = (*it).first + "_end";
625 DlModuleInitEndFunction fend = (*it).second->GetFunction(name);
626 if (fend) fend();
627 delete (*it).second;
628 }
629
630for(ScriptList::iterator sit = mScripts.begin();
631 sit != mScripts.end(); sit++) delete (*sit).second;
632
633if (cur_commander == this) cur_commander = NULL;
634}
635
636/* --Methode-- */
637Commander* Commander::GetInterpreter()
638{
639return(cur_commander);
640}
641
642/* --Methode-- */
643//! Returns the string \c Commander as the interpreter's name.
644string Commander::Name()
645{
646return("Commander");
647}
648
649/* --Methode-- */
650//! Add the \b grp help group with description \b desc.
651void Commander::AddHelpGroup(string& grp, string& desc)
652{
653 int gid;
654 CheckHelpGrp(grp, gid, desc);
655}
656
657/* --Methode-- */
658/*!
659 \brief Register a command executor associated with a given keyword.
660 \param keyw : keyword identifying the command
661 \param usage : the command help and usage information
662 \param ce : CmdExecutor pointer for this a command. The same object can be registered
663 multiple time for different commands.
664 \param grp : The help group corresponding to this command.
665*/
666void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
667{
668if (!ce) {
669 RegisterHelp(keyw, usage, grp);
670 return;
671 }
672int gid;
673CheckHelpGrp(grp,gid);
674cmdex cme;
675cme.group = gid;
676cme.us = usage;
677cme.cex = ce;
678cmdexmap[keyw] = cme;
679}
680
681/* --Methode-- */
682/*!
683 \brief Register a help text.
684 \param keyw : help keyword
685 \param usage : help text
686 \param grp : help group
687*/
688void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
689{
690int gid;
691CheckHelpGrp(grp,gid);
692cmdex cme;
693cme.group = gid;
694cme.us = usage;
695cme.cex = NULL;
696helpexmap[keyw] = cme;
697}
698
699/* --Methode-- */
700bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
701{
702gid = 0;
703CmdHGroup::iterator it = cmdhgrp.find(grp);
704if (it == cmdhgrp.end()) {
705 cmdgrpid++; gid = cmdgrpid;
706 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
707 cmdhgrp[grp] = hgs;
708 return true;
709 }
710else {
711 if (desc.length() > 0) (*it).second.desc = desc;
712 gid = (*it).second.gid;
713 return false;
714}
715}
716
717
718/* --Methode-- */
719/*!
720 \brief Dynamic loader for modules
721
722 A module is a shared library extending the application functionalities.
723 Typically, a module adds new commands to the interpreter. Once loaded,
724 the module is activated (initialized) by calling a function with the
725 name \b modulename_init . This function should be declared extern C
726 to avoid C++ name mangling. A cleanup function \b modulename_end
727 is called by the Commander destructor.
728
729 \param fnameso : Shared library name containing the module functions
730 and classes.
731 \param name : Module name. This string is used to form module
732 initializer and cleanup function name \c name_init \c name_end
733*/
734void Commander::LoadModule(string& fnameso, string& name)
735{
736PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false);
737if (dynlink == NULL) {
738 cerr << "Commander/LoadModule_Error: Pb opening SO " << fnameso << endl;
739 return;
740 }
741string fname = name + "_init";
742DlModuleInitEndFunction finit = dynlink->GetFunction(fname);
743if (!finit) {
744 cerr << "Commander/LoadModule_Error: Pb linking " << fname << endl;
745 return;
746 }
747cout << "Commander/LoadModule_Info: Initialisation module" << name
748 << " " << fname << "() ..." << endl;
749finit();
750modmap[name] = dynlink;
751return;
752}
753
754/* --Methode-- */
755//! Declare a new interpreter
756void Commander::AddInterpreter(CmdInterpreter * cl)
757{
758if (!cl) return;
759interpmap[cl->Name()] = cl;}
760
761/* --Methode-- */
762//! Select an interpreter by its name as the current interpreter.
763void Commander::SelInterpreter(string& name)
764{
765InterpMap::iterator it = interpmap.find(name);
766if (it == interpmap.end()) return;
767curcmdi = (*it).second;
768}
769
770
771
772/* Fonction */
773static string GetStringFrStdin(Commander* piac)
774{
775char buff[128];
776fgets(buff, 128, stdin);
777buff[127] = '\0';
778return((string)buff);
779}
780
781/* --Methode-- */
782/*!
783 \brief Method which has to be invoked to interpret a given command line or string.
784*/
785int Commander::Interpret(string& s)
786{
787int rc = 0;
788ScriptList::iterator sit;
789
790// Si le flag d'arret d'execution a ete positionne on returne avec le code
791// de BREAKEXECUTION
792if (fgexebrk) {
793 cout << " ===> Commander::Interpret() - STOP Execution (CMD_BREAKEXE_RC)" << endl;
794 fgexebrk = false; return CMD_BREAKEXE_RC;
795}
796
797// On saute de commandes vides
798size_t l;
799l = s.length();
800if (!mulinefg && (l < 1)) return(0);
801
802// On enregistre les commandes
803if (histon) hist << s << endl;
804
805if (s[0] == '#') return(0); // si c'est un commentaire
806
807// Logique de gestion des lignes suite
808// un \ en derniere position indique la presence d'une ligne suite
809size_t lnb = s.find_last_not_of(' ');
810if (lnb >= l) return(0); // il n'y a que des blancs
811if (s[lnb] == '\\' ) { // Lignes suite ...
812 mulinecmd += s.substr(0,lnb);
813 if (!mulinefg) {
814 spromptmul = GetCurrentPrompt();
815 SetCurrentPrompt("...? ");
816 mulinefg = true;
817 }
818 return(0);
819}
820
821if (mulinefg) { // Il y avait des lignes suite
822 s = mulinecmd + s;
823 l = s.length();
824 mulinecmd = "";
825 mulinefg = false;
826 SetCurrentPrompt(spromptmul);
827}
828
829// Removing leading blanks
830size_t p,q;
831
832// On enleve le dernier caractere, si celui-ci est \n
833if (s[l-1] == '\n') s[l-1] = '\0';
834p=s.find_first_not_of(" \t");
835if (p < l) s = s.substr(p);
836// >>>> Substitution d'alias (1er mot)
837CmdStrList::iterator it;
838p = 0;
839q = s.find_first_of(" \t");
840l = s.length();
841string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p);
842it = mAliases.find(w1);
843if (it != mAliases.end()) {
844 s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ;
845 l = s.length();
846 p=s.find_first_not_of(" \t");
847 if (p < l) s = s.substr(p);
848 p = 0;
849 q = s.find_first_of(" ");
850 }
851
852// >>>> Separating keyword
853string toks,kw;
854if (q < l)
855 { kw = s.substr(p,q-p); toks = s.substr(q, l-q); }
856else { kw = s.substr(p,l-p); toks = ""; }
857
858// les mot-cle end else endif doivent etre le seul mot de la ligne
859if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
860 size_t ltk = toks.length();
861 if (toks.find_first_not_of(" \t") < ltk) {
862 cerr << "Commander::Interpret()/syntax error near end else endif endscript \n"
863 << "line: " << s << endl;
864 _xstatus = 91;
865 return(91);
866 }
867}
868
869// On verifie si on est en train de definir un script
870if (curscript) {
871 if (kw == "endscript") {
872 if (curscript->CheckScript()) {
873 sit = mScripts.find(curscript->Name());
874 if (sit != mScripts.end()) {
875 cout << "Commander::Interpret() replacing script "
876 << curscript->Name() << endl;
877 CommanderScript* scr = mScripts[curscript->Name()];
878 mScripts.erase(sit);
879 delete scr;
880 }
881 cout << "Commander::Interpret() Script " << curscript->Name()
882 << " defined successfully" << endl;
883 mScripts[curscript->Name()] = curscript;
884 SetCurrentPrompt("Cmd> ");
885 curscript = NULL;
886 _xstatus = 0;
887 return(0);
888 }
889 else {
890 cout << "Commander::Interpret() Error in Script " << curscript->Name()
891 << " definition " << endl;
892 SetCurrentPrompt("Cmd> ");
893 curscript = NULL;
894 _xstatus = 92;
895 return(92);
896 }
897 }
898 else curscript->AddLine(s, kw);
899 _xstatus = 0;
900 return(0);
901}
902// On verifie si nous sommes dans un bloc (for , foreach)
903if (CmdBlks.top() != NULL) { // On est dans un bloc
904 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel++;
905 else if (kw == "end") felevel--;
906
907 int rcbex = 0;
908 if (felevel == 0) { // Il faut executer le bloc
909 CommanderBloc* curb = CmdBlks.top();
910 CmdBlks.top() = curb->Parent();
911 SetCurrentPrompt("Cmd> ");
912 if (!curb->CheckBloc()) {
913 cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
914 << " within for/foreach/forinfile bloc ! " << endl;
915 delete curb;
916 _xstatus = 93;
917 return(93);
918 }
919 // cout << " *DBG* Executing bloc " << endl;
920 bool ohv = histon;
921 histon = false;
922 if (curtestresult) {
923 // We push also CommanderBloc and testresult on the stack
924 CmdBlks.push(NULL);
925 list<char> xtx;
926 TestsStack.push(xtx);
927 rcbex = curb->Execute();
928 // And CommanderBloc and TestResult from the corresponding stacks
929 PopStack(false);
930 }
931 SetCurrentPrompt(defprompt);
932 delete curb;
933 histon = ohv;
934 }
935 else CmdBlks.top()->AddLine(s, kw);
936 _xstatus = rcbex;
937 return(rcbex);
938}
939else if (kw == "end") {
940 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
941 << "line: " << s << endl;
942 _xstatus = 94;
943 return(94);
944}
945
946// Sommes-nous dans un bloc de test if then else
947if (TestsStack.top().size() > 0) { // Nous sommes ds un bloc if
948 if (kw == "else") {
949 if ((*tresit) & 2) {
950 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
951 << "line: " << s << endl;
952 _xstatus = 95;
953 return(95);
954 }
955 else {
956 const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
957 if ((*tresit)&1) curtestresult = false;
958 SetCurrentPrompt(npr);
959 (*tresit) |= 2;
960 _xstatus = 0;
961 return(0);
962 }
963 }
964 else if (kw == "endif") {
965 list<char>::iterator dbit = tresit;
966 tresit--;
967 TestsStack.top().erase(dbit);
968 const char * npr = "Cmd> ";
969 if (TestsStack.top().size() > 1) {
970 curtestresult = true;
971 list<char>::iterator it;
972 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
973 // Si on n'est pas ds le else et le if est faux
974 if ( !((*it)&2) && !((*it)&1) ) curtestresult = false;
975 // Si on est ds else et le if etait vrai !
976 if ( ((*it)&2) && ((*it)&1) ) curtestresult = false;
977 if (!curtestresult) break;
978 }
979
980 if (!((*tresit)&2))
981 npr = ((*tresit)&1) ? "if-T> " : "if-F> ";
982 else
983 npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
984 }
985 else curtestresult = true;
986 SetCurrentPrompt(npr);
987 _xstatus = 0;
988 return(0);
989 }
990}
991else if ((kw == "else") || (kw == "endif")) {
992 cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
993 << "line: " << s << endl;
994 _xstatus = 91;
995 return(91);
996}
997
998bool fgcont = true;
999if (TestsStack.top().size() > 0) { // Resultat de if ou else
1000 list<char>::iterator it;
1001 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
1002 // Si on n'est pas ds le else et le if est faux
1003 if ( !((*it)&2) && !((*it)&1) ) fgcont = false;
1004 // Si on est ds else et le if etait vrai !
1005 if ( ((*it)&2) && ((*it)&1) ) fgcont = false;
1006 if (!fgcont) break;
1007 }
1008}
1009
1010if ((!fgcont) && (kw != "if")) {
1011 _xstatus = 0;
1012 return(0);
1013}
1014
1015
1016// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
1017if (kw == "break") return CMD_BREAK_RC;
1018else if (kw == "return") {
1019 _retstr = toks;
1020 return CMD_RETURN_RC;
1021}
1022
1023// Nous ne sommes donc pas dans un bloc .... Substitution de variables
1024string s2;
1025int rcs ;
1026
1027rcs = SubstituteVars(s, s2);
1028if (rcs) {
1029 cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n"
1030 << "line: " << s << endl;
1031 _xstatus = 99;
1032 return(99);
1033}
1034// >>>> Separating keyword and tokens
1035vector<string> tokens;
1036vector<bool> qottoks;
1037/* decoupage en mots */
1038LineToWords(s2, kw, tokens, qottoks, toks, true);
1039
1040// Si c'est un for/foreach, on cree un nouveau bloc
1041if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
1042 // cout << " *DBG* We got a foreach... " << endl;
1043 CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens);
1044 if (!bloc->CheckOK()) {
1045 cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl;
1046 delete bloc;
1047 _xstatus = 91;
1048 return(91);
1049 }
1050 felevel++;
1051 if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc);
1052 else SetCurrentPrompt("for...> ");
1053 CmdBlks.top() = bloc;
1054 // cout << " *DBG* New Bloc created ... " << endl;
1055 return(0);
1056 }
1057else if (kw == "if") { // Un test if
1058 bool restst = true;
1059 int rct = EvaluateTest(tokens, s, restst);
1060 if (rct) {
1061 cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl;
1062 _xstatus = 91;
1063 return(91);
1064 }
1065 char res_tst = (restst) ? 1 : 0;
1066 TestsStack.top().push_back(res_tst);
1067 if (TestsStack.top().size() == 1) tresit = TestsStack.top().begin();
1068 else tresit++;
1069 const char * npr = (restst) ? "if-T> " : "if-F> ";
1070 SetCurrentPrompt(npr);
1071}
1072else if ((tokens.size() > 0) && (tokens[0] == "=")) {
1073 // x = Expression
1074 if (qottoks[1]) { // decodage sous forme de chaine
1075 SetVariable(kw, tokens[1]);
1076 }
1077 else {
1078 try {
1079 double res = 0.;
1080 if (tokens.size() > 2) {
1081 string sex = tokens[1];
1082 for(unsigned int js=2; js<tokens.size(); js++) sex += tokens[js];
1083 CExpressionEvaluator cex(sex);
1084 res = cex.Value();
1085 }
1086 else {
1087 CExpressionEvaluator cex(tokens[1]);
1088 res = cex.Value();
1089 }
1090 string vv = cval_dble2str(res);
1091 SetVariable(kw, vv);
1092 }
1093 catch (CExprException& cexerr) {
1094 cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s
1095 << " \n Msg=" << cexerr.Msg() << endl;
1096 _xstatus = 98;
1097 return(98);
1098 }
1099 }
1100}
1101else if (kw == "defscript") { // definition de script
1102 if (tokens.size() > 0) {
1103 if (tokens.size() < 2) tokens.push_back("");
1104 curscript = new CommanderScript(this, tokens[0], tokens[1]);
1105 SetCurrentPrompt("Script...> ");
1106 return(0);
1107 }
1108 else {
1109 cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl;
1110 _xstatus = 91;
1111 return(91);
1112 }
1113}
1114else {
1115 // Si c'est le nom d'un script
1116 sit = mScripts.find(kw);
1117 if (sit != mScripts.end()) {
1118 bool ohv = histon;
1119 histon = false;
1120 tokens.insert(tokens.begin(), kw);
1121 PushStack(tokens);
1122 (*sit).second->Execute(tokens);
1123 PopStack(true);
1124 histon = ohv;
1125 }
1126 // Execution de commandes
1127 else rc = ExecuteCommandLine(kw, tokens, toks);
1128 _xstatus = rc;
1129 return(rc);
1130}
1131// cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
1132// for(int ii=0; ii<tokens.size(); ii++)
1133// cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
1134
1135return(0);
1136}
1137
1138//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
1139void Commander::StopExecution()
1140{
1141 fgexebrk = true;
1142}
1143
1144
1145/* --Methode-- */
1146int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
1147 vector<bool>& qottoks, string& toks, bool uq)
1148{
1149if (line.length() < 1) return(0);
1150int nw = 1;
1151size_t p = line.find_first_not_of(" ");
1152line = line.substr(p);
1153p = 0;
1154size_t q = line.find_first_of(" ");
1155size_t l = line.length();
1156
1157if (q < l)
1158 { kw = line.substr(p,q-p); toks = line.substr(q, l-q); }
1159else { kw = line.substr(p,l-p); toks = ""; }
1160
1161q = 0;
1162while (q < l) {
1163 bool swq = false; // true -> chaine delimite par ' ou "
1164 p = toks.find_first_not_of(" \t",q+1); // au debut d'un token
1165 if (p>=l) break;
1166 if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) {
1167 q = toks.find(toks[p],p+1);
1168 if (q>=l) {
1169 cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl;
1170 return(-1);
1171 }
1172 p++; swq = true;
1173 }
1174 else {
1175 q = toks.find_first_of(" \t",p); // la fin du token;
1176 }
1177 string token = toks.substr(p,q-p);
1178 tokens.push_back(token);
1179 qottoks.push_back(swq);
1180 nw++;
1181 }
1182
1183return(nw);
1184}
1185
1186/* --Methode-- */
1187int Commander::SubstituteVars(string & s, string & s2)
1188// Variable substitution
1189{
1190
1191int iarr = -1; // index d'element de tableau
1192size_t p,q,q2,q3,l;
1193bool fgvarapp = false; // Si true, VarApp en priorite
1194
1195s2="";
1196p = 0;
1197l = s.length();
1198string vn, vv;
1199while (p < l) {
1200 iarr = -1;
1201 fgvarapp = false;
1202 q = s.find('$',p);
1203 if (q > l) break;
1204 q2 = s.find('\'',p);
1205 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
1206 q2 = s.find('\'',q2+1);
1207 if (q2 >= l) {
1208 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
1209 return(1);
1210 }
1211 s2 += s.substr(p, q2-p+1);
1212 p = q2+1; continue;
1213 }
1214 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
1215 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
1216 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
1217 continue;
1218 }
1219 if (q >= l-1) {
1220 cerr << " Syntax error - line ending with $ !!! " << endl;
1221 return(2);
1222 }
1223 vn = "";
1224 if ( s[q+1] == '{' ) { // Variable in the form ${name}
1225 q2 = s.find('}',q+1);
1226 if (q2 >= l) {
1227 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
1228 return(3);
1229 }
1230 vn = s.substr(q+2,q2-q-2);
1231 q2++;
1232 fgvarapp = true;
1233 }
1234 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
1235 q2 = s.find(')',q+1);
1236 if (q2 >= l) {
1237 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
1238 return(3);
1239 }
1240 vn = s.substr(q+2,q2-q-2);
1241 q2++;
1242 }
1243 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
1244 q2 = s.find(']',q+1);
1245 if (q2 >= l) {
1246 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
1247 return(4);
1248 }
1249 vn = s.substr(q+2,q2-q-2);
1250 if (!Var2Str(vn, vv)) return(5);
1251 vn = vv;
1252 q2++;
1253 }
1254 else {
1255 if (s[q+1] == '#' ) q3 = q+2; // Variable in the form $#varname
1256 else q3 = q+1;
1257 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'<>^%=#@\\",q3);
1258 if (q2 > l) q2 = l;
1259 q3 = q2;
1260 vn = s.substr(q+1, q2-q-1);
1261 // Si variable de type $varname[index] : element de tableau
1262 if ((q2 < l) && (s[q2] == '[') ) {
1263 q3 = s.find_first_of("]",q2+1);
1264 string sia = s.substr(q2+1, q3-q2-1);
1265 if (sia.length() < 1) {
1266 cerr << " Syntax error - in $varname[index] : $"
1267 << vn << "[" << sia <<"]" << endl;
1268 return(4);
1269 }
1270 if (isalpha(sia[0])) {
1271 string sia2;
1272 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1273 cerr << " Syntax error - in $varname[index] : $"
1274 << vn << "[" << sia <<"]" << endl;
1275 return(4);
1276 }
1277 sia = sia2;
1278 }
1279 int rcdia = ctoi(sia.c_str(), &iarr);
1280 if (rcdia < 0) {
1281 cerr << " Syntax error - in $varname[iarr] : $"
1282 << vn << "[" << sia <<"]" << endl;
1283 return(4);
1284 }
1285 }
1286 }
1287 if (fgvarapp) {
1288 if (!GetVarApp(vn, vv))
1289 if (!Var2Str(vn, vv)) return(5);
1290 s2 += (s.substr(p, q-p) + vv);
1291 p = q2;
1292 }
1293 else if (iarr < 0) {
1294 if (!Var2Str(vn, vv)) return(5);
1295 s2 += (s.substr(p, q-p) + vv);
1296 p = q2;
1297 }
1298 else {
1299 if (! Var2Str(vn, iarr, vv) ) {
1300 cerr << " Substitution error - word index out of range in "
1301 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1302 return(4);
1303 }
1304 else s2 += (s.substr(p, q-p) + vv);
1305 p = q3+1;
1306 }
1307}
1308if (p < l) s2 += s.substr(p);
1309
1310p = s2.find_first_not_of(" \t");
1311if (p < l) s2 = s2.substr(p);
1312
1313return(0);
1314}
1315
1316/* --Methode-- */
1317bool Commander::Var2Str(string const & vn, string & vv)
1318{
1319if (vn.length() < 1) {
1320 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
1321 vv = ""; return(false);
1322}
1323// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1324int ka = 0;
1325char buff[32];
1326
1327if (vn == "#") {
1328 if (ArgsStack.empty()) {
1329 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1330 << " ($" << vn << ")" << endl;
1331 vv = ""; return(false);
1332 }
1333 char buff[32];
1334 long an = ArgsStack.top().size();
1335 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
1336 sprintf(buff,"%ld", an);
1337 vv = buff; return(true);
1338}
1339else if (vn == "*") {
1340 if (ArgsStack.empty()) {
1341 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1342 << " ($" << vn << ")" << endl;
1343 vv = ""; return(false);
1344 }
1345 vv = ArgsStack.top()[0];
1346 for(unsigned int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
1347 return(true);
1348}
1349else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1350 if (ArgsStack.empty()) {
1351 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1352 << " ($" << vn << ")" << endl;
1353 vv = ""; return(false);
1354 }
1355 if ( (ka < 0) || (ka >= (int)ArgsStack.top().size()) ) {
1356 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
1357 << " ($" << vn << ")" << endl;
1358 vv = ""; return(false);
1359 }
1360 vv = ArgsStack.top()[ka]; return(true);
1361}
1362else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
1363 CmdVarList::iterator it = variables.find(vn.substr(1));
1364 if (it == variables.end()) {
1365 cerr << " Commander::Var2Str/Error #vname Undefined variable "
1366 << vn << " ! " << endl;
1367 vv = ""; return(false);
1368 }
1369 sprintf(buff,"%d", (int)(*it).second.size());
1370 vv = buff; return(true);
1371}
1372else if (vn == "status") {
1373 sprintf(buff,"%d", _xstatus);
1374 vv = buff;
1375 return true;
1376}
1377else if ((vn == "retstr") || (vn == "retval")) {
1378 vv = _retstr;
1379 return true;
1380}
1381else { // Variable de l'interpreteur, ou de l'environnement application , env. global
1382 if (GetVar(vn, vv)) return true;
1383 else if (GetVarApp(vn, vv)) return true;
1384 else if (GetVarEnv(vn, vv)) return true;
1385 else {
1386 cerr << " Commander::Var2Str/Error Undefined variable "
1387 << vn << " ! " << endl;
1388 vv = ""; return false;
1389 }
1390}
1391
1392return false;
1393}
1394
1395/* --Methode-- */
1396bool Commander::SetVariable(string const & vn, string const & vv)
1397{
1398 // On verifie si le nom est de type vname[idx]
1399 size_t p,q,l;
1400 l = vn.length();
1401 p = vn.find('[');
1402 if (p < l) {
1403 q = vn.find(']');
1404 if (q != (l-1)) {
1405 cout << "Commander::Str2Var/SetVar() - Bad varname with []: "
1406 << vn << endl;
1407 return false;
1408 }
1409 string vna = vn.substr(0, p);
1410 string sia = vn.substr(p+1, q-(p+1));
1411 if (isalpha(sia[0])) {
1412 string sia2;
1413 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1414 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:"
1415 << vn << endl;
1416 return false;
1417 }
1418 sia = sia2;
1419 }
1420 int iarr;
1421 int rcdia = ctoi(sia.c_str(), &iarr);
1422 if (rcdia < 0) {
1423 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: "
1424 << vn << endl;
1425 return false;
1426 }
1427 return SetVar(vna, iarr, vv);
1428 }
1429 else {
1430 if (vn == "status") {
1431 _xstatus = atoi(vv.c_str());
1432 return true;
1433 }
1434 else if (vn == "retstr") {
1435 _retstr = vv;
1436 return true;
1437 }
1438 else return SetVar(vn, vv);
1439 }
1440}
1441
1442/* --Methode-- */
1443bool Commander::GetVar(string const & vn, string & vv)
1444{
1445 CmdVarList::iterator it = variables.find(vn);
1446 if (it == variables.end()) {
1447 vv = "";
1448 return false;
1449 }
1450 vv = (*it).second[0];
1451 if ((*it).second.size() > 1) {
1452 for(unsigned int k=1; k<(*it).second.size(); k++) {
1453 vv += ' '; vv += (*it).second[k];
1454 }
1455 }
1456 return true;
1457}
1458
1459/* --Methode-- */
1460bool Commander::GetVar(string const & vn, int idx, string & vv)
1461{
1462 vv = "";
1463 CmdVarList::iterator it = variables.find(vn);
1464 if (it == variables.end()) return false;
1465 if ((idx < 0) || (idx > (int)(*it).second.size()-1))
1466 return false;
1467 vv = (*it).second[idx];
1468 return true;
1469}
1470
1471/* --Methode-- */
1472bool Commander::GetVar(string const & vn, vector<string> & vv)
1473{
1474 vv.clear();
1475 // vv.erase(vv.begin(),vv.end());
1476 CmdVarList::iterator it = variables.find(vn);
1477 if (it == variables.end()) return false;
1478 vv = (*it).second;
1479 return true;
1480}
1481
1482/* --Methode-- */
1483bool Commander::SetVar(string const & vn, string const & val)
1484{
1485 if ( !CheckVarName(vn) ) {
1486 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1487 return(false);
1488 }
1489 bool fg = false;
1490 vector<string> nouv;
1491 nouv.push_back(val);
1492 CmdVarList::iterator it = variables.find(vn);
1493 if (it == variables.end()) variables[vn] = nouv;
1494 else {
1495 (*it).second = nouv;
1496 fg = true;
1497 }
1498 return fg;
1499}
1500
1501/* --Methode-- */
1502bool Commander::SetVar(string const & vn, int idx, string const & val)
1503{
1504 if ( !CheckVarName(vn) ) {
1505 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
1506 return(false);
1507 }
1508 if ((vn == "status") || (vn == "retstr")) {
1509 cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr "
1510 << endl;
1511 return(false);
1512 }
1513 if (idx < 0) {
1514 cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl;
1515 return(false);
1516 }
1517 bool fg = false;
1518 CmdVarList::iterator it = variables.find(vn);
1519 if (it == variables.end()) {
1520 vector<string> nouv;
1521 for(int j=0; j<idx; j++) nouv.push_back("");
1522 nouv.push_back(val);
1523 variables[vn] = nouv;
1524 }
1525 else {
1526 if (idx >= (int)(*it).second.size())
1527 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1528 (*it).second[idx] = val;
1529 fg = true;
1530 }
1531 return fg;
1532}
1533
1534/* --Methode-- */
1535bool Commander::SetVar(string const & vn, vector<string> const & val)
1536{
1537 if ( !CheckVarName(vn) ) {
1538 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1539 return(false);
1540 }
1541 if ((vn == "status") || (vn == "retstr")) {
1542 cerr << "Commander::SetVar(vn, vector<string>) ERROR - special var status/retstr "
1543 << endl;
1544 return(false);
1545 }
1546 bool fg = false;
1547 CmdVarList::iterator it = variables.find(vn);
1548 if (it == variables.end()) variables[vn] = val;
1549 else {
1550 (*it).second = val;
1551 fg = true;
1552 }
1553 return fg;
1554}
1555
1556/* --Methode-- */
1557bool Commander::CheckVarName(string const & vn)
1558{
1559 size_t l,k;
1560 l = vn.length();
1561 if (l < 1) return false;
1562 if (!isalpha(vn[0])) return false;
1563 for(k=1; k<l; k++)
1564 if ((!isalnum(vn[k])) && (vn[k] != '_')) return false;
1565 return true;
1566}
1567
1568/* --Methode-- */
1569bool Commander::DeleteVar(string const & vn)
1570{
1571 CmdVarList::iterator it = variables.find(vn);
1572 if (it == variables.end()) {
1573 cerr << "Commander::DeleteVar() Var " << vn << " undefined!" << endl;
1574 return false;
1575 }
1576 variables.erase(it);
1577 return true;
1578}
1579
1580/* --Methode-- */
1581void Commander::ListVar()
1582{
1583 cout << " ---- Commander::ListVar() List of defined variables ---- "
1584 << endl;
1585 CmdVarList::iterator it;
1586 for(it = variables.begin(); it != variables.end(); it++) {
1587 string vn = (*it).first;
1588 int vs = (*it).second.size();
1589 cout << vn << " -> Size= " << vs << endl;
1590 }
1591 cout << "---------------------------------------------------------- "
1592 << endl;
1593}
1594
1595/* --Methode-- */
1596bool Commander::GetVarApp(string const & vn, string & vv)
1597{
1598 vv = "";
1599 // cout << " Commander::GetVarApp() Not available ! " << endl;
1600 return false;
1601}
1602
1603/* --Methode-- */
1604bool Commander::SetVarApp(string const & vn, string const & vv)
1605{
1606 // cout << " Commander::SetVarApp() Not available ! " << endl;
1607 return false;
1608}
1609
1610/* --Methode-- */
1611bool Commander::DeleteVarApp(string const & vn)
1612{
1613 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
1614 return false;
1615}
1616
1617/* --Methode-- */
1618void Commander::ListVarApp()
1619{
1620 // cout << " Commander::ListVarApp() Not available ! " << endl;
1621 return;
1622}
1623
1624
1625/* --Methode-- */
1626bool Commander::GetVarEnv(string const & vn, string & vv)
1627{
1628 char* vev = getenv(vn.c_str());
1629 if (vev) {
1630 vv = vev;
1631 return true;
1632 }
1633 else {
1634 vv = "";
1635 return false;
1636 }
1637}
1638
1639/* --Methode-- */
1640bool Commander::SetVarEnv(string const & vn, string const & vv)
1641{
1642 string pev = vn;
1643 pev += '=';
1644 pev += vv;
1645// if defined(Linux) || defined(AIX)
1646// Reza - 28/04/2004
1647// putenv de Linux ne declare pas la variable char *string const
1648// On ne doit meme pas utiliser une variable automatique
1649// J'alloue donc un nouveau tableau - mais qui va le liberer ?
1650// Idem AIX , Reza Dec 2005
1651// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1652// Je fais copie pour tout le monde
1653 char* bev = new char[pev.size()+1];
1654 strcpy(bev, pev.c_str());
1655 if (putenv(bev) == 0) return true;
1656// else
1657// if (putenv(pev.c_str()) == 0) return true;
1658// endif
1659 else return false;
1660}
1661
1662/* --Methode-- */
1663bool Commander::DeleteVarEnv(string const & vn)
1664{
1665 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
1666 return false;
1667}
1668
1669/* --Methode-- */
1670void Commander::ListVarEnv()
1671{
1672 cout << " Commander::ListVarEnv() Not available ! " << endl;
1673 return;
1674}
1675
1676
1677/* --Methode-- */
1678string Commander::GetTmpDir()
1679{
1680 return("/tmp");
1681}
1682
1683/* --Methode-- */
1684void Commander::SetCurrentPrompt(const char* pr)
1685{
1686 curprompt = pr;
1687}
1688
1689/* --Methode-- */
1690void Commander::ShowMessage(const char * msg, int att)
1691{
1692 cout << msg ;
1693}
1694
1695
1696
1697/* --Methode-- */
1698int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1699{
1700 res = true;
1701 if ((args.size() != 6) || (args[5] != "then") ||
1702 (args[0] != "(") || (args[4] != ")") ) return(1);
1703 if (args[2] == "==") res = (args[1] == args[3]);
1704 else if (args[2] == "!=") res = (args[1] != args[3]);
1705 else if (args[2] == "<")
1706 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1707 else if (args[2] == ">")
1708 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1709 else if (args[2] == "<=")
1710 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1711 else if (args[2] == ">=")
1712 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1713 else return(2);
1714 return(0);
1715}
1716
1717
1718/* --Methode-- */
1719int Commander::EvalRPNExpr(vector<string> & args, string & line)
1720{
1721 // A virer - Reza 15/03/2004
1722 return(0);
1723}
1724
1725/* --Methode-- */
1726void Commander::PushStack(vector<string>& args)
1727{
1728 // We push the argument list (args) on the stack
1729 ArgsStack.push(args);
1730 // We push also CommanderBloc and testresult on the stack
1731 CmdBlks.push(NULL);
1732 list<char> xtx;
1733 TestsStack.push(xtx);
1734
1735}
1736
1737/* --Methode-- */
1738void Commander::PopStack(bool psta)
1739{
1740 // We remove the argument list (args) from the stack
1741 if (psta) ArgsStack.pop();
1742 // And CommanderBloc and TestResult from the corresponding stacks
1743 CommanderBloc* curb = CmdBlks.top();
1744 while (curb != NULL) {
1745 CommanderBloc* parb = curb->Parent();
1746 delete curb; curb = parb;
1747 }
1748 CmdBlks.pop();
1749 TestsStack.pop();
1750}
1751
1752/* --Methode-- */
1753int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1754{
1755int rc = 0;
1756
1757// >>>>>>>>>>> Commande d'interpreteur
1758if (kw == "help") {
1759 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1760 else {
1761 string kwh = "Commander";
1762 cout << GetUsage(kwh) << endl;
1763 }
1764 }
1765else if (kw == "sleep") {
1766 if (tokens.size() < 1) {
1767 cout << "Commander::Interpret() Usage: sleep nsec " << endl;
1768 return(1);
1769 }
1770 int nsec = atoi(tokens[0].c_str());
1771 cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl;
1772 sleep(nsec);
1773}
1774
1775else if (kw == "set") {
1776 if (tokens.size() < 2) {
1777 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1778 return(1);
1779 }
1780
1781 if (tokens.size() == 2)
1782 SetVariable(tokens[0], tokens[1]);
1783 else {
1784 if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
1785 cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;
1786 return(1);
1787 }
1788 string vname = tokens[0];
1789 vector<string>::iterator vit;
1790 vit = tokens.begin(); tokens.erase(vit);
1791 vit = tokens.begin(); tokens.erase(vit);
1792 tokens.pop_back();
1793 SetVar(vname, tokens);
1794 }
1795 return 0;
1796}
1797else if (kw == "var2words") {
1798 if (tokens.size() < 2) {
1799 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1800 return(1);
1801 }
1802 char sep = ' ';
1803 if (tokens.size() > 2) sep = tokens[2][0];
1804 string vv;
1805 if (!GetVar(tokens[0], vv)) {
1806 cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl;
1807 return 2;
1808 }
1809 vector<string> vs;
1810 FillVStringFrString(vv, vs, sep);
1811 SetVar(tokens[1], vs);
1812}
1813else if (kw == "alias") {
1814 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1815 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1816 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
1817 return(1);
1818 }
1819 string xx = tokens[1];
1820 for (unsigned int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1821 mAliases[tokens[0]] = xx;
1822}
1823
1824else if ( (kw == "unset") || (kw == "clearvar") ) {
1825 if (tokens.size() < 1) {
1826 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
1827 return(1);
1828 }
1829 else DeleteVar(tokens[0]);
1830}
1831// Evaluation d'expression en notation polonaise inverse
1832else if (kw == "rpneval") {
1833 try {
1834 RPNExpressionEvaluator rpn(tokens, 1);
1835 double res = rpn.Value();
1836 string vv = cval_dble2str(res);
1837 SetVariable(tokens[0],vv);
1838 return 0;
1839 }
1840 catch (RPNExprException& rpnerr) {
1841 cerr << " rpneval: Syntax error - Msg=" << rpnerr.Msg()
1842 << " \n Line=" << toks << endl;
1843 return 98;
1844 }
1845}
1846else if (kw == "echo") {
1847 for (unsigned int ii=0; ii<tokens.size(); ii++)
1848 cout << tokens[ii] << " " ;
1849 cout << endl;
1850 }
1851else if (kw == "echo2file") {
1852 if (tokens.size() < 1) {
1853 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
1854 return(1);
1855 }
1856 ofstream ofs(tokens[0].c_str(), ios::app);
1857 for (unsigned int ii=1; ii<tokens.size(); ii++)
1858 ofs << tokens[ii] << " " ;
1859 ofs << endl;
1860 }
1861else if (kw == "readstdin") {
1862 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1863 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1864 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1865 return(0);
1866 }
1867 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1868 cout << tokens[0] << " ? " << endl;
1869 SetVar(tokens[0], GetStringFrStdin(this) );
1870 }
1871
1872else if (kw == "listvars" || kw == "listvar") ListVar();
1873else if (kw == "listalias") {
1874 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1875 CmdStrList::iterator it;
1876 for(it = mAliases.begin(); it != mAliases.end(); it++)
1877 cout << (*it).first << " = " << (*it).second << "\n";
1878 cout << endl;
1879 }
1880else if (kw == "listcommands") {
1881 cout << "---- Commander::Interpret() Command List ----- \n";
1882 CmdExmap::iterator it;
1883 int kc = 0;
1884 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1885 cout << (*it).first << " ";
1886 kc++;
1887 if (kc >= 5) { cout << "\n"; kc = 0; }
1888 }
1889 cout << endl;
1890 }
1891else if (kw == "listscripts") {
1892 cout << "---- Commander::Interpret() Script List ----- \n";
1893 for(ScriptList::iterator sit = mScripts.begin();
1894 sit != mScripts.end(); sit++)
1895 cout << " Script: " << (*sit).second->Name() << " - "
1896 << (*sit).second->Comment() << endl;
1897}
1898else if (kw == "clearscript") {
1899 if (tokens.size() < 1) {
1900 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1901 return(0);
1902 }
1903 ScriptList::iterator sit = mScripts.find(tokens[0]);
1904 if (sit == mScripts.end()) {
1905 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1906 return(0);
1907 }
1908 else {
1909 delete (*sit).second;
1910 mScripts.erase(sit);
1911 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1912 return(0);
1913 }
1914}
1915//---------------------------------------------
1916//--- Commandes de gestion des threads ------
1917//---------------------------------------------
1918else if (kw == "thrlist") {
1919 ListThreads();
1920 return(0);
1921}
1922else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1923 if (tokens.size() < 1) {
1924 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1925 return(0);
1926 }
1927 uint_8 id = atol(tokens[0].c_str());
1928 bool fgkill = false;
1929 if (kw == "killthr") fgkill = true;
1930 StopThr(id, fgkill);
1931 return (0);
1932}
1933else if (kw == "waitthr") {
1934 WaitThreads();
1935 return (0);
1936}
1937else if (kw == "cleanthrlist") {
1938 CleanThrList();
1939 return (0);
1940}
1941
1942else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1943else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1944else if (kw == "timingon") {
1945 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1946 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1947 }
1948else if (kw == "timingoff") {
1949 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1950 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1951 }
1952else if (kw == "exec") {
1953 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1954 ExecFile(tokens[0], tokens);
1955 }
1956else if (kw == "autoiniranf") {
1957 AutoInitRand(1);
1958 return(0);
1959}
1960else if (kw == "shell") {
1961 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1962 string cmd;
1963 for (unsigned int ii=0; ii<tokens.size(); ii++)
1964 cmd += (tokens[ii] + ' ');
1965 system(cmd.c_str());
1966 }
1967else if (kw == "cshell") {
1968 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1969 string cmd="";
1970 for(unsigned int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
1971 CShellExecute(cmd);
1972 }
1973
1974// Execution d'une commande enregistree
1975else rc = ExecuteCommand(kw, tokens, toks);
1976
1977if (timing) gltimer->Split();
1978return(rc);
1979}
1980
1981/* --Methode-- */
1982int Commander::ParseLineExecute(string& line, bool qw)
1983 // Si qw == true, on decoupe entre '' ou "" ou espaces
1984{
1985vector<string> tokens;
1986vector<bool> qottoks;
1987string kw, toks;
1988if (line.length() < 1) return(0);
1989LineToWords(line, kw, tokens, qottoks, toks, qw);
1990return(ExecuteCommand(kw, tokens, toks));
1991}
1992
1993/* --Methode-- */
1994int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
1995{
1996 int rc = -1;
1997 CmdExmap::iterator it = cmdexmap.find(keyw);
1998 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
1999 else {
2000 if ((*it).second.cex) {
2001 // Doit-on l'executer sous forme de thread separe ?
2002 if ( (args.size()>0) && (args[args.size()-1] == "&") ) {
2003 if ((*it).second.cex->IsThreadable(keyw) ) {
2004 ThrId++;
2005 CommandExeThr * thr =
2006 new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
2007 CmdThrExeList.push_back(thr);
2008 cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
2009 thr->start();
2010 if (CmdThrExeList.size() > 5) CleanThrList();
2011 rc = 0;
2012 }
2013 else {
2014 args.erase(args.end()-1);
2015 for(size_t k=toks.size()-1; k>0; k--)
2016 if (toks[k] == '&') { toks[k] = ' '; break; }
2017 cout << " Commander::ExecuteCommand() : Thread execution NOT available for" << keyw << endl;
2018 rc = (*it).second.cex->Execute(keyw, args, toks);
2019 }
2020 }
2021 else rc = (*it).second.cex->Execute(keyw, args, toks);
2022 }
2023 else cout << "Dont know how to execute " << keyw << " ? " << endl;
2024 }
2025 return(rc);
2026}
2027
2028/* --Methode-- */
2029int Commander::ExecFile(string& file, vector<string>& args)
2030{
2031char line_buff[1024];
2032FILE *fip;
2033int rcc = 0;
2034if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
2035 if (file.find('.') >= file.length()) {
2036 cout << "Commander::Exec(): Error opening file " << file << endl;
2037 file += ".pic";
2038 cout << " Trying file " << file << endl;
2039 fip = fopen(file.c_str(),"r");
2040 }
2041 }
2042
2043if(fip == NULL) {
2044 cerr << "Commander::Exec() Error opening file " << file << endl;
2045 hist << "##! Commander::Exec() Error opening file " << file << endl;
2046 return(0);
2047 }
2048
2049// hist << "### Executing commands from " << file << endl;
2050PushStack(args);
2051if (trace) {
2052 ShowMessage("### Executing commands from ", _MAGENTA_);
2053 ShowMessage(file.c_str(), _MAGENTA_);
2054 ShowMessage("\n", _MAGENTA_);
2055 }
2056
2057bool ohv = histon;
2058histon = false;
2059while (fgets(line_buff,1023,fip) != NULL)
2060 {
2061 if (trace) ShowMessage(line_buff, _MAGENTA_);
2062 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
2063 string line(line_buff);
2064 rcc = Interpret(line);
2065 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
2066 }
2067histon = ohv;
2068
2069// hist << "### End of Exec( " << file << " ) " << endl;
2070if (trace) {
2071 ShowMessage("### End of Exec( ", _MAGENTA_);
2072 ShowMessage(file.c_str(), _MAGENTA_);
2073 ShowMessage(" ) \n", _MAGENTA_);
2074 }
2075
2076PopStack(true);
2077
2078return(0);
2079}
2080
2081/* --Methode-- */
2082void Commander::ListThreads()
2083{
2084 cout << "--- Commander::ListThreads()- command execution threads NThread="
2085 << CmdThrExeList.size() << " ---" << endl;
2086 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2087 tit != CmdThrExeList.end(); tit++) {
2088 cout << "Id=" << (*tit)->Id();
2089 if ( (*tit)->IfRunning() ) cout << " Executing";
2090 else if ( (*tit)->IfDone() ) cout << " Finished , Rc= " << (*tit)->getRC();
2091 else cout << " Stopped/Canceled";
2092 cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens().substr(0,35);
2093 if ((*tit)->Tokens().length() > 35) cout << "... )" << endl;
2094 else cout << " )" << endl;
2095 }
2096}
2097/* --Methode-- */
2098void Commander::StopThr(uint_8 id, bool fgkill)
2099{
2100 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2101 tit != CmdThrExeList.end(); tit++) {
2102 if ( ((*tit)->Id() == id) && ((*tit)->IfRunning()) ) {
2103 if (fgkill) {
2104 (*tit)->kill(SIGUSR1);
2105 cout << "Commander::StopThr() Send signal SIGUSR1 to Thread Id= " << id << endl;
2106 }
2107 else {
2108 (*tit)->cancel();
2109 cout << "Commander::StopThr() Canceling Thread Id= " << id << endl;
2110 }
2111 return;
2112 }
2113 }
2114 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
2115}
2116
2117/* --Methode-- */
2118void Commander::CleanThrList()
2119{
2120 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2121 list<CommandExeThr *> thrcopie;
2122 int ncl = 0;
2123 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2124 tit != CmdThrExeList.end(); tit++) {
2125 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
2126 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2127 delete (*tit);
2128 ncl++;
2129 }
2130 else thrcopie.push_back((*tit));
2131 }
2132 CmdThrExeList = thrcopie;
2133 cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
2134}
2135
2136/* --Methode-- */
2137void Commander::WaitThreads()
2138{
2139 cout << "---- Commander::WaitThreads() Wait/Join command execution threads - NThread="
2140 << CmdThrExeList.size() << " ----- " << endl;
2141 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2142 tit != CmdThrExeList.end(); tit++) {
2143 try {
2144 if (! (*tit)->IfDone()) (*tit)->join();
2145 }
2146 catch (std::exception & e) {
2147 cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
2148 }
2149 cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
2150 delete (*tit);
2151 }
2152 CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
2153}
2154
2155/* --Methode-- */
2156int Commander::CShellExecute(string cmd)
2157{
2158 if(cmd.size()<=0) return -1;
2159
2160 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
2161
2162 string cmdrm = "rm -f " + fname;
2163 system(cmdrm.c_str());
2164
2165 FILE *fip = fopen(fname.c_str(),"w");
2166 if(fip==NULL) {
2167 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
2168 return -2;
2169 }
2170 fprintf(fip,"#!/bin/csh\n\n");
2171 fprintf(fip,"%s\n",cmd.c_str());
2172 fprintf(fip,"\nexit 0\n");
2173 fclose(fip);
2174
2175 cmd = "csh "; cmd += fname;
2176 system(cmd.c_str());
2177
2178 system(cmdrm.c_str());
2179
2180 return 0;
2181}
2182
2183static string* videstr = NULL;
2184/* --Methode-- */
2185string& Commander::GetUsage(const string& kw)
2186{
2187bool fndok = false;
2188CmdExmap::iterator it = cmdexmap.find(kw);
2189if (it == cmdexmap.end()) {
2190 it = helpexmap.find(kw);
2191 if (it != helpexmap.end()) fndok = true;
2192 }
2193 else fndok = true;
2194if (fndok) return( (*it).second.us );
2195// Keyword pas trouve
2196if (videstr == NULL) videstr = new string("");
2197*videstr = "Nothing known about " + kw + " ?? ";
2198return(*videstr);
2199
2200}
2201
2202
2203/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
2204 \newcommand{\piacommand}[1]{
2205 \framebox{\bf \Large #1 } \index{#1} % (Command)
2206 }
2207
2208 \newcommand{\piahelpitem}[1]{
2209 \framebox{\bf \Large #1 } \index{#1} (Help item)
2210 }
2211
2212 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2213*/
2214
2215// Fonction qui remplace tout caractere non alphanumerique en Z
2216static void check_latex_reflabel(string & prl)
2217{
2218 for(unsigned int k=0; k<prl.length(); k++)
2219 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2220}
2221
2222// Fonction qui remplace _ en \_
2223static string check_latex_underscore(string const & mot)
2224{
2225 string rs;
2226 for(unsigned int k=0; k<mot.length(); k++) {
2227 if (mot[k] == '_') rs += "\\_";
2228 else rs += mot[k];
2229 }
2230 return rs;
2231}
2232
2233/* --Methode-- */
2234/*!
2235 \brief Produces a LaTeX file containing the registered command helps
2236 The file \b fname is created and can be inserted into a LaTeX document
2237 in order to produce the list of registered commands and corresponding description
2238 texts.
2239 The LaTeX file should contain the following definitions:
2240\verbatim
2241 \newcommand{\piacommand}[1]{
2242 \framebox{\bf \Large #1 } \index{#1} % (Command)
2243 }
2244
2245 \newcommand{\piahelpitem}[1]{
2246 \framebox{\bf \Large #1 } \index{#1} (Help item)
2247 }
2248
2249 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2250
2251\endverbatim
2252*/
2253void Commander::HelptoLaTeX(string const & fname)
2254{
2255FILE *fip;
2256if ((fip = fopen(fname.c_str(), "w")) == NULL) {
2257 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
2258 return;
2259 }
2260
2261fputs("% ----- Liste des groupes de Help ----- \n",fip);
2262fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
2263fputs("\\begin{itemize} \n",fip);
2264string prl;
2265string mol;
2266CmdHGroup::iterator it;
2267for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2268 if ((*it).first == "All") continue;
2269 prl = (*it).first; check_latex_reflabel(prl);
2270 mol = check_latex_underscore((*it).first);
2271 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
2272 mol.c_str(), prl.c_str());
2273}
2274
2275fputs("\\end{itemize} \n",fip);
2276
2277fputs("\\vspace*{10mm} \n",fip);
2278
2279CmdExmap::iterator ite;
2280fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
2281fputs("\\vspace{5mm} \n",fip);
2282// fputs("\\begin{table}[h!] \n", fip);
2283fputs("\\begin{center} \n ", fip);
2284fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
2285fputs("\\vspace{3mm} \n",fip);
2286fputs("\\begin{tabular}{llllll} \n", fip);
2287int kt = 0;
2288for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2289 prl = (*ite).first; check_latex_reflabel(prl);
2290 mol = check_latex_underscore((*ite).first);
2291 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2292 kt++;
2293 if (kt < 3) fputs(" & ", fip);
2294 else { fputs(" \\\\ \n", fip); kt = 0; }
2295 }
2296if (kt == 1) fputs(" & & & \\\\ \n", fip);
2297else if (kt == 2) fputs(" & \\\\ \n", fip);
2298fputs("\\end{tabular} \n", fip);
2299fputs("\\end{center} \n", fip);
2300//fputs("\\end{table} \n", fip);
2301fputs("\\newpage \n",fip);
2302
2303int gid;
2304for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2305 gid = (*it).second.gid;
2306 if (gid == 0) continue;
2307 // fputs("\\begin{table}[h!] \n",fip);
2308 fputs("\\vspace{6mm} \n",fip);
2309 fputs("\\begin{center} \n ", fip);
2310 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
2311 (*it).first.c_str());
2312 fputs("\\vspace{3mm} \n",fip);
2313 fputs("\\begin{tabular}{llllll} \n", fip);
2314 kt = 0;
2315 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2316 if ((*ite).second.group != gid) continue;
2317 prl = (*ite).first; check_latex_reflabel(prl);
2318 mol = check_latex_underscore((*ite).first);
2319 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2320 kt++;
2321 if (kt < 3) fputs(" & ", fip);
2322 else { fputs(" \\\\ \n", fip); kt = 0; }
2323 }
2324 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2325 if ((*ite).second.group != gid) continue;
2326 prl = (*ite).first; check_latex_reflabel(prl);
2327 mol = check_latex_underscore((*ite).first);
2328 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2329 kt++;
2330 if (kt < 3) fputs(" & ", fip);
2331 else { fputs(" \\\\ \n", fip); kt = 0; }
2332 }
2333 if (kt == 1) fputs(" & & & \\\\ \n", fip);
2334 else if (kt == 2) fputs(" & \\\\ \n", fip);
2335 fputs("\\end{tabular} \n", fip);
2336 fputs("\\end{center} \n", fip);
2337 // fputs("\\end{table} \n",fip);
2338 // fputs("\\vspace{5mm} \n",fip);
2339}
2340// fputs("\\newline \n",fip);
2341
2342fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
2343fputs("\\newpage \n",fip);
2344
2345for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2346 gid = (*it).second.gid;
2347 if (gid == 0) continue;
2348 prl = (*it).first; check_latex_reflabel(prl);
2349 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
2350 (*it).first.c_str(), prl.c_str());
2351 if ((*it).second.desc.length() > 0)
2352 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
2353 fprintf(fip,"\\noindent \n");
2354 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2355 if ((*ite).second.group != gid) continue;
2356 prl = (*ite).first; check_latex_reflabel(prl);
2357 mol = check_latex_underscore((*ite).first);
2358 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
2359 mol.c_str(), prl.c_str());
2360 fputs("\\begin{verbatim} \n",fip);
2361 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2362 fputs("\\end{verbatim} \n",fip);
2363 }
2364 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2365 if ((*ite).second.group != gid) continue;
2366 prl = (*ite).first; check_latex_reflabel(prl);
2367 mol = check_latex_underscore((*ite).first);
2368 fprintf(fip,"\\piacommand{%s} \\label{%s} \n",
2369 mol.c_str(), prl.c_str());
2370 fputs("\\begin{verbatim} \n",fip);
2371 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2372 fputs("\\end{verbatim} \n",fip);
2373 }
2374}
2375
2376fclose(fip);
2377cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2378
2379return;
2380}
2381
2382
2383} // End of namespace SOPHYA
2384
Note: See TracBrowser for help on using the repository browser.