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

Last change on this file since 4011 was 3814, checked in by ansari, 15 years ago

Correction oubli initialisation de la limite des boucles de l'interpreteur, Reza 26/07/2010

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