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

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

correction gestion & pour ThrExec ds Commander - Reza 31/05/2006

File size: 65.7 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;
1163
1164s2="";
1165p = 0;
1166l = s.length();
1167string vn, vv;
1168while (p < l) {
1169 iarr = -1;
1170 q = s.find('$',p);
1171 if (q > l) break;
1172 q2 = s.find('\'',p);
1173 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
1174 q2 = s.find('\'',q2+1);
1175 if (q2 >= l) {
1176 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
1177 return(1);
1178 }
1179 s2 += s.substr(p, q2-p+1);
1180 p = q2+1; continue;
1181 }
1182 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
1183 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
1184 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
1185 continue;
1186 }
1187 if (q >= l-1) {
1188 cerr << " Syntax error - line ending with $ !!! " << endl;
1189 return(2);
1190 }
1191 vn = "";
1192 if ( s[q+1] == '{' ) { // Variable in the form ${name}
1193 q2 = s.find('}',q+1);
1194 if (q2 >= l) {
1195 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
1196 return(3);
1197 }
1198 vn = s.substr(q+2,q2-q-2);
1199 q2++;
1200 }
1201 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
1202 q2 = s.find(')',q+1);
1203 if (q2 >= l) {
1204 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
1205 return(3);
1206 }
1207 vn = s.substr(q+2,q2-q-2);
1208 q2++;
1209 }
1210 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
1211 q2 = s.find(']',q+1);
1212 if (q2 >= l) {
1213 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
1214 return(4);
1215 }
1216 vn = s.substr(q+2,q2-q-2);
1217 if (!Var2Str(vn, vv)) return(5);
1218 vn = vv;
1219 q2++;
1220 }
1221 else {
1222 if (s[q+1] == '#' ) q3 = q+2; // Variable in the form $#varname
1223 else q3 = q+1;
1224 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'<>^%=#@\\",q3);
1225 if (q2 > l) q2 = l;
1226 q3 = q2;
1227 vn = s.substr(q+1, q2-q-1);
1228 // Si variable de type $varname[index] : element de tableau
1229 if ((q2 < l) && (s[q2] == '[') ) {
1230 q3 = s.find_first_of("]",q2+1);
1231 string sia = s.substr(q2+1, q3-q2-1);
1232 if (sia.length() < 1) {
1233 cerr << " Syntax error - in $varname[index] : $"
1234 << vn << "[" << sia <<"]" << endl;
1235 return(4);
1236 }
1237 if (isalpha(sia[0])) {
1238 string sia2;
1239 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1240 cerr << " Syntax error - in $varname[index] : $"
1241 << vn << "[" << sia <<"]" << endl;
1242 return(4);
1243 }
1244 sia = sia2;
1245 }
1246 int rcdia = ctoi(sia.c_str(), &iarr);
1247 if (rcdia < 0) {
1248 cerr << " Syntax error - in $varname[iarr] : $"
1249 << vn << "[" << sia <<"]" << endl;
1250 return(4);
1251 }
1252 }
1253 }
1254 if (iarr < 0) {
1255 if (!Var2Str(vn, vv)) return(5);
1256 s2 += (s.substr(p, q-p) + vv);
1257 p = q2;
1258 }
1259 else {
1260 if (! Var2Str(vn, iarr, vv) ) {
1261 cerr << " Substitution error - word index out of range in "
1262 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1263 return(4);
1264 }
1265 else s2 += (s.substr(p, q-p) + vv);
1266 p = q3+1;
1267 }
1268}
1269if (p < l) s2 += s.substr(p);
1270
1271p = s2.find_first_not_of(" \t");
1272if (p < l) s2 = s2.substr(p);
1273
1274return(0);
1275}
1276
1277/* --Methode-- */
1278bool Commander::Var2Str(string const & vn, string & vv)
1279{
1280if (vn.length() < 1) {
1281 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
1282 vv = ""; return(false);
1283}
1284// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1285int ka = 0;
1286char buff[32];
1287
1288if (vn == "#") {
1289 if (ArgsStack.empty()) {
1290 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1291 << " ($" << vn << ")" << endl;
1292 vv = ""; return(false);
1293 }
1294 char buff[32];
1295 long an = ArgsStack.top().size();
1296 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
1297 sprintf(buff,"%ld", an);
1298 vv = buff; return(true);
1299}
1300else if (vn == "*") {
1301 if (ArgsStack.empty()) {
1302 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1303 << " ($" << vn << ")" << endl;
1304 vv = ""; return(false);
1305 }
1306 vv = ArgsStack.top()[0];
1307 for(int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
1308 return(true);
1309}
1310else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1311 if (ArgsStack.empty()) {
1312 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1313 << " ($" << vn << ")" << endl;
1314 vv = ""; return(false);
1315 }
1316 if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
1317 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
1318 << " ($" << vn << ")" << endl;
1319 vv = ""; return(false);
1320 }
1321 vv = ArgsStack.top()[ka]; return(true);
1322}
1323else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
1324 CmdVarList::iterator it = variables.find(vn.substr(1));
1325 if (it == variables.end()) {
1326 cerr << " Commander::Var2Str/Error #vname Undefined variable "
1327 << vn << " ! " << endl;
1328 vv = ""; return(false);
1329 }
1330 sprintf(buff,"%d", (int)(*it).second.size());
1331 vv = buff; return(true);
1332}
1333else if (vn == "status") {
1334 sprintf(buff,"%d", _xstatus);
1335 vv = buff;
1336 return true;
1337}
1338else if ((vn == "retstr") || (vn == "retval")) {
1339 vv = _retstr;
1340 return true;
1341}
1342else { // Variable de l'interpreteur, ou de l'environnement application , env. global
1343 if (GetVar(vn, vv)) return true;
1344 else if (GetVarApp(vn, vv)) return true;
1345 else if (GetVarEnv(vn, vv)) return true;
1346 else {
1347 cerr << " Commander::Var2Str/Error Undefined variable "
1348 << vn << " ! " << endl;
1349 vv = ""; return false;
1350 }
1351}
1352
1353return false;
1354}
1355
1356/* --Methode-- */
1357bool Commander::SetVariable(string const & vn, string const & vv)
1358{
1359 // On verifie si le nom est de type vname[idx]
1360 size_t p,q,l;
1361 l = vn.length();
1362 p = vn.find('[');
1363 if (p < l) {
1364 q = vn.find(']');
1365 if (q != (l-1)) {
1366 cout << "Commander::Str2Var/SetVar() - Bad varname with []: "
1367 << vn << endl;
1368 return false;
1369 }
1370 string vna = vn.substr(0, p);
1371 string sia = vn.substr(p+1, q-(p+1));
1372 if (isalpha(sia[0])) {
1373 string sia2;
1374 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1375 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:"
1376 << vn << endl;
1377 return false;
1378 }
1379 sia = sia2;
1380 }
1381 int iarr;
1382 int rcdia = ctoi(sia.c_str(), &iarr);
1383 if (rcdia < 0) {
1384 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: "
1385 << vn << endl;
1386 return false;
1387 }
1388 return SetVar(vna, iarr, vv);
1389 }
1390 else {
1391 if (vn == "status") {
1392 _xstatus = atoi(vv.c_str());
1393 return true;
1394 }
1395 else if (vn == "retstr") {
1396 _retstr = vv;
1397 return true;
1398 }
1399 else return SetVar(vn, vv);
1400 }
1401}
1402
1403/* --Methode-- */
1404bool Commander::GetVar(string const & vn, string & vv)
1405{
1406 CmdVarList::iterator it = variables.find(vn);
1407 if (it == variables.end()) {
1408 vv = "";
1409 return false;
1410 }
1411 vv = (*it).second[0];
1412 if ((*it).second.size() > 1) {
1413 for(int k=1; k<(*it).second.size(); k++) {
1414 vv += ' '; vv += (*it).second[k];
1415 }
1416 }
1417 return true;
1418}
1419
1420/* --Methode-- */
1421bool Commander::GetVar(string const & vn, int idx, string & vv)
1422{
1423 vv = "";
1424 CmdVarList::iterator it = variables.find(vn);
1425 if (it == variables.end()) return false;
1426 if ((idx < 0) || (idx > (*it).second.size()-1))
1427 return false;
1428 vv = (*it).second[idx];
1429 return true;
1430}
1431
1432/* --Methode-- */
1433bool Commander::GetVar(string const & vn, vector<string> & vv)
1434{
1435 vv.clear();
1436 // vv.erase(vv.begin(),vv.end());
1437 CmdVarList::iterator it = variables.find(vn);
1438 if (it == variables.end()) return false;
1439 vv = (*it).second;
1440 return true;
1441}
1442
1443/* --Methode-- */
1444bool Commander::SetVar(string const & vn, string const & val)
1445{
1446 if ( !CheckVarName(vn) ) {
1447 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1448 return(false);
1449 }
1450 bool fg = false;
1451 vector<string> nouv;
1452 nouv.push_back(val);
1453 CmdVarList::iterator it = variables.find(vn);
1454 if (it == variables.end()) variables[vn] = nouv;
1455 else {
1456 (*it).second = nouv;
1457 fg = true;
1458 }
1459 return fg;
1460}
1461
1462/* --Methode-- */
1463bool Commander::SetVar(string const & vn, int idx, string const & val)
1464{
1465 if ( !CheckVarName(vn) ) {
1466 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
1467 return(false);
1468 }
1469 if ((vn == "status") || (vn == "retstr")) {
1470 cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr "
1471 << endl;
1472 return(false);
1473 }
1474 if (idx < 0) {
1475 cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl;
1476 return(false);
1477 }
1478 bool fg = false;
1479 CmdVarList::iterator it = variables.find(vn);
1480 if (it == variables.end()) {
1481 vector<string> nouv;
1482 for(int j=0; j<idx; j++) nouv.push_back("");
1483 nouv.push_back(val);
1484 variables[vn] = nouv;
1485 }
1486 else {
1487 if (idx >= (*it).second.size())
1488 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1489 (*it).second[idx] = val;
1490 fg = true;
1491 }
1492 return fg;
1493}
1494
1495/* --Methode-- */
1496bool Commander::SetVar(string const & vn, vector<string> const & val)
1497{
1498 if ( !CheckVarName(vn) ) {
1499 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1500 return(false);
1501 }
1502 if ((vn == "status") || (vn == "retstr")) {
1503 cerr << "Commander::SetVar(vn, vector<string>) ERROR - special var status/retstr "
1504 << endl;
1505 return(false);
1506 }
1507 bool fg = false;
1508 CmdVarList::iterator it = variables.find(vn);
1509 if (it == variables.end()) variables[vn] = val;
1510 else {
1511 (*it).second = val;
1512 fg = true;
1513 }
1514 return fg;
1515}
1516
1517/* --Methode-- */
1518bool Commander::CheckVarName(string const & vn)
1519{
1520 size_t l,k;
1521 l = vn.length();
1522 if (l < 1) return false;
1523 if (!isalpha(vn[0])) return false;
1524 for(k=1; k<l; k++)
1525 if ((!isalnum(vn[k])) && (vn[k] != '_')) return false;
1526 return true;
1527}
1528
1529/* --Methode-- */
1530bool Commander::DeleteVar(string const & vn)
1531{
1532 CmdVarList::iterator it = variables.find(vn);
1533 if (it == variables.end()) {
1534 cerr << "Commander::DeleteVar() Var " << vn << " undefined!" << endl;
1535 return false;
1536 }
1537 variables.erase(it);
1538 return true;
1539}
1540
1541/* --Methode-- */
1542void Commander::ListVar()
1543{
1544 cout << " ---- Commander::ListVar() List of defined variables ---- "
1545 << endl;
1546 CmdVarList::iterator it;
1547 for(it = variables.begin(); it != variables.end(); it++) {
1548 string vn = (*it).first;
1549 int vs = (*it).second.size();
1550 cout << vn << " -> Size= " << vs << endl;
1551 }
1552 cout << "---------------------------------------------------------- "
1553 << endl;
1554}
1555
1556/* --Methode-- */
1557bool Commander::GetVarApp(string const & vn, string & vv)
1558{
1559 vv = "";
1560 // cout << " Commander::GetVarApp() Not available ! " << endl;
1561 return false;
1562}
1563
1564/* --Methode-- */
1565bool Commander::SetVarApp(string const & vn, string const & vv)
1566{
1567 // cout << " Commander::SetVarApp() Not available ! " << endl;
1568 return false;
1569}
1570
1571/* --Methode-- */
1572bool Commander::DeleteVarApp(string const & vn)
1573{
1574 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
1575 return false;
1576}
1577
1578/* --Methode-- */
1579void Commander::ListVarApp()
1580{
1581 // cout << " Commander::ListVarApp() Not available ! " << endl;
1582 return;
1583}
1584
1585
1586/* --Methode-- */
1587bool Commander::GetVarEnv(string const & vn, string & vv)
1588{
1589 char* vev = getenv(vn.c_str());
1590 if (vev) {
1591 vv = vev;
1592 return true;
1593 }
1594 else {
1595 vv = "";
1596 return false;
1597 }
1598}
1599
1600/* --Methode-- */
1601bool Commander::SetVarEnv(string const & vn, string const & vv)
1602{
1603 string pev = vn;
1604 pev += '=';
1605 pev += vv;
1606// if defined(Linux) || defined(AIX)
1607// Reza - 28/04/2004
1608// putenv de Linux ne declare pas la variable char *string const
1609// On ne doit meme pas utiliser une variable automatique
1610// J'alloue donc un nouveau tableau - mais qui va le liberer ?
1611// Idem AIX , Reza Dec 2005
1612// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1613// Je fais copie pour tout le monde
1614 char* bev = new char[pev.size()+1];
1615 strcpy(bev, pev.c_str());
1616 if (putenv(bev) == 0) return true;
1617// else
1618// if (putenv(pev.c_str()) == 0) return true;
1619// endif
1620 else return false;
1621}
1622
1623/* --Methode-- */
1624bool Commander::DeleteVarEnv(string const & vn)
1625{
1626 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
1627 return false;
1628}
1629
1630/* --Methode-- */
1631void Commander::ListVarEnv()
1632{
1633 cout << " Commander::ListVarEnv() Not available ! " << endl;
1634 return;
1635}
1636
1637
1638/* --Methode-- */
1639string Commander::GetTmpDir()
1640{
1641 return("/tmp");
1642}
1643
1644/* --Methode-- */
1645void Commander::SetCurrentPrompt(const char* pr)
1646{
1647 curprompt = pr;
1648}
1649
1650/* --Methode-- */
1651void Commander::ShowMessage(const char * msg, int att)
1652{
1653 cout << msg ;
1654}
1655
1656
1657
1658/* --Methode-- */
1659int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1660{
1661 res = true;
1662 if ((args.size() != 6) || (args[5] != "then") ||
1663 (args[0] != "(") || (args[4] != ")") ) return(1);
1664 if (args[2] == "==") res = (args[1] == args[3]);
1665 else if (args[2] == "!=") res = (args[1] != args[3]);
1666 else if (args[2] == "<")
1667 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1668 else if (args[2] == ">")
1669 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1670 else if (args[2] == "<=")
1671 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1672 else if (args[2] == ">=")
1673 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1674 else return(2);
1675 return(0);
1676}
1677
1678
1679/* --Methode-- */
1680int Commander::EvalRPNExpr(vector<string> & args, string & line)
1681{
1682 // A virer - Reza 15/03/2004
1683 return(0);
1684}
1685
1686/* --Methode-- */
1687void Commander::PushStack(vector<string>& args)
1688{
1689 // We push the argument list (args) on the stack
1690 ArgsStack.push(args);
1691 // We push also CommanderBloc and testresult on the stack
1692 CmdBlks.push(NULL);
1693 list<char> xtx;
1694 TestsStack.push(xtx);
1695
1696}
1697
1698/* --Methode-- */
1699void Commander::PopStack(bool psta)
1700{
1701 // We remove the argument list (args) from the stack
1702 if (psta) ArgsStack.pop();
1703 // And CommanderBloc and TestResult from the corresponding stacks
1704 CommanderBloc* curb = CmdBlks.top();
1705 while (curb != NULL) {
1706 CommanderBloc* parb = curb->Parent();
1707 delete curb; curb = parb;
1708 }
1709 CmdBlks.pop();
1710 TestsStack.pop();
1711}
1712
1713/* --Methode-- */
1714int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1715{
1716int rc = 0;
1717
1718// >>>>>>>>>>> Commande d'interpreteur
1719if (kw == "help") {
1720 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1721 else {
1722 string kwh = "Commander";
1723 cout << GetUsage(kwh) << endl;
1724 }
1725 }
1726else if (kw == "sleep") {
1727 if (tokens.size() < 1) {
1728 cout << "Commander::Interpret() Usage: sleep nsec " << endl;
1729 return(1);
1730 }
1731 int nsec = atoi(tokens[0].c_str());
1732 cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl;
1733 sleep(nsec);
1734}
1735
1736else if (kw == "set") {
1737 if (tokens.size() < 2) {
1738 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1739 return(1);
1740 }
1741
1742 if (tokens.size() == 2)
1743 SetVariable(tokens[0], tokens[1]);
1744 else {
1745 if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
1746 cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;
1747 return(1);
1748 }
1749 string vname = tokens[0];
1750 vector<string>::iterator vit;
1751 vit = tokens.begin(); tokens.erase(vit);
1752 vit = tokens.begin(); tokens.erase(vit);
1753 tokens.pop_back();
1754 SetVar(vname, tokens);
1755 }
1756 return 0;
1757}
1758else if (kw == "var2words") {
1759 if (tokens.size() < 2) {
1760 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1761 return(1);
1762 }
1763 char sep = ' ';
1764 if (tokens.size() > 2) sep = tokens[2][0];
1765 string vv;
1766 if (!GetVar(tokens[0], vv)) {
1767 cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl;
1768 return 2;
1769 }
1770 vector<string> vs;
1771 FillVStringFrString(vv, vs, sep);
1772 SetVar(tokens[1], vs);
1773}
1774else if (kw == "alias") {
1775 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1776 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1777 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
1778 return(1);
1779 }
1780 string xx = tokens[1];
1781 for (int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1782 mAliases[tokens[0]] = xx;
1783}
1784
1785else if ( (kw == "unset") || (kw == "clearvar") ) {
1786 if (tokens.size() < 1) {
1787 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
1788 return(1);
1789 }
1790 else DeleteVar(tokens[0]);
1791}
1792// Evaluation d'expression en notation polonaise inverse
1793else if (kw == "rpneval") {
1794 try {
1795 RPNExpressionEvaluator rpn(tokens, 1);
1796 double res = rpn.Value();
1797 char cbuff[64];
1798 sprintf(cbuff,"%g",res);
1799 string vv = cbuff;
1800 SetVariable(tokens[0],vv);
1801 return 0;
1802 }
1803 catch (RPNExprException& rpnerr) {
1804 cerr << " rpneval: Syntax error - Msg=" << rpnerr.Msg()
1805 << " \n Line=" << toks << endl;
1806 return 98;
1807 }
1808}
1809else if (kw == "echo") {
1810 for (int ii=0; ii<tokens.size(); ii++)
1811 cout << tokens[ii] << " " ;
1812 cout << endl;
1813 }
1814else if (kw == "echo2file") {
1815 if (tokens.size() < 1) {
1816 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
1817 return(1);
1818 }
1819 ofstream ofs(tokens[0].c_str(), ios::app);
1820 for (int ii=1; ii<tokens.size(); ii++)
1821 ofs << tokens[ii] << " " ;
1822 ofs << endl;
1823 }
1824else if (kw == "readstdin") {
1825 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1826 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1827 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1828 return(0);
1829 }
1830 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1831 cout << tokens[0] << " ? " << endl;
1832 SetVar(tokens[0], GetStringFrStdin(this) );
1833 }
1834
1835else if (kw == "listvars" || kw == "listvar") ListVar();
1836else if (kw == "listalias") {
1837 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1838 CmdStrList::iterator it;
1839 for(it = mAliases.begin(); it != mAliases.end(); it++)
1840 cout << (*it).first << " = " << (*it).second << "\n";
1841 cout << endl;
1842 }
1843else if (kw == "listcommands") {
1844 cout << "---- Commander::Interpret() Command List ----- \n";
1845 CmdExmap::iterator it;
1846 int kc = 0;
1847 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1848 cout << (*it).first << " ";
1849 kc++;
1850 if (kc >= 5) { cout << "\n"; kc = 0; }
1851 }
1852 cout << endl;
1853 }
1854else if (kw == "listscripts") {
1855 cout << "---- Commander::Interpret() Script List ----- \n";
1856 for(ScriptList::iterator sit = mScripts.begin();
1857 sit != mScripts.end(); sit++)
1858 cout << " Script: " << (*sit).second->Name() << " - "
1859 << (*sit).second->Comment() << endl;
1860}
1861else if (kw == "clearscript") {
1862 if (tokens.size() < 1) {
1863 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1864 return(0);
1865 }
1866 ScriptList::iterator sit = mScripts.find(tokens[0]);
1867 if (sit == mScripts.end()) {
1868 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1869 return(0);
1870 }
1871 else {
1872 delete (*sit).second;
1873 mScripts.erase(sit);
1874 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1875 return(0);
1876 }
1877}
1878//---------------------------------------------
1879//--- Commandes de gestion des threads ------
1880//---------------------------------------------
1881else if (kw == "thrlist") {
1882 ListThreads();
1883 return(0);
1884}
1885else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1886 if (tokens.size() < 1) {
1887 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1888 return(0);
1889 }
1890 uint_8 id = atol(tokens[0].c_str());
1891 bool fgkill = false;
1892 if (kw == "killthr") fgkill = true;
1893 StopThr(id, fgkill);
1894 return (0);
1895}
1896else if (kw == "waitthr") {
1897 WaitThreads();
1898 return (0);
1899}
1900else if (kw == "cleanthrlist") {
1901 CleanThrList();
1902 return (0);
1903}
1904
1905else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1906else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1907else if (kw == "timingon") {
1908 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1909 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1910 }
1911else if (kw == "timingoff") {
1912 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1913 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1914 }
1915else if (kw == "exec") {
1916 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1917 ExecFile(tokens[0], tokens);
1918 }
1919else if (kw == "autoiniranf") {
1920 Auto_Ini_Ranf(1);
1921 return(0);
1922}
1923else if (kw == "shell") {
1924 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1925 string cmd;
1926 for (int ii=0; ii<tokens.size(); ii++)
1927 cmd += (tokens[ii] + ' ');
1928 system(cmd.c_str());
1929 }
1930else if (kw == "cshell") {
1931 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1932 string cmd="";
1933 for(int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
1934 CShellExecute(cmd);
1935 }
1936
1937// Execution d'une commande enregistree
1938else rc = ExecuteCommand(kw, tokens, toks);
1939
1940if (timing) gltimer->Split();
1941return(rc);
1942}
1943
1944/* --Methode-- */
1945int Commander::ParseLineExecute(string& line, bool qw)
1946 // Si qw == true, on decoupe entre '' ou "" ou espaces
1947{
1948vector<string> tokens;
1949vector<bool> qottoks;
1950string kw, toks;
1951if (line.length() < 1) return(0);
1952LineToWords(line, kw, tokens, qottoks, toks, qw);
1953return(ExecuteCommand(kw, tokens, toks));
1954}
1955
1956/* --Methode-- */
1957int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
1958{
1959 int rc = -1;
1960 CmdExmap::iterator it = cmdexmap.find(keyw);
1961 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
1962 else {
1963 if ((*it).second.cex) {
1964 // Doit-on l'executer sous forme de thread separe ?
1965 if ( (args.size()>0) && (args[args.size()-1] == "&") ) {
1966 if ((*it).second.cex->IsThreadable(keyw) ) {
1967 ThrId++;
1968 CommandExeThr * thr =
1969 new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
1970 CmdThrExeList.push_back(thr);
1971 cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
1972 thr->start();
1973 if (CmdThrExeList.size() > 5) CleanThrList();
1974 rc = 0;
1975 }
1976 else {
1977 args.erase(args.end()-1);
1978 for(size_t k=toks.size()-1; k>0; k--)
1979 if (toks[k] == '&') { toks[k] = ' '; break; }
1980 cout << " Commander::ExecuteCommand() : Thread execution NOT available for" << keyw << endl;
1981 rc = (*it).second.cex->Execute(keyw, args, toks);
1982 }
1983 }
1984 else rc = (*it).second.cex->Execute(keyw, args, toks);
1985 }
1986 else cout << "Dont know how to execute " << keyw << " ? " << endl;
1987 }
1988 return(rc);
1989}
1990
1991/* --Methode-- */
1992int Commander::ExecFile(string& file, vector<string>& args)
1993{
1994char line_buff[1024];
1995FILE *fip;
1996int rcc = 0;
1997if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
1998 if (file.find('.') >= file.length()) {
1999 cout << "Commander::Exec(): Error opening file " << file << endl;
2000 file += ".pic";
2001 cout << " Trying file " << file << endl;
2002 fip = fopen(file.c_str(),"r");
2003 }
2004 }
2005
2006if(fip == NULL) {
2007 cerr << "Commander::Exec() Error opening file " << file << endl;
2008 hist << "##! Commander::Exec() Error opening file " << file << endl;
2009 return(0);
2010 }
2011
2012// hist << "### Executing commands from " << file << endl;
2013PushStack(args);
2014if (trace) {
2015 ShowMessage("### Executing commands from ", _MAGENTA_);
2016 ShowMessage(file.c_str(), _MAGENTA_);
2017 ShowMessage("\n", _MAGENTA_);
2018 }
2019
2020bool ohv = histon;
2021histon = false;
2022while (fgets(line_buff,1023,fip) != NULL)
2023 {
2024 if (trace) ShowMessage(line_buff, _MAGENTA_);
2025 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
2026 string line(line_buff);
2027 rcc = Interpret(line);
2028 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
2029 }
2030histon = ohv;
2031
2032// hist << "### End of Exec( " << file << " ) " << endl;
2033if (trace) {
2034 ShowMessage("### End of Exec( ", _MAGENTA_);
2035 ShowMessage(file.c_str(), _MAGENTA_);
2036 ShowMessage(" ) \n", _MAGENTA_);
2037 }
2038
2039PopStack(true);
2040
2041return(0);
2042}
2043
2044/* --Methode-- */
2045void Commander::ListThreads()
2046{
2047 cout << "--- Commander::ListThreads()- command execution threads NThread="
2048 << CmdThrExeList.size() << " ---" << endl;
2049 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2050 tit != CmdThrExeList.end(); tit++) {
2051 cout << "Id=" << (*tit)->Id();
2052 if ( (*tit)->IfRunning() ) cout << " Executing";
2053 else if ( (*tit)->IfDone() ) cout << " Finished , Rc= " << (*tit)->getRC();
2054 else cout << " Stopped/Canceled";
2055 cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens().substr(0,35);
2056 if ((*tit)->Tokens().length() > 35) cout << "... )" << endl;
2057 else cout << " )" << endl;
2058 }
2059}
2060/* --Methode-- */
2061void Commander::StopThr(uint_8 id, bool fgkill)
2062{
2063 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2064 tit != CmdThrExeList.end(); tit++) {
2065 if ( ((*tit)->Id() == id) && ((*tit)->IfRunning()) ) {
2066 if (fgkill) {
2067 (*tit)->kill(SIGUSR1);
2068 cout << "Commander::StopThr() Send signal SIGUSR1 to Thread Id= " << id << endl;
2069 }
2070 else {
2071 (*tit)->cancel();
2072 cout << "Commander::StopThr() Canceling Thread Id= " << id << endl;
2073 }
2074 return;
2075 }
2076 }
2077 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
2078}
2079
2080/* --Methode-- */
2081void Commander::CleanThrList()
2082{
2083 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2084 list<CommandExeThr *> thrcopie;
2085 int ncl = 0;
2086 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2087 tit != CmdThrExeList.end(); tit++) {
2088 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
2089 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2090 delete (*tit);
2091 ncl++;
2092 }
2093 else thrcopie.push_back((*tit));
2094 }
2095 CmdThrExeList = thrcopie;
2096 cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
2097}
2098
2099/* --Methode-- */
2100void Commander::WaitThreads()
2101{
2102 cout << "---- Commander::WaitThreads() Wait/Join command execution threads - NThread="
2103 << CmdThrExeList.size() << " ----- " << endl;
2104 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2105 tit != CmdThrExeList.end(); tit++) {
2106 try {
2107 if (! (*tit)->IfDone()) (*tit)->join();
2108 }
2109 catch (std::exception & e) {
2110 cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
2111 }
2112 cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
2113 delete (*tit);
2114 }
2115 CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
2116}
2117
2118/* --Methode-- */
2119int Commander::CShellExecute(string cmd)
2120{
2121 if(cmd.size()<=0) return -1;
2122
2123 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
2124
2125 string cmdrm = "rm -f " + fname;
2126 system(cmdrm.c_str());
2127
2128 FILE *fip = fopen(fname.c_str(),"w");
2129 if(fip==NULL) {
2130 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
2131 return -2;
2132 }
2133 fprintf(fip,"#!/bin/csh\n\n");
2134 fprintf(fip,"%s\n",cmd.c_str());
2135 fprintf(fip,"\nexit 0\n");
2136 fclose(fip);
2137
2138 cmd = "csh "; cmd += fname;
2139 system(cmd.c_str());
2140
2141 system(cmdrm.c_str());
2142
2143 return 0;
2144}
2145
2146static string* videstr = NULL;
2147/* --Methode-- */
2148string& Commander::GetUsage(const string& kw)
2149{
2150bool fndok = false;
2151CmdExmap::iterator it = cmdexmap.find(kw);
2152if (it == cmdexmap.end()) {
2153 it = helpexmap.find(kw);
2154 if (it != helpexmap.end()) fndok = true;
2155 }
2156 else fndok = true;
2157if (fndok) return( (*it).second.us );
2158// Keyword pas trouve
2159if (videstr == NULL) videstr = new string("");
2160*videstr = "Nothing known about " + kw + " ?? ";
2161return(*videstr);
2162
2163}
2164
2165
2166/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
2167 \newcommand{\piacommand}[1]{
2168 \framebox{\bf \Large #1 } \index{#1} % (Command)
2169 }
2170
2171 \newcommand{\piahelpitem}[1]{
2172 \framebox{\bf \Large #1 } \index{#1} (Help item)
2173 }
2174
2175 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2176*/
2177
2178// Fonction qui remplace tout caractere non alphanumerique en Z
2179static void check_latex_reflabel(string & prl)
2180{
2181 for(int k=0; k<prl.length(); k++)
2182 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2183}
2184
2185// Fonction qui remplace _ en \_
2186static string check_latex_underscore(string const & mot)
2187{
2188 string rs;
2189 for(int k=0; k<mot.length(); k++) {
2190 if (mot[k] == '_') rs += "\\_";
2191 else rs += mot[k];
2192 }
2193 return rs;
2194}
2195
2196/* --Methode-- */
2197/*!
2198 \brief Produces a LaTeX file containing the registered command helps
2199 The file \b fname is created and can be inserted into a LaTeX document
2200 in order to produce the list of registered commands and corresponding description
2201 texts.
2202 The LaTeX file should contain the following definitions:
2203\verbatim
2204 \newcommand{\piacommand}[1]{
2205 \framebox{\bf \Large #1 } \index{#1} % (Command)
2206 }
2207
2208 \newcommand{\piahelpitem}[1]{
2209 \framebox{\bf \Large #1 } \index{#1} (Help item)
2210 }
2211
2212 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2213
2214\endverbatim
2215*/
2216void Commander::HelptoLaTeX(string const & fname)
2217{
2218FILE *fip;
2219if ((fip = fopen(fname.c_str(), "w")) == NULL) {
2220 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
2221 return;
2222 }
2223
2224fputs("% ----- Liste des groupes de Help ----- \n",fip);
2225fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
2226fputs("\\begin{itemize} \n",fip);
2227string prl;
2228string mol;
2229CmdHGroup::iterator it;
2230for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2231 if ((*it).first == "All") continue;
2232 prl = (*it).first; check_latex_reflabel(prl);
2233 mol = check_latex_underscore((*it).first);
2234 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
2235 mol.c_str(), prl.c_str());
2236}
2237
2238fputs("\\end{itemize} \n",fip);
2239
2240fputs("\\vspace*{10mm} \n",fip);
2241
2242CmdExmap::iterator ite;
2243fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
2244fputs("\\vspace{5mm} \n",fip);
2245// fputs("\\begin{table}[h!] \n", fip);
2246fputs("\\begin{center} \n ", fip);
2247fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
2248fputs("\\vspace{3mm} \n",fip);
2249fputs("\\begin{tabular}{llllll} \n", fip);
2250int kt = 0;
2251for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2252 prl = (*ite).first; check_latex_reflabel(prl);
2253 mol = check_latex_underscore((*ite).first);
2254 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2255 kt++;
2256 if (kt < 3) fputs(" & ", fip);
2257 else { fputs(" \\\\ \n", fip); kt = 0; }
2258 }
2259if (kt == 1) fputs(" & & & \\\\ \n", fip);
2260else if (kt == 2) fputs(" & \\\\ \n", fip);
2261fputs("\\end{tabular} \n", fip);
2262fputs("\\end{center} \n", fip);
2263//fputs("\\end{table} \n", fip);
2264fputs("\\newpage \n",fip);
2265
2266int gid;
2267for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2268 gid = (*it).second.gid;
2269 if (gid == 0) continue;
2270 // fputs("\\begin{table}[h!] \n",fip);
2271 fputs("\\vspace{6mm} \n",fip);
2272 fputs("\\begin{center} \n ", fip);
2273 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
2274 (*it).first.c_str());
2275 fputs("\\vspace{3mm} \n",fip);
2276 fputs("\\begin{tabular}{llllll} \n", fip);
2277 kt = 0;
2278 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2279 if ((*ite).second.group != gid) continue;
2280 prl = (*ite).first; check_latex_reflabel(prl);
2281 mol = check_latex_underscore((*ite).first);
2282 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2283 kt++;
2284 if (kt < 3) fputs(" & ", fip);
2285 else { fputs(" \\\\ \n", fip); kt = 0; }
2286 }
2287 for(ite = cmdexmap.begin(); ite != cmdexmap.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 if (kt == 1) fputs(" & & & \\\\ \n", fip);
2297 else if (kt == 2) fputs(" & \\\\ \n", fip);
2298 fputs("\\end{tabular} \n", fip);
2299 fputs("\\end{center} \n", fip);
2300 // fputs("\\end{table} \n",fip);
2301 // fputs("\\vspace{5mm} \n",fip);
2302}
2303// fputs("\\newline \n",fip);
2304
2305fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
2306fputs("\\newpage \n",fip);
2307
2308for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2309 gid = (*it).second.gid;
2310 if (gid == 0) continue;
2311 prl = (*it).first; check_latex_reflabel(prl);
2312 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
2313 (*it).first.c_str(), prl.c_str());
2314 if ((*it).second.desc.length() > 0)
2315 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
2316 fprintf(fip,"\\noindent \n");
2317 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2318 if ((*ite).second.group != gid) continue;
2319 prl = (*ite).first; check_latex_reflabel(prl);
2320 mol = check_latex_underscore((*ite).first);
2321 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
2322 mol.c_str(), prl.c_str());
2323 fputs("\\begin{verbatim} \n",fip);
2324 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2325 fputs("\\end{verbatim} \n",fip);
2326 }
2327 for(ite = cmdexmap.begin(); ite != cmdexmap.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,"\\piacommand{%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}
2338
2339fclose(fip);
2340cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2341
2342return;
2343}
2344
2345
2346} // End of namespace SOPHYA
2347
Note: See TracBrowser for help on using the repository browser.