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

Last change on this file since 3577 was 3577, checked in by ansari, 17 years ago

amelioration format conversion double->string pour eviter perte de precision lors des evaluations avec l'interpreteur (Commander) - Reza 19/02/2008

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