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

Last change on this file since 3824 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
RevLine 
[2615]1#include "sopnamsp.h"
[2446]2#include "commander.h"
3#include <stdio.h>
4#include <stdlib.h>
[3619]5#include <string.h>
[2518]6#include <unistd.h>
[2446]7#include <ctype.h>
8#include <math.h>
[2943]9#include <signal.h>
[2446]10
11#include "strutil.h"
12#include "strutilxx.h"
[2512]13#include "cexpre.h"
14#include "rpneval.h"
[2446]15#include "srandgen.h"
[2671]16#include "zthread.h"
[2446]17
18
[2483]19namespace SOPHYA {
[2518]20
[3577]21//--------------------------------------------------
22// Pour ecrire une valeur double sous forme de string
23// sans perte de precision, et si possible de maniere
[3581]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: }
[3577]38char * cval_dble2str(double v)
39{
[3581]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;
[3577]53}
54//--------------------------------------------------
55
[2518]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
[2446]61// ------------------------------------------------------------
62// Bloc de commandes (Foreach, ...)
63// Classe CommanderBloc
64// ------------------------------------------------------------
65/*!
[2598]66 \internal
[2446]67 \class SOPHYA::CommanderBloc
68 \ingroup SysTools
[2598]69 Class for internal use by class Commander to handle loops
[2446]70*/
71class CommanderBloc {
72public:
[2483]73 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat,
74 BT_ForeachLineInFile };
[2446]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()); }
[2518]85
86 // Execution complete du bloc (boucle)
87 int Execute();
88 // Execution pour un element de bloc
89 int ExecuteOnce(string& lvv);
90
[2446]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;
[2483]102 string filename; // forinfile bloc
[2446]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;
[2483]127if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return;
[2518]128if (!piac->CheckVarName(args[0])) return;
129varname = args[0];
130
[2446]131//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
[2483]132if (kw == "forinfile") {
133 filename = args[1];
[2518]134 typ = BT_ForeachLineInFile;
[2483]135 blkok = true;
136}
137else if (kw == "foreach" ) { // This is a foreach bloc with string list
[2518]138 if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
139 // foreach varname ( w1 w2 w3 ... )
[3581]140 for(unsigned int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
[2518]141 }
142 else {
143 // foreach varname WordVectorName
144 if (!piac->GetVar(args[1], strlist)) return;
145 }
146 if (strlist.size() < 1) return;
[2446]147 typ = BT_ForeachList;
148 blkok = true;
[2483]149}
[2446]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{
[3581]189for(unsigned int k=0; k<blocs.size(); k++) delete blocs[k];
[2446]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-- */
[2518]204int CommanderBloc::Execute()
[2446]205{
206int k=0;
207char buff[32];
208int rcc = 0;
209
210int mxloop = _commander->GetMaxLoopLimit();
211
[2483]212if (typ == BT_ForeachLineInFile) { // foreach line in file loop
[2518]213 ifstream is(filename.c_str());
214 string line;
215 while (!is.eof()) {
216 rcc = 0;
[2796]217 line = "";
218 getline(is,line);
219 if (is.good() || is.eof()) {
[2518]220 rcc = ExecuteOnce(line);
[2796]221 if (rcc == CMD_BREAKEXE_RC) return rcc;
222 else if (rcc == CMD_BREAK_RC) break;
[2518]223 }
224 }
[2483]225}
[2518]226else if (typ == BT_ForeachList) { // foreach string loop
[3581]227 for(unsigned int k=0; k<strlist.size(); k++) {
[2518]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
[2446]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 }
[2518]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;
[2446]245 }
[2518]246}
247else if (typ == BT_ForeachFloat) { // float loop
248 for(double f=f1; f<f2; f+=df) {
[2446]249 k++;
250 if ((mxloop>0) && (k > mxloop)) {
251 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
252 break;
253 }
[3577]254 string lvv = cval_dble2str(f);
[2518]255 rcc = ExecuteOnce(lvv);
256 if (rcc == CMD_BREAKEXE_RC) return rcc;
257 else if (rcc == CMD_BREAK_RC) break;
[2446]258 }
[2518]259}
260return(rcc);
261}
[2446]262
[2518]263/* --Methode-- */
264int CommanderBloc::ExecuteOnce(string& lvv)
265{
[3581]266 unsigned int kj=0;
[2518]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;
[2446]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/*!
[2598]291 \internal
[2446]292 \class SOPHYA::CommanderScript
293 \ingroup SysTools
[2598]294 Class for internal use by class Commander to handle functions
[2446]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{
[3581]357 int rcc=-2;
[2446]358 if (!CheckScript()) return(-1);
359 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
[3581]360 for(unsigned int k=0; k<lines.size(); k++) {
[2518]361 rcc = _commander->Interpret(lines[k]);
362 if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break;
[2446]363 }
[2518]364 return(rcc);
[2446]365}
366
[2671]367
[2446]368// ------------------------------------------------------------
[2671]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.
[2943]376 The command execution is carried in method run() which has its own exception handling bloc.
[2671]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;
[2956]402 _args = args;
403 _args.erase(_args.end()-1);
[2671]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{
[2943]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 }
[2671]431 _fgdone = true;
432 setRC(rc);
433}
434
435// ------------------------------------------------------------
[2446]436// Classe Commander
437// ------------------------------------------------------------
438typedef void (* DlModuleInitEndFunction) ();
439
440/*!
[2598]441 \class Commander
[2446]442 \ingroup SysTools
[2598]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
[2671]449 Although the interpreter has many limitations compared to
[2598]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
[2943]455 - Command execution in separate threads
[2598]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
[2446]471*/
472
473#define _MAGENTA_ 1
474
475static Commander* cur_commander = NULL;
476/* --Methode-- */
[2955]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)
[2446]482{
483system("cp history.pic hisold.pic");
484hist.open("history.pic");
485histon = true;
486trace = false; timing = false;
487gltimer = NULL;
488felevel = 0;
[3814]489SetMaxLoopLimit();
[2446]490mulinecmd = "";
491mulinefg = false;
492spromptmul = "Cmd> ";
493SetCurrentPrompt(spromptmul);
[2483]494SetDefaultPrompt(spromptmul);
[2446]495curscript = NULL;
496
[2483]497_xstatus = 0;
498 _retstr = "";
499
[2518]500// Controle du flot d'execution
501 fgexebrk = false;
502
[2446]503CmdBlks.push(NULL);
504list<char> xtx;
505TestsStack.push(xtx);
506curtestresult = true;
507
[2671]508// Pour la numerotation et l'identification des threads
509ThrId = 0;
510
[2473]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;
[2446]514
[2466]515string grp = "Commander";
516string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
517AddHelpGroup(grp, gdesc);
518
[2446]519string kw = "Commander";
520string usage;
521usage = ">>> (Commander) Interpreter's keywords : \n";
[2671]522usage += " > set varname string # To set a variable, $varname \n";
[2446]523usage += " > unset varname # clear variable definition \n";
[2518]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";
[2446]533usage += " > for varname f1:f2[:df] # Float loop \n";
[2518]534usage += " > forinfile varname FileName # Loop over lines in file \n";
[2446]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";
[2671]547usage += " > thrlist # List of command execution threads (& as the last character) \n";
548usage += " > clearthrlist # Removes finished threads from the list \n";
[2955]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";
[2671]551usage += " > waitthr # Waits until all active threads have finished (join()) \n";
[2446]552usage += " > exec filename # Execute commands from file \n";
[2518]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";
[2446]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";
[3615]587usage += " by AutoInitRand(int lp) \n";
[2446]588usage += " Usage: autoiniranf";
589RegisterCommand(kw, usage, NULL, grp);
590
[2671]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
[2446]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;
[2955]615if (fgsigzt) ZThread::ActivateExitOnSignal(SIGUSR1);
[2446]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-- */
[2598]644//! Returns the string \c Commander as the interpreter's name.
[2446]645string Commander::Name()
646{
647return("Commander");
648}
649
650/* --Methode-- */
[2598]651//! Add the \b grp help group with description \b desc.
[2466]652void Commander::AddHelpGroup(string& grp, string& desc)
[2446]653{
[2466]654 int gid;
655 CheckHelpGrp(grp, gid, desc);
656}
657
658/* --Methode-- */
[2598]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*/
[2466]667void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
668{
[2446]669if (!ce) {
670 RegisterHelp(keyw, usage, grp);
671 return;
672 }
[2466]673int gid;
674CheckHelpGrp(grp,gid);
[2446]675cmdex cme;
676cme.group = gid;
677cme.us = usage;
678cme.cex = ce;
679cmdexmap[keyw] = cme;
680}
681
682/* --Methode-- */
[2598]683/*!
684 \brief Register a help text.
685 \param keyw : help keyword
686 \param usage : help text
687 \param grp : help group
688*/
[2446]689void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
690{
[2466]691int gid;
692CheckHelpGrp(grp,gid);
[2446]693cmdex cme;
694cme.group = gid;
695cme.us = usage;
696cme.cex = NULL;
697helpexmap[keyw] = cme;
698}
699
700/* --Methode-- */
[2466]701bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
[2446]702{
[2466]703gid = 0;
[2446]704CmdHGroup::iterator it = cmdhgrp.find(grp);
705if (it == cmdhgrp.end()) {
[2466]706 cmdgrpid++; gid = cmdgrpid;
707 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
708 cmdhgrp[grp] = hgs;
709 return true;
[2446]710 }
[2466]711else {
712 if (desc.length() > 0) (*it).second.desc = desc;
713 gid = (*it).second.gid;
714 return false;
[2446]715}
[2466]716}
[2446]717
718
719/* --Methode-- */
[2598]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*/
[2446]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-- */
[2598]756//! Declare a new interpreter
[2446]757void Commander::AddInterpreter(CmdInterpreter * cl)
758{
759if (!cl) return;
760interpmap[cl->Name()] = cl;}
761
762/* --Methode-- */
[2943]763//! Select an interpreter by its name as the current interpreter.
[2446]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-- */
[2598]783/*!
[2671]784 \brief Method which has to be invoked to interpret a given command line or string.
[2598]785*/
[2446]786int Commander::Interpret(string& s)
787{
788int rc = 0;
789ScriptList::iterator sit;
790
[2671]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
[2446]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(' ');
[3383]811if (lnb >= l) return(0); // il n'y a que des blancs
[2446]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;
[2483]865 _xstatus = 91;
866 return(91);
[2446]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;
[2483]887 _xstatus = 0;
[2446]888 return(0);
889 }
890 else {
891 cout << "Commander::Interpret() Error in Script " << curscript->Name()
892 << " definition " << endl;
893 SetCurrentPrompt("Cmd> ");
894 curscript = NULL;
[2483]895 _xstatus = 92;
896 return(92);
[2446]897 }
898 }
899 else curscript->AddLine(s, kw);
[2483]900 _xstatus = 0;
[2446]901 return(0);
902}
903// On verifie si nous sommes dans un bloc (for , foreach)
904if (CmdBlks.top() != NULL) { // On est dans un bloc
[2671]905 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel++;
[2446]906 else if (kw == "end") felevel--;
[2856]907
908 int rcbex = 0;
[2446]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"
[2671]915 << " within for/foreach/forinfile bloc ! " << endl;
[2446]916 delete curb;
[2483]917 _xstatus = 93;
918 return(93);
[2446]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);
[2856]928 rcbex = curb->Execute();
[2446]929 // And CommanderBloc and TestResult from the corresponding stacks
930 PopStack(false);
931 }
[2483]932 SetCurrentPrompt(defprompt);
[2446]933 delete curb;
934 histon = ohv;
935 }
936 else CmdBlks.top()->AddLine(s, kw);
[2856]937 _xstatus = rcbex;
938 return(rcbex);
[2446]939}
940else if (kw == "end") {
[2671]941 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
[2446]942 << "line: " << s << endl;
[2483]943 _xstatus = 94;
944 return(94);
[2446]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;
[2483]953 _xstatus = 95;
954 return(95);
[2446]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;
[2483]961 _xstatus = 0;
[2446]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);
[2483]988 _xstatus = 0;
[2446]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;
[2483]995 _xstatus = 91;
996 return(91);
[2446]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
[2483]1011if ((!fgcont) && (kw != "if")) {
1012 _xstatus = 0;
1013 return(0);
1014}
[2446]1015
1016
1017// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
[2518]1018if (kw == "break") return CMD_BREAK_RC;
[2483]1019else if (kw == "return") {
1020 _retstr = toks;
[2518]1021 return CMD_RETURN_RC;
[2483]1022}
[2446]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;
[2483]1032 _xstatus = 99;
1033 return(99);
[2446]1034}
1035// >>>> Separating keyword and tokens
1036vector<string> tokens;
[2518]1037vector<bool> qottoks;
[2446]1038/* decoupage en mots */
[2518]1039LineToWords(s2, kw, tokens, qottoks, toks, true);
[2446]1040
1041// Si c'est un for/foreach, on cree un nouveau bloc
[2483]1042if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
[2446]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;
[2483]1048 _xstatus = 91;
1049 return(91);
[2446]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;
[2483]1063 _xstatus = 91;
1064 return(91);
[2446]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] == "=")) {
[2512]1074 // x = Expression
[2518]1075 if (qottoks[1]) { // decodage sous forme de chaine
1076 SetVariable(kw, tokens[1]);
[2512]1077 }
[2518]1078 else {
1079 try {
1080 double res = 0.;
1081 if (tokens.size() > 2) {
1082 string sex = tokens[1];
[3581]1083 for(unsigned int js=2; js<tokens.size(); js++) sex += tokens[js];
[2518]1084 CExpressionEvaluator cex(sex);
1085 res = cex.Value();
1086 }
1087 else {
1088 CExpressionEvaluator cex(tokens[1]);
1089 res = cex.Value();
1090 }
[3577]1091 string vv = cval_dble2str(res);
[2518]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 }
[2446]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;
[2483]1111 _xstatus = 91;
1112 return(91);
[2446]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);
[2483]1129 _xstatus = rc;
[2446]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
[2943]1139//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
[2671]1140void Commander::StopExecution()
1141{
1142 fgexebrk = true;
1143}
[2446]1144
[2671]1145
[2446]1146/* --Methode-- */
1147int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
[2518]1148 vector<bool>& qottoks, string& toks, bool uq)
[2446]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) {
[2518]1164 bool swq = false; // true -> chaine delimite par ' ou "
[2446]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 }
[2518]1173 p++; swq = true;
[2446]1174 }
1175 else {
1176 q = toks.find_first_of(" \t",p); // la fin du token;
1177 }
1178 string token = toks.substr(p,q-p);
[2518]1179 tokens.push_back(token);
1180 qottoks.push_back(swq);
1181 nw++;
[2446]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;
[2997]1194bool fgvarapp = false; // Si true, VarApp en priorite
[2446]1195
1196s2="";
1197p = 0;
1198l = s.length();
1199string vn, vv;
1200while (p < l) {
1201 iarr = -1;
[2997]1202 fgvarapp = false;
[2446]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++;
[2997]1233 fgvarapp = true;
[2446]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);
[2483]1251 if (!Var2Str(vn, vv)) return(5);
[2446]1252 vn = vv;
1253 q2++;
1254 }
1255 else {
[2779]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);
[2446]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;
[2483]1273 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
[2446]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 }
[2997]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) {
[2483]1295 if (!Var2Str(vn, vv)) return(5);
[2446]1296 s2 += (s.substr(p, q-p) + vv);
1297 p = q2;
1298 }
1299 else {
[2483]1300 if (! Var2Str(vn, iarr, vv) ) {
[2446]1301 cerr << " Substitution error - word index out of range in "
1302 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1303 return(4);
1304 }
[2483]1305 else s2 += (s.substr(p, q-p) + vv);
[2446]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-- */
[2483]1318bool Commander::Var2Str(string const & vn, string & vv)
[2446]1319{
1320if (vn.length() < 1) {
[2518]1321 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
[2446]1322 vv = ""; return(false);
1323}
1324// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1325int ka = 0;
[2483]1326char buff[32];
1327
[2446]1328if (vn == "#") {
1329 if (ArgsStack.empty()) {
[2518]1330 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
[2446]1331 << " ($" << vn << ")" << endl;
1332 vv = ""; return(false);
1333 }
1334 char buff[32];
1335 long an = ArgsStack.top().size();
[2518]1336 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
[2446]1337 sprintf(buff,"%ld", an);
1338 vv = buff; return(true);
1339}
[2518]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];
[3581]1347 for(unsigned int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
[2518]1348 return(true);
1349}
[2446]1350else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1351 if (ArgsStack.empty()) {
[2518]1352 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
[2446]1353 << " ($" << vn << ")" << endl;
1354 vv = ""; return(false);
1355 }
[3581]1356 if ( (ka < 0) || (ka >= (int)ArgsStack.top().size()) ) {
[2518]1357 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
[2446]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)
[2483]1364 CmdVarList::iterator it = variables.find(vn.substr(1));
1365 if (it == variables.end()) {
[2518]1366 cerr << " Commander::Var2Str/Error #vname Undefined variable "
[2446]1367 << vn << " ! " << endl;
1368 vv = ""; return(false);
1369 }
[2483]1370 sprintf(buff,"%d", (int)(*it).second.size());
[2446]1371 vv = buff; return(true);
[2483]1372}
1373else if (vn == "status") {
1374 sprintf(buff,"%d", _xstatus);
1375 vv = buff;
1376 return true;
1377}
[2518]1378else if ((vn == "retstr") || (vn == "retval")) {
[2483]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 {
[2518]1387 cerr << " Commander::Var2Str/Error Undefined variable "
[2446]1388 << vn << " ! " << endl;
[2483]1389 vv = ""; return false;
[2446]1390 }
1391}
1392
[2483]1393return false;
[2446]1394}
[2483]1395
[2446]1396/* --Methode-- */
[2483]1397bool Commander::SetVariable(string const & vn, string const & vv)
[2446]1398{
[2483]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);
[2446]1429 }
[2483]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 }
[2446]1441}
1442
1443/* --Methode-- */
[2483]1444bool Commander::GetVar(string const & vn, string & vv)
[2446]1445{
[2483]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) {
[3581]1453 for(unsigned int k=1; k<(*it).second.size(); k++) {
[2483]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;
[3581]1466 if ((idx < 0) || (idx > (int)(*it).second.size()-1))
[2483]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;
[2446]1488 return(false);
1489 }
[2483]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;
[2446]1500}
1501
1502/* --Methode-- */
[2483]1503bool Commander::SetVar(string const & vn, int idx, string const & val)
[2446]1504{
[2483]1505 if ( !CheckVarName(vn) ) {
1506 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
[2446]1507 return(false);
1508 }
[2483]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 {
[3581]1527 if (idx >= (int)(*it).second.size())
[2512]1528 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1529 (*it).second[idx] = val;
[2483]1530 fg = true;
1531 }
[2446]1532 return fg;
1533}
1534
1535/* --Methode-- */
[2483]1536bool Commander::SetVar(string const & vn, vector<string> const & val)
[2446]1537{
[2483]1538 if ( !CheckVarName(vn) ) {
1539 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
[2446]1540 return(false);
1541 }
[2483]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;
[2446]1555}
1556
1557/* --Methode-- */
[2483]1558bool Commander::CheckVarName(string const & vn)
[2446]1559{
[2483]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 ---- "
[2446]1585 << endl;
[2483]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 }
[2446]1592 cout << "---------------------------------------------------------- "
1593 << endl;
1594}
1595
1596/* --Methode-- */
[2483]1597bool Commander::GetVarApp(string const & vn, string & vv)
1598{
1599 vv = "";
[2518]1600 // cout << " Commander::GetVarApp() Not available ! " << endl;
[2483]1601 return false;
1602}
1603
1604/* --Methode-- */
1605bool Commander::SetVarApp(string const & vn, string const & vv)
1606{
[2518]1607 // cout << " Commander::SetVarApp() Not available ! " << endl;
[2483]1608 return false;
1609}
1610
1611/* --Methode-- */
1612bool Commander::DeleteVarApp(string const & vn)
1613{
[2518]1614 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
[2483]1615 return false;
1616}
1617
1618/* --Methode-- */
1619void Commander::ListVarApp()
1620{
[2518]1621 // cout << " Commander::ListVarApp() Not available ! " << endl;
[2483]1622 return;
1623}
1624
1625
1626/* --Methode-- */
1627bool Commander::GetVarEnv(string const & vn, string & vv)
1628{
[2518]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 }
[2483]1638}
1639
1640/* --Methode-- */
1641bool Commander::SetVarEnv(string const & vn, string const & vv)
1642{
[2518]1643 string pev = vn;
1644 pev += '=';
1645 pev += vv;
[2887]1646// if defined(Linux) || defined(AIX)
[2532]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 ?
[2867]1651// Idem AIX , Reza Dec 2005
[2887]1652// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1653// Je fais copie pour tout le monde
[2532]1654 char* bev = new char[pev.size()+1];
1655 strcpy(bev, pev.c_str());
1656 if (putenv(bev) == 0) return true;
[2887]1657// else
1658// if (putenv(pev.c_str()) == 0) return true;
1659// endif
[2518]1660 else return false;
[2483]1661}
1662
1663/* --Methode-- */
1664bool Commander::DeleteVarEnv(string const & vn)
1665{
[2518]1666 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
[2483]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-- */
[2446]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{
[2512]1722 // A virer - Reza 15/03/2004
[2446]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 }
[2518]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}
[2446]1775
1776else if (kw == "set") {
[2518]1777 if (tokens.size() < 2) {
1778 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1779 return(1);
1780 }
1781
[2483]1782 if (tokens.size() == 2)
1783 SetVariable(tokens[0], tokens[1]);
1784 else {
[2518]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);
[2446]1795 }
[2483]1796 return 0;
1797}
[2518]1798else if (kw == "var2words") {
1799 if (tokens.size() < 2) {
1800 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1801 return(1);
[2446]1802 }
[2518]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}
[2446]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;
[2518]1818 return(1);
[2483]1819 }
[2446]1820 string xx = tokens[1];
[3581]1821 for (unsigned int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
[2446]1822 mAliases[tokens[0]] = xx;
[2483]1823}
[2446]1824
[2483]1825else if ( (kw == "unset") || (kw == "clearvar") ) {
1826 if (tokens.size() < 1) {
1827 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
[2518]1828 return(1);
[2446]1829 }
[2483]1830 else DeleteVar(tokens[0]);
1831}
1832// Evaluation d'expression en notation polonaise inverse
[2512]1833else if (kw == "rpneval") {
1834 try {
1835 RPNExpressionEvaluator rpn(tokens, 1);
1836 double res = rpn.Value();
[3577]1837 string vv = cval_dble2str(res);
[2512]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 }
[2446]1846}
1847else if (kw == "echo") {
[3581]1848 for (unsigned int ii=0; ii<tokens.size(); ii++)
[2446]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;
[2518]1855 return(1);
[2446]1856 }
1857 ofstream ofs(tokens[0].c_str(), ios::app);
[3581]1858 for (unsigned int ii=1; ii<tokens.size(); ii++)
[2446]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
[2914]1873else if (kw == "listvars" || kw == "listvar") ListVar();
[2446]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}
[2671]1916//---------------------------------------------
1917//--- Commandes de gestion des threads ------
1918//---------------------------------------------
1919else if (kw == "thrlist") {
1920 ListThreads();
1921 return(0);
1922}
[2955]1923else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1924 if (tokens.size() < 1) {
1925 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1926 return(0);
1927 }
[2671]1928 uint_8 id = atol(tokens[0].c_str());
[2955]1929 bool fgkill = false;
1930 if (kw == "killthr") fgkill = true;
1931 StopThr(id, fgkill);
[2671]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
[2446]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") {
[3615]1958 AutoInitRand(1);
[2446]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;
[3581]1964 for (unsigned int ii=0; ii<tokens.size(); ii++)
[2446]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="";
[3581]1971 for(unsigned int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
[2446]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;
[2518]1987vector<bool> qottoks;
[2446]1988string kw, toks;
1989if (line.length() < 1) return(0);
[2518]1990LineToWords(line, kw, tokens, qottoks, toks, qw);
[2446]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 {
[2671]2001 if ((*it).second.cex) {
2002 // Doit-on l'executer sous forme de thread separe ?
[2956]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 }
[2671]2021 }
[2943]2022 else rc = (*it).second.cex->Execute(keyw, args, toks);
[2671]2023 }
[2446]2024 else cout << "Dont know how to execute " << keyw << " ? " << endl;
[2943]2025 }
[2446]2026 return(rc);
2027}
2028
2029/* --Methode-- */
2030int Commander::ExecFile(string& file, vector<string>& args)
2031{
[2856]2032char line_buff[1024];
[2446]2033FILE *fip;
[2518]2034int rcc = 0;
[2446]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;
[2856]2060while (fgets(line_buff,1023,fip) != NULL)
[2446]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);
[2518]2065 rcc = Interpret(line);
2066 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
[2446]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-- */
[2671]2083void Commander::ListThreads()
2084{
[2955]2085 cout << "--- Commander::ListThreads()- command execution threads NThread="
2086 << CmdThrExeList.size() << " ---" << endl;
[2671]2087 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2088 tit != CmdThrExeList.end(); tit++) {
2089 cout << "Id=" << (*tit)->Id();
[2955]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;
[2671]2096 }
2097}
2098/* --Methode-- */
[2955]2099void Commander::StopThr(uint_8 id, bool fgkill)
[2671]2100{
2101 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2102 tit != CmdThrExeList.end(); tit++) {
[2955]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 }
[2671]2112 return;
2113 }
2114 }
[2943]2115 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
[2671]2116}
2117
2118/* --Methode-- */
2119void Commander::CleanThrList()
2120{
2121 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2122 list<CommandExeThr *> thrcopie;
[2955]2123 int ncl = 0;
[2671]2124 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2125 tit != CmdThrExeList.end(); tit++) {
[2955]2126 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
[2671]2127 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2128 delete (*tit);
[2955]2129 ncl++;
[2671]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-- */
[2446]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{
[3581]2219 for(unsigned int k=0; k<prl.length(); k++)
[2446]2220 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2221}
[2466]2222
[2446]2223// Fonction qui remplace _ en \_
2224static string check_latex_underscore(string const & mot)
2225{
2226 string rs;
[3581]2227 for(unsigned int k=0; k<mot.length(); k++) {
[2466]2228 if (mot[k] == '_') rs += "\\_";
[2446]2229 else rs += mot[k];
2230 }
2231 return rs;
2232}
2233
2234/* --Methode-- */
[2943]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*/
[2446]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++) {
[2466]2306 gid = (*it).second.gid;
[2446]2307 if (gid == 0) continue;
2308 // fputs("\\begin{table}[h!] \n",fip);
2309 fputs("\\vspace{6mm} \n",fip);
2310 fputs("\\begin{center} \n ", fip);
[2466]2311 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
[2446]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++) {
[2466]2347 gid = (*it).second.gid;
[2446]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());
[2466]2352 if ((*it).second.desc.length() > 0)
2353 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
[2446]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);
[2466]2378cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2379
[2446]2380return;
2381}
2382
2383
[2483]2384} // End of namespace SOPHYA
[2446]2385
Note: See TracBrowser for help on using the repository browser.