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

Last change on this file since 3383 was 3383, checked in by ansari, 18 years ago

Correction probleme (exception substring) pour lors du traitement de chaine contenant uniquement des espaces ds Commander::Interpret() - Reza 18/11/2007

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