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

Last change on this file since 3274 was 2997, checked in by ansari, 19 years ago

Mise en place priorite d'acces variables application AppVar() ds commander
si specifie sous forme ${varname} - Reza 2/7/2006

File size: 65.9 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 (s[lnb] == '\\' ) { // Lignes suite ...
780 mulinecmd += s.substr(0,lnb);
781 if (!mulinefg) {
782 spromptmul = GetCurrentPrompt();
783 SetCurrentPrompt("...? ");
784 mulinefg = true;
785 }
786 return(0);
787}
788
789if (mulinefg) { // Il y avait des lignes suite
790 s = mulinecmd + s;
791 l = s.length();
792 mulinecmd = "";
793 mulinefg = false;
794 SetCurrentPrompt(spromptmul);
795}
796
797// Removing leading blanks
798size_t p,q;
799
800// On enleve le dernier caractere, si celui-ci est \n
801if (s[l-1] == '\n') s[l-1] = '\0';
802p=s.find_first_not_of(" \t");
803if (p < l) s = s.substr(p);
804// >>>> Substitution d'alias (1er mot)
805CmdStrList::iterator it;
806p = 0;
807q = s.find_first_of(" \t");
808l = s.length();
809string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p);
810it = mAliases.find(w1);
811if (it != mAliases.end()) {
812 s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ;
813 l = s.length();
814 p=s.find_first_not_of(" \t");
815 if (p < l) s = s.substr(p);
816 p = 0;
817 q = s.find_first_of(" ");
818 }
819
820// >>>> Separating keyword
821string toks,kw;
822if (q < l)
823 { kw = s.substr(p,q-p); toks = s.substr(q, l-q); }
824else { kw = s.substr(p,l-p); toks = ""; }
825
826// les mot-cle end else endif doivent etre le seul mot de la ligne
827if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
828 size_t ltk = toks.length();
829 if (toks.find_first_not_of(" \t") < ltk) {
830 cerr << "Commander::Interpret()/syntax error near end else endif endscript \n"
831 << "line: " << s << endl;
832 _xstatus = 91;
833 return(91);
834 }
835}
836
837// On verifie si on est en train de definir un script
838if (curscript) {
839 if (kw == "endscript") {
840 if (curscript->CheckScript()) {
841 sit = mScripts.find(curscript->Name());
842 if (sit != mScripts.end()) {
843 cout << "Commander::Interpret() replacing script "
844 << curscript->Name() << endl;
845 CommanderScript* scr = mScripts[curscript->Name()];
846 mScripts.erase(sit);
847 delete scr;
848 }
849 cout << "Commander::Interpret() Script " << curscript->Name()
850 << " defined successfully" << endl;
851 mScripts[curscript->Name()] = curscript;
852 SetCurrentPrompt("Cmd> ");
853 curscript = NULL;
854 _xstatus = 0;
855 return(0);
856 }
857 else {
858 cout << "Commander::Interpret() Error in Script " << curscript->Name()
859 << " definition " << endl;
860 SetCurrentPrompt("Cmd> ");
861 curscript = NULL;
862 _xstatus = 92;
863 return(92);
864 }
865 }
866 else curscript->AddLine(s, kw);
867 _xstatus = 0;
868 return(0);
869}
870// On verifie si nous sommes dans un bloc (for , foreach)
871if (CmdBlks.top() != NULL) { // On est dans un bloc
872 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel++;
873 else if (kw == "end") felevel--;
874
875 int rcbex = 0;
876 if (felevel == 0) { // Il faut executer le bloc
877 CommanderBloc* curb = CmdBlks.top();
878 CmdBlks.top() = curb->Parent();
879 SetCurrentPrompt("Cmd> ");
880 if (!curb->CheckBloc()) {
881 cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
882 << " within for/foreach/forinfile bloc ! " << endl;
883 delete curb;
884 _xstatus = 93;
885 return(93);
886 }
887 // cout << " *DBG* Executing bloc " << endl;
888 bool ohv = histon;
889 histon = false;
890 if (curtestresult) {
891 // We push also CommanderBloc and testresult on the stack
892 CmdBlks.push(NULL);
893 list<char> xtx;
894 TestsStack.push(xtx);
895 rcbex = curb->Execute();
896 // And CommanderBloc and TestResult from the corresponding stacks
897 PopStack(false);
898 }
899 SetCurrentPrompt(defprompt);
900 delete curb;
901 histon = ohv;
902 }
903 else CmdBlks.top()->AddLine(s, kw);
904 _xstatus = rcbex;
905 return(rcbex);
906}
907else if (kw == "end") {
908 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
909 << "line: " << s << endl;
910 _xstatus = 94;
911 return(94);
912}
913
914// Sommes-nous dans un bloc de test if then else
915if (TestsStack.top().size() > 0) { // Nous sommes ds un bloc if
916 if (kw == "else") {
917 if ((*tresit) & 2) {
918 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
919 << "line: " << s << endl;
920 _xstatus = 95;
921 return(95);
922 }
923 else {
924 const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
925 if ((*tresit)&1) curtestresult = false;
926 SetCurrentPrompt(npr);
927 (*tresit) |= 2;
928 _xstatus = 0;
929 return(0);
930 }
931 }
932 else if (kw == "endif") {
933 list<char>::iterator dbit = tresit;
934 tresit--;
935 TestsStack.top().erase(dbit);
936 const char * npr = "Cmd> ";
937 if (TestsStack.top().size() > 1) {
938 curtestresult = true;
939 list<char>::iterator it;
940 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
941 // Si on n'est pas ds le else et le if est faux
942 if ( !((*it)&2) && !((*it)&1) ) curtestresult = false;
943 // Si on est ds else et le if etait vrai !
944 if ( ((*it)&2) && ((*it)&1) ) curtestresult = false;
945 if (!curtestresult) break;
946 }
947
948 if (!((*tresit)&2))
949 npr = ((*tresit)&1) ? "if-T> " : "if-F> ";
950 else
951 npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
952 }
953 else curtestresult = true;
954 SetCurrentPrompt(npr);
955 _xstatus = 0;
956 return(0);
957 }
958}
959else if ((kw == "else") || (kw == "endif")) {
960 cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
961 << "line: " << s << endl;
962 _xstatus = 91;
963 return(91);
964}
965
966bool fgcont = true;
967if (TestsStack.top().size() > 0) { // Resultat de if ou else
968 list<char>::iterator it;
969 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
970 // Si on n'est pas ds le else et le if est faux
971 if ( !((*it)&2) && !((*it)&1) ) fgcont = false;
972 // Si on est ds else et le if etait vrai !
973 if ( ((*it)&2) && ((*it)&1) ) fgcont = false;
974 if (!fgcont) break;
975 }
976}
977
978if ((!fgcont) && (kw != "if")) {
979 _xstatus = 0;
980 return(0);
981}
982
983
984// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
985if (kw == "break") return CMD_BREAK_RC;
986else if (kw == "return") {
987 _retstr = toks;
988 return CMD_RETURN_RC;
989}
990
991// Nous ne sommes donc pas dans un bloc .... Substitution de variables
992string s2;
993int rcs ;
994
995rcs = SubstituteVars(s, s2);
996if (rcs) {
997 cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n"
998 << "line: " << s << endl;
999 _xstatus = 99;
1000 return(99);
1001}
1002// >>>> Separating keyword and tokens
1003vector<string> tokens;
1004vector<bool> qottoks;
1005/* decoupage en mots */
1006LineToWords(s2, kw, tokens, qottoks, toks, true);
1007
1008// Si c'est un for/foreach, on cree un nouveau bloc
1009if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
1010 // cout << " *DBG* We got a foreach... " << endl;
1011 CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens);
1012 if (!bloc->CheckOK()) {
1013 cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl;
1014 delete bloc;
1015 _xstatus = 91;
1016 return(91);
1017 }
1018 felevel++;
1019 if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc);
1020 else SetCurrentPrompt("for...> ");
1021 CmdBlks.top() = bloc;
1022 // cout << " *DBG* New Bloc created ... " << endl;
1023 return(0);
1024 }
1025else if (kw == "if") { // Un test if
1026 bool restst = true;
1027 int rct = EvaluateTest(tokens, s, restst);
1028 if (rct) {
1029 cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl;
1030 _xstatus = 91;
1031 return(91);
1032 }
1033 char res_tst = (restst) ? 1 : 0;
1034 TestsStack.top().push_back(res_tst);
1035 if (TestsStack.top().size() == 1) tresit = TestsStack.top().begin();
1036 else tresit++;
1037 const char * npr = (restst) ? "if-T> " : "if-F> ";
1038 SetCurrentPrompt(npr);
1039}
1040else if ((tokens.size() > 0) && (tokens[0] == "=")) {
1041 // x = Expression
1042 if (qottoks[1]) { // decodage sous forme de chaine
1043 SetVariable(kw, tokens[1]);
1044 }
1045 else {
1046 try {
1047 double res = 0.;
1048 if (tokens.size() > 2) {
1049 string sex = tokens[1];
1050 for(int js=2; js<tokens.size(); js++) sex += tokens[js];
1051 CExpressionEvaluator cex(sex);
1052 res = cex.Value();
1053 }
1054 else {
1055 CExpressionEvaluator cex(tokens[1]);
1056 res = cex.Value();
1057 }
1058 char cbuff[64];
1059 sprintf(cbuff,"%g",res);
1060 string vv = cbuff;
1061 SetVariable(kw, vv);
1062 }
1063 catch (CExprException& cexerr) {
1064 cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s
1065 << " \n Msg=" << cexerr.Msg() << endl;
1066 _xstatus = 98;
1067 return(98);
1068 }
1069 }
1070}
1071else if (kw == "defscript") { // definition de script
1072 if (tokens.size() > 0) {
1073 if (tokens.size() < 2) tokens.push_back("");
1074 curscript = new CommanderScript(this, tokens[0], tokens[1]);
1075 SetCurrentPrompt("Script...> ");
1076 return(0);
1077 }
1078 else {
1079 cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl;
1080 _xstatus = 91;
1081 return(91);
1082 }
1083}
1084else {
1085 // Si c'est le nom d'un script
1086 sit = mScripts.find(kw);
1087 if (sit != mScripts.end()) {
1088 bool ohv = histon;
1089 histon = false;
1090 tokens.insert(tokens.begin(), kw);
1091 PushStack(tokens);
1092 (*sit).second->Execute(tokens);
1093 PopStack(true);
1094 histon = ohv;
1095 }
1096 // Execution de commandes
1097 else rc = ExecuteCommandLine(kw, tokens, toks);
1098 _xstatus = rc;
1099 return(rc);
1100}
1101// cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
1102// for(int ii=0; ii<tokens.size(); ii++)
1103// cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
1104
1105return(0);
1106}
1107
1108//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
1109void Commander::StopExecution()
1110{
1111 fgexebrk = true;
1112}
1113
1114
1115/* --Methode-- */
1116int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
1117 vector<bool>& qottoks, string& toks, bool uq)
1118{
1119if (line.length() < 1) return(0);
1120int nw = 1;
1121size_t p = line.find_first_not_of(" ");
1122line = line.substr(p);
1123p = 0;
1124size_t q = line.find_first_of(" ");
1125size_t l = line.length();
1126
1127if (q < l)
1128 { kw = line.substr(p,q-p); toks = line.substr(q, l-q); }
1129else { kw = line.substr(p,l-p); toks = ""; }
1130
1131q = 0;
1132while (q < l) {
1133 bool swq = false; // true -> chaine delimite par ' ou "
1134 p = toks.find_first_not_of(" \t",q+1); // au debut d'un token
1135 if (p>=l) break;
1136 if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) {
1137 q = toks.find(toks[p],p+1);
1138 if (q>=l) {
1139 cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl;
1140 return(-1);
1141 }
1142 p++; swq = true;
1143 }
1144 else {
1145 q = toks.find_first_of(" \t",p); // la fin du token;
1146 }
1147 string token = toks.substr(p,q-p);
1148 tokens.push_back(token);
1149 qottoks.push_back(swq);
1150 nw++;
1151 }
1152
1153return(nw);
1154}
1155
1156/* --Methode-- */
1157int Commander::SubstituteVars(string & s, string & s2)
1158// Variable substitution
1159{
1160
1161int iarr = -1; // index d'element de tableau
1162size_t p,q,q2,q3,l;
1163bool fgvarapp = false; // Si true, VarApp en priorite
1164
1165s2="";
1166p = 0;
1167l = s.length();
1168string vn, vv;
1169while (p < l) {
1170 iarr = -1;
1171 fgvarapp = false;
1172 q = s.find('$',p);
1173 if (q > l) break;
1174 q2 = s.find('\'',p);
1175 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
1176 q2 = s.find('\'',q2+1);
1177 if (q2 >= l) {
1178 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
1179 return(1);
1180 }
1181 s2 += s.substr(p, q2-p+1);
1182 p = q2+1; continue;
1183 }
1184 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
1185 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
1186 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
1187 continue;
1188 }
1189 if (q >= l-1) {
1190 cerr << " Syntax error - line ending with $ !!! " << endl;
1191 return(2);
1192 }
1193 vn = "";
1194 if ( s[q+1] == '{' ) { // Variable in the form ${name}
1195 q2 = s.find('}',q+1);
1196 if (q2 >= l) {
1197 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
1198 return(3);
1199 }
1200 vn = s.substr(q+2,q2-q-2);
1201 q2++;
1202 fgvarapp = true;
1203 }
1204 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
1205 q2 = s.find(')',q+1);
1206 if (q2 >= l) {
1207 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
1208 return(3);
1209 }
1210 vn = s.substr(q+2,q2-q-2);
1211 q2++;
1212 }
1213 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
1214 q2 = s.find(']',q+1);
1215 if (q2 >= l) {
1216 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
1217 return(4);
1218 }
1219 vn = s.substr(q+2,q2-q-2);
1220 if (!Var2Str(vn, vv)) return(5);
1221 vn = vv;
1222 q2++;
1223 }
1224 else {
1225 if (s[q+1] == '#' ) q3 = q+2; // Variable in the form $#varname
1226 else q3 = q+1;
1227 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'<>^%=#@\\",q3);
1228 if (q2 > l) q2 = l;
1229 q3 = q2;
1230 vn = s.substr(q+1, q2-q-1);
1231 // Si variable de type $varname[index] : element de tableau
1232 if ((q2 < l) && (s[q2] == '[') ) {
1233 q3 = s.find_first_of("]",q2+1);
1234 string sia = s.substr(q2+1, q3-q2-1);
1235 if (sia.length() < 1) {
1236 cerr << " Syntax error - in $varname[index] : $"
1237 << vn << "[" << sia <<"]" << endl;
1238 return(4);
1239 }
1240 if (isalpha(sia[0])) {
1241 string sia2;
1242 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1243 cerr << " Syntax error - in $varname[index] : $"
1244 << vn << "[" << sia <<"]" << endl;
1245 return(4);
1246 }
1247 sia = sia2;
1248 }
1249 int rcdia = ctoi(sia.c_str(), &iarr);
1250 if (rcdia < 0) {
1251 cerr << " Syntax error - in $varname[iarr] : $"
1252 << vn << "[" << sia <<"]" << endl;
1253 return(4);
1254 }
1255 }
1256 }
1257 if (fgvarapp) {
1258 if (!GetVarApp(vn, vv))
1259 if (!Var2Str(vn, vv)) return(5);
1260 s2 += (s.substr(p, q-p) + vv);
1261 p = q2;
1262 }
1263 else if (iarr < 0) {
1264 if (!Var2Str(vn, vv)) return(5);
1265 s2 += (s.substr(p, q-p) + vv);
1266 p = q2;
1267 }
1268 else {
1269 if (! Var2Str(vn, iarr, vv) ) {
1270 cerr << " Substitution error - word index out of range in "
1271 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1272 return(4);
1273 }
1274 else s2 += (s.substr(p, q-p) + vv);
1275 p = q3+1;
1276 }
1277}
1278if (p < l) s2 += s.substr(p);
1279
1280p = s2.find_first_not_of(" \t");
1281if (p < l) s2 = s2.substr(p);
1282
1283return(0);
1284}
1285
1286/* --Methode-- */
1287bool Commander::Var2Str(string const & vn, string & vv)
1288{
1289if (vn.length() < 1) {
1290 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
1291 vv = ""; return(false);
1292}
1293// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1294int ka = 0;
1295char buff[32];
1296
1297if (vn == "#") {
1298 if (ArgsStack.empty()) {
1299 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1300 << " ($" << vn << ")" << endl;
1301 vv = ""; return(false);
1302 }
1303 char buff[32];
1304 long an = ArgsStack.top().size();
1305 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
1306 sprintf(buff,"%ld", an);
1307 vv = buff; return(true);
1308}
1309else if (vn == "*") {
1310 if (ArgsStack.empty()) {
1311 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1312 << " ($" << vn << ")" << endl;
1313 vv = ""; return(false);
1314 }
1315 vv = ArgsStack.top()[0];
1316 for(int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
1317 return(true);
1318}
1319else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1320 if (ArgsStack.empty()) {
1321 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1322 << " ($" << vn << ")" << endl;
1323 vv = ""; return(false);
1324 }
1325 if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
1326 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
1327 << " ($" << vn << ")" << endl;
1328 vv = ""; return(false);
1329 }
1330 vv = ArgsStack.top()[ka]; return(true);
1331}
1332else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
1333 CmdVarList::iterator it = variables.find(vn.substr(1));
1334 if (it == variables.end()) {
1335 cerr << " Commander::Var2Str/Error #vname Undefined variable "
1336 << vn << " ! " << endl;
1337 vv = ""; return(false);
1338 }
1339 sprintf(buff,"%d", (int)(*it).second.size());
1340 vv = buff; return(true);
1341}
1342else if (vn == "status") {
1343 sprintf(buff,"%d", _xstatus);
1344 vv = buff;
1345 return true;
1346}
1347else if ((vn == "retstr") || (vn == "retval")) {
1348 vv = _retstr;
1349 return true;
1350}
1351else { // Variable de l'interpreteur, ou de l'environnement application , env. global
1352 if (GetVar(vn, vv)) return true;
1353 else if (GetVarApp(vn, vv)) return true;
1354 else if (GetVarEnv(vn, vv)) return true;
1355 else {
1356 cerr << " Commander::Var2Str/Error Undefined variable "
1357 << vn << " ! " << endl;
1358 vv = ""; return false;
1359 }
1360}
1361
1362return false;
1363}
1364
1365/* --Methode-- */
1366bool Commander::SetVariable(string const & vn, string const & vv)
1367{
1368 // On verifie si le nom est de type vname[idx]
1369 size_t p,q,l;
1370 l = vn.length();
1371 p = vn.find('[');
1372 if (p < l) {
1373 q = vn.find(']');
1374 if (q != (l-1)) {
1375 cout << "Commander::Str2Var/SetVar() - Bad varname with []: "
1376 << vn << endl;
1377 return false;
1378 }
1379 string vna = vn.substr(0, p);
1380 string sia = vn.substr(p+1, q-(p+1));
1381 if (isalpha(sia[0])) {
1382 string sia2;
1383 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1384 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:"
1385 << vn << endl;
1386 return false;
1387 }
1388 sia = sia2;
1389 }
1390 int iarr;
1391 int rcdia = ctoi(sia.c_str(), &iarr);
1392 if (rcdia < 0) {
1393 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: "
1394 << vn << endl;
1395 return false;
1396 }
1397 return SetVar(vna, iarr, vv);
1398 }
1399 else {
1400 if (vn == "status") {
1401 _xstatus = atoi(vv.c_str());
1402 return true;
1403 }
1404 else if (vn == "retstr") {
1405 _retstr = vv;
1406 return true;
1407 }
1408 else return SetVar(vn, vv);
1409 }
1410}
1411
1412/* --Methode-- */
1413bool Commander::GetVar(string const & vn, string & vv)
1414{
1415 CmdVarList::iterator it = variables.find(vn);
1416 if (it == variables.end()) {
1417 vv = "";
1418 return false;
1419 }
1420 vv = (*it).second[0];
1421 if ((*it).second.size() > 1) {
1422 for(int k=1; k<(*it).second.size(); k++) {
1423 vv += ' '; vv += (*it).second[k];
1424 }
1425 }
1426 return true;
1427}
1428
1429/* --Methode-- */
1430bool Commander::GetVar(string const & vn, int idx, string & vv)
1431{
1432 vv = "";
1433 CmdVarList::iterator it = variables.find(vn);
1434 if (it == variables.end()) return false;
1435 if ((idx < 0) || (idx > (*it).second.size()-1))
1436 return false;
1437 vv = (*it).second[idx];
1438 return true;
1439}
1440
1441/* --Methode-- */
1442bool Commander::GetVar(string const & vn, vector<string> & vv)
1443{
1444 vv.clear();
1445 // vv.erase(vv.begin(),vv.end());
1446 CmdVarList::iterator it = variables.find(vn);
1447 if (it == variables.end()) return false;
1448 vv = (*it).second;
1449 return true;
1450}
1451
1452/* --Methode-- */
1453bool Commander::SetVar(string const & vn, string const & val)
1454{
1455 if ( !CheckVarName(vn) ) {
1456 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1457 return(false);
1458 }
1459 bool fg = false;
1460 vector<string> nouv;
1461 nouv.push_back(val);
1462 CmdVarList::iterator it = variables.find(vn);
1463 if (it == variables.end()) variables[vn] = nouv;
1464 else {
1465 (*it).second = nouv;
1466 fg = true;
1467 }
1468 return fg;
1469}
1470
1471/* --Methode-- */
1472bool Commander::SetVar(string const & vn, int idx, string const & val)
1473{
1474 if ( !CheckVarName(vn) ) {
1475 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
1476 return(false);
1477 }
1478 if ((vn == "status") || (vn == "retstr")) {
1479 cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr "
1480 << endl;
1481 return(false);
1482 }
1483 if (idx < 0) {
1484 cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl;
1485 return(false);
1486 }
1487 bool fg = false;
1488 CmdVarList::iterator it = variables.find(vn);
1489 if (it == variables.end()) {
1490 vector<string> nouv;
1491 for(int j=0; j<idx; j++) nouv.push_back("");
1492 nouv.push_back(val);
1493 variables[vn] = nouv;
1494 }
1495 else {
1496 if (idx >= (*it).second.size())
1497 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1498 (*it).second[idx] = val;
1499 fg = true;
1500 }
1501 return fg;
1502}
1503
1504/* --Methode-- */
1505bool Commander::SetVar(string const & vn, vector<string> const & val)
1506{
1507 if ( !CheckVarName(vn) ) {
1508 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1509 return(false);
1510 }
1511 if ((vn == "status") || (vn == "retstr")) {
1512 cerr << "Commander::SetVar(vn, vector<string>) ERROR - special var status/retstr "
1513 << endl;
1514 return(false);
1515 }
1516 bool fg = false;
1517 CmdVarList::iterator it = variables.find(vn);
1518 if (it == variables.end()) variables[vn] = val;
1519 else {
1520 (*it).second = val;
1521 fg = true;
1522 }
1523 return fg;
1524}
1525
1526/* --Methode-- */
1527bool Commander::CheckVarName(string const & vn)
1528{
1529 size_t l,k;
1530 l = vn.length();
1531 if (l < 1) return false;
1532 if (!isalpha(vn[0])) return false;
1533 for(k=1; k<l; k++)
1534 if ((!isalnum(vn[k])) && (vn[k] != '_')) return false;
1535 return true;
1536}
1537
1538/* --Methode-- */
1539bool Commander::DeleteVar(string const & vn)
1540{
1541 CmdVarList::iterator it = variables.find(vn);
1542 if (it == variables.end()) {
1543 cerr << "Commander::DeleteVar() Var " << vn << " undefined!" << endl;
1544 return false;
1545 }
1546 variables.erase(it);
1547 return true;
1548}
1549
1550/* --Methode-- */
1551void Commander::ListVar()
1552{
1553 cout << " ---- Commander::ListVar() List of defined variables ---- "
1554 << endl;
1555 CmdVarList::iterator it;
1556 for(it = variables.begin(); it != variables.end(); it++) {
1557 string vn = (*it).first;
1558 int vs = (*it).second.size();
1559 cout << vn << " -> Size= " << vs << endl;
1560 }
1561 cout << "---------------------------------------------------------- "
1562 << endl;
1563}
1564
1565/* --Methode-- */
1566bool Commander::GetVarApp(string const & vn, string & vv)
1567{
1568 vv = "";
1569 // cout << " Commander::GetVarApp() Not available ! " << endl;
1570 return false;
1571}
1572
1573/* --Methode-- */
1574bool Commander::SetVarApp(string const & vn, string const & vv)
1575{
1576 // cout << " Commander::SetVarApp() Not available ! " << endl;
1577 return false;
1578}
1579
1580/* --Methode-- */
1581bool Commander::DeleteVarApp(string const & vn)
1582{
1583 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
1584 return false;
1585}
1586
1587/* --Methode-- */
1588void Commander::ListVarApp()
1589{
1590 // cout << " Commander::ListVarApp() Not available ! " << endl;
1591 return;
1592}
1593
1594
1595/* --Methode-- */
1596bool Commander::GetVarEnv(string const & vn, string & vv)
1597{
1598 char* vev = getenv(vn.c_str());
1599 if (vev) {
1600 vv = vev;
1601 return true;
1602 }
1603 else {
1604 vv = "";
1605 return false;
1606 }
1607}
1608
1609/* --Methode-- */
1610bool Commander::SetVarEnv(string const & vn, string const & vv)
1611{
1612 string pev = vn;
1613 pev += '=';
1614 pev += vv;
1615// if defined(Linux) || defined(AIX)
1616// Reza - 28/04/2004
1617// putenv de Linux ne declare pas la variable char *string const
1618// On ne doit meme pas utiliser une variable automatique
1619// J'alloue donc un nouveau tableau - mais qui va le liberer ?
1620// Idem AIX , Reza Dec 2005
1621// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1622// Je fais copie pour tout le monde
1623 char* bev = new char[pev.size()+1];
1624 strcpy(bev, pev.c_str());
1625 if (putenv(bev) == 0) return true;
1626// else
1627// if (putenv(pev.c_str()) == 0) return true;
1628// endif
1629 else return false;
1630}
1631
1632/* --Methode-- */
1633bool Commander::DeleteVarEnv(string const & vn)
1634{
1635 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
1636 return false;
1637}
1638
1639/* --Methode-- */
1640void Commander::ListVarEnv()
1641{
1642 cout << " Commander::ListVarEnv() Not available ! " << endl;
1643 return;
1644}
1645
1646
1647/* --Methode-- */
1648string Commander::GetTmpDir()
1649{
1650 return("/tmp");
1651}
1652
1653/* --Methode-- */
1654void Commander::SetCurrentPrompt(const char* pr)
1655{
1656 curprompt = pr;
1657}
1658
1659/* --Methode-- */
1660void Commander::ShowMessage(const char * msg, int att)
1661{
1662 cout << msg ;
1663}
1664
1665
1666
1667/* --Methode-- */
1668int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1669{
1670 res = true;
1671 if ((args.size() != 6) || (args[5] != "then") ||
1672 (args[0] != "(") || (args[4] != ")") ) return(1);
1673 if (args[2] == "==") res = (args[1] == args[3]);
1674 else if (args[2] == "!=") res = (args[1] != args[3]);
1675 else if (args[2] == "<")
1676 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1677 else if (args[2] == ">")
1678 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1679 else if (args[2] == "<=")
1680 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1681 else if (args[2] == ">=")
1682 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1683 else return(2);
1684 return(0);
1685}
1686
1687
1688/* --Methode-- */
1689int Commander::EvalRPNExpr(vector<string> & args, string & line)
1690{
1691 // A virer - Reza 15/03/2004
1692 return(0);
1693}
1694
1695/* --Methode-- */
1696void Commander::PushStack(vector<string>& args)
1697{
1698 // We push the argument list (args) on the stack
1699 ArgsStack.push(args);
1700 // We push also CommanderBloc and testresult on the stack
1701 CmdBlks.push(NULL);
1702 list<char> xtx;
1703 TestsStack.push(xtx);
1704
1705}
1706
1707/* --Methode-- */
1708void Commander::PopStack(bool psta)
1709{
1710 // We remove the argument list (args) from the stack
1711 if (psta) ArgsStack.pop();
1712 // And CommanderBloc and TestResult from the corresponding stacks
1713 CommanderBloc* curb = CmdBlks.top();
1714 while (curb != NULL) {
1715 CommanderBloc* parb = curb->Parent();
1716 delete curb; curb = parb;
1717 }
1718 CmdBlks.pop();
1719 TestsStack.pop();
1720}
1721
1722/* --Methode-- */
1723int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1724{
1725int rc = 0;
1726
1727// >>>>>>>>>>> Commande d'interpreteur
1728if (kw == "help") {
1729 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1730 else {
1731 string kwh = "Commander";
1732 cout << GetUsage(kwh) << endl;
1733 }
1734 }
1735else if (kw == "sleep") {
1736 if (tokens.size() < 1) {
1737 cout << "Commander::Interpret() Usage: sleep nsec " << endl;
1738 return(1);
1739 }
1740 int nsec = atoi(tokens[0].c_str());
1741 cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl;
1742 sleep(nsec);
1743}
1744
1745else if (kw == "set") {
1746 if (tokens.size() < 2) {
1747 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1748 return(1);
1749 }
1750
1751 if (tokens.size() == 2)
1752 SetVariable(tokens[0], tokens[1]);
1753 else {
1754 if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
1755 cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;
1756 return(1);
1757 }
1758 string vname = tokens[0];
1759 vector<string>::iterator vit;
1760 vit = tokens.begin(); tokens.erase(vit);
1761 vit = tokens.begin(); tokens.erase(vit);
1762 tokens.pop_back();
1763 SetVar(vname, tokens);
1764 }
1765 return 0;
1766}
1767else if (kw == "var2words") {
1768 if (tokens.size() < 2) {
1769 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1770 return(1);
1771 }
1772 char sep = ' ';
1773 if (tokens.size() > 2) sep = tokens[2][0];
1774 string vv;
1775 if (!GetVar(tokens[0], vv)) {
1776 cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl;
1777 return 2;
1778 }
1779 vector<string> vs;
1780 FillVStringFrString(vv, vs, sep);
1781 SetVar(tokens[1], vs);
1782}
1783else if (kw == "alias") {
1784 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1785 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1786 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
1787 return(1);
1788 }
1789 string xx = tokens[1];
1790 for (int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1791 mAliases[tokens[0]] = xx;
1792}
1793
1794else if ( (kw == "unset") || (kw == "clearvar") ) {
1795 if (tokens.size() < 1) {
1796 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
1797 return(1);
1798 }
1799 else DeleteVar(tokens[0]);
1800}
1801// Evaluation d'expression en notation polonaise inverse
1802else if (kw == "rpneval") {
1803 try {
1804 RPNExpressionEvaluator rpn(tokens, 1);
1805 double res = rpn.Value();
1806 char cbuff[64];
1807 sprintf(cbuff,"%g",res);
1808 string vv = cbuff;
1809 SetVariable(tokens[0],vv);
1810 return 0;
1811 }
1812 catch (RPNExprException& rpnerr) {
1813 cerr << " rpneval: Syntax error - Msg=" << rpnerr.Msg()
1814 << " \n Line=" << toks << endl;
1815 return 98;
1816 }
1817}
1818else if (kw == "echo") {
1819 for (int ii=0; ii<tokens.size(); ii++)
1820 cout << tokens[ii] << " " ;
1821 cout << endl;
1822 }
1823else if (kw == "echo2file") {
1824 if (tokens.size() < 1) {
1825 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
1826 return(1);
1827 }
1828 ofstream ofs(tokens[0].c_str(), ios::app);
1829 for (int ii=1; ii<tokens.size(); ii++)
1830 ofs << tokens[ii] << " " ;
1831 ofs << endl;
1832 }
1833else if (kw == "readstdin") {
1834 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1835 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1836 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1837 return(0);
1838 }
1839 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1840 cout << tokens[0] << " ? " << endl;
1841 SetVar(tokens[0], GetStringFrStdin(this) );
1842 }
1843
1844else if (kw == "listvars" || kw == "listvar") ListVar();
1845else if (kw == "listalias") {
1846 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1847 CmdStrList::iterator it;
1848 for(it = mAliases.begin(); it != mAliases.end(); it++)
1849 cout << (*it).first << " = " << (*it).second << "\n";
1850 cout << endl;
1851 }
1852else if (kw == "listcommands") {
1853 cout << "---- Commander::Interpret() Command List ----- \n";
1854 CmdExmap::iterator it;
1855 int kc = 0;
1856 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1857 cout << (*it).first << " ";
1858 kc++;
1859 if (kc >= 5) { cout << "\n"; kc = 0; }
1860 }
1861 cout << endl;
1862 }
1863else if (kw == "listscripts") {
1864 cout << "---- Commander::Interpret() Script List ----- \n";
1865 for(ScriptList::iterator sit = mScripts.begin();
1866 sit != mScripts.end(); sit++)
1867 cout << " Script: " << (*sit).second->Name() << " - "
1868 << (*sit).second->Comment() << endl;
1869}
1870else if (kw == "clearscript") {
1871 if (tokens.size() < 1) {
1872 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1873 return(0);
1874 }
1875 ScriptList::iterator sit = mScripts.find(tokens[0]);
1876 if (sit == mScripts.end()) {
1877 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1878 return(0);
1879 }
1880 else {
1881 delete (*sit).second;
1882 mScripts.erase(sit);
1883 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1884 return(0);
1885 }
1886}
1887//---------------------------------------------
1888//--- Commandes de gestion des threads ------
1889//---------------------------------------------
1890else if (kw == "thrlist") {
1891 ListThreads();
1892 return(0);
1893}
1894else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1895 if (tokens.size() < 1) {
1896 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1897 return(0);
1898 }
1899 uint_8 id = atol(tokens[0].c_str());
1900 bool fgkill = false;
1901 if (kw == "killthr") fgkill = true;
1902 StopThr(id, fgkill);
1903 return (0);
1904}
1905else if (kw == "waitthr") {
1906 WaitThreads();
1907 return (0);
1908}
1909else if (kw == "cleanthrlist") {
1910 CleanThrList();
1911 return (0);
1912}
1913
1914else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1915else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1916else if (kw == "timingon") {
1917 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1918 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1919 }
1920else if (kw == "timingoff") {
1921 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1922 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1923 }
1924else if (kw == "exec") {
1925 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1926 ExecFile(tokens[0], tokens);
1927 }
1928else if (kw == "autoiniranf") {
1929 Auto_Ini_Ranf(1);
1930 return(0);
1931}
1932else if (kw == "shell") {
1933 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1934 string cmd;
1935 for (int ii=0; ii<tokens.size(); ii++)
1936 cmd += (tokens[ii] + ' ');
1937 system(cmd.c_str());
1938 }
1939else if (kw == "cshell") {
1940 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1941 string cmd="";
1942 for(int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
1943 CShellExecute(cmd);
1944 }
1945
1946// Execution d'une commande enregistree
1947else rc = ExecuteCommand(kw, tokens, toks);
1948
1949if (timing) gltimer->Split();
1950return(rc);
1951}
1952
1953/* --Methode-- */
1954int Commander::ParseLineExecute(string& line, bool qw)
1955 // Si qw == true, on decoupe entre '' ou "" ou espaces
1956{
1957vector<string> tokens;
1958vector<bool> qottoks;
1959string kw, toks;
1960if (line.length() < 1) return(0);
1961LineToWords(line, kw, tokens, qottoks, toks, qw);
1962return(ExecuteCommand(kw, tokens, toks));
1963}
1964
1965/* --Methode-- */
1966int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
1967{
1968 int rc = -1;
1969 CmdExmap::iterator it = cmdexmap.find(keyw);
1970 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
1971 else {
1972 if ((*it).second.cex) {
1973 // Doit-on l'executer sous forme de thread separe ?
1974 if ( (args.size()>0) && (args[args.size()-1] == "&") ) {
1975 if ((*it).second.cex->IsThreadable(keyw) ) {
1976 ThrId++;
1977 CommandExeThr * thr =
1978 new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
1979 CmdThrExeList.push_back(thr);
1980 cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
1981 thr->start();
1982 if (CmdThrExeList.size() > 5) CleanThrList();
1983 rc = 0;
1984 }
1985 else {
1986 args.erase(args.end()-1);
1987 for(size_t k=toks.size()-1; k>0; k--)
1988 if (toks[k] == '&') { toks[k] = ' '; break; }
1989 cout << " Commander::ExecuteCommand() : Thread execution NOT available for" << keyw << endl;
1990 rc = (*it).second.cex->Execute(keyw, args, toks);
1991 }
1992 }
1993 else rc = (*it).second.cex->Execute(keyw, args, toks);
1994 }
1995 else cout << "Dont know how to execute " << keyw << " ? " << endl;
1996 }
1997 return(rc);
1998}
1999
2000/* --Methode-- */
2001int Commander::ExecFile(string& file, vector<string>& args)
2002{
2003char line_buff[1024];
2004FILE *fip;
2005int rcc = 0;
2006if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
2007 if (file.find('.') >= file.length()) {
2008 cout << "Commander::Exec(): Error opening file " << file << endl;
2009 file += ".pic";
2010 cout << " Trying file " << file << endl;
2011 fip = fopen(file.c_str(),"r");
2012 }
2013 }
2014
2015if(fip == NULL) {
2016 cerr << "Commander::Exec() Error opening file " << file << endl;
2017 hist << "##! Commander::Exec() Error opening file " << file << endl;
2018 return(0);
2019 }
2020
2021// hist << "### Executing commands from " << file << endl;
2022PushStack(args);
2023if (trace) {
2024 ShowMessage("### Executing commands from ", _MAGENTA_);
2025 ShowMessage(file.c_str(), _MAGENTA_);
2026 ShowMessage("\n", _MAGENTA_);
2027 }
2028
2029bool ohv = histon;
2030histon = false;
2031while (fgets(line_buff,1023,fip) != NULL)
2032 {
2033 if (trace) ShowMessage(line_buff, _MAGENTA_);
2034 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
2035 string line(line_buff);
2036 rcc = Interpret(line);
2037 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
2038 }
2039histon = ohv;
2040
2041// hist << "### End of Exec( " << file << " ) " << endl;
2042if (trace) {
2043 ShowMessage("### End of Exec( ", _MAGENTA_);
2044 ShowMessage(file.c_str(), _MAGENTA_);
2045 ShowMessage(" ) \n", _MAGENTA_);
2046 }
2047
2048PopStack(true);
2049
2050return(0);
2051}
2052
2053/* --Methode-- */
2054void Commander::ListThreads()
2055{
2056 cout << "--- Commander::ListThreads()- command execution threads NThread="
2057 << CmdThrExeList.size() << " ---" << endl;
2058 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2059 tit != CmdThrExeList.end(); tit++) {
2060 cout << "Id=" << (*tit)->Id();
2061 if ( (*tit)->IfRunning() ) cout << " Executing";
2062 else if ( (*tit)->IfDone() ) cout << " Finished , Rc= " << (*tit)->getRC();
2063 else cout << " Stopped/Canceled";
2064 cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens().substr(0,35);
2065 if ((*tit)->Tokens().length() > 35) cout << "... )" << endl;
2066 else cout << " )" << endl;
2067 }
2068}
2069/* --Methode-- */
2070void Commander::StopThr(uint_8 id, bool fgkill)
2071{
2072 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2073 tit != CmdThrExeList.end(); tit++) {
2074 if ( ((*tit)->Id() == id) && ((*tit)->IfRunning()) ) {
2075 if (fgkill) {
2076 (*tit)->kill(SIGUSR1);
2077 cout << "Commander::StopThr() Send signal SIGUSR1 to Thread Id= " << id << endl;
2078 }
2079 else {
2080 (*tit)->cancel();
2081 cout << "Commander::StopThr() Canceling Thread Id= " << id << endl;
2082 }
2083 return;
2084 }
2085 }
2086 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
2087}
2088
2089/* --Methode-- */
2090void Commander::CleanThrList()
2091{
2092 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2093 list<CommandExeThr *> thrcopie;
2094 int ncl = 0;
2095 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2096 tit != CmdThrExeList.end(); tit++) {
2097 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
2098 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2099 delete (*tit);
2100 ncl++;
2101 }
2102 else thrcopie.push_back((*tit));
2103 }
2104 CmdThrExeList = thrcopie;
2105 cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
2106}
2107
2108/* --Methode-- */
2109void Commander::WaitThreads()
2110{
2111 cout << "---- Commander::WaitThreads() Wait/Join command execution threads - NThread="
2112 << CmdThrExeList.size() << " ----- " << endl;
2113 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2114 tit != CmdThrExeList.end(); tit++) {
2115 try {
2116 if (! (*tit)->IfDone()) (*tit)->join();
2117 }
2118 catch (std::exception & e) {
2119 cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
2120 }
2121 cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
2122 delete (*tit);
2123 }
2124 CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
2125}
2126
2127/* --Methode-- */
2128int Commander::CShellExecute(string cmd)
2129{
2130 if(cmd.size()<=0) return -1;
2131
2132 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
2133
2134 string cmdrm = "rm -f " + fname;
2135 system(cmdrm.c_str());
2136
2137 FILE *fip = fopen(fname.c_str(),"w");
2138 if(fip==NULL) {
2139 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
2140 return -2;
2141 }
2142 fprintf(fip,"#!/bin/csh\n\n");
2143 fprintf(fip,"%s\n",cmd.c_str());
2144 fprintf(fip,"\nexit 0\n");
2145 fclose(fip);
2146
2147 cmd = "csh "; cmd += fname;
2148 system(cmd.c_str());
2149
2150 system(cmdrm.c_str());
2151
2152 return 0;
2153}
2154
2155static string* videstr = NULL;
2156/* --Methode-- */
2157string& Commander::GetUsage(const string& kw)
2158{
2159bool fndok = false;
2160CmdExmap::iterator it = cmdexmap.find(kw);
2161if (it == cmdexmap.end()) {
2162 it = helpexmap.find(kw);
2163 if (it != helpexmap.end()) fndok = true;
2164 }
2165 else fndok = true;
2166if (fndok) return( (*it).second.us );
2167// Keyword pas trouve
2168if (videstr == NULL) videstr = new string("");
2169*videstr = "Nothing known about " + kw + " ?? ";
2170return(*videstr);
2171
2172}
2173
2174
2175/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
2176 \newcommand{\piacommand}[1]{
2177 \framebox{\bf \Large #1 } \index{#1} % (Command)
2178 }
2179
2180 \newcommand{\piahelpitem}[1]{
2181 \framebox{\bf \Large #1 } \index{#1} (Help item)
2182 }
2183
2184 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2185*/
2186
2187// Fonction qui remplace tout caractere non alphanumerique en Z
2188static void check_latex_reflabel(string & prl)
2189{
2190 for(int k=0; k<prl.length(); k++)
2191 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2192}
2193
2194// Fonction qui remplace _ en \_
2195static string check_latex_underscore(string const & mot)
2196{
2197 string rs;
2198 for(int k=0; k<mot.length(); k++) {
2199 if (mot[k] == '_') rs += "\\_";
2200 else rs += mot[k];
2201 }
2202 return rs;
2203}
2204
2205/* --Methode-- */
2206/*!
2207 \brief Produces a LaTeX file containing the registered command helps
2208 The file \b fname is created and can be inserted into a LaTeX document
2209 in order to produce the list of registered commands and corresponding description
2210 texts.
2211 The LaTeX file should contain the following definitions:
2212\verbatim
2213 \newcommand{\piacommand}[1]{
2214 \framebox{\bf \Large #1 } \index{#1} % (Command)
2215 }
2216
2217 \newcommand{\piahelpitem}[1]{
2218 \framebox{\bf \Large #1 } \index{#1} (Help item)
2219 }
2220
2221 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2222
2223\endverbatim
2224*/
2225void Commander::HelptoLaTeX(string const & fname)
2226{
2227FILE *fip;
2228if ((fip = fopen(fname.c_str(), "w")) == NULL) {
2229 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
2230 return;
2231 }
2232
2233fputs("% ----- Liste des groupes de Help ----- \n",fip);
2234fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
2235fputs("\\begin{itemize} \n",fip);
2236string prl;
2237string mol;
2238CmdHGroup::iterator it;
2239for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2240 if ((*it).first == "All") continue;
2241 prl = (*it).first; check_latex_reflabel(prl);
2242 mol = check_latex_underscore((*it).first);
2243 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
2244 mol.c_str(), prl.c_str());
2245}
2246
2247fputs("\\end{itemize} \n",fip);
2248
2249fputs("\\vspace*{10mm} \n",fip);
2250
2251CmdExmap::iterator ite;
2252fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
2253fputs("\\vspace{5mm} \n",fip);
2254// fputs("\\begin{table}[h!] \n", fip);
2255fputs("\\begin{center} \n ", fip);
2256fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
2257fputs("\\vspace{3mm} \n",fip);
2258fputs("\\begin{tabular}{llllll} \n", fip);
2259int kt = 0;
2260for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2261 prl = (*ite).first; check_latex_reflabel(prl);
2262 mol = check_latex_underscore((*ite).first);
2263 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2264 kt++;
2265 if (kt < 3) fputs(" & ", fip);
2266 else { fputs(" \\\\ \n", fip); kt = 0; }
2267 }
2268if (kt == 1) fputs(" & & & \\\\ \n", fip);
2269else if (kt == 2) fputs(" & \\\\ \n", fip);
2270fputs("\\end{tabular} \n", fip);
2271fputs("\\end{center} \n", fip);
2272//fputs("\\end{table} \n", fip);
2273fputs("\\newpage \n",fip);
2274
2275int gid;
2276for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2277 gid = (*it).second.gid;
2278 if (gid == 0) continue;
2279 // fputs("\\begin{table}[h!] \n",fip);
2280 fputs("\\vspace{6mm} \n",fip);
2281 fputs("\\begin{center} \n ", fip);
2282 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
2283 (*it).first.c_str());
2284 fputs("\\vspace{3mm} \n",fip);
2285 fputs("\\begin{tabular}{llllll} \n", fip);
2286 kt = 0;
2287 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2288 if ((*ite).second.group != gid) continue;
2289 prl = (*ite).first; check_latex_reflabel(prl);
2290 mol = check_latex_underscore((*ite).first);
2291 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2292 kt++;
2293 if (kt < 3) fputs(" & ", fip);
2294 else { fputs(" \\\\ \n", fip); kt = 0; }
2295 }
2296 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2297 if ((*ite).second.group != gid) continue;
2298 prl = (*ite).first; check_latex_reflabel(prl);
2299 mol = check_latex_underscore((*ite).first);
2300 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2301 kt++;
2302 if (kt < 3) fputs(" & ", fip);
2303 else { fputs(" \\\\ \n", fip); kt = 0; }
2304 }
2305 if (kt == 1) fputs(" & & & \\\\ \n", fip);
2306 else if (kt == 2) fputs(" & \\\\ \n", fip);
2307 fputs("\\end{tabular} \n", fip);
2308 fputs("\\end{center} \n", fip);
2309 // fputs("\\end{table} \n",fip);
2310 // fputs("\\vspace{5mm} \n",fip);
2311}
2312// fputs("\\newline \n",fip);
2313
2314fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
2315fputs("\\newpage \n",fip);
2316
2317for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2318 gid = (*it).second.gid;
2319 if (gid == 0) continue;
2320 prl = (*it).first; check_latex_reflabel(prl);
2321 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
2322 (*it).first.c_str(), prl.c_str());
2323 if ((*it).second.desc.length() > 0)
2324 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
2325 fprintf(fip,"\\noindent \n");
2326 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2327 if ((*ite).second.group != gid) continue;
2328 prl = (*ite).first; check_latex_reflabel(prl);
2329 mol = check_latex_underscore((*ite).first);
2330 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
2331 mol.c_str(), prl.c_str());
2332 fputs("\\begin{verbatim} \n",fip);
2333 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2334 fputs("\\end{verbatim} \n",fip);
2335 }
2336 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2337 if ((*ite).second.group != gid) continue;
2338 prl = (*ite).first; check_latex_reflabel(prl);
2339 mol = check_latex_underscore((*ite).first);
2340 fprintf(fip,"\\piacommand{%s} \\label{%s} \n",
2341 mol.c_str(), prl.c_str());
2342 fputs("\\begin{verbatim} \n",fip);
2343 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2344 fputs("\\end{verbatim} \n",fip);
2345 }
2346}
2347
2348fclose(fip);
2349cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2350
2351return;
2352}
2353
2354
2355} // End of namespace SOPHYA
2356
Note: See TracBrowser for help on using the repository browser.