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

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

ajout methode ZThread::kill() pour envoi de signal a un thread + remplacement CancelThread par StopThread (par kill/SIGUSR1) dans Commander (commander.cc) + amelioration documentation , Reza 26/4/2006

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